• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{err::*, *};
2 
3 /// Slice containing laxly separated IPv4 or IPv6 headers & payload.
4 ///
5 /// Compared to the normal [`IpSlice`] this slice allows the
6 /// payload to be incomplete/cut off and errors to be present in
7 /// the IpPayload.
8 ///
9 /// The main usecases for "laxly" parsed slices are are:
10 ///
11 /// * Parsing packets that have been cut off. This is, for example, useful to
12 ///   parse packets returned via ICMP as these usually only contain the start.
13 /// * Parsing packets where the `total_len` (for IPv4) or `payload_len` (for IPv6)
14 ///   have not yet been set. This can be useful when parsing packets which have
15 ///   been recorded in a layer before the length field was set (e.g. before the
16 ///   operating system set the length fields).
17 #[derive(Clone, Debug, Eq, PartialEq)]
18 pub enum LaxIpSlice<'a> {
19     /// The ipv4 header & the decoded extension headers.
20     Ipv4(LaxIpv4Slice<'a>),
21     /// The ipv6 header & the decoded extension headers.
22     Ipv6(LaxIpv6Slice<'a>),
23 }
24 
25 impl<'a> LaxIpSlice<'a> {
26     /// Returns a reference to the `Ipv4Slice` if `self` is a `IpSlice::Ipv4`.
ipv4(&self) -> Option<&LaxIpv4Slice>27     pub fn ipv4(&self) -> Option<&LaxIpv4Slice> {
28         use LaxIpSlice::*;
29         match self {
30             Ipv4(slice) => Some(slice),
31             Ipv6(_) => None,
32         }
33     }
34 
35     /// Returns a reference to the `Ipv6Slice` if `self` is a `IpSlice::Ipv6`.
ipv6(&self) -> Option<&LaxIpv6Slice>36     pub fn ipv6(&self) -> Option<&LaxIpv6Slice> {
37         use LaxIpSlice::*;
38         match self {
39             Ipv4(_) => None,
40             Ipv6(slice) => Some(slice),
41         }
42     }
43 
44     /// Returns true if the payload is fragmented.
is_fragmenting_payload(&self) -> bool45     pub fn is_fragmenting_payload(&self) -> bool {
46         match self {
47             LaxIpSlice::Ipv4(s) => s.is_payload_fragmented(),
48             LaxIpSlice::Ipv6(s) => s.is_payload_fragmented(),
49         }
50     }
51 
52     /// Return the source address as an std::net::Ipvddr (requires
53     /// crate feature `std`).
54     #[cfg(feature = "std")]
55     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
source_addr(&self) -> std::net::IpAddr56     pub fn source_addr(&self) -> std::net::IpAddr {
57         match self {
58             LaxIpSlice::Ipv4(s) => s.header().source_addr().into(),
59             LaxIpSlice::Ipv6(s) => s.header().source_addr().into(),
60         }
61     }
62 
63     /// Return the destination address as an std::net::IpAddr (requires
64     /// crate feature `std`).
65     #[cfg(feature = "std")]
66     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
destination_addr(&self) -> std::net::IpAddr67     pub fn destination_addr(&self) -> std::net::IpAddr {
68         match self {
69             LaxIpSlice::Ipv4(s) => s.header().destination_addr().into(),
70             LaxIpSlice::Ipv6(s) => s.header().destination_addr().into(),
71         }
72     }
73 
74     /// Returns a slice containing the data after the IP header
75     /// and IP extensions headers.
76     #[inline]
payload(&self) -> &LaxIpPayloadSlice<'a>77     pub fn payload(&self) -> &LaxIpPayloadSlice<'a> {
78         use LaxIpSlice::*;
79         match self {
80             Ipv4(ipv4) => ipv4.payload(),
81             Ipv6(ipv6) => ipv6.payload(),
82         }
83     }
84 
85     /// Returns the ip number the type of payload of the IP packet.
86     ///
87     /// This function returns the ip number stored in the last
88     /// IP header or extension header.
89     #[inline]
payload_ip_number(&self) -> IpNumber90     pub fn payload_ip_number(&self) -> IpNumber {
91         use LaxIpSlice::*;
92         match self {
93             Ipv4(ipv4) => ipv4.payload().ip_number,
94             Ipv6(ipv6) => ipv6.payload().ip_number,
95         }
96     }
97 
98     /// Separates IP headers (include extension headers) & the IP payload from the given slice
99     /// as far as possible without encountering an error and with less strict length checks.
100     /// This function is usefull for cut off packet or for packets with unset length fields.
101     ///
102     /// If you want to only receive correct IpPayloads use [`IpSlice::from_slice`]
103     /// instead.
104     ///
105     /// The main usecases for this functions are:
106     ///
107     /// * Parsing packets that have been cut off. This is, for example, useful to
108     ///   parse packets returned via ICMP as these usually only contain the start.
109     /// * Parsing packets where the `total_len` (for IPv4) or `payload_length` (for IPv6)
110     ///   have not yet been set. This can be useful when parsing packets which have been
111     ///   recorded in a layer before the length field was set (e.g. before the operating
112     ///   system set the length fields).
113     ///
114     /// # Differences to `IpSlice::from_slice`:
115     ///
116     // There are two main differences:
117     ///
118     /// * Errors in the expansion headers will only stop the parsing and return an `Ok`
119     ///   with the successfully parsed parts and the error as optional. Only if an
120     ///   unrecoverable error is encountered in the IP header itself an `Err` is returned.
121     ///   In the normal `from_slice` function an `Err` is returned if an error is
122     ///   encountered in an exteions header.
123     /// * `from_slice_lax` ignores inconsistent `total_len` (in IPv4 headers) and
124     ///   inconsistent `payload_length` (in IPv6 headers) values. When these length
125     ///   values in the IP header are inconsistant the length of the given slice is
126     ///   used as a substitute.
127     ///
128     /// You can check if the slice length was used as a substitude by checking
129     /// if `result.payload().len_source` is set to [`LenSource::Slice`].
130     /// If a substitution was not needed `len_source` is set to
131     /// [`LenSource::Ipv4HeaderTotalLen`] or [`LenSource::Ipv6HeaderPayloadLen`].
132     ///
133     /// # When is the slice length used as a fallback?
134     ///
135     /// For IPv4 packets the slice length is used as a fallback/substitude
136     /// if the `total_length` field in the IPv4 header is:
137     ///
138     ///  * Bigger then the given slice (payload cannot fully be seperated).
139     ///  * Too small to contain at least the IPv4 header.
140     ///
141     /// For IPv6 packet the slice length is used as a fallback/substitude
142     /// if the `payload_length` is
143     ///
144     /// * Bigger then the given slice (payload cannot fully be seperated).
145     /// * The value `0`.
from_slice( slice: &[u8], ) -> Result< ( LaxIpSlice, Option<(err::ipv6_exts::HeaderSliceError, err::Layer)>, ), err::ip::LaxHeaderSliceError, >146     pub fn from_slice(
147         slice: &[u8],
148     ) -> Result<
149         (
150             LaxIpSlice,
151             Option<(err::ipv6_exts::HeaderSliceError, err::Layer)>,
152         ),
153         err::ip::LaxHeaderSliceError,
154     > {
155         use crate::ip_number::AUTH;
156         use err::ip::HeaderError::*;
157         use err::ip::LaxHeaderSliceError as E;
158         use err::ipv6_exts::HeaderError as SH;
159         use err::ipv6_exts::HeaderSliceError as S;
160         use LaxIpSlice::*;
161 
162         if slice.is_empty() {
163             Err(E::Len(err::LenError {
164                 required_len: 1,
165                 len: slice.len(),
166                 len_source: LenSource::Slice,
167                 layer: err::Layer::IpHeader,
168                 layer_start_offset: 0,
169             }))
170         } else {
171             // SAFETY: Safe as slice is not empty.
172             let first_byte = unsafe { slice.get_unchecked(0) };
173             match first_byte >> 4 {
174                 4 => {
175                     let ihl = first_byte & 0xf;
176 
177                     // check that the ihl has at least the length of the base IPv4 header
178                     if ihl < 5 {
179                         return Err(E::Content(Ipv4HeaderLengthSmallerThanHeader { ihl }));
180                     }
181 
182                     // check there is enough data for the header
183                     let header_len = (usize::from(ihl)) * 4;
184                     if slice.len() < header_len {
185                         return Err(E::Len(LenError {
186                             required_len: header_len,
187                             len: slice.len(),
188                             len_source: LenSource::Slice,
189                             layer: Layer::Ipv4Header,
190                             layer_start_offset: 0,
191                         }));
192                     }
193 
194                     // SAFETY:
195                     // Safe as the slice length is checked to be at least
196                     // header_len or greater above.
197                     let header = unsafe {
198                         Ipv4HeaderSlice::from_slice_unchecked(core::slice::from_raw_parts(
199                             slice.as_ptr(),
200                             header_len,
201                         ))
202                     };
203 
204                     // check the total_lenat least contains the header
205                     let total_len = usize::from(header.total_len());
206 
207                     let (header_payload, len_source, incomplete) = if total_len < header_len {
208                         // fallback to slice len
209                         (
210                             unsafe {
211                                 core::slice::from_raw_parts(
212                                     // SAFETY: Safe as slice.len() >= header_len was validated
213                                     // in a if statement above.
214                                     slice.as_ptr().add(header_len),
215                                     // SAFETY: Safe as slice.len() >= header_len was validated
216                                     // in a if statement above.
217                                     slice.len() - header_len,
218                                 )
219                             },
220                             LenSource::Slice,
221                             false,
222                         )
223                     } else if slice.len() < total_len {
224                         // fallback to slice len
225                         (
226                             unsafe {
227                                 core::slice::from_raw_parts(
228                                     // SAFETY: Safe as slice.len() >= header_len was validated
229                                     // in a if statement above.
230                                     slice.as_ptr().add(header_len),
231                                     // SAFETY: Safe as slice.len() >= header_len was validated
232                                     // in a if statement above.
233                                     slice.len() - header_len,
234                                 )
235                             },
236                             LenSource::Slice,
237                             true, // flag payload as incomplete
238                         )
239                     } else {
240                         (
241                             unsafe {
242                                 core::slice::from_raw_parts(
243                                     // SAFETY: Safe as slice.len() >= header_len was validated
244                                     // in a if statement above.
245                                     slice.as_ptr().add(header_len),
246                                     // SAFETY: Safe as total_length >= header_len was verfied in an
247                                     // if statement above as well as that slice.len() >= total_length_usize.
248                                     total_len - header_len,
249                                 )
250                             },
251                             LenSource::Ipv4HeaderTotalLen,
252                             false,
253                         )
254                     };
255 
256                     // slice extension headers
257                     // decode the authentication header if needed
258                     let fragmented = header.is_fragmenting_payload();
259                     match header.protocol() {
260                         AUTH => {
261                             use crate::err::ip_auth::HeaderSliceError as A;
262 
263                             // parse extension headers
264                             match IpAuthHeaderSlice::from_slice(header_payload) {
265                                 Ok(auth) => {
266                                     // remove the extension header from the payload
267                                     let payload = unsafe {
268                                         core::slice::from_raw_parts(
269                                             header_payload.as_ptr().add(auth.slice().len()),
270                                             header_payload.len() - auth.slice().len(),
271                                         )
272                                     };
273                                     Ok((
274                                         Ipv4(LaxIpv4Slice {
275                                             header,
276                                             exts: Ipv4ExtensionsSlice { auth: Some(auth) },
277                                             payload: LaxIpPayloadSlice {
278                                                 incomplete,
279                                                 ip_number: auth.next_header(),
280                                                 fragmented,
281                                                 len_source,
282                                                 payload,
283                                             },
284                                         }),
285                                         None,
286                                     ))
287                                 }
288                                 Err(err) => {
289                                     let ip_number = header.protocol();
290                                     Ok((
291                                         Ipv4(LaxIpv4Slice {
292                                             header,
293                                             exts: Ipv4ExtensionsSlice { auth: None },
294                                             payload: LaxIpPayloadSlice {
295                                                 incomplete,
296                                                 ip_number,
297                                                 fragmented,
298                                                 len_source,
299                                                 payload: header_payload,
300                                             },
301                                         }),
302                                         match err {
303                                             A::Len(mut l) => Some((
304                                                 S::Len({
305                                                     l.len_source = len_source;
306                                                     l.add_offset(header.slice().len())
307                                                 }),
308                                                 err::Layer::IpAuthHeader,
309                                             )),
310                                             A::Content(l) => Some((
311                                                 S::Content(SH::IpAuth(l)),
312                                                 err::Layer::IpAuthHeader,
313                                             )),
314                                         },
315                                     ))
316                                 }
317                             }
318                         }
319                         ip_number => Ok((
320                             Ipv4(LaxIpv4Slice {
321                                 header,
322                                 exts: Ipv4ExtensionsSlice { auth: None },
323                                 payload: LaxIpPayloadSlice {
324                                     incomplete,
325                                     ip_number,
326                                     fragmented,
327                                     len_source,
328                                     payload: header_payload,
329                                 },
330                             }),
331                             None,
332                         )),
333                     }
334                 }
335                 6 => {
336                     // check length
337                     if slice.len() < Ipv6Header::LEN {
338                         return Err(E::Len(LenError {
339                             required_len: Ipv6Header::LEN,
340                             len: slice.len(),
341                             len_source: LenSource::Slice,
342                             layer: Layer::Ipv6Header,
343                             layer_start_offset: 0,
344                         }));
345                     }
346 
347                     let header = unsafe {
348                         Ipv6HeaderSlice::from_slice_unchecked(core::slice::from_raw_parts(
349                             slice.as_ptr(),
350                             Ipv6Header::LEN,
351                         ))
352                     };
353 
354                     // restrict slice by the length specified in the header (if possible)
355                     let payload_len = usize::from(header.payload_length());
356                     let (header_payload, len_source, incomplete) =
357                         if 0 == payload_len && slice.len() > Ipv6Header::LEN {
358                             // zero set as payload len, assume jumbograms or unitialized
359                             // length and use the slice length as a fallback value
360                             // TODO: Add payload length parsing from the jumbogram for the zero case
361                             (
362                                 unsafe {
363                                     core::slice::from_raw_parts(
364                                         slice.as_ptr().add(Ipv6Header::LEN),
365                                         slice.len() - Ipv6Header::LEN,
366                                     )
367                                 },
368                                 LenSource::Slice,
369                                 false,
370                             )
371                         } else if slice.len() - Ipv6Header::LEN < payload_len {
372                             // slice is smaller then the assumed payload length
373                             (
374                                 unsafe {
375                                     core::slice::from_raw_parts(
376                                         slice.as_ptr().add(Ipv6Header::LEN),
377                                         slice.len() - Ipv6Header::LEN,
378                                     )
379                                 },
380                                 LenSource::Slice,
381                                 true, // incomplete
382                             )
383                         } else {
384                             // all good, all data should be here
385                             (
386                                 unsafe {
387                                     core::slice::from_raw_parts(
388                                         slice.as_ptr().add(Ipv6Header::LEN),
389                                         payload_len,
390                                     )
391                                 },
392                                 LenSource::Ipv6HeaderPayloadLen,
393                                 false,
394                             )
395                         };
396 
397                     // parse extension headers
398                     let (exts, payload_ip_number, payload, mut ext_stop_err) =
399                         Ipv6ExtensionsSlice::from_slice_lax(header.next_header(), header_payload);
400 
401                     // add len offset
402                     if let Some((S::Len(l), _)) = ext_stop_err.as_mut() {
403                         l.len_source = len_source;
404                         l.layer_start_offset += header.header_len();
405                     }
406                     let fragmented = exts.is_fragmenting_payload();
407                     Ok((
408                         Ipv6(LaxIpv6Slice {
409                             header,
410                             exts,
411                             payload: LaxIpPayloadSlice {
412                                 incomplete,
413                                 ip_number: payload_ip_number,
414                                 fragmented,
415                                 len_source,
416                                 payload,
417                             },
418                         }),
419                         ext_stop_err,
420                     ))
421                 }
422                 version_number => Err(E::Content(UnsupportedIpVersion { version_number })),
423             }
424         }
425     }
426 }
427 
428 impl<'a> From<LaxIpv4Slice<'a>> for LaxIpSlice<'a> {
from(value: LaxIpv4Slice<'a>) -> Self429     fn from(value: LaxIpv4Slice<'a>) -> Self {
430         LaxIpSlice::Ipv4(value)
431     }
432 }
433 
434 impl<'a> From<LaxIpv6Slice<'a>> for LaxIpSlice<'a> {
from(value: LaxIpv6Slice<'a>) -> Self435     fn from(value: LaxIpv6Slice<'a>) -> Self {
436         LaxIpSlice::Ipv6(value)
437     }
438 }
439 
440 #[cfg(test)]
441 mod test {
442     use super::*;
443     use crate::test_gens::*;
444     use alloc::{format, vec::Vec};
445     use proptest::prelude::*;
446     use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
447 
448     #[test]
debug_clone_eq()449     fn debug_clone_eq() {
450         // ipv4
451         {
452             let mut header: Ipv4Header = Default::default();
453             header.protocol = ip_number::UDP;
454             header.set_payload_len(0).unwrap();
455             let buffer = header.to_bytes();
456 
457             let ipv4 = LaxIpv4Slice::from_slice(&buffer).unwrap().0;
458             let slice = LaxIpSlice::Ipv4(ipv4.clone());
459 
460             // clone & eq
461             assert_eq!(slice.clone(), slice);
462 
463             // debug
464             assert_eq!(format!("{:?}", slice), format!("Ipv4({:?})", ipv4));
465         }
466         // ipv6
467         {
468             let header = Ipv6Header {
469                 payload_length: 0,
470                 next_header: ip_number::UDP,
471                 ..Default::default()
472             };
473             let buffer = header.to_bytes();
474             let ipv6 = LaxIpv6Slice::from_slice(&buffer).unwrap().0;
475             let slice = LaxIpSlice::Ipv6(ipv6.clone());
476 
477             // clone & eq
478             assert_eq!(slice.clone(), slice);
479 
480             // debug
481             assert_eq!(format!("{:?}", slice), format!("Ipv6({:?})", ipv6));
482         }
483     }
484 
485     #[test]
is_fragmenting_payload()486     fn is_fragmenting_payload() {
487         for fragment in [false, true] {
488             use ip_number::UDP;
489             // ipv4
490             {
491                 let mut ipv4 = Ipv4Header::new(0, 1, UDP, [3, 4, 5, 6], [7, 8, 9, 10]).unwrap();
492                 if fragment {
493                     ipv4.fragment_offset = 123.try_into().unwrap();
494                 }
495 
496                 let data = ipv4.to_bytes();
497                 let ipv4_slice = LaxIpv4Slice::from_slice(&data).unwrap().0;
498                 assert_eq!(
499                     fragment,
500                     LaxIpSlice::Ipv4(ipv4_slice).is_fragmenting_payload()
501                 );
502             }
503 
504             // ipv6
505             {
506                 let ipv6_frag = Ipv6FragmentHeader {
507                     next_header: UDP,
508                     fragment_offset: IpFragOffset::ZERO,
509                     more_fragments: fragment,
510                     identification: 0,
511                 };
512                 let ipv6 = Ipv6Header {
513                     traffic_class: 0,
514                     flow_label: 1.try_into().unwrap(),
515                     payload_length: ipv6_frag.header_len() as u16,
516                     next_header: ip_number::IPV6_FRAG,
517                     hop_limit: 4,
518                     source: [1; 16],
519                     destination: [2; 16],
520                 };
521                 let mut data = Vec::with_capacity(ipv6.header_len() + ipv6_frag.header_len());
522                 data.extend_from_slice(&ipv6.to_bytes());
523                 data.extend_from_slice(&ipv6_frag.to_bytes());
524 
525                 assert_eq!(
526                     fragment,
527                     LaxIpSlice::Ipv6(LaxIpv6Slice::from_slice(&data).unwrap().0)
528                         .is_fragmenting_payload()
529                 );
530             }
531         }
532     }
533 
534     #[cfg(feature = "std")]
535     #[test]
source_addr()536     fn source_addr() {
537         // ipv4
538         {
539             let data = Ipv4Header::new(0, 1, 2.into(), [3, 4, 5, 6], [7, 8, 9, 10])
540                 .unwrap()
541                 .to_bytes();
542             assert_eq!(
543                 IpAddr::V4(Ipv4Addr::from([3, 4, 5, 6])),
544                 LaxIpSlice::Ipv4(LaxIpv4Slice::from_slice(&data[..]).unwrap().0).source_addr()
545             );
546         }
547 
548         // ipv6
549         {
550             let data = Ipv6Header {
551                 traffic_class: 0,
552                 flow_label: 1.try_into().unwrap(),
553                 payload_length: 0,
554                 next_header: ip_number::IGMP,
555                 hop_limit: 4,
556                 source: [1; 16],
557                 destination: [2; 16],
558             }
559             .to_bytes();
560 
561             assert_eq!(
562                 IpAddr::V6(Ipv6Addr::from([1; 16])),
563                 LaxIpSlice::Ipv6(LaxIpv6Slice::from_slice(&data[..]).unwrap().0).source_addr()
564             );
565         }
566     }
567 
568     #[cfg(feature = "std")]
569     #[test]
destination_addr()570     fn destination_addr() {
571         use crate::ip_number::UDP;
572 
573         // ipv4
574         {
575             let data = Ipv4Header::new(0, 1, UDP, [3, 4, 5, 6], [7, 8, 9, 10])
576                 .unwrap()
577                 .to_bytes();
578 
579             assert_eq!(
580                 IpAddr::V4(Ipv4Addr::from([7, 8, 9, 10])),
581                 LaxIpSlice::Ipv4(LaxIpv4Slice::from_slice(&data[..]).unwrap().0).destination_addr()
582             );
583         }
584 
585         // ipv6
586         {
587             let data = Ipv6Header {
588                 traffic_class: 0,
589                 flow_label: 1.try_into().unwrap(),
590                 payload_length: 0,
591                 next_header: ip_number::IGMP,
592                 hop_limit: 4,
593                 source: [1; 16],
594                 destination: [2; 16],
595             }
596             .to_bytes();
597 
598             assert_eq!(
599                 IpAddr::V6(Ipv6Addr::from([2; 16])),
600                 LaxIpSlice::Ipv6(LaxIpv6Slice::from_slice(&data).unwrap().0).destination_addr()
601             );
602         }
603     }
604 
605     #[test]
ip_payload()606     fn ip_payload() {
607         let payload: [u8; 4] = [1, 2, 3, 4];
608         // ipv4
609         {
610             let header = Ipv4Header::new(
611                 payload.len() as u16,
612                 1,
613                 ip_number::UDP,
614                 [3, 4, 5, 6],
615                 [7, 8, 9, 10],
616             )
617             .unwrap();
618             let mut data = Vec::with_capacity(header.header_len() + payload.len());
619             data.extend_from_slice(&header.to_bytes());
620             data.extend_from_slice(&payload);
621             assert_eq!(
622                 LaxIpSlice::Ipv4(LaxIpv4Slice::from_slice(&data[..]).unwrap().0).payload(),
623                 &LaxIpPayloadSlice {
624                     incomplete: false,
625                     ip_number: ip_number::UDP.into(),
626                     fragmented: header.is_fragmenting_payload(),
627                     len_source: LenSource::Ipv4HeaderTotalLen,
628                     payload: &payload,
629                 }
630             );
631         }
632 
633         // ipv6
634         {
635             let header = Ipv6Header {
636                 traffic_class: 0,
637                 flow_label: 1.try_into().unwrap(),
638                 payload_length: payload.len() as u16,
639                 next_header: ip_number::UDP,
640                 hop_limit: 4,
641                 source: [1; 16],
642                 destination: [2; 16],
643             };
644             let mut data = Vec::with_capacity(header.header_len() + payload.len());
645             data.extend_from_slice(&header.to_bytes());
646             data.extend_from_slice(&payload);
647             assert_eq!(
648                 LaxIpSlice::Ipv6(LaxIpv6Slice::from_slice(&data[..]).unwrap().0).payload(),
649                 &LaxIpPayloadSlice {
650                     incomplete: false,
651                     ip_number: ip_number::UDP.into(),
652                     fragmented: false,
653                     len_source: LenSource::Ipv6HeaderPayloadLen,
654                     payload: &payload,
655                 }
656             );
657         }
658     }
659 
660     #[test]
payload_ip_number()661     fn payload_ip_number() {
662         use crate::ip_number::{IGMP, UDP};
663 
664         // ipv4
665         {
666             let data = Ipv4Header::new(0, 1, UDP, [3, 4, 5, 6], [7, 8, 9, 10])
667                 .unwrap()
668                 .to_bytes();
669             assert_eq!(
670                 UDP,
671                 LaxIpSlice::Ipv4(LaxIpv4Slice::from_slice(&data[..]).unwrap().0)
672                     .payload_ip_number()
673             );
674         }
675 
676         // ipv6
677         {
678             let data = Ipv6Header {
679                 traffic_class: 0,
680                 flow_label: 1.try_into().unwrap(),
681                 payload_length: 0,
682                 next_header: IGMP,
683                 hop_limit: 4,
684                 source: [1; 16],
685                 destination: [2; 16],
686             }
687             .to_bytes();
688 
689             assert_eq!(
690                 IGMP,
691                 LaxIpSlice::Ipv6(LaxIpv6Slice::from_slice(&data).unwrap().0).payload_ip_number()
692             );
693         }
694     }
695 
696     proptest! {
697         #[test]
698         fn from_ip_slice(
699             ipv4_header in ipv4_any(),
700             ipv4_exts in ipv4_extensions_with(ip_number::UDP),
701             ipv6_header in ipv6_any(),
702             mut ipv6_exts in ipv6_extensions_with(ip_number::UDP)
703         ) {
704             use err::ip::HeaderError::*;
705             use err::ip::LaxHeaderSliceError as E;
706             use err::ipv6_exts::HeaderSliceError as S;
707             use err::ip_auth::HeaderError::*;
708             use crate::IpHeaders;
709 
710             // zero payload
711             assert_eq!(
712                 LaxIpSlice::from_slice(&[]),
713                 Err(E::Len(LenError{
714                     required_len: 1,
715                     len: 0,
716                     len_source: LenSource::Slice,
717                     layer: Layer::IpHeader,
718                     layer_start_offset: 0,
719                 }))
720             );
721 
722             // unknown version number
723             for bad_version in 0..0xfu8 {
724                 if bad_version != 4 && bad_version != 6 {
725                     assert_eq!(
726                         LaxIpSlice::from_slice(&[bad_version << 4]),
727                         Err(E::Content(UnsupportedIpVersion {
728                             version_number: bad_version,
729                         }))
730                     );
731                 }
732             }
733 
734             let payload = [1,2,3,4];
735 
736             // IPv4
737             {
738                 // setup header length & fields
739                 let ipv4_header = {
740                     let mut header = ipv4_header;
741                     header.protocol = if ipv4_exts.auth.is_some() {
742                         ip_number::AUTH
743                     } else {
744                         ip_number::UDP
745                     };
746                     header.total_len = (header.header_len() + ipv4_exts.header_len() + payload.len()) as u16;
747                     header.header_checksum = header.calc_header_checksum();
748                     header
749                 };
750 
751                 let ipv4 = IpHeaders::Ipv4(
752                     ipv4_header.clone(),
753                     ipv4_exts.clone()
754                 );
755 
756                 // build packet
757                 let mut buffer = Vec::with_capacity(ipv4.header_len() + payload.len());
758                 ipv4.write(&mut buffer).unwrap();
759                 buffer.extend_from_slice(&payload);
760 
761                 // happy path v4
762                 {
763                     // run test
764                     let (actual, actual_stop_err) = LaxIpSlice::from_slice(&buffer).unwrap();
765                     assert_eq!(None, actual_stop_err);
766                     assert!(actual.ipv6().is_none());
767                     let actual = actual.ipv4().unwrap().clone();
768                     assert_eq!(actual.header.to_header(), ipv4_header);
769                     assert_eq!(actual.extensions().to_header(), ipv4_exts);
770                     assert_eq!(
771                         actual.payload,
772                         LaxIpPayloadSlice{
773                             incomplete: false,
774                             ip_number: ip_number::UDP.into(),
775                             fragmented: ipv4_header.is_fragmenting_payload(),
776                             len_source: LenSource::Ipv4HeaderTotalLen,
777                             payload: &payload
778                         }
779                     );
780                 }
781 
782                 // ihl smaller then 5 error
783                 for bad_ihl in 0..5u8 {
784                     let mut buffer = buffer.clone();
785 
786                     // inject bad IHL
787                     buffer[0] = (buffer[0] & 0xf0u8) | bad_ihl;
788 
789                     assert_eq!(
790                         LaxIpSlice::from_slice(&buffer),
791                         Err(E::Content(Ipv4HeaderLengthSmallerThanHeader { ihl: bad_ihl }))
792                     );
793                 }
794 
795                 // slice smaller then header error
796                 for bad_len in 1..ipv4_header.header_len() {
797                     assert_eq!(
798                         LaxIpSlice::from_slice(&buffer[..bad_len]),
799                         Err(E::Len(LenError{
800                             required_len: ipv4_header.header_len(),
801                             len: bad_len,
802                             len_source: LenSource::Slice,
803                             layer: Layer::Ipv4Header,
804                             layer_start_offset: 0,
805                         }))
806                     );
807                 }
808 
809                 // total len smaller then header
810                 for bad_len in 1..ipv4_header.header_len() {
811                     let mut buffer = buffer.clone();
812 
813                     // inject bad total length
814                     let bad_len_be = (bad_len as u16).to_be_bytes();
815                     buffer[2] = bad_len_be[0];
816                     buffer[3] = bad_len_be[1];
817 
818                     // expect a valid parse with length source "slice"
819                     let (actual, actual_stop_err) = LaxIpSlice::from_slice(&buffer).unwrap();
820                     assert_eq!(None, actual_stop_err);
821                     let actual = actual.ipv4().unwrap().clone();
822                     let mut expected_header = ipv4_header.clone();
823                     expected_header.total_len = bad_len as u16;
824                     assert_eq!(actual.header.to_header(), expected_header);
825                     assert_eq!(actual.extensions().to_header(), ipv4_exts);
826                     assert_eq!(
827                         actual.payload,
828                         LaxIpPayloadSlice{
829                             incomplete: false,
830                             ip_number: ip_number::UDP.into(),
831                             fragmented: ipv4_header.is_fragmenting_payload(),
832                             len_source: LenSource::Slice,
833                             payload: &payload
834                         }
835                     );
836                 }
837 
838                 // total len bigger then slice
839                 {
840                     let bad_len = (buffer.len() + 1) as u16;
841                     let mut buffer = buffer.clone();
842 
843                     // inject bad total length
844                     let bad_len_be = (bad_len as u16).to_be_bytes();
845                     buffer[2] = bad_len_be[0];
846                     buffer[3] = bad_len_be[1];
847 
848                     // expect a valid parse with length source "slice" & incomplete set
849                     let (actual, actual_stop_err) = LaxIpSlice::from_slice(&buffer).unwrap();
850                     assert_eq!(None, actual_stop_err);
851                     let actual = actual.ipv4().unwrap().clone();
852                     let mut expected_header = ipv4_header.clone();
853                     expected_header.total_len = bad_len as u16;
854                     assert_eq!(actual.header.to_header(), expected_header);
855                     assert_eq!(actual.extensions().to_header(), ipv4_exts);
856                     assert_eq!(
857                         actual.payload,
858                         LaxIpPayloadSlice{
859                             incomplete: true,
860                             ip_number: ip_number::UDP.into(),
861                             fragmented: ipv4_header.is_fragmenting_payload(),
862                             len_source: LenSource::Slice,
863                             payload: &payload
864                         }
865                     );
866                 }
867 
868                 // auth ext header len error
869                 if ipv4_exts.auth.is_some() {
870                     let bad_len = ipv4_header.header_len() + ipv4_exts.header_len() - 1;
871 
872                     let (actual, actual_stop_err) = LaxIpSlice::from_slice(&buffer[..bad_len]).unwrap();
873                     assert_eq!(
874                         actual_stop_err,
875                         Some((
876                             S::Len(LenError{
877                                 required_len: ipv4_exts.header_len(),
878                                 len: bad_len - ipv4_header.header_len(),
879                                 len_source: LenSource::Slice,
880                                 layer: Layer::IpAuthHeader,
881                                 layer_start_offset: ipv4_header.header_len(),
882                             }),
883                             Layer::IpAuthHeader
884                         ))
885                     );
886                     assert_eq!(actual.ipv4().unwrap().clone().header().to_header(), ipv4_header);
887                     assert_eq!(
888                         actual.payload(),
889                         &LaxIpPayloadSlice{
890                             incomplete: true,
891                             ip_number: ip_number::AUTH,
892                             fragmented: ipv4_header.is_fragmenting_payload(),
893                             len_source: LenSource::Slice,
894                             payload: &buffer[ipv4_header.header_len()..bad_len],
895                         }
896                     );
897                 }
898 
899                 // auth ext header content error
900                 if ipv4_exts.auth.is_some() {
901                     let mut buffer = buffer.clone();
902                     buffer[ipv4_header.header_len() + 1] = 0;
903 
904                     let (actual, actual_stop_err) = LaxIpSlice::from_slice(&buffer).unwrap();
905 
906                     assert_eq!(
907                         actual_stop_err,
908                         Some((
909                             S::Content(ipv6_exts::HeaderError::IpAuth(ZeroPayloadLen)),
910                             Layer::IpAuthHeader
911                         ))
912                     );
913                     assert_eq!(actual.ipv4().unwrap().clone().header().to_header(), ipv4_header);
914                     assert_eq!(
915                         actual.payload(),
916                         &LaxIpPayloadSlice{
917                             incomplete: false,
918                             ip_number: ip_number::AUTH,
919                             fragmented: ipv4_header.is_fragmenting_payload(),
920                             len_source: LenSource::Ipv4HeaderTotalLen,
921                             payload: &buffer[ipv4_header.header_len()..],
922                         }
923                     );
924                 }
925             }
926 
927             // IPv6
928             {
929                 let ipv6_header = {
930                     let mut header = ipv6_header;
931                     header.next_header = ipv6_exts.set_next_headers(ip_number::UDP);
932                     header.payload_length = (ipv6_exts.header_len() + payload.len()) as u16;
933                     header
934                 };
935 
936                 let ipv6 = IpHeaders::Ipv6(
937                     ipv6_header.clone(),
938                     ipv6_exts.clone()
939                 );
940 
941                 // build packet
942                 let mut buffer = Vec::with_capacity(ipv6.header_len() + payload.len());
943                 ipv6.write(&mut buffer).unwrap();
944                 buffer.extend_from_slice(&payload);
945 
946                 // happy path v6
947                 {
948                     // run test
949                     let (actual, actual_stop_err) = LaxIpSlice::from_slice(&buffer).unwrap();
950                     assert_eq!(None, actual_stop_err);
951                     assert!(actual.ipv4().is_none());
952                     let actual = actual.ipv6().unwrap().clone();
953                     assert_eq!(actual.header.to_header(), ipv6_header);
954                     assert_eq!(
955                         Ipv6Extensions::from_slice(
956                             ipv6_header.next_header,
957                             actual.extensions().slice()
958                         ).unwrap().0,
959                         ipv6_exts
960                     );
961                     assert_eq!(
962                         actual.payload,
963                         LaxIpPayloadSlice{
964                             incomplete: false,
965                             ip_number: ip_number::UDP.into(),
966                             fragmented: ipv6_exts.is_fragmenting_payload(),
967                             len_source: LenSource::Ipv6HeaderPayloadLen,
968                             payload: &payload
969                         }
970                     );
971                 }
972 
973                 // len error when parsing header
974                 for bad_len in 1..ipv6_header.header_len() {
975                     assert_eq!(
976                         LaxIpSlice::from_slice(&buffer[..bad_len]),
977                         Err(E::Len(LenError{
978                             required_len: ipv6_header.header_len(),
979                             len: bad_len,
980                             len_source: LenSource::Slice,
981                             layer: Layer::Ipv6Header,
982                             layer_start_offset: 0,
983                         }))
984                     );
985                 }
986 
987                 // ipv6 with zero payload length (should fallback to the slice length)
988                 {
989                     let mut buffer = buffer.clone();
990 
991                     // inject 0 as payload len
992                     buffer[4] = 0;
993                     buffer[5] = 0;
994 
995                     // run test
996                     let (actual, actual_stop_err) = LaxIpSlice::from_slice(&buffer).unwrap();
997                     assert_eq!(None, actual_stop_err);
998                     let actual = actual.ipv6().unwrap().clone();
999                     let mut expected_header = ipv6_header.clone();
1000                     expected_header.payload_length = 0;
1001                     assert_eq!(actual.header.to_header(), expected_header);
1002                     assert_eq!(
1003                         Ipv6Extensions::from_slice(
1004                             ipv6_header.next_header,
1005                             actual.extensions().slice()
1006                         ).unwrap().0,
1007                         ipv6_exts
1008                     );
1009                     assert_eq!(
1010                         actual.payload,
1011                         LaxIpPayloadSlice{
1012                             incomplete: false,
1013                             ip_number: ip_number::UDP.into(),
1014                             fragmented: ipv6_exts.is_fragmenting_payload(),
1015                             len_source: LenSource::Slice,
1016                             payload: &payload
1017                         }
1018                     );
1019                 }
1020 
1021                 // payload len bigger then slice
1022                 {
1023                     let mut buffer = buffer.clone();
1024 
1025                     // inject 0 as payload len
1026                     let bad_payload_len = (buffer.len() - ipv6_header.header_len() + 1) as u16;
1027                     let bad_payload_len_be = bad_payload_len.to_be_bytes();
1028                     buffer[4] = bad_payload_len_be[0];
1029                     buffer[5] = bad_payload_len_be[1];
1030 
1031                     // run test
1032                     let (actual, actual_stop_err) = LaxIpSlice::from_slice(&buffer).unwrap();
1033                     assert_eq!(None, actual_stop_err);
1034                     let actual = actual.ipv6().unwrap().clone();
1035                     let mut expected_header = ipv6_header.clone();
1036                     expected_header.payload_length = bad_payload_len;
1037 
1038                     assert_eq!(actual.header.to_header(), expected_header);
1039                     assert_eq!(
1040                         Ipv6Extensions::from_slice(
1041                             ipv6_header.next_header,
1042                             actual.extensions().slice()
1043                         ).unwrap().0,
1044                         ipv6_exts
1045                     );
1046                     assert_eq!(
1047                         actual.payload,
1048                         LaxIpPayloadSlice{
1049                             incomplete: true,
1050                             ip_number: ip_number::UDP.into(),
1051                             fragmented: ipv6_exts.is_fragmenting_payload(),
1052                             len_source: LenSource::Slice,
1053                             payload: &payload
1054                         }
1055                     );
1056                 }
1057 
1058                 // extension length error
1059                 if ipv6_exts.hop_by_hop_options.is_some() {
1060                     let bad_len = Ipv6Header::LEN + 1;
1061 
1062                     let (actual, actual_stop_err) = LaxIpSlice::from_slice(&buffer[..bad_len]).unwrap();
1063 
1064                     let actual = actual.ipv6().unwrap().clone();
1065                     assert_eq!(actual.header.to_header(), ipv6_header);
1066                     assert_eq!(
1067                         actual_stop_err,
1068                         Some((
1069                             S::Len(LenError{
1070                                 required_len: 8,
1071                                 len: bad_len - ipv6_header.header_len(),
1072                                 len_source: LenSource::Slice,
1073                                 layer: Layer::Ipv6ExtHeader,
1074                                 layer_start_offset: ipv6_header.header_len(),
1075                             }),
1076                             Layer::Ipv6HopByHopHeader
1077                         ))
1078                     );
1079                     assert_eq!(
1080                         actual.payload,
1081                         LaxIpPayloadSlice{
1082                             incomplete: true,
1083                             ip_number: ip_number::IPV6_HOP_BY_HOP,
1084                             fragmented: false, // fragment header will not be able to be read
1085                             len_source: LenSource::Slice,
1086                             payload: &buffer[ipv6_header.header_len()..bad_len]
1087                         }
1088                     );
1089                 }
1090 
1091                 // extension content error
1092                 if ipv6_exts.auth.is_some() {
1093 
1094                     // introduce a auth header zero payload error
1095                     let mut buffer = buffer.clone();
1096                     let auth_offset = ipv6_header.header_len() +
1097                         ipv6_exts.hop_by_hop_options.as_ref().map(|h| h.header_len()).unwrap_or(0) +
1098                         ipv6_exts.destination_options.as_ref().map(|h| h.header_len()).unwrap_or(0) +
1099                         ipv6_exts.routing.as_ref().map(|h| h.routing.header_len()).unwrap_or(0) +
1100                         // routing.final_destination_options skiped, as after auth
1101                         ipv6_exts.fragment.as_ref().map(|h| h.header_len()).unwrap_or(0);
1102 
1103                     // inject length zero into auth header (not valid, will
1104                     // trigger a content error)
1105                     buffer[auth_offset + 1] = 0;
1106 
1107                     let (actual, actual_stop_err) = LaxIpSlice::from_slice(&buffer).unwrap();
1108                     let actual = actual.ipv6().unwrap().clone();
1109                     assert_eq!(actual.header.to_header(), ipv6_header);
1110                     assert_eq!(
1111                         actual_stop_err,
1112                         Some((
1113                             S::Content(ipv6_exts::HeaderError::IpAuth(ZeroPayloadLen)),
1114                             Layer::IpAuthHeader,
1115                         ))
1116                     );
1117                 }
1118             }
1119         }
1120     }
1121 
1122     proptest! {
1123         #[test]
1124         fn from_ipv4_slice(
1125             ipv4_header in ipv4_unknown()
1126         ) {
1127             let mut header = ipv4_header.clone();
1128             header.total_len = (header.header_len() + 4) as u16;
1129 
1130             let mut buffer = Vec::with_capacity(header.total_len.into());
1131             buffer.extend_from_slice(&header.to_bytes()[..]);
1132             buffer.extend_from_slice(&[1,2,3,4]);
1133             let s = LaxIpv4Slice::from_slice(&buffer).unwrap().0;
1134             let actual: LaxIpSlice = s.clone().into();
1135             assert_eq!(LaxIpSlice::Ipv4(s), actual);
1136         }
1137     }
1138 
1139     proptest! {
1140         #[test]
1141         fn from_ipv6_slice(
1142             ipv6_header in ipv6_unknown()
1143         ) {
1144             let mut header = ipv6_header.clone();
1145             header.payload_length = 4;
1146 
1147             let mut buffer = Vec::with_capacity(header.header_len() + 4);
1148             buffer.extend_from_slice(&header.to_bytes()[..]);
1149             buffer.extend_from_slice(&[1,2,3,4]);
1150             let s = LaxIpv6Slice::from_slice(&buffer).unwrap().0;
1151             let actual: LaxIpSlice = s.clone().into();
1152             assert_eq!(LaxIpSlice::Ipv6(s), actual);
1153         }
1154     }
1155 }
1156