test-dhcp-service.py (2358B)
1 # forge packets for testing liminix and send them via the qemu udp 2 # multicast socket interface 3 4 MCAST_GRP = '230.0.0.1' 5 MCAST_PORT = 1235 6 MULTICAST_TTL = 2 7 8 TIMEOUT = 10 # seconds 9 10 from warnings import filterwarnings 11 filterwarnings("ignore") 12 13 import random 14 import binascii 15 import socket 16 import time 17 import json 18 19 from builtins import bytes, bytearray 20 21 from scapy.all import Ether, IP, UDP, BOOTP, DHCP, sendp, send, raw 22 23 class JSONEncoderWithBytes(json.JSONEncoder): 24 def default(self, obj): 25 if isinstance(obj, (bytes, bytearray)): 26 return obj.decode('utf-8') 27 return json.JSONEncoder.default(self, obj) 28 29 30 def dhcp_option(pkt, label): 31 if pkt.haslayer(DHCP): 32 for i in pkt[DHCP].options: 33 l, v = i 34 if l == label: 35 return v 36 return None 37 38 def is_dhcp_offer(pkt): 39 val = dhcp_option(pkt, 'message-type') 40 return (val == 2) 41 42 43 44 def mac_to_bytes(mac_addr: str) -> bytes: 45 """ Converts a MAC address string to bytes. 46 """ 47 return int(mac_addr.replace(":", ""), 16).to_bytes(6, "big") 48 49 50 client_mac = "01:02:03:04:05:06" 51 discover = ( 52 Ether(dst="ff:ff:ff:ff:ff:ff") / 53 IP(src="0.0.0.0", dst="255.255.255.255") / 54 UDP(sport=68, dport=67) / 55 BOOTP( 56 chaddr=mac_to_bytes(client_mac), 57 xid=random.randint(1, 2**32-1), 58 ) / 59 DHCP(options=[("message-type", "discover"), "end"]) 60 ) 61 payload = raw(discover) 62 63 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 64 sock.settimeout(TIMEOUT) 65 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 66 sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL) 67 68 sock.bind((MCAST_GRP, MCAST_PORT)) 69 sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton('127.0.0.1')) 70 sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, 71 socket.inet_aton(MCAST_GRP) + socket.inet_aton('127.0.0.1')) 72 73 endtime = time.time() + TIMEOUT 74 sock.sendto(payload, (MCAST_GRP, MCAST_PORT)) 75 76 while time.time() < endtime: 77 try: 78 data, addr = sock.recvfrom(1024) 79 except socket.error as e: 80 print('recv exception: ', e) 81 else: 82 reply = Ether(data) 83 if is_dhcp_offer(reply): 84 opts = dict([o for o in reply[DHCP].options if type(o) is tuple]) 85 print(json.dumps(opts, cls=JSONEncoderWithBytes)) 86 exit(0) 87 exit(1)