Pobieranie adresu MAC

111

Potrzebuję wieloplatformowej metody określania adresu MAC komputera w czasie wykonywania. W systemie Windows można użyć modułu „wmi”, a jedyną metodą, jaką znalazłem pod Linuksem, było uruchomienie ifconfig i wykonanie wyrażenia regularnego na jego wyjściu. Nie podoba mi się używanie pakietu, który działa tylko w jednym systemie operacyjnym, a analiza danych wyjściowych innego programu nie wydaje się zbyt elegancka, nie wspominając o podatności na błędy.

Czy ktoś zna metodę międzyplatformową (Windows i Linux), aby uzyskać adres MAC? Jeśli nie, to czy ktoś zna bardziej eleganckie metody niż te, które wymieniłem powyżej?

Mark Roddy
źródło
Istnieje wiele potencjalnie pomocnych odpowiedzi! Jak mogę uzyskać adres IP eth0 w Pythonie?
uhoh,

Odpowiedzi:

160

Python 2.5 zawiera implementację uuid, która (w co najmniej jednej wersji) wymaga adresu mac. Możesz łatwo zaimportować funkcję wyszukiwania mac do własnego kodu:

from uuid import getnode as get_mac
mac = get_mac()

Wartość zwracana to adres mac jako 48-bitowa liczba całkowita.

Armin Ronacher
źródło
25
Właśnie wypróbowałem to na komputerze z systemem Windows i działa świetnie ... poza tym, że laptop, na którym go wypróbowałem, ma 2 karty sieciowe (jedną bezprzewodową) i nie ma sposobu, aby określić, który MAC zwrócił. Tylko słowo ostrzeżenia, jeśli chcesz użyć tego kodu.
technomalogiczny
24
Tylko ostrzeżenie: jeśli spojrzysz na getnodedokumentację, zobaczysz, że zwróci losowo długi czas, jeśli nie wykryje mac: „Jeśli wszystkie próby uzyskania adresu sprzętowego zawiodą, wybieramy losową 48-bitową liczbę z jej ósmym bitem ustaw na 1 zgodnie z zaleceniami w dokumencie RFC 4122. ” Więc sprawdź ósmy kawałek!
deinonychusaur
27
hex(mac)aby uzyskać znajomy format szesnastkowy komputera Mac
zrzut
43
Lub ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2))w przypadku adresu MAC z wielkimi literami, w którym każdy bajt jest oddzielony dwukropkiem.
tomlogic
5
getnode () zwraca coś innego za każdym razem, gdy ponownie uruchamiam laptopa z systemem Windows 7.
nu everest
81

Czyste rozwiązanie w Pythonie dla tego problemu pod Linuksem, aby uzyskać MAC dla określonego lokalnego interfejsu, pierwotnie opublikowane jako komentarz przez vishnubob i ulepszone przez Bena Mackeya w tym przepisie dotyczącym aktywnej wersji

#!/usr/bin/python

import fcntl, socket, struct

