[python] Getting MAC Address

I need a cross platform method of determining the MAC address of a computer at run time. For windows the 'wmi' module can be used and the only method under Linux I could find was to run ifconfig and run a regex across its output. I don't like using a package that only works on one OS, and parsing the output of another program doesn't seem very elegant not to mention error prone.

Does anyone know a cross platform method (windows and linux) method to get the MAC address? If not, does anyone know any more elegant methods then those I listed above?

This question is related to python windows linux networking

The answer is


Python 2.5 includes an uuid implementation which (in at least one version) needs the mac address. You can import the mac finding function into your own code easily:

from uuid import getnode as get_mac
mac = get_mac()

The return value is the mac address as 48 bit integer.


One other thing that you should note is that uuid.getnode() can fake the MAC addr by returning a random 48-bit number which may not be what you are expecting. Also, there's no explicit indication that the MAC address has been faked, but you could detect it by calling getnode() twice and seeing if the result varies. If the same value is returned by both calls, you have the MAC address, otherwise you are getting a faked address.

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

Alternatively,

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

netifaces is a good module to use for getting the mac address (and other addresses). It's crossplatform and makes a bit more sense than using socket or 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'}]


For Linux let me introduce a shell script that will show the mac address and allows to change it (MAC sniffing).

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

Cut arguements may dffer (I am not an expert) try:

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

To change MAC we may do:

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

will change mac address to 00:80:48:BA:d1:30 (temporarily, will restore to actual one upon reboot).


The cross-platform getmac package will work for this, if you don't mind taking on a dependency. It works with Python 2.7+ and 3.4+. It will try many different methods until either getting a address or returning 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)

Disclaimer: I am the author of the package.

Update (Jan 14 2019): the package now only supports Python 2.7+ and 3.4+. You can still use an older version of the package if you need to work with an older Python (2.5, 2.6, 3.2, 3.3).


The pure python solution for this problem under Linux to get the MAC for a specific local interface, originally posted as a comment by vishnubob and improved by on Ben Mackey in 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')

This is the Python 3 compatible code:

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

You can do this with psutil which is cross-platform:

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]

To get the eth0 interface MAC address,

import psutil

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

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

Note that you can build your own cross-platform library in python using conditional imports. e.g.

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

This will allow you to use os.system calls or platform-specific libraries.


Sometimes we have more than one net interface.

A simple method to find out the mac address of a specific interface, is:

def getmac(interface):

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

  return mac[0:17]

to call the method is simple

myMAC = getmac("wlan0")

For Linux you can retrieve the MAC address using a 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 ...

You've tagged the question "python". I don't know of an existing Python module to get this information. You could use ctypes to call the ioctl directly.


Using my answer from here: https://stackoverflow.com/a/18031868/2362361

It would be important to know to which iface you want the MAC for since many can exist (bluetooth, several nics, etc.).

This does the job when you know the IP of the iface you need the MAC for, using netifaces (available in 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

Testing:

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

I dont know of a unified way, but heres something that you might find useful:

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

What I would do in this case would be to wrap these up into a function, and based on the OS it would run the proper command, parse as required and return only the MAC address formatted as you want. Its ofcourse all the same, except that you only have to do it once, and it looks cleaner from the main code.


Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to windows

"Permission Denied" trying to run Python on Windows 10 A fatal error occurred while creating a TLS client credential. The internal error state is 10013 How to install OpenJDK 11 on Windows? I can't install pyaudio on Windows? How to solve "error: Microsoft Visual C++ 14.0 is required."? git clone: Authentication failed for <URL> How to avoid the "Windows Defender SmartScreen prevented an unrecognized app from starting warning" XCOPY: Overwrite all without prompt in BATCH Laravel 5 show ErrorException file_put_contents failed to open stream: No such file or directory how to open Jupyter notebook in chrome on windows Tensorflow import error: No module named 'tensorflow'

Examples related to linux

grep's at sign caught as whitespace How to prevent Google Colab from disconnecting? "E: Unable to locate package python-pip" on Ubuntu 18.04 How to upgrade Python version to 3.7? Install Qt on Ubuntu Get first line of a shell command's output Cannot connect to the Docker daemon at unix:/var/run/docker.sock. Is the docker daemon running? Run bash command on jenkins pipeline How to uninstall an older PHP version from centOS7 How to update-alternatives to Python 3 without breaking apt?

Examples related to networking

Access HTTP response as string in Go Communication between multiple docker-compose projects Can't access 127.0.0.1 How do I delete virtual interface in Linux? ConnectivityManager getNetworkInfo(int) deprecated Bridged networking not working in Virtualbox under Windows 10 Difference between PACKETS and FRAMES How to communicate between Docker containers via "hostname" java.net.ConnectException: failed to connect to /192.168.253.3 (port 2468): connect failed: ECONNREFUSED (Connection refused) wget: unable to resolve host address `http'