Obtain MAC Address from Devices using Python

Posted on

Question :

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 databases of IP addresses on regular intervals ensuring that the mac addresses have not changed and if they have, email alerts to myself.

Asked By: nfarrar

||

Answer #1:

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-fd]{1,2}:){5}[a-fd]{1,2})", s).groups()[0]
>>> mac
"fe:fd:61:6b:8a:0f"
Answered By: Jed Smith

Answer #2:

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!

Answered By: jathanism

Answer #3:

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/

Answered By: intgr

Answer #4:

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

Answered By: Andrei Volokitin

Answer #5:

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
Answered By: urnenfeld

Answer #6:

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))
Answered By: AliA

Answer #7:

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
Answered By: thais dbraz

Answer #8:

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('Typern'))[1]).split('     ')
IP  =  IP.strip(' ')
MAC =  MAC.strip(' ')

if ip == IP:
    print ('Remote Host : %sn        MAC : %s' % (IP, MAC))
Answered By: ZF007

Leave a Reply

Your email address will not be published.