Obtendo endereço MAC

111

Preciso de um método de plataforma cruzada para determinar o endereço MAC de um computador em tempo de execução. Para Windows, o módulo 'wmi' pode ser usado e o único método no Linux que consegui encontrar foi executar ifconfig e executar um regex em sua saída. Não gosto de usar um pacote que só funciona em um sistema operacional, e analisar a saída de outro programa não parece muito elegante, sem falar que é sujeito a erros.

Alguém conhece um método de plataforma cruzada (Windows e Linux) para obter o endereço MAC? Se não, alguém conhece métodos mais elegantes do que aqueles que listei acima?

Mark Roddy
fonte
Existem muitas respostas potencialmente úteis aqui! Como posso obter o endereço IP de eth0 em Python?
uhoh

Respostas:

160

Python 2.5 inclui uma implementação uuid que (em pelo menos uma versão) precisa do endereço mac. Você pode importar a função de localização do mac para seu próprio código facilmente:

from uuid import getnode as get_mac
mac = get_mac()

O valor de retorno é o endereço mac como um inteiro de 48 bits.

Armin Ronacher
fonte
25
Acabei de experimentar isso em uma caixa do Windows e funciona muito bem ... exceto que o laptop em que testei tem 2 NICs (uma sem fio) e não há como determinar qual MAC ele retornou. Apenas um aviso se você quiser usar este código.
tecnomalógico de
24
Apenas um aviso: Se você olhar a getnodedocumentação diz que retornará um longo aleatório se não conseguir detectar o mac: "Se todas as tentativas de obter o endereço de hardware falharem, escolhemos um número aleatório de 48 bits com seu oitavo bit definido como 1 conforme recomendado em RFC 4122. " Portanto, verifique o oitavo bit!
deinonychusaur
27
hex(mac)para obter o familiar formato hexadecimal do mac
screenshot345
43
Ou ':'.join(("%012X" % mac)[i:i+2] for i in range(0, 12, 2))para um MAC maiúsculo com cada byte separado por dois pontos.
tomlogic
5
getnode () retorna algo diferente toda vez que eu reinicio meu laptop windows 7.
nu everest
80

A solução python pura para este problema no Linux para obter o MAC para uma interface local específica, postada originalmente como um comentário por vishnubob e aprimorada por Ben Mackey nesta receita de estado ativo

#!/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 é o código compatível com 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()
synthesizerpatel
fonte
35

netifaces é um bom módulo a ser usado para obter o endereço mac (e outros endereços). É uma plataforma cruzada e faz mais sentido do que usar 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'}]

camflan
fonte
Usado pessoalmente, requer uma instalação / compilação específica em cada sistema, mas funciona bem.
Aatch
22

Outra coisa que você deve observar é que uuid.getnode()pode falsificar o endereço MAC retornando um número aleatório de 48 bits que pode não ser o que você esperava. Além disso, não há indicação explícita de que o endereço MAC foi falsificado, mas você pode detectá-lo chamando getnode()duas vezes e ver se o resultado varia. Se o mesmo valor for retornado por ambas as chamadas, você tem o endereço MAC, caso contrário, está recebendo um endereço falso.

>>> 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
fonte
8
Não que o valor do 8º seja 1 precisamente porque não pode ser usado por uma placa de rede. Basta verificar esse bit para detectar se o endereço é falso ou não.
Frédéric Grosshans
15
A verificação é feita apenas com: if (mac >> 40)% 2: raise OSError, "O sistema não parece ter um MAC válido"
Frédéric Grosshans
17

Às vezes, temos mais de uma interface de rede.

Um método simples para descobrir o endereço mac de uma interface específica é:

def getmac(interface):

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

  return mac[0:17]

chamar o método é simples

myMAC = getmac("wlan0")
Julio Schurt
fonte
2
Não é muito útil para OS X ou Windows. : |
RandomInsano
1
Perfeito para Pis!
MikeT
8

Usando minha resposta aqui: https://stackoverflow.com/a/18031868/2362361

Seria importante saber para qual iface você quer o MAC já que podem existir muitos (bluetooth, vários nics, etc.).

Isso funciona quando você sabe o IP do iface para o qual precisa do MAC, usando netifaces(disponível no 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

Teste:

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

Você pode fazer isso com o psutil, que é 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]
Python Novato
fonte
import socketem seguida, [addr.address for n in nics for addr in nics[n] if n == 'enp4s0' and addr.family == socket.AF_PACKET]resulta em['ab:cd:ef:01:02:03']
Donn Lee
3

Observe que você pode construir sua própria biblioteca de plataforma cruzada em python usando importações condicionais. por exemplo

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

Isso permitirá que você use chamadas os.system ou bibliotecas específicas da plataforma.

John Fouhy
fonte
2
isso não é realmente uma resposta - apenas um comentário
Stefano
1

O pacote getmac de plataforma cruzada funcionará para isso, se você não se importar em assumir uma dependência. Funciona com Python 2.7+ e 3.4+. Ele tentará muitos métodos diferentes até obter um endereço ou retornar Nenhum.

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)

Isenção de responsabilidade: eu sou o autor do pacote.

Atualização (14 de janeiro de 2019): o pacote agora oferece suporte apenas para Python 2.7+ e 3.4+. Você ainda pode usar uma versão mais antiga do pacote se precisar trabalhar com um Python mais antigo (2.5, 2.6, 3.2, 3.3).

Ghost of Goes
fonte
1

Para obter o eth0endereço MAC da interface,

import psutil

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

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

Não conheço uma forma unificada, mas aqui está algo que você pode achar útil:

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

O que eu faria nesse caso seria agrupá-los em uma função e, com base no sistema operacional, ele executaria o comando adequado, analisaria conforme necessário e retornaria apenas o endereço MAC formatado como você deseja. É claro que é tudo igual, exceto que você só precisa fazer isso uma vez, e parece mais limpo do código principal.

Quase inofensivo
fonte
0

Para o Linux, deixe-me apresentar um script de shell que mostrará o endereço mac e permite alterá-lo (farejamento de MAC).

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

Cortar argumentos pode ser diferente (não sou um especialista), tente:

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

Para alterar o MAC, podemos fazer:

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

mudará o endereço mac para 00: 80: 48: BA: d1: 30 (temporariamente, restaurará o endereço real na reinicialização).

Sarath Sadasivan Pillai
fonte
6
Isso tem a ver com a pergunta?
bot47
-1

Alternativamente,

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

Para Linux, você pode recuperar o endereço MAC usando um 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 ...

Você marcou a pergunta "python". Não conheço um módulo Python existente para obter essas informações. Você pode usar ctypes para chamar o ioctl diretamente.

DGentry
fonte
8
-1 Ele quer uma solução python, então você vai e dá a ele a mesma solução C regurgitada espalhada por toda a web.
Aatch