Fix the DHCP server (fixes #44)
[invirt/packages/python-pydhcplib.git] / pydhcplib / dhcp_packet.py
1 # Anemon Dhcp
2 # Copyright (C) 2005 Mathieu Ignacio -- mignacio@april.org
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
17
18 import operator
19 from struct import unpack
20 from struct import pack
21 from dhcp_basic_packet import *
22 from dhcp_constants import *
23 from type_ipv4 import ipv4
24 from type_strlist import strlist
25 class DhcpPacket(DhcpBasicPacket):
26
27
28     # Useful function for debugging
29     def PrintHeaders(self):
30         print "# Header fields\n"
31         print "readable_dhcp_headers = {"
32         for opt in  ['op','htype','hlen','hops','xid','secs','flags',
33                      'ciaddr','yiaddr','siaddr','giaddr','chaddr','sname','file'] :
34             begin = DhcpFields[opt][0]
35             end = DhcpFields[opt][0]+DhcpFields[opt][1]
36             data = self.packet_data[begin:end]
37             if DhcpFieldsTypes[opt] == "int" : result = str(data[0])
38             if DhcpFieldsTypes[opt] == "int2" : result = str(data[0]*256+data[0])
39             if DhcpFieldsTypes[opt] == "int4" : result = str(ipv4(data).int())
40             if DhcpFieldsTypes[opt] == "str" : result = strlist(data).str()
41             if DhcpFieldsTypes[opt] == "ipv4" : result = ipv4(data).str()
42             if DhcpFieldsTypes[opt] == "hwmac" : result = "".join(map(chr,data))
43
44             line = "\t'"+opt+"':"+str(data)+",\t# "+result
45             print line
46         print "\t'end':'true'}"
47
48     # Useful function for debugging
49     def PrintOptions(self):
50         print "# Options fields"
51         print "readable_dhcp_options = {"
52         for opt in self.options_data.keys():
53             data = self.options_data[opt]
54             result = ""
55             optnum  = DhcpOptions[opt]
56             if DhcpOptionsTypes[optnum] == "char" : result = str(data[0])
57             if DhcpOptionsTypes[optnum] == "16-bits" : result = str(data[0]*256+data[0])
58             if DhcpOptionsTypes[optnum] == "32bits" : result = str(ipv4(data).int())
59             if DhcpOptionsTypes[optnum] == "string" : result = strlist(data).str()
60             if DhcpOptionsTypes[optnum] == "ipv4" : result = ipv4(data).str()
61             if DhcpOptionsTypes[optnum] == "ipv4+" :
62                 for i in range(0,len(data),4) :
63                     if len(data[i:i+4]) == 4 :
64                         result += ipv4(data[i:i+4]).str() + " - "
65             line = "\t'"+opt+"':"+str(data)+",\t# "+result
66             print line
67         print "\t'end':'true'}"
68         
69
70             
71     # FIXME: This is called from IsDhcpSomethingPacket, but is this really
72     # needed?  Or maybe this testing should be done in
73     # DhcpBasicPacket.DecodePacket().
74
75     # Test Packet Type
76     def IsDhcpSomethingPacket(self,type):
77         if self.IsDhcpPacket() == False : return False
78         if self.IsOption("dhcp_message_type") == False : return False
79         if self.GetOption("dhcp_message_type") != type : return False
80         return True
81     
82     def IsDhcpDiscoverPacket(self):
83         return self.IsDhcpSomethingPacket([1])
84
85     def IsDhcpOfferPacket(self):
86         return self.IsDhcpSomethingPacket([2])
87
88     def IsDhcpRequestPacket(self):
89         return self.IsDhcpSomethingPacket([3])
90
91     def IsDhcpDeclinePacket(self):
92         return self.IsDhcpSomethingPacket([4])
93
94     def IsDhcpAckPacket(self):
95         return self.IsDhcpSomethingPacket([5])
96
97     def IsDhcpNackPacket(self):
98         return self.IsDhcpSomethingPacket([6])
99
100     def IsDhcpReleasePacket(self):
101         return self.IsDhcpSomethingPacket([7])
102
103     def IsDhcpInformPacket(self):
104         return self.IsDhcpSomethingPacket([8])
105
106
107     def GetMultipleOptions(self,options=()):
108         result = {}
109         for each in options:
110             result[each] = self.GetOption(each)
111         return result
112
113     def SetMultipleOptions(self,options={}):
114         for each in options.keys():
115             self.SetOption(each,options[each])
116
117
118
119
120
121
122     # Creating Response Packet
123
124     # Server-side functions
125     # From RFC 2132 page 28/29
126     def CreateDhcpOfferPacketFrom(self,src): # src = discover packet
127         self.SetOption("htype",src.GetOption("htype"))
128         self.SetOption("xid",src.GetOption("xid"))
129         self.SetOption("flags",src.GetOption("flags"))
130         self.SetOption("giaddr",src.GetOption("giaddr"))
131         self.SetOption("chaddr",src.GetOption("chaddr"))
132         self.SetOption("ip_address_lease_time",src.GetOption("ip_address_lease_time"))
133         self.TransformToDhcpOfferPacket()
134
135     def TransformToDhcpOfferPacket(self):
136         self.SetOption("dhcp_message_type",[2])
137         self.SetOption("op",[2])
138         self.SetOption("hlen",[6]) 
139
140         self.DeleteOption("secs")
141         self.DeleteOption("ciaddr")
142         self.DeleteOption("request_ip_address")
143         self.DeleteOption("parameter_request_list")
144         self.DeleteOption("client_identifier")
145         self.DeleteOption("maximum_message_size")
146
147
148
149
150
151     """ Dhcp ACK packet creation """
152     def CreateDhcpAckPacketFrom(self,src): # src = request or inform packet
153         self.SetOption("htype",src.GetOption("htype"))
154         self.SetOption("xid",src.GetOption("xid"))
155         self.SetOption("ciaddr",src.GetOption("ciaddr"))
156         self.SetOption("flags",src.GetOption("flags"))
157         self.SetOption("giaddr",src.GetOption("giaddr"))
158         self.SetOption("chaddr",src.GetOption("chaddr"))
159         self.SetOption("ip_address_lease_time_option",src.GetOption("ip_address_lease_time_option"))
160         self.TransformToDhcpAckPacket()
161
162     def TransformToDhcpAckPacket(self): # src = request or inform packet
163         self.SetOption("op",[2])
164         self.SetOption("hlen",[6]) 
165         self.SetOption("dhcp_message_type",[5])
166
167         self.DeleteOption("secs")
168         self.DeleteOption("request_ip_address")
169         self.DeleteOption("parameter_request_list")
170         self.DeleteOption("client_identifier")
171         self.DeleteOption("maximum_message_size")
172
173
174     """ Dhcp NACK packet creation """
175     def CreateDhcpNackPacketFrom(self,src): # src = request or inform packet
176         
177         self.SetOption("htype",src.GetOption("htype"))
178         self.SetOption("xid",src.GetOption("xid"))
179         self.SetOption("flags",src.GetOption("flags"))
180         self.SetOption("giaddr",src.GetOption("giaddr"))
181         self.SetOption("chaddr",src.GetOption("chaddr"))
182         self.TransformToDhcpNackPacket()
183
184     def TransformToDhcpNackPacket(self):
185         self.SetOption("op",[2])
186         self.SetOption("hlen",[6]) 
187         self.DeleteOption("secs")
188         self.DeleteOption("ciaddr")
189         self.DeleteOption("yiaddr")
190         self.DeleteOption("siaddr")
191         self.DeleteOption("sname")
192         self.DeleteOption("file")
193         self.DeleteOption("request_ip_address")
194         self.DeleteOption("ip_address_lease_time_option")
195         self.DeleteOption("parameter_request_list")
196         self.DeleteOption("client_identifier")
197         self.DeleteOption("maximum_message_size")
198         self.SetOption("dhcp_message_type",[6])
199
200
201
202
203
204
205
206     """ GetClientIdentifier """
207
208     def GetClientIdentifier(self) :
209         if self.IsOption("client_identifier") :
210             return self.GetOption("client_identifier")
211         return []
212
213     def GetGiaddr(self) :
214         return self.GetOption("giaddr")
215
216     def GetHardwareAddress(self) :
217         length = self.GetOption("hlen")[0]
218         full_hw = self.GetOption("chaddr")
219         if length!=[] and length<len(full_hw) : return full_hw[0:length]
220         return full_hw
221