| 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 |  | 
|---|