Obtener la dirección MAC

111

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 en Linux que pude encontrar fue ejecutar ifconfig y ejecutar una expresión regular en su salida. No me gusta usar un paquete que solo funciona en un sistema operativo, y analizar la salida de otro programa no parece muy elegante, por no mencionar propenso a errores.

¿Alguien conoce un método multiplataforma (windows y linux) para obtener la dirección MAC? Si no es así, ¿alguien conoce algún método más elegante que los que enumeré anteriormente?

Mark Roddy
fuente
¡Aquí hay muchas respuestas potencialmente útiles! ¿Cómo puedo obtener la dirección IP de eth0 en Python?
uhoh

Respuestas:

160

Python 2.5 incluye una implementación uuid que (en al menos una versión) necesita la dirección mac. Puede importar la función de búsqueda de mac 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.

Armin Ronacher
fuente
25
Intenté esto en una caja de Windows y funciona muy bien ... excepto que la computadora portátil en la que lo probé tiene 2 NIC (una inalámbrica) y no hay forma de determinar qué MAC devolvió. Solo una advertencia si desea utilizar este código.
technomalogical
24
Solo una advertencia: si miras la getnodedocumentación, dice que devolverá un largo aleatorio si no detecta el mac: "Si todos los intentos de obtener la dirección de hardware fallan, elegimos un número aleatorio de 48 bits con su octavo bit establecido en 1 como se recomienda en RFC 4122. " ¡Así que revisa ese octavo bit!
deinonychusaur
27
hex(mac)para obtener el formato hexadecimal familiar del mac
screenshot345
43
O ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2))para un MAC en mayúsculas con cada byte separado por dos puntos.
tomlogic
5
getnode () devuelve algo diferente cada vez que reinicio mi computadora portátil con Windows 7.
nu Everest
80

La solución de Python pura para este problema en Linux para obtener el MAC para una interfaz local específica, originalmente publicado como un comentario por vishnubob y mejorado por Ben Mackey en esta receta de estado activo

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

Este es el código compatible con 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()
sintetizador
fuente
35

netifaces es un buen módulo para obtener la dirección mac (y otras direcciones). Es multiplataforma y tiene un poco más de 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'}]

camflan
fuente
Usado personalmente, requiere una instalación / compilación específica en cada sistema, pero funciona bien.
Aatch el
22

Otra cosa que debe tener en cuenta es que uuid.getnode()puede falsificar la dirección MAC devolviendo un número aleatorio de 48 bits que puede no ser lo que esperaba. Además, no hay ninguna indicación explícita de que la dirección MAC haya sido falsificada, pero podría detectarla llamando getnode()dos veces y viendo si el resultado varía. Si ambas llamadas devuelven el mismo valor, tienes la dirección MAC; de lo contrario, obtendrás 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.
mhawke
fuente
8
No es que el valor del octavo sea 1 precisamente porque no puede ser utilizado por una tarjeta de red. Basta con comprobar este bit para detectar si la dirección es falsa o no.
Frédéric Grosshans
15
La comprobación se acaba de hacer con: if (mac >> 40)% 2: raise OSError, "El sistema no parece tener una MAC válida"
Frédéric Grosshans
17

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:

def getmac(interface):

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

  return mac[0:17]

llamar al método es simple

myMAC = getmac("wlan0")
Julio Schurt
fuente
2
No es muy útil para OS X o Windows. : |
RandomInsano
1
¡Perfecto para Pis!
MikeT
8

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

Sería importante saber para qué iface quieres el MAC ya que pueden existir muchos (bluetooth, varios nics, etc.).

Esto funciona cuando conoce la IP del iface para el que necesita el MAC, 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'
kursancew
fuente
6

Puede hacer esto con psutil, que es multiplataforma:

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]
Principiante de Python
fuente
import socketluego [addr.address for n in nics for addr in nics[n] if n == 'enp4s0' and addr.family == socket.AF_PACKET]resulta en['ab:cd:ef:01:02:03']
Donn Lee
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 llamadas a os.system o bibliotecas específicas de la plataforma.

John Fouhy
fuente
2
eso no es realmente una respuesta, solo un comentario
Stefano
1

El paquete getmac multiplataforma funcionará para esto, si no le importa asumir una dependencia. Funciona con Python 2.7+ y 3.4+. Intentará muchos métodos diferentes hasta obtener una dirección o devolver Ninguno.

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)

Descargo de responsabilidad: soy el autor del paquete.

Actualización (14 de enero de 2019): el paquete ahora solo es compatible con Python 2.7+ y 3.4+. Aún puede usar una versión anterior del paquete si necesita trabajar con un Python anterior (2.5, 2.6, 3.2, 3.3).

Fantasma de Goes
fuente
1

Para obtener la eth0dirección MAC de la interfaz,

import psutil

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

for interface in nics:
   if interface.family == 17:
      print(interface.address)
Balaji Reddy
fuente
0

No conozco una forma unificada, pero aquí hay algo que puede resultarle útil:

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

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

Sobre todo inofensivo
fuente
0

Para Linux, permítanme presentarles un script de shell que mostrará la dirección mac y permitirá cambiarla (rastreo de MAC).

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

Los argumentos de corte pueden dffer (no soy un experto) intente:

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

cambiará la dirección mac a 00: 80: 48: BA: d1: 30 (temporalmente, se restaurará a la actual al reiniciar).

Sarath Sadasivan Pillai
fuente
6
¿Tiene esto que ver algo con la pregunta?
bot47
-1

Alternativamente,

import uuid
mac_id=(':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff)
Ajay Kumar KK
fuente
-8

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 conozco un módulo de Python existente para obtener esta información. Puede usar ctypes para llamar al ioctl directamente.

DGentrada
fuente
8
-1 Quiere una solución de pitón, así que ve y dale la misma solución de C regurgitada que se encuentra en toda la web.
Aatch el