2008-10-01 37 views
85

Necesito un método multiplataforma para determinar la dirección MAC de una computadora en tiempo de ejecución. Para Windows se puede usar el módulo 'wmi' y el único método bajo Linux que pude encontrar fue ejecutar ifconfig y ejecutar una expresión regular a través de su salida. No me gusta usar un paquete que solo funcione en un sistema operativo, y analizar el resultado de otro programa no parece muy elegante, por no mencionar que es propenso a errores.Obteniendo la dirección MAC

¿Alguien sabe un método de plataforma cruzada (Windows y Linux) para obtener la dirección MAC? Si no, ¿alguien sabe métodos más elegantes que los que enumeré arriba?

Respuesta

123

Python 2.5 incluye una implementación de uuid que (en al menos una versión) necesita la dirección MAC. Puede importar el mac función de búsqueda en su propio código fácilmente:

from uuid import getnode as get_mac 
mac = get_mac() 

El valor de retorno es la dirección MAC como un entero de 48 bits.

+16

Acabo de probar esto en una caja de Windows y funciona muy bien ... excepto que la computadora portátil que probé tiene 2 NIC (una inalámbrica) y no hay manera de determinar qué MAC devolvió. Solo una palabra de advertencia si quieres usar este código. – technomalogical

+1

Esa es una función del enumerador de dispositivo de Windows, cualquiera que sea el método que use para obtener la dirección: debe tener cuidado si lo usa como una ID única. –

+15

Solo una advertencia: si nos fijamos en la documentación 'getnode' dice que devolverá una longitud aleatoria si no puede detectar el mac:" Si todos los intentos de obtener la dirección de hardware fallan, seleccionamos aleatoria de 48 bits número con su octavo bit puesto a 1 como se recomienda en RFC 4122. " ¡Así que revisa ese octavo bit! – deinonychusaur

19

netifaces es un buen módulo para usar para obtener la dirección MAC (y otras direcciones). Es una plataforma cruzada y tiene más sentido que usar socket o 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'}] 

+0

Utilizado personalmente, requiere una instalación/compilación específica en cada sistema pero funciona bien. – Aatch

1

No sé de una manera unificada, pero aquí está algo que le puede resultar útil:

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

Lo que haría en este caso sería ajustar esto en una función, y basado en el sistema operativo ejecutaría el comando correcto, analizar según sea necesario y devolver solo la dirección MAC formateada como desee. Por supuesto, es lo mismo, excepto que solo tienes que hacerlo una vez, y se ve más limpio desde el código principal.

-6

Para Linux puede recuperar la dirección MAC utilizando un 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 ... 

Has etiquetado la pregunta "python". No sé de un módulo de Python existente para obtener esta información. Puede usar ctypes para llamar al ioctl directamente.

+5

-1 Quiere una solución de python, así que ve y dale la misma solución de C regurgitada enlucida en toda la web. – Aatch

+11

Culpable como cargado. Es por eso que existen votaciones negativas. – DGentry

3

Tenga en cuenta que puede crear su propia biblioteca multiplataforma en python utilizando importaciones condicionales. p.ej.

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

Esto le permitirá utilizar las llamadas al sistema os o las bibliotecas específicas de la plataforma.

19

Otra cosa que debes tener en cuenta es que uuid.getnode() puede falsificar el código MAC devolviendo un número aleatorio de 48 bits que puede no ser el que estás esperando. Además, no hay ninguna indicación explícita de que la dirección MAC haya sido falsificada, pero puede detectarla llamando al getnode() dos veces y ver si el resultado varía. Si ambas llamadas devuelven el mismo valor, usted tiene la dirección MAC, de lo contrario recibirá una dirección falsa.

>>> 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. 
+2

No es que el valor de 8 sea 1 precisamente porque no puede ser usado por una tarjeta de red. Solo ver este bit es suficiente para detectar si la dirección es falsa o no. –

+11

La comprobación se acaba de hacer con: if (mac >> 40)% 2: raise OSError, "El sistema no parece tener un MAC válido" –

70

La solución Python puro para este problema en Linux para obtener el MAC de una interfaz local específico, originalmente publicado como un comentario de vishnubob y mejorado por el Ben Mackey en this activestate recipe

#!/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') 
2

Para Linux permítanme presentar un guión de shell que muestre la dirección MAC y permita cambiarla (olfateo MAC).

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

me lo quitaron cortados puede dffer (no soy un experto) Proveedores:

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

Para cambiar MAC podemos hacer:

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

cambiaremos la dirección MAC a 00:80: 48: BA: d1: 30 (temporalmente, restaurará a uno real al reiniciar).

+1

¿Tiene esto que ver con la pregunta? –

8

Usando mi respuesta desde aquí: https://stackoverflow.com/a/18031868/2362361

sería importante saber a qué iface de la que desea que el MAC para ya que muchos pueden existir (bluetooth, varias tarjetas de red, etc.).

Esto hace el trabajo cuando se conoce la IP del iface de lo que necesita el MAC para, usando netifaces (disponible en 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 

Pruebas:

>>> mac_for_ip('169.254.90.191') 
'2c:41:38:0a:94:8b' 
-1

para la solución de 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!' 

Uso:

print get_mac_id(ifname="eth0") 
+0

No es necesario generar una herramienta de envoltura externa, como ifconfig, para buscar este tipo de información. Este es de lejos el peor ejemplo aquí. – sleepycal

11

A veces tenemos más de una interfaz de red.

Un método simple para averiguar la dirección MAC de una interfaz específica, es decir:

def getmac(interface): 

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

    return mac[0:17] 

para llamar al método es simple

myMAC = getmac("wlan0") 
+0

No muy útil para OS X o Windows. : | – RandomInsano

1

Usted puede hacer esto con psutil que es cruzada plataforma:

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) 
Cuestiones relacionadas