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

etherparse/net/
ipv6_slice.rs

1use crate::err::{ipv6::SliceError, Layer, LenError};
2use crate::*;
3
4/// Slice containing the IPv6 headers & payload.
5#[derive(Clone, Debug, Eq, PartialEq)]
6pub struct Ipv6Slice<'a> {
7    pub(crate) header: Ipv6HeaderSlice<'a>,
8    pub(crate) exts: Ipv6ExtensionsSlice<'a>,
9    pub(crate) payload: IpPayloadSlice<'a>,
10}
11
12impl<'a> Ipv6Slice<'a> {
13    /// Separates and validates IPv6 headers (including extension headers)
14    /// in the given slice and determine the sub-slice containing the payload
15    /// of the IPv6 packet (based on the payload length value in the header).
16    ///
17    /// Note that his function returns an [`crate::err::LenError`] if the given slice
18    /// contains less data then the `payload_len` field in the IPv6 header indicates
19    /// should be present.
20    ///
21    /// If you want to ignore these kind of length errors based on the length
22    /// fields in the IP headers use [`Ipv6Slice::from_slice_lax`] instead.
23    pub fn from_slice(slice: &'a [u8]) -> Result<Ipv6Slice<'a>, SliceError> {
24        // try reading the header
25        let header = Ipv6HeaderSlice::from_slice(slice).map_err(|err| {
26            use crate::err::ipv6::HeaderSliceError::*;
27            match err {
28                Len(err) => SliceError::Len(err),
29                Content(err) => SliceError::Header(err),
30            }
31        })?;
32
33        // restrict slice by the length specified in the header
34        let (header_payload, len_source) =
35            if 0 == header.payload_length() && slice.len() > Ipv6Header::LEN {
36                // In case the payload_length is 0 assume that the entire
37                // rest of the slice is part of the packet until the jumbogram
38                // parameters can be parsed.
39
40                // TODO: Add payload length parsing from the jumbogram
41                (
42                    unsafe {
43                        core::slice::from_raw_parts(
44                            slice.as_ptr().add(Ipv6Header::LEN),
45                            slice.len() - Ipv6Header::LEN,
46                        )
47                    },
48                    LenSource::Slice,
49                )
50            } else {
51                let payload_len = usize::from(header.payload_length());
52                let expected_len = Ipv6Header::LEN + payload_len;
53                if slice.len() < expected_len {
54                    return Err(SliceError::Len(LenError {
55                        required_len: expected_len,
56                        len: slice.len(),
57                        len_source: LenSource::Slice,
58                        layer: Layer::Ipv6Packet,
59                        layer_start_offset: 0,
60                    }));
61                } else {
62                    (
63                        unsafe {
64                            core::slice::from_raw_parts(
65                                slice.as_ptr().add(Ipv6Header::LEN),
66                                payload_len,
67                            )
68                        },
69                        LenSource::Ipv6HeaderPayloadLen,
70                    )
71                }
72            };
73
74        // parse extension headers
75        let (exts, payload_ip_number, payload) =
76            Ipv6ExtensionsSlice::from_slice(header.next_header(), header_payload).map_err(
77                |err| {
78                    // modify length errors
79                    use crate::err::ipv6_exts::HeaderSliceError::*;
80                    match err {
81                        Len(mut err) => {
82                            err.len_source = LenSource::Ipv6HeaderPayloadLen;
83                            err.layer_start_offset += Ipv6Header::LEN;
84                            SliceError::Len(err)
85                        }
86                        Content(err) => SliceError::Exts(err),
87                    }
88                },
89            )?;
90
91        let fragmented = exts.is_fragmenting_payload();
92        Ok(Ipv6Slice {
93            header,
94            exts,
95            payload: IpPayloadSlice {
96                ip_number: payload_ip_number,
97                fragmented,
98                len_source,
99                payload,
100            },
101        })
102    }
103
104    /// Seperate an IPv6 header (+ extensions) & the payload from the given slice with
105    /// less strict length checks (useful for cut off packet or for packets with
106    /// unset length fields).
107    ///
108    /// If you want to only receive correct IpPayloads use [`crate::Ipv4Slice::from_slice`]
109    /// instead.
110    ///
111    /// The main usecases for this functions are:
112    ///
113    /// * Parsing packets that have been cut off. This is, for example, useful to
114    ///   parse packets returned via ICMP as these usually only contain the start.
115    /// * Parsing packets where the `payload_length` (in the IPv6 header) has not
116    ///   yet been set. This can be useful when parsing packets which have been
117    ///   recorded in a layer before the length field was set (e.g. before the operating
118    ///   system set the length fields).
119    ///
120    /// # Differences to `from_slice`:
121    ///
122    /// The main differences is that the function ignores inconsistent
123    /// `payload_length` values (in IPv6 headers). When these length values
124    /// in the IP header are inconsistant the length of the given slice is
125    /// used as a substitute.
126    ///
127    /// You can check if the slice length was used as a substitude by checking
128    /// if the `len_source` value in the returned [`IpPayloadSlice`] is set to
129    /// [`LenSource::Slice`]. If a substitution was not needed `len_source`
130    /// is set to [`LenSource::Ipv6HeaderPayloadLen`].
131    ///
132    /// # When is the slice length used as a fallback?
133    ///
134    /// The slice length is used as a fallback/substitude if the `payload_length`
135    /// field in the IPv6 header is
136    ///
137    /// * Bigger then the given slice (payload cannot fully be seperated).
138    /// * The value `0`.
139    pub fn from_slice_lax(slice: &'a [u8]) -> Result<Ipv6Slice<'a>, SliceError> {
140        // try reading the header
141        let header = Ipv6HeaderSlice::from_slice(slice).map_err(|err| {
142            use crate::err::ipv6::HeaderSliceError::*;
143            match err {
144                Len(err) => SliceError::Len(err),
145                Content(err) => SliceError::Header(err),
146            }
147        })?;
148
149        // restrict slice by the length specified in the header
150        let (header_payload, len_source) =
151            if 0 == header.payload_length() && slice.len() > Ipv6Header::LEN {
152                // In case the payload_length is 0 assume that the entire
153                // rest of the slice is part of the packet until the jumbogram
154                // parameters can be parsed.
155
156                // TODO: Add payload length parsing from the jumbogram
157                (
158                    unsafe {
159                        core::slice::from_raw_parts(
160                            slice.as_ptr().add(Ipv6Header::LEN),
161                            slice.len() - Ipv6Header::LEN,
162                        )
163                    },
164                    LenSource::Slice,
165                )
166            } else {
167                let payload_len = usize::from(header.payload_length());
168                let expected_len = Ipv6Header::LEN + payload_len;
169                if slice.len() < expected_len {
170                    (
171                        unsafe {
172                            core::slice::from_raw_parts(
173                                slice.as_ptr().add(Ipv6Header::LEN),
174                                slice.len() - Ipv6Header::LEN,
175                            )
176                        },
177                        LenSource::Slice,
178                    )
179                } else {
180                    (
181                        unsafe {
182                            core::slice::from_raw_parts(
183                                slice.as_ptr().add(Ipv6Header::LEN),
184                                payload_len,
185                            )
186                        },
187                        LenSource::Ipv6HeaderPayloadLen,
188                    )
189                }
190            };
191
192        // parse extension headers
193        let (exts, payload_ip_number, payload) =
194            Ipv6ExtensionsSlice::from_slice(header.next_header(), header_payload).map_err(
195                |err| {
196                    // modify length errors
197                    use crate::err::ipv6_exts::HeaderSliceError::*;
198                    match err {
199                        Len(mut err) => {
200                            err.len_source = len_source;
201                            err.layer_start_offset += Ipv6Header::LEN;
202                            SliceError::Len(err)
203                        }
204                        Content(err) => SliceError::Exts(err),
205                    }
206                },
207            )?;
208
209        let fragmented = exts.is_fragmenting_payload();
210        Ok(Ipv6Slice {
211            header,
212            exts,
213            payload: IpPayloadSlice {
214                ip_number: payload_ip_number,
215                fragmented,
216                len_source,
217                payload,
218            },
219        })
220    }
221
222    /// Returns a slice containing the IPv6 header.
223    #[inline]
224    pub fn header(&self) -> Ipv6HeaderSlice<'a> {
225        self.header
226    }
227
228    /// Returns a slice containing the IPv6 extension headers.
229    #[inline]
230    pub fn extensions(&self) -> &Ipv6ExtensionsSlice<'a> {
231        &self.exts
232    }
233
234    /// Returns a slice containing the data after the IPv6 header
235    /// and IPv6 extensions headers.
236    #[inline]
237    pub fn payload(&self) -> &IpPayloadSlice<'a> {
238        &self.payload
239    }
240
241    /// Returns true if the payload is flagged as being fragmented.
242    #[inline]
243    pub fn is_payload_fragmented(&self) -> bool {
244        self.payload.fragmented
245    }
246}
247
248#[cfg(test)]
249mod test {
250    use super::*;
251    use crate::{
252        ip_number::{AUTH, IGMP, UDP},
253        test_gens::*,
254    };
255    use alloc::{format, vec::Vec};
256    use proptest::prelude::*;
257
258    proptest! {
259        #[test]
260        fn debug_clone_eq(
261            ipv6_base in ipv6_any(),
262            auth_base in ip_auth_any()
263        ) {
264            let mut auth = auth_base.clone();
265            auth.next_header = IGMP;
266            let payload: [u8;4] = [1,2,3,4];
267            let mut data = Vec::with_capacity(
268                ipv6_base.header_len() +
269                auth.header_len() +
270                payload.len()
271            );
272            let mut ipv6 = ipv6_base.clone();
273            ipv6.next_header = AUTH;
274            ipv6.payload_length = (auth.header_len() + payload.len()) as u16;
275            data.extend_from_slice(&ipv6.to_bytes());
276            data.extend_from_slice(&auth.to_bytes());
277            data.extend_from_slice(&payload);
278
279            // decode packet
280            let slice = Ipv6Slice::from_slice(&data).unwrap();
281
282            // check debug output
283            prop_assert_eq!(
284                format!("{:?}", slice),
285                format!(
286                    "Ipv6Slice {{ header: {:?}, exts: {:?}, payload: {:?} }}",
287                    slice.header(),
288                    slice.extensions(),
289                    slice.payload()
290                )
291            );
292            prop_assert_eq!(slice.clone(), slice);
293        }
294    }
295
296    proptest! {
297        #[test]
298        fn from_slice(
299            ipv6_base in ipv6_any(),
300            auth_base in ip_auth_any()
301        ) {
302            let payload: [u8;6] = [1,2,3,4,5,6];
303
304            // build packets
305            let data_without_ext = {
306                let mut data = Vec::with_capacity(
307                    ipv6_base.header_len() +
308                    payload.len() +
309                    4
310                );
311                let mut ipv6 = ipv6_base.clone();
312                ipv6.payload_length = (payload.len()) as u16;
313                ipv6.next_header = UDP;
314                data.extend_from_slice(&ipv6.to_bytes());
315                data.extend_from_slice(&payload);
316                data.extend_from_slice(&[0,0,0,0]);
317                data
318            };
319            let data_with_ext = {
320                let payload: [u8;6] = [1,2,3,4,5,6];
321                let mut data = Vec::with_capacity(
322                    ipv6_base.header_len() +
323                    auth_base.header_len() +
324                    payload.len() +
325                    4
326                );
327                let mut ipv6 = ipv6_base.clone();
328                ipv6.payload_length = (auth_base.header_len() + payload.len()) as u16;
329                ipv6.next_header = AUTH;
330                let mut auth = auth_base.clone();
331                auth.next_header = UDP;
332                data.extend_from_slice(&ipv6.to_bytes());
333                data.extend_from_slice(&auth.to_bytes());
334                data.extend_from_slice(&payload);
335                data.extend_from_slice(&[0,0,0,0]);
336                data
337            };
338
339            // parsing without extensions (normal length)
340            {
341                let actual = Ipv6Slice::from_slice(&data_without_ext).unwrap();
342                prop_assert_eq!(actual.header().slice(), &data_without_ext[..ipv6_base.header_len()]);
343                prop_assert!(actual.extensions().first_header().is_none());
344                prop_assert_eq!(
345                    actual.payload(),
346                    &IpPayloadSlice{
347                        ip_number: UDP.into(),
348                        fragmented: false,
349                        len_source: LenSource::Ipv6HeaderPayloadLen,
350                        payload: &payload,
351                    }
352                );
353            }
354
355            // parsing with extensions (normal length)
356            {
357                let actual = Ipv6Slice::from_slice(&data_with_ext).unwrap();
358                prop_assert_eq!(actual.header().slice(), &data_with_ext[..ipv6_base.header_len()]);
359                let (expected, _, _) = Ipv6ExtensionsSlice::from_slice(AUTH, &data_with_ext[ipv6_base.header_len()..]).unwrap();
360                prop_assert_eq!(
361                    actual.extensions(),
362                    &expected
363                );
364                prop_assert_eq!(
365                    actual.payload(),
366                    &IpPayloadSlice{
367                        ip_number: UDP.into(),
368                        fragmented: false,
369                        len_source: LenSource::Ipv6HeaderPayloadLen,
370                        payload: &payload,
371                    }
372                );
373            }
374
375            // parsing without extensions (zero length, fallback to slice length)
376            {
377                // inject zero as payload length
378                let mut data = data_without_ext.clone();
379                data[4] = 0;
380                data[5] = 0;
381                let actual = Ipv6Slice::from_slice(&data).unwrap();
382                prop_assert_eq!(actual.header().slice(), &data[..ipv6_base.header_len()]);
383                prop_assert!(actual.extensions().first_header().is_none());
384                prop_assert_eq!(
385                    actual.payload(),
386                    &IpPayloadSlice{
387                        ip_number: UDP.into(),
388                        fragmented: false,
389                        len_source: LenSource::Slice,
390                        payload: &data[ipv6_base.header_len()..],
391                    }
392                );
393            }
394
395            // parsing with extensions (zero length, fallback to slice length)
396            {
397                // inject zero as payload length
398                let mut data = data_with_ext.clone();
399                data[4] = 0;
400                data[5] = 0;
401                let actual = Ipv6Slice::from_slice(&data).unwrap();
402                prop_assert_eq!(actual.header().slice(), &data[..ipv6_base.header_len()]);
403                let (expected, _, _) = Ipv6ExtensionsSlice::from_slice(AUTH, &data[ipv6_base.header_len()..]).unwrap();
404                prop_assert_eq!(
405                    actual.extensions(),
406                    &expected
407                );
408                prop_assert_eq!(
409                    actual.payload(),
410                    &IpPayloadSlice{
411                        ip_number: UDP.into(),
412                        fragmented: false,
413                        len_source: LenSource::Slice,
414                        payload: &data[ipv6_base.header_len() + auth_base.header_len()..],
415                    }
416                );
417            }
418
419            // header content error
420            {
421                use crate::err::ipv6::HeaderError;
422                // inject invalid ip version
423                let mut data = data_without_ext.clone();
424                data[0] = data[0] & 0x0f; // version 0
425                prop_assert_eq!(
426                    Ipv6Slice::from_slice(&data).unwrap_err(),
427                    SliceError::Header(
428                        HeaderError::UnexpectedVersion{ version_number: 0 }
429                    )
430                );
431            }
432
433            // header length error
434            for len in 0..Ipv6Header::LEN {
435                prop_assert_eq!(
436                    Ipv6Slice::from_slice(&data_without_ext[..len]).unwrap_err(),
437                    SliceError::Len(
438                        LenError{
439                            required_len: Ipv6Header::LEN,
440                            len,
441                            len_source: LenSource::Slice,
442                            layer: Layer::Ipv6Header,
443                            layer_start_offset: 0
444                        }
445                    )
446                );
447            }
448
449            // payload length error without auth header
450            {
451                use crate::err::{LenError, Layer};
452
453                let required_len = ipv6_base.header_len() + payload.len();
454                prop_assert_eq!(
455                    Ipv6Slice::from_slice(&data_without_ext[..required_len - 1]).unwrap_err(),
456                    SliceError::Len(LenError{
457                        required_len: required_len,
458                        len: required_len - 1,
459                        len_source: LenSource::Slice,
460                        layer: Layer::Ipv6Packet,
461                        layer_start_offset: 0,
462                    })
463                );
464            }
465
466            // payload length error auth header
467            {
468                use crate::err::{LenError, Layer};
469
470                let required_len = ipv6_base.header_len() + auth_base.header_len() + payload.len();
471                prop_assert_eq!(
472                    Ipv6Slice::from_slice(&data_with_ext[..required_len - 1]).unwrap_err(),
473                    SliceError::Len(LenError{
474                        required_len: required_len,
475                        len: required_len - 1,
476                        len_source: LenSource::Slice,
477                        layer: Layer::Ipv6Packet,
478                        layer_start_offset: 0,
479                    })
480                );
481            }
482
483            // auth length error
484            {
485                use crate::err::{LenError, Layer};
486
487                // inject payload length that is smaller then the auth header
488                let mut data = data_with_ext.clone();
489                let payload_len_too_small = auth_base.header_len() - 1;
490                {
491                    let plts = (payload_len_too_small as u16).to_be_bytes();
492                    data[4] = plts[0];
493                    data[5] = plts[1];
494                }
495
496                prop_assert_eq!(
497                    Ipv6Slice::from_slice(&data).unwrap_err(),
498                    SliceError::Len(
499                        LenError{
500                            required_len: auth_base.header_len(),
501                            len: auth_base.header_len() - 1,
502                            len_source: LenSource::Ipv6HeaderPayloadLen,
503                            layer: Layer::IpAuthHeader,
504                            layer_start_offset: ipv6_base.header_len(),
505                        }
506                    )
507                );
508            }
509
510            // auth content error
511            {
512                use crate::err::{ip_auth, ipv6_exts};
513
514                // inject zero as auth header length
515                let mut data = data_with_ext.clone();
516                data[ipv6_base.header_len() + 1] = 0;
517
518                prop_assert_eq!(
519                    Ipv6Slice::from_slice(&data).unwrap_err(),
520                    SliceError::Exts(ipv6_exts::HeaderError::IpAuth(
521                        ip_auth::HeaderError::ZeroPayloadLen
522                    ))
523                );
524            }
525        }
526    }
527
528    proptest! {
529        #[test]
530        fn from_slice_lax(
531            ipv6_base in ipv6_any(),
532            auth_base in ip_auth_any()
533        ) {
534            let payload: [u8;6] = [1,2,3,4,5,6];
535
536            // build packets
537            let data_without_ext = {
538                let mut data = Vec::with_capacity(
539                    ipv6_base.header_len() +
540                    payload.len() +
541                    4
542                );
543                let mut ipv6 = ipv6_base.clone();
544                ipv6.payload_length = (payload.len()) as u16;
545                ipv6.next_header = UDP;
546                data.extend_from_slice(&ipv6.to_bytes());
547                data.extend_from_slice(&payload);
548                data.extend_from_slice(&[0,0,0,0]);
549                data
550            };
551            let data_with_ext = {
552                let payload: [u8;6] = [1,2,3,4,5,6];
553                let mut data = Vec::with_capacity(
554                    ipv6_base.header_len() +
555                    auth_base.header_len() +
556                    payload.len() +
557                    4
558                );
559                let mut ipv6 = ipv6_base.clone();
560                ipv6.payload_length = (auth_base.header_len() + payload.len()) as u16;
561                ipv6.next_header = AUTH;
562                let mut auth = auth_base.clone();
563                auth.next_header = UDP;
564                data.extend_from_slice(&ipv6.to_bytes());
565                data.extend_from_slice(&auth.to_bytes());
566                data.extend_from_slice(&payload);
567                data.extend_from_slice(&[0,0,0,0]);
568                data
569            };
570
571            // parsing without extensions (normal length)
572            {
573                let actual = Ipv6Slice::from_slice_lax(&data_without_ext).unwrap();
574                prop_assert_eq!(actual.header().slice(), &data_without_ext[..ipv6_base.header_len()]);
575                prop_assert!(actual.extensions().first_header().is_none());
576                prop_assert_eq!(
577                    actual.payload(),
578                    &IpPayloadSlice{
579                        ip_number: UDP.into(),
580                        fragmented: false,
581                        len_source: LenSource::Ipv6HeaderPayloadLen,
582                        payload: &payload,
583                    }
584                );
585            }
586
587            // parsing with extensions (normal length)
588            {
589                let actual = Ipv6Slice::from_slice_lax(&data_with_ext).unwrap();
590                prop_assert_eq!(actual.header().slice(), &data_with_ext[..ipv6_base.header_len()]);
591                let (expected, _, _) = Ipv6ExtensionsSlice::from_slice(AUTH, &data_with_ext[ipv6_base.header_len()..]).unwrap();
592                prop_assert_eq!(
593                    actual.extensions(),
594                    &expected
595                );
596                prop_assert_eq!(
597                    actual.payload(),
598                    &IpPayloadSlice{
599                        ip_number: UDP.into(),
600                        fragmented: false,
601                        len_source: LenSource::Ipv6HeaderPayloadLen,
602                        payload: &payload,
603                    }
604                );
605            }
606
607            // parsing without extensions (zero length, fallback to slice length)
608            {
609                // inject zero as payload length
610                let mut data = data_without_ext.clone();
611                data[4] = 0;
612                data[5] = 0;
613                let actual = Ipv6Slice::from_slice_lax(&data).unwrap();
614                prop_assert_eq!(actual.header().slice(), &data[..ipv6_base.header_len()]);
615                prop_assert!(actual.extensions().first_header().is_none());
616                prop_assert_eq!(
617                    actual.payload(),
618                    &IpPayloadSlice{
619                        ip_number: UDP.into(),
620                        fragmented: false,
621                        len_source: LenSource::Slice,
622                        payload: &data[ipv6_base.header_len()..],
623                    }
624                );
625            }
626
627            // parsing with extensions (zero length, fallback to slice length)
628            {
629                // inject zero as payload length
630                let mut data = data_with_ext.clone();
631                data[4] = 0;
632                data[5] = 0;
633                let actual = Ipv6Slice::from_slice_lax(&data).unwrap();
634                prop_assert_eq!(actual.header().slice(), &data[..ipv6_base.header_len()]);
635                let (expected, _, _) = Ipv6ExtensionsSlice::from_slice(AUTH, &data[ipv6_base.header_len()..]).unwrap();
636                prop_assert_eq!(
637                    actual.extensions(),
638                    &expected
639                );
640                prop_assert_eq!(
641                    actual.payload(),
642                    &IpPayloadSlice{
643                        ip_number: UDP.into(),
644                        fragmented: false,
645                        len_source: LenSource::Slice,
646                        payload: &data[ipv6_base.header_len() + auth_base.header_len()..],
647                    }
648                );
649            }
650
651            // header content error
652            {
653                use crate::err::ipv6::HeaderError;
654                // inject invalid ip version
655                let mut data = data_without_ext.clone();
656                data[0] = data[0] & 0x0f; // version 0
657                prop_assert_eq!(
658                    Ipv6Slice::from_slice_lax(&data).unwrap_err(),
659                    SliceError::Header(
660                        HeaderError::UnexpectedVersion{ version_number: 0 }
661                    )
662                );
663            }
664
665            // header length error
666            for len in 0..Ipv6Header::LEN {
667                prop_assert_eq!(
668                    Ipv6Slice::from_slice_lax(&data_without_ext[..len]).unwrap_err(),
669                    SliceError::Len(
670                        LenError{
671                            required_len: Ipv6Header::LEN,
672                            len,
673                            len_source: LenSource::Slice,
674                            layer: Layer::Ipv6Header,
675                            layer_start_offset: 0
676                        }
677                    )
678                );
679            }
680
681            // payload length larger then slice (fallback to slice length)
682            {
683                let len = ipv6_base.header_len() + payload.len() - 1;
684                let actual = Ipv6Slice::from_slice_lax(&data_without_ext[..len]).unwrap();
685                prop_assert_eq!(actual.header().slice(), &data_without_ext[..ipv6_base.header_len()]);
686                prop_assert_eq!(
687                    0,
688                    actual.extensions().slice().len()
689                );
690                prop_assert_eq!(
691                    actual.payload(),
692                    &IpPayloadSlice{
693                        ip_number: UDP.into(),
694                        fragmented: false,
695                        len_source: LenSource::Slice,
696                        payload: &data_without_ext[ipv6_base.header_len()..len],
697                    }
698                );
699            }
700
701            // payload length error auth header
702            {
703                use crate::err::{LenError, Layer};
704
705                let required_len = ipv6_base.header_len() + auth_base.header_len();
706                prop_assert_eq!(
707                    Ipv6Slice::from_slice_lax(&data_with_ext[..required_len - 1]).unwrap_err(),
708                    SliceError::Len(LenError{
709                        required_len: required_len - Ipv6Header::LEN,
710                        len: required_len - Ipv6Header::LEN - 1,
711                        len_source: LenSource::Slice,
712                        layer: Layer::IpAuthHeader,
713                        layer_start_offset: Ipv6Header::LEN,
714                    })
715                );
716            }
717
718            // auth length error
719            {
720                use crate::err::{LenError, Layer};
721
722                // inject payload length that is smaller then the auth header
723                let mut data = data_with_ext.clone();
724                let payload_len_too_small = auth_base.header_len() - 1;
725                {
726                    let plts = (payload_len_too_small as u16).to_be_bytes();
727                    data[4] = plts[0];
728                    data[5] = plts[1];
729                }
730
731                prop_assert_eq!(
732                    Ipv6Slice::from_slice_lax(&data).unwrap_err(),
733                    SliceError::Len(
734                        LenError{
735                            required_len: auth_base.header_len(),
736                            len: auth_base.header_len() - 1,
737                            len_source: LenSource::Ipv6HeaderPayloadLen,
738                            layer: Layer::IpAuthHeader,
739                            layer_start_offset: ipv6_base.header_len(),
740                        }
741                    )
742                );
743            }
744
745            // auth content error
746            {
747                use crate::err::{ip_auth, ipv6_exts};
748
749                // inject zero as auth header length
750                let mut data = data_with_ext.clone();
751                data[ipv6_base.header_len() + 1] = 0;
752
753                prop_assert_eq!(
754                    Ipv6Slice::from_slice_lax(&data).unwrap_err(),
755                    SliceError::Exts(ipv6_exts::HeaderError::IpAuth(
756                        ip_auth::HeaderError::ZeroPayloadLen
757                    ))
758                );
759            }
760        }
761    }
762
763    #[test]
764    fn is_payload_fragmented() {
765        use crate::ip_number::{IPV6_FRAG, UDP};
766
767        // not fragmented
768        {
769            let data = Ipv6Header {
770                traffic_class: 0,
771                flow_label: 1.try_into().unwrap(),
772                payload_length: 0,
773                next_header: UDP,
774                hop_limit: 4,
775                source: [0; 16],
776                destination: [0; 16],
777            }
778            .to_bytes();
779            assert_eq!(
780                false,
781                Ipv6Slice::from_slice(&data)
782                    .unwrap()
783                    .is_payload_fragmented()
784            );
785        }
786
787        // fragmented
788        {
789            let ipv6_frag = Ipv6FragmentHeader {
790                next_header: UDP,
791                fragment_offset: 0.try_into().unwrap(),
792                more_fragments: true,
793                identification: 0,
794            };
795            let ipv6 = Ipv6Header {
796                traffic_class: 0,
797                flow_label: 1.try_into().unwrap(),
798                payload_length: ipv6_frag.header_len() as u16,
799                next_header: IPV6_FRAG,
800                hop_limit: 4,
801                source: [0; 16],
802                destination: [0; 16],
803            };
804
805            let mut data = Vec::with_capacity(ipv6.header_len() + ipv6_frag.header_len());
806            data.extend_from_slice(&ipv6.to_bytes());
807            data.extend_from_slice(&ipv6_frag.to_bytes());
808            assert!(Ipv6Slice::from_slice(&data)
809                .unwrap()
810                .is_payload_fragmented());
811        }
812    }
813}