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# Impacket - Collection of Python classes for working with network protocols.

2#

3# SECUREAUTH LABS. Copyright (C) 2018 SecureAuth Corporation. All rights reserved.

4#

5# This software is provided under a slightly modified version

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

7# for more information.

8#

9

10 import array

11

12 from impacket.ImpactPacket import Header, ImpactPacketException, PacketBuffer

13

14 class IP6_Extension_Header(Header):

15# --------------------------------- - - - - - - -

16# | Next Header | Header Ext Len | Options

17# --------------------------------- - - - - - - -

18

19 HEADER_TYPE_VALUE = -1

20 EXTENSION_HEADER_FIELDS_SIZE = 2

21

22 EXTENSION_HEADER_DECODER = None

23

24 def __init__(self, buffer = None):

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

26 self._option_list = []

27 if buffer:

28 self.load_header(buffer)

29 else:

30 self.reset()

31

32 def __str__(self):

33 header_type = self.get_header_type()

34 next_header_value = self.get_next_header()

35 header_ext_length = self.get_header_extension_length()

36

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

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

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

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

41 s += "Options:\n"

42

43 for option in self._option_list:

44 option_str = str(option)

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

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

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

48

49 return s

50

51 def load_header(self, buffer):

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

53

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

55 remaining_bytes -= self.get_headers_field_size()

56

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

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

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

60

61 while remaining_bytes > 0:

62 option_type = buffer[0]

63 if option_type == Option_PAD1.OPTION_TYPE_VALUE:

64 # Pad1

65 self._option_list.append(Option_PAD1())

66

67 remaining_bytes -= 1

68 buffer = buffer[1:]

69 else:

70 # PadN

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

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

73 # of N-2 zero-valued octets.

74 option_length = buffer[1]

75 option_length += 2

76

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

78

79 remaining_bytes -= option_length

80 buffer = buffer[option_length:]

81

82 def reset(self):

83 pass

84

85 @classmethod

86 def get_header_type_value(cls):

87 return cls.HEADER_TYPE_VALUE

88

89 @classmethod

90 def get_extension_headers(cls):

91 header_types = {}

92 for subclass in cls.__subclasses__():

93 subclass_header_types = subclass.get_extension_headers()

94 if not subclass_header_types:

95 # If the subclass did not return anything it means

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

97 # type value

98 header_types[subclass.get_header_type_value()] = subclass

99 else:

100 # Else we extend the list of the obtained types

101 header_types.update(subclass_header_types)

102 return header_types

103

104 @classmethod

105 def get_decoder(cls):

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

107

108 def get_header_type(self):

109 return self.__class__.get_header_type_value()

110

111 def get_headers_field_size(self):

112 return IP6_Extension_Header.EXTENSION_HEADER_FIELDS_SIZE

113

114 def get_header_size(self):

115 header_size = self.get_headers_field_size()

116 for option in self._option_list:

117 header_size += option.get_len()

118 return header_size

119

120 def get_next_header(self):

121 return self.get_byte(0)

122

123 def get_header_extension_length(self):

124 return self.get_byte(1)

125

126 def set_next_header(self, next_header):

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

128

129 def set_header_extension_length(self, header_extension_length):

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

131

132 def add_option(self, option):

133 self._option_list.append(option)

134

135 def get_options(self):

136 return self._option_list

137

138 def get_packet(self):

139 data = self.get_data_as_string()

140

141 # Update the header length

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

143

144 # Build the entire extension header packet

145 header_bytes = self.get_buffer_as_string()

146 for option in self._option_list:

147 header_bytes += option.get_buffer_as_string()

148

149 if data:

150 return header_bytes + data

151 else:

152 return header_bytes

153

154 def contains(self, aHeader):

155 Header.contains(self, aHeader)

156 if isinstance(aHeader, IP6_Extension_Header):

157 self.set_next_header(aHeader.get_header_type())

158

159 def get_pseudo_header(self):

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

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

162 return self.parent().get_pseudo_header()

163

164 class Extension_Option(PacketBuffer):

165 MAX_OPTION_LEN = 256

166 OPTION_TYPE_VALUE = -1

167

168 def __init__(self, option_type, size):

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

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

171 PacketBuffer.__init__(self, size)

172 self.set_option_type(option_type)

173

174 def __str__(self):

175 option_type = self.get_option_type()

176 option_length = self.get_option_length()

