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