Получение MAC-адреса

Мне нужен кросс-платформенный метод определения MAC-адреса компьютера во время выполнения. Для окон можно использовать модуль "wmi", и единственным методом под Linux, который я смог найти, было запустить ifconfig и запустить регулярное выражение на его выходе. Мне не нравится использовать пакет, который работает только на одной ОС, и анализ вывода другой программы не выглядит очень элегантным, не говоря уже о склонности к ошибкам.

Кто-нибудь знает метод кросс-платформенного метода (windows и linux) для получения MAC-адреса? Если нет, кто-нибудь знает какие-либо более элегантные методы, чем те, которые я перечислял выше?

Ответ 1

Python 2.5 включает реализацию uuid, которая (по крайней мере, для одной версии) нуждается в адресе mac. Вы можете легко импортировать функцию поиска макросов в свой собственный код:

from uuid import getnode as get_mac
mac = get_mac()

Возвращаемое значение - это MAC-адрес как целое число 48 бит.

Ответ 2

Чистое решение 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')

Это 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()

Ответ 3

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'}]

Ответ 4

Еще одна вещь, которую вы должны отметить, заключается в том, что 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.

Ответ 5

Иногда у нас есть несколько сетевых интерфейсов.

Простым методом определения 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")

Ответ 6

Используя мой ответ отсюда: fooobar.com/questions/67917/...

Было бы важно знать, к какому iface вам нужен MAC, поскольку многие могут существовать (bluetooth, несколько nics и т.д.).

Это задание, когда вы знаете 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'

Ответ 7

Вы можете сделать это с помощью psutil, который является кроссплатформенным:

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]

Ответ 8

Обратите внимание, что вы можете создать свою собственную кросс-платформенную библиотеку в python, используя условный импорт. например.

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

Это позволит вам использовать вызовы os.system или библиотеки, специфичные для платформы.

Ответ 9

Кроссплатформенный пакет getmac будет работать для этого, если вы не возражаете против зависимости. Он работает с Python 2. 7+ и 3. 4+. Он будет пробовать много разных методов, пока не получит адрес или не вернет 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)

Отказ от ответственности: я являюсь автором пакета.

Обновление (14 января 2019 г.): теперь пакет поддерживает только Python 2. 7+ и 3. 4+. Вы все еще можете использовать более старую версию пакета, если вам нужно работать со старым Python (2.5, 2.6, 3.2, 3.3).

Ответ 10

Я не знаю об унифицированном способе, но вот что-то полезное:

http://www.codeguru.com/Cpp/I-N/network/networkinformation/article.php/c5451

Что бы я делал в этом случае, это было бы превратить их в функцию, и на основе ОС он выполнил бы правильную команду, проанализировал бы по мере необходимости и вернул бы только MAC-адрес, отформатированный так, как вы хотите. Конечно, все это происходит, за исключением того, что вам нужно сделать это только один раз, и он выглядит более чистым от основного кода.

Ответ 11

Для Linux позвольте мне представить оболочку script, которая покажет MAC-адрес и позволит его изменить (обнюхивание MAC).

 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 (временно, при перезагрузке он будет восстановлен до фактического).

Ответ 12

С другой стороны,

import uuid
mac_id=(':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff)

Ответ 13

Чтобы получить MAC-адрес интерфейса eth0,

import psutil

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

for interface in nics:
   if interface.family == 17:
      print(interface.address)

Ответ 14

для решения Linux

INTERFACE_NAME = "eth0"

#######################################
def get_mac_id(ifname=INTERFACE_NAME):

import commands

words = commands.getoutput("ifconfig " + ifname).split()
if "HWaddr" in words:
    return words[ words.index("HWaddr") + 1 ]
else:
    return 'No MAC Address Found!'

Использование:

print get_mac_id(ifname="eth0")

Ответ 15

Для 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.