Obtain MAC Address from Devices using Python
I'm looking for a way (with python) to obtain the layer II
address from a device on my local network. Layer III
addresses are known.
The goal is to build a script that will poll a datab开发者_JS百科ases of IP addresses on regular intervals ensuring that the mac addresses have not changed and if they have, email alerts to myself.
To answer the question with Python depends on your platform. I don't have Windows handy, so the following solution works on the Linux box I wrote it on. A small change to the regular expression will make it work in OS X.
First, you must ping the target. That will place the target -- as long as it's within your netmask, which it sounds like in this situation it will be -- in your system's ARP cache. Observe:
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
Knowing that, you do a little subprocess magic -- otherwise you're writing ARP cache checking code yourself, and you don't want to do that:
>>> 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"
There was a similar question answered not too long ago on this site. As mentioned in the answer chosen by the asker of that question, Python doesn't have a built-in way to do it. You must either call a system command such as arp
to get ARP information, or generate your own packets using Scapy.
Edit: An example using Scapy from their website:
Here is another tool that will constantly monitor all interfaces on a machine and print all ARP request it sees, even on 802.11 frames from a Wi-Fi card in monitor mode. Note the store=0 parameter to sniff() to avoid storing all packets in memory for nothing.
#! /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)
You could also do something similar to the verified answer. See https://scapy.readthedocs.io/en/latest/routing.html
>>> mac = getmacbyip("10.0.0.1")
>>> mac
'f3:ae:5e:76:31:9b'
This is fully cross platform.
Not exactly what you're looking for, but definitely on the right track. Enjoy!
A simple solution using scapy, to scan the 192.168.0.0/24 subnet is as follows:
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))
Sounds like you want to monitor ARP spoofers? In this case, all you need is arpwatch, available in every well-supplied Linux distribution near you. Download sources here: http://ee.lbl.gov/
for Unix based systems:
#!/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)
will return list of tuples with macs. scapy is an amazing tool , but seems to be overkill for this case
In Linux sometimems you miss the command line util "arp". A base yocto linux embedded environment image for instance.
An alternative way without the "arp" tool would be to read and parse the file /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
an easier way, if on linux:
print os.system('arp -n ' + str(remoteIP))
you will get:
Address HWtype HWaddress Flags Mask Iface
192.168..... ether 9B:39:15:f2:45:51 C wlan0
General update for Python 3.7. Remark: the option -n
for arp
does not provide the arp list on windows systems as provided with certain answers for linux based systems. Use the option -a
as stated in the answer here.
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))
精彩评论