· Python · 4 min read
Scapy ARP listener in Python
This script listens for ARP request packets using scapy to learn the IP and Mac Address of LAN hosts. A little background on the ARP protocolARP is the protocol that hosts use to discover the mac...
This post was originally published on jcutrer.com (WordPress) and has been migrated to the archive.
This script listens for ARP request packets using scapy to learn the IP and Mac Address of LAN hosts.
A little background on the ARP protocol
ARP is the protocol that hosts use to discover the mac address of another LAN host. The initiating host asks “Who Has ”, this request is transmitted as a broadcast ethernet packet to destination 00:00:00:00:00:00. Since the ARP request is sent as a broadcast, all hosts on the LAN receive and process this packet. Because of the nature of the protocol, no special port mirroring or tapping is required on the host that runs this script.
The host that has will reply back directly to the requester so we will not see that ARP reply packet unless our machine sent the initial ARP request.
This script is the foundation for creating a passive network discovery tool. We can collect and store the MAC Address, IP Address pairs for all hosts we hear communicating on the network.
The Script
#!/usr/bin/env python3
"""scapy-arp-listener.py
Listen for arp packets using scapy to learn the IP and Mac Address of LAN hosts
Copyright (C) 2018 Jonathan Cutrer
License Dual MIT, 0BSD
"""
from __future__ import print_function
from scapy.all import *
import time
__version__ = "0.0.1"
def handle_arp_packet(packet):
# Match ARP requests
if packet.op == ARP.who_has:
print('New ARP Request')
print(packet.summary())
#print(ls(packet))
print(packet.src, "has IP", packet.psrc)
# Match ARP replies
if packet.op == ARP.is_at:
print('New ARP Reply')
print(packet.summary())
#print(ls(packet))
return
if __name__ == "__main__":
sniff(filter="arp", prn=handle_arp_packet)The script is also available as a github gist. (https://gist.github.com/joncutrer/5d834e705f9ab4d2f9cc3fc6c4ed3c3d)
Example Output
(venv) user@ubuntu:~/$ sudo ./venv/bin/python scapy-arp-listener.py
New ARP Request
Ether / ARP who has 172.16.##.48 says 172.16.##.34 / Padding
34:17:eb:##:##:## has IP 172.16.##.34
New ARP Request
Ether / ARP who has 172.16.##.48 says 172.16.##.34 / Padding
34:17:eb:##:##:## has IP 172.16.##.34
New ARP Request
Ether / ARP who has 172.16.##.152 says 172.16.##.78 / Padding
00:15:5d:##:##:## has IP 172.16.##.78
New ARP Request
Ether / ARP who has 172.16.##.74 says 172.16.##.25 / Padding
34:17:eb:##:##:## has IP 172.16.##.25
New ARP Request
Ether / ARP who has 172.16.##.86 says 172.16.##.25 / Padding
34:17:eb:##:##:## has IP 172.16.##.25
New ARP Request
Ether / ARP who has 172.16.##.48 says 172.16.##.34 / Padding
34:17:eb:##:##:## has IP 172.16.##.34Environment
This script was developed and tested on a Ubuntu 18.10 host running python 3.6.7. Below, I have also included the requirements.txt of my virtual environment.
#requirements.txt
astroid==2.1.0
isort==4.3.4
lazy-object-proxy==1.3.1
mccabe==0.6.1
pkg-resources==0.0.0
pylint==2.2.2
scapy==2.4.0
six==1.12.0
typed-ast==1.1.1
wrapt==1.10.11Troubleshooting
If you get the following error when running the script it’s because you need sudo/root privileges to the oses networking layers to be able to sniff ethernet frames. This is true for most scapy based applications.
(venv) user@ubuntu:~/$ ./venv/bin/python scapy-arp-listener.py
Traceback (most recent call last):
File "scapy-arp-listener.py", line 36, in
sniff(filter="arp", prn=handle_arp_packet)
File ".../venv/lib/python3.6/site-packages/scapy/sendrecv.py", line 731, in sniff
*arg, **karg)] = iface
File ".../venv/lib/python3.6/site-packages/scapy/arch/linux.py", line 567, in __init__
self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
File "/usr/lib/python3.6/socket.py", line 144, in __init__
_socket.socket.__init__(self, family, type, proto, fileno)
PermissionError: Operation not permittedLicense & Legal Disclaimer The source code & script(s) contained in this article are dual licensed (https://opensource.org/licenses/MIT) & (https://opensource.org/licenses/0BSD).
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
If you find this script useful leave a comment below and also checkout my other (/python). I’ve also created a similar (/python/scapy-dhcp-listener).
Comments are disabled (Giscus not yet configured).