Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
This script listens for DHCP packets using scapy to learn when LAN hosts request IP addresses from DHCP Servers. Learn more about this script at https://jcutrer.com/python/scapy-dhcp-listener
#!/usr/bin/env python3
"""scapy-dhcp-listener.py
Listen for DHCP packets using scapy to learn when LAN
hosts request IP addresses from DHCP Servers.
Copyright (C) 2018 Jonathan Cutrer
License Dual MIT, 0BSD
"""
from __future__ import print_function
from scapy.all import *
import time
__version__ = "0.0.3"
# Fixup function to extract dhcp_options by key
def get_option(dhcp_options, key):
must_decode = ['hostname', 'domain', 'vendor_class_id']
try:
for i in dhcp_options:
if i[0] == key:
# If DHCP Server Returned multiple name servers
# return all as comma seperated string.
if key == 'name_server' and len(i) > 2:
return ",".join(i[1:])
# domain and hostname are binary strings,
# decode to unicode string before returning
elif key in must_decode:
return i[1].decode()
else:
return i[1]
except:
pass
def handle_dhcp_packet(packet):
# Match DHCP discover
if DHCP in packet and packet[DHCP].options[0][1] == 1:
print('---')
print('New DHCP Discover')
#print(packet.summary())
#print(ls(packet))
hostname = get_option(packet[DHCP].options, 'hostname')
print(f"Host {hostname} ({packet[Ether].src}) asked for an IP")
# Match DHCP offer
elif DHCP in packet and packet[DHCP].options[0][1] == 2:
print('---')
print('New DHCP Offer')
#print(packet.summary())
#print(ls(packet))
subnet_mask = get_option(packet[DHCP].options, 'subnet_mask')
lease_time = get_option(packet[DHCP].options, 'lease_time')
router = get_option(packet[DHCP].options, 'router')
name_server = get_option(packet[DHCP].options, 'name_server')
domain = get_option(packet[DHCP].options, 'domain')
print(f"DHCP Server {packet[IP].src} ({packet[Ether].src}) "
f"offered {packet[BOOTP].yiaddr}")
print(f"DHCP Options: subnet_mask: {subnet_mask}, lease_time: "
f"{lease_time}, router: {router}, name_server: {name_server}, "
f"domain: {domain}")
# Match DHCP request
elif DHCP in packet and packet[DHCP].options[0][1] == 3:
print('---')
print('New DHCP Request')
#print(packet.summary())
#print(ls(packet))
requested_addr = get_option(packet[DHCP].options, 'requested_addr')
hostname = get_option(packet[DHCP].options, 'hostname')
print(f"Host {hostname} ({packet[Ether].src}) requested {requested_addr}")
# Match DHCP ack
elif DHCP in packet and packet[DHCP].options[0][1] == 5:
print('---')
print('New DHCP Ack')
#print(packet.summary())
#print(ls(packet))
subnet_mask = get_option(packet[DHCP].options, 'subnet_mask')
lease_time = get_option(packet[DHCP].options, 'lease_time')
router = get_option(packet[DHCP].options, 'router')
name_server = get_option(packet[DHCP].options, 'name_server')
print(f"DHCP Server {packet[IP].src} ({packet[Ether].src}) "
f"acked {packet[BOOTP].yiaddr}")
print(f"DHCP Options: subnet_mask: {subnet_mask}, lease_time: "
f"{lease_time}, router: {router}, name_server: {name_server}")
# Match DHCP inform
elif DHCP in packet and packet[DHCP].options[0][1] == 8:
print('---')
print('New DHCP Inform')
#print(packet.summary())
#print(ls(packet))
hostname = get_option(packet[DHCP].options, 'hostname')
vendor_class_id = get_option(packet[DHCP].options, 'vendor_class_id')
print(f"DHCP Inform from {packet[IP].src} ({packet[Ether].src}) "
f"hostname: {hostname}, vendor_class_id: {vendor_class_id}")
else:
print('---')
print('Some Other DHCP Packet')
print(packet.summary())
print(ls(packet))
return
if __name__ == "__main__":
sniff(filter="udp and (port 67 or 68)", prn=handle_dhcp_packet)
@afsara-ben

This comment has been minimized.

Copy link

@afsara-ben afsara-ben commented Sep 3, 2019

Gives this error

File "scapy-dhcp-listener.py", line 45
print(f"Host {hostname} ({packet[Ether].src}) asked for an IP")
^
SyntaxError: invalid syntax

@GadgetSteve

This comment has been minimized.

Copy link

@GadgetSteve GadgetSteve commented Oct 30, 2019

Gives this error

File "scapy-dhcp-listener.py", line 45
print(f"Host {hostname} ({packet[Ether].src}) asked for an IP")
^
SyntaxError: invalid syntax

This is because the script above uses f strings which were introduced in Python 3.6 - if your python is <3.6 you will get an error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.