1# $Id: dhcp.py,v 1.1.1.1 2005/10/29 18:20:48 provos Exp $ 2 3from dpkt import Packet 4import arp 5 6DHCP_OP_REQUEST = 1 7DHCP_OP_REPLY = 2 8 9DHCP_MAGIC = 0x63825363 10 11# DHCP option codes 12DHCP_OPT_NETMASK = 1 # I: subnet mask 13DHCP_OPT_ROUTER = 3 # s: list of router IPs 14DHCP_OPT_DNS_SVRS = 6 # s: list of DNS servers 15DHCP_OPT_HOSTNAME = 12 # s: client hostname 16DHCP_OPT_DOMAIN = 15 # s: domain name 17DHCP_OPT_REQ_IP = 50 # I: IP address 18DHCP_OPT_LEASE_SEC = 51 # I: lease seconds 19DHCP_OPT_MSGTYPE = 53 # B: message type 20DHCP_OPT_SERVER_ID = 54 # I: server IP address 21DHCP_OPT_PARAM_REQ = 55 # s: list of option codes 22DHCP_OPT_VENDOR_ID = 60 # s: vendor string 23DHCP_OPT_CLIENT_ID = 61 # Bs: idtype, id (idtype 0: FQDN, idtype 1: MAC) 24 25# DHCP message type values 26DHCPDISCOVER = 1 27DHCPOFFER = 2 28DHCPREQUEST = 3 29DHCPDECLINE = 4 30DHCPACK = 5 31DHCPNAK = 6 32DHCPRELEASE = 7 33DHCPINFORM = 8 34 35class DHCP(Packet): 36 """Dynamic Host Configuration Protocol.""" 37 __hdr__ = ( 38 ('op', 'B', DHCP_OP_REQUEST), 39 ('hrd', 'B', arp.ARP_HRD_ETH), # just like ARP.hrd 40 ('hln', 'B', 6), # and ARP.hln 41 ('hops', 'B', 0), 42 ('xid', 'I', 0xdeadbeefL), 43 ('secs', 'H', 0), 44 ('flags', 'H', 0), 45 ('ciaddr', 'I', 0), 46 ('yiaddr', 'I', 0), 47 ('siaddr', 'I', 0), 48 ('giaddr', 'I', 0), 49 ('chaddr', '16s', 16 * '\x00'), 50 ('sname', '64s', 64 * '\x00'), 51 ('file', '128s', 128 * '\x00'), 52 ('magic', 'I', DHCP_MAGIC), 53 ) 54 opts = () # list of (type, data) tuples 55 56 def __len__(self): 57 return self.__hdr_len__ + \ 58 sum([ 2 + len(o[1]) for o in self.opts ]) + len(self.data) 59 60 def __str__(self): 61 return self.pack_hdr() + self.pack_opts() + self.data 62 63 def pack_opts(self): 64 """Return packed options string.""" 65 if not self.opts: 66 return '' 67 l = [] 68 for t, data in self.opts: 69 l.append('%s%s%s' % (chr(t), chr(len(data)), data)) 70 l.append('\xff') 71 return ''.join(l) 72 73 def unpack(self, buf): 74 Packet.unpack(self, buf) 75 self.chaddr = self.chaddr[:self.hln] 76 buf = self.data 77 l = [] 78 while buf: 79 t = ord(buf[0]) 80 if t == 0xff: 81 buf = buf[1:] 82 break 83 elif t == 0: 84 buf = buf[1:] 85 else: 86 n = ord(buf[1]) 87 l.append((t, buf[2:2+n])) 88 buf = buf[2+n:] 89 self.opts = l 90 self.data = buf 91 92if __name__ == '__main__': 93 import unittest 94 95 class DHCPTestCast(unittest.TestCase): 96 def test_DHCP(self): 97 s = '\x01\x01\x06\x00\xadS\xc8c\xb8\x87\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02U\x82\xf3\xa6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00c\x82Sc5\x01\x01\xfb\x01\x01=\x07\x01\x00\x02U\x82\xf3\xa62\x04\n\x00\x01e\x0c\tGuinevere<\x08MSFT 5.07\n\x01\x0f\x03\x06,./\x1f!+\xff\x00\x00\x00\x00\x00' 98 dhcp = DHCP(s) 99 self.failUnless(s == str(dhcp)) 100 101 unittest.main() 102 103