Coverage for /root/GitHubProjects/impacket/impacket/IP6_Extension_Headers.py: 81%

# Coverage for /root/GitHubProjects/impacket/impacket/IP6_Extension_Headers.py : 81%

## 221 statements

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.

2#

3# This software is provided under under a slightly modified version

4# of the Apache Software License. See the accompanying LICENSE file

5# for more information.

6#

7 import array

8

9 from impacket.ImpactPacket import Header, ImpactPacketException, PacketBuffer

10

11 class IP6_Extension_Header(Header):

12# --------------------------------- - - - - - - -

13# | Next Header | Header Ext Len | Options

14# --------------------------------- - - - - - - -

15

16 HEADER_TYPE_VALUE = -1

17 EXTENSION_HEADER_FIELDS_SIZE = 2

18

19 EXTENSION_HEADER_DECODER = None

20

21 def __init__(self, buffer = None):

22 Header.__init__(self, self.get_headers_field_size())

23 self._option_list = []

24 if buffer:

25 self.load_header(buffer)

26 else:

27 self.reset()

28

29 def __str__(self):

30 header_type = self.get_header_type()

31 next_header_value = self.get_next_header()

32 header_ext_length = self.get_header_extension_length()

33

34 s = "Header Extension Name: " + self.__class__.HEADER_EXTENSION_DESCRIPTION + "\n"

35 s += "Header Type Value: " + str(header_type) + "\n"

36 s += "Next Header: " + str(next_header_value) + "\n"

37 s += "Header Extension Length: " + str(header_ext_length) + "\n"

38 s += "Options:\n"

39

40 for option in self._option_list:

41 option_str = str(option)

42 option_str = option_str.split('\n')

43 option_str = [(' ' * 4) + s for s in option_str]

44 s += '\n'.join(option_str) + '\n'

45

46 return s

47

48 def load_header(self, buffer):

49 self.set_bytes_from_string(buffer[:self.get_headers_field_size()])

50

51 remaining_bytes = (self.get_header_extension_length() + 1) * 8

52 remaining_bytes -= self.get_headers_field_size()

53

54 buffer = array.array('B', buffer[self.get_headers_field_size():])

55 if remaining_bytes > len(buffer): 55 ↛ 56line 55 didn't jump to line 56, because the condition on line 55 was never true

56 raise ImpactPacketException("Cannot load options from truncated packet")

57

58 while remaining_bytes > 0:

59 option_type = buffer[0]

60 if option_type == Option_PAD1.OPTION_TYPE_VALUE:

61 # Pad1

62 self._option_list.append(Option_PAD1())

63

64 remaining_bytes -= 1

65 buffer = buffer[1:]

66 else:

67 # PadN

68 # From RFC 2460: For N octets of padding, the Opt Data Len

69 # field contains the value N-2, and the Option Data consists

70 # of N-2 zero-valued octets.

71 option_length = buffer[1]

72 option_length += 2

73

74 self._option_list.append(Option_PADN(option_length))

75

76 remaining_bytes -= option_length

77 buffer = buffer[option_length:]

78

79 def reset(self):

80 pass

81

82 @classmethod

83 def get_header_type_value(cls):

84 return cls.HEADER_TYPE_VALUE

85

86 @classmethod

87 def get_extension_headers(cls):

88 header_types = {}

89 for subclass in cls.__subclasses__():

90 subclass_header_types = subclass.get_extension_headers()

91 if not subclass_header_types:

92 # If the subclass did not return anything it means

93 # that it is a leaf subclass, so we take its header

94 # type value

95 header_types[subclass.get_header_type_value()] = subclass

96 else:

97 # Else we extend the list of the obtained types

98 header_types.update(subclass_header_types)

99 return header_types

100

101 @classmethod

102 def get_decoder(cls):

103 raise RuntimeError("Class method %s.get_decoder must be overridden." % cls)

104

105 def get_header_type(self):

106 return self.__class__.get_header_type_value()

107

108 def get_headers_field_size(self):

109 return IP6_Extension_Header.EXTENSION_HEADER_FIELDS_SIZE