177

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

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

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

181

182 return s

183

184 def set_option_type(self, option_type):

185 self.set_byte(0, option_type)

186

187 def get_option_type(self):

188 return self.get_byte(0)

189

190 def set_option_length(self, length):

191 self.set_byte(1, length)

192

193 def get_option_length(self):

194 return self.get_byte(1)

195

196 def set_data(self, data):

197 self.set_option_length(len(data))

198 option_bytes = self.get_bytes()

199

200 option_bytes = self.get_bytes()

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

202 self.set_bytes(option_bytes)

203

204 def get_len(self):

205 return len(self.get_bytes())

206

207 class Option_PAD1(Extension_Option):

208 OPTION_TYPE_VALUE = 0x00 # Pad1 (RFC 2460)

209 OPTION_DESCRIPTION = "Pad1 Option"

210

211 def __init__(self):

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

213

214 def get_len(self):

215 return 1

216

217 class Option_PADN(Extension_Option):

218 OPTION_TYPE_VALUE = 0x01 # Pad1 (RFC 2460)

219 OPTION_DESCRIPTION = "PadN Option"

220

221 def __init__(self, padding_size):

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

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

224

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

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

227

228 class Basic_Extension_Header(IP6_Extension_Header):

229 MAX_OPTIONS_LEN = 256 * 8

230 MIN_HEADER_LEN = 8

231 MAX_HEADER_LEN = MIN_HEADER_LEN + MAX_OPTIONS_LEN

232

233 def __init__(self, buffer = None):

234 self.padded = False

235 IP6_Extension_Header.__init__(self, buffer)

236

237 def reset(self):

238 self.set_next_header(0)

239 self.set_header_extension_length(0)

240 self.add_padding()

241

242 def add_option(self, option):

243 if self.padded:

244 self._option_list.pop()

245 self.padded = False

246

247 IP6_Extension_Header.add_option(self, option)

248

249 self.add_padding()

250

251 def add_padding(self):

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

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

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

255

256 # Insert Pad1 or PadN to fill the necessary octets

257 if 0 < required_octets < 8:

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

259 self.add_option(Option_PAD1())

260 else:

261 self.add_option(Option_PADN(required_octets))

262 self.padded = True

263 else:

264 self.padded = False

265

266 class Hop_By_Hop(Basic_Extension_Header):

267 HEADER_TYPE_VALUE = 0x00

268 HEADER_EXTENSION_DESCRIPTION = "Hop By Hop Options"

269

270 @classmethod

271 def get_decoder(self):

272 from impacket import ImpactDecoder

273 return ImpactDecoder.HopByHopDecoder

274

275 class Destination_Options(Basic_Extension_Header):

276 HEADER_TYPE_VALUE = 0x3c

277 HEADER_EXTENSION_DESCRIPTION = "Destination Options"

278

279 @classmethod

280 def get_decoder(self):

281 from impacket import ImpactDecoder

282 return ImpactDecoder.DestinationOptionsDecoder

283

284 class Routing_Options(IP6_Extension_Header):

285 HEADER_TYPE_VALUE = 0x2b

286 HEADER_EXTENSION_DESCRIPTION = "Routing Options"

287 ROUTING_OPTIONS_HEADER_FIELDS_SIZE = 8

288

289 def reset(self):

290 self.set_next_header(0)

291 self.set_header_extension_length(0)

292 self.set_routing_type(0)

293 self.set_segments_left(0)

294

295 def __str__(self):

296 header_type = self.get_header_type()

297 next_header_value = self.get_next_header()

298 header_ext_length = self.get_header_extension_length()

299 routing_type = self.get_routing_type()

300 segments_left = self.get_segments_left()

301

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

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

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

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

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

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

308

309 return s

310

311 @classmethod

312 def get_decoder(self):

313 from . import ImpactDecoder

314 return ImpactDecoder.RoutingOptionsDecoder

315

316 def get_headers_field_size(self):

317 return Routing_Options.ROUTING_OPTIONS_HEADER_FIELDS_SIZE

318

319 def set_routing_type(self, routing_type):

320 self.set_byte(2, routing_type)

321

322 def get_routing_type(self):

323 return self.get_byte(2)

324

325 def set_segments_left(self, segments_left):

326 self.set_byte(3, segments_left)

327

328 def get_segments_left(self):

329 return self.get_byte(3)