--- /dev/null
+# Anemon Dhcp
+# Copyright (C) 2005 Mathieu Ignacio -- mignacio@april.org
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+import operator
+from struct import unpack
+from struct import pack
+from dhcp_constants import *
+
+# DhcpPacket : base class to encode/decode dhcp packets.
+
+
+class DhcpBasicPacket:
+ def __init__(self):
+ self.packet_data = [0]*240
+ self.options_data = {}
+ self.packet_data[236:240] = MagicCookie
+
+ def IsDhcpPacket(self):
+ if self.packet_data[236:240] != MagicCookie : return False
+ return True
+
+ # Check if variable is a list with int between 0 and 255
+ def CheckType(self,variable):
+ if type(variable) == list :
+ for each in variable :
+ if (type(each) != int) or (each < 0) or (each > 255) :
+ return False
+ return True
+ else : return False
+
+
+ def DeleteOption(self,name):
+ # if name is a standard dhcp field
+ # Set field to 0
+ if DhcpFields.has_key(name) :
+ begin = DhcpFields[name][0]
+ end = DhcpFields[name][0]+DhcpFields[name][1]
+ self.packet_data[begin:end] = [0]*DhcpFields[name][1]
+ return True
+
+ # if name is a dhcp option
+ # delete option from self.option_data
+ elif self.options_data.has_key(name) :
+ # forget how to remove a key... try delete
+ self.options_data.__delitem__(name)
+ return True
+
+ return False
+
+ def GetOption(self,name):
+ if DhcpFields.has_key(name) :
+ option_info = DhcpFields[name]
+ return self.packet_data[option_info[0]:option_info[0]+option_info[1]]
+
+ elif self.options_data.has_key(name) :
+ return self.options_data[name]
+
+ return []
+
+
+ def SetOption(self,name,value):
+
+ # Basic vlue checking :
+ # has value list a correct length
+
+ # if name is a standard dhcp field
+ if DhcpFields.has_key(name) :
+ if len(value) != DhcpFields[name][1] :
+ print "Error, bad option length (a): ", name
+ return False
+ begin = DhcpFields[name][0]
+ end = DhcpFields[name][0]+DhcpFields[name][1]
+ self.packet_data[begin:end] = value
+ return True
+
+ # if name is a dhcp option
+ elif DhcpOptions.has_key(name) :
+
+ # fields_specs : {'option_code',fixed_length,minimum_length,multiple}
+ # if fixed_length == 0 : minimum_length and multiple apply
+ # else : forget minimum_length and multiple
+ # multiple : length MUST be a multiple of 'multiple'
+ fields_specs = { "ipv4":[4,0,1], "ipv4+":[0,4,4],
+ "string":[0,0,1], "bool":[1,0,1],
+ "char":[1,0,1], "16-bits":[2,0,1],
+ "32-bits":[4,0,1], "identifier":[0,2,1]}
+
+ specs = fields_specs[DhcpOptionsTypes[DhcpOptions[name]]]
+ length = len(value)
+ if (specs[0]!=0 and specs==length) or (specs[1]<=length and length%specs[2]==0):
+ self.options_data[name] = value
+ return True
+ else :
+ return False
+
+ print "Error, unknown option : ", name, value
+ return False
+
+
+
+ def IsOption(self,name):
+ if self.options_data.has_key(name) : return True
+ elif DhcpFields.has_key(name) : return True
+ else : return False
+
+
+ # Encode Packet and return it
+ def EncodePacket(self):
+ options = []
+
+
+ for each in self.options_data.keys() :
+ options.append(DhcpOptions[each])
+ options.append(len(self.options_data[each]))
+ options += self.options_data[each]
+
+ packet = self.packet_data[:240] + options
+ packet.append(255) # add end option
+ pack_fmt = str(len(packet))+"c"
+
+ packet = map(chr,packet)
+
+ return pack(pack_fmt,*packet)
+
+
+ # Insert packet in the object
+ def DecodePacket(self,data,debug=False):
+ self.packet_data = []
+ self.options_data = {}
+
+ if (not data) : return False
+ # we transform all data to int list
+ unpack_fmt = str(len(data)) + "c"
+ for i in unpack(unpack_fmt,data):
+ self.packet_data.append(ord(i))
+ if ( debug ) : print "Packet length : ",len(self.packet_data)
+
+
+ # Some servers or clients don't place magic cookie immediately
+ # after headers and begin options fields only after magic.
+ # These 4 lines search magic cookie and begin iterator after.
+ iterator = 236
+ end_iterator = len(self.packet_data)
+ while ( self.packet_data[iterator:iterator+4] != MagicCookie and iterator < end_iterator) :
+ iterator += 1
+ iterator += 4
+
+ # parse extended options
+ if ( debug ) : print "Debug : ", self.packet_data[iterator:-1]
+
+
+ while iterator < end_iterator :
+ if ( debug ) :
+ print "Debug Option : ", iterator , self.packet_data[iterator]," : ",DhcpOptionsList[self.packet_data[iterator]]
+ if self.packet_data[iterator] == 0 : # pad option
+ opt_first = iterator+1
+ iterator += 1
+
+ elif self.packet_data[iterator] == 255 :
+ self.packet_data = self.packet_data[:240] # base packet length without magic cookie
+ return
+
+ elif DhcpOptionsTypes.has_key(self.packet_data[iterator]) and self.packet_data[iterator]!= 255:
+ opt_len = self.packet_data[iterator+1]
+ opt_first = iterator+1
+ self.options_data[DhcpOptionsList[self.packet_data[iterator]]] = self.packet_data[opt_first+1:opt_len+opt_first+1]
+ iterator += self.packet_data[opt_first] + 2
+ else :
+ opt_first = iterator+1
+ iterator += self.packet_data[opt_first] + 2
+
+ # cut packet_data to remove options
+
+ self.packet_data = self.packet_data[:240] # base packet length with magic cookie