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

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#
10import array
12from impacket.ImpactPacket import Header, ImpactPacketException, PacketBuffer
14class IP6_Extension_Header(Header):
15# --------------------------------- - - - - - - -
16# | Next Header | Header Ext Len | Options
17# --------------------------------- - - - - - - -
19 HEADER_TYPE_VALUE = -1
20 EXTENSION_HEADER_FIELDS_SIZE = 2
22 EXTENSION_HEADER_DECODER = None
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()
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()
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"
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'
49 return s
51 def load_header(self, buffer):
52 self.set_bytes_from_string(buffer[:self.get_headers_field_size()])
54 remaining_bytes = (self.get_header_extension_length() + 1) * 8
55 remaining_bytes -= self.get_headers_field_size()
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")
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())
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
77 self._option_list.append(Option_PADN(option_length))
79 remaining_bytes -= option_length
80 buffer = buffer[option_length:]
82 def reset(self):
83 pass
85 @classmethod
86 def get_header_type_value(cls):
87 return cls.HEADER_TYPE_VALUE
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
104 @classmethod
105 def get_decoder(cls):
106 raise RuntimeError("Class method %s.get_decoder must be overridden." % cls)
108 def get_header_type(self):
109 return self.__class__.get_header_type_value()
111 def get_headers_field_size(self):
112 return IP6_Extension_Header.EXTENSION_HEADER_FIELDS_SIZE
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
120 def get_next_header(self):
121 return self.get_byte(0)
123 def get_header_extension_length(self):
124 return self.get_byte(1)
126 def set_next_header(self, next_header):
127 self.set_byte(0, next_header & 0xFF)
129 def set_header_extension_length(self, header_extension_length):
130 self.set_byte(1, header_extension_length & 0xFF)
132 def add_option(self, option):
133 self._option_list.append(option)
135 def get_options(self):
136 return self._option_list
138 def get_packet(self):
139 data = self.get_data_as_string()
141 # Update the header length
142 self.set_header_extension_length(self.get_header_size() // 8 - 1)
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()
149 if data:
150 return header_bytes + data
151 else:
152 return header_bytes
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())
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()
164class Extension_Option(PacketBuffer):
165 MAX_OPTION_LEN = 256
166 OPTION_TYPE_VALUE = -1
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)
174 def __str__(self):
175 option_type = self.get_option_type()
176 option_length = self.get_option_length()
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"
182 return s
184 def set_option_type(self, option_type):
185 self.set_byte(0, option_type)
187 def get_option_type(self):
188 return self.get_byte(0)
190 def set_option_length(self, length):
191 self.set_byte(1, length)
193 def get_option_length(self):
194 return self.get_byte(1)
196 def set_data(self, data):
197 self.set_option_length(len(data))
198 option_bytes = self.get_bytes()
200 option_bytes = self.get_bytes()
201 option_bytes[2:2+len(data)] = array.array('B', data)
202 self.set_bytes(option_bytes)
204 def get_len(self):
205 return len(self.get_bytes())
207class Option_PAD1(Extension_Option):
208 OPTION_TYPE_VALUE = 0x00 # Pad1 (RFC 2460)
209 OPTION_DESCRIPTION = "Pad1 Option"
211 def __init__(self):
212 Extension_Option.__init__(self, Option_PAD1.OPTION_TYPE_VALUE, 1)
214 def get_len(self):
215 return 1
217class Option_PADN(Extension_Option):
218 OPTION_TYPE_VALUE = 0x01 # Pad1 (RFC 2460)
219 OPTION_DESCRIPTION = "PadN Option"
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")
225 Extension_Option.__init__(self, Option_PADN.OPTION_TYPE_VALUE, padding_size)
226 self.set_data(b'\x00' * (padding_size - 2))
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
233 def __init__(self, buffer = None):
234 self.padded = False
235 IP6_Extension_Header.__init__(self, buffer)
237 def reset(self):
238 self.set_next_header(0)
239 self.set_header_extension_length(0)
240 self.add_padding()
242 def add_option(self, option):
243 if self.padded:
244 self._option_list.pop()
245 self.padded = False
247 IP6_Extension_Header.add_option(self, option)
249 self.add_padding()
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")
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
266class Hop_By_Hop(Basic_Extension_Header):
267 HEADER_TYPE_VALUE = 0x00
268 HEADER_EXTENSION_DESCRIPTION = "Hop By Hop Options"
270 @classmethod
271 def get_decoder(self):
272 from impacket import ImpactDecoder
273 return ImpactDecoder.HopByHopDecoder
275class Destination_Options(Basic_Extension_Header):
276 HEADER_TYPE_VALUE = 0x3c
277 HEADER_EXTENSION_DESCRIPTION = "Destination Options"
279 @classmethod
280 def get_decoder(self):
281 from impacket import ImpactDecoder
282 return ImpactDecoder.DestinationOptionsDecoder
284class Routing_Options(IP6_Extension_Header):
285 HEADER_TYPE_VALUE = 0x2b
286 HEADER_EXTENSION_DESCRIPTION = "Routing Options"
287 ROUTING_OPTIONS_HEADER_FIELDS_SIZE = 8
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)
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()
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"
309 return s
311 @classmethod
312 def get_decoder(self):
313 from . import ImpactDecoder
314 return ImpactDecoder.RoutingOptionsDecoder
316 def get_headers_field_size(self):
317 return Routing_Options.ROUTING_OPTIONS_HEADER_FIELDS_SIZE
319 def set_routing_type(self, routing_type):
320 self.set_byte(2, routing_type)
322 def get_routing_type(self):
323 return self.get_byte(2)
325 def set_segments_left(self, segments_left):
326 self.set_byte(3, segments_left)
328 def get_segments_left(self):
329 return self.get_byte(3)