pythonnetwork-programmingscapydhcp

How to add domain name in DHCP offer packet with scapy?


I have written a DHCP server code in python using Scapy that can sniff discovery messages and send an appropriate offer message with an IP for a client. I tried to insert another option in the packet regarding the DNS server IP, but it doesn't show up no matter what in the DHCP options in the packet. Can someone help?

DHCP Server Code

from time import sleep
from scapy.all import *
from scapy.layers.dhcp import BOOTP, DHCP
from scapy.layers.inet import UDP, IP
from scapy.layers.l2 import Ether, ARP
import random


requested_ips = {}
assigned_ips = {}
domain_ip = ""

# Function to check if an IP address is in use
def ip_in_use(ip):
    arp_request = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(op="who-has", pdst=ip)
    arp_response = srp1(arp_request, timeout=1, verbose=0)
    if arp_response is not None:
        return True
    else:
        return False

# Define a function to handle DHCP requests
def handle_dhcp_request(pkt):
    if DHCP in pkt and pkt[DHCP].options[0][1] == 1:
        print("DHCP Discover received")
        
        client_mac = pkt[Ether].src
        
        # Generate a random IP address if no specific IP was requested
        random_ip = "192.168.1." + str(random.randint(2, 254))
        
        # Check if the requested IP address is already in use on network
        while ip_in_use(random_ip):
            print(f"Requested IP {random_ip} is already in use, offering random IP")
            random_ip = "192.168.1." + str(random.randint(2, 254))

        # Check if the IP address was already assigned by the DHCP server
        while assigned_ips and random_ip in assigned_ips.values():
            random_ip = "192.168.1." + str(random.randint(2, 254))
        
        requested_ips[client_mac] = random_ip
        offer = Ether(src=get_if_hwaddr(conf.iface), dst=client_mac)/ \
            IP(src="192.168.1.1", dst=random_ip)/ \
            UDP(sport=67, dport=68)/ \
            BOOTP(op=2, yiaddr=random_ip, siaddr="192.168.1.1", giaddr="0.0.0.0", xid=pkt[BOOTP].xid)/ \
            DHCP(options=[("message-type", "offer"),
                           ("subnet_mask", "255.255.255.0"),
                           ("router", "192.168.1.1"),
                           ("lease_time", 86400),
                           "end"])
        # Add DNS server IP to options
        offer[DHCP].options.insert(4, ("domain_name_server", domain_ip))

        # Send packet
        print(offer[DHCP])
        sleep(1)
        sendp(offer, iface=conf.iface)
        print(f"DHCP Offer sent with IP: {random_ip}")
        

# Create an IP address for the DNS server
domain_ip = "192.168.1." + str(random.randint(2, 254))

# Set up a sniffing filter for DHCP requests
sniff_filter = "udp and (port 67 or 68)"

# Start sniffing for DHCP requests
print("DHCP Server started.")
print(f"Domain IP: {domain_ip}")
sniff(filter=sniff_filter, prn=handle_dhcp_request)

I tried using "offer[DHCP].options.insert(4, ("domain_name_server", domain_ip))" or add ("domain_name_server", domain_ip) in the (options=[("message-type", "offer"), ("subnet_mask", "255.255.255.0"),("router", "192.168.1.1"),("lease_time", 86400), "end"]) but it didn't. I right after try to do "print(offer[DHCP])" and there are no bytes representing the domain name...


Solution

  • According to the Scapy DHCP module (BOOTP Class), the parameter name is name_server, and not domain_name_server. enter image description here