def getHwAddr(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    info = fcntl.ioctl(s.fileno(), 0x8927,  struct.pack('256s', ifname[:15]))
    return ':'.join(['%02x' % ord(char) for char in info[18:24]])

print getHwAddr('eth0')

Oto kod zgodny z Python 3:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import fcntl
import socket
import struct


def getHwAddr(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    info = fcntl.ioctl(s.fileno(), 0x8927,  struct.pack('256s', bytes(ifname, 'utf-8')[:15]))
    return ':'.join('%02x' % b for b in info[18:24])


def main():
    print(getHwAddr('enp0s8'))


if __name__ == "__main__":
    main()
synthesizerpatel
źródło
36

netifaces to dobry moduł do pobrania adresu MAC (i innych adresów). Jest wieloplatformowy i ma nieco więcej sensu niż użycie gniazda lub uuid.

>>> import netifaces
>>> netifaces.interfaces()
['lo', 'eth0', 'tun2']

>>> netifaces.ifaddresses('eth0')[netifaces.AF_LINK]
[{'addr': '08:00:27:50:f2:51', 'broadcast': 'ff:ff:ff:ff:ff:ff'}]

kamflan
źródło
Używana osobiście, wymaga określonej instalacji / kompilacji w każdym systemie, ale działa dobrze.
Aatch
22

Inną rzeczą, na którą powinieneś zwrócić uwagę, jest to, że uuid.getnode()może sfałszować adres MAC, zwracając losową 48-bitową liczbę, która może nie być tym, czego oczekujesz. Ponadto nie ma wyraźnego wskazania, że ​​adres MAC został sfałszowany, ale można go wykryć, dzwoniąc getnode()dwukrotnie i sprawdzając, czy wynik się różni. Jeśli oba wywołania zwracają tę samą wartość, masz adres MAC, w przeciwnym razie otrzymujesz fałszywy adres.

>>> print uuid.getnode.__doc__
Get the hardware address as a 48-bit positive integer.

    The first time this runs, it may launch a separate program, which could
    be quite slow.  If all attempts to obtain the hardware address fail, we
    choose a random 48-bit number with its eighth bit set to 1 as recommended
    in RFC 4122.
mhawke
źródło
8
Nie chodzi o to, że wartość 8 wynosi 1 właśnie dlatego, że nie może być używana przez kartę sieciową. Wystarczy sprawdzić ten bit, aby wykryć, czy adres jest fałszywy, czy nie.
Frédéric Grosshans
15
Sprawdzenie jest wykonywane za pomocą: if (mac >> 40)% 2: raise OSError, "Wygląda na to, że system nie ma prawidłowego adresu MAC"
Frédéric Grosshans
17

Czasami mamy więcej niż jeden interfejs sieciowy.

Prostą metodą znalezienia adresu MAC konkretnego interfejsu jest:

def getmac(interface):

  try:
    mac = open('/sys/class/net/'+interface+'/address').readline()
  except:
    mac = "00:00:00:00:00:00"

  return mac[0:17]

wywołanie metody jest proste

myMAC = getmac("wlan0")
Julio Schurt
źródło
2
Niezbyt przydatne w systemie OS X lub Windows. : |
RandomInsano,
1
Idealne dla Pis!
MikeT
8

Korzystając z mojej odpowiedzi tutaj: https://stackoverflow.com/a/18031868/2362361

Byłoby ważne, aby wiedzieć, do którego adresu MAC chcesz mieć adres MAC, ponieważ może istnieć wiele (bluetooth, kilka kart sieciowych itp.).

Wykonuje to zadanie, gdy znasz adres IP, do którego potrzebujesz adresu MAC, używając netifaces(dostępne w PyPI):

import netifaces as nif
def mac_for_ip(ip):
    'Returns a list of MACs for interfaces that have given IP, returns None if not found'
    for i in nif.interfaces():
        addrs = nif.ifaddresses(i)
        try:
            if_mac = addrs[nif.AF_LINK][0]['addr']
            if_ip = addrs[nif.AF_INET][0]['addr']
        except IndexError, KeyError: #ignore ifaces that dont have MAC or IP
            if_mac = if_ip = None
        if if_ip == ip:
            return if_mac
    return None

Testowanie:

>>> mac_for_ip('169.254.90.191')
'2c:41:38:0a:94:8b'
kursancew
źródło
6

Możesz to zrobić za pomocą psutil, który jest wieloplatformowy:

import psutil
nics = psutil.net_if_addrs()
print [j.address for j in nics[i] for i in nics if i!="lo" and j.family==17]
Nowicjusz w Pythonie
źródło
import socketnastępnie [addr.address for n in nics for addr in nics[n] if n == 'enp4s0' and addr.family == socket.AF_PACKET]skutkuje['ab:cd:ef:01:02:03']
Donn Lee
3

Zauważ, że możesz zbudować własną bibliotekę wieloplatformową w Pythonie, używając importu warunkowego. na przykład

import platform
if platform.system() == 'Linux':
  import LinuxMac
  mac_address = LinuxMac.get_mac_address()
elif platform.system() == 'Windows':
  # etc

Umożliwi to korzystanie z wywołań os.system lub bibliotek specyficznych dla platformy.

John Fouhy
źródło
2
to naprawdę nie jest odpowiedź - tylko komentarz
Stefano
1

Cross-platform getmac pakiet będzie działać na tym, jeśli nie masz nic przeciwko biorąc na uzależnienia. Działa z Pythonem 2.7+ i 3.4+. Spróbuje wielu różnych metod, dopóki nie uzyska adresu lub nie zwróci None.

from getmac import get_mac_address
eth_mac = get_mac_address(interface="eth0")
win_mac = get_mac_address(interface="Ethernet 3")
ip_mac = get_mac_address(ip="192.168.0.1")
ip6_mac = get_mac_address(ip6="::1")
host_mac = get_mac_address(hostname="localhost")
updated_mac = get_mac_address(ip="10.0.0.1", network_request=True)

Zastrzeżenie: jestem autorem pakietu.

Aktualizacja (14 stycznia 2019 r.): Pakiet obsługuje teraz tylko Python 2.7+ i 3.4+. Nadal możesz używać starszej wersji pakietu, jeśli potrzebujesz pracować ze starszym Pythonem (2.5, 2.6, 3.2, 3.3).

Ghost of Goes
źródło
1

Aby uzyskać eth0adres MAC interfejsu,

import psutil

nics = psutil.net_if_addrs()['eth0']

for interface in nics:
   if interface.family == 17:
      print(interface.address)
Balaji Reddy
źródło
0

Nie znam jednolitego sposobu, ale oto coś, co może Ci się przydać:

http://www.codeguru.com/Cpp/IN/network/networkinformation/article.php/c5451

To, co zrobiłbym w tym przypadku, byłoby zawinięciem ich w funkcję i na podstawie systemu operacyjnego uruchomiłoby odpowiednie polecenie, przeanalizowałoby zgodnie z wymaganiami i zwróciło tylko adres MAC sformatowany tak, jak chcesz. Oczywiście jest tak samo, z wyjątkiem tego, że musisz to zrobić tylko raz i wygląda bardziej czysto od głównego kodu.

W zasadzie niegroźny
źródło
0

W przypadku Linuksa przedstawię skrypt powłoki, który pokaże adres mac i umożliwi jego zmianę (sniffing MAC).

 ifconfig eth0 | grep HWaddr |cut -dH -f2|cut -d\  -f2
 00:26:6c:df:c3:95

Wytnij argumenty mogą odrzucić (nie jestem ekspertem) spróbować:

ifconfig etho | grep HWaddr
eth0      Link encap:Ethernet  HWaddr 00:26:6c:df:c3:95  

Aby zmienić MAC możemy zrobić:

ifconfig eth0 down
ifconfig eth0 hw ether 00:80:48:BA:d1:30
ifconfig eth0 up

zmieni adres mac na 00: 80: 48: BA: d1: 30 (tymczasowo przywróci aktualny adres po ponownym uruchomieniu).

Sarath Sadasivan Pillai
źródło
6
Czy to ma coś wspólnego z pytaniem?
bot47
-1

Alternatywnie,

import uuid
mac_id=(':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff)
Ajay Kumar KK
źródło
-8

W systemie Linux adres MAC można pobrać za pomocą ioctl SIOCGIFHWADDR.

struct ifreq    ifr;
uint8_t         macaddr[6];

if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0)
    return -1;

strcpy(ifr.ifr_name, "eth0");

if (ioctl(s, SIOCGIFHWADDR, (void *)&ifr) == 0) {
    if (ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
        memcpy(macaddr, ifr.ifr_hwaddr.sa_data, 6);
        return 0;
... etc ...

Oznaczyłeś pytanie „python”. Nie znam istniejącego modułu Pythona, aby uzyskać te informacje. Możesz użyć ctypes do bezpośredniego wywołania ioctl.

DGentry
źródło
8
-1 On chce roztworu pytona, więc idź i podaj mu ten sam zwrócony roztwór C otynkowany w całej sieci.
Aatch