Получение MAC-адреса
Мне нужен кроссплатформенный метод определения MAC-адреса компьютера во время выполнения. Для windows можно использовать модуль 'wmi', и единственный метод под Linux, который я смог найти, - это запустить ifconfig и запустить регулярное выражение в выходных данных. Мне не нравится использовать пакет, который работает только на одной ОС, и анализ выходных данных другой программы выглядит не очень элегантно, не говоря уже о подверженности ошибкам.
Кто-нибудь знает метод кросс-платформенный (Windows и Linux), чтобы получить MAC-адрес? Если нет, знает ли кто-нибудь более изящные методы, чем те, которые я перечислил выше?
17 ответов
Python 2.5 включает в себя реализацию uuid, которой (по крайней мере, в одной версии) нужен MAC-адрес. Вы можете легко импортировать функцию поиска Mac в свой собственный код:
from uuid import getnode as get_mac
mac = get_mac()
Возвращаемым значением является MAC-адрес как 48-битное целое число.
Чистое решение Python для этой проблемы под Linux, чтобы получить MAC для определенного локального интерфейса, первоначально опубликованный в качестве комментария vishnubob и улучшенный Беном Макки в этом рецепте activestate
#!/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')
netifaces - хороший модуль для получения MAC-адреса (и других адресов). Он кроссплатформенный и имеет больше смысла, чем использование сокетов или 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'}]
Иногда у нас более одного сетевого интерфейса.
Простой способ узнать MAC-адрес определенного интерфейса:
def getmac(interface):
try:
mac = open('/sys/class/net/'+interface+'/address').readline()
except:
mac = "00:00:00:00:00:00"
return mac[0:17]
вызвать метод просто
myMAC = getmac("wlan0")
Еще одна вещь, которую вы должны отметить, это то, что uuid.getnode()
может подделать MAC-адрес, возвращая случайное 48-битное число, которое может не соответствовать ожидаемому. Кроме того, нет явного указания на то, что MAC-адрес был подделан, но вы можете обнаружить его, позвонив getnode()
дважды и увидим, если результат меняется. Если оба вызова возвращают одно и то же значение, у вас есть MAC-адрес, в противном случае вы получаете поддельный адрес.
>>> 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.
Используя мой ответ отсюда: /questions/1734947/python-poluchit-mac-adres-tolko-podklyuchennogo-lokalnogo-setevogo-adaptera/1734969#1734969
Было бы важно знать, для какого iface вы хотите MAC, поскольку многие могут существовать (Bluetooth, несколько сетевых карт и т. Д.).
Это делает работу, когда вы знаете IP-адрес iface, для которого вам нужен MAC, используя netifaces
(доступно в 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
Тестирование:
>>> mac_for_ip('169.254.90.191')
'2c:41:38:0a:94:8b'
Вы можете сделать это с помощью psutil, который является кроссплатформенным:
import psutil
mac_addresses = []
nics = psutil.net_if_addrs()
nics.pop('lo') # remove loopback since it doesnt have a real mac address
for i in nics:
for j in nics[i]:
if j.family == 17: # AF_LINK
mac_addresses.append(j.address)
Кроссплатформенный пакет getmac будет работать для этого, если вы не возражаете против зависимости. Работает с Python 2.6+ и 3.2+. Он будет пытаться использовать много разных методов, пока либо не получит адрес, либо вернет 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)
Отказ от ответственности: я являюсь автором пакета.
Обратите внимание, что вы можете создать свою собственную кроссплатформенную библиотеку в Python, используя условный импорт. например
import platform
if platform.system() == 'Linux':
import LinuxMac
mac_address = LinuxMac.get_mac_address()
elif platform.system() == 'Windows':
# etc
Это позволит вам использовать системные вызовы os.s или библиотеки для конкретной платформы.
Для Linux позвольте мне представить скрипт оболочки, который покажет MAC-адрес и позволит изменить его (MAC-сниффинг).
ifconfig eth0 | grep HWaddr |cut -dH -f2|cut -d\ -f2
00:26:6c:df:c3:95
Вырезать аргументы могут (я не эксперт) попробовать:
ifconfig etho | grep HWaddr
eth0 Link encap:Ethernet HWaddr 00:26:6c:df:c3:95
Чтобы изменить MAC, мы можем сделать:
ifconfig eth0 down
ifconfig eth0 hw ether 00:80:48:BA:d1:30
ifconfig eth0 up
изменит MAC-адрес на 00:80:48:BA:d1:30 (временно, после перезагрузки вернется к фактическому).
Чтобы получить eth0
MAC-адрес интерфейса,
import psutil
nics = psutil.net_if_addrs()['eth0']
for interface in nics:
if interface.family == 17:
print(interface.address)
Этот кроссплатформенный код не на 100% работает в Windows. Это работает в Windows:
import psutil
print([(k, addr.address) for k, v in psutil.net_if_addrs().items() for addr in v if addr.family == -1])
Пример:
[
('Local Area Connection', '01-23-45-67-89-0A'),
('Wireless Network Connection', '23-45-67-89-0A-BC'),
('Bluetooth Network Connection', '45-67-89-0A-BC-DE'),
('isatap.{01ABCDEF-0123-4567-890A-0123456789AB}', '00-00-00-00-00-00-00-01')
]
nice на самом деле возвращает словарь в словаре, он возвращает список, а в списке он возвращает скобу. но итерация nics['Ethernet'][0].address решает проблему.
import psutil
nics = psutil.net_if_addrs()
mac_address = nics['Ethernet'][0].address
print(mac_address)
Чтобы получить MAC-адрес в виде 48-битного целого числа, можно использоватьuuid.getnode()
:
import uuid
uuid.getnode()
12345678901234
Чтобы отформатировать это как шестнадцатеричную строку, разделенную двоеточиями, вы можете использовать
":".join(f"{b:02x}" for b in uuid.getnode().to_bytes(6))
0b:3a:73:ce:2f:f2
Я не знаю единого пути, но вот кое-что, что вы могли бы найти полезным:
http://www.codeguru.com/Cpp/I-N/network/networkinformation/article.php/c5451
В этом случае я хотел бы заключить их в функцию, и в зависимости от ОС он будет запускать правильную команду, анализировать при необходимости и возвращать только MAC-адрес, отформатированный так, как вы хотите. Это, конечно, само собой, за исключением того, что вам нужно сделать это только один раз, и это выглядит чище из основного кода.
С другой стороны,
import uuid
mac_id=(':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff)
Для Linux вы можете получить MAC-адрес, используя SIOCGIFHWADDR ioctl.
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 ...
Вы пометили вопрос "питон". Я не знаю существующего модуля Python, чтобы получить эту информацию. Вы можете использовать ctypes для прямого вызова ioctl.