Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
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:
It provides one function: get_mac_address()
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. However, unfortunately it is no longer maintained as of May 2021, 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-extensions 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 a GitHub Gist.
Stable release from PyPI
pip install getmac
Latest development version
pip install https://github.com/ghostofgoes/getmac/archive/main.tar.gz
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)
# Enable debugging
from getmac import getmac
getmac.DEBUG = 2 # DEBUG level 2
print(getmac.get_mac_address(interface="Ethernet 3"))
# Change the UDP port used for updating the ARP table (UDP packet)
from getmac import getmac
getmac.PORT = 44444 # Default is 55555
print(getmac.get_mac_address(ip="192.168.0.1", network_request=True))
Python 2 users: use getmac2
or python -m getmac
instead of getmac
.
getmac --help
getmac --version
# Invoking with no arguments will return MAC of the default interface
getmac
# Usage as a module
python3 -m getmac
# Interface names, IPv4/IPv6 addresses, or Hostnames can be specified
getmac --interface ens33
getmac --ip 192.168.0.1
getmac --ip6 ::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 ::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-network-request, as shown here:
getmac --no-network-request --ip 192.168.0.1
python -m getmac --no-network-request -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
# 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
# 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 ctypeshost
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 an 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 a empty UDP packet sent to a high port, 55555
by default. This can be changed by setting getmac.PORT
to the desired integer value. Additionally, on Windows, this will send a UDP packet to 1.1.1.1:53
to attempt to determine the default interface (Note: the IP is CloudFlare's DNS server).logging.getLogger("getmac")
: Runtime messages and errors are recorded to the getmac
logger using Python's logging module. They can be configured by using logging.basicConfig() or adding handlers to the "getmac"
logger.getmac.getmac.DEBUG
: integer value that controls debugging output. The higher the value, the more output you get.getmac.getmac.PORT
: UDP port used to populate the ARP/NDP table (see the documentation of the network_request
argument in get_mac_address()
for details)getmac.getmac.OVERRIDE_PLATFORM
: Override the platform detection with the given value (e.g. "linux"
, "windows"
, "freebsd"
, etc.'). Any values returned by platform.system()
are valid.getmac.getmac.FORCE_METHOD
: Force a specific method to be used, e.g. 'IpNeighborShow'. This will be used regardless of it's method type or platform compatibility, and Method.test()
will NOT be checked! The list of available methods is in getmac.getmac.METHODS
.If you are running a old Python (2.6/3.3 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.
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 :)
Ethernet
on Windows, em0
on BSD, en0
on OSX/Darwin, and eth0
otherwise). If that fails, then it will fallback to lo
on POSIX systems.network_request
does not have any functionality when the interface
argument is specified, and can be safely set if using in a script.DEBUG
to true and get more information about what's happening. If you're still having issues, please create an issue on GitHub and include the output with DEBUG
enabled.getmac.exe
, ipconfig.exe
, arp.exe
, wmic.exe
uuid
, ctypes
, socket
arp
, ip
, ifconfig
, netstat
, ip link
, lanscan
uuid
, fcntl
, socket
/sys/class/net/{iface}/address
, /proc/net/arp
/proc/net/route
, route
, ip route list
networksetup
ifconfig
, arp
route
ifconfig
, arp
netstat
ip link
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.
Add -v /proc/1/net/arp:/host/arp -e ARP_PATH=/host/arp
to access arp table of host inside container in bridge network mode.
docker build -f packaging/Dockerfile -t getmac .
docker run -it getmac:latest --help
docker run -it getmac:latest --version
docker run -it getmac:latest -n localhost
docker run --rm -it -v /proc/1/net/arp:/host/arp -e ARP_PATH=/host/arp getmac:latest -n 192.168.0.1
getmac --ip 10.0.0.4
will fail if 10.0.0.4
is the IP address of a local interface). This issue may be present on other POSIX systems as well.network_request
is enabled. If not, Ethernet
is used as the default.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 docs/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.
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#0001).
Many of the methods used to acquire an address and the core logic framework are attributed to the CPython project's UUID implementation.
MIT. Feel free to copy, modify, and use to your heart's content. Enjoy :)
NOTE: if any changes significantly impact your project or use case, please open an issue on GitHub or email me (see git commit author info for address).
Announcement: Compatibility with Python versions older than 3.7 (2.7, 3.4, 3.5, and 3.6) is deprecated and will be removed in getmac 1.0.0. If you are stuck on an unsupported Python, consider loosely pinning the version of this package in your dependency list, e.g. getmac<1.0.0
or getmac~=0.9.0
.
This release is a complete rewrite of getmac from the ground up. The public API of getmac
is unchanged as part of this rewrite. get_mac_address()
is still the primary way of getting a MAC address, it's just the "under the hood" internals that have changed completely.
It's passing tests and seems to be operable. However, with a change this large there are inevitably issues that the tests or I don't catch, so I'm doing a series of pre-releases until I'm 99% confident in it's stability. Refer to docs/rewrite.md
for a in-depth explanation of the rewrite changes.
The new system has a number of benefits
route get default
)sunos
(Which applies to any system where platform.system() == SunOS
).arping
(POSIX) or SendARP
(Windows) will now always be used instead of sending a UDP packet when looking for the MAC of a IPv4 host, if they're available and operable (otherwise, UDP + ARP table check will be used like before).DEBUG>=1
or -d
)--override-port
(this was already possible in Python via getmac.getmac.PORT
, but wasn't configurable via the CLI. Now it is!).--override-platform
argument (CLI) or getmac.getmac.OVERRIDE_PLATFORM
variable (Python). This will force methods for that platform to be used, regardless of the actual platform. Here's an example forcing linux
to be used as the platform: getmac -i eth0 --override-platform linux
. In version 1.0.0, this feature will added as an argument to get_mac_address()
.--force-method
argument (CLI) or getmac.getmac.FORCE_METHOD
variable (Python). This is useful for troubleshooting issues, general debugging, and testing changes. Example: getmac -v -dddd --ip 192.168.0.1 --force-method ctypeshost
getmac
from the ground up. Refer to docs/rewrite.md
for a in-depth explanation of the rewrite changesNone
, as expected, instead of raising an exception (socket.gaierror
).netstat
on older Linux distros (such as Ubuntu 12.04)ifconfig
parsing. It should now be far more reliable and accurate across all platforms.root
)./proc/net/route
parsing (this affected Android and potentially other platforms)route get default
)getmac.1
/getmac2.1
). They were severely out of date and unused. May re-add at a later date.flake8-pytest-style
and flake8-annotations
packaging/rpm/
. This stuff hasn't been updated since 0.6.0, may remove in the future and leave distro packaging to distro maintainers.arping
in addition to the existing iputils one (contributed by Ville Skyttä (@scop) in #52 and #54)arping
as last resortvulture
, several Flake8 pluginsip
or ip6
were used,
which could lead to a ResourceWarning
(GH-42)print
(logger: getmac
)--no-network-requests
: -N
and --no-net
-v
/--verbose
RuntimeWarning
pytest
netifaces
, psutil
, scapy
, and arpreq
).
This should improve the performance of lookups of non-existent interfaces
or hosts, since this feature was punishing that path without providing much value.
If you want to use these packages directly, I have a guide on how to do so on a
GitHub Gist.warnings
module will only be imported if a error/warning
occurs (improve compatibility with some freezers, notably PyInstaller)pytest
for all tests now instead of unittest
network_request
is enabled (Credit: @cyberhobbes)getmac
. This applies to the
command line tool, GitHub, and the documentation.__future__
getmac.getmac.DEBUG
.argparse
if Python version is 2.6 or olderarp
arpreq
packagewmic nic
get_mac_address(ip='10.0.0.100')
was 1.71 seconds.
Now, the average is 12.7 miliseconds
, with the special case of a unpopulated
arp table being only slightly higher. This was brought about by changes in
how the arp table is populated. The original method was to use the
host's ping
command to send an ICMP packet to the host. This took time,
which heavily delayed the ability to actually get an address. The solution
is to instead simply send a empty UDP packet to a high port. The port
this packet is sent to can be configured using the module variable getmac.PORT
.getmac.py
psutil
: Interface MACs on all platformsscapy
: Interface MACs and Remote MACs on all platformsnetifaces
: Interface MACs on Non-Windows platformsip neighbor show
, Abuse of uuid._arp_getnode()
lanscan -ai
(HP-UX)ip6
argument (IPv6 addresses)proc/net/arp
would return shorter addresses in the
same subnet if they came earlier in the sequence. Example: a search for
192.168.16.2
on Linux would instead return the MAC address of
192.168.16.254
with no errors or warning whatsoever.ip
or route
commands available, or the
netifaces
Python module.Nothing changed. PyPI just won't let me push changes without a new version.
--debug
-d
option from --no-network-requests
get-mac
python -m getmac
arp_request
argument was renamed to network_request
FAQs
Get MAC addresses of remote hosts and local interfaces
We found that get-mac demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.