Skip to main content

etherparse/net/
ipv6_exts.rs

1use 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)]
24pub 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
32impl 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.
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.
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")))]
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")))]
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 a [`err::ipv6_exts::ExtsWalkError`] is returned.
643    pub(crate) fn write_internal<T: CoreWrite + ?Sized>(
644        &self,
645        writer: &mut T,
646        first_header: IpNumber,
647    ) -> Result<(), WriteError<T::Error, err::ipv6_exts::ExtsWalkError>> {
648        use err::ipv6_exts::ExtsWalkError::*;
649        use ip_number::*;
650
651        /// Struct flagging if a header needs to be written.
652        struct NeedsWrite {
653            pub hop_by_hop_options: bool,
654            pub destination_options: bool,
655            pub routing: bool,
656            pub fragment: bool,
657            pub auth: bool,
658            pub final_destination_options: bool,
659        }
660
661        let mut needs_write = NeedsWrite {
662            hop_by_hop_options: self.hop_by_hop_options.is_some(),
663            destination_options: self.destination_options.is_some(),
664            routing: self.routing.is_some(),
665            fragment: self.fragment.is_some(),
666            auth: self.auth.is_some(),
667            final_destination_options: if let Some(ref routing) = self.routing {
668                routing.final_destination_options.is_some()
669            } else {
670                false
671            },
672        };
673
674        let mut next_header = first_header;
675        let mut route_written = false;
676
677        // check if hop by hop header should be written first
678        if IPV6_HOP_BY_HOP == next_header {
679            let header = &self.hop_by_hop_options.as_ref().unwrap();
680            writer
681                .write_all(&header.to_bytes())
682                .map_err(WriteError::Io)?;
683            next_header = header.next_header;
684            needs_write.hop_by_hop_options = false;
685        }
686
687        loop {
688            match next_header {
689                IPV6_HOP_BY_HOP => {
690                    // Only trigger a "hop by hop not at start" error
691                    // if we actually still have to write a hop by hop header.
692                    //
693                    // The ip number for hop by hop is 0, which could be used
694                    // as a placeholder by user and later replaced. So let's
695                    // not be overzealous and allow a next header with hop
696                    // by hop if it is not part of this extensions struct.
697                    if needs_write.hop_by_hop_options {
698                        // the hop by hop header is only allowed at the start
699                        return Err(WriteError::Content(HopByHopNotAtStart));
700                    } else {
701                        break;
702                    }
703                }
704                IPV6_DEST_OPTIONS => {
705                    // the destination options are allowed to be written twice
706                    // once before a routing header and once after.
707                    if route_written {
708                        if needs_write.final_destination_options {
709                            let header = &self
710                                .routing
711                                .as_ref()
712                                .unwrap()
713                                .final_destination_options
714                                .as_ref()
715                                .unwrap();
716                            writer
717                                .write_all(&header.to_bytes())
718                                .map_err(WriteError::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                        writer
727                            .write_all(&header.to_bytes())
728                            .map_err(WriteError::Io)?;
729                        next_header = header.next_header;
730                        needs_write.destination_options = false;
731                    } else {
732                        break;
733                    }
734                }
735                IPV6_ROUTE => {
736                    if needs_write.routing {
737                        let header = &self.routing.as_ref().unwrap().routing;
738                        writer
739                            .write_all(&header.to_bytes())
740                            .map_err(WriteError::Io)?;
741                        next_header = header.next_header;
742                        needs_write.routing = false;
743                        // for destination options
744                        route_written = true;
745                    } else {
746                        break;
747                    }
748                }
749                IPV6_FRAG => {
750                    if needs_write.fragment {
751                        let header = &self.fragment.as_ref().unwrap();
752                        writer
753                            .write_all(&header.to_bytes())
754                            .map_err(WriteError::Io)?;
755                        next_header = header.next_header;
756                        needs_write.fragment = false;
757                    } else {
758                        break;
759                    }
760                }
761                AUTH => {
762                    if needs_write.auth {
763                        let header = &self.auth.as_ref().unwrap();
764                        writer
765                            .write_all(&header.to_bytes())
766                            .map_err(WriteError::Io)?;
767                        next_header = header.next_header;
768                        needs_write.auth = false;
769                    } else {
770                        break;
771                    }
772                }
773                _ => {
774                    // reached an unknown next_header id, proceed to check if everything was written
775                    break;
776                }
777            }
778        }
779
780        // check that all header have been written
781        if needs_write.hop_by_hop_options {
782            Err(WriteError::Content(ExtNotReferenced {
783                missing_ext: IpNumber::IPV6_HEADER_HOP_BY_HOP,
784            }))
785        } else if needs_write.destination_options {
786            Err(WriteError::Content(ExtNotReferenced {
787                missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS,
788            }))
789        } else if needs_write.routing {
790            Err(WriteError::Content(ExtNotReferenced {
791                missing_ext: IpNumber::IPV6_ROUTE_HEADER,
792            }))
793        } else if needs_write.fragment {
794            Err(WriteError::Content(ExtNotReferenced {
795                missing_ext: IpNumber::IPV6_FRAGMENTATION_HEADER,
796            }))
797        } else if needs_write.auth {
798            Err(WriteError::Content(ExtNotReferenced {
799                missing_ext: IpNumber::AUTHENTICATION_HEADER,
800            }))
801        } else if needs_write.final_destination_options {
802            Err(WriteError::Content(ExtNotReferenced {
803                missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS,
804            }))
805        } else {
806            Ok(())
807        }
808    }
809
810    /// Writes the given headers to a writer based on the order defined in
811    /// the next_header fields of the headers and the first header_id
812    /// passed to this function.
813    ///
814    /// It is required that all next header are correctly set in the headers
815    /// and no other ipv6 header extensions follow this header. If this is not
816    /// the case an [`err::ipv6_exts::HeaderWriteError::Content`] error is
817    /// returned.
818    #[cfg(feature = "std")]
819    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
820    pub fn write<T: std::io::Write + Sized>(
821        &self,
822        writer: &mut T,
823        first_header: IpNumber,
824    ) -> Result<(), err::ipv6_exts::HeaderWriteError> {
825        self.write_internal(&mut IoWriter(writer), first_header)
826            .map_err(|err| match err {
827                WriteError::Io(err) => err::ipv6_exts::HeaderWriteError::Io(err),
828                WriteError::Content(err) => err::ipv6_exts::HeaderWriteError::Content(err),
829            })
830    }
831
832    /// Length of the all present headers in bytes.
833    pub fn header_len(&self) -> usize {
834        let mut result = 0;
835
836        if let Some(ref header) = self.hop_by_hop_options {
837            result += header.header_len();
838        }
839        if let Some(ref header) = self.destination_options {
840            result += header.header_len();
841        }
842        if let Some(ref header) = self.routing {
843            result += header.routing.header_len();
844            if let Some(ref header) = header.final_destination_options {
845                result += header.header_len();
846            }
847        }
848        if let Some(ref header) = self.fragment {
849            result += header.header_len();
850        }
851        if let Some(ref header) = self.auth {
852            result += header.header_len();
853        }
854
855        result
856    }
857
858    /// Sets all the next_header fields of the headers based on the adviced default order
859    /// with the given protocol number as last "next header" value. The return value is the protocol
860    /// number of the first existing extension header that should be entered in the ipv6 header as
861    /// next_header.
862    ///
863    /// If no extension headers are present the value of the argument is returned.
864    pub fn set_next_headers(&mut self, last_protocol_number: IpNumber) -> IpNumber {
865        use ip_number::*;
866
867        let mut next = last_protocol_number;
868
869        // go through the proposed order of extension headers from
870        // RFC 8200 backwards. The header order defined in RFC8200 is:
871        //
872        // * IPv6 header
873        // * Hop-by-Hop Options header
874        // * Destination Options header
875        // * Routing header
876        // * Fragment header
877        // * Authentication header
878        // * Encapsulating Security Payload header
879        // * Destination Options header
880        // * Upper-Layer header
881        //
882        if let Some(ref mut routing) = self.routing {
883            if let Some(ref mut header) = routing.final_destination_options {
884                header.next_header = next;
885                next = IPV6_DEST_OPTIONS;
886            }
887        }
888        if let Some(ref mut header) = self.auth {
889            header.next_header = next;
890            next = AUTH;
891        }
892        if let Some(ref mut header) = self.fragment {
893            header.next_header = next;
894            next = IPV6_FRAG;
895        }
896        if let Some(ref mut routing) = self.routing {
897            routing.routing.next_header = next;
898            next = IPV6_ROUTE;
899        }
900        if let Some(ref mut header) = self.destination_options {
901            header.next_header = next;
902            next = IPV6_DEST_OPTIONS;
903        }
904        if let Some(ref mut header) = self.hop_by_hop_options {
905            header.next_header = next;
906            next = IPV6_HOP_BY_HOP;
907        }
908
909        next
910    }
911
912    /// Return next header based on the extension headers and
913    /// the first ip protocol number.
914    pub fn next_header(&self, first_next_header: IpNumber) -> Result<IpNumber, ExtsWalkError> {
915        use ip_number::*;
916        use ExtsWalkError::*;
917
918        /// Struct flagging if a header needs to be referenced.
919        struct OutstandingRef {
920            pub hop_by_hop_options: bool,
921            pub destination_options: bool,
922            pub routing: bool,
923            pub fragment: bool,
924            pub auth: bool,
925            pub final_destination_options: bool,
926        }
927
928        let mut outstanding_refs = OutstandingRef {
929            hop_by_hop_options: self.hop_by_hop_options.is_some(),
930            destination_options: self.destination_options.is_some(),
931            routing: self.routing.is_some(),
932            fragment: self.fragment.is_some(),
933            auth: self.auth.is_some(),
934            final_destination_options: if let Some(ref routing) = self.routing {
935                routing.final_destination_options.is_some()
936            } else {
937                false
938            },
939        };
940
941        let mut next = first_next_header;
942        let mut route_refed = false;
943
944        // check if hop by hop header should be written first
945        if IPV6_HOP_BY_HOP == next {
946            if let Some(ref header) = self.hop_by_hop_options {
947                next = header.next_header;
948                outstanding_refs.hop_by_hop_options = false;
949            }
950        }
951
952        loop {
953            match next {
954                IPV6_HOP_BY_HOP => {
955                    // Only trigger a "hop by hop not at start" error
956                    // if we actually still have to write a hop by hop header.
957                    //
958                    // The ip number for hop by hop is 0, which could be used
959                    // as a placeholder by user and later replaced. So let's
960                    // not be overzealous and allow a next header with hop
961                    // by hop if it is not part of this extensions struct.
962                    if outstanding_refs.hop_by_hop_options {
963                        // the hop by hop header is only allowed at the start
964                        return Err(HopByHopNotAtStart);
965                    } else {
966                        break;
967                    }
968                }
969                IPV6_DEST_OPTIONS => {
970                    // the destination options are allowed to be written twice
971                    // once before a routing header and once after.
972                    if route_refed {
973                        if outstanding_refs.final_destination_options {
974                            let header = &self
975                                .routing
976                                .as_ref()
977                                .unwrap()
978                                .final_destination_options
979                                .as_ref()
980                                .unwrap();
981                            next = header.next_header;
982                            outstanding_refs.final_destination_options = false;
983                        } else {
984                            break;
985                        }
986                    } else if outstanding_refs.destination_options {
987                        let header = &self.destination_options.as_ref().unwrap();
988                        next = header.next_header;
989                        outstanding_refs.destination_options = false;
990                    } else {
991                        break;
992                    }
993                }
994                IPV6_ROUTE => {
995                    if outstanding_refs.routing {
996                        let header = &self.routing.as_ref().unwrap().routing;
997                        next = header.next_header;
998                        outstanding_refs.routing = false;
999                        // for destination options
1000                        route_refed = true;
1001                    } else {
1002                        break;
1003                    }
1004                }
1005                IPV6_FRAG => {
1006                    if outstanding_refs.fragment {
1007                        let header = &self.fragment.as_ref().unwrap();
1008                        next = header.next_header;
1009                        outstanding_refs.fragment = false;
1010                    } else {
1011                        break;
1012                    }
1013                }
1014                AUTH => {
1015                    if outstanding_refs.auth {
1016                        let header = &self.auth.as_ref().unwrap();
1017                        next = header.next_header;
1018                        outstanding_refs.auth = false;
1019                    } else {
1020                        break;
1021                    }
1022                }
1023                _ => break,
1024            }
1025        }
1026
1027        // assume all done
1028        if outstanding_refs.hop_by_hop_options {
1029            return Err(ExtNotReferenced {
1030                missing_ext: IpNumber::IPV6_HEADER_HOP_BY_HOP,
1031            });
1032        }
1033        if outstanding_refs.destination_options {
1034            return Err(ExtNotReferenced {
1035                missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS,
1036            });
1037        }
1038        if outstanding_refs.routing {
1039            return Err(ExtNotReferenced {
1040                missing_ext: IpNumber::IPV6_ROUTE_HEADER,
1041            });
1042        }
1043        if outstanding_refs.fragment {
1044            return Err(ExtNotReferenced {
1045                missing_ext: IpNumber::IPV6_FRAGMENTATION_HEADER,
1046            });
1047        }
1048        if outstanding_refs.auth {
1049            return Err(ExtNotReferenced {
1050                missing_ext: IpNumber::AUTHENTICATION_HEADER,
1051            });
1052        }
1053        if outstanding_refs.final_destination_options {
1054            return Err(ExtNotReferenced {
1055                missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS,
1056            });
1057        }
1058
1059        Ok(next)
1060    }
1061
1062    /// Returns true if a fragmentation header is present in
1063    /// the extensions that fragments the payload.
1064    ///
1065    /// Note: A fragmentation header can still be present
1066    /// even if the return value is false in case the fragmentation
1067    /// headers don't fragment the payload. This is the case if
1068    /// the offset of all fragmentation header is 0 and the
1069    /// more fragment bit is not set.
1070    #[inline]
1071    pub fn is_fragmenting_payload(&self) -> bool {
1072        if let Some(frag) = self.fragment.as_ref() {
1073            frag.is_fragmenting_payload()
1074        } else {
1075            false
1076        }
1077    }
1078
1079    /// Returns true if no IPv6 extension header is present (all fields `None`).
1080    #[inline]
1081    pub fn is_empty(&self) -> bool {
1082        self.hop_by_hop_options.is_none()
1083            && self.destination_options.is_none()
1084            && self.routing.is_none()
1085            && self.fragment.is_none()
1086            && self.auth.is_none()
1087    }
1088}
1089
1090#[cfg(test)]
1091pub mod ipv6_exts_test_helpers {
1092    use super::*;
1093    use crate::ip_number::*;
1094    use alloc::vec::Vec;
1095
1096    /// IP numbers that are assigned ipv6 header extensions.
1097    pub const EXTENSION_KNOWN_IP_NUMBERS: [IpNumber; 5] = [
1098        AUTH,
1099        IPV6_DEST_OPTIONS,
1100        IPV6_HOP_BY_HOP,
1101        IPV6_FRAG,
1102        IPV6_ROUTE,
1103    ];
1104
1105    /// Helper struct that generates test data with dummy
1106    /// extension header data.
1107    pub struct ExtensionTestPayload {
1108        pub ip_numbers: Vec<IpNumber>,
1109        pub lengths: Vec<usize>,
1110        pub data: Vec<u8>,
1111    }
1112
1113    impl ExtensionTestPayload {
1114        pub fn new(ip_numbers: &[IpNumber], header_sizes: &[u8]) -> ExtensionTestPayload {
1115            assert!(ip_numbers.len() > 1);
1116            assert!(header_sizes.len() > 0);
1117
1118            let mut result = ExtensionTestPayload {
1119                ip_numbers: ip_numbers.to_vec(),
1120                lengths: Vec::with_capacity(ip_numbers.len() - 1),
1121                data: Vec::with_capacity((ip_numbers.len() - 1) * (0xff * 8 + 8)),
1122            };
1123            for i in 0..ip_numbers.len() - 1 {
1124                result.add_payload(
1125                    ip_numbers[i],
1126                    ip_numbers[i + 1],
1127                    header_sizes[i % header_sizes.len()],
1128                )
1129            }
1130            result
1131        }
1132
1133        pub fn slice(&self) -> &[u8] {
1134            &self.data
1135        }
1136
1137        fn add_payload(&mut self, ip_number: IpNumber, next_header: IpNumber, header_ext_len: u8) {
1138            match ip_number {
1139                IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS => {
1140                    // insert next header & size
1141                    let mut raw: [u8; 0xff * 8 + 8] = [0; 0xff * 8 + 8];
1142                    raw[0] = next_header.0;
1143                    raw[1] = header_ext_len;
1144
1145                    // insert payload
1146                    self.data
1147                        .extend_from_slice(&raw[..8 + usize::from(header_ext_len) * 8]);
1148                    self.lengths.push(8 + usize::from(header_ext_len) * 8);
1149                }
1150                IPV6_FRAG => {
1151                    // generate payload
1152                    let mut raw: [u8; 8] = [0; 8];
1153                    raw[0] = next_header.0;
1154                    raw[1] = 0;
1155
1156                    // insert payload
1157                    self.data.extend_from_slice(&raw[..8]);
1158                    self.lengths.push(8);
1159                }
1160                AUTH => {
1161                    let mut raw: [u8; 0xff * 4 + 8] = [0; 0xff * 4 + 8];
1162                    raw[0] = next_header.0;
1163                    // authentfication header len is defined as
1164                    // '32-bit words (4-byteunits), minus "2"'
1165                    let len = if header_ext_len > 0 {
1166                        raw[1] = header_ext_len;
1167                        usize::from(header_ext_len) * 4
1168                    } else {
1169                        // auth has a minimum size of 1
1170                        raw[1] = 1;
1171                        4
1172                    } + 8;
1173                    self.data.extend_from_slice(&raw[..len]);
1174                    self.lengths.push(len);
1175                }
1176                _ => unreachable!(),
1177            }
1178        }
1179
1180        /// Returns true of the payload will trigger a "hop by hop not
1181        /// at start" error which is not ignored because of an early
1182        /// parsing abort.
1183        pub fn exts_hop_by_hop_error(&self) -> bool {
1184            struct ReadState {
1185                dest_opt: bool,
1186                routing: bool,
1187                final_dest_opt: bool,
1188                frag: bool,
1189                auth: bool,
1190            }
1191
1192            // state if a header type has already been read
1193            let mut read = ReadState {
1194                dest_opt: false,
1195                routing: false,
1196                final_dest_opt: false,
1197                frag: false,
1198                auth: false,
1199            };
1200
1201            for i in 0..self.ip_numbers.len() {
1202                match self.ip_numbers[i] {
1203                    IPV6_HOP_BY_HOP => {
1204                        if i != 0 {
1205                            return true;
1206                        }
1207                    }
1208                    IPV6_ROUTE => {
1209                        if read.routing {
1210                            return false;
1211                        } else {
1212                            read.routing = true;
1213                        }
1214                    }
1215                    IPV6_DEST_OPTIONS => {
1216                        // check the kind of destination options (aka is it before or after the routing header)
1217                        if read.routing {
1218                            // final dest opt
1219                            if read.final_dest_opt {
1220                                return false;
1221                            } else {
1222                                read.final_dest_opt = true;
1223                            }
1224                        } else {
1225                            // dst opt
1226                            if read.dest_opt {
1227                                return false;
1228                            } else {
1229                                read.dest_opt = true;
1230                            }
1231                        }
1232                    }
1233                    IPV6_FRAG => {
1234                        if read.frag {
1235                            return false;
1236                        } else {
1237                            read.frag = true;
1238                        }
1239                    }
1240                    AUTH => {
1241                        if read.auth {
1242                            return false;
1243                        } else {
1244                            read.auth = true;
1245                        }
1246                    }
1247                    _ => return false,
1248                }
1249            }
1250            return false;
1251        }
1252
1253        /// Checks the if the extensions match the expected values based
1254        /// on this test payload.
1255        pub fn assert_extensions(
1256            &self,
1257            exts: &Ipv6Extensions,
1258        ) -> (usize, Option<IpNumber>, IpNumber) {
1259            struct ReadState {
1260                hop_by_hop: bool,
1261                dest_opt: bool,
1262                routing: bool,
1263                final_dest_opt: bool,
1264                frag: bool,
1265                auth: bool,
1266            }
1267
1268            // state if a header type has already been read
1269            let mut read = ReadState {
1270                hop_by_hop: false,
1271                dest_opt: false,
1272                routing: false,
1273                final_dest_opt: false,
1274                frag: false,
1275                auth: false,
1276            };
1277
1278            let mut slice = &self.data[..];
1279            let mut last_decoded = None;
1280            let mut post_header = self.ip_numbers[0];
1281
1282            for i in 0..self.ip_numbers.len() - 1 {
1283                let mut stop = false;
1284                match self.ip_numbers[i] {
1285                    IPV6_HOP_BY_HOP => {
1286                        assert!(false == read.hop_by_hop);
1287                        let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1288                        assert_eq!(&header, exts.hop_by_hop_options.as_ref().unwrap());
1289                        slice = rest;
1290                        read.hop_by_hop = true;
1291                        last_decoded = Some(IPV6_HOP_BY_HOP);
1292                    }
1293                    IPV6_ROUTE => {
1294                        if read.routing {
1295                            stop = true;
1296                        } else {
1297                            let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1298                            assert_eq!(&header, &exts.routing.as_ref().unwrap().routing);
1299                            slice = rest;
1300                            read.routing = true;
1301                            last_decoded = Some(IPV6_ROUTE);
1302                        }
1303                    }
1304                    IPV6_DEST_OPTIONS => {
1305                        // check the kind of destination options (aka is it before or after the routing header)
1306                        if read.routing {
1307                            // final dest opt
1308                            if read.final_dest_opt {
1309                                stop = true;
1310                            } else {
1311                                let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1312                                assert_eq!(
1313                                    &header,
1314                                    exts.routing
1315                                        .as_ref()
1316                                        .unwrap()
1317                                        .final_destination_options
1318                                        .as_ref()
1319                                        .unwrap()
1320                                );
1321                                slice = rest;
1322                                read.final_dest_opt = true;
1323                                last_decoded = Some(IPV6_DEST_OPTIONS);
1324                            }
1325                        } else {
1326                            // dst opt
1327                            if read.dest_opt {
1328                                stop = true;
1329                            } else {
1330                                let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1331                                assert_eq!(&header, exts.destination_options.as_ref().unwrap());
1332                                slice = rest;
1333                                read.dest_opt = true;
1334                                last_decoded = Some(IPV6_DEST_OPTIONS);
1335                            }
1336                        }
1337                    }
1338                    IPV6_FRAG => {
1339                        if read.frag {
1340                            // duplicate header -> stop
1341                            stop = true;
1342                        } else {
1343                            let (header, rest) = Ipv6FragmentHeader::from_slice(slice).unwrap();
1344                            assert_eq!(&header, exts.fragment.as_ref().unwrap());
1345                            slice = rest;
1346                            read.frag = true;
1347                            last_decoded = Some(IPV6_FRAG);
1348                        }
1349                    }
1350                    AUTH => {
1351                        if read.auth {
1352                            // duplicate header -> stop
1353                            stop = true;
1354                        } else {
1355                            let (header, rest) = IpAuthHeader::from_slice(slice).unwrap();
1356                            assert_eq!(&header, exts.auth.as_ref().unwrap());
1357                            slice = rest;
1358                            read.auth = true;
1359                            last_decoded = Some(AUTH);
1360                        }
1361                    }
1362                    _ => {
1363                        // non extension header -> stop
1364                        stop = true;
1365                    }
1366                }
1367                if stop {
1368                    post_header = self.ip_numbers[i];
1369                    break;
1370                } else {
1371                    post_header = self.ip_numbers[i + 1];
1372                }
1373            }
1374
1375            // check the non parsed headers are not present
1376            if false == read.hop_by_hop {
1377                assert!(exts.hop_by_hop_options.is_none());
1378            }
1379            if false == read.dest_opt {
1380                assert!(exts.destination_options.is_none());
1381            }
1382            if false == read.routing {
1383                assert!(exts.routing.is_none());
1384            } else {
1385                if false == read.final_dest_opt {
1386                    assert!(exts
1387                        .routing
1388                        .as_ref()
1389                        .unwrap()
1390                        .final_destination_options
1391                        .is_none());
1392                }
1393            }
1394            if false == read.frag {
1395                assert!(exts.fragment.is_none());
1396            }
1397            if false == read.auth {
1398                assert!(exts.auth.is_none());
1399            }
1400
1401            (self.data.len() - slice.len(), last_decoded, post_header)
1402        }
1403
1404        /// Return the expected lax from slice result and ipnumber which caused
1405        /// an error.
1406        pub fn lax_extensions_for_len(
1407            &self,
1408            limiting_len: usize,
1409        ) -> (Ipv6Extensions, IpNumber, &[u8], Option<IpNumber>) {
1410            // state if a header type has already been read
1411            let mut exts: Ipv6Extensions = Default::default();
1412            let mut post_header = *self.ip_numbers.first().unwrap();
1413            let mut slice = &self.data[..];
1414
1415            for i in 0..self.ip_numbers.len() - 1 {
1416                // check if the limiting size gets hit
1417                if self.slice().len() - slice.len() + self.lengths[i] > limiting_len {
1418                    return (
1419                        exts,
1420                        self.ip_numbers[i],
1421                        &self.slice()[self.slice().len() - slice.len()..limiting_len],
1422                        Some(self.ip_numbers[i]),
1423                    );
1424                }
1425
1426                let mut stop = false;
1427                match self.ip_numbers[i] {
1428                    IPV6_HOP_BY_HOP => {
1429                        assert!(exts.hop_by_hop_options.is_none());
1430                        let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1431                        exts.hop_by_hop_options = Some(header);
1432                        slice = rest;
1433                    }
1434                    IPV6_ROUTE => {
1435                        if exts.routing.is_some() {
1436                            stop = true;
1437                        } else {
1438                            let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1439                            exts.routing = Some(Ipv6RoutingExtensions {
1440                                routing: header,
1441                                final_destination_options: None,
1442                            });
1443                            slice = rest;
1444                        }
1445                    }
1446                    IPV6_DEST_OPTIONS => {
1447                        // check the kind of destination options (aka is it before or after the routing header)
1448                        if let Some(routing) = exts.routing.as_mut() {
1449                            // final dest opt
1450                            if routing.final_destination_options.is_some() {
1451                                stop = true;
1452                            } else {
1453                                let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1454                                routing.final_destination_options = Some(header);
1455                                slice = rest;
1456                            }
1457                        } else {
1458                            // dst opt
1459                            if exts.destination_options.is_some() {
1460                                stop = true;
1461                            } else {
1462                                let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap();
1463                                exts.destination_options = Some(header);
1464                                slice = rest;
1465                            }
1466                        }
1467                    }
1468                    IPV6_FRAG => {
1469                        if exts.fragment.is_some() {
1470                            // duplicate header -> stop
1471                            stop = true;
1472                        } else {
1473                            let (header, rest) = Ipv6FragmentHeader::from_slice(slice).unwrap();
1474                            exts.fragment = Some(header);
1475                            slice = rest;
1476                        }
1477                    }
1478                    AUTH => {
1479                        if exts.auth.is_some() {
1480                            // duplicate header -> stop
1481                            stop = true;
1482                        } else {
1483                            let (header, rest) = IpAuthHeader::from_slice(slice).unwrap();
1484                            exts.auth = Some(header);
1485                            slice = rest;
1486                        }
1487                    }
1488                    _ => {
1489                        // non extension header -> stop
1490                        stop = true;
1491                    }
1492                }
1493                if stop {
1494                    post_header = self.ip_numbers[i];
1495                    break;
1496                } else {
1497                    post_header = self.ip_numbers[i + 1];
1498                }
1499            }
1500
1501            (
1502                exts,
1503                post_header,
1504                &self.slice()[self.slice().len() - slice.len()..limiting_len],
1505                None,
1506            )
1507        }
1508    }
1509
1510    /// extension header data.
1511    #[derive(Clone)]
1512    pub struct ExtensionTestHeaders {
1513        pub ip_numbers: Vec<IpNumber>,
1514        pub data: Ipv6Extensions,
1515    }
1516
1517    impl ExtensionTestHeaders {
1518        pub fn new(ip_numbers: &[IpNumber], header_sizes: &[u8]) -> ExtensionTestHeaders {
1519            assert!(ip_numbers.len() > 1);
1520            assert!(header_sizes.len() > 0);
1521
1522            let mut result = ExtensionTestHeaders {
1523                ip_numbers: ip_numbers.to_vec(),
1524                data: Default::default(),
1525            };
1526            for i in 0..ip_numbers.len() - 1 {
1527                let succ = result.add_payload(
1528                    ip_numbers[i],
1529                    ip_numbers[i + 1],
1530                    header_sizes[i % header_sizes.len()],
1531                );
1532                if false == succ {
1533                    // write was not possible (duplicate)
1534                    // reduce the list so the current ip number
1535                    // is the final one
1536                    result.ip_numbers.truncate(i + 1);
1537                    break;
1538                }
1539            }
1540            result
1541        }
1542
1543        pub fn introduce_missing_ref(&mut self, new_header: IpNumber) -> IpNumber {
1544            assert!(self.ip_numbers.len() >= 2);
1545
1546            // set the next_header of the last extension header and return the id
1547            if self.ip_numbers.len() >= 3 {
1548                match self.ip_numbers[self.ip_numbers.len() - 3] {
1549                    IPV6_HOP_BY_HOP => {
1550                        self.data.hop_by_hop_options.as_mut().unwrap().next_header = new_header;
1551                    }
1552                    IPV6_DEST_OPTIONS => {
1553                        if self.ip_numbers[..self.ip_numbers.len() - 3]
1554                            .iter()
1555                            .any(|&x| x == IPV6_ROUTE)
1556                        {
1557                            self.data
1558                                .routing
1559                                .as_mut()
1560                                .unwrap()
1561                                .final_destination_options
1562                                .as_mut()
1563                                .unwrap()
1564                                .next_header = new_header;
1565                        } else {
1566                            self.data.destination_options.as_mut().unwrap().next_header =
1567                                new_header;
1568                        }
1569                    }
1570                    IPV6_ROUTE => {
1571                        self.data.routing.as_mut().unwrap().routing.next_header = new_header;
1572                    }
1573                    IPV6_FRAG => {
1574                        self.data.fragment.as_mut().unwrap().next_header = new_header;
1575                    }
1576                    AUTH => {
1577                        self.data.auth.as_mut().unwrap().next_header = new_header;
1578                    }
1579                    _ => unreachable!(),
1580                }
1581                match self.ip_numbers[self.ip_numbers.len() - 2] {
1582                    IPV6_HOP_BY_HOP => IpNumber::IPV6_HEADER_HOP_BY_HOP,
1583                    IPV6_DEST_OPTIONS => IpNumber::IPV6_DESTINATION_OPTIONS,
1584                    IPV6_ROUTE => IpNumber::IPV6_ROUTE_HEADER,
1585                    IPV6_FRAG => IpNumber::IPV6_FRAGMENTATION_HEADER,
1586                    AUTH => IpNumber::AUTHENTICATION_HEADER,
1587                    _ => unreachable!(),
1588                }
1589            } else {
1590                // rewrite start number in case it is just one extension header
1591                let missing = self.ip_numbers[0];
1592                self.ip_numbers[0] = new_header;
1593                match missing {
1594                    IPV6_HOP_BY_HOP => IpNumber::IPV6_HEADER_HOP_BY_HOP,
1595                    IPV6_DEST_OPTIONS => IpNumber::IPV6_DESTINATION_OPTIONS,
1596                    IPV6_ROUTE => IpNumber::IPV6_ROUTE_HEADER,
1597                    IPV6_FRAG => IpNumber::IPV6_FRAGMENTATION_HEADER,
1598                    AUTH => IpNumber::AUTHENTICATION_HEADER,
1599                    _ => unreachable!(),
1600                }
1601            }
1602        }
1603
1604        fn add_payload(
1605            &mut self,
1606            ip_number: IpNumber,
1607            next_header: IpNumber,
1608            header_ext_len: u8,
1609        ) -> bool {
1610            match ip_number {
1611                IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS => {
1612                    use Ipv6RawExtHeader as R;
1613                    let payload: [u8; R::MAX_PAYLOAD_LEN] = [0; R::MAX_PAYLOAD_LEN];
1614                    let len = usize::from(header_ext_len) * 8 + 6;
1615
1616                    let raw = Ipv6RawExtHeader::new_raw(next_header, &payload[..len]).unwrap();
1617                    match ip_number {
1618                        IPV6_HOP_BY_HOP => {
1619                            if self.data.hop_by_hop_options.is_none() {
1620                                self.data.hop_by_hop_options = Some(raw);
1621                                true
1622                            } else {
1623                                false
1624                            }
1625                        }
1626                        IPV6_ROUTE => {
1627                            if self.data.routing.is_none() {
1628                                self.data.routing = Some(Ipv6RoutingExtensions {
1629                                    routing: raw,
1630                                    final_destination_options: None,
1631                                });
1632                                true
1633                            } else {
1634                                false
1635                            }
1636                        }
1637                        IPV6_DEST_OPTIONS => {
1638                            if let Some(ref mut route) = self.data.routing {
1639                                if route.final_destination_options.is_none() {
1640                                    route.final_destination_options = Some(raw);
1641                                    true
1642                                } else {
1643                                    false
1644                                }
1645                            } else {
1646                                // dest option
1647                                if self.data.destination_options.is_none() {
1648                                    self.data.destination_options = Some(raw);
1649                                    true
1650                                } else {
1651                                    false
1652                                }
1653                            }
1654                        }
1655                        _ => unreachable!(),
1656                    }
1657                }
1658                IPV6_FRAG => {
1659                    if self.data.fragment.is_none() {
1660                        self.data.fragment = Some(Ipv6FragmentHeader::new(
1661                            next_header,
1662                            IpFragOffset::ZERO,
1663                            true,
1664                            123,
1665                        ));
1666                        true
1667                    } else {
1668                        false
1669                    }
1670                }
1671                AUTH => {
1672                    if self.data.auth.is_none() {
1673                        use IpAuthHeader as A;
1674
1675                        let mut len = usize::from(header_ext_len) * 4;
1676                        if len > A::MAX_ICV_LEN {
1677                            len = A::MAX_ICV_LEN;
1678                        }
1679                        let raw_icv: [u8; A::MAX_ICV_LEN] = [0; A::MAX_ICV_LEN];
1680                        self.data.auth = Some(
1681                            IpAuthHeader::new(next_header, 123, 234, &raw_icv[..len]).unwrap(),
1682                        );
1683                        true
1684                    } else {
1685                        false
1686                    }
1687                }
1688                _ => unreachable!(),
1689            }
1690        }
1691    }
1692}
1693
1694#[cfg(test)]
1695mod test {
1696    use super::ipv6_exts_test_helpers::*;
1697    use super::*;
1698    use crate::ip_number::*;
1699    use crate::test_gens::*;
1700    use alloc::{borrow::ToOwned, vec::Vec};
1701    use proptest::prelude::*;
1702
1703    proptest! {
1704        #[test]
1705        fn from_slice(
1706            header_size in any::<u8>(),
1707            post_header in ip_number_any()
1708                .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
1709                    |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
1710                )
1711        ) {
1712            use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*};
1713
1714            // no extension headers filled
1715            {
1716                let some_data = [1,2,3,4];
1717                let actual = Ipv6Extensions::from_slice(post_header, &some_data).unwrap();
1718                assert_eq!(actual.0, Default::default());
1719                assert_eq!(actual.1, post_header);
1720                assert_eq!(actual.2, &some_data);
1721            }
1722
1723            /// Run a test with the given ip numbers
1724            fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) {
1725                // setup test payload
1726                let e = ExtensionTestPayload::new(
1727                    ip_numbers,
1728                    header_sizes
1729                );
1730
1731                if e.exts_hop_by_hop_error() {
1732                    // a hop by hop header that is not at the start triggers an error
1733                    assert_eq!(
1734                        Ipv6Extensions::from_slice(ip_numbers[0], e.slice()).unwrap_err(),
1735                        Content(HopByHopNotAtStart)
1736                    );
1737                } else {
1738                    // normal read
1739                    let (header, next, rest) = Ipv6Extensions::from_slice(ip_numbers[0], e.slice()).unwrap();
1740                    let (read_len, last_header, expected_post_header) = e.assert_extensions(&header);
1741                    assert_eq!(next, expected_post_header);
1742                    assert_eq!(rest, &e.slice()[read_len..]);
1743
1744                    // unexpected end of slice
1745                    {
1746                        let mut offset: usize = 0;
1747                        for l in &e.lengths {
1748                            if offset + l >= read_len {
1749                                break;
1750                            }
1751                            offset += l;
1752                        }
1753
1754                        assert_eq!(
1755                            Ipv6Extensions::from_slice(ip_numbers[0], &e.slice()[..read_len - 1]).unwrap_err(),
1756                            Len(err::LenError {
1757                                required_len: read_len - offset,
1758                                len: read_len - offset - 1,
1759                                len_source: LenSource::Slice,
1760                                layer: match last_header.unwrap() {
1761                                    AUTH => err::Layer::IpAuthHeader,
1762                                    IPV6_FRAG => err::Layer::Ipv6FragHeader,
1763                                    _ => err::Layer::Ipv6ExtHeader
1764                                },
1765                                layer_start_offset: offset,
1766                            })
1767                        );
1768                    }
1769                }
1770            }
1771
1772            // test the parsing of different extension header combinations
1773            for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
1774
1775                // single header parsing
1776                run_test(
1777                    &[*first_header, post_header],
1778                    &[header_size],
1779                );
1780
1781                for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
1782
1783                    // double header parsing
1784                    run_test(
1785                        &[*first_header, *second_header, post_header],
1786                        &[header_size],
1787                    );
1788
1789                    for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
1790                        // tripple header parsing
1791                        run_test(
1792                            &[*first_header, *second_header, *third_header, post_header],
1793                            &[header_size],
1794                        );
1795                    }
1796                }
1797            }
1798
1799            // test that the auth content error gets forwarded
1800            {
1801                let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap();
1802                let mut bytes = auth.to_bytes();
1803                // inject an invalid len value
1804                bytes[1] = 0;
1805                let actual = Ipv6Extensions::from_slice(AUTH, &bytes).unwrap_err();
1806
1807                use err::ipv6_exts::HeaderError::IpAuth;
1808                use err::ip_auth::HeaderError::ZeroPayloadLen;
1809                assert_eq!(actual, Content(IpAuth(ZeroPayloadLen)));
1810            }
1811        }
1812    }
1813
1814    proptest! {
1815        #[test]
1816        fn from_slice_lax(
1817            header_size in any::<u8>(),
1818            post_header in ip_number_any()
1819                .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
1820                    |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
1821                )
1822        ) {
1823            use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*};
1824
1825            // no extension headers filled
1826            {
1827                let some_data = [1,2,3,4];
1828                let actual = Ipv6Extensions::from_slice_lax(post_header, &some_data);
1829                assert_eq!(actual.0, Default::default());
1830                assert_eq!(actual.1, post_header);
1831                assert_eq!(actual.2, &some_data);
1832                assert!(actual.3.is_none());
1833            }
1834
1835            /// Run a test with the given ip numbers
1836            fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) {
1837                // setup test payload
1838                let e = ExtensionTestPayload::new(
1839                    ip_numbers,
1840                    header_sizes
1841                );
1842
1843                if e.exts_hop_by_hop_error() {
1844                    // a hop by hop header that is not at the start triggers an error
1845                    let actual = Ipv6Extensions::from_slice_lax(ip_numbers[0], e.slice());
1846                    assert_eq!(actual.3.unwrap(), (Content(HopByHopNotAtStart), Layer::Ipv6HopByHopHeader));
1847                } else {
1848                    // normal read
1849                    let norm_actual = Ipv6Extensions::from_slice_lax(ip_numbers[0], e.slice());
1850                    let norm_expected = e.lax_extensions_for_len(e.slice().len());
1851                    assert_eq!(norm_actual.0, norm_expected.0);
1852                    assert_eq!(norm_actual.1, norm_expected.1);
1853                    assert_eq!(norm_actual.2, norm_expected.2);
1854                    assert!(norm_actual.3.is_none());
1855
1856                    // unexpected end of slice
1857                    if norm_actual.0.header_len() > 0 {
1858
1859                        let norm_len = norm_actual.0.header_len();
1860                        let actual = Ipv6Extensions::from_slice_lax(ip_numbers[0], &e.slice()[..norm_len - 1]);
1861
1862                        let expected = e.lax_extensions_for_len(norm_len - 1);
1863                        assert_eq!(actual.0, expected.0);
1864                        assert_eq!(actual.1, expected.1);
1865                        assert_eq!(actual.2, expected.2);
1866                        let len_err = actual.3.unwrap().0.len_error().unwrap().clone();
1867                        assert_eq!(len_err.len, norm_len - 1 - expected.0.header_len());
1868                        assert_eq!(len_err.len_source, LenSource::Slice);
1869                        assert_eq!(
1870                            len_err.layer,
1871                            match expected.3.unwrap() {
1872                                AUTH => err::Layer::IpAuthHeader,
1873                                IPV6_FRAG => err::Layer::Ipv6FragHeader,
1874                                _ => err::Layer::Ipv6ExtHeader
1875                            }
1876                        );
1877                        assert_eq!(len_err.layer_start_offset, expected.0.header_len());
1878                    }
1879                }
1880            }
1881
1882            // test the parsing of different extension header combinations
1883            for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
1884
1885                // single header parsing
1886                run_test(
1887                    &[*first_header, post_header],
1888                    &[header_size],
1889                );
1890
1891                for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
1892
1893                    // double header parsing
1894                    run_test(
1895                        &[*first_header, *second_header, post_header],
1896                        &[header_size],
1897                    );
1898
1899                    for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
1900                        // tripple header parsing
1901                        run_test(
1902                            &[*first_header, *second_header, *third_header, post_header],
1903                            &[header_size],
1904                        );
1905                    }
1906                }
1907            }
1908
1909            // test that the auth content error gets forwarded
1910            {
1911                let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap();
1912                let mut bytes = auth.to_bytes();
1913                // inject an invalid len value
1914                bytes[1] = 0;
1915                let actual = Ipv6Extensions::from_slice_lax(AUTH, &bytes);
1916                assert_eq!(0, actual.0.header_len());
1917                assert_eq!(AUTH, actual.1);
1918                assert_eq!(&bytes[..], actual.2);
1919
1920                use err::ipv6_exts::HeaderError::IpAuth;
1921                use err::ip_auth::HeaderError::ZeroPayloadLen;
1922                assert_eq!(actual.3.unwrap(), (Content(IpAuth(ZeroPayloadLen)), Layer::IpAuthHeader));
1923            }
1924        }
1925    }
1926
1927    proptest! {
1928        #[test]
1929        fn read(
1930            header_size in any::<u8>(),
1931            post_header in ip_number_any()
1932                .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
1933                    |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
1934                )
1935        ) {
1936            use err::ipv6_exts::HeaderError::*;
1937            use std::io::Cursor;
1938
1939            // no extension headers filled
1940            {
1941                let mut cursor = Cursor::new(&[]);
1942                let actual = Ipv6Extensions::read(&mut cursor, post_header).unwrap();
1943                assert_eq!(actual.0, Default::default());
1944                assert_eq!(actual.1, post_header);
1945                assert_eq!(0, cursor.position());
1946            }
1947
1948            /// Run a test with the given ip numbers
1949            fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) {
1950                // setup test payload
1951                let e = ExtensionTestPayload::new(
1952                    ip_numbers,
1953                    header_sizes
1954                );
1955                let mut cursor = Cursor::new(e.slice());
1956
1957                if e.exts_hop_by_hop_error() {
1958                    // a hop by hop header that is not at the start triggers an error
1959                    assert_eq!(
1960                        Ipv6Extensions::read(&mut cursor, ip_numbers[0]).unwrap_err().content_error().unwrap(),
1961                        HopByHopNotAtStart
1962                    );
1963                } else {
1964                    // normal read
1965                    let (header, next) = Ipv6Extensions::read(&mut cursor, ip_numbers[0]).unwrap();
1966                    let (read_len, _, expected_post_header) = e.assert_extensions(&header);
1967                    assert_eq!(next, expected_post_header);
1968                    assert_eq!(cursor.position() as usize, read_len);
1969
1970                    // unexpected end of slice
1971                    {
1972                        let mut short_cursor = Cursor::new(&e.slice()[..read_len - 1]);
1973                        assert!(
1974                            Ipv6Extensions::read(&mut short_cursor, ip_numbers[0])
1975                            .unwrap_err()
1976                            .io_error()
1977                            .is_some()
1978                        );
1979                    }
1980                }
1981            }
1982
1983            // test the parsing of different extension header combinations
1984            for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
1985
1986                // single header parsing
1987                run_test(
1988                    &[*first_header, post_header],
1989                    &[header_size],
1990                );
1991
1992                for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
1993
1994                    // double header parsing
1995                    run_test(
1996                        &[*first_header, *second_header, post_header],
1997                        &[header_size],
1998                    );
1999
2000                    for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
2001                        // tripple header parsing
2002                        run_test(
2003                            &[*first_header, *second_header, *third_header, post_header],
2004                            &[header_size],
2005                        );
2006                    }
2007                }
2008            }
2009
2010            // test that the auth content error gets forwarded
2011            {
2012                let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap();
2013                let mut bytes = auth.to_bytes();
2014                // inject an invalid len value
2015                bytes[1] = 0;
2016                let mut cursor = Cursor::new(&bytes[..]);
2017                let actual = Ipv6Extensions::read(&mut cursor, AUTH).unwrap_err();
2018
2019                use err::ipv6_exts::HeaderError::IpAuth;
2020                use err::ip_auth::HeaderError::ZeroPayloadLen;
2021                assert_eq!(actual.content_error().unwrap(), IpAuth(ZeroPayloadLen));
2022            }
2023        }
2024    }
2025
2026    proptest! {
2027        #[test]
2028        fn read_limited(
2029            header_size in any::<u8>(),
2030            post_header in ip_number_any()
2031                .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
2032                    |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
2033                )
2034        ) {
2035            use err::ipv6_exts::HeaderError::*;
2036            use err::Layer;
2037            use std::io::Cursor;
2038            use crate::io::LimitedReader;
2039
2040            // no extension headers filled
2041            {
2042                let mut reader = LimitedReader::new(
2043                    Cursor::new(&[]),
2044                    0,
2045                    LenSource::Slice,
2046                    0,
2047                    Layer::Ipv6Header
2048                );
2049                let actual = Ipv6Extensions::read_limited(&mut reader, post_header).unwrap();
2050                assert_eq!(actual.0, Default::default());
2051                assert_eq!(actual.1, post_header);
2052                assert_eq!(0, reader.read_len());
2053            }
2054
2055            /// Run a test with the given ip numbers
2056            fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) {
2057                // setup test payload
2058                let e = ExtensionTestPayload::new(
2059                    ip_numbers,
2060                    header_sizes
2061                );
2062                let mut reader = LimitedReader::new(
2063                    Cursor::new(e.slice()),
2064                    e.slice().len(),
2065                    LenSource::Slice,
2066                    0,
2067                    Layer::Ipv6Header
2068                );
2069
2070                if e.exts_hop_by_hop_error() {
2071                    // a hop by hop header that is not at the start triggers an error
2072                    assert_eq!(
2073                        Ipv6Extensions::read_limited(&mut reader, ip_numbers[0]).unwrap_err().content().unwrap(),
2074                        HopByHopNotAtStart
2075                    );
2076                } else {
2077                    // normal read
2078                    let (header, next) = Ipv6Extensions::read_limited(&mut reader, ip_numbers[0]).unwrap();
2079                    let (read_len, _, expected_post_header) = e.assert_extensions(&header);
2080                    assert_eq!(next, expected_post_header);
2081                    assert_eq!(reader.read_len() + reader.layer_offset(), read_len);
2082
2083                    // io error unexpected end
2084                    {
2085                        let mut short_reader = LimitedReader::new(
2086                            Cursor::new(&e.slice()[..read_len - 1]),
2087                            read_len,
2088                            LenSource::Slice,
2089                            0,
2090                            Layer::Ipv6Header
2091                        );
2092
2093                        assert!(
2094                            Ipv6Extensions::read_limited(&mut short_reader, ip_numbers[0])
2095                            .unwrap_err()
2096                            .io()
2097                            .is_some()
2098                        );
2099                    }
2100
2101                    // len error
2102                    {
2103                        let mut short_reader = LimitedReader::new(
2104                            Cursor::new(e.slice()),
2105                            read_len - 1,
2106                            LenSource::Slice,
2107                            0,
2108                            Layer::Ipv6Header
2109                        );
2110
2111                        assert!(
2112                            Ipv6Extensions::read_limited(&mut short_reader, ip_numbers[0])
2113                            .unwrap_err()
2114                            .len()
2115                            .is_some()
2116                        );
2117                    }
2118                }
2119            }
2120
2121            // test the parsing of different extension header combinations
2122            for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
2123
2124                // single header parsing
2125                run_test(
2126                    &[*first_header, post_header],
2127                    &[header_size],
2128                );
2129
2130                for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
2131
2132                    // double header parsing
2133                    run_test(
2134                        &[*first_header, *second_header, post_header],
2135                        &[header_size],
2136                    );
2137
2138                    for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
2139                        // tripple header parsing
2140                        run_test(
2141                            &[*first_header, *second_header, *third_header, post_header],
2142                            &[header_size],
2143                        );
2144                    }
2145                }
2146            }
2147
2148            // test that the auth content error gets forwarded
2149            {
2150                let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap();
2151                let mut bytes = auth.to_bytes();
2152                // inject an invalid len value
2153                bytes[1] = 0;
2154                let mut reader = LimitedReader::new(
2155                    Cursor::new(&bytes[..]),
2156                    bytes.len(),
2157                    LenSource::Slice,
2158                    0,
2159                    Layer::Ipv6Header
2160                );
2161                let actual = Ipv6Extensions::read_limited(&mut reader, AUTH).unwrap_err();
2162
2163                use err::ipv6_exts::HeaderError::IpAuth;
2164                use err::ip_auth::HeaderError::ZeroPayloadLen;
2165                assert_eq!(actual.content().unwrap(), IpAuth(ZeroPayloadLen));
2166            }
2167        }
2168    }
2169
2170    proptest! {
2171        #[test]
2172        fn write(
2173            header_size in any::<u8>(),
2174            post_header in ip_number_any()
2175                .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
2176                    |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
2177                )
2178        ) {
2179            // no extension headers filled
2180            {
2181                let exts : Ipv6Extensions = Default::default();
2182                let mut buffer = Vec::new();
2183                exts.write(&mut buffer, post_header).unwrap();
2184                assert_eq!(0, buffer.len());
2185            }
2186
2187            /// Run a test with the given ip numbers
2188            fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8], post_header: IpNumber) {
2189                use std::io::Cursor;
2190                use crate::err::ipv6_exts::ExtsWalkError::*;
2191
2192                // setup test header
2193                let e = ExtensionTestHeaders::new(
2194                    ip_numbers,
2195                    header_sizes
2196                );
2197
2198                if e.ip_numbers[1..e.ip_numbers.len()-1].iter().any(|&x| x == IPV6_HOP_BY_HOP) {
2199                    // a hop by hop header that is not at the start triggers an error
2200                    let mut writer = Vec::with_capacity(e.data.header_len());
2201                    assert_eq!(
2202                        e.data.write(&mut writer, e.ip_numbers[0]).unwrap_err().content().unwrap(),
2203                        &HopByHopNotAtStart
2204                    );
2205                } else {
2206                    // normal write
2207                    {
2208                        let mut writer = Vec::with_capacity(e.data.header_len());
2209                        e.data.write(&mut writer, e.ip_numbers[0]).unwrap();
2210
2211                        if *e.ip_numbers.last().unwrap() != IPV6_HOP_BY_HOP {
2212                            // decoding if there will be no duplicate hop by hop error
2213                            // will be triggered
2214                            let (read, read_next, _) = Ipv6Extensions::from_slice(
2215                                e.ip_numbers[0],
2216                                &writer
2217                            ).unwrap();
2218                            assert_eq!(e.data, read);
2219                            assert_eq!(*e.ip_numbers.last().unwrap(), read_next);
2220                        }
2221                    }
2222
2223                    // write error
2224                    {
2225                        let mut buffer = Vec::with_capacity(e.data.header_len() - 1);
2226                        buffer.resize(e.data.header_len() - 1, 0);
2227                        let mut cursor = Cursor::new(&mut buffer[..]);
2228
2229                        let err = e.data.write(
2230                            &mut cursor,
2231                            e.ip_numbers[0]
2232                        ).unwrap_err();
2233
2234                        assert!(err.io().is_some());
2235                    }
2236
2237                    // missing reference (skip the last header)
2238                    {
2239                        use crate::err::ipv6_exts::ExtsWalkError::ExtNotReferenced;
2240
2241                        let mut missing_ref = e.clone();
2242                        let missing_ext = missing_ref.introduce_missing_ref(post_header);
2243
2244                        let mut writer = Vec::with_capacity(e.data.header_len());
2245                        let err = missing_ref.data.write(
2246                            &mut writer,
2247                            missing_ref.ip_numbers[0]
2248                        ).unwrap_err();
2249
2250                        assert_eq!(
2251                            err.content().unwrap(),
2252                            &ExtNotReferenced{ missing_ext }
2253                        );
2254                    }
2255                }
2256            }
2257
2258            // test the parsing of different extension header combinations
2259            for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
2260
2261                // single header parsing
2262                run_test(
2263                    &[*first_header, post_header],
2264                    &[header_size],
2265                    post_header,
2266                );
2267
2268                for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
2269
2270                    // double header parsing
2271                    run_test(
2272                        &[*first_header, *second_header, post_header],
2273                        &[header_size],
2274                        post_header,
2275                    );
2276
2277                    for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
2278                        // tripple header parsing
2279                        run_test(
2280                            &[*first_header, *second_header, *third_header, post_header],
2281                            &[header_size],
2282                            post_header,
2283                        );
2284                    }
2285                }
2286            }
2287        }
2288    }
2289
2290    proptest! {
2291        #[test]
2292        fn header_len(
2293            hop_by_hop_options in ipv6_raw_ext_any(),
2294            destination_options in ipv6_raw_ext_any(),
2295            routing in ipv6_raw_ext_any(),
2296            fragment in ipv6_fragment_any(),
2297            auth in ip_auth_any(),
2298            final_destination_options in ipv6_raw_ext_any(),
2299        ) {
2300            // None
2301            {
2302                let exts : Ipv6Extensions = Default::default();
2303                assert_eq!(0, exts.header_len());
2304            }
2305
2306            // All filled
2307            {
2308                let exts = Ipv6Extensions{
2309                    hop_by_hop_options: Some(hop_by_hop_options.clone()),
2310                    destination_options: Some(destination_options.clone()),
2311                    routing: Some(
2312                        Ipv6RoutingExtensions{
2313                            routing: routing.clone(),
2314                            final_destination_options: Some(final_destination_options.clone()),
2315                        }
2316                    ),
2317                    fragment: Some(fragment.clone()),
2318                    auth: Some(auth.clone()),
2319                };
2320                assert_eq!(
2321                    exts.header_len(),
2322                    (
2323                        hop_by_hop_options.header_len() +
2324                        destination_options.header_len() +
2325                        routing.header_len() +
2326                        final_destination_options.header_len() +
2327                        fragment.header_len() +
2328                        auth.header_len()
2329                    )
2330                );
2331            }
2332
2333            // Routing without final destination options
2334            {
2335                let exts = Ipv6Extensions{
2336                    hop_by_hop_options: Some(hop_by_hop_options.clone()),
2337                    destination_options: Some(destination_options.clone()),
2338                    routing: Some(
2339                        Ipv6RoutingExtensions{
2340                            routing: routing.clone(),
2341                            final_destination_options: None,
2342                        }
2343                    ),
2344                    fragment: Some(fragment.clone()),
2345                    auth: Some(auth.clone()),
2346                };
2347                assert_eq!(
2348                    exts.header_len(),
2349                    (
2350                        hop_by_hop_options.header_len() +
2351                        destination_options.header_len() +
2352                        routing.header_len() +
2353                        fragment.header_len() +
2354                        auth.header_len()
2355                    )
2356                );
2357            }
2358        }
2359    }
2360
2361    proptest! {
2362        #[test]
2363        fn set_next_headers(
2364            hop_by_hop_options in ipv6_raw_ext_any(),
2365            destination_options in ipv6_raw_ext_any(),
2366            routing in ipv6_raw_ext_any(),
2367            fragment in ipv6_fragment_any(),
2368            auth in ip_auth_any(),
2369            final_destination_options in ipv6_raw_ext_any(),
2370            post_header in ip_number_any()
2371                .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
2372                    |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
2373                ),
2374        ) {
2375            // none filled
2376            {
2377                let mut exts : Ipv6Extensions = Default::default();
2378                assert_eq!(post_header, exts.set_next_headers(post_header));
2379                assert!(exts.hop_by_hop_options.is_none());
2380                assert!(exts.destination_options.is_none());
2381                assert!(exts.routing.is_none());
2382                assert!(exts.fragment.is_none());
2383                assert!(exts.auth.is_none());
2384            }
2385
2386            // all filled
2387            {
2388                let mut exts = Ipv6Extensions{
2389                    hop_by_hop_options: Some(hop_by_hop_options.clone()),
2390                    destination_options: Some(destination_options.clone()),
2391                    routing: Some(
2392                        Ipv6RoutingExtensions{
2393                            routing: routing.clone(),
2394                            final_destination_options: Some(final_destination_options.clone()),
2395                        }
2396                    ),
2397                    fragment: Some(fragment.clone()),
2398                    auth: Some(auth.clone()),
2399                };
2400                assert_eq!(IPV6_HOP_BY_HOP, exts.set_next_headers(post_header));
2401
2402                assert_eq!(IPV6_DEST_OPTIONS, exts.hop_by_hop_options.as_ref().unwrap().next_header);
2403                assert_eq!(IPV6_ROUTE, exts.destination_options.as_ref().unwrap().next_header);
2404                assert_eq!(IPV6_FRAG, exts.routing.as_ref().unwrap().routing.next_header);
2405                assert_eq!(AUTH, exts.fragment.as_ref().unwrap().next_header);
2406                assert_eq!(IPV6_DEST_OPTIONS, exts.auth.as_ref().unwrap().next_header);
2407                assert_eq!(post_header, exts.routing.as_ref().unwrap().final_destination_options.as_ref().unwrap().next_header);
2408            }
2409        }
2410    }
2411
2412    proptest! {
2413        #[test]
2414        fn next_header(
2415            header_size in any::<u8>(),
2416            post_header in ip_number_any()
2417                .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
2418                    |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
2419                ),)
2420        {
2421            // test empty
2422            {
2423                let exts : Ipv6Extensions = Default::default();
2424                assert_eq!(post_header, exts.next_header(post_header).unwrap());
2425            }
2426
2427            /// Run a test with the given ip numbers
2428            fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8], post_header: IpNumber) {
2429                // setup test header
2430                let e = ExtensionTestHeaders::new(
2431                    ip_numbers,
2432                    header_sizes
2433                );
2434
2435                if e.ip_numbers[1..e.ip_numbers.len()-1].iter().any(|&x| x == IPV6_HOP_BY_HOP) {
2436                    // a hop by hop header that is not at the start triggers an error
2437                    use crate::err::ipv6_exts::ExtsWalkError::HopByHopNotAtStart;
2438                    assert_eq!(
2439                        e.data.next_header(e.ip_numbers[0]).unwrap_err(),
2440                        HopByHopNotAtStart
2441                    );
2442                } else {
2443                    // normal header
2444                    assert_eq!(
2445                        *e.ip_numbers.last().unwrap(),
2446                        e.data.next_header(e.ip_numbers[0]).unwrap()
2447                    );
2448
2449                    // missing reference (skip the last header)
2450                    {
2451                        use crate::err::ipv6_exts::ExtsWalkError::ExtNotReferenced;
2452
2453                        let mut missing_ref = e.clone();
2454                        let missing_ext = missing_ref.introduce_missing_ref(post_header);
2455                        assert_eq!(
2456                            missing_ref.data.next_header(missing_ref.ip_numbers[0]).unwrap_err(),
2457                            ExtNotReferenced{ missing_ext }
2458                        );
2459                    }
2460                }
2461            }
2462
2463            // test the parsing of different extension header combinations
2464            for first_header in &EXTENSION_KNOWN_IP_NUMBERS {
2465
2466                // single header parsing
2467                run_test(
2468                    &[*first_header, post_header],
2469                    &[header_size],
2470                    post_header,
2471                );
2472
2473                for second_header in &EXTENSION_KNOWN_IP_NUMBERS {
2474
2475                    // double header parsing
2476                    run_test(
2477                        &[*first_header, *second_header, post_header],
2478                        &[header_size],
2479                        post_header,
2480                    );
2481
2482                    for third_header in &EXTENSION_KNOWN_IP_NUMBERS {
2483                        // tripple header parsing
2484                        run_test(
2485                            &[*first_header, *second_header, *third_header, post_header],
2486                            &[header_size],
2487                            post_header,
2488                        );
2489                    }
2490                }
2491            }
2492        }
2493    }
2494
2495    #[test]
2496    fn is_fragmenting_payload() {
2497        // empty
2498        assert_eq!(
2499            false,
2500            Ipv6Extensions {
2501                hop_by_hop_options: None,
2502                destination_options: None,
2503                routing: None,
2504                fragment: None,
2505                auth: None,
2506            }
2507            .is_fragmenting_payload()
2508        );
2509
2510        // non fragmenting frag header
2511        assert_eq!(
2512            false,
2513            Ipv6Extensions {
2514                hop_by_hop_options: None,
2515                destination_options: None,
2516                routing: None,
2517                fragment: Some(Ipv6FragmentHeader::new(
2518                    ip_number::UDP,
2519                    IpFragOffset::ZERO,
2520                    false,
2521                    0
2522                )),
2523                auth: None,
2524            }
2525            .is_fragmenting_payload()
2526        );
2527
2528        // fragmenting frag header
2529        assert!(Ipv6Extensions {
2530            hop_by_hop_options: None,
2531            destination_options: None,
2532            routing: None,
2533            fragment: Some(Ipv6FragmentHeader::new(
2534                ip_number::UDP,
2535                IpFragOffset::ZERO,
2536                true,
2537                0
2538            )),
2539            auth: None,
2540        }
2541        .is_fragmenting_payload());
2542    }
2543
2544    #[test]
2545    fn is_empty() {
2546        // empty
2547        assert!(Ipv6Extensions {
2548            hop_by_hop_options: None,
2549            destination_options: None,
2550            routing: None,
2551            fragment: None,
2552            auth: None,
2553        }
2554        .is_empty());
2555
2556        // hop_by_hop_options
2557        assert_eq!(
2558            false,
2559            Ipv6Extensions {
2560                hop_by_hop_options: Some(
2561                    Ipv6RawExtHeader::new_raw(ip_number::UDP, &[1, 2, 3, 4, 5, 6]).unwrap()
2562                ),
2563                destination_options: None,
2564                routing: None,
2565                fragment: None,
2566                auth: None,
2567            }
2568            .is_empty()
2569        );
2570
2571        // destination_options
2572        assert_eq!(
2573            false,
2574            Ipv6Extensions {
2575                hop_by_hop_options: None,
2576                destination_options: Some(
2577                    Ipv6RawExtHeader::new_raw(ip_number::UDP, &[1, 2, 3, 4, 5, 6]).unwrap()
2578                ),
2579                routing: None,
2580                fragment: None,
2581                auth: None,
2582            }
2583            .is_empty()
2584        );
2585
2586        // routing
2587        assert_eq!(
2588            false,
2589            Ipv6Extensions {
2590                hop_by_hop_options: None,
2591                destination_options: None,
2592                routing: Some(Ipv6RoutingExtensions {
2593                    routing: Ipv6RawExtHeader::new_raw(ip_number::UDP, &[1, 2, 3, 4, 5, 6])
2594                        .unwrap(),
2595                    final_destination_options: None,
2596                }),
2597                fragment: None,
2598                auth: None,
2599            }
2600            .is_empty()
2601        );
2602
2603        // fragment
2604        assert_eq!(
2605            false,
2606            Ipv6Extensions {
2607                hop_by_hop_options: None,
2608                destination_options: None,
2609                routing: None,
2610                fragment: Some(Ipv6FragmentHeader::new(
2611                    ip_number::UDP,
2612                    IpFragOffset::ZERO,
2613                    true,
2614                    0
2615                )),
2616                auth: None,
2617            }
2618            .is_empty()
2619        );
2620
2621        // auth
2622        assert_eq!(
2623            false,
2624            Ipv6Extensions {
2625                hop_by_hop_options: None,
2626                destination_options: None,
2627                routing: None,
2628                fragment: None,
2629                auth: Some(IpAuthHeader::new(ip_number::UDP, 0, 0, &[]).unwrap()),
2630            }
2631            .is_empty()
2632        );
2633    }
2634
2635    #[test]
2636    fn debug() {
2637        use alloc::format;
2638
2639        let a: Ipv6Extensions = Default::default();
2640        assert_eq!(
2641            &format!(
2642                "Ipv6Extensions {{ hop_by_hop_options: {:?}, destination_options: {:?}, routing: {:?}, fragment: {:?}, auth: {:?} }}",
2643                a.hop_by_hop_options,
2644                a.destination_options,
2645                a.routing,
2646                a.fragment,
2647                a.auth,
2648            ),
2649            &format!("{:?}", a)
2650        );
2651    }
2652
2653    #[test]
2654    fn clone_eq() {
2655        let a: Ipv6Extensions = Default::default();
2656        assert_eq!(a, a.clone());
2657    }
2658
2659    #[test]
2660    fn default() {
2661        let a: Ipv6Extensions = Default::default();
2662        assert_eq!(a.hop_by_hop_options, None);
2663        assert_eq!(a.destination_options, None);
2664        assert_eq!(a.routing, None);
2665        assert_eq!(a.fragment, None);
2666        assert_eq!(a.auth, None);
2667    }
2668}