Obtenir l'adresse MAC


111

J'ai besoin d'une méthode multiplateforme pour déterminer l'adresse MAC d'un ordinateur au moment de l'exécution. Pour Windows, le module 'wmi' peut être utilisé et la seule méthode sous Linux que j'ai pu trouver était d'exécuter ifconfig et d'exécuter une expression régulière sur sa sortie. Je n'aime pas utiliser un package qui ne fonctionne que sur un seul système d'exploitation, et l'analyse de la sortie d'un autre programme ne semble pas très élégante, sans parler des erreurs.

Est-ce que quelqu'un connaît une méthode multiplateforme (Windows et Linux) pour obtenir l'adresse MAC? Sinon, est-ce que quelqu'un connaît des méthodes plus élégantes que celles que j'ai énumérées ci-dessus?


Il existe de nombreuses réponses potentiellement utiles ici! Comment puis-je obtenir l'adresse IP de eth0 en Python?
uhoh

Réponses:


160

Python 2.5 inclut une implémentation uuid qui (dans au moins une version) a besoin de l'adresse mac. Vous pouvez facilement importer la fonction de recherche Mac dans votre propre code:

from uuid import getnode as get_mac
mac = get_mac()

La valeur de retour est l'adresse mac sous forme d'entier 48 bits.


25
Je viens de l'essayer sur une boîte Windows et cela fonctionne très bien ... sauf que l'ordinateur portable sur lequel je l'ai essayé a 2 cartes réseau (une sans fil) et qu'il n'y a aucun moyen de déterminer quel MAC il a renvoyé. Juste un mot d'avertissement si vous souhaitez utiliser ce code.
technomalogical

24
Juste un avertissement: si vous regardez la getnodedocumentation, elle indique qu'elle renverra un long aléatoire s'il ne parvient pas à détecter le mac: "Si toutes les tentatives pour obtenir l'adresse matérielle échouent, nous choisissons un nombre aléatoire de 48 bits avec son huitième bit mis à 1 comme recommandé dans la RFC 4122. " Alors vérifiez ce huitième bit!
deinonychusaur

27
hex(mac)pour obtenir le format hexadécimal familier du mac
capture d'

43
Ou ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2))pour un MAC en majuscule avec chaque octet séparé par un deux-points.
tomlogic

5
getnode () renvoie quelque chose de différent chaque fois que je redémarre mon ordinateur portable Windows 7.
nu everest

80

La solution pure python pour ce problème sous Linux pour obtenir le MAC pour une interface locale spécifique, initialement publiée en tant que commentaire par vishnubob et améliorée par sur Ben Mackey dans cette recette d'activation

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

Voici le code compatible 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()

35

netifaces est un bon module à utiliser pour obtenir l'adresse mac (et d'autres adresses). C'est crossplatform et cela a un peu plus de sens que d'utiliser socket ou 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'}]


Utilisé personnellement, nécessite une installation / compilation spécifique sur chaque système mais fonctionne bien.
Aatch le

22

Une autre chose que vous devez noter est que vous uuid.getnode()pouvez simuler l'adresse MAC en renvoyant un nombre aléatoire de 48 bits qui peut ne pas être ce que vous attendez. De plus, il n'y a aucune indication explicite que l'adresse MAC a été falsifiée, mais vous pouvez la détecter en appelant getnode()deux fois et en voyant si le résultat varie. Si la même valeur est renvoyée par les deux appels, vous avez l'adresse MAC, sinon vous obtenez une fausse adresse.

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

8
Non pas que la valeur du 8e soit 1 précisément parce qu'il ne peut pas être utilisé par une carte réseau. Il suffit de vérifier ce bit pour détecter si l'adresse est fausse ou non.
Frédéric Grosshans

15
La vérification est juste faite avec: if (mac >> 40)% 2: lever OSError, "Le système ne semble pas avoir de MAC valide"
Frédéric Grosshans

17

Parfois, nous avons plus d'une interface réseau.

Une méthode simple pour connaître l'adresse mac d'une interface spécifique est:

def getmac(interface):

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

  return mac[0:17]

appeler la méthode est simple

myMAC = getmac("wlan0")

2
Pas super utile pour OS X ou Windows. : |
RandomInsano

1
Parfait pour les Pis!
MikeT

8

En utilisant ma réponse d'ici: https://stackoverflow.com/a/18031868/2362361

Il serait important de savoir pour quelle iface vous voulez le MAC car beaucoup peuvent exister (bluetooth, plusieurs nics, etc.).

Cela fait le travail lorsque vous connaissez l'adresse IP de l'iface pour laquelle vous avez besoin du MAC, en utilisant netifaces(disponible dans 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

Essai:

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

6

Vous pouvez le faire avec psutil qui est multiplateforme:

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]

import socketpuis [addr.address for n in nics for addr in nics[n] if n == 'enp4s0' and addr.family == socket.AF_PACKET]résultats['ab:cd:ef:01:02:03']
Donn Lee

3

Notez que vous pouvez créer votre propre bibliothèque multiplateforme en python à l'aide d'importations conditionnelles. par exemple

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

Cela vous permettra d'utiliser des appels os.system ou des bibliothèques spécifiques à la plateforme.


2
ce n'est pas vraiment une réponse - juste un commentaire
Stefano

1

Le package getmac multiplateforme fonctionnera pour cela, si cela ne vous dérange pas de prendre une dépendance. Il fonctionne avec Python 2.7+ et 3.4+. Il essaiera de nombreuses méthodes différentes jusqu'à obtenir une adresse ou renvoyer Aucune.

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)

Avertissement: Je suis l'auteur du package.

Mise à jour (14 janvier 2019): le package ne prend désormais en charge que Python 2.7+ et 3.4+. Vous pouvez toujours utiliser une ancienne version du package si vous devez travailler avec un ancien Python (2.5, 2.6, 3.2, 3.3).


1

Pour obtenir l' eth0adresse MAC de l' interface,

import psutil

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

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

0

Je ne connais pas de manière unifiée, mais voici quelque chose que vous pourriez trouver utile:

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

Ce que je ferais dans ce cas serait de les envelopper dans une fonction, et en fonction du système d'exploitation, il exécuterait la commande appropriée, analyserait si nécessaire et ne renverrait que l'adresse MAC formatée comme vous le souhaitez. C'est bien sûr tout de même, sauf que vous ne devez le faire qu'une seule fois, et cela semble plus propre du code principal.


0

Pour Linux, permettez-moi d'introduire un script shell qui affichera l'adresse mac et permet de la changer (reniflage MAC).

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

Les arguments de coupe peuvent différer (je ne suis pas un expert) essayer:

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

Pour changer de MAC, nous pouvons faire:

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

changera l'adresse mac à 00: 80: 48: BA: d1: 30 (temporairement, restaure à l'adresse réelle au redémarrage).


6
Cela a-t-il quelque chose à voir avec la question?
bot47

-1

Alternativement,

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

-8

Pour Linux, vous pouvez récupérer l'adresse MAC à l'aide d'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 ...

Vous avez tagué la question "python". Je ne connais pas de module Python existant pour obtenir ces informations. Vous pouvez utiliser ctypes pour appeler l'ioctl directement.


8
-1 Il veut une solution python, alors vous allez lui donner la même solution C régurgitée plâtrée dans tout le web.
Aatch le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.