110

111 def get_header_size(self):

112 header_size = self.get_headers_field_size()

113 for option in self._option_list:

114 header_size += option.get_len()

115 return header_size

116

117 def get_next_header(self):

118 return self.get_byte(0)

119

120 def get_header_extension_length(self):

121 return self.get_byte(1)

122

123 def set_next_header(self, next_header):

124 self.set_byte(0, next_header & 0xFF)

125

126 def set_header_extension_length(self, header_extension_length):

127 self.set_byte(1, header_extension_length & 0xFF)

128

129 def add_option(self, option):

130 self._option_list.append(option)

131

132 def get_options(self):

133 return self._option_list

134

135 def get_packet(self):

136 data = self.get_data_as_string()

137

138 # Update the header length

139 self.set_header_extension_length(self.get_header_size() // 8 - 1)

140

141 # Build the entire extension header packet

142 header_bytes = self.get_buffer_as_string()

143 for option in self._option_list:

144 header_bytes += option.get_buffer_as_string()

145

146 if data:

147 return header_bytes + data

148 else:

149 return header_bytes

150

151 def contains(self, aHeader):

152 Header.contains(self, aHeader)

153 if isinstance(aHeader, IP6_Extension_Header):

154 self.set_next_header(aHeader.get_header_type())

155

156 def get_pseudo_header(self):

157 # The pseudo-header only contains data from the IPv6 header.

158 # So we pass the message to the parent until it reaches it.

159 return self.parent().get_pseudo_header()

160

161 class Extension_Option(PacketBuffer):

162 MAX_OPTION_LEN = 256

163 OPTION_TYPE_VALUE = -1

164

165 def __init__(self, option_type, size):

166 if size > Extension_Option.MAX_OPTION_LEN: 166 ↛ 167line 166 didn't jump to line 167, because the condition on line 166 was never true

167 raise ImpactPacketException("Option size of % is greater than the maximum of %d" % (size, Extension_Option.MAX_OPTION_LEN))

168 PacketBuffer.__init__(self, size)

169 self.set_option_type(option_type)

170

171 def __str__(self):

172 option_type = self.get_option_type()

173 option_length = self.get_option_length()

174

175 s = "Option Name: " + str(self.__class__.OPTION_DESCRIPTION) + "\n"

176 s += "Option Type: " + str(option_type) + "\n"

177 s += "Option Length: " + str(option_length) + "\n"

178

179 return s

180

181 def set_option_type(self, option_type):

182 self.set_byte(0, option_type)

183

184 def get_option_type(self):

185 return self.get_byte(0)

186

187 def set_option_length(self, length):

188 self.set_byte(1, length)

189

190 def get_option_length(self):

191 return self.get_byte(1)

192

193 def set_data(self, data):

194 self.set_option_length(len(data))

195 option_bytes = self.get_bytes()

196

197 option_bytes = self.get_bytes()

198 option_bytes[2:2+len(data)] = array.array('B', data)

199 self.set_bytes(option_bytes)

200

201 def get_len(self):

202 return len(self.get_bytes())

203

204 class Option_PAD1(Extension_Option):

205 OPTION_TYPE_VALUE = 0x00 # Pad1 (RFC 2460)

206 OPTION_DESCRIPTION = "Pad1 Option"

207

208 def __init__(self):

209 Extension_Option.__init__(self, Option_PAD1.OPTION_TYPE_VALUE, 1)

210

211 def get_len(self):

212 return 1

213

214 class Option_PADN(Extension_Option):

215 OPTION_TYPE_VALUE = 0x01 # Pad1 (RFC 2460)

216 OPTION_DESCRIPTION = "PadN Option"

217

218 def __init__(self, padding_size):

219 if padding_size < 2: 219 ↛ 220line 219 didn't jump to line 220, because the condition on line 219 was never true

220 raise ImpactPacketException("PadN Extension Option must be greater than 2 bytes")

221

222 Extension_Option.__init__(self, Option_PADN.OPTION_TYPE_VALUE, padding_size)

223 self.set_data(b'\x00' * (padding_size - 2))

224

225 class Basic_Extension_Header(IP6_Extension_Header):

226 MAX_OPTIONS_LEN = 256 * 8

227 MIN_HEADER_LEN = 8

228 MAX_HEADER_LEN = MIN_HEADER_LEN + MAX_OPTIONS_LEN

229

230 def __init__(self, buffer = None):

231 self.padded = False

232 IP6_Extension_Header.__init__(self, buffer)

233

234 def reset(self):

235 self.set_next_header(0)

236 self.set_header_extension_length(0)

237 self.add_padding()

238

239 def add_option(self, option):

240 if self.padded:

241 self._option_list.pop()

242 self.padded = False

243

244 IP6_Extension_Header.add_option(self, option)

245

246 self.add_padding()

247

248 def add_padding(self):

249 required_octets = 8 - (self.get_header_size() % 8)

250 if self.get_header_size() + required_octets > Basic_Extension_Header.MAX_HEADER_LEN: 250 ↛ 251line 250 didn't jump to line 251, because the condition on line 250 was never true

251 raise Exception("Not enough space for the padding")

252

253 # Insert Pad1 or PadN to fill the necessary octets

254 if 0 < required_octets < 8:

255 if required_octets == 1: 255 ↛ 256line 255 didn't jump to line 256, because the condition on line 255 was never true

256 self.add_option(Option_PAD1())

257 else:

258 self.add_option(Option_PADN(required_octets))

259 self.padded = True

260 else:

261 self.padded = False

262

263 class Hop_By_Hop(Basic_Extension_Header):

264 HEADER_TYPE_VALUE = 0x00

265 HEADER_EXTENSION_DESCRIPTION = "Hop By Hop Options"

266

267 @classmethod

268 def get_decoder(self):

269 from impacket import ImpactDecoder

270 return ImpactDecoder.HopByHopDecoder

271

272 class Destination_Options(Basic_Extension_Header):

273 HEADER_TYPE_VALUE = 0x3c

274 HEADER_EXTENSION_DESCRIPTION = "Destination Options"

275

276 @classmethod

277 def get_decoder(self):

278 from impacket import ImpactDecoder

279 return ImpactDecoder.DestinationOptionsDecoder

280

281 class Routing_Options(IP6_Extension_Header):

282 HEADER_TYPE_VALUE = 0x2b

283 HEADER_EXTENSION_DESCRIPTION = "Routing Options"

284 ROUTING_OPTIONS_HEADER_FIELDS_SIZE = 8

285

286 def reset(self):

287 self.set_next_header(0)

288 self.set_header_extension_length(0)

289 self.set_routing_type(0)

290 self.set_segments_left(0)

291

292 def __str__(self):

293 header_type = self.get_header_type()

294 next_header_value = self.get_next_header()

295 header_ext_length = self.get_header_extension_length()

296 routing_type = self.get_routing_type()

297 segments_left = self.get_segments_left()

298

299 s = "Header Extension Name: " + self.__class__.HEADER_EXTENSION_DESCRIPTION + "\n"

300 s += "Header Type Value: " + str(header_type) + "\n"

301 s += "Next Header: " + str(next_header_value) + "\n"

302 s += "Header Extension Length: " + str(header_ext_length) + "\n"

303 s += "Routing Type: " + str(routing_type) + "\n"

304 s += "Segments Left: " + str(segments_left) + "\n"

305

306 return s

307

308 @classmethod

309 def get_decoder(self):

310 from . import ImpactDecoder

311 return ImpactDecoder.RoutingOptionsDecoder

312

313 def get_headers_field_size(self):

314 return Routing_Options.ROUTING_OPTIONS_HEADER_FIELDS_SIZE

315

316 def set_routing_type(self, routing_type):

317 self.set_byte(2, routing_type)

318

319 def get_routing_type(self):

320 return self.get_byte(2)

321

322 def set_segments_left(self, segments_left):

323 self.set_byte(3, segments_left)

324

325 def get_segments_left(self):

326 return self.get_byte(3)