简体   繁体   English

获取 MAC 地址

[英]Getting MAC Address

I need a cross platform method of determining the MAC address of a computer at run time.我需要一种在运行时确定计算机 MAC 地址的跨平台方法。 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.对于 windows,可以使用“wmi”模块,在 Linux 下,我能找到的唯一方法是运行 ifconfig 并在其 output 上运行正则表达式。我不喜欢使用仅适用于一个操作系统的 package,并解析 output另一个程序似乎不太优雅,更不用说容易出错了。

Does anyone know a cross platform method (windows and linux) method to get the MAC address?有谁知道获取MAC地址的跨平台方法(windows和linux)方法? If not, does anyone know any more elegant methods then those I listed above?如果没有,有没有人知道比我上面列出的方法更优雅的方法?

Python 2.5 includes an uuid implementation which (in at least one version) needs the mac address. Python 2.5 包含一个 uuid 实现,它(至少在一个版本中)需要 mac 地址。 You can import the mac finding function into your own code easily:您可以轻松地将 mac 查找功能导入到您自己的代码中:

from uuid import getnode as get_mac
mac = get_mac()

The return value is the mac address as 48 bit integer.返回值为 48 位整数的 mac 地址。

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 Linux 下此问题的纯 python 解决方案,用于获取特定本地接口的 MAC,最初由 vishnubob 作为评论发布,并由 Ben Mackey 在此 activestate 配方中改进

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

netifaces is a good module to use for getting the mac address (and other addresses). netifaces是一个很好的模块,用于获取 mac 地址(和其他地址)。 It's crossplatform and makes a bit more sense than using socket or uuid.它是跨平台的,比使用套接字或 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'}]

Sometimes we have more than one net interface.有时我们有不止一个网络接口。

A simple method to find out the mac address of a specific interface, is:找出特定接口的mac地址的简单方法是:

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")

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.您应该注意的另一件事是uuid.getnode()可以通过返回一个随机的 48 位数字来伪造 MAC 地址,这可能不是您所期望的。 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.此外,没有明确指示 MAC 地址已被伪造,但您可以通过调用getnode()两次并查看结果是否变化来检测它。 If the same value is returned by both calls, you have the MAC address, otherwise you are getting a faked address.如果两个调用都返回相同的值,则您拥有 MAC 地址,否则您将获得伪造的地址。

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

Using my answer from here: https://stackoverflow.com/a/18031868/2362361使用我的回答: 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.).重要的是要知道您想要 MAC 用于哪个接口,因为可以存在许多接口(蓝牙、多个 nic 等)。

This does the job when you know the IP of the iface you need the MAC for, using netifaces (available in PyPI):当您使用netifaces (在 PyPI 中可用)知道需要 MAC 的 iface 的 IP 时,这可以完成工作:

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'

You can do this with psutil which is cross-platform:您可以使用跨平台的 psutil 执行此操作:

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]

Note that you can build your own cross-platform library in python using conditional imports.请注意,您可以使用条件导入在 python 中构建自己的跨平台库。 eg例如

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.这将允许您使用 os.system 调用或特定于平台的库。

The cross-platform getmac package will work for this, if you don't mind taking on a dependency.如果您不介意依赖依赖,跨平台的getmac包将适用于此。 It works with Python 2.7+ and 3.4+.它适用于 Python 2.7+ 和 3.4+。 It will try many different methods until either getting a address or returning None.它将尝试许多不同的方法,直到获得地址或返回 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+.更新(2019 年 1 月 14 日):该包现在仅支持 Python 2.7+ 和 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).如果您需要使用较旧的 Python(2.5、2.6、3.2、3.3),您仍然可以使用较旧版本的包。

To get the eth0 interface MAC address,要获取eth0接口 MAC 地址,

import psutil

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

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

nice actually return a dictionary within the dictionary it returns a list and within the list, it returns a staple. nice实际上在字典中返回一个字典,它返回一个列表,在列表中,它返回一个订书钉。 but nics['Ethernet'][0].address iteration solve the problem.但是nics['Ethernet'][0].address迭代解决了这个问题。

import psutil

nics = psutil.net_if_addrs()

mac_address = nics['Ethernet'][0].address

print(mac_address)

I dont know of a unified way, but heres something that you might find useful:我不知道统一的方式,但这里有一些你可能会觉得有用的东西:

http://www.codeguru.com/Cpp/IN/network/networkinformation/article.php/c5451 http://www.codeguru.com/Cpp/IN/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.在这种情况下,我要做的是将它们包装成一个函数,并根据操作系统运行正确的命令,根据需要进行解析并仅返回您想要格式化的 MAC 地址。 Its ofcourse all the same, except that you only have to do it once, and it looks cleaner from the main code.它当然都是一样的,除了你只需要做一次,而且从主代码看起来更干净。

This cross-platform code does not 100% work on Windows. This works on Windows:跨平台代码并非 100% 适用于 Windows。这适用于 Windows:

import psutil
print([(k, addr.address) for k, v in psutil.net_if_addrs().items() for addr in v if addr.family == -1])

Example:例子:

[
    ('Local Area Connection', '01-23-45-67-89-0A'), 
    ('Wireless Network Connection', '23-45-67-89-0A-BC'), 
    ('Bluetooth Network Connection', '45-67-89-0A-BC-DE'), 
    ('isatap.{01ABCDEF-0123-4567-890A-0123456789AB}', '00-00-00-00-00-00-00-01')
]

Alternatively,或者,

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

For Linux let me introduce a shell script that will show the mac address and allows to change it (MAC sniffing).对于 Linux,让我介绍一个 shell 脚本,它将显示 mac 地址并允许更改它(MAC 嗅探)。

 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:要更改 MAC,我们可以这样做:

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).将 mac 地址更改为 00:80:48:BA:d1:30 (暂时,将在重新启动时恢复为实际地址)。

For Linux you can retrieve the MAC address using a SIOCGIFHWADDR ioctl.对于 Linux,您可以使用 SIOCGIFHWADDR ioctl 检索 MAC 地址。

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".您已将问题标记为“python”。 I don't know of an existing Python module to get this information.我不知道现有的 Python 模块可以获取此信息。 You could use ctypes to call the ioctl directly.您可以使用ctypes直接调用 ioctl。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM