From a982da5a7cb419138e3c8911f9392d9a905e87b1 Mon Sep 17 00:00:00 2001 From: Mike Zeng Date: Fri, 10 Jan 2025 22:07:11 -0600 Subject: [PATCH 1/9] DHCPAM: Make_reply to use raw to inject IP. --- scapy/layers/dhcp.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py index 031fe34decc..c829297e0ca 100644 --- a/scapy/layers/dhcp.py +++ b/scapy/layers/dhcp.py @@ -39,6 +39,7 @@ StrField, StrFixedLenField, XIntField, + RawVal ) from scapy.layers.inet import UDP, IP from scapy.layers.l2 import Ether, HARDWARE_TYPES @@ -669,6 +670,24 @@ def make_reply(self, req): class DHCP_am(BOOTP_am): function_name = "dhcpd" + def ip_to_bytes(self, ip_string): + """Concat a IP str of form IP,IP,IP and returns it as bytes + Backcompatible if IP is a single IP. + :param ip_string: String of the IP to be packed""" + ip_string = ip_string.replace(" ", "") + + # Split IPs by commas and filter out empty strings + ip_list = [ip.strip() for ip in ip_string.split(',') if ip.strip()] + + # Convert each IP to packed format + packed_ips = [] + for ip in ip_list: + packed_ips.append(socket.inet_aton(ip)) + + # Concatenate packed IPs into a single byte string + return b''.join(packed_ips) + + def make_reply(self, req): resp = BOOTP_am.make_reply(self, req) if DHCP in req: @@ -677,12 +696,15 @@ def make_reply(self, req): for op in req[DHCP].options if isinstance(op, tuple) and op[0] == "message-type" ] + + nameserver_list = self.ip_to_bytes(self.nameserver) + dhcp_options += [ x for x in [ ("server_id", self.gw), ("domain", self.domain), ("router", self.gw), - ("name_server", self.nameserver), + ("name_server", IP(len = RawVal(nameserver_list))), ("broadcast_address", self.broadcast), ("subnet_mask", self.netmask), ("renewal_time", self.renewal_time), From 23f9dfc81b596d268806bb41f6e3325624951787 Mon Sep 17 00:00:00 2001 From: Mike Zeng Date: Fri, 10 Jan 2025 22:13:23 -0600 Subject: [PATCH 2/9] REFACT: Removed whitespace. --- scapy/layers/dhcp.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py index c829297e0ca..40cf6feeb71 100644 --- a/scapy/layers/dhcp.py +++ b/scapy/layers/dhcp.py @@ -675,18 +675,17 @@ def ip_to_bytes(self, ip_string): Backcompatible if IP is a single IP. :param ip_string: String of the IP to be packed""" ip_string = ip_string.replace(" ", "") - + # Split IPs by commas and filter out empty strings ip_list = [ip.strip() for ip in ip_string.split(',') if ip.strip()] - + # Convert each IP to packed format packed_ips = [] for ip in ip_list: packed_ips.append(socket.inet_aton(ip)) - + # Concatenate packed IPs into a single byte string return b''.join(packed_ips) - def make_reply(self, req): resp = BOOTP_am.make_reply(self, req) @@ -696,7 +695,7 @@ def make_reply(self, req): for op in req[DHCP].options if isinstance(op, tuple) and op[0] == "message-type" ] - + nameserver_list = self.ip_to_bytes(self.nameserver) dhcp_options += [ @@ -704,7 +703,7 @@ def make_reply(self, req): ("server_id", self.gw), ("domain", self.domain), ("router", self.gw), - ("name_server", IP(len = RawVal(nameserver_list))), + ("name_server", IP(len=RawVal(nameserver_list))), ("broadcast_address", self.broadcast), ("subnet_mask", self.netmask), ("renewal_time", self.renewal_time), From 20f5d0b6b250b701aadd6749c000915396108e36 Mon Sep 17 00:00:00 2001 From: Mike Zeng Date: Fri, 10 Jan 2025 22:45:36 -0600 Subject: [PATCH 3/9] REFACT: Minimize make_reply routes. --- scapy/layers/dhcp.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py index 40cf6feeb71..b942a9d02b1 100644 --- a/scapy/layers/dhcp.py +++ b/scapy/layers/dhcp.py @@ -696,14 +696,18 @@ def make_reply(self, req): if isinstance(op, tuple) and op[0] == "message-type" ] - nameserver_list = self.ip_to_bytes(self.nameserver) + if ',' in self.nameserver: + # Use if statement to reduce how much changes there are. + ns_val = IP(len=RawVal(self.ip_to_bytes(self.nameserver))) + else: + ns_val = nameserver dhcp_options += [ x for x in [ ("server_id", self.gw), ("domain", self.domain), ("router", self.gw), - ("name_server", IP(len=RawVal(nameserver_list))), + ("name_server", ns_val), ("broadcast_address", self.broadcast), ("subnet_mask", self.netmask), ("renewal_time", self.renewal_time), From cd8de295010276f44210abf058dbfec0af7e9c7a Mon Sep 17 00:00:00 2001 From: Mike Zeng Date: Fri, 10 Jan 2025 22:47:21 -0600 Subject: [PATCH 4/9] BUG: namesaver not referencing self --- scapy/layers/dhcp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py index b942a9d02b1..38731484606 100644 --- a/scapy/layers/dhcp.py +++ b/scapy/layers/dhcp.py @@ -700,7 +700,7 @@ def make_reply(self, req): # Use if statement to reduce how much changes there are. ns_val = IP(len=RawVal(self.ip_to_bytes(self.nameserver))) else: - ns_val = nameserver + ns_val = self.nameserver dhcp_options += [ x for x in [ From d6d746598427c0d431c983ec0ad908c6cc174d45 Mon Sep 17 00:00:00 2001 From: Mike Zeng Date: Thu, 16 Jan 2025 10:49:31 -0600 Subject: [PATCH 5/9] IMPL: Utilize IP to solve multiple ns --- scapy/layers/dhcp.py | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py index 38731484606..57d50796d56 100644 --- a/scapy/layers/dhcp.py +++ b/scapy/layers/dhcp.py @@ -670,23 +670,6 @@ def make_reply(self, req): class DHCP_am(BOOTP_am): function_name = "dhcpd" - def ip_to_bytes(self, ip_string): - """Concat a IP str of form IP,IP,IP and returns it as bytes - Backcompatible if IP is a single IP. - :param ip_string: String of the IP to be packed""" - ip_string = ip_string.replace(" ", "") - - # Split IPs by commas and filter out empty strings - ip_list = [ip.strip() for ip in ip_string.split(',') if ip.strip()] - - # Convert each IP to packed format - packed_ips = [] - for ip in ip_list: - packed_ips.append(socket.inet_aton(ip)) - - # Concatenate packed IPs into a single byte string - return b''.join(packed_ips) - def make_reply(self, req): resp = BOOTP_am.make_reply(self, req) if DHCP in req: @@ -697,17 +680,18 @@ def make_reply(self, req): ] if ',' in self.nameserver: - # Use if statement to reduce how much changes there are. - ns_val = IP(len=RawVal(self.ip_to_bytes(self.nameserver))) + # flatten if multiple + split = tuple(self.nameserver.split(",")) + ns_val = ("name_server", *split) else: - ns_val = self.nameserver + ns_val = ("name_server", self.nameserver) dhcp_options += [ x for x in [ ("server_id", self.gw), ("domain", self.domain), ("router", self.gw), - ("name_server", ns_val), + ns_val, ("broadcast_address", self.broadcast), ("subnet_mask", self.netmask), ("renewal_time", self.renewal_time), From d42fc74871ec721741ac64489bfb9bc1780a73a7 Mon Sep 17 00:00:00 2001 From: Mike Zeng Date: Thu, 16 Jan 2025 10:55:14 -0600 Subject: [PATCH 6/9] REFACT: Fix style --- scapy/layers/dhcp.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py index 57d50796d56..ffcd423c6f5 100644 --- a/scapy/layers/dhcp.py +++ b/scapy/layers/dhcp.py @@ -39,7 +39,6 @@ StrField, StrFixedLenField, XIntField, - RawVal ) from scapy.layers.inet import UDP, IP from scapy.layers.l2 import Ether, HARDWARE_TYPES From d3d8713bb3cbf8e836c9c27546e6b95d1f6241b7 Mon Sep 17 00:00:00 2001 From: Mike Zeng Date: Mon, 20 Jan 2025 19:46:20 +0000 Subject: [PATCH 7/9] IMPL: DHCP_am tests --- test/answering_machines.uts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/answering_machines.uts b/test/answering_machines.uts index a4844e006de..4c0c52142f7 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 2a62d6ce9a201283214aa0228d3fa6d185fdaac6 Mon Sep 17 00:00:00 2001 From: Mike Zeng Date: Mon, 10 Feb 2025 01:42:45 -0600 Subject: [PATCH 8/9] REFAC: Move flatten to parseopt --- scapy/layers/dhcp.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py index ffcd423c6f5..7656e3cef3a 100644 --- a/scapy/layers/dhcp.py +++ b/scapy/layers/dhcp.py @@ -621,7 +621,7 @@ 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 + self.nameserver = tuple(nameserver.split(",")) if ("," in nameserver) else ((nameserver,) or (gw,)) if isinstance(pool, str): pool = Net(pool) if isinstance(pool, Iterable): @@ -678,19 +678,12 @@ def make_reply(self, req): if isinstance(op, tuple) and op[0] == "message-type" ] - if ',' in self.nameserver: - # flatten if multiple - split = tuple(self.nameserver.split(",")) - ns_val = ("name_server", *split) - else: - ns_val = ("name_server", self.nameserver) - dhcp_options += [ x for x in [ ("server_id", self.gw), ("domain", self.domain), ("router", self.gw), - ns_val, + ("name_server", self.nameserver), ("broadcast_address", self.broadcast), ("subnet_mask", self.netmask), ("renewal_time", self.renewal_time), From 56b4cf8fff44fd51ff95f4595a443321d488aae5 Mon Sep 17 00:00:00 2001 From: Mike Zeng Date: Mon, 10 Feb 2025 08:20:43 +0000 Subject: [PATCH 9/9] IMPL: unpack+None handle --- scapy/layers/dhcp.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py index 7656e3cef3a..1bbadaa13fb 100644 --- a/scapy/layers/dhcp.py +++ b/scapy/layers/dhcp.py @@ -621,7 +621,9 @@ def parse_options(self, self.network = ltoa(atol(netw) & msk) self.broadcast = ltoa(atol(self.network) | (0xffffffff & ~msk)) self.gw = gw - self.nameserver = tuple(nameserver.split(",")) if ("," in nameserver) else ((nameserver,) or (gw,)) + realns = nameserver or gw + self.nameserver = tuple(realns.split(",")) if ("," in realns) else (realns,) + if isinstance(pool, str): pool = Net(pool) if isinstance(pool, Iterable): @@ -683,7 +685,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),