Hide keyboard shortcuts

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 

10import array 

11 

12from impacket.ImpactPacket import Header, ImpactPacketException, PacketBuffer 

13 

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

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

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

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

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

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

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

284class 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)