Pure-Python package to get the MAC address of network interfaces and hosts on the local network.
It provides a platform-independent interface to get the MAC addresses of:
- System network interfaces (by interface name)
- Remote hosts on the local network (by IPv4/IPv6 address or hostname)
It provides one primary function, get_mac_address(), and a command line tool, getmac.
The full documentation is at https://ghostofgoes.github.io/getmac/, including the usage guide, the command line reference, troubleshooting, and how to upgrade from 0.9.x.
The commands from the recording are also written out in Terminal examples.
- Pure-Python (no compiled C-extensions required!)
- Python 3.9+, on CPython and PyPy
- Lightweight, with no dependencies and a relatively small package size
- Supports most platforms: Windows, Linux, macOS, the BSDs, Solaris and illumos, HP-UX, Android, WSL, and Docker (see Platforms currently supported)
- Provides a simple command line tool
- MIT licensed!
If you only need the addresses of network interfaces, have a limited set of platforms to support, and are able to handle C-extension modules, then you should instead check out the excellent netifaces package by Alastair Houghton (@al45tair). It's significantly faster (thanks to it being C code) and has been around a long time and seen widespread usage. Unfortunately, it hasn't been maintained since May 2021 (the last commit to netifaces), so it may not be a great choice for new projects. Another great option that fits these requirements is the well-known and battle-hardened psutil package by Giampaolo Rodola.
If the only system you need to run on is Linux, you can run as root, and C-extension modules are fine, then you should instead check out the arpreq package by Sebastian Schrader. In some cases it can be significantly faster.
If you want to use psutil, scapy, or netifaces, I have examples of how to do so in my Gist on using psutil, scapy, and netifaces.
Python 3.9+, CPython and PyPy, no dependencies. Older Pythons (3.8 and older) need an older version of getmac.
pip install getmacAlpha, beta, and release candidate versions are published to PyPI before a stable release. pip skips them unless you pass the --pre flag:
pip install --pre getmacpip install https://github.com/ghostofgoes/getmac/archive/main.tar.gzapt may have it available, depending on your distro (see packaging status below):
sudo apt install getmacA Docker image of the getmac command is published to the GitHub Container Registry for linux/amd64 and linux/arm64. The container runs getmac as an unprivileged user (nobody), and any arguments are passed to it.
docker run --rm ghcr.io/ghostofgoes/getmac --help
docker run --rm ghcr.io/ghostofgoes/getmac --version
docker run --rm ghcr.io/ghostofgoes/getmac -n localhostThe latest tag is the newest stable release, and releases are also tagged with their version (e.g. 1.0.0, 1.0, and 1). Pre-releases are only tagged with their version. The edge tag is built from the main branch.
By default the container is on Docker's bridge network, so it sees its own interfaces and ARP table, not the host's. On Linux, use --network host to look up the host's interfaces. In bridge mode, add -v /proc/1/net/arp:/host/arp:ro -e ARP_PATH=/host/arp to read the host's ARP table. With Docker Desktop on macOS and Windows, the container only sees the Docker VM's network, not your computer's. IPv6 lookups (-6) need a Docker network with IPv6 enabled.
docker run --rm --network host ghcr.io/ghostofgoes/getmac
docker run --rm -v /proc/1/net/arp:/host/arp:ro -e ARP_PATH=/host/arp ghcr.io/ghostofgoes/getmac -4 192.168.0.1To build the image yourself, see the Docker section of the contribution guide.
If you are running an old Python (3.8 and older) or interpreter, then you can install an older version of getmac that supported that version. The wheels are available in the GitHub releases, or from PyPI with a current version of pip and some special arguments.
- Python 2.5:
get-mac==0.5.0 - Python 2.6:
getmac==0.6.0 - Python 2.7:
getmac<1.0.0 - Python 3.2:
get-mac==0.3.0 - Python 3.3:
get-mac==0.3.0 - Python 3.4:
getmac<1.0.0 - Python 3.5:
getmac<1.0.0 - Python 3.6:
getmac<1.0.0 - Python 3.7:
getmac<1.0.0 - Python 3.8:
getmac<1.0.0
NOTE: these versions do not have many of the performance improvements, platform support, and bug fixes that came with later releases. They generally work, just not as well. However, if you're using such an old Python, you probably don't care about all that :)
from getmac import get_mac_address, settings
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="fe80::1")
host_mac = get_mac_address(hostname="home.router")
updated_mac = get_mac_address(ip="10.0.0.1", network_request=True)
# Enable debugging
settings.DEBUG = 2 # DEBUG level 2
print(get_mac_address(interface="Ethernet 3"))
# Change the UDP port used for updating the ARP table (UDP packet)
settings.PORT = 44444 # Default is 55555
print(get_mac_address(ip="192.168.0.1", network_request=True))
# After sending the UDP packet, keep checking the ARP table for the host for up to
# 1 second, since it can take a moment to reply. Default is 0 (check once).
settings.ARP_TIMEOUT = 1.0
print(get_mac_address(ip="192.168.0.1"))
# Get the name of the system's default network interface
from getmac import get_default_interface
print(get_default_interface())getmac --help
getmac --version
# Invoking with no arguments will return MAC of the default interface
getmac
# Usage as a module
python3 -m getmac
# On Windows, `getmac` may run the built-in getmac.exe instead of this package, so use
# `py -m getmac` or put your Python Scripts folder on PATH. More at
# https://ghostofgoes.github.io/getmac/troubleshooting.html#windows-runs-the-wrong-getmac
# Interface names, IPv4/IPv6 addresses, or Hostnames can be specified
getmac --interface ens33
getmac --ip 192.168.0.1
getmac --ip6 fe80::1
getmac --hostname home.router
# Running as a Python module with shorthands for the arguments
python -m getmac -i 'Ethernet 4'
python -m getmac -4 192.168.0.1
python -m getmac -6 fe80::1
python -m getmac -n home.router
# Getting the MAC address of a remote host requires the ARP table to be populated.
# By default, getmac will populate the table by sending a UDP packet to a high port on the host (defaults to 55555).
# This can be disabled with --no-net (or -N), as shown here:
getmac --no-net --ip 192.168.0.1
python -m getmac -N -n home.router
# Enable output messages
getmac --verbose
# Debug levels can be specified with '-d'
getmac -v --debug
python -m getmac -v -d -i enp11s4
python -m getmac -v -dd -n home.router
# Change the UDP port used for populating the ARP table when getting the MAC of a remote host
getmac --ip 192.168.0.1 --override-port 9001
# Keep checking the ARP table for the host for up to 1 second after sending the UDP packet
getmac --ip 192.168.0.1 --arp-timeout 1
# Stop commands that getmac runs (e.g. arp) after 5 seconds instead of the default 15, and try the next method
getmac --ip 192.168.0.1 --command-timeout 5
# The platform detected by getmac can be overridden via '--override-platform'.
# This is useful when debugging issues or if you know a method
# for a different platform works on the current platform.
# Any values returned by platform.system() are valid.
getmac -i eth0 --override-platform linux
getmac --ip 192.168.0.1 --override-platform windows
# Print the name of the default interface (e.g. "eth0"), instead of its MAC
getmac --default-interface
# Exclude one or more methods
getmac -i eth0 --exclude-method SysIfaceFile
getmac -i eth0 --exclude-method SysIfaceFile --exclude-method ArpFile
# List the methods for this platform, in the order getmac tries them, and which ones work here
getmac --list-methods
# Force a specific method to be used, regardless of the consequences or if it even works
getmac -v -dddd --ip 192.168.0.1 --force-method ctypeshostThe MAC is printed to stdout and the exit code is 0. If nothing was found, nothing is printed and the exit code is 1. Bad arguments (e.g. using two lookup options at once) exit with 2. Log messages (-v) go to stderr.
interface: Name of a network interface on the systemip: IPv4 address of a remote hostip6: IPv6 address of a remote hosthostname: Hostname of a remote hostnetwork_request: If a network request should be made to update and populate the ARP/NDP table of remote hosts used to lookup MACs in most circumstances. Disable this if you want to just use what's already in the table, or if you have requirements to prevent network traffic.- The network request is an empty UDP packet sent to a high port,
55555by default. This can be changed by settinggetmac.settings.PORTto the desired integer value. - If
arpingis installed (Linux and macOS), or on Windows, an ARP request is sent instead of the UDP packet (IPv4 only). On Linux, the ARP table file is read first, and nothing is sent if it has a complete entry for the host. - With no arguments on Windows, getmac connects a UDP socket to
1.1.1.1:53to find the IP of the default interface (Note: the IP is CloudFlare's DNS server). Nothing is sent, since connecting a UDP socket only picks a route. Skipped withnetwork_request=False.
- The network request is an empty UDP packet sent to a high port,
Only one of the first four arguments can be used at a time. network_request does nothing with interface (so it's safe to set in a script). With ip, ip6 and hostname, it allows the ARP request or UDP packet. With no arguments, it only matters on Windows, for the socket step above. ip and ip6 also accept objects from the standard library's ipaddress module (IPv4Address, IPv4Interface, IPv6Address, IPv6Interface), and all four accept bytes (decoded as UTF-8).
Some things worth knowing:
- If none of the arguments are selected, the default network interface for the system will be used. If the default network interface cannot be determined (for example, if there aren't any routes) or doesn't have a MAC (for example, a VPN tunnel), then the first interface that has a MAC and isn't a loopback interface is used. If there isn't one,
Noneis returned. On Windows, only the default interface is used, and with network requests enabled, the IP of the default interface is found first (a UDP socket is connected to1.1.1.1:53, but nothing is sent) and looked up as a host. hostname="localhost"(-n localhost) andip="127.0.0.1"(-4 127.0.0.1) return"00:00:00:00:00:00", the MAC of the loopback interface. Other spellings, such as::1,127.0.0.2,LOCALHOST, or the host's own name, aren't short-circuited and returnNone.- Most exceptions are handled silently and returned as
None. If you run into problems, setDEBUGto1or higher (or usegetmac -v -ddddon the command line) to get more information about what's happening. If you're still having issues, check the troubleshooting guide, then please create an issue on GitHub and include the output withDEBUGenabled. - As of 1.0.0, a
RuntimeErroris raised if no methods match the type of request and platform, or if all matching methods fail their test (in other words, none of them work). On a platform getmac doesn't know, it falls back to generic methods and still shows aRuntimeWarningwhen it does. AValueErroris raised for anipaddressnetwork (e.g.IPv4Network), since getmac needs a host, not a network. - The first call is slower than the rest. getmac checks which methods work on your system the first time it needs one, and remembers the result for the rest of the process.
Settings are attributes of getmac.settings (from getmac import settings). Set them before calling get_mac_address().
logging.getLogger("getmac"): Runtime messages and errors are recorded to thegetmaclogger using Python's logging module. They can be configured by using logging.basicConfig() or adding handlers to the"getmac"logger.settings.DEBUG: integer value that controls debugging output. The higher the value, the more output you get (0is the default,4is roughly the highest).settings.PORT: UDP port used to populate the ARP/NDP table (see the documentation of thenetwork_requestargument inget_mac_address()for details). Default is55555.settings.ARP_TIMEOUT: How long to keep checking the ARP/NDP table for a host after sending the UDP packet, in seconds. The host's entry is only added once it replies, which can take longer than getmac takes to check. Default is0(check once, without waiting). Lookups of hosts that don't reply take this much longer.settings.COMMAND_TIMEOUT: How long to wait for a command that getmac runs (such asarporipconfig.exe) to finish, in seconds. A command that takes longer is stopped, and the next method is tried. Default is15.Noneor0waits for as long as the command takes.settings.OVERRIDE_PLATFORM: Override the platform detection with the given value (e.g."linux","windows","freebsd", etc.). Any value returned byplatform.system()is valid.settings.FORCE_METHOD: Force a specific method to be used, e.g."IpNeighborShow". This will be used regardless of its method type or platform compatibility, andMethod.test()will NOT be checked! The list of available methods is ingetmac.getmac.METHODS(and in the API reference).ARP_PATH(environment variable): The file to read the ARP table from, instead of/proc/net/arp. Linux only, and read when getmac is imported. Useful in containers.
The platforms page lists the methods getmac tries on each platform, in order, and the API reference documents each method.
- Windows
- Commands:
getmac.exe,ipconfig.exe,arp.exe,netsh.exe,wmic.exe - Libraries:
ctypes,socket - Default interfaces:
netsh.exe
- Commands:
- Linux/Unix
- Commands:
arp,ip,ifconfig,netstat,ip link,arping(iputils, Habets', and BusyBox variants) - Libraries:
fcntl,socket - Files:
/sys/class/net/{iface}/address,/proc/net/arp - Default interfaces:
/proc/net/route,route,ip route list
- Commands:
- HP-UX:
- Commands:
lanscan
- Commands:
- macOS (Darwin)
- Commands:
networksetup,arping,ndp(IPv6 hosts) - Many of the same commands as Linux
- Commands:
- WSL1
- Unix commands and files are used for interfaces
- Windows
arp.exeis used for IPv4 hosts
- WSL2
- The same as Linux
- OpenBSD
- Commands:
ifconfig,arp,ndp(IPv6 hosts) - Default interfaces:
route
- Commands:
- FreeBSD
- Commands:
ifconfig,arp,ndp(IPv6 hosts) - Default interfaces:
route,netstat
- Commands:
- NetBSD
- Commands:
ifconfig,arp,ndp(IPv6 hosts) - Default interfaces:
route
- Commands:
- DragonFly BSD
- Commands:
ifconfig,arp,ndp(IPv6 hosts) - Default interfaces:
route
- Commands:
- Solaris and illumos
- Commands:
dladm,netstat,ifconfig,arp - Default interfaces:
route
- Commands:
- Android
- The same commands and files as Linux, where they're available. See the note on Android below.
All or almost all features should work on "supported" platforms. While other versions of the same family or distro may work, they are untested and may have bugs or missing features.
- Windows
- Desktop: 7, 8, 8.1, 10, 11 (thanks @StevenLooman for testing Windows 11!)
- Server: 2025, 2022
- Partially supported (untested): 2000, XP, Vista
- Linux distros
- CentOS/RHEL 6+
- Ubuntu 16.04+ (15.10 and older should work, but are untested)
- Fedora (24+)
- macOS (Darwin)
- The latest release, though macOS 14 and 13 have been tested with success.
- Android (6+)
- Windows Subsystem for Linux (WSL)
- FreeBSD (11+)
- OpenBSD
- NetBSD (9.3+)
- DragonFly BSD (6.4+)
- Oracle Solaris 11.4
- illumos distros: OmniOS (r151054+), OpenIndiana (2026.04+). Others like SmartOS should work, but are untested.
- HP-UX (untested): interface lookups only, via
lanscan - Docker
- BusyBox (not technically a platform, but several of the methods work on this platform)
- "Remote hosts" refer to hosts in your local layer 2 network, also commonly referred to as a "broadcast domain", "LAN", or "VLAN". As far as I know, there is not a reliable method to get a MAC address for a remote host external to the LAN. If you know any methods otherwise, please open a GitHub issue or shoot me an email, I'd love to be wrong about this.
- The physical transport is assumed to be Ethernet or Wi-Fi. Others, such as Bluetooth or cellular, may work, but they're untested. I'm definitely open to pull requests or issues related to this, including error reports.
- The accuracy and reliability of the MAC address retrieval may vary depending on the network configuration, the target host's settings, and other factors.
- Platform coverage is limited to what's under Platforms currently supported.
- Linux, WSL: Getting the mac of a local interface IP does not currently work (
getmac --ip 10.0.0.4will fail if10.0.0.4is the IP address of a local interface). This issue may be present on other POSIX systems as well. - Hostnames for IPv6 devices are not yet supported.
- WSL1: remote IPv6 hosts aren't supported yet. Windows'
arp.exeis used for IPv4 hosts, andnetsh.exeisn't used on WSL1 yet. - IPv6 link-local addresses can carry a zone (
fe80::1%en0orfe80::1%2), but only macOS and the BSDs and Solaris and illumos use it. On Linux and Windows, pass the address without a zone. - Windows:
ipconfig.exe(a fallback for whengetmac.exedoesn't work) only finds interfaces by name in English output, since the adapter headers are translated. - IPv6 support is good but lags behind IPv4 in some places and isn't as well-tested across the supported platform set.
- Platform test coverage is imperfect. If you're having issues, then you might be using a platform I haven't been able to test. Keep calm, open a GitHub issue, and I'd be more than happy to help.
The Python standard library has a robust set of networking functionality, such as urllib, ipaddress, ftplib, telnetlib, ssl, and more. Imagine my surprise, then, when I discovered there was not a way to get a seemingly simple piece of information: a MAC address. This package was born out of a need to get the MAC address of hosts on the network without needing admin permissions, and a cross-platform way get the addresses of local interfaces.
In Fall 2018 the package name changed to getmac from get-mac. This affected the package name, the CLI script, and some of the documentation. There were no changes to the core library code. While both package names will updated on PyPI, the use of getmac is preferred.
In Summer 2020, the code was significantly refactored, moving to a class-based structure and significantly improving performance and accuracy. See rewrite.md for details.
Contributors are more than welcome! See the contribution guide to get started, and checkout the todo list for a full list of tasks and bugs. If you want to add support for a new command or platform, there's a guide to adding a new method.
Before submitting a PR, please make sure you've completed the pull request checklist!
The Python Discord server is a good place to ask questions or discuss the project (handle: @knownerror).
- Christopher Goes (@ghostofgoes) - Author and maintainer
- Calvin Tran (@cyberhobbes) - Windows interface detection improvements
- Daniel Flanagan (@FlantasticDan) - Code cleanup
- @emadmahdi - Android fixes
- Izra Faturrahman (@Frizz925) - Unit tests using the platform samples
- Jose Gonzalez (@Komish) - Docker container and Docker testing
- @fortunate-man - Awesome usage videos
- @martmists - legacy Python compatibility improvements
- @hargoniX - scripts and specfiles for RPM packaging
- Ville Skyttä (@scop) - arping lookup support
- Tomasz Duda (@tomaszduda23) - support for docker in network bridge mode
- Steven Looman (@StevenLooman) - Windows 11 testing
- Reimund Renner (@raymanP) - macOS fixes
- Simone Chemelli (@chemelli74) - py.typed the library
Many of the methods used to acquire an address and the core logic framework are attributed to the CPython project's UUID implementation.
- https://github.com/python/cpython/blob/master/Lib/uuid.py
- https://github.com/python/cpython/blob/2.7/Lib/uuid.py
- _unix_fcntl_by_interface
- _windows_get_remote_mac_ctypes
- String joining
- Facter - Command output examples from Facter are leveraged for better test coverage
- GLPI Agent - Command output examples from GLPI Agent are leveraged for better test coverage
- Ansible - NetBSD
ifconfig -aoutput from Ansible's unit tests is leveraged for better test coverage - Ohai - FreeBSD
route -n get defaultoutput from Chef Ohai's specs is leveraged for better test coverage - jackpal/gateway - FreeBSD
netstat -rnoutput from its route tables is leveraged for better test coverage
The code is licensed MIT. The test data contains Apache 2.0, BSD 3-Clause, GPLv2, and GPLv3 (Ansible) licensed files, in the tests/samples/third_party/ directory. These files are not included in the packages published to PyPI.