Получение MAC-адреса
Мне нужен кросс-платформенный способ определения MAC-адреса компьютера во время выполнения. Для windows можно использовать модуль "wmi", и единственным методом в Linux, который я мог найти, было запустить ifconfig и запустить регулярное выражение на его выходе. Мне не нравится использовать пакет, который работает только на одной ОС, и разбор вывода другой программы не кажется очень элегантным, не говоря уже об ошибке.
кто-нибудь знает кросс-платформенный метод (windows и linux) для получения MAC адрес? Если нет, то знает ли кто-нибудь более элегантные методы, чем те, которые я перечислил выше?
12 ответов:
Python 2.5 включает реализацию uuid, которая (по крайней мере, в одной версии) нуждается в mac-адресе. Вы можете легко импортировать функцию поиска mac в свой собственный код:
from uuid import getnode as get_mac mac = get_mac()
возвращаемое значение-это mac-адрес в виде 48-битного целого числа.
чистое решение python для этой проблемы под Linux, чтобы получить MAC для конкретного локального интерфейса, первоначально опубликованного в качестве комментария vishnubob и улучшенного на Ben Mackey в этот рецепт 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'}]
еще одна вещь, которую вы должны отметить, что
uuid.getnode()
может подделать Mac addr, возвращая случайное 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.
иногда у нас есть более одного сетевого интерфейса.
простой способ узнать 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")
используя мой ответ отсюда:https://stackoverflow.com/a/18031868/2362361
было бы важно знать, к какому 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'
обратите внимание, что вы можете создать свою собственную кросс-платформенную библиотеку в python, используя условный импорт. например,
import platform if platform.system() == 'Linux': import LinuxMac mac_address = LinuxMac.get_mac_address() elif platform.system() == 'Windows': # etc
Это позволит вам использовать ОС.системные вызовы или библиотеки для конкретной платформы.
для Linux позвольте мне представить сценарий оболочки, который покажет mac-адрес и позволит его изменить (MAC sniffing).
ifconfig eth0 | grep HWaddr |cut -dH -f2|cut -d\ -f2 00:26:6c:df:c3:95
вырезать аргументы может dffer (я не эксперт) попробуйте:
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 (временно, восстановится до фактического при перезагрузке).
Я не знаю единого способа, но вот что вы можете найти полезным:
http://www.codeguru.com/Cpp/I-N/network/networkinformation/article.php/c5451
то, что я бы сделал в этом случае, было бы обернуть их в функцию, и на основе ОС он будет запускать соответствующую команду, анализировать по мере необходимости и возвращать только MAC-адрес, отформатированный так, как вы хотите. Его, конечно, все равно, за исключением того, что вам нужно сделать это только один раз, и это выглядит очиститель от основного кода.
вы можете сделать это с 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+. Он будет пробовать много различных методов, пока либо не получит адрес, либо не вернет его.
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)
отказ от ответственности: я являюсь автором пакета.
для 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". Я не знаю существующего модуля Python, чтобы получить эту информацию. Вы могли бы использовать ctypes для прямого вызова ioctl.