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