You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dhcp_basic_packet.py 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. # pydhcplib
  2. # Copyright (C) 2008 Mathieu Ignacio -- mignacio@april.org
  3. #
  4. # This file is part of pydhcplib.
  5. # Pydhcplib is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 3 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. import operator
  18. from struct import unpack
  19. from struct import pack
  20. from dhcp_constants import *
  21. import sys
  22. # DhcpPacket : base class to encode/decode dhcp packets.
  23. class DhcpBasicPacket:
  24. def __init__(self):
  25. self.packet_data = [0]*240
  26. self.options_data = {}
  27. self.packet_data[236:240] = MagicCookie
  28. self.source_address = False
  29. def IsDhcpPacket(self):
  30. if self.packet_data[236:240] != MagicCookie : return False
  31. return True
  32. # Check if variable is a list with int between 0 and 255
  33. def CheckType(self,variable):
  34. if type(variable) == list :
  35. for each in variable :
  36. if (type(each) != int) or (each < 0) or (each > 255) :
  37. return False
  38. return True
  39. else : return False
  40. def DeleteOption(self,name):
  41. # if name is a standard dhcp field
  42. # Set field to 0
  43. if DhcpFields.has_key(name) :
  44. begin = DhcpFields[name][0]
  45. end = DhcpFields[name][0]+DhcpFields[name][1]
  46. self.packet_data[begin:end] = [0]*DhcpFields[name][1]
  47. return True
  48. # if name is a dhcp option
  49. # delete option from self.option_data
  50. elif self.options_data.has_key(name) :
  51. # forget how to remove a key... try delete
  52. self.options_data.__delitem__(name)
  53. return True
  54. return False
  55. def GetOption(self,name):
  56. if DhcpFields.has_key(name) :
  57. option_info = DhcpFields[name]
  58. return self.packet_data[option_info[0]:option_info[0]+option_info[1]]
  59. elif self.options_data.has_key(name) :
  60. return self.options_data[name]
  61. return []
  62. def SetOption(self,name,value):
  63. # Basic value checking :
  64. # has value list a correct length
  65. # if name is a standard dhcp field
  66. if DhcpFields.has_key(name) :
  67. if len(value) != DhcpFields[name][1] :
  68. sys.stderr.write( "pydhcplib.dhcp_basic_packet.setoption error, bad option length : "+name+" Expected: "+str(DhcpFields[name][1])+" Got: "+str(len(value)))
  69. return False
  70. begin = DhcpFields[name][0]
  71. end = DhcpFields[name][0]+DhcpFields[name][1]
  72. self.packet_data[begin:end] = value
  73. return True
  74. # if name is a dhcp option
  75. elif DhcpOptions.has_key(name) :
  76. # fields_specs : {'option_code':fixed_length,minimum_length,multiple}
  77. # if fixed_length == 0 : minimum_length and multiple apply
  78. # else : forget minimum_length and multiple
  79. # multiple : length MUST be a multiple of 'multiple'
  80. # FIXME : this definition should'nt be in dhcp_constants ?
  81. fields_specs = { "ipv4":[4,0,1], "ipv4+":[0,4,4],
  82. "string":[0,0,1], "bool":[1,0,1],
  83. "char":[1,0,1], "16-bits":[2,0,1],
  84. "32-bits":[4,0,1], "identifier":[0,2,1],
  85. "RFC3397":[0,4,1],"none":[0,0,1],"char+":[0,1,1]
  86. }
  87. specs = fields_specs[DhcpOptionsTypes[DhcpOptions[name]]]
  88. length = len(value)
  89. if (specs[0]!=0 and specs==length) or (specs[1]<=length and length%specs[2]==0):
  90. self.options_data[name] = value
  91. return True
  92. else :
  93. return False
  94. sys.stderr.write( "pydhcplib.dhcp_basic_packet.setoption error : unknown option "+name)
  95. return False
  96. def IsOption(self,name):
  97. if self.options_data.has_key(name) : return True
  98. elif DhcpFields.has_key(name) : return True
  99. else : return False
  100. # Encode Packet and return it
  101. def EncodePacket(self):
  102. # MUST set options in order to respect the RFC (see router option)
  103. order = {}
  104. for each in self.options_data.keys() :
  105. order[DhcpOptions[each]] = []
  106. order[DhcpOptions[each]].append(DhcpOptions[each])
  107. order[DhcpOptions[each]].append(len(self.options_data[each]))
  108. order[DhcpOptions[each]] += self.options_data[each]
  109. options = []
  110. for each in sorted(order.keys()) : options += (order[each])
  111. packet = self.packet_data[:240] + options
  112. packet.append(255) # add end option
  113. pack_fmt = str(len(packet))+"c"
  114. packet = map(chr,packet)
  115. data = pack(pack_fmt,*packet)
  116. data_len = len(data)
  117. if data_len < 300:
  118. data = data + (300 - data_len) * '\0'
  119. return data
  120. # Insert packet in the object
  121. def DecodePacket(self,data,debug=False):
  122. self.packet_data = []
  123. self.options_data = {}
  124. if (not data) : return False
  125. # we transform all data to int list
  126. unpack_fmt = str(len(data)) + "c"
  127. for i in unpack(unpack_fmt,data):
  128. self.packet_data.append(ord(i))
  129. # Some servers or clients don't place magic cookie immediately
  130. # after headers and begin options fields only after magic.
  131. # These 4 lines search magic cookie and begin iterator after.
  132. iterator = 236
  133. end_iterator = len(self.packet_data)
  134. while ( self.packet_data[iterator:iterator+4] != MagicCookie and iterator < end_iterator) :
  135. iterator += 1
  136. iterator += 4
  137. # parse extended options
  138. while iterator < end_iterator :
  139. if self.packet_data[iterator] == 0 : # pad option
  140. opt_first = iterator+1
  141. iterator += 1
  142. elif self.packet_data[iterator] == 255 :
  143. self.packet_data = self.packet_data[:240] # base packet length without magic cookie
  144. return
  145. elif DhcpOptionsTypes.has_key(self.packet_data[iterator]) and self.packet_data[iterator]!= 255:
  146. opt_len = self.packet_data[iterator+1]
  147. opt_first = iterator+1
  148. self.options_data[DhcpOptionsList[self.packet_data[iterator]]] = self.packet_data[opt_first+1:opt_len+opt_first+1]
  149. iterator += self.packet_data[opt_first] + 2
  150. else :
  151. opt_first = iterator+1
  152. iterator += self.packet_data[opt_first] + 2
  153. # cut packet_data to remove options
  154. self.packet_data = self.packet_data[:240] # base packet length with magic cookie