From fa7d1d56e842169a277b45288421e67413fa140a Mon Sep 17 00:00:00 2001 From: Mike Zeng Date: Fri, 10 Jan 2025 22:07:11 -0600 Subject: [PATCH 1/2] DHCP_am: support multiple nameservers --- scapy/layers/dhcp.py | 39 +++++++++++++++++++++++++++---------- test/answering_machines.uts | 11 +++++++++++ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py index 8b679bfbf36..693a21aa8b7 100644 --- a/scapy/layers/dhcp.py +++ b/scapy/layers/dhcp.py @@ -61,6 +61,13 @@ from scapy.error import warning from scapy.config import conf +# Typing imports +from typing import ( + List, + Optional, + Union, +) + dhcpmagic = b"c\x82Sc" @@ -601,20 +608,21 @@ class BOOTP_am(AnsweringMachine): filter = "udp and port 68 and port 67" def parse_options(self, - pool=Net("192.168.1.128/25"), - network="192.168.1.0/24", - gw="192.168.1.1", - nameserver=None, - domain=None, - renewal_time=60, - lease_time=1800, + pool: Union[Net, List[str]] = Net("192.168.1.128/25"), + network: str = "192.168.1.0/24", + gw: str = "192.168.1.1", + nameserver: Union[str, List[str]] = None, + domain: Optional[str] = None, + renewal_time: int = 60, + lease_time: int = 1800, **kwargs): """ :param pool: the range of addresses to distribute. Can be a Net, a list of IPs or a string (always gives the same IP). :param network: the subnet range :param gw: the gateway IP (can be None) - :param nameserver: the DNS server IP (by default, same than gw) + :param nameserver: the DNS server IP (by default, same than gw). + This can also be a list. :param domain: the domain to advertise (can be None) Other DHCP parameters can be passed as kwargs. See DHCPOptions in dhcp.py. @@ -622,6 +630,11 @@ def parse_options(self, dhcpd(pool=Net("10.0.10.0/24"), network="10.0.0.0/8", gw="10.0.10.1", classless_static_routes=["1.2.3.4/32:9.8.7.6"]) + + Other example with different options:: + + dhcpd(pool=Net("10.0.10.0/24"), network="10.0.0.0/8", gw="10.0.10.1", + nameserver=["8.8.8.8", "4.4.4.4"], domain="DOMAIN.LOCAL") """ self.domain = domain netw, msk = (network.split("/") + ["32"])[:2] @@ -630,7 +643,13 @@ def parse_options(self, self.network = ltoa(atol(netw) & msk) self.broadcast = ltoa(atol(self.network) | (0xffffffff & ~msk)) self.gw = gw - self.nameserver = nameserver or gw + if nameserver is None: + self.nameserver = (gw,) + elif isinstance(nameserver, str): + self.nameserver = (nameserver,) + else: + self.nameserver = tuple(nameserver) + if isinstance(pool, str): pool = Net(pool) if isinstance(pool, Iterable): @@ -691,7 +710,7 @@ def make_reply(self, req): ("server_id", self.gw), ("domain", self.domain), ("router", self.gw), - ("name_server", self.nameserver), + ("name_server", *self.nameserver), ("broadcast_address", self.broadcast), ("subnet_mask", self.netmask), ("renewal_time", self.renewal_time), diff --git a/test/answering_machines.uts b/test/answering_machines.uts index bee850405cb..15a8e01e436 100644 --- a/test/answering_machines.uts +++ b/test/answering_machines.uts @@ -39,12 +39,23 @@ test_am(BOOTP_am, def check_DHCP_am_reply(packet): assert DHCP in packet and len(packet[DHCP].options) assert ("domain", b"localnet") in packet[DHCP].options + assert ('name_server', '192.168.1.1') in packet[DHCP].options + +def check_ns_DHCP_am_reply(packet): + assert DHCP in packet and len(packet[DHCP].options) + assert ("domain", b"localnet") in packet[DHCP].options + assert ('name_server', '1.1.1.1', '2.2.2.2') in packet[DHCP].options test_am(DHCP_am, Ether()/IP()/UDP()/BOOTP(op=1)/DHCP(options=[('message-type', 'request')]), check_DHCP_am_reply, domain="localnet") +test_am(DHCP_am, + Ether()/IP()/UDP()/BOOTP(op=1)/DHCP(options=[('message-type', 'request')]), + check_ns_DHCP_am_reply, + domain="localnet", + nameserver=["1.1.1.1", "2.2.2.2"]) = ARP_am def check_ARP_am_reply(packet): From 7711b1f44a0410dc07f743a0a78922d586e84576 Mon Sep 17 00:00:00 2001 From: gpotter2 <10530980+gpotter2@users.noreply.github.com> Date: Mon, 15 Sep 2025 22:59:34 +0200 Subject: [PATCH 2/2] Fix dhcpd IPython test --- test/scapy/layers/dhcp.uts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/scapy/layers/dhcp.uts b/test/scapy/layers/dhcp.uts index fd953f551d5..4c92d438a5e 100644 --- a/test/scapy/layers/dhcp.uts +++ b/test/scapy/layers/dhcp.uts @@ -125,5 +125,14 @@ assert DHCPRevOptions['static-routes'][0] == 33 assert dhcpd import IPython -assert IPython.lib.pretty.pretty(dhcpd) == '' + +result = IPython.lib.pretty.pretty(dhcpd) +result + +# 3 results depending on the Python version +assert result in [ + '', + '', + '', +]