使用Python获取设备的MAC地址

25

我想找到一种使用Python从本地网络上的设备获取第二层地址的方法。已知第三层地址。

目标是构建一个脚本,定期轮询IP地址数据库以确保MAC地址未更改,并在更改时向自己发送电子邮件警报。


他正在避免不必要的ARP,而不是在本地机器上检查东西。仔细阅读问题:来自我本地网络上的设备 - Jed Smith
这里有许多可能有帮助的答案!如何在Python中获取eth0的IP地址? - uhoh
8个回答

23

用Python回答这个问题取决于你的平台。我手边没有Windows,所以以下解决方案适用于我编写它的Linux系统。将正则表达式进行小改动即可在OS X上运行。

首先,你必须ping目标。只要目标在你的子网掩码内,它就会出现在你的系统ARP缓存中(在这种情况下听起来是这样)。观察:

13:40 jsmith@undertow% ping 97.107.138.15
PING 97.107.138.15 (97.107.138.15) 56(84) bytes of data.
64 bytes from 97.107.138.15: icmp_seq=1 ttl=64 time=1.25 ms
^C

13:40 jsmith@undertow% arp -n 97.107.138.15
Address                  HWtype  HWaddress           Flags Mask            Iface
97.107.138.15            ether   fe:fd:61:6b:8a:0f   C                     eth0

明白了这一点,你可以运用一些子进程的技巧--否则你就要自己编写ARP缓存检查代码,而你不想这样做:

>>> from subprocess import Popen, PIPE
>>> import re
>>> IP = "1.2.3.4"

>>> # do_ping(IP)
>>> # The time between ping and arp check must be small, as ARP may not cache long

>>> pid = Popen(["arp", "-n", IP], stdout=PIPE)
>>> s = pid.communicate()[0]
>>> mac = re.search(r"(([a-f\d]{1,2}\:){5}[a-f\d]{1,2})", s).groups()[0]
>>> mac
"fe:fd:61:6b:8a:0f"

2
哈,那正是我正在写的答案! - Nick Craig-Wood
1
如果你没有arp(OpenWRT没有),但有ip-neighbour包(可以在OpenWRT上安装),那么你可以使用以下命令获取“pid”的值:pid = Popen(["ip", "neigh", "show", IP], stdout=PIPE) - David Poxon
在树莓派 Zero 上运行了这段代码。在命令终端中输入时找不到 arp,但是可以找到。 - MathCrackExchange

7
在这个网站上不久之前有一个类似的问题(相似问题)得到了解答。正如该问题的提问者选择的答案中所提到的,Python没有内置的方法来执行此操作。您必须调用系统命令,例如arp来获取ARP信息,或者使用Scapy生成自己的数据包。 编辑: 从其网站上使用Scapy的示例:

这是另一个工具,将不断监视机器上的所有接口,并打印它看到的所有ARP请求,甚至可以在监视模式下的Wi-Fi卡的802.11帧上进行。请注意,使用store=0参数来避免将所有数据包存储在内存中。

#! /usr/bin/env python
from scapy import *

def arp_monitor_callback(pkt):
    if ARP in pkt and pkt[ARP].op in (1,2): #who-has or is-at
        return pkt.sprintf("%ARP.hwsrc% %ARP.psrc%")

sniff(prn=arp_monitor_callback, filter="arp", store=0)

您还可以类似于已验证的答案执行某些操作。请参见https://scapy.readthedocs.io/en/latest/routing.html

>>> mac = getmacbyip("10.0.0.1")
>>> mac
'f3:ae:5e:76:31:9b'

这是完全跨平台的。

虽然不完全符合你的要求,但已经朝着正确的方向发展。享受吧!


3

在Linux中,有时候你会错过命令行工具“arp”,比如在基于yocto的嵌入式环境中。

如果没有“arp”工具,另一种替代方法是读取和解析文件/proc/net/arp:

root@raspberrypi:~# cat /proc/net/arp
IP address       HW type     Flags       HW address            Mask     Device
192.168.1.1      0x1         0x2         xx:xx:xx:xx:xx:xx     *        wlan0
192.168.1.33     0x1         0x2         yy:yy:yy:yy:yy:yy     *        wlan0

3
使用scapy扫描192.168.0.0/24子网的简单解决方案如下:
from scapy.all import *

ans,unans = arping("192.168.0.0/24", verbose=0)
for s,r in ans:
    print("{} {}".format(r[Ether].src,s[ARP].pdst))

2
听起来你想监控ARP欺骗者?在这种情况下,你只需要使用arpwatch,它可以在你附近每个配备良好的Linux发行版中找到。从这里下载源代码:http://ee.lbl.gov/

2

针对基于Unix系统的操作:

#!/usr/bin/env python2.7

import re
import subprocess
arp_out =subprocess.check_output(['arp','-lan'])

re.findall(r"((\w{2,2}\:{0,1}){6})",arp_out)

将返回包含MAC地址元组的列表。 Scapy是一种非常棒的工具,但似乎对于这种情况来说有点过于复杂。


1

如果在Linux系统上,更简单的方法是:

print os.system('arp -n ' + str(remoteIP))

你将会得到:

    Address        HWtype  HWaddress           Flags Mask            Iface
    192.168.....   ether   9B:39:15:f2:45:51   C                     wlan0

0

Python 3.7 的一般更新。注意:在 Windows 系统上,选项 -n 对于 arp 不会像在某些 Linux 系统中提供的那样提供 arp 列表。请使用此处答案中所述的选项 -a

from subprocess import Popen, PIPE

pid = Popen(['arp', '-a', ip], stdout=PIPE, stderr=PIPE)

IP, MAC, var = ((pid.communicate()[0].decode('utf-8').split('Type\r\n'))[1]).split('     ')
IP  =  IP.strip(' ')
MAC =  MAC.strip(' ')

if ip == IP:
    print ('Remote Host : %s\n        MAC : %s' % (IP, MAC))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接