1 use crate::err::{ipv6::SliceError, Layer, LenError};
2 use crate::*;
3 
4 /// Slice containing the IPv6 headers & payload.
5 #[derive(Clone, Debug, Eq, PartialEq)]
6 pub struct Ipv6Slice<'a> {
7     pub(crate) header: Ipv6HeaderSlice<'a>,
8     pub(crate) exts: Ipv6ExtensionsSlice<'a>,
9     pub(crate) payload: IpPayloadSlice<'a>,
10 }
11 
12 impl<'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.
from_slice(slice: &'a [u8]) -> Result<Ipv6Slice<'a>, SliceError>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`.
from_slice_lax(slice: &'a [u8]) -> Result<Ipv6Slice<'a>, SliceError>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]
header(&self) -> Ipv6HeaderSlice<'a>224     pub fn header(&self) -> Ipv6HeaderSlice<'a> {
225         self.header
226     }
227 
228     /// Returns a slice containing the IPv6 extension headers.
229     #[inline]
extensions(&self) -> &Ipv6ExtensionsSlice<'a>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]
payload(&self) -> &IpPayloadSlice<'a>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]
is_payload_fragmented(&self) -> bool243     pub fn is_payload_fragmented(&self) -> bool {
244         self.payload.fragmented
245     }
246 }
247 
248 #[cfg(test)]
249 mod 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]
is_payload_fragmented()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 }
814