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# 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#
7import array
9from impacket.ImpactPacket import Header, ImpactPacketException, PacketBuffer
11class IP6_Extension_Header(Header):
12# --------------------------------- - - - - - - -
13# | Next Header | Header Ext Len | Options
14# --------------------------------- - - - - - - -
16 HEADER_TYPE_VALUE = -1
17 EXTENSION_HEADER_FIELDS_SIZE = 2
19 EXTENSION_HEADER_DECODER = None
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()
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()
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"
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'
46 return s
48 def load_header(self, buffer):
49 self.set_bytes_from_string(buffer[:self.get_headers_field_size()])
51 remaining_bytes = (self.get_header_extension_length() + 1) * 8
52 remaining_bytes -= self.get_headers_field_size()
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")
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())
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
74 self._option_list.append(Option_PADN(option_length))
76 remaining_bytes -= option_length
77 buffer = buffer[option_length:]
79 def reset(self):
80 pass
82 @classmethod
83 def get_header_type_value(cls):
84 return cls.HEADER_TYPE_VALUE
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
101 @classmethod
102 def get_decoder(cls):
103 raise RuntimeError("Class method %s.get_decoder must be overridden." % cls)
105 def get_header_type(self):
106 return self.__class__.get_header_type_value()
108 def get_headers_field_size(self):
109 return IP6_Extension_Header.EXTENSION_HEADER_FIELDS_SIZE
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
117 def get_next_header(self):
118 return self.get_byte(0)
120 def get_header_extension_length(self):
121 return self.get_byte(1)
123 def set_next_header(self, next_header):
124 self.set_byte(0, next_header & 0xFF)
126 def set_header_extension_length(self, header_extension_length):
127 self.set_byte(1, header_extension_length & 0xFF)
129 def add_option(self, option):
130 self._option_list.append(option)
132 def get_options(self):
133 return self._option_list
135 def get_packet(self):
136 data = self.get_data_as_string()
138 # Update the header length
139 self.set_header_extension_length(self.get_header_size() // 8 - 1)
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()
146 if data:
147 return header_bytes + data
148 else:
149 return header_bytes
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())
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()
161class Extension_Option(PacketBuffer):
162 MAX_OPTION_LEN = 256
163 OPTION_TYPE_VALUE = -1
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)
171 def __str__(self):
172 option_type = self.get_option_type()
173 option_length = self.get_option_length()
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"
179 return s
181 def set_option_type(self, option_type):
182 self.set_byte(0, option_type)
184 def get_option_type(self):
185 return self.get_byte(0)
187 def set_option_length(self, length):
188 self.set_byte(1, length)
190 def get_option_length(self):
191 return self.get_byte(1)
193 def set_data(self, data):
194 self.set_option_length(len(data))
195 option_bytes = self.get_bytes()
197 option_bytes = self.get_bytes()
198 option_bytes[2:2+len(data)] = array.array('B', data)
199 self.set_bytes(option_bytes)
201 def get_len(self):
202 return len(self.get_bytes())
204class Option_PAD1(Extension_Option):
205 OPTION_TYPE_VALUE = 0x00 # Pad1 (RFC 2460)
206 OPTION_DESCRIPTION = "Pad1 Option"
208 def __init__(self):
209 Extension_Option.__init__(self, Option_PAD1.OPTION_TYPE_VALUE, 1)
211 def get_len(self):
212 return 1
214class Option_PADN(Extension_Option):
215 OPTION_TYPE_VALUE = 0x01 # Pad1 (RFC 2460)
216 OPTION_DESCRIPTION = "PadN Option"
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")
222 Extension_Option.__init__(self, Option_PADN.OPTION_TYPE_VALUE, padding_size)
223 self.set_data(b'\x00' * (padding_size - 2))
225class 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
230 def __init__(self, buffer = None):
231 self.padded = False
232 IP6_Extension_Header.__init__(self, buffer)
234 def reset(self):
235 self.set_next_header(0)
236 self.set_header_extension_length(0)
237 self.add_padding()
239 def add_option(self, option):
240 if self.padded:
241 self._option_list.pop()
242 self.padded = False
244 IP6_Extension_Header.add_option(self, option)
246 self.add_padding()
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")
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
263class Hop_By_Hop(Basic_Extension_Header):
264 HEADER_TYPE_VALUE = 0x00
265 HEADER_EXTENSION_DESCRIPTION = "Hop By Hop Options"
267 @classmethod
268 def get_decoder(self):
269 from impacket import ImpactDecoder
270 return ImpactDecoder.HopByHopDecoder
272class Destination_Options(Basic_Extension_Header):
273 HEADER_TYPE_VALUE = 0x3c
274 HEADER_EXTENSION_DESCRIPTION = "Destination Options"
276 @classmethod
277 def get_decoder(self):
278 from impacket import ImpactDecoder
279 return ImpactDecoder.DestinationOptionsDecoder
281class Routing_Options(IP6_Extension_Header):
282 HEADER_TYPE_VALUE = 0x2b
283 HEADER_EXTENSION_DESCRIPTION = "Routing Options"
284 ROUTING_OPTIONS_HEADER_FIELDS_SIZE = 8
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)
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()
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"
306 return s
308 @classmethod
309 def get_decoder(self):
310 from . import ImpactDecoder
311 return ImpactDecoder.RoutingOptionsDecoder
313 def get_headers_field_size(self):
314 return Routing_Options.ROUTING_OPTIONS_HEADER_FIELDS_SIZE
316 def set_routing_type(self, routing_type):
317 self.set_byte(2, routing_type)
319 def get_routing_type(self):
320 return self.get_byte(2)
322 def set_segments_left(self, segments_left):
323 self.set_byte(3, segments_left)
325 def get_segments_left(self):
326 return self.get_byte(3)