Thanks to visit codestin.com
Credit goes to docs.rs

etherparse/net/
ipv6_header.rs

1use crate::{err::ValueTooBigError, *};
2
3/// IPv6 header according to rfc8200.
4#[derive(Clone, Debug, Eq, PartialEq, Default)]
5pub struct Ipv6Header {
6    pub traffic_class: u8,
7    /// If non 0 serves as a hint to router and switches with multiple outbound paths that these packets should stay on the same path, so that they will not be reordered.
8    pub flow_label: Ipv6FlowLabel,
9    ///The length of the payload and extension headers in bytes (0 in case of jumbo payloads).
10    pub payload_length: u16,
11    /// IP protocol number specifying the next header or transport layer protocol.
12    ///
13    /// See [IpNumber] or [ip_number] for a definitions of ids.
14    pub next_header: IpNumber,
15    /// The number of hops the packet can take before it is discarded.
16    pub hop_limit: u8,
17    /// IPv6 source address
18    pub source: [u8; 16],
19    /// IPv6 destination address
20    pub destination: [u8; 16],
21}
22
23impl Ipv6Header {
24    /// Serialized size of an IPv6 header in bytes/octets.
25    pub const LEN: usize = 40;
26
27    #[deprecated(since = "0.14.0", note = "Use `Ipv6Header::LEN` instead")]
28    pub const SERIALIZED_SIZE: usize = Ipv6Header::LEN;
29
30    /// Renamed to `Ipv6Header::from_slice`
31    #[deprecated(since = "0.10.1", note = "Renamed to `Ipv6Header::from_slice`")]
32    #[inline]
33    pub fn read_from_slice(
34        slice: &[u8],
35    ) -> Result<(Ipv6Header, &[u8]), err::ipv6::HeaderSliceError> {
36        Ipv6Header::from_slice(slice)
37    }
38
39    /// Read an Ipv6Header from a slice and return the header & unused parts of the slice.
40    ///
41    /// Note that this function DOES NOT separate the payload based on the length
42    /// payload_length present in the IPv6 header. It just returns the left over slice
43    /// after the header.
44    ///
45    /// If you want to have correctly separated payload including the IP extension
46    /// headers use
47    ///
48    /// * [`crate::IpHeaders::from_ipv6_slice`] (decodes all the fields of the IP headers)
49    /// * [`crate::Ipv6Slice::from_slice`] (just identifies the ranges in the slice where
50    ///   the headers and payload are present)
51    ///
52    /// or
53    ///
54    /// * [`crate::IpHeaders::from_ipv6_slice_lax`]
55    /// * [`crate::Ipv6Slice::from_slice_lax`]
56    ///
57    /// for a laxer version which falls back to slice length when the `payload_length`
58    /// contains an inconsistent value.
59    #[inline]
60    pub fn from_slice(slice: &[u8]) -> Result<(Ipv6Header, &[u8]), err::ipv6::HeaderSliceError> {
61        Ok((
62            Ipv6HeaderSlice::from_slice(slice)?.to_header(),
63            &slice[Ipv6Header::LEN..],
64        ))
65    }
66
67    ///Reads an IPv6 header from the current position.
68    #[cfg(feature = "std")]
69    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
70    pub fn read<T: std::io::Read + std::io::Seek + Sized>(
71        reader: &mut T,
72    ) -> Result<Ipv6Header, err::ipv6::HeaderReadError> {
73        use err::ipv6::{HeaderError::*, HeaderReadError::*};
74
75        let mut value: [u8; 1] = [0; 1];
76        reader.read_exact(&mut value).map_err(Io)?;
77        let version_number = value[0] >> 4;
78        if 6 != version_number {
79            return Err(Content(UnexpectedVersion { version_number }));
80        }
81        Ipv6Header::read_without_version(reader, value[0] & 0xf).map_err(Io)
82    }
83
84    ///Reads an IPv6 header assuming the version & flow_label field have already been read.
85    #[cfg(feature = "std")]
86    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
87    pub fn read_without_version<T: std::io::Read + std::io::Seek + Sized>(
88        reader: &mut T,
89        version_rest: u8,
90    ) -> Result<Ipv6Header, std::io::Error> {
91        let mut buffer: [u8; 8 + 32 - 1] = [0; 8 + 32 - 1];
92        reader.read_exact(&mut buffer[..])?;
93
94        Ok(Ipv6Header {
95            traffic_class: (version_rest << 4) | (buffer[0] >> 4),
96            flow_label: unsafe {
97                // SAFETY: Safe as the bitmask & 0 contant guarantee that the value
98                // does not exceed 20 bytes.
99                Ipv6FlowLabel::new_unchecked(u32::from_be_bytes([
100                    0,
101                    buffer[0] & 0b0000_1111,
102                    buffer[1],
103                    buffer[2],
104                ]))
105            },
106            payload_length: u16::from_be_bytes([buffer[3], buffer[4]]),
107            next_header: IpNumber(buffer[5]),
108            hop_limit: buffer[6],
109            #[rustfmt::skip]
110            source: [
111                buffer[7],   buffer[8],  buffer[9], buffer[10],
112                buffer[11], buffer[12], buffer[13], buffer[14],
113                buffer[15], buffer[16], buffer[17], buffer[18],
114                buffer[19], buffer[20], buffer[21], buffer[22],
115            ],
116            #[rustfmt::skip]
117            destination: [
118                buffer[23], buffer[24], buffer[25], buffer[26],
119                buffer[27], buffer[28], buffer[29], buffer[30],
120                buffer[31], buffer[32], buffer[33], buffer[34],
121                buffer[35], buffer[36], buffer[37], buffer[38],
122            ],
123        })
124    }
125
126    ///Takes a slice and skips an ipv6 header extensions and returns the next_header ip number & the slice past the header.
127    pub fn skip_header_extension_in_slice(
128        slice: &[u8],
129        next_header: IpNumber,
130    ) -> Result<(IpNumber, &[u8]), err::LenError> {
131        use crate::ip_number::*;
132
133        // verify that a ipv6 extension is present (before
134        // validating the slice length)
135        match next_header {
136            IPV6_FRAG | AUTH | IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS | MOBILITY
137            | HIP | SHIM6 => {}
138            _ => {
139                return Ok((next_header, slice));
140            }
141        }
142
143        if slice.len() >= 2 {
144            //determine the length
145            let len = match next_header {
146                IPV6_FRAG => 8,
147                AUTH => (usize::from(slice[1]) + 2) * 4,
148                IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS | MOBILITY | HIP | SHIM6 => {
149                    (usize::from(slice[1]) + 1) * 8
150                }
151                // not a ipv6 header extension that can be skipped
152                _ => unreachable!(),
153            };
154
155            if slice.len() < len {
156                Err(err::LenError {
157                    required_len: len,
158                    len: slice.len(),
159                    len_source: LenSource::Slice,
160                    layer: err::Layer::Ipv6ExtHeader,
161                    layer_start_offset: 0,
162                })
163            } else {
164                Ok((IpNumber(slice[0]), &slice[len..]))
165            }
166        } else {
167            Err(err::LenError {
168                required_len: 2,
169                len: slice.len(),
170                len_source: LenSource::Slice,
171                layer: err::Layer::Ipv6ExtHeader,
172                layer_start_offset: 0,
173            })
174        }
175    }
176
177    /// Returns true if the given ip protocol number is a skippable header extension.
178    ///
179    /// A skippable header extension is an extension header for which it is known how
180    /// to determine the protocol number of the following header as well as how many
181    /// octets have to be skipped to reach the start of the following header.
182    pub fn is_skippable_header_extension(ip_protocol_number: IpNumber) -> bool {
183        use crate::ip_number::*;
184        //Note: EncapsulatingSecurityPayload & ExperimentalAndTesting0 can not be skipped
185        matches!(
186            ip_protocol_number,
187            IPV6_HOP_BY_HOP
188                | IPV6_ROUTE
189                | IPV6_FRAG
190                | AUTH
191                | IPV6_DEST_OPTIONS
192                | MOBILITY
193                | HIP
194                | SHIM6
195        )
196    }
197
198    ///Takes a slice & ip protocol number (identifying the first header type) and returns next_header id & the slice past after all ipv6 header extensions.
199    pub fn skip_all_header_extensions_in_slice(
200        slice: &[u8],
201        next_header: IpNumber,
202    ) -> Result<(IpNumber, &[u8]), err::LenError> {
203        let mut next_header = next_header;
204        let mut rest = slice;
205        let mut offset = 0;
206
207        loop {
208            let (n_id, n_rest) = Ipv6Header::skip_header_extension_in_slice(rest, next_header)
209                .map_err(|err| err.add_offset(offset))?;
210            offset = slice.len() - n_rest.len();
211
212            if n_rest.len() == rest.len() {
213                return Ok((next_header, rest));
214            } else {
215                next_header = n_id;
216                rest = n_rest;
217            }
218        }
219    }
220
221    ///Skips the ipv6 header extension and returns the next ip protocol number
222    #[cfg(feature = "std")]
223    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
224    pub fn skip_header_extension<T: std::io::Read + std::io::Seek + Sized>(
225        reader: &mut T,
226        next_header: IpNumber,
227    ) -> Result<IpNumber, std::io::Error> {
228        use crate::ip_number::*;
229
230        let (next_header, rest_length) = match next_header {
231            IPV6_FRAG => {
232                let mut buf = [0; 1];
233                reader.read_exact(&mut buf)?;
234                (IpNumber(buf[0]), 7)
235            }
236            AUTH => {
237                let mut buf = [0; 2];
238                reader.read_exact(&mut buf)?;
239                (IpNumber(buf[0]), i64::from(buf[1]) * 4 + 6)
240            }
241            IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS | MOBILITY | HIP | SHIM6 => {
242                let mut buf = [0; 2];
243                reader.read_exact(&mut buf)?;
244                (IpNumber(buf[0]), i64::from(buf[1]) * 8 + 6)
245            }
246            // not a ipv6 header extension that can be skipped
247            _ => return Ok(next_header),
248        };
249
250        //Sadly seek does not return an error if the seek could not be fulfilled.
251        //Some implementations do not even truncate the returned position to the
252        //last valid one. std::io::Cursor for example just moves the position
253        //over the border of the given slice (e.g. returns position 15 even when
254        //the given slice contains only 1 element).
255        //The only option, to detect that we are in an invalid state, is to move the
256        //seek offset to one byte before the end and then execute a normal read to
257        //trigger an error.
258        reader.seek(std::io::SeekFrom::Current(rest_length - 1))?;
259        {
260            let mut buf = [0; 1];
261            reader.read_exact(&mut buf)?;
262        }
263        Ok(next_header)
264    }
265
266    ///Skips all ipv6 header extensions and returns the next ip protocol number
267    #[cfg(feature = "std")]
268    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
269    pub fn skip_all_header_extensions<T: std::io::Read + std::io::Seek + Sized>(
270        reader: &mut T,
271        next_header: IpNumber,
272    ) -> Result<IpNumber, std::io::Error> {
273        let mut next_header = next_header;
274
275        loop {
276            if Ipv6Header::is_skippable_header_extension(next_header) {
277                next_header = Ipv6Header::skip_header_extension(reader, next_header)?;
278            } else {
279                return Ok(next_header);
280            }
281        }
282    }
283
284    ///Writes a given IPv6 header to the current position.
285    #[cfg(feature = "std")]
286    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
287    pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> {
288        writer.write_all(&self.to_bytes())
289    }
290
291    /// Return the ipv6 source address as an core::net::Ipv6Addr
292    #[inline]
293    pub fn source_addr(&self) -> core::net::Ipv6Addr {
294        core::net::Ipv6Addr::from(self.source)
295    }
296
297    /// Return the ipv6 destination address as an core::net::Ipv6Addr
298    #[inline]
299    pub fn destination_addr(&self) -> core::net::Ipv6Addr {
300        core::net::Ipv6Addr::from(self.destination)
301    }
302
303    /// Length of the serialized header in bytes.
304    ///
305    /// The function always returns the constant Ipv6Header::LEN
306    /// and exists to keep the methods consistent with other headers.
307    #[inline]
308    pub fn header_len(&self) -> usize {
309        Ipv6Header::LEN
310    }
311
312    /// Sets the field total_length based on the size of the payload and the options. Returns an error if the payload is too big to fit.
313    pub fn set_payload_length(&mut self, size: usize) -> Result<(), ValueTooBigError<usize>> {
314        use crate::err::ValueType;
315        // check that the total length fits into the field
316        const MAX_PAYLOAD_LENGTH: usize = u16::MAX as usize;
317        if MAX_PAYLOAD_LENGTH < size {
318            return Err(ValueTooBigError {
319                actual: size,
320                max_allowed: MAX_PAYLOAD_LENGTH,
321                value_type: ValueType::Ipv6PayloadLength,
322            });
323        }
324
325        self.payload_length = size as u16;
326        Ok(())
327    }
328
329    /// Sets the ECN field in the `traffic_class` octet.
330    pub fn set_ecn(&mut self, ecn: IpEcn) {
331        self.traffic_class = (self.traffic_class & 0b1111_1100) | (ecn.value() & 0b11);
332    }
333
334    /// Returns the [`IpEcn`] decoded from the `traffic_class` octet.
335    pub fn ecn(&self) -> IpEcn {
336        // SAFETY: Safe as value can only be at most 0b11 as it is bit-and-ed with 0b11.
337        unsafe { IpEcn::new_unchecked(self.traffic_class & 0b0000_0011) }
338    }
339
340    /// Set the DSCP field in the `traffic_class` octet.
341    pub fn set_dscp(&mut self, dscp: IpDscp) {
342        self.traffic_class =
343            (self.traffic_class & 0b0000_0011) | ((dscp.value() << 2) & 0b1111_1100);
344    }
345
346    /// Returns the [`IpDscp`] decoded from the `traffic_class` octet.
347    pub fn dscp(&self) -> IpDscp {
348        // SAFETY: Safe as value can not be bigger than IpDscp::MAX_U8 as it
349        //         is bit masked with IpDscp::MAX_U8 (0b0011_1111).
350        unsafe { IpDscp::new_unchecked((self.traffic_class >> 2) & 0b0011_1111) }
351    }
352
353    /// Returns the serialized form of the header as a statically
354    /// sized byte array.
355    #[rustfmt::skip]
356    pub fn to_bytes(&self) -> [u8;Ipv6Header::LEN] {
357        // serialize header
358        let flow_label_be = self.flow_label.value().to_be_bytes();
359        let payload_len_be = self.payload_length.to_be_bytes();
360
361        [
362            (6 << 4) | (self.traffic_class >> 4),
363            (self.traffic_class << 4) | flow_label_be[1],
364            flow_label_be[2],
365            flow_label_be[3],
366            payload_len_be[0],
367            payload_len_be[1],
368            self.next_header.0,
369            self.hop_limit,
370            self.source[0], self.source[1], self.source[2], self.source[3],
371            self.source[4], self.source[5], self.source[6], self.source[7],
372            self.source[8], self.source[9], self.source[10], self.source[11],
373            self.source[12], self.source[13], self.source[14], self.source[15],
374            self.destination[0], self.destination[1], self.destination[2], self.destination[3],
375            self.destination[4], self.destination[5], self.destination[6], self.destination[7],
376            self.destination[8], self.destination[9], self.destination[10], self.destination[11],
377            self.destination[12], self.destination[13], self.destination[14], self.destination[15],
378        ]
379    }
380}
381
382#[cfg(test)]
383mod test {
384    use crate::{
385        err::ipv6::HeaderError::*, err::ipv6::HeaderSliceError::*, ip_number::*, test_gens::*, *,
386    };
387    use alloc::format;
388    use arrayvec::ArrayVec;
389    use proptest::*;
390    use std::io::Cursor;
391
392    #[test]
393    fn default() {
394        let header: Ipv6Header = Default::default();
395        assert_eq!(0, header.traffic_class);
396        assert_eq!(0, header.flow_label.value());
397        assert_eq!(0, header.payload_length);
398        assert_eq!(255, header.next_header.0);
399        assert_eq!(0, header.hop_limit);
400        assert_eq!([0u8; 16], header.source);
401        assert_eq!([0u8; 16], header.destination);
402    }
403
404    #[test]
405    fn debug() {
406        let header: Ipv6Header = Default::default();
407        assert_eq!(
408            format!("{:?}", header),
409            format!(
410                "Ipv6Header {{ traffic_class: {}, flow_label: {:?}, payload_length: {}, next_header: {:?}, hop_limit: {}, source: {:?}, destination: {:?} }}",
411                header.traffic_class,
412                header.flow_label,
413                header.payload_length,
414                header.next_header,
415                header.hop_limit,
416                header.source,
417                header.destination
418            )
419        );
420    }
421
422    proptest! {
423        #[test]
424        fn clone_eq(header in ipv6_any()) {
425            assert_eq!(header.clone(), header);
426        }
427    }
428
429    proptest! {
430        #[test]
431        #[allow(deprecated)]
432        fn read_from_slice(
433            header in ipv6_any(),
434            bad_version in 0..=0b1111u8
435        ) {
436            // ok read
437            {
438                let bytes = header.to_bytes();
439                let (actual, rest) = Ipv6Header::read_from_slice(&bytes).unwrap();
440                assert_eq!(header, actual);
441                assert_eq!(rest, &[]);
442            }
443
444            // version error
445            if bad_version != 6 {
446                let mut bytes = header.to_bytes();
447                // inject a bad version number
448                bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4);
449
450                assert_eq!(
451                    Ipv6Header::read_from_slice(&bytes).unwrap_err(),
452                    Content(UnexpectedVersion{ version_number: bad_version })
453                );
454            }
455
456            // length error
457            {
458                let bytes = header.to_bytes();
459                for len in 0..bytes.len() {
460                    assert_eq!(
461                        Ipv6Header::read_from_slice(&bytes[..len])
462                            .unwrap_err(),
463                        Len(err::LenError{
464                            required_len: Ipv6Header::LEN,
465                            len: len,
466                            len_source: LenSource::Slice,
467                            layer: err::Layer::Ipv6Header,
468                            layer_start_offset: 0,
469                        })
470                    );
471                }
472            }
473        }
474    }
475
476    proptest! {
477        #[test]
478        fn set_dscp(
479            header in ipv6_any(),
480            dscp in ip_dscp_any()
481        ) {
482            let mut header = header;
483            assert_eq!(header.dscp(), IpDscp::try_new(header.traffic_class >> 2).unwrap());
484            header.set_dscp(dscp);
485            assert_eq!(dscp, IpDscp::try_new(header.traffic_class >> 2).unwrap());
486            assert_eq!(header.dscp(), dscp);
487        }
488    }
489
490    proptest! {
491        #[test]
492        fn set_ecn(
493            header in ipv6_any(),
494            ecn in ip_ecn_any()
495        ) {
496            let mut header = header;
497            assert_eq!(header.ecn(), IpEcn::try_new(header.traffic_class & 0b11).unwrap());
498            header.set_ecn(ecn);
499            assert_eq!(ecn, IpEcn::try_new(header.traffic_class & 0b11).unwrap());
500            assert_eq!(header.ecn(), ecn);
501        }
502    }
503
504    proptest! {
505        #[test]
506        fn from_slice(
507            header in ipv6_any(),
508            bad_version in 0..=0b1111u8
509        ) {
510            // ok read
511            {
512                let bytes = header.to_bytes();
513                let (actual, rest) = Ipv6Header::from_slice(&bytes).unwrap();
514                assert_eq!(header, actual);
515                assert_eq!(rest, &[]);
516            }
517
518            // version error
519            if bad_version != 6 {
520                let mut bytes = header.to_bytes();
521                // inject a bad version number
522                bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4);
523
524                assert_eq!(
525                    Ipv6Header::from_slice(&bytes).unwrap_err(),
526                    Content(UnexpectedVersion{ version_number: bad_version })
527                );
528            }
529
530            // length error
531            {
532                let bytes = header.to_bytes();
533                for len in 0..bytes.len() {
534                    assert_eq!(
535                        Ipv6Header::from_slice(&bytes[..len])
536                            .unwrap_err(),
537                        Len(err::LenError{
538                            required_len: Ipv6Header::LEN,
539                            len: len,
540                            len_source: LenSource::Slice,
541                            layer: err::Layer::Ipv6Header,
542                            layer_start_offset: 0,
543                        })
544                    );
545                }
546            }
547        }
548    }
549
550    proptest! {
551        #[test]
552        fn read(
553            header in ipv6_any(),
554            bad_version in 0..=0b1111u8
555        ) {
556            use err::ipv6::HeaderError::*;
557
558            // ok read
559            {
560                let bytes = header.to_bytes();
561                let mut cursor = Cursor::new(&bytes[..]);
562                let actual = Ipv6Header::read(&mut cursor).unwrap();
563                assert_eq!(header, actual);
564                assert_eq!(cursor.position(), bytes.len() as u64);
565            }
566
567            // version error
568            if bad_version != 6 {
569                let mut bytes = header.to_bytes();
570                // inject a bad version number
571                bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4);
572
573                let mut cursor = Cursor::new(&bytes[..]);
574                assert_eq!(
575                    Ipv6Header::read(&mut cursor)
576                        .unwrap_err()
577                        .content_error()
578                        .unwrap(),
579                    UnexpectedVersion {
580                        version_number: bad_version,
581                    }
582                );
583            }
584
585            // io error
586            {
587                let bytes = header.to_bytes();
588                for len in 0..bytes.len() {
589                    let mut cursor = Cursor::new(&bytes[..len]);
590                    assert!(Ipv6Header::read(&mut cursor).is_err());
591                }
592            }
593        }
594    }
595
596    proptest! {
597        #[test]
598        fn read_without_version(header in ipv6_any()) {
599            // ok read
600            {
601                let bytes = header.to_bytes();
602                let mut cursor = Cursor::new(&bytes[1..]);
603                let actual = Ipv6Header::read_without_version(&mut cursor, bytes[0] & 0xf).unwrap();
604                assert_eq!(header, actual);
605                assert_eq!(cursor.position(), bytes.len() as u64 - 1);
606            }
607
608            // io error
609            {
610                let bytes = header.to_bytes();
611                for len in 1..bytes.len() {
612                    let mut cursor = Cursor::new(&bytes[1..len]);
613                    assert!(Ipv6Header::read_without_version(&mut cursor, bytes[0] & 0xf).is_err());
614                }
615            }
616        }
617    }
618
619    proptest! {
620        #[test]
621        fn skip_header_extension_in_slice(
622            generic in ipv6_raw_ext_any(),
623            frag in ipv6_fragment_any(),
624            auth in ip_auth_any()
625        ) {
626            const GENERICS: [IpNumber;7] = [
627                IPV6_HOP_BY_HOP,
628                IPV6_DEST_OPTIONS,
629                IPV6_ROUTE,
630                IPV6_DEST_OPTIONS,
631                MOBILITY,
632                HIP,
633                SHIM6,
634            ];
635
636            // generic headers
637            for g in GENERICS {
638                let bytes = generic.to_bytes();
639                // ok case
640                {
641                    let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, g).unwrap();
642                    assert_eq!(next, generic.next_header);
643                    assert_eq!(rest, &[]);
644                }
645                // length error
646                for len in 0..bytes.len() {
647                    assert_eq!(
648                        Ipv6Header::skip_header_extension_in_slice(&bytes[..len], g).unwrap_err(),
649                        err::LenError {
650                            required_len: if len < 2 {
651                                2
652                            } else {
653                                bytes.len()
654                            },
655                            len: len,
656                            len_source: LenSource::Slice,
657                            layer: err::Layer::Ipv6ExtHeader,
658                            layer_start_offset: 0,
659                        }
660                    );
661                }
662            }
663            // frag header
664            {
665                let bytes = frag.to_bytes();
666                // ok case
667                {
668                    let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, IPV6_FRAG).unwrap();
669                    assert_eq!(next, frag.next_header);
670                    assert_eq!(rest, &[]);
671                }
672                // length error
673                for len in 0..bytes.len() {
674                    assert_eq!(
675                        Ipv6Header::skip_header_extension_in_slice(&bytes[..len], IPV6_FRAG).unwrap_err(),
676                        err::LenError {
677                            required_len: if len < 2 {
678                                2
679                            } else {
680                                bytes.len()
681                            },
682                            len: len,
683                            len_source: LenSource::Slice,
684                            layer: err::Layer::Ipv6ExtHeader,
685                            layer_start_offset: 0,
686                        }
687                    );
688                }
689            }
690
691            // auth header
692            {
693                let bytes = auth.to_bytes();
694                // ok case
695                {
696                    let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, AUTH).unwrap();
697                    assert_eq!(next, auth.next_header);
698                    assert_eq!(rest, &[]);
699                }
700                // length error
701                for len in 0..bytes.len() {
702                    assert_eq!(
703                        Ipv6Header::skip_header_extension_in_slice(&bytes[..len], AUTH).unwrap_err(),
704                        err::LenError {
705                            required_len: if len < 2 {
706                                2
707                            } else {
708                                bytes.len()
709                            },
710                            len: len,
711                            len_source: LenSource::Slice,
712                            layer: err::Layer::Ipv6ExtHeader,
713                            layer_start_offset: 0,
714                        }
715                    );
716                }
717            }
718        }
719    }
720
721    #[test]
722    fn is_skippable_header_extension() {
723        for i in 0..0xffu8 {
724            let expected = match IpNumber(i) {
725                IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_FRAG | AUTH | IPV6_DEST_OPTIONS | MOBILITY
726                | HIP | SHIM6 => true,
727                _ => false,
728            };
729            assert_eq!(
730                expected,
731                Ipv6Header::is_skippable_header_extension(IpNumber(i))
732            );
733        }
734    }
735
736    proptest! {
737        #[test]
738        fn skip_all_header_extensions_in_slice(
739            hop_by_hop in ipv6_raw_ext_any(),
740            dst_opt1 in ipv6_raw_ext_any(),
741            route in ipv6_raw_ext_any(),
742            frag in ipv6_fragment_any(),
743            auth in ip_auth_any(),
744            dst_opt2 in ipv6_raw_ext_any(),
745            mobility in ipv6_raw_ext_any(),
746            hip in ipv6_raw_ext_any(),
747            shim6 in ipv6_raw_ext_any()
748        ) {
749            // no extension header
750            {
751                let (next, rest) = Ipv6Header::skip_all_header_extensions_in_slice(&[], UDP).unwrap();
752                assert_eq!(UDP, next);
753                assert_eq!(rest, &[]);
754            }
755
756            // setup a buffer with all extension headers present
757            let buffer = {
758                let mut buffer = ArrayVec::<u8, {
759                    Ipv6RawExtHeader::MAX_LEN * 8 + IpAuthHeader::MAX_LEN
760                }>::new();
761
762                // based on RFC 8200 4.1. Extension Header Order
763                // & IANA https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml
764                //
765                // IPV6_HOP_BY_HOP,
766                // IPV6_DEST_OPTIONS,
767                // IPV6_ROUTE,
768                // IPV6_FRAG,
769                // AUTH,
770                // IPV6_DEST_OPTIONS,
771                // MOBILITY,
772                // HIP,
773                // SHIM6,
774
775                let mut hop_by_hop = hop_by_hop.clone();
776                hop_by_hop.next_header = IPV6_DEST_OPTIONS;
777                buffer.extend(hop_by_hop.to_bytes());
778
779                let mut dst_opt1 = dst_opt1.clone();
780                dst_opt1.next_header = IPV6_ROUTE;
781                buffer.extend(dst_opt1.to_bytes());
782
783                let mut route = route.clone();
784                route.next_header = IPV6_FRAG;
785                buffer.extend(route.to_bytes());
786
787                let mut frag = frag.clone();
788                frag.next_header = AUTH;
789                buffer.extend(frag.to_bytes());
790
791                let mut auth = auth.clone();
792                auth.next_header = IPV6_DEST_OPTIONS;
793                buffer.extend(auth.to_bytes());
794
795                let mut dst_opt2 = dst_opt2.clone();
796                dst_opt2.next_header = MOBILITY;
797                buffer.extend(dst_opt2.to_bytes());
798
799                let mut mobility = mobility.clone();
800                mobility.next_header = HIP;
801                buffer.extend(mobility.to_bytes());
802
803                let mut hip = hip.clone();
804                hip.next_header = SHIM6;
805                buffer.extend(hip.to_bytes());
806
807                let mut shim6 = shim6.clone();
808                shim6.next_header = TCP;
809                buffer.extend(shim6.to_bytes());
810
811                buffer
812            };
813
814            // ok skip case with all extension headers
815            {
816                let (next, rest) = Ipv6Header::skip_all_header_extensions_in_slice(&buffer, IPV6_HOP_BY_HOP).unwrap();
817                assert_eq!(next, TCP);
818                assert_eq!(rest, &[]);
819            }
820
821            // length error
822            {
823                let len_ranges: [usize;9] = [
824                    hop_by_hop.header_len(),
825                    dst_opt1.header_len(),
826                    route.header_len(),
827                    frag.header_len(),
828                    auth.header_len(),
829                    dst_opt2.header_len(),
830                    mobility.header_len(),
831                    hip.header_len(),
832                    shim6.header_len()
833                ];
834                let get_expected = |len: usize| -> usize{
835                    let mut curr = 0;
836                    for next in &len_ranges {
837                        if len < curr {
838                            break;
839                        }
840                        if len < curr + 2 {
841                            curr += 2;
842                            break;
843                        }
844                        curr += next;
845                    }
846                    curr
847                };
848
849                let get_offset = |len: usize| -> usize{
850                    let mut curr = 0;
851                    for next in &len_ranges {
852                        if len < curr + next {
853                            break;
854                        }
855                        curr += next;
856                    }
857                    curr
858                };
859
860                for len in 0..buffer.len() {
861                    assert_eq!(
862                        Ipv6Header::skip_all_header_extensions_in_slice(&buffer[..len], IPV6_HOP_BY_HOP)
863                            .unwrap_err(),
864                        err::LenError {
865                            required_len: get_expected(len) - get_offset(len),
866                            len: len - get_offset(len),
867                            len_source: LenSource::Slice,
868                            layer: err::Layer::Ipv6ExtHeader,
869                            layer_start_offset: get_offset(len),
870                        }
871                    );
872                }
873            }
874        }
875    }
876
877    #[test]
878    fn skip_header_extension() {
879        use crate::ip_number::*;
880        {
881            let buffer: [u8; 8] = [0; 8];
882            let mut cursor = Cursor::new(&buffer);
883            assert_eq!(
884                Ipv6Header::skip_header_extension(&mut cursor, ICMP).unwrap(),
885                ICMP
886            );
887            assert_eq!(0, cursor.position());
888        }
889        {
890            let buffer: [u8; 8] = [0; 8];
891            let mut cursor = Cursor::new(&buffer);
892            assert_eq!(
893                Ipv6Header::skip_header_extension(&mut cursor, IPV6_HOP_BY_HOP).unwrap(),
894                IpNumber(0)
895            );
896            assert_eq!(8, cursor.position());
897        }
898        {
899            #[rustfmt::skip]
900            let buffer: [u8; 8 * 3] = [
901                4, 2, 0, 0, 0, 0, 0, 0,
902                0, 0, 0, 0, 0, 0, 0, 0,
903                0, 0, 0, 0, 0, 0, 0, 0,
904            ];
905            let mut cursor = Cursor::new(&buffer);
906            assert_eq!(
907                Ipv6Header::skip_header_extension(&mut cursor, IPV6_ROUTE).unwrap(),
908                IpNumber(4)
909            );
910            assert_eq!(8 * 3, cursor.position());
911        }
912        {
913            //fragmentation header has a fixed size -> the 2 should be ignored
914            #[rustfmt::skip]
915            let buffer: [u8; 8 * 3] = [
916                4, 2, 0, 0, 0, 0, 0, 0,
917                0, 0, 0, 0, 0, 0, 0, 0,
918                0, 0, 0, 0, 0, 0, 0, 0,
919            ];
920            let mut cursor = Cursor::new(&buffer);
921            assert_eq!(
922                Ipv6Header::skip_header_extension(&mut cursor, IPV6_FRAG).unwrap(),
923                IpNumber(4)
924            );
925            assert_eq!(8, cursor.position());
926        }
927    }
928
929    proptest! {
930        #[test]
931        fn skip_all_header_extensions(
932            hop_by_hop in ipv6_raw_ext_any(),
933            dst_opt1 in ipv6_raw_ext_any(),
934            route in ipv6_raw_ext_any(),
935            frag in ipv6_fragment_any(),
936            auth in ip_auth_any(),
937            dst_opt2 in ipv6_raw_ext_any(),
938            mobility in ipv6_raw_ext_any(),
939            hip in ipv6_raw_ext_any(),
940            shim6 in ipv6_raw_ext_any()
941        ) {
942            // no extension header
943            {
944                let mut cursor = Cursor::new(&[]);
945                let next = Ipv6Header::skip_all_header_extensions(&mut cursor, UDP).unwrap();
946                assert_eq!(UDP, next);
947                assert_eq!(0, cursor.position());
948            }
949
950            // setup a buffer with all extension headers present
951            let buffer = {
952                let mut buffer = ArrayVec::<u8, {
953                    Ipv6RawExtHeader::MAX_LEN * 8 + IpAuthHeader::MAX_LEN
954                }>::new();
955
956                // based on RFC 8200 4.1. Extension Header Order
957                // & IANA https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml
958                //
959                // IPV6_HOP_BY_HOP,
960                // IPV6_DEST_OPTIONS,
961                // IPV6_ROUTE,
962                // IPV6_FRAG,
963                // AUTH,
964                // IPV6_DEST_OPTIONS,
965                // MOBILITY,
966                // HIP,
967                // SHIM6,
968
969                let mut hop_by_hop = hop_by_hop.clone();
970                hop_by_hop.next_header = IPV6_DEST_OPTIONS;
971                buffer.extend(hop_by_hop.to_bytes());
972
973                let mut dst_opt1 = dst_opt1.clone();
974                dst_opt1.next_header = IPV6_ROUTE;
975                buffer.extend(dst_opt1.to_bytes());
976
977                let mut route = route.clone();
978                route.next_header = IPV6_FRAG;
979                buffer.extend(route.to_bytes());
980
981                let mut frag = frag.clone();
982                frag.next_header = AUTH;
983                buffer.extend(frag.to_bytes());
984
985                let mut auth = auth.clone();
986                auth.next_header = IPV6_DEST_OPTIONS;
987                buffer.extend(auth.to_bytes());
988
989                let mut dst_opt2 = dst_opt2.clone();
990                dst_opt2.next_header = MOBILITY;
991                buffer.extend(dst_opt2.to_bytes());
992
993                let mut mobility = mobility.clone();
994                mobility.next_header = HIP;
995                buffer.extend(mobility.to_bytes());
996
997                let mut hip = hip.clone();
998                hip.next_header = SHIM6;
999                buffer.extend(hip.to_bytes());
1000
1001                let mut shim6 = shim6.clone();
1002                shim6.next_header = TCP;
1003                buffer.extend(shim6.to_bytes());
1004
1005                buffer
1006            };
1007
1008            // ok skip case with all extension headers
1009            {
1010                let mut cursor = Cursor::new(&buffer);
1011                let last = Ipv6Header::skip_all_header_extensions(&mut cursor, IPV6_HOP_BY_HOP).unwrap();
1012                assert_eq!(last, TCP);
1013                assert_eq!(cursor.position(), buffer.len() as u64);
1014            }
1015
1016            // length error
1017            for len in 0..buffer.len() {
1018                let mut cursor = Cursor::new(&buffer[..len]);
1019                assert!(
1020                    Ipv6Header::skip_all_header_extensions(&mut cursor, IPV6_HOP_BY_HOP)
1021                    .is_err()
1022                );
1023            }
1024        }
1025    }
1026
1027    proptest! {
1028        #[test]
1029        fn write(header in ipv6_any()) {
1030            let mut buffer = [0u8;Ipv6Header::LEN];
1031            let len = {
1032                let mut cursor = Cursor::new(&mut buffer[..]);
1033                header.write(&mut cursor).unwrap();
1034                cursor.position() as usize
1035            };
1036            assert_eq!(len, header.header_len());
1037            assert_eq!(
1038                Ipv6Header::from_slice(&buffer[..len]).unwrap().0,
1039                header
1040            );
1041        }
1042    }
1043
1044    proptest! {
1045        #[test]
1046        fn source_addr(header in ipv6_any()) {
1047            assert_eq!(
1048                header.source_addr().octets(),
1049                header.source
1050            );
1051        }
1052    }
1053
1054    proptest! {
1055        #[test]
1056        fn destination_addr(header in ipv6_any()) {
1057            assert_eq!(
1058                header.destination_addr().octets(),
1059                header.destination
1060            );
1061        }
1062    }
1063
1064    proptest! {
1065        #[test]
1066        fn to_bytes(header in ipv6_any()) {
1067            let bytes = header.to_bytes();
1068            assert_eq!(
1069                Ipv6Header::from_slice(&bytes).unwrap().0,
1070                header
1071            );
1072        }
1073    }
1074}