1 use crate::{
2     err::{ipv6_exts::*, Layer},
3     *,
4 };
5 
6 /// IPv6 extension headers present after the ip header.
7 ///
8 /// Currently supported:
9 ///
10 /// * Authentication Header
11 /// * Hop by Hop Options Header
12 /// * Destination Options Header (before and after routing headers)
13 /// * Routing Header
14 /// * Fragment
15 /// * Authentication Header
16 ///
17 /// Currently not supported:
18 ///
19 /// * Encapsulating Security Payload Header (ESP)
20 /// * Host Identity Protocol (HIP)
21 /// * IP Mobility
22 /// * Site Multihoming by IPv6 Intermediation (SHIM6)
23 #[derive(Clone, Debug, Eq, PartialEq, Default)]
24 pub struct Ipv6Extensions {
25     pub hop_by_hop_options: Option<Ipv6RawExtHeader>,
26     pub destination_options: Option<Ipv6RawExtHeader>,
27     pub routing: Option<Ipv6RoutingExtensions>,
28     pub fragment: Option<Ipv6FragmentHeader>,
29     pub auth: Option<IpAuthHeader>,
30 }
31 
32 impl Ipv6Extensions {
33     /// Minimum length required for extension header in bytes/octets.
34     /// Which is zero as no extension headers are required.
35     pub const MIN_LEN: usize = 0;
36 
37     /// Maximum summed up length of all extension headers in bytes/octets.
38     pub const MAX_LEN: usize = Ipv6RawExtHeader::MAX_LEN * 2
39         + Ipv6RoutingExtensions::MAX_LEN
40         + Ipv6FragmentHeader::LEN
41         + IpAuthHeader::MAX_LEN;
42 
43     /// Reads as many extension headers as possible from the slice.
44     ///
45     /// Returns the found ipv6 extension headers, the next header ip number after the read
46     /// headers and a slice containing the rest of the packet after the read headers.
47     ///
48     /// Note that this function can only handle ipv6 extensions if each extension header does
49     /// occur at most once, except for destination options headers which are allowed to
50     /// exist once in front of a routing header and once after a routing header.
51     ///
52     /// In case that more extension headers then can fit into a `Ipv6Extensions` struct are
53     /// encountered, the parsing is stoped at the point where the data would no longer fit into
54     /// the struct. In such a scenario a struct with the data that could be parsed is returned
55     /// together with the next header ip number and slice containing the unparsed data.
56     ///
57     /// It is in the responsibility of the caller to handle a scenario like this.
58     ///
59     /// The reason that no error is generated, is that even though according to RFC 8200 packets
60     /// "should" not contain more then one occurence of an extension header the RFC also specifies
61     /// that "IPv6 nodes must accept and attempt to process extension headers in any order and
62     /// occurring any number of times in the same packet". So packets with multiple headers "should"
63     /// not exist, but are still valid IPv6 packets. As such this function does not generate a
64     /// parsing error, as it is not an invalid packet, but if packets like these are encountered
65     /// the user of this function has to themself decide how to handle packets like these.
66     ///
67     /// The only exception is if an hop by hop header is located somewhere else then directly at
68     /// the start. In this case an `ReadError::Ipv6HopByHopHeaderNotAtStart` error is generated as
69     /// the hop by hop header is required to be located directly after the IPv6 header according
70     /// to RFC 8200.
from_slice( start_ip_number: IpNumber, slice: &[u8], ) -> Result<(Ipv6Extensions, IpNumber, &[u8]), err::ipv6_exts::HeaderSliceError>71     pub fn from_slice(
72         start_ip_number: IpNumber,
73         slice: &[u8],
74     ) -> Result<(Ipv6Extensions, IpNumber, &[u8]), err::ipv6_exts::HeaderSliceError> {
75         let mut result: Ipv6Extensions = Default::default();
76         let mut rest = slice;
77         let mut next_header = start_ip_number;
78 
79         use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*};
80         use ip_number::*;
81 
82         // the hop by hop header is required to occur directly after the ipv6 header
83         if IPV6_HOP_BY_HOP == next_header {
84             let slice = Ipv6RawExtHeaderSlice::from_slice(rest).map_err(Len)?;
85             rest = &rest[slice.slice().len()..];
86             next_header = slice.next_header();
87             result.hop_by_hop_options = Some(slice.to_header());
88         }
89 
90         loop {
91             match next_header {
92                 IPV6_HOP_BY_HOP => {
93                     return Err(Content(HopByHopNotAtStart));
94                 }
95                 IPV6_DEST_OPTIONS => {
96                     if let Some(ref mut routing) = result.routing {
97                         // if the routing header is already present
98                         // this this a "final destination options" header
99                         if routing.final_destination_options.is_some() {
100                             // more then one header of this type found -> abort parsing
101                             return Ok((result, next_header, rest));
102                         } else {
103                             let slice = Ipv6RawExtHeaderSlice::from_slice(rest)
104                                 .map_err(|err| Len(err.add_offset(slice.len() - rest.len())))?;
105                             rest = &rest[slice.slice().len()..];
106                             next_header = slice.next_header();
107                             routing.final_destination_options = Some(slice.to_header());
108                         }
109                     } else if result.destination_options.is_some() {
110                         // more then one header of this type found -> abort parsing
111                         return Ok((result, next_header, rest));
112                     } else {
113                         let slice = Ipv6RawExtHeaderSlice::from_slice(rest)
114                             .map_err(|err| Len(err.add_offset(slice.len() - rest.len())))?;
115                         rest = &rest[slice.slice().len()..];
116                         next_header = slice.next_header();
117                         result.destination_options = Some(slice.to_header());
118                     }
119                 }
120                 IPV6_ROUTE => {
121                     if result.routing.is_some() {
122                         // more then one header of this type found -> abort parsing
123                         return Ok((result, next_header, rest));
124                     } else {
125                         let slice = Ipv6RawExtHeaderSlice::from_slice(rest)
126                             .map_err(|err| Len(err.add_offset(slice.len() - rest.len())))?;
127                         rest = &rest[slice.slice().len()..];
128                         next_header = slice.next_header();
129                         result.routing = Some(Ipv6RoutingExtensions {
130                             routing: slice.to_header(),
131                             final_destination_options: None,
132                         });
133                     }
134                 }
135                 IPV6_FRAG => {
136                     if result.fragment.is_some() {
137                         // more then one header of this type found -> abort parsing
138                         return Ok((result, next_header, rest));
139                     } else {
140                         let slice = Ipv6FragmentHeaderSlice::from_slice(rest)
141                             .map_err(|err| Len(err.add_offset(slice.len() - rest.len())))?;
142                         rest = &rest[slice.slice().len()..];
143                         next_header = slice.next_header();
144                         result.fragment = Some(slice.to_header());
145                     }
146                 }
147                 AUTH => {
148                     if result.auth.is_some() {
149                         // more then one header of this type found -> abort parsing
150                         return Ok((result, next_header, rest));
151                     } else {
152                         let slice = IpAuthHeaderSlice::from_slice(rest).map_err(|err| {
153                             use err::ip_auth::HeaderSliceError as I;
154                             use err::ipv6_exts::HeaderError as O;
155                             match err {
156                                 I::Len(err) => Len(err.add_offset(slice.len() - rest.len())),
157                                 I::Content(err) => Content(O::IpAuth(err)),
158                             }
159                         })?;
160                         rest = &rest[slice.slice().len()..];
161                         next_header = slice.next_header();
162                         result.auth = Some(slice.to_header());
163                     }
164                 }
165                 _ => {
166                     // done parsing, the next header is not a known header extension
167                     return Ok((result, next_header, rest));
168                 }
169             }
170         }
171         //should not be hit
172     }
173 
174     /// Reads as many extension headers as possible from the slice until a non IPv6 extension
175     /// header or an error gets encountered.
176     ///
177     /// This function differs from [`Ipv6Extensions::from_slice`] in that it returns the successfully
178     /// parsed parts together with the error. While [`Ipv6Extensions::from_slice`] only returns an
179     /// error.
180     ///
181     /// Note that this function (same as [`Ipv6Extensions::from_slice`]) will stop parsing as soon
182     /// as more headers then can be stored in [`Ipv6Extensions`] are encountered. E.g. if there is
183     /// more then one "auth" header the function returns as soon as the second "auth" header is
184     /// encountered.
from_slice_lax( start_ip_number: IpNumber, slice: &[u8], ) -> ( Ipv6Extensions, IpNumber, &[u8], Option<(err::ipv6_exts::HeaderSliceError, err::Layer)>, )185     pub fn from_slice_lax(
186         start_ip_number: IpNumber,
187         slice: &[u8],
188     ) -> (
189         Ipv6Extensions,
190         IpNumber,
191         &[u8],
192         Option<(err::ipv6_exts::HeaderSliceError, err::Layer)>,
193     ) {
194         let mut result: Ipv6Extensions = Default::default();
195         let mut rest = slice;
196         let mut next_header = start_ip_number;
197 
198         use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*};
199         use ip_number::*;
200 
201         // the hop by hop header is required to occur directly after the ipv6 header
202         if IPV6_HOP_BY_HOP == next_header {
203             match Ipv6RawExtHeaderSlice::from_slice(rest) {
204                 Ok(slice) => {
205                     rest = &rest[slice.slice().len()..];
206                     next_header = slice.next_header();
207                     result.hop_by_hop_options = Some(slice.to_header());
208                 }
209                 Err(error) => {
210                     return (
211                         result,
212                         next_header,
213                         rest,
214                         Some((Len(error), Layer::Ipv6HopByHopHeader)),
215                     );
216                 }
217             }
218         }
219 
220         loop {
221             match next_header {
222                 IPV6_HOP_BY_HOP => {
223                     return (
224                         result,
225                         next_header,
226                         rest,
227                         Some((Content(HopByHopNotAtStart), Layer::Ipv6HopByHopHeader)),
228                     );
229                 }
230                 IPV6_DEST_OPTIONS => {
231                     if let Some(ref mut routing) = result.routing {
232                         // if the routing header is already present
233                         // this this a "final destination options" header
234                         if routing.final_destination_options.is_some() {
235                             // more then one header of this type found -> abort parsing
236                             return (result, next_header, rest, None);
237                         } else {
238                             match Ipv6RawExtHeaderSlice::from_slice(rest) {
239                                 Ok(slice) => {
240                                     rest = &rest[slice.slice().len()..];
241                                     next_header = slice.next_header();
242                                     routing.final_destination_options = Some(slice.to_header());
243                                 }
244                                 Err(err) => {
245                                     return (
246                                         result,
247                                         next_header,
248                                         rest,
249                                         Some((
250                                             Len(err.add_offset(slice.len() - rest.len())),
251                                             Layer::Ipv6DestOptionsHeader,
252                                         )),
253                                     );
254                                 }
255                             }
256                         }
257                     } else if result.destination_options.is_some() {
258                         // more then one header of this type found -> abort parsing
259                         return (result, next_header, rest, None);
260                     } else {
261                         match Ipv6RawExtHeaderSlice::from_slice(rest) {
262                             Ok(slice) => {
263                                 rest = &rest[slice.slice().len()..];
264                                 next_header = slice.next_header();
265                                 result.destination_options = Some(slice.to_header());
266                             }
267                             Err(err) => {
268                                 return (
269                                     result,
270                                     next_header,
271                                     rest,
272                                     Some((
273                                         Len(err.add_offset(slice.len() - rest.len())),
274                                         Layer::Ipv6DestOptionsHeader,
275                                     )),
276                                 );
277                             }
278                         }
279                     }
280                 }
281                 IPV6_ROUTE => {
282                     if result.routing.is_some() {
283                         // more then one header of this type found -> abort parsing
284                         return (result, next_header, rest, None);
285                     } else {
286                         match Ipv6RawExtHeaderSlice::from_slice(rest) {
287                             Ok(slice) => {
288                                 rest = &rest[slice.slice().len()..];
289                                 next_header = slice.next_header();
290                                 result.routing = Some(Ipv6RoutingExtensions {
291                                     routing: slice.to_header(),
292                                     final_destination_options: None,
293                                 });
294                             }
295                             Err(err) => {
296                                 return (
297                                     result,
298                                     next_header,
299                                     rest,
300                                     Some((
301                                         Len(err.add_offset(slice.len() - rest.len())),
302                                         Layer::Ipv6RouteHeader,
303                                     )),
304                                 );
305                             }
306                         }
307                     }
308                 }
309                 IPV6_FRAG => {
310                     if result.fragment.is_some() {
311                         // more then one header of this type found -> abort parsing
312                         return (result, next_header, rest, None);
313                     } else {
314                         match Ipv6FragmentHeaderSlice::from_slice(rest) {
315                             Ok(slice) => {
316                                 rest = &rest[slice.slice().len()..];
317                                 next_header = slice.next_header();
318                                 result.fragment = Some(slice.to_header());
319                             }
320                             Err(err) => {
321                                 return (
322                                     result,
323                                     next_header,
324                                     rest,
325                                     Some((
326                                         Len(err.add_offset(slice.len() - rest.len())),
327                                         Layer::Ipv6FragHeader,
328                                     )),
329                                 );
330                             }
331                         }
332                     }
333                 }
334                 AUTH => {
335                     if result.auth.is_some() {
336                         // more then one header of this type found -> abort parsing
337                         return (result, next_header, rest, None);
338                     } else {
339                         match IpAuthHeaderSlice::from_slice(rest) {
340                             Ok(slice) => {
341                                 rest = &rest[slice.slice().len()..];
342                                 next_header = slice.next_header();
343                                 result.auth = Some(slice.to_header());
344                             }
345                             Err(err) => {
346                                 use err::ip_auth::HeaderSliceError as I;
347                                 use err::ipv6_exts::HeaderError as O;
348                                 return (
349                                     result,
350                                     next_header,
351                                     rest,
352                                     Some((
353                                         match err {
354                                             I::Len(err) => {
355                                                 Len(err.add_offset(slice.len() - rest.len()))
356                                             }
357                                             I::Content(err) => Content(O::IpAuth(err)),
358                                         },
359                                         Layer::IpAuthHeader,
360                                     )),
361                                 );
362                             }
363                         }
364                     }
365                 }
366                 _ => {
367                     // done parsing, the next header is not a known header extension
368                     return (result, next_header, rest, None);
369                 }
370             }
371         }
372         //should not be hit
373     }
374 
375     /// Reads as many extension headers as possible from the reader and returns the found ipv6
376     /// extension headers and the next header ip number.
377     ///
378     /// If no extension headers are present an unfilled struct and the original `first_header`
379     /// ip number is returned.
380     ///
381     /// Note that this function can only handle ipv6 extensions if each extension header does
382     /// occur at most once, except for destination options headers which are allowed to
383     /// exist once in front of a routing header and once after a routing header.
384     ///
385     /// In case that more extension headers then can fit into a `Ipv6Extensions` struct are
386     /// encountered, the parsing is stoped at the point where the data would no longer fit into
387     /// the struct. In such a scenario a struct with the data that could be parsed is returned
388     /// together with the next header ip number that identfies which header could be read next.
389     ///
390     /// It is in the responsibility of the caller to handle a scenario like this.
391     ///
392     /// The reason that no error is generated, is that even though according to RFC 8200, packets
393     /// "should" not contain more then one occurence of an extension header, the RFC also specifies
394     /// that "IPv6 nodes must accept and attempt to process extension headers in any order and
395     /// occurring any number of times in the same packet". So packets with multiple headers "should"
396     /// not exist, but are still valid IPv6 packets. As such this function does not generate a
397     /// parsing error, as it is not an invalid packet, but if packets like these are encountered
398     /// the user of this function has to themself decide how to handle packets like these.
399     ///
400     /// The only exception is if an hop by hop header is located somewhere else then directly at
401     /// the start. In this case an `ReadError::Ipv6HopByHopHeaderNotAtStart` error is generated as
402     /// the hop by hop header is required to be located directly after the IPv6 header according
403     /// to RFC 8200.
404     #[cfg(feature = "std")]
405     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
read<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, start_ip_number: IpNumber, ) -> Result<(Ipv6Extensions, IpNumber), err::ipv6_exts::HeaderReadError>406     pub fn read<T: std::io::Read + std::io::Seek + Sized>(
407         reader: &mut T,
408         start_ip_number: IpNumber,
409     ) -> Result<(Ipv6Extensions, IpNumber), err::ipv6_exts::HeaderReadError> {
410         let mut result: Ipv6Extensions = Default::default();
411         let mut next_protocol = start_ip_number;
412 
413         use err::ipv6_exts::{HeaderError::*, HeaderReadError::*};
414         use ip_number::*;
415 
416         // the hop by hop header is required to occur directly after the ipv6 header
417         if IPV6_HOP_BY_HOP == next_protocol {
418             let header = Ipv6RawExtHeader::read(reader).map_err(Io)?;
419             next_protocol = header.next_header;
420             result.hop_by_hop_options = Some(header);
421         }
422 
423         loop {
424             match next_protocol {
425                 IPV6_HOP_BY_HOP => {
426                     return Err(Content(HopByHopNotAtStart));
427                 }
428                 IPV6_DEST_OPTIONS => {
429                     if let Some(ref mut routing) = result.routing {
430                         // if the routing header is already present
431                         // asume this is a "final destination options" header
432                         if routing.final_destination_options.is_some() {
433                             // more then one header of this type found -> abort parsing
434                             return Ok((result, next_protocol));
435                         } else {
436                             let header = Ipv6RawExtHeader::read(reader).map_err(Io)?;
437                             next_protocol = header.next_header;
438                             routing.final_destination_options = Some(header);
439                         }
440                     } else if result.destination_options.is_some() {
441                         // more then one header of this type found -> abort parsing
442                         return Ok((result, next_protocol));
443                     } else {
444                         let header = Ipv6RawExtHeader::read(reader).map_err(Io)?;
445                         next_protocol = header.next_header;
446                         result.destination_options = Some(header);
447                     }
448                 }
449                 IPV6_ROUTE => {
450                     if result.routing.is_some() {
451                         // more then one header of this type found -> abort parsing
452                         return Ok((result, next_protocol));
453                     } else {
454                         let header = Ipv6RawExtHeader::read(reader).map_err(Io)?;
455                         next_protocol = header.next_header;
456                         result.routing = Some(Ipv6RoutingExtensions {
457                             routing: header,
458                             final_destination_options: None,
459                         });
460                     }
461                 }
462                 IPV6_FRAG => {
463                     if result.fragment.is_some() {
464                         // more then one header of this type found -> abort parsing
465                         return Ok((result, next_protocol));
466                     } else {
467                         let header = Ipv6FragmentHeader::read(reader).map_err(Io)?;
468                         next_protocol = header.next_header;
469                         result.fragment = Some(header);
470                     }
471                 }
472                 AUTH => {
473                     if result.auth.is_some() {
474                         // more then one header of this type found -> abort parsing
475                         return Ok((result, next_protocol));
476                     } else {
477                         let header = IpAuthHeader::read(reader).map_err(|err| {
478                             use err::ip_auth::HeaderReadError as I;
479                             match err {
480                                 I::Io(err) => Io(err),
481                                 I::Content(err) => Content(IpAuth(err)),
482                             }
483                         })?;
484                         next_protocol = header.next_header;
485                         result.auth = Some(header);
486                     }
487                 }
488                 _ => {
489                     // done parsing, the next header is not a known header extension
490                     return Ok((result, next_protocol));
491                 }
492             }
493         }
494 
495         //should not be hit
496     }
497 
498     /// Reads as many extension headers as possible from the limited reader and returns the found ipv6
499     /// extension headers and the next header ip number.
500     ///
501     /// If no extension headers are present an unfilled struct and the original `first_header`
502     /// ip number is returned.
503     ///
504     /// Note that this function can only handle ipv6 extensions if each extension header does
505     /// occur at most once, except for destination options headers which are allowed to
506     /// exist once in front of a routing header and once after a routing header.
507     ///
508     /// In case that more extension headers then can fit into a `Ipv6Extensions` struct are
509     /// encountered, the parsing is stoped at the point where the data would no longer fit into
510     /// the struct. In such a scenario a struct with the data that could be parsed is returned
511     /// together with the next header ip number that identfies which header could be read next.
512     ///
513     /// It is in the responsibility of the caller to handle a scenario like this.
514     ///
515     /// The reason that no error is generated, is that even though according to RFC 8200, packets
516     /// "should" not contain more then one occurence of an extension header, the RFC also specifies
517     /// that "IPv6 nodes must accept and attempt to process extension headers in any order and
518     /// occurring any number of times in the same packet". So packets with multiple headers "should"
519     /// not exist, but are still valid IPv6 packets. As such this function does not generate a
520     /// parsing error, as it is not an invalid packet, but if packets like these are encountered
521     /// the user of this function has to themself decide how to handle packets like these.
522     ///
523     /// The only exception is if an hop by hop header is located somewhere else then directly at
524     /// the start. In this case an `ReadError::Ipv6HopByHopHeaderNotAtStart` error is generated as
525     /// the hop by hop header is required to be located directly after the IPv6 header according
526     /// to RFC 8200.
527     #[cfg(feature = "std")]
528     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
read_limited<T: std::io::Read + std::io::Seek + Sized>( reader: &mut crate::io::LimitedReader<T>, start_ip_number: IpNumber, ) -> Result<(Ipv6Extensions, IpNumber), HeaderLimitedReadError>529     pub fn read_limited<T: std::io::Read + std::io::Seek + Sized>(
530         reader: &mut crate::io::LimitedReader<T>,
531         start_ip_number: IpNumber,
532     ) -> Result<(Ipv6Extensions, IpNumber), HeaderLimitedReadError> {
533         use ip_number::*;
534         use HeaderError::*;
535         use HeaderLimitedReadError::*;
536 
537         fn map_limited_err(err: err::io::LimitedReadError) -> HeaderLimitedReadError {
538             use crate::err::io::LimitedReadError as I;
539             match err {
540                 I::Io(err) => Io(err),
541                 I::Len(err) => Len(err),
542             }
543         }
544 
545         // start decoding
546         let mut result: Ipv6Extensions = Default::default();
547         let mut next_protocol = start_ip_number;
548 
549         // the hop by hop header is required to occur directly after the ipv6 header
550         if IPV6_HOP_BY_HOP == next_protocol {
551             let header = Ipv6RawExtHeader::read_limited(reader).map_err(map_limited_err)?;
552             next_protocol = header.next_header;
553             result.hop_by_hop_options = Some(header);
554         }
555 
556         loop {
557             match next_protocol {
558                 IPV6_HOP_BY_HOP => {
559                     return Err(Content(HopByHopNotAtStart));
560                 }
561                 IPV6_DEST_OPTIONS => {
562                     if let Some(ref mut routing) = result.routing {
563                         // if the routing header is already present
564                         // asume this is a "final destination options" header
565                         if routing.final_destination_options.is_some() {
566                             // more then one header of this type found -> abort parsing
567                             return Ok((result, next_protocol));
568                         } else {
569                             let header =
570                                 Ipv6RawExtHeader::read_limited(reader).map_err(map_limited_err)?;
571                             next_protocol = header.next_header;
572                             routing.final_destination_options = Some(header);
573                         }
574                     } else if result.destination_options.is_some() {
575                         // more then one header of this type found -> abort parsing
576                         return Ok((result, next_protocol));
577                     } else {
578                         let header =
579                             Ipv6RawExtHeader::read_limited(reader).map_err(map_limited_err)?;
580                         next_protocol = header.next_header;
581                         result.destination_options = Some(header);
582                     }
583                 }
584                 IPV6_ROUTE => {
585                     if result.routing.is_some() {
586                         // more then one header of this type found -> abort parsing
587                         return Ok((result, next_protocol));
588                     } else {
589                         let header =
590                             Ipv6RawExtHeader::read_limited(reader).map_err(map_limited_err)?;
591                         next_protocol = header.next_header;
592                         result.routing = Some(Ipv6RoutingExtensions {
593                             routing: header,
594                             final_destination_options: None,
595                         });
596                     }
597                 }
598                 IPV6_FRAG => {
599                     if result.fragment.is_some() {
600                         // more then one header of this type found -> abort parsing
601                         return Ok((result, next_protocol));
602                     } else {
603                         let header =
604                             Ipv6FragmentHeader::read_limited(reader).map_err(map_limited_err)?;
605                         next_protocol = header.next_header;
606                         result.fragment = Some(header);
607                     }
608                 }
609                 AUTH => {
610                     if result.auth.is_some() {
611                         // more then one header of this type found -> abort parsing
612                         return Ok((result, next_protocol));
613                     } else {
614                         let header = IpAuthHeader::read_limited(reader).map_err(|err| {
615                             use err::ip_auth::HeaderLimitedReadError as I;
616                             match err {
617                                 I::Io(err) => Io(err),
618                                 I::Len(err) => Len(err),
619                                 I::Content(err) => Content(IpAuth(err)),
620                             }
621                         })?;
622                         next_protocol = header.next_header;
623                         result.auth = Some(header);
624                     }
625                 }
626                 _ => {
627                     // done parsing, the next header is not a known header extension
628                     return Ok((result, next_protocol));
629                 }
630             }
631         }
632 
633         //should not be hit
634     }
635 
636     /// Writes the given headers to a writer based on the order defined in
637     /// the next_header fields of the headers and the first header_id
638     /// passed to this function.
639     ///
640     /// It is required that all next header are correctly set in the headers
641     /// and no other ipv6 header extensions follow this header. If this is not
642     /// the case an [`err::ipv6_exts::HeaderWriteError::Content`] error is
643     /// returned.
644     #[cfg(feature = "std")]
645     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
write<T: std::io::Write + Sized>( &self, writer: &mut T, first_header: IpNumber, ) -> Result<(), err::ipv6_exts::HeaderWriteError>646     pub fn write<T: std::io::Write + Sized>(
647         &self,
648         writer: &mut T,
649         first_header: IpNumber,
650     ) -> Result<(), err::ipv6_exts::HeaderWriteError> {
651         use err::ipv6_exts::ExtsWalkError::*;
652         use err::ipv6_exts::HeaderWriteError::*;
653         use ip_number::*;
654 
655         /// Struct flagging if a header needs to be written.
656         struct NeedsWrite {
657             pub hop_by_hop_options: bool,
658             pub destination_options: bool,
659             pub routing: bool,
660             pub fragment: bool,
661             pub auth: bool,
662             pub final_destination_options: bool,
663         }
664 
665         let mut needs_write = NeedsWrite {
666             hop_by_hop_options: self.hop_by_hop_options.is_some(),
667             destination_options: self.destination_options.is_some(),
668             routing: self.routing.is_some(),
669             fragment: self.fragment.is_some(),
670             auth: self.auth.is_some(),
671             final_destination_options: if let Some(ref routing) = self.routing {
672                 routing.final_destination_options.is_some()
673             } else {
674                 false
675             },
676         };
677 
678         let mut next_header = first_header;
679         let mut route_written = false;
680 
681         // check if hop by hop header should be written first
682         if IPV6_HOP_BY_HOP == next_header {
683             let header = &self.hop_by_hop_options.as_ref().unwrap();
684             header.write(writer).map_err(Io)?;
685             next_header = header.next_header;
686             needs_write.hop_by_hop_options = false;
687         }
688 
689         loop {
690             match next_header {
691                 IPV6_HOP_BY_HOP => {
692                     // Only trigger a "hop by hop not at start" error
693                     // if we actually still have to write a hop by hop header.
694                     //
695                     // The ip number for hop by hop is 0, which could be used
696                     // as a placeholder by user and later replaced. So let's
697                     // not be overzealous and allow a next header with hop
698                     // by hop if it is not part of this extensions struct.
699                     if needs_write.hop_by_hop_options {
700                         // the hop by hop header is only allowed at the start
701                         return Err(Content(HopByHopNotAtStart));
702                     } else {
703                         break;
704                     }
705                 }
706                 IPV6_DEST_OPTIONS => {
707                     // the destination options are allowed to be written twice
708                     // once before a routing header and once after.
709                     if route_written {
710                         if needs_write.final_destination_options {
711                             let header = &self
712                                 .routing
713                                 .as_ref()
714                                 .unwrap()
715                                 .final_destination_options
716                                 .as_ref()
717                                 .unwrap();
718                             header.write(writer).map_err(Io)?;
719                             next_header = header.next_header;
720                             needs_write.final_destination_options = false;
721                         } else {
722                             break;
723                         }
724                     } else if needs_write.destination_options {
725                         let header = &self.destination_options.as_ref().unwrap();
726                         header.write(writer).map_err(Io)?;
727                         next_header = header.next_header;
728                         needs_write.destination_options = false;
729                     } else {
730                         break;
731                     }
732                 }
733                 IPV6_ROUTE => {
734                     if needs_write.routing {
735                         let header = &self.routing.as_ref().unwrap().routing;
736                         header.write(writer).map_err(Io)?;
737                         next_header = header.next_header;
738                         needs_write.routing = false;
739                         // for destination options
740                         route_written = true;
741                     } else {
742                         break;
743                     }
744                 }
745                 IPV6_FRAG => {
746                     if needs_write.fragment {
747                         let header = &self.fragment.as_ref().unwrap();
748                         header.write(writer).map_err(Io)?;
749                         next_header = header.next_header;
750                         needs_write.fragment = false;
751                     } else {
752                         break;
753                     }
754                 }
755                 AUTH => {
756                     if needs_write.auth {
757                         let header = &self.auth.as_ref().unwrap();
758                         header.write(writer).map_err(Io)?;
759                         next_header = header.next_header;
760                         needs_write.auth = false;
761                     } else {
762                         break;
763                     }
764                 }
765                 _ => {
766                     // reached an unknown next_header id, proceed to check if everything was written
767                     break;
768                 }
769             }
770         }
771 
772         // check that all header have been written
773         if needs_write.hop_by_hop_options {
774             Err(Content(ExtNotReferenced {
775                 missing_ext: IpNumber::IPV6_HEADER_HOP_BY_HOP,
776             }))
777         } else if needs_write.destination_options {
778             Err(Content(ExtNotReferenced {
779                 missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS,
780             }))
781         } else if needs_write.routing {
782             Err(Content(ExtNotReferenced {
783                 missing_ext: IpNumber::IPV6_ROUTE_HEADER,
784             }))
785         } else if needs_write.fragment {
786             Err(Content(ExtNotReferenced {
787                 missing_ext: IpNumber::IPV6_FRAGMENTATION_HEADER,
788             }))
789         } else if needs_write.auth {
790             Err(Content(ExtNotReferenced {
791                 missing_ext: IpNumber::AUTHENTICATION_HEADER,
792             }))
793         } else if needs_write.final_destination_options {
794             Err(Content(ExtNotReferenced {
795                 missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS,
796             }))
797         } else {
798             Ok(())
799         }
800     }
801 
802     /// Length of the all present headers in bytes.
header_len(&self) -> usize803     pub fn header_len(&self) -> usize {
804         let mut result = 0;
805 
806         if let Some(ref header) = self.hop_by_hop_options {
807             result += header.header_len();
808         }
809         if let Some(ref header) = self.destination_options {
810             result += header.header_len();
811         }
812         if let Some(ref header) = self.routing {
813             result += header.routing.header_len();
814             if let Some(ref header) = header.final_destination_options {
815                 result += header.header_len();
816             }
817         }
818         if let Some(ref header) = self.fragment {
819             result += header.header_len();
820         }
821         if let Some(ref header) = self.auth {
822             result += header.header_len();
823         }
824 
825         result
826     }
827 
828     /// Sets all the next_header fields of the headers based on the adviced default order
829     /// with the given protocol number as last "next header" value. The return value is the protocol
830     /// number of the first existing extension header that should be entered in the ipv6 header as
831     /// next_header.
832     ///
833     /// If no extension headers are present the value of the argument is returned.
set_next_headers(&mut self, last_protocol_number: IpNumber) -> IpNumber834     pub fn set_next_headers(&mut self, last_protocol_number: IpNumber) -> IpNumber {
835         use ip_number::*;
836 
837         let mut next = last_protocol_number;
838 
839         // go through the proposed order of extension headers from
840         // RFC 8200 backwards. The header order defined in RFC8200 is:
841         //
842         // * IPv6 header
843         // * Hop-by-Hop Options header
844         // * Destination Options header
845         // * Routing header
846         // * Fragment header
847         // * Authentication header
848         // * Encapsulating Security Payload header
849         // * Destination Options header
850         // * Upper-Layer header
851         //
852         if let Some(ref mut routing) = self.routing {
853             if let Some(ref mut header) = routing.final_destination_options {
854                 header.next_header = next;
855                 next = IPV6_DEST_OPTIONS;
856             }
857         }
858         if let Some(ref mut header) = self.auth {
859             header.next_header = next;
860             next = AUTH;
861         }
862         if let Some(ref mut header) = self.fragment {
863             header.next_header = next;
864             next = IPV6_FRAG;
865         }
866         if let Some(ref mut routing) = self.routing {
867             routing.routing.next_header = next;
868             next = IPV6_ROUTE;
869         }
870         if let Some(ref mut header) = self.destination_options {
871             header.next_header = next;
872             next = IPV6_DEST_OPTIONS;
873         }
874         if let Some(ref mut header) = self.hop_by_hop_options {
875             header.next_header = next;
876             next = IPV6_HOP_BY_HOP;
877         }
878 
879         next
880     }
881 
882     /// Return next header based on the extension headers and
883     /// the first ip protocol number.
next_header(&self, first_next_header: IpNumber) -> Result<IpNumber, ExtsWalkError>884     pub fn next_header(&self, first_next_header: IpNumber) -> Result<IpNumber, ExtsWalkError> {
885         use ip_number::*;
886         use ExtsWalkError::*;
887 
888         /// Struct flagging if a header needs to be referenced.
889         struct OutstandingRef {
890             pub hop_by_hop_options: bool,
891             pub destination_options: bool,
892             pub routing: bool,
893             pub fragment: bool,
894             pub auth: bool,
895             pub final_destination_options: bool,
896         }
897 
898         let mut outstanding_refs = OutstandingRef {
899             hop_by_hop_options: self.hop_by_hop_options.is_some(),
900             destination_options: self.destination_options.is_some(),
901             routing: self.routing.is_some(),
902             fragment: self.fragment.is_some(),
903             auth: self.auth.is_some(),
904             final_destination_options: if let Some(ref routing) = self.routing {
905                 routing.final_destination_options.is_some()
906             } else {
907                 false
908             },
909         };
910 
911         let mut next = first_next_header;
912         let mut route_refed = false;
913 
914         // check if hop by hop header should be written first
915         if IPV6_HOP_BY_HOP == next {
916             if let Some(ref header) = self.hop_by_hop_options {
917                 next = header.next_header;
918                 outstanding_refs.hop_by_hop_options = false;
919             }
920         }
921 
922         loop {
923             match next {
924                 IPV6_HOP_BY_HOP => {
925                     // Only trigger a "hop by hop not at start" error
926                     // if we actually still have to write a hop by hop header.
927                     //
928                     // The ip number for hop by hop is 0, which could be used
929                     // as a placeholder by user and later replaced. So let's
930                     // not be overzealous and allow a next header with hop
931                     // by hop if it is not part of this extensions struct.
932                     if outstanding_refs.hop_by_hop_options {
933                         // the hop by hop header is only allowed at the start
934                         return Err(HopByHopNotAtStart);
935                     } else {
936                         break;
937                     }
938                 }
939                 IPV6_DEST_OPTIONS => {
940                     // the destination options are allowed to be written twice
941                     // once before a routing header and once after.
942                     if route_refed {
943                         if outstanding_refs.final_destination_options {
944                             let header = &self
945                                 .routing
946                                 .as_ref()
947                                 .unwrap()
948                                 .final_destination_options
949                                 .as_ref()
950                                 .unwrap();
951                             next = header.next_header;
952                             outstanding_refs.final_destination_options = false;
953                         } else {
954                             break;
955                         }
956                     } else if outstanding_refs.destination_options {
957                         let header = &self.destination_options.as_ref().unwrap();
958                         next = header.next_header;
959                         outstanding_refs.destination_options = false;
960                     } else {
961                         break;
962                     }
963                 }
964                 IPV6_ROUTE => {
965                     if outstanding_refs.routing {
966                         let header = &self.routing.as_ref().unwrap().routing;
967                         next = header.next_header;
968                         outstanding_refs.routing = false;
969                         // for destination options
970                         route_refed = true;
971                     } else {
972                         break;
973                     }
974                 }
975                 IPV6_FRAG => {
976                     if outstanding_refs.fragment {
977                         let header = &self.fragment.as_ref().unwrap();
978                         next = header.next_header;
979                         outstanding_refs.fragment = false;
980                     } else {
981                         break;
982                     }
983                 }
984                 AUTH => {
985                     if outstanding_refs.auth {
986                         let header = &self.auth.as_ref().unwrap();
987                         next = header.next_header;
988                         outstanding_refs.auth = false;
989                     } else {
990                         break;
991                     }
992                 }
993                 _ => break,
994             }
995         }
996 
997         // assume all done
998         if outstanding_refs.hop_by_hop_options {
999             return Err(ExtNotReferenced {
1000                 missing_ext: IpNumber::IPV6_HEADER_HOP_BY_HOP,
1001             });
1002         }
1003         if outstanding_refs.destination_options {
1004             return Err(ExtNotReferenced {
1005                 missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS,
1006             });
1007         }
1008         if outstanding_refs.routing {
1009             return Err(ExtNotReferenced {
1010                 missing_ext: IpNumber::IPV6_ROUTE_HEADER,
1011             });
1012         }
1013         if outstanding_refs.fragment {
1014             return Err(ExtNotReferenced {
1015                 missing_ext: IpNumber::IPV6_FRAGMENTATION_HEADER,
1016             });
1017         }
1018         if outstanding_refs.auth {
1019             return Err(ExtNotReferenced {
1020                 missing_ext: IpNumber::AUTHENTICATION_HEADER,
1021             });
1022         }
1023         if outstanding_refs.final_destination_options {
1024             return Err(ExtNotReferenced {
1025                 missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS,
1026             });
1027         }
1028 
1029         Ok(next)
1030     }
1031 
1032     /// Returns true if a fragmentation header is present in
1033     /// the extensions that fragments the payload.
1034     ///
1035     /// Note: A fragmentation header can still be present
1036     /// even if the return value is false in case the fragmentation
1037     /// headers don't fragment the payload. This is the case if
1038     /// the offset of all fragmentation header is 0 and the
1039     /// more fragment bit is not set.
1040     #[inline]
is_fragmenting_payload(&self) -> bool1041     pub fn is_fragmenting_payload(&self) -> bool {
1042         if let Some(frag) = self.fragment.as_ref() {
1043             frag.is_fragmenting_payload()
1044         } else {
1045             false
1046         }
1047     }
1048 
1049     /// Returns true if no IPv6 extension header is present (all fields `None`).
1050     #[inline]
is_empty(&self) -> bool1051     pub fn is_empty(&self) -> bool {
1052         self.hop_by_hop_options.is_none()
1053             && self.destination_options.is_none()
1054             && self.routing.is_none()
1055             && self.fragment.is_none()
1056             && self.auth.is_none()
1057     }
1058 }
1059 
1060 #[cfg(test)]
1061 pub mod ipv6_exts_test_helpers {
1062     use super::*;
1063     use crate::ip_number::*;
1064     use alloc::vec::Vec;
1065 
1066     /// IP numbers that are assigned ipv6 header extensions.
1067     pub const EXTENSION_KNOWN_IP_NUMBERS: [IpNumber; 5] = [
1068         AUTH,
1069         IPV6_DEST_OPTIONS,
1070         IPV6_HOP_BY_HOP,
1071         IPV6_FRAG,
1072         IPV6_ROUTE,
1073     ];
1074 
1075     /// Helper struct that generates test data with dummy
1076     /// extension header data.
1077     pub struct ExtensionTestPayload {
1078         pub ip_numbers: Vec<IpNumber>,
1079         pub lengths: Vec<usize>,
1080         pub data: Vec<u8>,
1081     }
1082 
1083     impl ExtensionTestPayload {
new(ip_numbers: &[IpNumber], header_sizes: &[u8]) -> ExtensionTestPayload1084         pub fn new(ip_numbers: &[IpNumber], header_sizes: &[u8]) -> ExtensionTestPayload {
1085             assert!(ip_numbers.len() > 1);
1086             assert!(header_sizes.len() > 0);
1087 
1088             let mut result = ExtensionTestPayload {
1089                 ip_numbers: ip_numbers.to_vec(),
1090                 lengths: Vec::with_capacity(ip_numbers.len() - 1),
1091                 data: Vec::with_capacity((ip_numbers.len() - 1) * (0xff * 8 + 8)),
1092             };
1093             for i in 0..ip_numbers.len() - 1 {
1094                 result.add_payload(
1095                     ip_numbers[i],
1096                     ip_numbers[i + 1],
1097                     header_sizes[i % header_sizes.len()],
1098                 )
1099             }
1100             result
1101         }
1102 
slice(&self) -> &[u8]1103         pub fn slice(&self) -> &[u8] {
1104             &self.data
1105         }
1106 
add_payload(&mut self, ip_number: IpNumber, next_header: IpNumber, header_ext_len: u8)1107         fn add_payload(&mut self, ip_number: IpNumber, next_header: IpNumber, header_ext_len: u8) {
1108             match ip_number {
1109                 IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS => {
1110                     // insert next header & size
1111                     let mut raw: [u8; 0xff * 8 + 8] = [0; 0xff * 8 + 8];
1112                     raw[0] = next_header.0;
1113                     raw[1] = header_ext_len;
1114 
1115                     // insert payload
1116                     self.data
1117                         .extend_from_slice(&raw[..8 + usize::from(header_ext_len) * 8]);
1118                     self.lengths.push(8 + usize::from(header_ext_len) * 8);
1119                 }
1120                 IPV6_FRAG => {
1121                     // generate payload
1122                     let mut raw: [u8; 8] = [0; 8];
1123                     raw[0] = next_header.0;
1124                     raw[1] = 0;
1125 
1126                     // insert payload
1127                     self.data.extend_from_slice(&raw[..8]);
1128                     self.lengths.push(8);
1129                 }
1130                 AUTH => {
1131                     let mut raw: [u8; 0xff * 4 + 8] = [0; 0xff * 4 + 8];
1132                     raw[0] = next_header.0;
1133                     // authentfication header len is defined as
1134                     // '32-bit words (4-byteunits), minus "2"'
1135                     let len = if header_ext_len > 0 {
1136                         raw[1] = header_ext_len;
1137                         usize::from(header_ext_len) * 4
1138                     } else {
1139                         // auth has a minimum size of 1
1140                         raw[1] = 1;
1141                         4
1142                     } + 8;
1143                     self.data.extend_from_slice(&raw[..len]);
1144                     self.lengths.push(len);
1145                 }
1146                 _ => unreachable!(),
1147             }
1148         }
1149 
1150         /// Returns true of the payload will trigger a "hop by hop not
1151         /// at start" error which is not ignored because of an early
1152         /// parsing abort.
exts_hop_by_hop_error(&self) -> bool1153         pub fn exts_hop_by_hop_error(&self) -> bool {
1154             struct ReadState {
1155                 dest_opt: bool,
1156                 routing: bool,
1157                 final_dest_opt: bool,
1158                 frag: bool,
1159                 auth: bool,
1160             }
1161 
1162             // state if a header type has already been read
1163             let mut read = ReadState {
1164                 dest_opt: false,
1165                 routing: false,
1166                 final_dest_opt: false,
1167                 frag: false,
1168                 auth: false,
1169             };
1170 
1171             for i in 0..self.ip_numbers.len() {
1172                 match self.ip_numbers[i] {
1173                     IPV6_HOP_BY_HOP => {
1174                         if i != 0 {
1175                             return true;
1176                         }
1177                     }
1178                     IPV6_ROUTE => {
1179                         if read.routing {
1180                             return false;
1181                         } else {
1182                             read.routing = true;
1183                         }
1184                     }
1185                     IPV6_DEST_OPTIONS => {
1186                         // check the kind of destination options (aka is it before or after the routing header)
1187                         if read.routing {
1188                             // final dest opt
1189                             if read.final_dest_opt {
1190                                 return false;
1191                             } else {
1192                                 read.final_dest_opt = true;
1193                             }
1194                         } else {
1195                             // dst opt
1196                             if read.dest_opt {
1197                                 return false;
1198                             } else {
1199                                 read.dest_opt = true;
1200                             }
1201                         }
1202                     }
1203                     IPV6_FRAG => {
1204                         if read.frag {
1205                             return false;
1206                         } else {
1207                             read.frag = true;
1208                         }
1209                     }
1210                     AUTH => {
1211                         if read.auth {
1212                             return false;
1213                         } else {
1214                             read.auth = true;
1215                         }
1216                     }
1217                     _ => return false,
1218                 }
1219             }
1220             return false;
1221         }
1222 
1223         /// Checks the if the extensions match the expected values based
1224         /// on this test payload.
assert_extensions( &self, exts: &Ipv6Extensions, ) -> (usize, Option<IpNumber>, IpNumber)1225         pub fn assert_extensions(
1226             &self,
1227             exts: &Ipv6Extensions,
1228         ) -> (usize, Option<IpNumber>, IpNumber) {
1229             struct ReadState {
1230                 hop_by_hop: bool,
1231                 dest_opt: bool,
1232                 routing: bool,
1233                 final_dest_opt: bool,
1234                 frag: bool,
1235                 auth: bool,
1236             }
1237 
1238             // state if a header type has already been read
1239             let mut read = ReadState {
1240                 hop_by_hop: false,
1241                 dest_opt: false,
1242                 routing: false,
1243                 final_dest_opt: false,
1244                 frag: false,
1245                 auth: false,
1246             };
1247 
1248             let mut slice = &self.data[..];
1249             let mut last_decoded = None;
1250             let mut post_header = self.ip_numbers[0];
1251 
1252             for i in 0..self.ip_numbers.len() - 1 {
1253                 let mut stop = false;
1254                 match self.ip_numbers[i] {
1255                     IPV6_HOP_BY_HOP => {
1256                         assert!(false == read.hop_by_hop);
1257                         let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1258                         assert_eq!(&header, exts.hop_by_hop_options.as_ref().unwrap());
1259                         slice = rest;
1260                         read.hop_by_hop = true;
1261                         last_decoded = Some(IPV6_HOP_BY_HOP);
1262                     }
1263                     IPV6_ROUTE => {
1264                         if read.routing {
1265                             stop = true;
1266                         } else {
1267                             let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1268                             assert_eq!(&header, &exts.routing.as_ref().unwrap().routing);
1269                             slice = rest;
1270                             read.routing = true;
1271                             last_decoded = Some(IPV6_ROUTE);
1272                         }
1273                     }
1274                     IPV6_DEST_OPTIONS => {
1275                         // check the kind of destination options (aka is it before or after the routing header)
1276                         if read.routing {
1277                             // final dest opt
1278                             if read.final_dest_opt {
1279                                 stop = true;
1280                             } else {
1281                                 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1282                                 assert_eq!(
1283                                     &header,
1284                                     exts.routing
1285                                         .as_ref()
1286                                         .unwrap()
1287                                         .final_destination_options
1288                                         .as_ref()
1289                                         .unwrap()
1290                                 );
1291                                 slice = rest;
1292                                 read.final_dest_opt = true;
1293                                 last_decoded = Some(IPV6_DEST_OPTIONS);
1294                             }
1295                         } else {
1296                             // dst opt
1297                             if read.dest_opt {
1298                                 stop = true;
1299                             } else {
1300                                 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1301                                 assert_eq!(&header, exts.destination_options.as_ref().unwrap());
1302                                 slice = rest;
1303                                 read.dest_opt = true;
1304                                 last_decoded = Some(IPV6_DEST_OPTIONS);
1305                             }
1306                         }
1307                     }
1308                     IPV6_FRAG => {
1309                         if read.frag {
1310                             // duplicate header -> stop
1311                             stop = true;
1312                         } else {
1313                             let (header, rest) = Ipv6FragmentHeader::from_slice(slice).unwrap();
1314                             assert_eq!(&header, exts.fragment.as_ref().unwrap());
1315                             slice = rest;
1316                             read.frag = true;
1317                             last_decoded = Some(IPV6_FRAG);
1318                         }
1319                     }
1320                     AUTH => {
1321                         if read.auth {
1322                             // duplicate header -> stop
1323                             stop = true;
1324                         } else {
1325                             let (header, rest) = IpAuthHeader::from_slice(slice).unwrap();
1326                             assert_eq!(&header, exts.auth.as_ref().unwrap());
1327                             slice = rest;
1328                             read.auth = true;
1329                             last_decoded = Some(AUTH);
1330                         }
1331                     }
1332                     _ => {
1333                         // non extension header -> stop
1334                         stop = true;
1335                     }
1336                 }
1337                 if stop {
1338                     post_header = self.ip_numbers[i];
1339                     break;
1340                 } else {
1341                     post_header = self.ip_numbers[i + 1];
1342                 }
1343             }
1344 
1345             // check the non parsed headers are not present
1346             if false == read.hop_by_hop {
1347                 assert!(exts.hop_by_hop_options.is_none());
1348             }
1349             if false == read.dest_opt {
1350                 assert!(exts.destination_options.is_none());
1351             }
1352             if false == read.routing {
1353                 assert!(exts.routing.is_none());
1354             } else {
1355                 if false == read.final_dest_opt {
1356                     assert!(exts
1357                         .routing
1358                         .as_ref()
1359                         .unwrap()
1360                         .final_destination_options
1361                         .is_none());
1362                 }
1363             }
1364             if false == read.frag {
1365                 assert!(exts.fragment.is_none());
1366             }
1367             if false == read.auth {
1368                 assert!(exts.auth.is_none());
1369             }
1370 
1371             (self.data.len() - slice.len(), last_decoded, post_header)
1372         }
1373 
1374         /// Return the expected lax from slice result and ipnumber which caused
1375         /// an error.
lax_extensions_for_len( &self, limiting_len: usize, ) -> (Ipv6Extensions, IpNumber, &[u8], Option<IpNumber>)1376         pub fn lax_extensions_for_len(
1377             &self,
1378             limiting_len: usize,
1379         ) -> (Ipv6Extensions, IpNumber, &[u8], Option<IpNumber>) {
1380             // state if a header type has already been read
1381             let mut exts: Ipv6Extensions = Default::default();
1382             let mut post_header = *self.ip_numbers.first().unwrap();
1383             let mut slice = &self.data[..];
1384 
1385             for i in 0..self.ip_numbers.len() - 1 {
1386                 // check if the limiting size gets hit
1387                 if self.slice().len() - slice.len() + self.lengths[i] > limiting_len {
1388                     return (
1389                         exts,
1390                         self.ip_numbers[i],
1391                         &self.slice()[self.slice().len() - slice.len()..limiting_len],
1392                         Some(self.ip_numbers[i]),
1393                     );
1394                 }
1395 
1396                 let mut stop = false;
1397                 match self.ip_numbers[i] {
1398                     IPV6_HOP_BY_HOP => {
1399                         assert!(exts.hop_by_hop_options.is_none());
1400                         let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1401                         exts.hop_by_hop_options = Some(header);
1402                         slice = rest;
1403                     }
1404                     IPV6_ROUTE => {
1405                         if exts.routing.is_some() {
1406                             stop = true;
1407                         } else {
1408                             let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1409                             exts.routing = Some(Ipv6RoutingExtensions {
1410                                 routing: header,
1411                                 final_destination_options: None,
1412                             });
1413                             slice = rest;
1414                         }
1415                     }
1416                     IPV6_DEST_OPTIONS => {
1417                         // check the kind of destination options (aka is it before or after the routing header)
1418                         if let Some(routing) = exts.routing.as_mut() {
1419                             // final dest opt
1420                             if routing.final_destination_options.is_some() {
1421                                 stop = true;
1422                             } else {
1423                                 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1424                                 routing.final_destination_options = Some(header);
1425                                 slice = rest;
1426                             }
1427                         } else {
1428                             // dst opt
1429                             if exts.destination_options.is_some() {
1430                                 stop = true;
1431                             } else {
1432                                 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1433                                 exts.destination_options = Some(header);
1434                                 slice = rest;
1435                             }
1436                         }
1437                     }
1438                     IPV6_FRAG => {
1439                         if exts.fragment.is_some() {
1440                             // duplicate header -> stop
1441                             stop = true;
1442                         } else {
1443                             let (header, rest) = Ipv6FragmentHeader::from_slice(slice).unwrap();
1444                             exts.fragment = Some(header);
1445                             slice = rest;
1446                         }
1447                     }
1448                     AUTH => {
1449                         if exts.auth.is_some() {
1450                             // duplicate header -> stop
1451                             stop = true;
1452                         } else {
1453                             let (header, rest) = IpAuthHeader::from_slice(slice).unwrap();
1454                             exts.auth = Some(header);
1455                             slice = rest;
1456                         }
1457                     }
1458                     _ => {
1459                         // non extension header -> stop
1460                         stop = true;
1461                     }
1462                 }
1463                 if stop {
1464                     post_header = self.ip_numbers[i];
1465                     break;
1466                 } else {
1467                     post_header = self.ip_numbers[i + 1];
1468                 }
1469             }
1470 
1471             (
1472                 exts,
1473                 post_header,
1474                 &self.slice()[self.slice().len() - slice.len()..limiting_len],
1475                 None,
1476             )
1477         }
1478     }
1479 
1480     /// extension header data.
1481     #[derive(Clone)]
1482     pub struct ExtensionTestHeaders {
1483         pub ip_numbers: Vec<IpNumber>,
1484         pub data: Ipv6Extensions,
1485     }
1486 
1487     impl ExtensionTestHeaders {
new(ip_numbers: &[IpNumber], header_sizes: &[u8]) -> ExtensionTestHeaders1488         pub fn new(ip_numbers: &[IpNumber], header_sizes: &[u8]) -> ExtensionTestHeaders {
1489             assert!(ip_numbers.len() > 1);
1490             assert!(header_sizes.len() > 0);
1491 
1492             let mut result = ExtensionTestHeaders {
1493                 ip_numbers: ip_numbers.to_vec(),
1494                 data: Default::default(),
1495             };
1496             for i in 0..ip_numbers.len() - 1 {
1497                 let succ = result.add_payload(
1498                     ip_numbers[i],
1499                     ip_numbers[i + 1],
1500                     header_sizes[i % header_sizes.len()],
1501                 );
1502                 if false == succ {
1503                     // write was not possible (duplicate)
1504                     // reduce the list so the current ip number
1505                     // is the final one
1506                     result.ip_numbers.truncate(i + 1);
1507                     break;
1508                 }
1509             }
1510             result
1511         }
1512 
introduce_missing_ref(&mut self, new_header: IpNumber) -> IpNumber1513         pub fn introduce_missing_ref(&mut self, new_header: IpNumber) -> IpNumber {
1514             assert!(self.ip_numbers.len() >= 2);
1515 
1516             // set the next_header of the last extension header and return the id
1517             if self.ip_numbers.len() >= 3 {
1518                 match self.ip_numbers[self.ip_numbers.len() - 3] {
1519                     IPV6_HOP_BY_HOP => {
1520                         self.data.hop_by_hop_options.as_mut().unwrap().next_header = new_header;
1521                     }
1522                     IPV6_DEST_OPTIONS => {
1523                         if self.ip_numbers[..self.ip_numbers.len() - 3]
1524                             .iter()
1525                             .any(|&x| x == IPV6_ROUTE)
1526                         {
1527                             self.data
1528                                 .routing
1529                                 .as_mut()
1530                                 .unwrap()
1531                                 .final_destination_options
1532                                 .as_mut()
1533                                 .unwrap()
1534                                 .next_header = new_header;
1535                         } else {
1536                             self.data.destination_options.as_mut().unwrap().next_header =
1537                                 new_header;
1538                         }
1539                     }
1540                     IPV6_ROUTE => {
1541                         self.data.routing.as_mut().unwrap().routing.next_header = new_header;
1542                     }
1543                     IPV6_FRAG => {
1544                         self.data.fragment.as_mut().unwrap().next_header = new_header;
1545                     }
1546                     AUTH => {
1547                         self.data.auth.as_mut().unwrap().next_header = new_header;
1548                     }
1549                     _ => unreachable!(),
1550                 }
1551                 match self.ip_numbers[self.ip_numbers.len() - 2] {
1552                     IPV6_HOP_BY_HOP => IpNumber::IPV6_HEADER_HOP_BY_HOP,
1553                     IPV6_DEST_OPTIONS => IpNumber::IPV6_DESTINATION_OPTIONS,
1554                     IPV6_ROUTE => IpNumber::IPV6_ROUTE_HEADER,
1555                     IPV6_FRAG => IpNumber::IPV6_FRAGMENTATION_HEADER,
1556                     AUTH => IpNumber::AUTHENTICATION_HEADER,
1557                     _ => unreachable!(),
1558                 }
1559             } else {
1560                 // rewrite start number in case it is just one extension header
1561                 let missing = self.ip_numbers[0];
1562                 self.ip_numbers[0] = new_header;
1563                 match missing {
1564                     IPV6_HOP_BY_HOP => IpNumber::IPV6_HEADER_HOP_BY_HOP,
1565                     IPV6_DEST_OPTIONS => IpNumber::IPV6_DESTINATION_OPTIONS,
1566                     IPV6_ROUTE => IpNumber::IPV6_ROUTE_HEADER,
1567                     IPV6_FRAG => IpNumber::IPV6_FRAGMENTATION_HEADER,
1568                     AUTH => IpNumber::AUTHENTICATION_HEADER,
1569                     _ => unreachable!(),
1570                 }
1571             }
1572         }
1573 
add_payload( &mut self, ip_number: IpNumber, next_header: IpNumber, header_ext_len: u8, ) -> bool1574         fn add_payload(
1575             &mut self,
1576             ip_number: IpNumber,
1577             next_header: IpNumber,
1578             header_ext_len: u8,
1579         ) -> bool {
1580             match ip_number {
1581                 IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS => {
1582                     use Ipv6RawExtHeader as R;
1583                     let payload: [u8; R::MAX_PAYLOAD_LEN] = [0; R::MAX_PAYLOAD_LEN];
1584                     let len = usize::from(header_ext_len) * 8 + 6;
1585 
1586                     let raw = Ipv6RawExtHeader::new_raw(next_header, &payload[..len]).unwrap();
1587                     match ip_number {
1588                         IPV6_HOP_BY_HOP => {
1589                             if self.data.hop_by_hop_options.is_none() {
1590                                 self.data.hop_by_hop_options = Some(raw);
1591                                 true
1592                             } else {
1593                                 false
1594                             }
1595                         }
1596                         IPV6_ROUTE => {
1597                             if self.data.routing.is_none() {
1598                                 self.data.routing = Some(Ipv6RoutingExtensions {
1599                                     routing: raw,
1600                                     final_destination_options: None,
1601                                 });
1602                                 true
1603                             } else {
1604                                 false
1605                             }
1606                         }
1607                         IPV6_DEST_OPTIONS => {
1608                             if let Some(ref mut route) = self.data.routing {
1609                                 if route.final_destination_options.is_none() {
1610                                     route.final_destination_options = Some(raw);
1611                                     true
1612                                 } else {
1613                                     false
1614                                 }
1615                             } else {
1616                                 // dest option
1617                                 if self.data.destination_options.is_none() {
1618                                     self.data.destination_options = Some(raw);
1619                                     true
1620                                 } else {
1621                                     false
1622                                 }
1623                             }
1624                         }
1625                         _ => unreachable!(),
1626                     }
1627                 }
1628                 IPV6_FRAG => {
1629                     if self.data.fragment.is_none() {
1630                         self.data.fragment = Some(Ipv6FragmentHeader::new(
1631                             next_header,
1632                             IpFragOffset::ZERO,
1633                             true,
1634                             123,
1635                         ));
1636                         true
1637                     } else {
1638                         false
1639                     }
1640                 }
1641                 AUTH => {
1642                     if self.data.auth.is_none() {
1643                         use IpAuthHeader as A;
1644 
1645                         let mut len = usize::from(header_ext_len) * 4;
1646                         if len > A::MAX_ICV_LEN {
1647                             len = A::MAX_ICV_LEN;
1648                         }
1649                         let raw_icv: [u8; A::MAX_ICV_LEN] = [0; A::MAX_ICV_LEN];
1650                         self.data.auth = Some(
1651                             IpAuthHeader::new(next_header, 123, 234, &raw_icv[..len]).unwrap(),
1652                         );
1653                         true
1654                     } else {
1655                         false
1656                     }
1657                 }
1658                 _ => unreachable!(),
1659             }
1660         }
1661     }
1662 }
1663 
1664 #[cfg(test)]
1665 mod test {
1666     use super::ipv6_exts_test_helpers::*;
1667     use super::*;
1668     use crate::ip_number::*;
1669     use crate::test_gens::*;
1670     use alloc::{borrow::ToOwned, vec::Vec};
1671     use proptest::prelude::*;
1672 
1673     proptest! {
1674         #[test]
1675         fn from_slice(
1676             header_size in any::<u8>(),
1677             post_header in ip_number_any()
1678                 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
1679                     |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
1680                 )
1681         ) {
1682             use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*};
1683 
1684             // no extension headers filled
1685             {
1686                 let some_data = [1,2,3,4];
1687                 let actual = Ipv6Extensions::from_slice(post_header, &some_data).unwrap();
1688                 assert_eq!(actual.0, Default::default());
1689                 assert_eq!(actual.1, post_header);
1690                 assert_eq!(actual.2, &some_data);
1691             }
1692 
1693             /// Run a test with the given ip numbers
1694             fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) {
1695                 // setup test payload
1696                 let e = ExtensionTestPayload::new(
1697                     ip_numbers,
1698                     header_sizes
1699                 );
1700 
1701                 if e.exts_hop_by_hop_error() {
1702                     // a hop by hop header that is not at the start triggers an error
1703                     assert_eq!(
1704                         Ipv6Extensions::from_slice(ip_numbers[0], e.slice()).unwrap_err(),
1705                         Content(HopByHopNotAtStart)
1706                     );
1707                 } else {
1708                     // normal read
1709                     let (header, next, rest) = Ipv6Extensions::from_slice(ip_numbers[0], e.slice()).unwrap();
1710                     let (read_len, last_header, expected_post_header) = e.assert_extensions(&header);
1711                     assert_eq!(next, expected_post_header);
1712                     assert_eq!(rest, &e.slice()[read_len..]);
1713 
1714                     // unexpected end of slice
1715                     {
1716                         let mut offset: usize = 0;
1717                         for l in &e.lengths {
1718                             if offset + l >= read_len {
1719                                 break;
1720                             }
1721                             offset += l;
1722                         }
1723 
1724                         assert_eq!(
1725                             Ipv6Extensions::from_slice(ip_numbers[0], &e.slice()[..read_len - 1]).unwrap_err(),
1726                             Len(err::LenError {
1727                                 required_len: read_len - offset,
1728                                 len: read_len - offset - 1,
1729                                 len_source: LenSource::Slice,
1730                                 layer: match last_header.unwrap() {
1731                                     AUTH => err::Layer::IpAuthHeader,
1732                                     IPV6_FRAG => err::Layer::Ipv6FragHeader,
1733                                     _ => err::Layer::Ipv6ExtHeader
1734                                 },
1735                                 layer_start_offset: offset,
1736                             })
1737                         );
1738                     }
1739                 }
1740             }
1741 
1742             // test the parsing of different extension header combinations
1743             for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
1744 
1745                 // single header parsing
1746                 run_test(
1747                     &[*first_header, post_header],
1748                     &[header_size],
1749                 );
1750 
1751                 for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
1752 
1753                     // double header parsing
1754                     run_test(
1755                         &[*first_header, *second_header, post_header],
1756                         &[header_size],
1757                     );
1758 
1759                     for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
1760                         // tripple header parsing
1761                         run_test(
1762                             &[*first_header, *second_header, *third_header, post_header],
1763                             &[header_size],
1764                         );
1765                     }
1766                 }
1767             }
1768 
1769             // test that the auth content error gets forwarded
1770             {
1771                 let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap();
1772                 let mut bytes = auth.to_bytes();
1773                 // inject an invalid len value
1774                 bytes[1] = 0;
1775                 let actual = Ipv6Extensions::from_slice(AUTH, &bytes).unwrap_err();
1776 
1777                 use err::ipv6_exts::HeaderError::IpAuth;
1778                 use err::ip_auth::HeaderError::ZeroPayloadLen;
1779                 assert_eq!(actual, Content(IpAuth(ZeroPayloadLen)));
1780             }
1781         }
1782     }
1783 
1784     proptest! {
1785         #[test]
1786         fn from_slice_lax(
1787             header_size in any::<u8>(),
1788             post_header in ip_number_any()
1789                 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
1790                     |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
1791                 )
1792         ) {
1793             use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*};
1794 
1795             // no extension headers filled
1796             {
1797                 let some_data = [1,2,3,4];
1798                 let actual = Ipv6Extensions::from_slice_lax(post_header, &some_data);
1799                 assert_eq!(actual.0, Default::default());
1800                 assert_eq!(actual.1, post_header);
1801                 assert_eq!(actual.2, &some_data);
1802                 assert!(actual.3.is_none());
1803             }
1804 
1805             /// Run a test with the given ip numbers
1806             fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) {
1807                 // setup test payload
1808                 let e = ExtensionTestPayload::new(
1809                     ip_numbers,
1810                     header_sizes
1811                 );
1812 
1813                 if e.exts_hop_by_hop_error() {
1814                     // a hop by hop header that is not at the start triggers an error
1815                     let actual = Ipv6Extensions::from_slice_lax(ip_numbers[0], e.slice());
1816                     assert_eq!(actual.3.unwrap(), (Content(HopByHopNotAtStart), Layer::Ipv6HopByHopHeader));
1817                 } else {
1818                     // normal read
1819                     let norm_actual = Ipv6Extensions::from_slice_lax(ip_numbers[0], e.slice());
1820                     let norm_expected = e.lax_extensions_for_len(e.slice().len());
1821                     assert_eq!(norm_actual.0, norm_expected.0);
1822                     assert_eq!(norm_actual.1, norm_expected.1);
1823                     assert_eq!(norm_actual.2, norm_expected.2);
1824                     assert!(norm_actual.3.is_none());
1825 
1826                     // unexpected end of slice
1827                     if norm_actual.0.header_len() > 0 {
1828 
1829                         let norm_len = norm_actual.0.header_len();
1830                         let actual = Ipv6Extensions::from_slice_lax(ip_numbers[0], &e.slice()[..norm_len - 1]);
1831 
1832                         let expected = e.lax_extensions_for_len(norm_len - 1);
1833                         assert_eq!(actual.0, expected.0);
1834                         assert_eq!(actual.1, expected.1);
1835                         assert_eq!(actual.2, expected.2);
1836                         let len_err = actual.3.unwrap().0.len_error().unwrap().clone();
1837                         assert_eq!(len_err.len, norm_len - 1 - expected.0.header_len());
1838                         assert_eq!(len_err.len_source, LenSource::Slice);
1839                         assert_eq!(
1840                             len_err.layer,
1841                             match expected.3.unwrap() {
1842                                 AUTH => err::Layer::IpAuthHeader,
1843                                 IPV6_FRAG => err::Layer::Ipv6FragHeader,
1844                                 _ => err::Layer::Ipv6ExtHeader
1845                             }
1846                         );
1847                         assert_eq!(len_err.layer_start_offset, expected.0.header_len());
1848                     }
1849                 }
1850             }
1851 
1852             // test the parsing of different extension header combinations
1853             for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
1854 
1855                 // single header parsing
1856                 run_test(
1857                     &[*first_header, post_header],
1858                     &[header_size],
1859                 );
1860 
1861                 for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
1862 
1863                     // double header parsing
1864                     run_test(
1865                         &[*first_header, *second_header, post_header],
1866                         &[header_size],
1867                     );
1868 
1869                     for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
1870                         // tripple header parsing
1871                         run_test(
1872                             &[*first_header, *second_header, *third_header, post_header],
1873                             &[header_size],
1874                         );
1875                     }
1876                 }
1877             }
1878 
1879             // test that the auth content error gets forwarded
1880             {
1881                 let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap();
1882                 let mut bytes = auth.to_bytes();
1883                 // inject an invalid len value
1884                 bytes[1] = 0;
1885                 let actual = Ipv6Extensions::from_slice_lax(AUTH, &bytes);
1886                 assert_eq!(0, actual.0.header_len());
1887                 assert_eq!(AUTH, actual.1);
1888                 assert_eq!(&bytes[..], actual.2);
1889 
1890                 use err::ipv6_exts::HeaderError::IpAuth;
1891                 use err::ip_auth::HeaderError::ZeroPayloadLen;
1892                 assert_eq!(actual.3.unwrap(), (Content(IpAuth(ZeroPayloadLen)), Layer::IpAuthHeader));
1893             }
1894         }
1895     }
1896 
1897     proptest! {
1898         #[test]
1899         fn read(
1900             header_size in any::<u8>(),
1901             post_header in ip_number_any()
1902                 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
1903                     |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
1904                 )
1905         ) {
1906             use err::ipv6_exts::HeaderError::*;
1907             use std::io::Cursor;
1908 
1909             // no extension headers filled
1910             {
1911                 let mut cursor = Cursor::new(&[]);
1912                 let actual = Ipv6Extensions::read(&mut cursor, post_header).unwrap();
1913                 assert_eq!(actual.0, Default::default());
1914                 assert_eq!(actual.1, post_header);
1915                 assert_eq!(0, cursor.position());
1916             }
1917 
1918             /// Run a test with the given ip numbers
1919             fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) {
1920                 // setup test payload
1921                 let e = ExtensionTestPayload::new(
1922                     ip_numbers,
1923                     header_sizes
1924                 );
1925                 let mut cursor = Cursor::new(e.slice());
1926 
1927                 if e.exts_hop_by_hop_error() {
1928                     // a hop by hop header that is not at the start triggers an error
1929                     assert_eq!(
1930                         Ipv6Extensions::read(&mut cursor, ip_numbers[0]).unwrap_err().content_error().unwrap(),
1931                         HopByHopNotAtStart
1932                     );
1933                 } else {
1934                     // normal read
1935                     let (header, next) = Ipv6Extensions::read(&mut cursor, ip_numbers[0]).unwrap();
1936                     let (read_len, _, expected_post_header) = e.assert_extensions(&header);
1937                     assert_eq!(next, expected_post_header);
1938                     assert_eq!(cursor.position() as usize, read_len);
1939 
1940                     // unexpected end of slice
1941                     {
1942                         let mut short_cursor = Cursor::new(&e.slice()[..read_len - 1]);
1943                         assert!(
1944                             Ipv6Extensions::read(&mut short_cursor, ip_numbers[0])
1945                             .unwrap_err()
1946                             .io_error()
1947                             .is_some()
1948                         );
1949                     }
1950                 }
1951             }
1952 
1953             // test the parsing of different extension header combinations
1954             for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
1955 
1956                 // single header parsing
1957                 run_test(
1958                     &[*first_header, post_header],
1959                     &[header_size],
1960                 );
1961 
1962                 for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
1963 
1964                     // double header parsing
1965                     run_test(
1966                         &[*first_header, *second_header, post_header],
1967                         &[header_size],
1968                     );
1969 
1970                     for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
1971                         // tripple header parsing
1972                         run_test(
1973                             &[*first_header, *second_header, *third_header, post_header],
1974                             &[header_size],
1975                         );
1976                     }
1977                 }
1978             }
1979 
1980             // test that the auth content error gets forwarded
1981             {
1982                 let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap();
1983                 let mut bytes = auth.to_bytes();
1984                 // inject an invalid len value
1985                 bytes[1] = 0;
1986                 let mut cursor = Cursor::new(&bytes[..]);
1987                 let actual = Ipv6Extensions::read(&mut cursor, AUTH).unwrap_err();
1988 
1989                 use err::ipv6_exts::HeaderError::IpAuth;
1990                 use err::ip_auth::HeaderError::ZeroPayloadLen;
1991                 assert_eq!(actual.content_error().unwrap(), IpAuth(ZeroPayloadLen));
1992             }
1993         }
1994     }
1995 
1996     proptest! {
1997         #[test]
1998         fn read_limited(
1999             header_size in any::<u8>(),
2000             post_header in ip_number_any()
2001                 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
2002                     |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
2003                 )
2004         ) {
2005             use err::ipv6_exts::HeaderError::*;
2006             use err::Layer;
2007             use std::io::Cursor;
2008             use crate::io::LimitedReader;
2009 
2010             // no extension headers filled
2011             {
2012                 let mut reader = LimitedReader::new(
2013                     Cursor::new(&[]),
2014                     0,
2015                     LenSource::Slice,
2016                     0,
2017                     Layer::Ipv6Header
2018                 );
2019                 let actual = Ipv6Extensions::read_limited(&mut reader, post_header).unwrap();
2020                 assert_eq!(actual.0, Default::default());
2021                 assert_eq!(actual.1, post_header);
2022                 assert_eq!(0, reader.read_len());
2023             }
2024 
2025             /// Run a test with the given ip numbers
2026             fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) {
2027                 // setup test payload
2028                 let e = ExtensionTestPayload::new(
2029                     ip_numbers,
2030                     header_sizes
2031                 );
2032                 let mut reader = LimitedReader::new(
2033                     Cursor::new(e.slice()),
2034                     e.slice().len(),
2035                     LenSource::Slice,
2036                     0,
2037                     Layer::Ipv6Header
2038                 );
2039 
2040                 if e.exts_hop_by_hop_error() {
2041                     // a hop by hop header that is not at the start triggers an error
2042                     assert_eq!(
2043                         Ipv6Extensions::read_limited(&mut reader, ip_numbers[0]).unwrap_err().content().unwrap(),
2044                         HopByHopNotAtStart
2045                     );
2046                 } else {
2047                     // normal read
2048                     let (header, next) = Ipv6Extensions::read_limited(&mut reader, ip_numbers[0]).unwrap();
2049                     let (read_len, _, expected_post_header) = e.assert_extensions(&header);
2050                     assert_eq!(next, expected_post_header);
2051                     assert_eq!(reader.read_len() + reader.layer_offset(), read_len);
2052 
2053                     // io error unexpected end
2054                     {
2055                         let mut short_reader = LimitedReader::new(
2056                             Cursor::new(&e.slice()[..read_len - 1]),
2057                             read_len,
2058                             LenSource::Slice,
2059                             0,
2060                             Layer::Ipv6Header
2061                         );
2062 
2063                         assert!(
2064                             Ipv6Extensions::read_limited(&mut short_reader, ip_numbers[0])
2065                             .unwrap_err()
2066                             .io()
2067                             .is_some()
2068                         );
2069                     }
2070 
2071                     // len error
2072                     {
2073                         let mut short_reader = LimitedReader::new(
2074                             Cursor::new(e.slice()),
2075                             read_len - 1,
2076                             LenSource::Slice,
2077                             0,
2078                             Layer::Ipv6Header
2079                         );
2080 
2081                         assert!(
2082                             Ipv6Extensions::read_limited(&mut short_reader, ip_numbers[0])
2083                             .unwrap_err()
2084                             .len()
2085                             .is_some()
2086                         );
2087                     }
2088                 }
2089             }
2090 
2091             // test the parsing of different extension header combinations
2092             for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
2093 
2094                 // single header parsing
2095                 run_test(
2096                     &[*first_header, post_header],
2097                     &[header_size],
2098                 );
2099 
2100                 for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
2101 
2102                     // double header parsing
2103                     run_test(
2104                         &[*first_header, *second_header, post_header],
2105                         &[header_size],
2106                     );
2107 
2108                     for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
2109                         // tripple header parsing
2110                         run_test(
2111                             &[*first_header, *second_header, *third_header, post_header],
2112                             &[header_size],
2113                         );
2114                     }
2115                 }
2116             }
2117 
2118             // test that the auth content error gets forwarded
2119             {
2120                 let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap();
2121                 let mut bytes = auth.to_bytes();
2122                 // inject an invalid len value
2123                 bytes[1] = 0;
2124                 let mut reader = LimitedReader::new(
2125                     Cursor::new(&bytes[..]),
2126                     bytes.len(),
2127                     LenSource::Slice,
2128                     0,
2129                     Layer::Ipv6Header
2130                 );
2131                 let actual = Ipv6Extensions::read_limited(&mut reader, AUTH).unwrap_err();
2132 
2133                 use err::ipv6_exts::HeaderError::IpAuth;
2134                 use err::ip_auth::HeaderError::ZeroPayloadLen;
2135                 assert_eq!(actual.content().unwrap(), IpAuth(ZeroPayloadLen));
2136             }
2137         }
2138     }
2139 
2140     proptest! {
2141         #[test]
2142         fn write(
2143             header_size in any::<u8>(),
2144             post_header in ip_number_any()
2145                 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
2146                     |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
2147                 )
2148         ) {
2149             // no extension headers filled
2150             {
2151                 let exts : Ipv6Extensions = Default::default();
2152                 let mut buffer = Vec::new();
2153                 exts.write(&mut buffer, post_header).unwrap();
2154                 assert_eq!(0, buffer.len());
2155             }
2156 
2157             /// Run a test with the given ip numbers
2158             fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8], post_header: IpNumber) {
2159                 use std::io::Cursor;
2160                 use crate::err::ipv6_exts::ExtsWalkError::*;
2161 
2162                 // setup test header
2163                 let e = ExtensionTestHeaders::new(
2164                     ip_numbers,
2165                     header_sizes
2166                 );
2167 
2168                 if e.ip_numbers[1..e.ip_numbers.len()-1].iter().any(|&x| x == IPV6_HOP_BY_HOP) {
2169                     // a hop by hop header that is not at the start triggers an error
2170                     let mut writer = Vec::with_capacity(e.data.header_len());
2171                     assert_eq!(
2172                         e.data.write(&mut writer, e.ip_numbers[0]).unwrap_err().content().unwrap(),
2173                         &HopByHopNotAtStart
2174                     );
2175                 } else {
2176                     // normal write
2177                     {
2178                         let mut writer = Vec::with_capacity(e.data.header_len());
2179                         e.data.write(&mut writer, e.ip_numbers[0]).unwrap();
2180 
2181                         if *e.ip_numbers.last().unwrap() != IPV6_HOP_BY_HOP {
2182                             // decoding if there will be no duplicate hop by hop error
2183                             // will be triggered
2184                             let (read, read_next, _) = Ipv6Extensions::from_slice(
2185                                 e.ip_numbers[0],
2186                                 &writer
2187                             ).unwrap();
2188                             assert_eq!(e.data, read);
2189                             assert_eq!(*e.ip_numbers.last().unwrap(), read_next);
2190                         }
2191                     }
2192 
2193                     // write error
2194                     {
2195                         let mut buffer = Vec::with_capacity(e.data.header_len() - 1);
2196                         buffer.resize(e.data.header_len() - 1, 0);
2197                         let mut cursor = Cursor::new(&mut buffer[..]);
2198 
2199                         let err = e.data.write(
2200                             &mut cursor,
2201                             e.ip_numbers[0]
2202                         ).unwrap_err();
2203 
2204                         assert!(err.io().is_some());
2205                     }
2206 
2207                     // missing reference (skip the last header)
2208                     {
2209                         use crate::err::ipv6_exts::ExtsWalkError::ExtNotReferenced;
2210 
2211                         let mut missing_ref = e.clone();
2212                         let missing_ext = missing_ref.introduce_missing_ref(post_header);
2213 
2214                         let mut writer = Vec::with_capacity(e.data.header_len());
2215                         let err = missing_ref.data.write(
2216                             &mut writer,
2217                             missing_ref.ip_numbers[0]
2218                         ).unwrap_err();
2219 
2220                         assert_eq!(
2221                             err.content().unwrap(),
2222                             &ExtNotReferenced{ missing_ext }
2223                         );
2224                     }
2225                 }
2226             }
2227 
2228             // test the parsing of different extension header combinations
2229             for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
2230 
2231                 // single header parsing
2232                 run_test(
2233                     &[*first_header, post_header],
2234                     &[header_size],
2235                     post_header,
2236                 );
2237 
2238                 for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
2239 
2240                     // double header parsing
2241                     run_test(
2242                         &[*first_header, *second_header, post_header],
2243                         &[header_size],
2244                         post_header,
2245                     );
2246 
2247                     for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
2248                         // tripple header parsing
2249                         run_test(
2250                             &[*first_header, *second_header, *third_header, post_header],
2251                             &[header_size],
2252                             post_header,
2253                         );
2254                     }
2255                 }
2256             }
2257         }
2258     }
2259 
2260     proptest! {
2261         #[test]
2262         fn header_len(
2263             hop_by_hop_options in ipv6_raw_ext_any(),
2264             destination_options in ipv6_raw_ext_any(),
2265             routing in ipv6_raw_ext_any(),
2266             fragment in ipv6_fragment_any(),
2267             auth in ip_auth_any(),
2268             final_destination_options in ipv6_raw_ext_any(),
2269         ) {
2270             // None
2271             {
2272                 let exts : Ipv6Extensions = Default::default();
2273                 assert_eq!(0, exts.header_len());
2274             }
2275 
2276             // All filled
2277             {
2278                 let exts = Ipv6Extensions{
2279                     hop_by_hop_options: Some(hop_by_hop_options.clone()),
2280                     destination_options: Some(destination_options.clone()),
2281                     routing: Some(
2282                         Ipv6RoutingExtensions{
2283                             routing: routing.clone(),
2284                             final_destination_options: Some(final_destination_options.clone()),
2285                         }
2286                     ),
2287                     fragment: Some(fragment.clone()),
2288                     auth: Some(auth.clone()),
2289                 };
2290                 assert_eq!(
2291                     exts.header_len(),
2292                     (
2293                         hop_by_hop_options.header_len() +
2294                         destination_options.header_len() +
2295                         routing.header_len() +
2296                         final_destination_options.header_len() +
2297                         fragment.header_len() +
2298                         auth.header_len()
2299                     )
2300                 );
2301             }
2302 
2303             // Routing without final destination options
2304             {
2305                 let exts = Ipv6Extensions{
2306                     hop_by_hop_options: Some(hop_by_hop_options.clone()),
2307                     destination_options: Some(destination_options.clone()),
2308                     routing: Some(
2309                         Ipv6RoutingExtensions{
2310                             routing: routing.clone(),
2311                             final_destination_options: None,
2312                         }
2313                     ),
2314                     fragment: Some(fragment.clone()),
2315                     auth: Some(auth.clone()),
2316                 };
2317                 assert_eq!(
2318                     exts.header_len(),
2319                     (
2320                         hop_by_hop_options.header_len() +
2321                         destination_options.header_len() +
2322                         routing.header_len() +
2323                         fragment.header_len() +
2324                         auth.header_len()
2325                     )
2326                 );
2327             }
2328         }
2329     }
2330 
2331     proptest! {
2332         #[test]
2333         fn set_next_headers(
2334             hop_by_hop_options in ipv6_raw_ext_any(),
2335             destination_options in ipv6_raw_ext_any(),
2336             routing in ipv6_raw_ext_any(),
2337             fragment in ipv6_fragment_any(),
2338             auth in ip_auth_any(),
2339             final_destination_options in ipv6_raw_ext_any(),
2340             post_header in ip_number_any()
2341                 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
2342                     |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
2343                 ),
2344         ) {
2345             // none filled
2346             {
2347                 let mut exts : Ipv6Extensions = Default::default();
2348                 assert_eq!(post_header, exts.set_next_headers(post_header));
2349                 assert!(exts.hop_by_hop_options.is_none());
2350                 assert!(exts.destination_options.is_none());
2351                 assert!(exts.routing.is_none());
2352                 assert!(exts.fragment.is_none());
2353                 assert!(exts.auth.is_none());
2354             }
2355 
2356             // all filled
2357             {
2358                 let mut exts = Ipv6Extensions{
2359                     hop_by_hop_options: Some(hop_by_hop_options.clone()),
2360                     destination_options: Some(destination_options.clone()),
2361                     routing: Some(
2362                         Ipv6RoutingExtensions{
2363                             routing: routing.clone(),
2364                             final_destination_options: Some(final_destination_options.clone()),
2365                         }
2366                     ),
2367                     fragment: Some(fragment.clone()),
2368                     auth: Some(auth.clone()),
2369                 };
2370                 assert_eq!(IPV6_HOP_BY_HOP, exts.set_next_headers(post_header));
2371 
2372                 assert_eq!(IPV6_DEST_OPTIONS, exts.hop_by_hop_options.as_ref().unwrap().next_header);
2373                 assert_eq!(IPV6_ROUTE, exts.destination_options.as_ref().unwrap().next_header);
2374                 assert_eq!(IPV6_FRAG, exts.routing.as_ref().unwrap().routing.next_header);
2375                 assert_eq!(AUTH, exts.fragment.as_ref().unwrap().next_header);
2376                 assert_eq!(IPV6_DEST_OPTIONS, exts.auth.as_ref().unwrap().next_header);
2377                 assert_eq!(post_header, exts.routing.as_ref().unwrap().final_destination_options.as_ref().unwrap().next_header);
2378             }
2379         }
2380     }
2381 
2382     proptest! {
2383         #[test]
2384         fn next_header(
2385             header_size in any::<u8>(),
2386             post_header in ip_number_any()
2387                 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
2388                     |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
2389                 ),)
2390         {
2391             // test empty
2392             {
2393                 let exts : Ipv6Extensions = Default::default();
2394                 assert_eq!(post_header, exts.next_header(post_header).unwrap());
2395             }
2396 
2397             /// Run a test with the given ip numbers
2398             fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8], post_header: IpNumber) {
2399                 // setup test header
2400                 let e = ExtensionTestHeaders::new(
2401                     ip_numbers,
2402                     header_sizes
2403                 );
2404 
2405                 if e.ip_numbers[1..e.ip_numbers.len()-1].iter().any(|&x| x == IPV6_HOP_BY_HOP) {
2406                     // a hop by hop header that is not at the start triggers an error
2407                     use crate::err::ipv6_exts::ExtsWalkError::HopByHopNotAtStart;
2408                     assert_eq!(
2409                         e.data.next_header(e.ip_numbers[0]).unwrap_err(),
2410                         HopByHopNotAtStart
2411                     );
2412                 } else {
2413                     // normal header
2414                     assert_eq!(
2415                         *e.ip_numbers.last().unwrap(),
2416                         e.data.next_header(e.ip_numbers[0]).unwrap()
2417                     );
2418 
2419                     // missing reference (skip the last header)
2420                     {
2421                         use crate::err::ipv6_exts::ExtsWalkError::ExtNotReferenced;
2422 
2423                         let mut missing_ref = e.clone();
2424                         let missing_ext = missing_ref.introduce_missing_ref(post_header);
2425                         assert_eq!(
2426                             missing_ref.data.next_header(missing_ref.ip_numbers[0]).unwrap_err(),
2427                             ExtNotReferenced{ missing_ext }
2428                         );
2429                     }
2430                 }
2431             }
2432 
2433             // test the parsing of different extension header combinations
2434             for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
2435 
2436                 // single header parsing
2437                 run_test(
2438                     &[*first_header, post_header],
2439                     &[header_size],
2440                     post_header,
2441                 );
2442 
2443                 for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
2444 
2445                     // double header parsing
2446                     run_test(
2447                         &[*first_header, *second_header, post_header],
2448                         &[header_size],
2449                         post_header,
2450                     );
2451 
2452                     for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
2453                         // tripple header parsing
2454                         run_test(
2455                             &[*first_header, *second_header, *third_header, post_header],
2456                             &[header_size],
2457                             post_header,
2458                         );
2459                     }
2460                 }
2461             }
2462         }
2463     }
2464 
2465     #[test]
is_fragmenting_payload()2466     fn is_fragmenting_payload() {
2467         // empty
2468         assert_eq!(
2469             false,
2470             Ipv6Extensions {
2471                 hop_by_hop_options: None,
2472                 destination_options: None,
2473                 routing: None,
2474                 fragment: None,
2475                 auth: None,
2476             }
2477             .is_fragmenting_payload()
2478         );
2479 
2480         // non fragmenting frag header
2481         assert_eq!(
2482             false,
2483             Ipv6Extensions {
2484                 hop_by_hop_options: None,
2485                 destination_options: None,
2486                 routing: None,
2487                 fragment: Some(Ipv6FragmentHeader::new(
2488                     ip_number::UDP,
2489                     IpFragOffset::ZERO,
2490                     false,
2491                     0
2492                 )),
2493                 auth: None,
2494             }
2495             .is_fragmenting_payload()
2496         );
2497 
2498         // fragmenting frag header
2499         assert!(Ipv6Extensions {
2500             hop_by_hop_options: None,
2501             destination_options: None,
2502             routing: None,
2503             fragment: Some(Ipv6FragmentHeader::new(
2504                 ip_number::UDP,
2505                 IpFragOffset::ZERO,
2506                 true,
2507                 0
2508             )),
2509             auth: None,
2510         }
2511         .is_fragmenting_payload());
2512     }
2513 
2514     #[test]
is_empty()2515     fn is_empty() {
2516         // empty
2517         assert!(Ipv6Extensions {
2518             hop_by_hop_options: None,
2519             destination_options: None,
2520             routing: None,
2521             fragment: None,
2522             auth: None,
2523         }
2524         .is_empty());
2525 
2526         // hop_by_hop_options
2527         assert_eq!(
2528             false,
2529             Ipv6Extensions {
2530                 hop_by_hop_options: Some(
2531                     Ipv6RawExtHeader::new_raw(ip_number::UDP, &[1, 2, 3, 4, 5, 6]).unwrap()
2532                 ),
2533                 destination_options: None,
2534                 routing: None,
2535                 fragment: None,
2536                 auth: None,
2537             }
2538             .is_empty()
2539         );
2540 
2541         // destination_options
2542         assert_eq!(
2543             false,
2544             Ipv6Extensions {
2545                 hop_by_hop_options: None,
2546                 destination_options: Some(
2547                     Ipv6RawExtHeader::new_raw(ip_number::UDP, &[1, 2, 3, 4, 5, 6]).unwrap()
2548                 ),
2549                 routing: None,
2550                 fragment: None,
2551                 auth: None,
2552             }
2553             .is_empty()
2554         );
2555 
2556         // routing
2557         assert_eq!(
2558             false,
2559             Ipv6Extensions {
2560                 hop_by_hop_options: None,
2561                 destination_options: None,
2562                 routing: Some(Ipv6RoutingExtensions {
2563                     routing: Ipv6RawExtHeader::new_raw(ip_number::UDP, &[1, 2, 3, 4, 5, 6])
2564                         .unwrap(),
2565                     final_destination_options: None,
2566                 }),
2567                 fragment: None,
2568                 auth: None,
2569             }
2570             .is_empty()
2571         );
2572 
2573         // fragment
2574         assert_eq!(
2575             false,
2576             Ipv6Extensions {
2577                 hop_by_hop_options: None,
2578                 destination_options: None,
2579                 routing: None,
2580                 fragment: Some(Ipv6FragmentHeader::new(
2581                     ip_number::UDP,
2582                     IpFragOffset::ZERO,
2583                     true,
2584                     0
2585                 )),
2586                 auth: None,
2587             }
2588             .is_empty()
2589         );
2590 
2591         // auth
2592         assert_eq!(
2593             false,
2594             Ipv6Extensions {
2595                 hop_by_hop_options: None,
2596                 destination_options: None,
2597                 routing: None,
2598                 fragment: None,
2599                 auth: Some(IpAuthHeader::new(ip_number::UDP, 0, 0, &[]).unwrap()),
2600             }
2601             .is_empty()
2602         );
2603     }
2604 
2605     #[test]
debug()2606     fn debug() {
2607         use alloc::format;
2608 
2609         let a: Ipv6Extensions = Default::default();
2610         assert_eq!(
2611             &format!(
2612                 "Ipv6Extensions {{ hop_by_hop_options: {:?}, destination_options: {:?}, routing: {:?}, fragment: {:?}, auth: {:?} }}",
2613                 a.hop_by_hop_options,
2614                 a.destination_options,
2615                 a.routing,
2616                 a.fragment,
2617                 a.auth,
2618             ),
2619             &format!("{:?}", a)
2620         );
2621     }
2622 
2623     #[test]
clone_eq()2624     fn clone_eq() {
2625         let a: Ipv6Extensions = Default::default();
2626         assert_eq!(a, a.clone());
2627     }
2628 
2629     #[test]
default()2630     fn default() {
2631         let a: Ipv6Extensions = Default::default();
2632         assert_eq!(a.hop_by_hop_options, None);
2633         assert_eq!(a.destination_options, None);
2634         assert_eq!(a.routing, None);
2635         assert_eq!(a.fragment, None);
2636         assert_eq!(a.auth, None);
2637     }
2638 }
2639