1 #[cfg(feature = "std")]
2 use crate::err::ip::HeadersWriteError;
3 use crate::err::{Layer, LenError, ValueTooBigError};
4 use crate::*;
5 
6 /// Internet protocol headers version 4 & 6.
7 #[derive(Clone, Debug, Eq, PartialEq)]
8 #[allow(clippy::large_enum_variant)]
9 pub enum IpHeaders {
10     /// IPv4 header & extension headers.
11     Ipv4(Ipv4Header, Ipv4Extensions),
12     /// IPv6 header & extension headers.
13     Ipv6(Ipv6Header, Ipv6Extensions),
14 }
15 
16 impl IpHeaders {
17     /// Maximum summed up length of all extension headers in bytes/octets.
18     pub const MAX_LEN: usize = Ipv6Header::LEN + Ipv6Extensions::MAX_LEN;
19 
20     /// Returns references to the IPv4 header & extensions if the header contains IPv4 values.
ipv4(&self) -> Option<(&Ipv4Header, &Ipv4Extensions)>21     pub fn ipv4(&self) -> Option<(&Ipv4Header, &Ipv4Extensions)> {
22         if let IpHeaders::Ipv4(header, exts) = self {
23             Some((header, exts))
24         } else {
25             None
26         }
27     }
28 
29     /// Returns references to the IPv6 header & extensions if the header contains IPv6 values.
ipv6(&self) -> Option<(&Ipv6Header, &Ipv6Extensions)>30     pub fn ipv6(&self) -> Option<(&Ipv6Header, &Ipv6Extensions)> {
31         if let IpHeaders::Ipv6(header, exts) = self {
32             Some((header, exts))
33         } else {
34             None
35         }
36     }
37 
38     /// Renamed to [`IpHeaders::from_slice`]
39     #[deprecated(since = "0.10.1", note = "Renamed to `IpHeaders::from_slice`")]
40     #[inline]
read_from_slice( slice: &[u8], ) -> Result<(IpHeaders, IpNumber, &[u8]), err::ip::HeadersSliceError>41     pub fn read_from_slice(
42         slice: &[u8],
43     ) -> Result<(IpHeaders, IpNumber, &[u8]), err::ip::HeadersSliceError> {
44         let (header, payload) = IpHeaders::from_slice(slice)?;
45         Ok((header, payload.ip_number, payload.payload))
46     }
47 
48     /// Read an [`IpHeaders`] from a slice and return the headers & payload of
49     /// the IP packet (determined based on the length fields in the IP header).
50     ///
51     /// Note that his function returns an [`crate::err::LenError`] if the given slice
52     /// contains less data then the length fields in the IP header indicate should
53     /// be present.
54     ///
55     /// If you want to ignore these kind of length errors based on the length
56     /// fields in the IP headers use [`IpHeaders::from_slice_lax`] instead.
from_slice( slice: &[u8], ) -> Result<(IpHeaders, IpPayloadSlice<'_>), err::ip::HeadersSliceError>57     pub fn from_slice(
58         slice: &[u8],
59     ) -> Result<(IpHeaders, IpPayloadSlice<'_>), err::ip::HeadersSliceError> {
60         use err::ip::{HeaderError::*, HeadersError::*, HeadersSliceError::*};
61 
62         if slice.is_empty() {
63             Err(Len(err::LenError {
64                 required_len: 1,
65                 len: slice.len(),
66                 len_source: LenSource::Slice,
67                 layer: err::Layer::IpHeader,
68                 layer_start_offset: 0,
69             }))
70         } else {
71             match slice[0] >> 4 {
72                 4 => {
73                     // check length
74                     if slice.len() < Ipv4Header::MIN_LEN {
75                         return Err(Len(err::LenError {
76                             required_len: Ipv4Header::MIN_LEN,
77                             len: slice.len(),
78                             len_source: LenSource::Slice,
79                             layer: err::Layer::Ipv4Header,
80                             layer_start_offset: 0,
81                         }));
82                     }
83 
84                     // read ihl
85                     //
86                     // SAFETY:
87                     // Safe as the slice length is checked to be at least
88                     // Ipv4Header::MIN_LEN (20) at the start.
89                     let ihl = unsafe { slice.get_unchecked(0) } & 0xf;
90 
91                     //check that the ihl is correct
92                     if ihl < 5 {
93                         return Err(Content(Ip(Ipv4HeaderLengthSmallerThanHeader { ihl })));
94                     }
95 
96                     // check that the slice contains enough data for the entire header + options
97                     let header_len = usize::from(ihl) * 4;
98                     if slice.len() < header_len {
99                         return Err(Len(LenError {
100                             required_len: header_len,
101                             len: slice.len(),
102                             len_source: LenSource::Slice,
103                             layer: Layer::Ipv4Header,
104                             layer_start_offset: 0,
105                         }));
106                     }
107 
108                     let header = unsafe {
109                         // SAFETY: Safe as the IHL & slice len has been validated
110                         Ipv4HeaderSlice::from_slice_unchecked(core::slice::from_raw_parts(
111                             slice.as_ptr(),
112                             header_len,
113                         ))
114                         .to_header()
115                     };
116 
117                     // check that the total len is at least containing the header len
118                     let total_len: usize = header.total_len.into();
119                     if total_len < header_len {
120                         return Err(Len(LenError {
121                             required_len: header_len,
122                             len: total_len,
123                             len_source: LenSource::Ipv4HeaderTotalLen,
124                             layer: Layer::Ipv4Packet,
125                             layer_start_offset: 0,
126                         }));
127                     }
128 
129                     // restrict the rest of the slice based on the total len
130                     let rest = if slice.len() < total_len {
131                         return Err(Len(LenError {
132                             required_len: total_len,
133                             len: slice.len(),
134                             len_source: LenSource::Slice,
135                             layer: Layer::Ipv4Packet,
136                             layer_start_offset: 0,
137                         }));
138                     } else {
139                         unsafe {
140                             core::slice::from_raw_parts(
141                                 // SAFETY: Safe as the slice length was validated to be at least header_length
142                                 slice.as_ptr().add(header_len),
143                                 // SAFETY: Safe as slice length has been validated to be at least total_length_usize long
144                                 total_len - header_len,
145                             )
146                         }
147                     };
148 
149                     let (exts, next_protocol, rest) =
150                         Ipv4Extensions::from_slice(header.protocol, rest).map_err(|err| {
151                             use err::ip_auth::HeaderSliceError as I;
152                             match err {
153                                 I::Len(mut err) => {
154                                     err.layer_start_offset += header_len;
155                                     err.len_source = LenSource::Ipv4HeaderTotalLen;
156                                     Len(err)
157                                 }
158                                 I::Content(err) => Content(Ipv4Ext(err)),
159                             }
160                         })?;
161 
162                     let fragmented = header.is_fragmenting_payload();
163                     Ok((
164                         IpHeaders::Ipv4(header, exts),
165                         IpPayloadSlice {
166                             ip_number: next_protocol,
167                             fragmented,
168                             len_source: LenSource::Ipv4HeaderTotalLen,
169                             payload: rest,
170                         },
171                     ))
172                 }
173                 6 => {
174                     if slice.len() < Ipv6Header::LEN {
175                         return Err(Len(err::LenError {
176                             required_len: Ipv6Header::LEN,
177                             len: slice.len(),
178                             len_source: LenSource::Slice,
179                             layer: err::Layer::Ipv6Header,
180                             layer_start_offset: 0,
181                         }));
182                     }
183                     let header = {
184                         // SAFETY:
185                         // This is safe as the slice length is checked to be
186                         // at least Ipv6Header::LEN (40) before this code block.
187                         unsafe {
188                             Ipv6HeaderSlice::from_slice_unchecked(core::slice::from_raw_parts(
189                                 slice.as_ptr(),
190                                 Ipv6Header::LEN,
191                             ))
192                             .to_header()
193                         }
194                     };
195 
196                     // restrict slice by the length specified in the header
197                     let (header_payload, len_source) =
198                         if 0 == header.payload_length && slice.len() > Ipv6Header::LEN {
199                             // In case the payload_length is 0 assume that the entire
200                             // rest of the slice is part of the packet until the jumbogram
201                             // parameters can be parsed.
202 
203                             // TODO: Add payload length parsing from the jumbogram
204                             unsafe {
205                                 (
206                                     core::slice::from_raw_parts(
207                                         slice.as_ptr().add(Ipv6Header::LEN),
208                                         slice.len() - Ipv6Header::LEN,
209                                     ),
210                                     LenSource::Slice,
211                                 )
212                             }
213                         } else {
214                             let payload_len: usize = header.payload_length.into();
215                             let expected_len = Ipv6Header::LEN + payload_len;
216                             if slice.len() < expected_len {
217                                 return Err(Len(LenError {
218                                     required_len: expected_len,
219                                     len: slice.len(),
220                                     len_source: LenSource::Slice,
221                                     layer: Layer::Ipv6Packet,
222                                     layer_start_offset: 0,
223                                 }));
224                             } else {
225                                 unsafe {
226                                     (
227                                         core::slice::from_raw_parts(
228                                             slice.as_ptr().add(Ipv6Header::LEN),
229                                             payload_len,
230                                         ),
231                                         LenSource::Ipv6HeaderPayloadLen,
232                                     )
233                                 }
234                             }
235                         };
236 
237                     let (exts, next_header, rest) =
238                         Ipv6Extensions::from_slice(header.next_header, header_payload).map_err(
239                             |err| {
240                                 use err::ipv6_exts::HeaderSliceError as I;
241                                 match err {
242                                     I::Len(mut err) => {
243                                         err.layer_start_offset += Ipv6Header::LEN;
244                                         err.len_source = len_source;
245                                         Len(err)
246                                     }
247                                     I::Content(err) => Content(Ipv6Ext(err)),
248                                 }
249                             },
250                         )?;
251 
252                     let fragmented = exts.is_fragmenting_payload();
253                     Ok((
254                         IpHeaders::Ipv6(header, exts),
255                         IpPayloadSlice {
256                             ip_number: next_header,
257                             fragmented,
258                             len_source,
259                             payload: rest,
260                         },
261                     ))
262                 }
263                 version_number => Err(Content(Ip(UnsupportedIpVersion { version_number }))),
264             }
265         }
266     }
267 
268     /// Reads an [`IpHeaders`] as far as possible without encountering an error &
269     /// separates the payload from the given slice with less strict length checks.
270     /// This function is usefull for cut off packet or for packets with unset length
271     /// fields).
272     ///
273     /// If you want to only receive correct IpPayloads use [`IpHeaders::from_slice`]
274     /// instead.
275     ///
276     /// The main usecases for this functions are:
277     ///
278     /// * Parsing packets that have been cut off. This is, for example, useful to
279     ///   parse packets returned via ICMP as these usually only contain the start.
280     /// * Parsing packets where the `total_len` (for IPv4) or `payload_length` (for IPv6)
281     ///   have not yet been set. This can be useful when parsing packets which have been
282     ///   recorded in a layer before the length field was set (e.g. before the operating
283     ///   system set the length fields).
284     ///
285     /// # Differences to `from_slice`:
286     ///
287     /// There are two main differences:
288     ///
289     /// * Errors in the expansion headers will only stop the parsing and return an `Ok`
290     ///   with the successfully parsed parts and the error as optional. Only if an
291     ///   unrecoverable error is encountered in the IP header itself an `Err` is returned.
292     ///   In the normal `from_slice` function an `Err` is returned if an error is
293     ///   encountered in an exteions header.
294     /// * `from_slice_lax` ignores inconsistent `total_len` (in IPv4 headers) and
295     ///   inconsistent `payload_length` (in IPv6 headers) values. When these length
296     ///   values in the IP header are inconsistant the length of the given slice is
297     ///   used as a substitute.
298     ///
299     /// You can check if the slice length was used as a substitude by checking
300     /// if the `len_source` value in the returned [`LaxIpPayloadSlice`] is set to
301     /// [`LenSource::Slice`]. If a substitution was not needed `len_source`
302     /// is set to [`LenSource::Ipv4HeaderTotalLen`] or
303     /// [`LenSource::Ipv6HeaderPayloadLen`].
304     ///
305     /// # When is the slice length used as a fallback?
306     ///
307     /// For IPv4 packets the slice length is used as a fallback/substitude
308     /// if the `total_length` field in the IPv4 header is:
309     ///
310     ///  * Bigger then the given slice (payload cannot fully be seperated).
311     ///  * Too small to contain at least the IPv4 header.
312     ///
313     /// For IPv6 packet the slice length is used as a fallback/substitude
314     /// if the `payload_length` is
315     ///
316     /// * Bigger then the given slice (payload cannot fully be seperated).
317     /// * The value `0`.
from_slice_lax( slice: &[u8], ) -> Result< ( IpHeaders, LaxIpPayloadSlice<'_>, Option<(err::ip_exts::HeadersSliceError, Layer)>, ), err::ip::LaxHeaderSliceError, >318     pub fn from_slice_lax(
319         slice: &[u8],
320     ) -> Result<
321         (
322             IpHeaders,
323             LaxIpPayloadSlice<'_>,
324             Option<(err::ip_exts::HeadersSliceError, Layer)>,
325         ),
326         err::ip::LaxHeaderSliceError,
327     > {
328         use err::ip::{HeaderError::*, LaxHeaderSliceError::*};
329 
330         if slice.is_empty() {
331             Err(Len(err::LenError {
332                 required_len: 1,
333                 len: slice.len(),
334                 len_source: LenSource::Slice,
335                 layer: err::Layer::IpHeader,
336                 layer_start_offset: 0,
337             }))
338         } else {
339             match slice[0] >> 4 {
340                 4 => {
341                     // check length
342                     if slice.len() < Ipv4Header::MIN_LEN {
343                         return Err(Len(err::LenError {
344                             required_len: Ipv4Header::MIN_LEN,
345                             len: slice.len(),
346                             len_source: LenSource::Slice,
347                             layer: err::Layer::Ipv4Header,
348                             layer_start_offset: 0,
349                         }));
350                     }
351 
352                     // read ihl
353                     //
354                     // SAFETY:
355                     // Safe as the slice length is checked to be at least
356                     // Ipv4Header::MIN_LEN (20) at the start.
357                     let ihl = unsafe { slice.get_unchecked(0) } & 0xf;
358 
359                     //check that the ihl is correct
360                     if ihl < 5 {
361                         return Err(Content(Ipv4HeaderLengthSmallerThanHeader { ihl }));
362                     }
363 
364                     // check that the slice contains enough data for the entire header + options
365                     let header_len = usize::from(ihl) * 4;
366                     if slice.len() < header_len {
367                         return Err(Len(LenError {
368                             required_len: header_len,
369                             len: slice.len(),
370                             len_source: LenSource::Slice,
371                             layer: Layer::Ipv4Header,
372                             layer_start_offset: 0,
373                         }));
374                     }
375 
376                     let header = unsafe {
377                         // SAFETY: Safe as the IHL & slice len has been validated
378                         Ipv4HeaderSlice::from_slice_unchecked(core::slice::from_raw_parts(
379                             slice.as_ptr(),
380                             header_len,
381                         ))
382                         .to_header()
383                     };
384 
385                     // check that the total len is at least containing the header len
386                     let total_len: usize = header.total_len.into();
387 
388                     // restrict the rest of the slice based on the total len (if the total_len is not conflicting)
389                     let (len_source, rest, incomplete) = if total_len < header_len {
390                         // fallback to slice len
391                         (
392                             LenSource::Slice,
393                             unsafe {
394                                 core::slice::from_raw_parts(
395                                     // SAFETY: Safe as the slice length was validated to be at least header_length
396                                     slice.as_ptr().add(header_len),
397                                     // SAFETY: Safe as slice length has been validated to be at least header_len long
398                                     slice.len() - header_len,
399                                 )
400                             },
401                             false,
402                         )
403                     } else if slice.len() < total_len {
404                         (
405                             LenSource::Slice,
406                             unsafe {
407                                 core::slice::from_raw_parts(
408                                     // SAFETY: Safe as the slice length was validated to be at least header_length
409                                     slice.as_ptr().add(header_len),
410                                     // SAFETY: Safe as slice length has been validated to be at least header_len long
411                                     slice.len() - header_len,
412                                 )
413                             },
414                             true,
415                         )
416                     } else {
417                         (
418                             LenSource::Ipv4HeaderTotalLen,
419                             unsafe {
420                                 core::slice::from_raw_parts(
421                                     // SAFETY: Safe as the slice length was validated to be at least header_length
422                                     slice.as_ptr().add(header_len),
423                                     // SAFETY: Safe as slice length has been validated to be at least total_length_usize long
424                                     total_len - header_len,
425                                 )
426                             },
427                             false,
428                         )
429                     };
430 
431                     let (exts, next_protocol, rest, stop_err) =
432                         Ipv4Extensions::from_slice_lax(header.protocol, rest);
433 
434                     let stop_err = stop_err.map(|err| {
435                         use err::ip_auth::HeaderSliceError as I;
436                         use err::ip_exts::HeaderError as OC;
437                         use err::ip_exts::HeadersSliceError as O;
438                         match err {
439                             I::Len(mut l) => O::Len({
440                                 l.layer_start_offset += header_len;
441                                 l.len_source = len_source;
442                                 l
443                             }),
444                             I::Content(c) => O::Content(OC::Ipv4Ext(c)),
445                         }
446                     });
447 
448                     let fragmented = header.is_fragmenting_payload();
449                     Ok((
450                         IpHeaders::Ipv4(header, exts),
451                         LaxIpPayloadSlice {
452                             incomplete,
453                             ip_number: next_protocol,
454                             fragmented,
455                             len_source,
456                             payload: rest,
457                         },
458                         stop_err.map(|v| (v, Layer::IpAuthHeader)),
459                     ))
460                 }
461                 6 => {
462                     if slice.len() < Ipv6Header::LEN {
463                         return Err(Len(err::LenError {
464                             required_len: Ipv6Header::LEN,
465                             len: slice.len(),
466                             len_source: LenSource::Slice,
467                             layer: err::Layer::Ipv6Header,
468                             layer_start_offset: 0,
469                         }));
470                     }
471                     let header = {
472                         // SAFETY:
473                         // This is safe as the slice length is checked to be
474                         // at least Ipv6Header::LEN (40) befpre this code block.
475                         unsafe {
476                             Ipv6HeaderSlice::from_slice_unchecked(core::slice::from_raw_parts(
477                                 slice.as_ptr(),
478                                 Ipv6Header::LEN,
479                             ))
480                             .to_header()
481                         }
482                     };
483 
484                     // restrict slice by the length specified in the header
485                     let payload_len = usize::from(header.payload_length);
486                     let (header_payload, len_source, incomplete) =
487                         if (header.payload_length == 0) && (Ipv6Header::LEN < slice.len()) {
488                             // TODO: Add payload length parsing from the jumbogram
489                             unsafe {
490                                 (
491                                     core::slice::from_raw_parts(
492                                         // SAFTEY: Safe as we verify what `slice.len() >= Ipv6Header::LEN` above.
493                                         slice.as_ptr().add(Ipv6Header::LEN),
494                                         // SAFTEY: Safe as we verify what `slice.len() >= Ipv6Header::LEN` above.
495                                         slice.len() - Ipv6Header::LEN,
496                                     ),
497                                     LenSource::Slice,
498                                     false,
499                                 )
500                             }
501                         } else if (slice.len() - Ipv6Header::LEN) < payload_len {
502                             unsafe {
503                                 (
504                                     core::slice::from_raw_parts(
505                                         // SAFTEY: Safe as we verify what `slice.len() >= Ipv6Header::LEN` above.
506                                         slice.as_ptr().add(Ipv6Header::LEN),
507                                         // SAFTEY: Safe as we verify what `slice.len() >= Ipv6Header::LEN` above.
508                                         slice.len() - Ipv6Header::LEN,
509                                     ),
510                                     LenSource::Slice,
511                                     true,
512                                 )
513                             }
514                         } else {
515                             unsafe {
516                                 (
517                                     core::slice::from_raw_parts(
518                                         // SAFTEY: Safe as we verify what `slice.len() >= Ipv6Header::LEN` above.
519                                         slice.as_ptr().add(Ipv6Header::LEN),
520                                         // SAFTEY: Safe as we verify that `(slice.len() - Ipv6Header::LEN) >= payload_len` above.
521                                         payload_len,
522                                     ),
523                                     LenSource::Ipv6HeaderPayloadLen,
524                                     false,
525                                 )
526                             }
527                         };
528 
529                     let (exts, next_header, rest, stop_err) =
530                         Ipv6Extensions::from_slice_lax(header.next_header, header_payload);
531 
532                     let stop_err = stop_err.map(|(err, layer)| {
533                         use err::ip_exts::HeaderError::Ipv6Ext;
534                         use err::ip_exts::HeadersSliceError as O;
535                         use err::ipv6_exts::HeaderSliceError as I;
536                         (
537                             match err {
538                                 I::Len(mut l) => {
539                                     l.layer_start_offset += Ipv6Header::LEN;
540                                     l.len_source = len_source;
541                                     O::Len(l)
542                                 }
543                                 I::Content(c) => O::Content(Ipv6Ext(c)),
544                             },
545                             layer,
546                         )
547                     });
548 
549                     let fragmented = exts.is_fragmenting_payload();
550                     Ok((
551                         IpHeaders::Ipv6(header, exts),
552                         LaxIpPayloadSlice {
553                             incomplete,
554                             ip_number: next_header,
555                             fragmented,
556                             len_source,
557                             payload: rest,
558                         },
559                         stop_err,
560                     ))
561                 }
562                 version_number => Err(Content(UnsupportedIpVersion { version_number })),
563             }
564         }
565     }
566 
567     /// Read an IPv4 header & extension headers from a slice and return the slice containing the payload
568     /// according to the total_length field in the IPv4 header.
569     ///
570     /// Note that his function returns an [`err::LenError`] if the given slice
571     /// contains less data then the `total_len` field in the IPv4 header indicates
572     /// should be present.
573     ///
574     /// If you want to ignore these kind of length errors based on the length
575     /// fields in the IP headers use [`IpHeaders::from_ipv4_slice_lax`] instead.
from_ipv4_slice( slice: &[u8], ) -> Result<(IpHeaders, IpPayloadSlice<'_>), err::ipv4::SliceError>576     pub fn from_ipv4_slice(
577         slice: &[u8],
578     ) -> Result<(IpHeaders, IpPayloadSlice<'_>), err::ipv4::SliceError> {
579         use err::ipv4::SliceError::*;
580 
581         // read the header
582         let (header, header_rest) = Ipv4Header::from_slice(slice).map_err(|err| {
583             use err::ipv4::HeaderSliceError as I;
584             match err {
585                 I::Len(err) => Len(err),
586                 I::Content(err) => Header(err),
587             }
588         })?;
589 
590         // check that the total length at least contains the header
591         let total_len: usize = header.total_len.into();
592         let header_len = header.header_len();
593         let payload_len = if total_len >= header_len {
594             total_len - header_len
595         } else {
596             return Err(Len(LenError {
597                 required_len: header_len,
598                 len: total_len,
599                 len_source: LenSource::Ipv4HeaderTotalLen,
600                 layer: Layer::Ipv4Packet,
601                 layer_start_offset: 0,
602             }));
603         };
604 
605         // limit rest based on ipv4 total length
606         let header_rest = if payload_len > header_rest.len() {
607             return Err(Len(err::LenError {
608                 required_len: total_len,
609                 len: slice.len(),
610                 len_source: LenSource::Slice,
611                 layer: Layer::Ipv4Packet,
612                 layer_start_offset: 0,
613             }));
614         } else {
615             unsafe {
616                 // Safe as the payload_len <= header_rest.len is verified above
617                 core::slice::from_raw_parts(header_rest.as_ptr(), payload_len)
618             }
619         };
620 
621         // read the extension header
622         let (exts, next_header, exts_rest) =
623             Ipv4Extensions::from_slice(header.protocol, header_rest).map_err(|err| {
624                 use err::ip_auth::HeaderSliceError as I;
625                 match err {
626                     I::Len(mut err) => {
627                         err.layer_start_offset += header.header_len();
628                         err.len_source = LenSource::Ipv4HeaderTotalLen;
629                         Len(err)
630                     }
631                     I::Content(err) => Exts(err),
632                 }
633             })?;
634 
635         let fragmented = header.is_fragmenting_payload();
636         Ok((
637             IpHeaders::Ipv4(header, exts),
638             IpPayloadSlice {
639                 ip_number: next_header,
640                 fragmented,
641                 len_source: LenSource::Ipv4HeaderTotalLen,
642                 payload: exts_rest,
643             },
644         ))
645     }
646 
647     /// Reads an IPv4 header & its extensions headers as far as is possible without encountering an
648     /// error & separates the payload from the given slice with less strict length checks.
649     /// This function is usefull for cut off packet or for packets with unset length fields).
650     ///
651     /// If you want to only receive correct IpPayloads use [`IpHeaders::from_ipv4_slice`]
652     /// instead.
653     ///
654     /// The main usecases for this functions are:
655     ///
656     /// * Parsing packets that have been cut off. This is, for example, useful to
657     ///   parse packets returned via ICMP as these usually only contain the start.
658     /// * Parsing packets where the `total_len` (for IPv4) have not yet been set.
659     ///   This can be useful when parsing packets which have been recorded in a
660     ///   layer before the length field was set (e.g. before the operating
661     ///   system set the length fields).
662     ///
663     /// # Differences to `from_ipv4_slice`:
664     ///
665     /// There are two main differences:
666     ///
667     /// * Errors in the expansion headers will only stop the parsing and return an `Ok`
668     ///   with the successfully parsed parts and the error as optional. Only if an
669     ///   unrecoverable error is encountered in the IP header itself an `Err` is returned.
670     ///   In the normal `from_slice` function an `Err` is returned if an error is
671     ///   encountered in an exteions header.
672     /// * `from_ipv4_slice_lax` ignores inconsistent `total_len` values. When the `total_len`
673     ///   value in the IPv4 header are inconsistant the length of the given slice is
674     ///   used as a substitute.
675     ///
676     /// You can check if the slice length was used as a substitude by checking
677     /// if the `len_source` value in the returned [`crate::LaxIpPayloadSlice`] is set to
678     /// [`LenSource::Slice`]. If a substitution was not needed `len_source`
679     /// is set to [`LenSource::Ipv4HeaderTotalLen`].
680     ///
681     /// # When is the slice length used as a fallback?
682     ///
683     /// For IPv4 packets the slice length is used as a fallback/substitude
684     /// if the `total_length` field in the IPv4 header is:
685     ///
686     ///  * Bigger then the given slice (payload cannot fully be seperated).
687     ///  * Too small to contain at least the IPv4 header.
from_ipv4_slice_lax( slice: &[u8], ) -> Result< ( IpHeaders, LaxIpPayloadSlice<'_>, Option<err::ip_auth::HeaderSliceError>, ), err::ip::LaxHeaderSliceError, >688     pub fn from_ipv4_slice_lax(
689         slice: &[u8],
690     ) -> Result<
691         (
692             IpHeaders,
693             LaxIpPayloadSlice<'_>,
694             Option<err::ip_auth::HeaderSliceError>,
695         ),
696         err::ip::LaxHeaderSliceError,
697     > {
698         use err::ip::LaxHeaderSliceError::*;
699 
700         // read the header
701         let (header, header_rest) = Ipv4Header::from_slice(slice).map_err(|err| {
702             use err::ip::HeaderError as O;
703             use err::ipv4::HeaderError as I1;
704             use err::ipv4::HeaderSliceError as I0;
705             match err {
706                 I0::Len(err) => Len(err),
707                 I0::Content(err) => Content(match err {
708                     I1::UnexpectedVersion { version_number } => {
709                         O::UnsupportedIpVersion { version_number }
710                     }
711                     I1::HeaderLengthSmallerThanHeader { ihl } => {
712                         O::Ipv4HeaderLengthSmallerThanHeader { ihl }
713                     }
714                 }),
715             }
716         })?;
717 
718         // check that the total len is at least containing the header len
719         let total_len: usize = header.total_len.into();
720 
721         // restrict the rest of the slice based on the total len (if the total_len is not conflicting)
722         let header_len = header.header_len();
723         let (len_source, header_rest, incomplete) = if total_len < header_len {
724             // fallback to the rest of the slice
725             (LenSource::Slice, header_rest, false)
726         } else if header_rest.len() < total_len - header_len {
727             // fallback to the rest of the slice
728             (LenSource::Slice, header_rest, true)
729         } else {
730             (
731                 LenSource::Ipv4HeaderTotalLen,
732                 unsafe {
733                     core::slice::from_raw_parts(
734                         header_rest.as_ptr(),
735                         // SAFETY: Safe as slice length has been validated to be at least total_length_usize long
736                         total_len - header_len,
737                     )
738                 },
739                 false,
740             )
741         };
742 
743         let (exts, next_protocol, payload, mut stop_err) =
744             Ipv4Extensions::from_slice_lax(header.protocol, header_rest);
745 
746         use err::ip_auth::HeaderSliceError as I;
747         if let Some(I::Len(err)) = stop_err.as_mut() {
748             err.layer_start_offset += header.header_len();
749             err.len_source = len_source;
750         }
751 
752         let fragmented = header.is_fragmenting_payload();
753         Ok((
754             IpHeaders::Ipv4(header, exts),
755             LaxIpPayloadSlice {
756                 incomplete,
757                 ip_number: next_protocol,
758                 fragmented,
759                 len_source,
760                 payload,
761             },
762             stop_err,
763         ))
764     }
765 
766     /// Read an IPv6 header & extension headers from a slice and return the slice
767     /// containing the payload (e.g. TCP, UDP etc.) length limited by payload_length
768     /// field in the IPv6 header.
769     ///
770     /// Note that slice length is used as a fallback value in case the
771     /// payload_length in the IPv6 is set to zero. This is a temporary workaround
772     /// to partially support jumbograms.
from_ipv6_slice( slice: &[u8], ) -> Result<(IpHeaders, IpPayloadSlice<'_>), err::ipv6::SliceError>773     pub fn from_ipv6_slice(
774         slice: &[u8],
775     ) -> Result<(IpHeaders, IpPayloadSlice<'_>), err::ipv6::SliceError> {
776         use err::ipv6::SliceError::*;
777 
778         // read ipv6 header
779         let (header, header_rest) = Ipv6Header::from_slice(slice).map_err(|err| {
780             use err::ipv6::HeaderSliceError as I;
781             match err {
782                 I::Len(err) => Len(err),
783                 I::Content(err) => Header(err),
784             }
785         })?;
786 
787         // restrict slice by the length specified in the header
788         let (header_payload, len_source) =
789             if 0 == header.payload_length && slice.len() > Ipv6Header::LEN {
790                 // In case the payload_length is 0 assume that the entire
791                 // rest of the slice is part of the packet until the jumbogram
792                 // parameters can be parsed.
793 
794                 // TODO: Add payload length parsing from the jumbogram
795                 (header_rest, LenSource::Slice)
796             } else {
797                 let payload_len: usize = header.payload_length.into();
798                 if header_rest.len() < payload_len {
799                     return Err(Len(LenError {
800                         required_len: payload_len + Ipv6Header::LEN,
801                         len: slice.len(),
802                         len_source: LenSource::Slice,
803                         layer: Layer::Ipv6Packet,
804                         layer_start_offset: 0,
805                     }));
806                 } else {
807                     unsafe {
808                         (
809                             core::slice::from_raw_parts(header_rest.as_ptr(), payload_len),
810                             LenSource::Ipv6HeaderPayloadLen,
811                         )
812                     }
813                 }
814             };
815 
816         // read ipv6 extensions headers
817         let (exts, next_header, exts_rest) =
818             Ipv6Extensions::from_slice(header.next_header, header_payload).map_err(|err| {
819                 use err::ipv6_exts::HeaderSliceError as I;
820                 match err {
821                     I::Len(mut err) => {
822                         err.layer_start_offset += Ipv6Header::LEN;
823                         err.len_source = len_source;
824                         Len(err)
825                     }
826                     I::Content(err) => Exts(err),
827                 }
828             })?;
829 
830         let fragmented = exts.is_fragmenting_payload();
831         Ok((
832             IpHeaders::Ipv6(header, exts),
833             IpPayloadSlice {
834                 ip_number: next_header,
835                 fragmented,
836                 len_source,
837                 payload: exts_rest,
838             },
839         ))
840     }
841 
842     /// Reads an IPv6 header & its extensions headers as far as is possible without encountering an
843     /// error & separates the payload from the given slice with less strict length checks.
844     /// This function is usefull for cut off packet or for packets with unset length fields).
845     ///
846     /// If you want to only receive correct IpPayloads use [`IpHeaders::from_ipv6_slice`]
847     /// instead.
848     ///
849     /// The main usecases for this functions are:
850     ///
851     /// * Parsing packets that have been cut off. This is, for example, useful to
852     ///   parse packets returned via ICMP as these usually only contain the start.
853     /// * Parsing packets where the `payload_length` (in the IPv6 header) has not
854     ///   yet been set. This can be useful when parsing packets which have been
855     ///   recorded in a layer before the length field was set (e.g. before the operating
856     ///   system set the length fields).
857     ///
858     /// # Differences to `from_slice`:
859     ///
860     /// There are two main differences:
861     ///
862     /// * Errors in the expansion headers will only stop the parsing and return an `Ok`
863     ///   with the successfully parsed parts and the error as optional. Only if an
864     ///   unrecoverable error is encountered in the IP header itself an `Err` is returned.
865     ///   In the normal `from_slice` function an `Err` is returned if an error is
866     ///   encountered in an exteions header.
867     /// * `from_slice_lax` ignores inconsistent `payload_length` values. When the
868     ///   `payload_length` value in the IPv6 header is inconsistant the length of
869     ///   the given slice is used as a substitute.
870     ///
871     /// You can check if the slice length was used as a substitude by checking
872     /// if the `len_source` value in the returned [`LaxIpPayloadSlice`] is set to
873     /// [`LenSource::Slice`]. If a substitution was not needed `len_source`
874     /// is set to [`LenSource::Ipv6HeaderPayloadLen`].
875     ///
876     /// # When is the slice length used as a fallback?
877     ///
878     /// The slice length is used as a fallback/substitude if the `payload_length`
879     /// field in the IPv6 header is
880     ///
881     /// * Bigger then the given slice (payload cannot fully be seperated).
882     /// * The value `0`.
from_ipv6_slice_lax( slice: &[u8], ) -> Result< ( IpHeaders, LaxIpPayloadSlice<'_>, Option<(err::ipv6_exts::HeaderSliceError, Layer)>, ), err::ipv6::HeaderSliceError, >883     pub fn from_ipv6_slice_lax(
884         slice: &[u8],
885     ) -> Result<
886         (
887             IpHeaders,
888             LaxIpPayloadSlice<'_>,
889             Option<(err::ipv6_exts::HeaderSliceError, Layer)>,
890         ),
891         err::ipv6::HeaderSliceError,
892     > {
893         // read ipv6 header
894         let (header, header_rest) = Ipv6Header::from_slice(slice)?;
895 
896         // restrict slice by the length specified in the header
897         let payload_len: usize = header.payload_length.into();
898         let (header_payload, len_source, incomplete) =
899             if payload_len == 0 && (false == header_rest.is_empty()) {
900                 (header_rest, LenSource::Slice, false)
901             } else if payload_len > header_rest.len() {
902                 (header_rest, LenSource::Slice, true)
903             } else {
904                 unsafe {
905                     (
906                         core::slice::from_raw_parts(header_rest.as_ptr(), payload_len),
907                         LenSource::Ipv6HeaderPayloadLen,
908                         false,
909                     )
910                 }
911             };
912 
913         // read ipv6 extensions headers
914         let (exts, next_header, exts_rest, mut stop_err) =
915             Ipv6Extensions::from_slice_lax(header.next_header, header_payload);
916 
917         use err::ipv6_exts::HeaderSliceError as I;
918         if let Some((I::Len(err), _)) = stop_err.as_mut() {
919             err.layer_start_offset += Ipv6Header::LEN;
920             err.len_source = len_source;
921         };
922 
923         let fragmented = exts.is_fragmenting_payload();
924         Ok((
925             IpHeaders::Ipv6(header, exts),
926             LaxIpPayloadSlice {
927                 incomplete,
928                 ip_number: next_header,
929                 fragmented,
930                 len_source,
931                 payload: exts_rest,
932             },
933             stop_err,
934         ))
935     }
936 
937     /// Reads an IP (v4 or v6) header from the current position (requires
938     /// crate feature `std`).
939     #[cfg(feature = "std")]
940     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
read<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, ) -> Result<(IpHeaders, IpNumber), err::ip::HeaderReadError>941     pub fn read<T: std::io::Read + std::io::Seek + Sized>(
942         reader: &mut T,
943     ) -> Result<(IpHeaders, IpNumber), err::ip::HeaderReadError> {
944         use crate::io::LimitedReader;
945         use err::ip::{HeaderError::*, HeaderReadError::*, HeadersError::*};
946 
947         let value = {
948             let mut buf = [0; 1];
949             reader.read_exact(&mut buf).map_err(Io)?;
950             buf[0]
951         };
952         match value >> 4 {
953             4 => {
954                 // get internet header length
955                 let ihl = value & 0xf;
956 
957                 // check that the ihl is correct
958                 if ihl < 5 {
959                     return Err(Content(Ip(Ipv4HeaderLengthSmallerThanHeader { ihl })));
960                 }
961 
962                 // read the rest of the header
963                 let header_len_u16 = u16::from(ihl) * 4;
964                 let header_len = usize::from(header_len_u16);
965                 let mut buffer = [0u8; Ipv4Header::MAX_LEN];
966                 buffer[0] = value;
967                 reader.read_exact(&mut buffer[1..header_len]).map_err(Io)?;
968 
969                 let header = unsafe {
970                     // SAFETY: Safe as both the IHL and slice len have been verified
971                     Ipv4HeaderSlice::from_slice_unchecked(&buffer[..header_len])
972                 }
973                 .to_header();
974 
975                 // check that the total len is long enough to contain the header
976                 let total_len = usize::from(header.total_len);
977                 let mut reader = if total_len < header_len {
978                     return Err(Len(LenError {
979                         required_len: header_len,
980                         len: total_len,
981                         len_source: LenSource::Ipv4HeaderTotalLen,
982                         layer: Layer::Ipv4Packet,
983                         layer_start_offset: 0,
984                     }));
985                 } else {
986                     // create a new reader that is limited by the total_len value length
987                     LimitedReader::new(
988                         reader,
989                         total_len - header_len,
990                         LenSource::Ipv4HeaderTotalLen,
991                         header_len,
992                         Layer::Ipv4Header,
993                     )
994                 };
995 
996                 // read the extension headers if present
997                 Ipv4Extensions::read_limited(&mut reader, header.protocol)
998                     .map(|(ext, next)| (IpHeaders::Ipv4(header, ext), next))
999                     .map_err(|err| {
1000                         use err::ip_auth::HeaderLimitedReadError as I;
1001                         match err {
1002                             I::Io(err) => Io(err),
1003                             I::Len(err) => Len(err),
1004                             I::Content(err) => Content(Ipv4Ext(err)),
1005                         }
1006                     })
1007             }
1008             6 => {
1009                 let header = Ipv6Header::read_without_version(reader, value & 0xf).map_err(Io)?;
1010 
1011                 // create a new reader that is limited by the payload_len value length
1012                 let mut reader = LimitedReader::new(
1013                     reader,
1014                     header.payload_length.into(),
1015                     LenSource::Ipv6HeaderPayloadLen,
1016                     header.header_len(),
1017                     Layer::Ipv6Header,
1018                 );
1019 
1020                 Ipv6Extensions::read_limited(&mut reader, header.next_header)
1021                     .map(|(ext, next)| (IpHeaders::Ipv6(header, ext), next))
1022                     .map_err(|err| {
1023                         use err::ipv6_exts::HeaderLimitedReadError as I;
1024                         match err {
1025                             I::Io(err) => Io(err),
1026                             I::Len(err) => Len(err),
1027                             I::Content(err) => Content(Ipv6Ext(err)),
1028                         }
1029                     })
1030             }
1031             version_number => Err(Content(Ip(UnsupportedIpVersion { version_number }))),
1032         }
1033     }
1034 
1035     /// Writes an IP (v4 or v6) header to the current position (requires
1036     /// crate feature `std`).
1037     #[cfg(feature = "std")]
1038     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
write<T: std::io::Write + Sized>( &self, writer: &mut T, ) -> Result<(), HeadersWriteError>1039     pub fn write<T: std::io::Write + Sized>(
1040         &self,
1041         writer: &mut T,
1042     ) -> Result<(), HeadersWriteError> {
1043         use crate::IpHeaders::*;
1044         use HeadersWriteError::*;
1045         match *self {
1046             Ipv4(ref header, ref extensions) => {
1047                 header.write(writer).map_err(Io)?;
1048                 extensions.write(writer, header.protocol).map_err(|err| {
1049                     use err::ipv4_exts::HeaderWriteError as I;
1050                     match err {
1051                         I::Io(err) => Io(err),
1052                         I::Content(err) => Ipv4Exts(err),
1053                     }
1054                 })
1055             }
1056             Ipv6(ref header, ref extensions) => {
1057                 header.write(writer).map_err(Io)?;
1058                 extensions.write(writer, header.next_header).map_err(|err| {
1059                     use err::ipv6_exts::HeaderWriteError as I;
1060                     match err {
1061                         I::Io(err) => Io(err),
1062                         I::Content(err) => Ipv6Exts(err),
1063                     }
1064                 })
1065             }
1066         }
1067     }
1068 
1069     /// Returns the size when the ip header & extensions are serialized
header_len(&self) -> usize1070     pub fn header_len(&self) -> usize {
1071         use crate::IpHeaders::*;
1072         match *self {
1073             Ipv4(ref header, ref extensions) => header.header_len() + extensions.header_len(),
1074             Ipv6(_, ref extensions) => Ipv6Header::LEN + extensions.header_len(),
1075         }
1076     }
1077 
1078     /// Returns the last next header number following the ip header
1079     /// and header extensions.
next_header(&self) -> Result<IpNumber, err::ip_exts::ExtsWalkError>1080     pub fn next_header(&self) -> Result<IpNumber, err::ip_exts::ExtsWalkError> {
1081         use crate::err::ip_exts::ExtsWalkError::*;
1082         use crate::IpHeaders::*;
1083         match *self {
1084             Ipv4(ref header, ref extensions) => {
1085                 extensions.next_header(header.protocol).map_err(Ipv4Exts)
1086             }
1087             Ipv6(ref header, ref extensions) => {
1088                 extensions.next_header(header.next_header).map_err(Ipv6Exts)
1089             }
1090         }
1091     }
1092 
1093     /// Sets all the next_header fields in the ipv4 & ipv6 header
1094     /// as well as in all extension headers and returns the ether
1095     /// type number.
1096     ///
1097     /// The given number will be set as the last "next_header" or
1098     /// protocol number.
set_next_headers(&mut self, last_next_header: IpNumber) -> u161099     pub fn set_next_headers(&mut self, last_next_header: IpNumber) -> u16 {
1100         use IpHeaders::*;
1101         match self {
1102             Ipv4(ref mut header, ref mut extensions) => {
1103                 header.protocol = extensions.set_next_headers(last_next_header);
1104                 EtherType::IPV4.0
1105             }
1106             Ipv6(ref mut header, ref mut extensions) => {
1107                 header.next_header = extensions.set_next_headers(last_next_header);
1108                 EtherType::IPV4.0
1109             }
1110         }
1111     }
1112 
1113     /// Tries to set the length field in the ip header given the length of data
1114     /// after the ip header and extension header(s).
1115     ///
1116     /// If the payload length is too large to be stored in the length fields
1117     /// of the ip header an error is returned.
1118     ///
1119     /// Note that this function will automatically add the length of the extension
1120     /// headers is they are present.
set_payload_len(&mut self, len: usize) -> Result<(), ValueTooBigError<usize>>1121     pub fn set_payload_len(&mut self, len: usize) -> Result<(), ValueTooBigError<usize>> {
1122         use crate::err::ValueType;
1123         match self {
1124             IpHeaders::Ipv4(ipv4_hdr, exts) => {
1125                 if let Some(complete_len) = len.checked_add(exts.header_len()) {
1126                     ipv4_hdr.set_payload_len(complete_len)
1127                 } else {
1128                     Err(ValueTooBigError {
1129                         actual: len,
1130                         max_allowed: usize::from(u16::MAX)
1131                             - ipv4_hdr.header_len()
1132                             - exts.header_len(),
1133                         value_type: ValueType::Ipv4PayloadLength,
1134                     })
1135                 }
1136             }
1137             IpHeaders::Ipv6(ipv6_hdr, exts) => {
1138                 if let Some(complete_len) = len.checked_add(exts.header_len()) {
1139                     ipv6_hdr.set_payload_length(complete_len)
1140                 } else {
1141                     Err(ValueTooBigError {
1142                         actual: len,
1143                         max_allowed: usize::from(u16::MAX) - exts.header_len(),
1144                         value_type: ValueType::Ipv4PayloadLength,
1145                     })
1146                 }
1147             }
1148         }
1149     }
1150 
1151     /// Returns true if the payload is fragmented based on the IPv4 header
1152     /// or the IPv6 fragment header.
is_fragmenting_payload(&self) -> bool1153     pub fn is_fragmenting_payload(&self) -> bool {
1154         match self {
1155             IpHeaders::Ipv4(ipv4, _) => ipv4.is_fragmenting_payload(),
1156             IpHeaders::Ipv6(_, exts) => exts.is_fragmenting_payload(),
1157         }
1158     }
1159 }
1160 
1161 #[cfg(test)]
1162 mod test {
1163     use crate::{
1164         err::{
1165             ip::{HeadersError, HeadersSliceError},
1166             Layer, LenError,
1167         },
1168         ip_number::*,
1169         test_gens::*,
1170         *,
1171     };
1172     use alloc::{borrow::ToOwned, format, vec::Vec};
1173     use proptest::prelude::*;
1174     use std::io::Cursor;
1175 
1176     const EXTENSION_KNOWN_IP_NUMBERS: [IpNumber; 5] = [
1177         AUTH,
1178         IPV6_DEST_OPTIONS,
1179         IPV6_HOP_BY_HOP,
1180         IPV6_FRAG,
1181         IPV6_ROUTE,
1182     ];
1183 
combine_v4(v4: &Ipv4Header, ext: &Ipv4Extensions, payload: &[u8]) -> IpHeaders1184     fn combine_v4(v4: &Ipv4Header, ext: &Ipv4Extensions, payload: &[u8]) -> IpHeaders {
1185         IpHeaders::Ipv4(
1186             {
1187                 let mut v4 = v4.clone();
1188                 v4.protocol = if ext.auth.is_some() { AUTH } else { UDP };
1189                 v4.total_len = (v4.header_len() + ext.header_len() + payload.len()) as u16;
1190                 v4.header_checksum = v4.calc_header_checksum();
1191                 v4
1192             },
1193             ext.clone(),
1194         )
1195     }
1196 
combine_v6(v6: &Ipv6Header, ext: &Ipv6Extensions, payload: &[u8]) -> IpHeaders1197     fn combine_v6(v6: &Ipv6Header, ext: &Ipv6Extensions, payload: &[u8]) -> IpHeaders {
1198         let (ext, next_header) = {
1199             let mut ext = ext.clone();
1200             let next_header = ext.set_next_headers(UDP);
1201             (ext, next_header)
1202         };
1203         IpHeaders::Ipv6(
1204             {
1205                 let mut v6 = v6.clone();
1206                 v6.next_header = next_header;
1207                 v6.payload_length = (ext.header_len() + payload.len()) as u16;
1208                 v6
1209             },
1210             ext,
1211         )
1212     }
1213 
1214     proptest! {
1215         #[test]
1216         fn debug(
1217             v4 in ipv4_any(),
1218             v4_exts in ipv4_extensions_any(),
1219             v6 in ipv6_any(),
1220             v6_exts in ipv6_extensions_any(),
1221         ) {
1222             assert_eq!(
1223                 format!(
1224                     "Ipv4({:?}, {:?})",
1225                     v4,
1226                     v4_exts
1227                 ),
1228                 format!("{:?}", IpHeaders::Ipv4(v4, v4_exts))
1229             );
1230             assert_eq!(
1231                 format!(
1232                     "Ipv6({:?}, {:?})",
1233                     v6,
1234                     v6_exts
1235                 ),
1236                 format!("{:?}", IpHeaders::Ipv6(v6, v6_exts))
1237             );
1238         }
1239     }
1240 
1241     proptest! {
1242         #[test]
1243         fn clone_eq(
1244             v4 in ipv4_any(),
1245             v4_exts in ipv4_extensions_any(),
1246             v6 in ipv6_any(),
1247             v6_exts in ipv6_extensions_any(),
1248         ) {
1249             {
1250                 let v4 = IpHeaders::Ipv4(v4, v4_exts);
1251                 assert_eq!(v4, v4.clone());
1252             }
1253             {
1254                 let v6 = IpHeaders::Ipv6(v6, v6_exts);
1255                 assert_eq!(v6, v6.clone());
1256             }
1257         }
1258     }
1259 
1260     proptest! {
1261         #[test]
1262         fn ipv4(
1263             v4 in ipv4_any(),
1264             v4_exts in ipv4_extensions_any(),
1265             v6 in ipv6_any(),
1266             v6_exts in ipv6_extensions_any(),
1267         ) {
1268             assert_eq!(
1269                 IpHeaders::Ipv4(v4.clone(), v4_exts.clone()).ipv4(),
1270                 Some((&v4, &v4_exts))
1271             );
1272             assert_eq!(
1273                 IpHeaders::Ipv6(v6.clone(), v6_exts.clone()).ipv4(),
1274                 None
1275             );
1276         }
1277     }
1278 
1279     proptest! {
1280         #[test]
1281         fn ipv6(
1282             v4 in ipv4_any(),
1283             v4_exts in ipv4_extensions_any(),
1284             v6 in ipv6_any(),
1285             v6_exts in ipv6_extensions_any(),
1286         ) {
1287             assert_eq!(
1288                 IpHeaders::Ipv4(v4.clone(), v4_exts.clone()).ipv6(),
1289                 None
1290             );
1291             assert_eq!(
1292                 IpHeaders::Ipv6(v6.clone(), v6_exts.clone()).ipv6(),
1293                 Some((&v6, &v6_exts))
1294             );
1295         }
1296     }
1297 
1298     proptest! {
1299         #[test]
1300         #[allow(deprecated)]
1301         fn read_from_slice(
1302             v4 in ipv4_any(),
1303             v4_exts in ipv4_extensions_any(),
1304         ) {
1305             let header = combine_v4(&v4, &v4_exts, &[]);
1306             let mut buffer = Vec::with_capacity(header.header_len());
1307             header.write(&mut buffer).unwrap();
1308 
1309             let actual = IpHeaders::read_from_slice(&buffer).unwrap();
1310             assert_eq!(actual.0, header);
1311             assert_eq!(actual.1, header.next_header().unwrap());
1312             assert_eq!(actual.2, &buffer[buffer.len()..]);
1313         }
1314     }
1315 
1316     proptest! {
1317         #[test]
1318         fn ip_from_slice(
1319             v4 in ipv4_any(),
1320             v4_exts in ipv4_extensions_any(),
1321             v6 in ipv6_any(),
1322             v6_exts in ipv6_extensions_any(),
1323         ) {
1324             use err::ip::{HeadersError::*, HeaderError::*, HeadersSliceError::*};
1325 
1326             // empty error
1327             assert_eq!(
1328                 IpHeaders::from_slice(&[]),
1329                 Err(Len(err::LenError {
1330                     required_len: 1,
1331                     len: 0,
1332                     len_source: LenSource::Slice,
1333                     layer: err::Layer::IpHeader,
1334                     layer_start_offset: 0,
1335                 }))
1336             );
1337 
1338             // unknown version
1339             for version_number in 0..=0xfu8 {
1340                 if version_number != 4 && version_number != 6 {
1341                     assert_eq!(
1342                         IpHeaders::from_slice(&[version_number << 4]),
1343                         Err(Content(Ip(UnsupportedIpVersion { version_number })))
1344                     );
1345                 }
1346             }
1347 
1348             let payload = [1,2,3,4];
1349 
1350             // v4
1351             {
1352                 let header = combine_v4(&v4, &v4_exts, &payload);
1353                 let mut buffer = Vec::with_capacity(header.header_len() + payload.len() + 1);
1354                 header.write(&mut buffer).unwrap();
1355                 buffer.extend_from_slice(&payload);
1356                 buffer.push(1); // add some value to check the return slice
1357 
1358                 // read
1359                 {
1360                     let actual = IpHeaders::from_slice(&buffer).unwrap();
1361                     assert_eq!(&actual.0, &header);
1362                     assert_eq!(
1363                         actual.1,
1364                         IpPayloadSlice{
1365                             ip_number: header.next_header().unwrap(),
1366                             fragmented: header.is_fragmenting_payload(),
1367                             len_source: LenSource::Ipv4HeaderTotalLen,
1368                             payload: &payload
1369                         }
1370                     );
1371                 }
1372 
1373                 // read error ipv4 header
1374                 IpHeaders::from_slice(&buffer[..1]).unwrap_err();
1375 
1376                 // read error ipv4 extensions
1377                 if v4_exts.header_len() > 0 {
1378                     IpHeaders::from_slice(&buffer[..v4.header_len() + 1]).unwrap_err();
1379                 }
1380 
1381                 // total length smaller the header
1382                 {
1383                     let bad_total_len = (v4.header_len() - 1) as u16;
1384 
1385                     let mut buffer = buffer.clone();
1386                     // inject bad total_len
1387                     let bad_total_len_be = bad_total_len.to_be_bytes();
1388                     buffer[2] = bad_total_len_be[0];
1389                     buffer[3] = bad_total_len_be[1];
1390                     assert_eq!(
1391                         IpHeaders::from_slice(&buffer[..]).unwrap_err(),
1392                         HeadersSliceError::Len(LenError{
1393                             required_len: v4.header_len(),
1394                             len: bad_total_len as usize,
1395                             len_source: LenSource::Ipv4HeaderTotalLen,
1396                             layer: Layer::Ipv4Packet,
1397                             layer_start_offset: 0,
1398                         })
1399                     );
1400                 }
1401             }
1402 
1403             // v6
1404             {
1405                 let header = combine_v6(&v6, &v6_exts, &payload);
1406                 let mut buffer = Vec::with_capacity(header.header_len() + payload.len() + 1);
1407                 header.write(&mut buffer).unwrap();
1408                 buffer.extend_from_slice(&payload);
1409                 buffer.push(1); // add some value to check the return slice
1410 
1411                 // len error
1412                 {
1413                     let actual = IpHeaders::from_slice(&buffer).unwrap();
1414                     assert_eq!(&actual.0, &header);
1415                     assert_eq!(
1416                         actual.1,
1417                         IpPayloadSlice{
1418                             ip_number: header.next_header().unwrap(),
1419                             fragmented: header.is_fragmenting_payload(),
1420                             len_source: LenSource::Ipv6HeaderPayloadLen,
1421                             payload: &payload
1422                         }
1423                     );
1424                 }
1425 
1426                 // read error header
1427                 IpHeaders::from_slice(&buffer[..1]).unwrap_err();
1428 
1429                 // read error ipv4 extensions
1430                 if v6_exts.header_len() > 0 {
1431                     IpHeaders::from_slice(&buffer[..Ipv6Header::LEN + 1]).unwrap_err();
1432                 }
1433 
1434                 // len error (with payload len zero)
1435                 if v6_exts.header_len() > 0 {
1436                     let mut buffer = buffer.clone();
1437 
1438                     // inject zero as payload len
1439                     buffer[4] = 0;
1440                     buffer[5] = 0;
1441 
1442                     assert!(
1443                         IpHeaders::from_slice(
1444                             &buffer[..buffer.len() - payload.len() - 2]
1445                         ).is_err()
1446                     );
1447                 }
1448             }
1449         }
1450     }
1451 
1452     proptest! {
1453         #[test]
1454         fn from_slice_lax(
1455             v4 in ipv4_any(),
1456             v4_exts in ipv4_extensions_any(),
1457             v6 in ipv6_any(),
1458             v6_exts in ipv6_extensions_any(),
1459         ) {
1460             use err::ip::{HeaderError::*, LaxHeaderSliceError::*};
1461 
1462             let payload = [1,2,3,4];
1463 
1464             // empty error
1465             assert_eq!(
1466                 IpHeaders::from_slice_lax(&[]),
1467                 Err(Len(err::LenError {
1468                     required_len: 1,
1469                     len: 0,
1470                     len_source: LenSource::Slice,
1471                     layer: err::Layer::IpHeader,
1472                     layer_start_offset: 0,
1473                 }))
1474             );
1475 
1476             // unknown version
1477             for version_number in 0..=0xfu8 {
1478                 if version_number != 4 && version_number != 6 {
1479                     assert_eq!(
1480                         IpHeaders::from_slice_lax(&[version_number << 4]),
1481                         Err(Content(UnsupportedIpVersion { version_number }))
1482                     );
1483                 }
1484             }
1485 
1486             // v4
1487             {
1488                 let header = combine_v4(&v4, &v4_exts, &payload);
1489                 let mut buffer = Vec::with_capacity(header.header_len() + payload.len() + 1);
1490                 header.write(&mut buffer).unwrap();
1491                 buffer.extend_from_slice(&payload);
1492                 buffer.push(1); // add some value to check the return slice
1493 
1494                 // normal read
1495                 {
1496                     let actual = IpHeaders::from_slice_lax(&buffer).unwrap();
1497                     assert_eq!(&actual.0, &header);
1498                     assert_eq!(
1499                         actual.1,
1500                         LaxIpPayloadSlice{
1501                             incomplete: false,
1502                             ip_number: header.next_header().unwrap(),
1503                             fragmented: header.is_fragmenting_payload(),
1504                             len_source: LenSource::Ipv4HeaderTotalLen,
1505                             payload: &payload
1506                         }
1507                     );
1508                 }
1509 
1510                 // error len smaller then min header len
1511                 for len in 1..Ipv4Header::MIN_LEN {
1512                     assert_eq!(
1513                         IpHeaders::from_slice_lax(&buffer[..len]),
1514                         Err(Len(err::LenError {
1515                             required_len: Ipv4Header::MIN_LEN,
1516                             len,
1517                             len_source: LenSource::Slice,
1518                             layer: err::Layer::Ipv4Header,
1519                             layer_start_offset: 0,
1520                         }))
1521                     );
1522                 }
1523 
1524                 // ihl value error
1525                 {
1526                     let mut bad_ihl_buffer = buffer.clone();
1527                     for bad_ihl in 0..5 {
1528                         bad_ihl_buffer[0] = (bad_ihl_buffer[0] & 0xf0) | bad_ihl;
1529                         assert_eq!(
1530                             IpHeaders::from_slice_lax(&bad_ihl_buffer),
1531                             Err(Content(Ipv4HeaderLengthSmallerThanHeader { ihl: bad_ihl }))
1532                         );
1533                     }
1534                 }
1535 
1536                 // ihl len error
1537                 for short_ihl in 5..usize::from(v4.ihl()) {
1538                     assert_eq!(
1539                         IpHeaders::from_slice_lax(&buffer[..4*short_ihl]),
1540                         Err(Len(err::LenError {
1541                             required_len: usize::from(v4.ihl())*4,
1542                             len: 4*short_ihl,
1543                             len_source: LenSource::Slice,
1544                             layer: err::Layer::Ipv4Header,
1545                             layer_start_offset: 0,
1546                         }))
1547                     );
1548                 }
1549 
1550                 // total_len bigger then slice len (fallback to slice len)
1551                 for payload_len in 0..payload.len(){
1552                     let actual = IpHeaders::from_slice_lax(&buffer[..v4.header_len() + v4_exts.header_len() + payload_len]).unwrap();
1553                     assert_eq!(&actual.0, &header);
1554                     assert_eq!(
1555                         actual.1,
1556                         LaxIpPayloadSlice{
1557                             incomplete: true,
1558                             ip_number: header.next_header().unwrap(),
1559                             fragmented: header.is_fragmenting_payload(),
1560                             len_source: LenSource::Slice,
1561                             payload: &payload[..payload_len]
1562                         }
1563                     );
1564                 }
1565 
1566                 // len error ipv4 extensions
1567                 if v4_exts.header_len() > 0 {
1568                     let (_, _, stop_err) = IpHeaders::from_slice_lax(&buffer[..v4.header_len() + 1]).unwrap();
1569                     assert!(stop_err.is_some());
1570                 }
1571 
1572                 // content error ipv4 extensions
1573                 if v4_exts.auth.is_some() {
1574                     use err::ip_auth::HeaderError::ZeroPayloadLen;
1575                     use err::ip_exts::HeadersSliceError::Content;
1576                     use err::ip_exts::HeaderError::Ipv4Ext;
1577 
1578                     // introduce a auth header zero payload error
1579                     let mut errored_buffer = buffer.clone();
1580                     // inject length zero into auth header (not valid, will
1581                     // trigger a content error)
1582                     errored_buffer[v4.header_len() + 1] = 0;
1583 
1584                     let (_, _, stop_err) = IpHeaders::from_slice_lax(&errored_buffer).unwrap();
1585 
1586                     assert_eq!(stop_err, Some((Content(Ipv4Ext(ZeroPayloadLen)), Layer::IpAuthHeader)));
1587                 }
1588 
1589                 // total length smaller the header (fallback to slice len)
1590                 {
1591                     let bad_total_len = (v4.header_len() - 1) as u16;
1592 
1593                     let mut buffer = buffer.clone();
1594                     // inject bad total_len
1595                     let bad_total_len_be = bad_total_len.to_be_bytes();
1596                     buffer[2] = bad_total_len_be[0];
1597                     buffer[3] = bad_total_len_be[1];
1598 
1599                     let actual = IpHeaders::from_slice_lax(&buffer[..]).unwrap();
1600 
1601                     let (v4_header, v4_exts) = header.ipv4().unwrap();
1602                     let expected_headers = IpHeaders::Ipv4(
1603                         {
1604                             let mut expected_v4 = v4_header.clone();
1605                             expected_v4.total_len = bad_total_len;
1606                             expected_v4
1607                         },
1608                         v4_exts.clone()
1609                     );
1610                     assert_eq!(&expected_headers, &actual.0);
1611                     assert_eq!(
1612                         actual.1,
1613                         LaxIpPayloadSlice{
1614                             incomplete: false,
1615                             ip_number: header.next_header().unwrap(),
1616                             fragmented: header.is_fragmenting_payload(),
1617                             len_source: LenSource::Slice,
1618                             payload: &buffer[v4_header.header_len() + v4_exts.header_len()..],
1619                         }
1620                     );
1621                 }
1622             }
1623 
1624             // v6
1625             {
1626                 let header = combine_v6(&v6, &v6_exts, &payload);
1627                 let mut buffer = Vec::with_capacity(header.header_len() + payload.len() + 1);
1628                 header.write(&mut buffer).unwrap();
1629                 buffer.extend_from_slice(&payload);
1630                 buffer.push(1); // add some value to check the return slice
1631 
1632                 // normal read
1633                 {
1634                     let actual = IpHeaders::from_slice_lax(&buffer).unwrap();
1635                     assert_eq!(&actual.0, &header);
1636                     assert_eq!(
1637                         actual.1,
1638                         LaxIpPayloadSlice{
1639                             incomplete: false,
1640                             ip_number: header.next_header().unwrap(),
1641                             fragmented: header.is_fragmenting_payload(),
1642                             len_source: LenSource::Ipv6HeaderPayloadLen,
1643                             payload: &payload
1644                         }
1645                     );
1646                 }
1647 
1648                 // smaller then header
1649                 for len in 1..Ipv6Header::LEN {
1650                     assert_eq!(
1651                         IpHeaders::from_slice_lax(&buffer[..len]),
1652                         Err(Len(err::LenError {
1653                             required_len: Ipv6Header::LEN,
1654                             len,
1655                             len_source: LenSource::Slice,
1656                             layer: err::Layer::Ipv6Header,
1657                             layer_start_offset: 0,
1658                         }))
1659                     );
1660                 }
1661 
1662                 // extension len error
1663                 if v6_exts.header_len() > 0 {
1664                     let (actual, _, stop_err) = IpHeaders::from_slice_lax(&buffer[..v6.header_len() + 1]).unwrap();
1665                     assert_eq!(&actual.ipv6().as_ref().unwrap().0, &header.ipv6().as_ref().unwrap().0);
1666                     assert!(stop_err.is_some());
1667                 }
1668 
1669                 // extension content error
1670                 if v6_exts.auth.is_some() {
1671                     use err::ip_auth::HeaderError::ZeroPayloadLen;
1672                     use err::ip_exts::HeadersSliceError::Content;
1673                     use err::ip_exts::HeaderError::Ipv6Ext;
1674                     use err::ipv6_exts::HeaderError::IpAuth;
1675 
1676                     // introduce a auth header zero payload error
1677                     let mut errored_buffer = buffer.clone();
1678                     let auth_offset = v6.header_len() +
1679                         v6_exts.hop_by_hop_options.as_ref().map(|h| h.header_len()).unwrap_or(0) +
1680                         v6_exts.destination_options.as_ref().map(|h| h.header_len()).unwrap_or(0) +
1681                         v6_exts.routing.as_ref().map(|h| h.routing.header_len()).unwrap_or(0) +
1682                         // routing.final_destination_options skiped, as after auth
1683                         v6_exts.fragment.as_ref().map(|h| h.header_len()).unwrap_or(0);
1684 
1685                     // inject length zero into auth header (not valid, will
1686                     // trigger a content error)
1687                     errored_buffer[auth_offset + 1] = 0;
1688 
1689                     let (_, _, stop_err) = IpHeaders::from_slice_lax(&errored_buffer).unwrap();
1690                     assert_eq!(
1691                         stop_err,
1692                         Some((Content(Ipv6Ext(IpAuth(ZeroPayloadLen))), Layer::IpAuthHeader))
1693                     );
1694                 }
1695 
1696                 // slice smaller then payload len
1697                 for len in (v6.header_len()+v6_exts.header_len())..buffer.len() - 1 {
1698                     let actual = IpHeaders::from_slice_lax(&buffer[..len]).unwrap();
1699                     assert_eq!(&actual.0, &header);
1700                     assert_eq!(
1701                         actual.1,
1702                         LaxIpPayloadSlice{
1703                             incomplete: true,
1704                             ip_number: header.next_header().unwrap(),
1705                             fragmented: header.is_fragmenting_payload(),
1706                             len_source: LenSource::Slice,
1707                             payload: &payload[..len - v6.header_len() - v6_exts.header_len()]
1708                         }
1709                     );
1710                 }
1711 
1712                 // payload len zero (fallback to slice len)
1713                 {
1714                     let mut buffer = buffer.clone();
1715                     // inject zero as payload len
1716                     buffer[4] = 0;
1717                     buffer[5] = 0;
1718 
1719                     let actual = IpHeaders::from_slice_lax(&buffer[..]).unwrap();
1720 
1721                     let (v6_header, v6_exts) = header.ipv6().unwrap();
1722                     let expected_headers = IpHeaders::Ipv6(
1723                         {
1724                             let mut expected_v6 = v6_header.clone();
1725                             expected_v6.payload_length = 0;
1726                             expected_v6
1727                         },
1728                         v6_exts.clone()
1729                     );
1730                     assert_eq!(&expected_headers, &actual.0);
1731                     assert_eq!(
1732                         actual.1,
1733                         LaxIpPayloadSlice{
1734                             incomplete: false,
1735                             ip_number: header.next_header().unwrap(),
1736                             fragmented: header.is_fragmenting_payload(),
1737                             len_source: LenSource::Slice,
1738                             payload: &buffer[v6_header.header_len() + v6_exts.header_len()..],
1739                         }
1740                     );
1741                 }
1742 
1743             }
1744         }
1745     }
1746 
1747     proptest! {
1748         #[test]
1749         fn from_ipv4_slice(
1750             v4 in ipv4_any(),
1751             v4_exts in ipv4_extensions_any(),
1752         ) {
1753             let payload = [1,2,3,4];
1754 
1755             let header = combine_v4(&v4, &v4_exts, &payload);
1756             let mut buffer = Vec::with_capacity(header.header_len() + payload.len() + 1);
1757             header.write(&mut buffer).unwrap();
1758             buffer.extend_from_slice(&payload);
1759             buffer.push(1); // add some value to check the return slice
1760 
1761             // read
1762             {
1763                 let actual = IpHeaders::from_ipv4_slice(&buffer).unwrap();
1764                 assert_eq!(&actual.0, &header);
1765                 assert_eq!(
1766                     actual.1,
1767                     IpPayloadSlice{
1768                         ip_number: header.next_header().unwrap(),
1769                         fragmented: header.is_fragmenting_payload(),
1770                         len_source: LenSource::Ipv4HeaderTotalLen,
1771                         payload: &payload
1772                     }
1773                 );
1774             }
1775 
1776             // read error ipv4 header
1777             IpHeaders::from_ipv4_slice(&buffer[..1]).unwrap_err();
1778 
1779             // read error ipv4 extensions
1780             if v4_exts.header_len() > 0 {
1781                 IpHeaders::from_ipv4_slice(&buffer[..v4.header_len() + 1]).unwrap_err();
1782             }
1783 
1784             // total length smaller the header
1785             {
1786                 let bad_total_len = (v4.header_len() - 1) as u16;
1787 
1788                 let mut buffer = buffer.clone();
1789                 // inject bad total_len
1790                 let bad_total_len_be = bad_total_len.to_be_bytes();
1791                 buffer[2] = bad_total_len_be[0];
1792                 buffer[3] = bad_total_len_be[1];
1793                 assert_eq!(
1794                     IpHeaders::from_ipv4_slice(&buffer[..]).unwrap_err(),
1795                     err::ipv4::SliceError::Len(LenError{
1796                         required_len: v4.header_len(),
1797                         len: bad_total_len as usize,
1798                         len_source: LenSource::Ipv4HeaderTotalLen,
1799                         layer: Layer::Ipv4Packet,
1800                         layer_start_offset: 0,
1801                     })
1802                 );
1803             }
1804         }
1805     }
1806 
1807     proptest! {
1808         #[test]
1809         fn from_ipv4_slice_lax(
1810             v4 in ipv4_any(),
1811             v4_exts in ipv4_extensions_any()
1812         ) {
1813             use err::ip::{LaxHeaderSliceError::*, HeaderError::*};
1814 
1815             let payload = [1,2,3,4];
1816 
1817             // empty error
1818             assert_eq!(
1819                 IpHeaders::from_ipv4_slice_lax(&[]),
1820                 Err(Len(err::LenError {
1821                     required_len: 20,
1822                     len: 0,
1823                     len_source: LenSource::Slice,
1824                     layer: err::Layer::Ipv4Header,
1825                     layer_start_offset: 0,
1826                 }))
1827             );
1828 
1829             // build a buffer with a valid packet
1830             let header = combine_v4(&v4, &v4_exts, &payload);
1831             let mut buffer = Vec::with_capacity(header.header_len() + payload.len() + 1);
1832             header.write(&mut buffer).unwrap();
1833             buffer.extend_from_slice(&payload);
1834             buffer.push(1); // add some value to check the return slice
1835 
1836             // normal read
1837             {
1838                 let actual = IpHeaders::from_ipv4_slice_lax(&buffer).unwrap();
1839                 assert_eq!(&actual.0, &header);
1840                 assert_eq!(
1841                     actual.1,
1842                     LaxIpPayloadSlice{
1843                         incomplete: false,
1844                         ip_number: header.next_header().unwrap(),
1845                         fragmented: header.is_fragmenting_payload(),
1846                         len_source: LenSource::Ipv4HeaderTotalLen,
1847                         payload: &payload
1848                     }
1849                 );
1850             }
1851 
1852             // error len smaller then min header len
1853             for len in 1..Ipv4Header::MIN_LEN {
1854                 assert_eq!(
1855                     IpHeaders::from_ipv4_slice_lax(&buffer[..len]),
1856                     Err(Len(err::LenError {
1857                         required_len: Ipv4Header::MIN_LEN,
1858                         len,
1859                         len_source: LenSource::Slice,
1860                         layer: err::Layer::Ipv4Header,
1861                         layer_start_offset: 0,
1862                     }))
1863                 );
1864             }
1865 
1866             // ihl value error
1867             {
1868                 let mut bad_ihl_buffer = buffer.clone();
1869                 for bad_ihl in 0..5 {
1870                     bad_ihl_buffer[0] = (bad_ihl_buffer[0] & 0xf0) | bad_ihl;
1871                     assert_eq!(
1872                         IpHeaders::from_ipv4_slice_lax(&bad_ihl_buffer),
1873                         Err(Content(Ipv4HeaderLengthSmallerThanHeader { ihl: bad_ihl }))
1874                     );
1875                 }
1876             }
1877 
1878             // ihl len error
1879             for short_ihl in 5..usize::from(v4.ihl()) {
1880                 assert_eq!(
1881                     IpHeaders::from_ipv4_slice_lax(&buffer[..4*short_ihl]),
1882                     Err(Len(err::LenError {
1883                         required_len: usize::from(v4.ihl())*4,
1884                         len: 4*short_ihl,
1885                         len_source: LenSource::Slice,
1886                         layer: err::Layer::Ipv4Header,
1887                         layer_start_offset: 0,
1888                     }))
1889                 );
1890             }
1891 
1892             // total_len bigger then slice len (fallback to slice len)
1893             for payload_len in 0..payload.len(){
1894                 let actual = IpHeaders::from_ipv4_slice_lax(&buffer[..v4.header_len() + v4_exts.header_len() + payload_len]).unwrap();
1895                 assert_eq!(&actual.0, &header);
1896                 assert_eq!(
1897                     actual.1,
1898                     LaxIpPayloadSlice{
1899                         incomplete: true,
1900                         ip_number: header.next_header().unwrap(),
1901                         fragmented: header.is_fragmenting_payload(),
1902                         len_source: LenSource::Slice,
1903                         payload: &payload[..payload_len]
1904                     }
1905                 );
1906             }
1907 
1908             // len error ipv4 extensions
1909             if v4_exts.header_len() > 0 {
1910                 let (actual, _, stop_err) = IpHeaders::from_ipv4_slice_lax(&buffer[..v4.header_len() + 1]).unwrap();
1911                 assert_eq!(actual.ipv4().unwrap().0, header.ipv4().unwrap().0);
1912                 assert!(stop_err.is_some());
1913             }
1914 
1915             // content error ipv4 extensions
1916             if v4_exts.auth.is_some() {
1917                 use err::ip_auth::HeaderSliceError::Content;
1918                 use err::ip_auth::HeaderError::ZeroPayloadLen;
1919 
1920                 // introduce a auth header zero payload error
1921                 let mut errored_buffer = buffer.clone();
1922                 // inject length zero into auth header (not valid, will
1923                 // trigger a content error)
1924                 errored_buffer[v4.header_len() + 1] = 0;
1925 
1926                 let (_, _, stop_err) = IpHeaders::from_ipv4_slice_lax(&errored_buffer).unwrap();
1927                 assert_eq!(stop_err, Some(Content(ZeroPayloadLen)));
1928             }
1929 
1930             // total length smaller the header (fallback to slice len)
1931             {
1932                 let bad_total_len = (v4.header_len() - 1) as u16;
1933 
1934                 let mut buffer = buffer.clone();
1935                 // inject bad total_len
1936                 let bad_total_len_be = bad_total_len.to_be_bytes();
1937                 buffer[2] = bad_total_len_be[0];
1938                 buffer[3] = bad_total_len_be[1];
1939 
1940                 let actual = IpHeaders::from_ipv4_slice_lax(&buffer[..]).unwrap();
1941 
1942                 let (v4_header, v4_exts) = header.ipv4().unwrap();
1943                 let expected_headers = IpHeaders::Ipv4(
1944                     {
1945                         let mut expected_v4 = v4_header.clone();
1946                         expected_v4.total_len = bad_total_len;
1947                         expected_v4
1948                     },
1949                     v4_exts.clone()
1950                 );
1951                 assert_eq!(&expected_headers, &actual.0);
1952                 assert_eq!(
1953                     actual.1,
1954                     LaxIpPayloadSlice{
1955                         incomplete: false,
1956                         ip_number: header.next_header().unwrap(),
1957                         fragmented: header.is_fragmenting_payload(),
1958                         len_source: LenSource::Slice,
1959                         payload: &buffer[v4_header.header_len() + v4_exts.header_len()..],
1960                     }
1961                 );
1962             }
1963         }
1964     }
1965 
1966     proptest! {
1967         #[test]
1968         fn from_ipv6_slice(
1969             v6 in ipv6_any(),
1970             v6_exts in ipv6_extensions_any(),
1971         ) {
1972             let payload = [1,2,3,4];
1973             let header = combine_v6(&v6, &v6_exts, &payload);
1974             let mut buffer = Vec::with_capacity(header.header_len() + payload.len() + 1);
1975             header.write(&mut buffer).unwrap();
1976             buffer.extend_from_slice(&payload);
1977             buffer.push(1); // add some value to check the return slice
1978 
1979             // len error
1980             {
1981                 let actual = IpHeaders::from_ipv6_slice(&buffer).unwrap();
1982                 assert_eq!(&actual.0, &header);
1983                 assert_eq!(
1984                     actual.1,
1985                     IpPayloadSlice{
1986                         ip_number: header.next_header().unwrap(),
1987                         fragmented: header.is_fragmenting_payload(),
1988                         len_source: LenSource::Ipv6HeaderPayloadLen,
1989                         payload: &payload
1990                     }
1991                 );
1992             }
1993 
1994             // read error header
1995             IpHeaders::from_ipv6_slice(&buffer[..1]).unwrap_err();
1996 
1997             // read error ipv4 extensions
1998             if v6_exts.header_len() > 0 {
1999                 IpHeaders::from_ipv6_slice(&buffer[..Ipv6Header::LEN + 1]).unwrap_err();
2000             }
2001 
2002             // len error (with payload len zero)
2003             if v6_exts.header_len() > 0 {
2004                 let mut buffer = buffer.clone();
2005 
2006                 // inject zero as payload len
2007                 buffer[4] = 0;
2008                 buffer[5] = 0;
2009 
2010                 assert!(
2011                     IpHeaders::from_ipv6_slice(
2012                         &buffer[..buffer.len() - payload.len() - 2]
2013                     ).is_err()
2014                 );
2015             }
2016         }
2017     }
2018 
2019     proptest! {
2020         #[test]
2021         fn from_ipv6_slice_lax(
2022             v6 in ipv6_any(),
2023             v6_exts in ipv6_extensions_any(),
2024             bad_version in 0..0xfu8
2025         ) {
2026             use err::ipv6::{HeaderError::*, HeaderSliceError::*};
2027 
2028             let payload = [1,2,3,4];
2029 
2030             // empty error
2031             assert_eq!(
2032                 IpHeaders::from_ipv6_slice_lax(&[]),
2033                 Err(Len(err::LenError {
2034                     required_len: Ipv6Header::LEN,
2035                     len: 0,
2036                     len_source: LenSource::Slice,
2037                     layer: err::Layer::Ipv6Header,
2038                     layer_start_offset: 0,
2039                 }))
2040             );
2041 
2042             // setup buffer with a valid packet
2043             let header = combine_v6(&v6, &v6_exts, &payload);
2044             let mut buffer = Vec::with_capacity(header.header_len() + payload.len() + 1);
2045             header.write(&mut buffer).unwrap();
2046             buffer.extend_from_slice(&payload);
2047             buffer.push(1); // add some value to check the return slice
2048 
2049             // unknown version
2050             if bad_version != 6 {
2051                 let mut bad_vers_buffer = buffer.clone();
2052                 bad_vers_buffer[0] = (bad_vers_buffer[0] & 0xf) | (bad_version << 4);
2053                 assert_eq!(
2054                     IpHeaders::from_ipv6_slice_lax(&bad_vers_buffer),
2055                     Err(Content(UnexpectedVersion { version_number: bad_version }))
2056                 );
2057             }
2058 
2059             // normal read
2060             {
2061                 let actual = IpHeaders::from_ipv6_slice_lax(&buffer).unwrap();
2062                 assert_eq!(&actual.0, &header);
2063                 assert_eq!(
2064                     actual.1,
2065                     LaxIpPayloadSlice{
2066                         incomplete: false,
2067                         ip_number: header.next_header().unwrap(),
2068                         fragmented: header.is_fragmenting_payload(),
2069                         len_source: LenSource::Ipv6HeaderPayloadLen,
2070                         payload: &payload
2071                     }
2072                 );
2073             }
2074 
2075             // smaller then header
2076             for len in 1..Ipv6Header::LEN {
2077                 assert_eq!(
2078                     IpHeaders::from_ipv6_slice_lax(&buffer[..len]),
2079                     Err(Len(err::LenError {
2080                         required_len: Ipv6Header::LEN,
2081                         len,
2082                         len_source: LenSource::Slice,
2083                         layer: err::Layer::Ipv6Header,
2084                         layer_start_offset: 0,
2085                     }))
2086                 );
2087             }
2088 
2089             // extension len error
2090             if v6_exts.header_len() > 0 {
2091                 let (_, _, err) = IpHeaders::from_ipv6_slice_lax(&buffer[..v6.header_len() + 1]).unwrap();
2092                 assert!(err.is_some());
2093             }
2094 
2095             // extension content error
2096             if v6_exts.auth.is_some() {
2097                 use err::ip_auth::HeaderError::ZeroPayloadLen;
2098                 use err::ipv6_exts::{HeaderSliceError::Content, HeaderError::IpAuth};
2099 
2100                 // introduce a auth header zero payload error
2101                 let mut errored_buffer = buffer.clone();
2102                 let auth_offset = v6.header_len() +
2103                     v6_exts.hop_by_hop_options.as_ref().map(|h| h.header_len()).unwrap_or(0) +
2104                     v6_exts.destination_options.as_ref().map(|h| h.header_len()).unwrap_or(0) +
2105                     v6_exts.routing.as_ref().map(|h| h.routing.header_len()).unwrap_or(0) +
2106                     // routing.final_destination_options skiped, as after auth
2107                     v6_exts.fragment.as_ref().map(|h| h.header_len()).unwrap_or(0);
2108 
2109                 // inject length zero into auth header (not valid, will
2110                 // trigger a content error)
2111                 errored_buffer[auth_offset + 1] = 0;
2112                 let (_, _, err) = IpHeaders::from_ipv6_slice_lax(&errored_buffer).unwrap();
2113                 assert_eq!(err, Some((Content(IpAuth(ZeroPayloadLen)), Layer::IpAuthHeader)));
2114             }
2115 
2116             // slice smaller then payload len
2117             for len in (v6.header_len()+v6_exts.header_len())..buffer.len() - 1 {
2118                 let actual = IpHeaders::from_ipv6_slice_lax(&buffer[..len]).unwrap();
2119                 assert_eq!(&actual.0, &header);
2120                 assert_eq!(
2121                     actual.1,
2122                     LaxIpPayloadSlice{
2123                         incomplete: true,
2124                         ip_number: header.next_header().unwrap(),
2125                         fragmented: header.is_fragmenting_payload(),
2126                         len_source: LenSource::Slice,
2127                         payload: &payload[..len - v6.header_len() - v6_exts.header_len()]
2128                     }
2129                 );
2130             }
2131 
2132             // payload len zero (fallback to slice len)
2133             {
2134                 let mut buffer = buffer.clone();
2135                 // inject zero as payload len
2136                 buffer[4] = 0;
2137                 buffer[5] = 0;
2138 
2139                 let actual = IpHeaders::from_ipv6_slice_lax(&buffer[..]).unwrap();
2140 
2141                 let (v6_header, v6_exts) = header.ipv6().unwrap();
2142                 let expected_headers = IpHeaders::Ipv6(
2143                     {
2144                         let mut expected_v6 = v6_header.clone();
2145                         expected_v6.payload_length = 0;
2146                         expected_v6
2147                     },
2148                     v6_exts.clone()
2149                 );
2150                 assert_eq!(&expected_headers, &actual.0);
2151                 assert_eq!(
2152                     actual.1,
2153                     LaxIpPayloadSlice{
2154                         incomplete: false,
2155                         ip_number: header.next_header().unwrap(),
2156                         fragmented: header.is_fragmenting_payload(),
2157                         len_source: LenSource::Slice,
2158                         payload: &buffer[v6_header.header_len() + v6_exts.header_len()..],
2159                     }
2160                 );
2161             }
2162         }
2163     }
2164 
2165     proptest! {
2166         #[test]
2167         fn read(
2168             v4 in ipv4_any(),
2169             v4_exts in ipv4_extensions_any(),
2170             bad_ihl in 0u8..5u8,
2171             v6 in ipv6_any(),
2172             v6_exts in ipv6_extensions_any(),
2173         ) {
2174             use err::ip::{HeadersError::*, HeaderError::*};
2175 
2176             // no data error
2177             {
2178                 let mut cursor = Cursor::new(&[]);
2179                 assert!(
2180                     IpHeaders::read(&mut cursor)
2181                     .unwrap_err()
2182                     .io()
2183                     .is_some()
2184                 );
2185             }
2186             // version error
2187             {
2188                 let mut cursor = Cursor::new(&[0xf << 4]);
2189                 assert_eq!(
2190                     IpHeaders::read(&mut cursor).unwrap_err().content().unwrap(),
2191                     Ip(UnsupportedIpVersion {
2192                         version_number: 0xf
2193                     })
2194                 );
2195             }
2196             // v4
2197             {
2198                 let header = combine_v4(&v4, &v4_exts, &[]);
2199                 let mut buffer = Vec::with_capacity(header.header_len());
2200                 header.write(&mut buffer).unwrap();
2201 
2202                 // read
2203                 {
2204                     let mut cursor = Cursor::new(&buffer[..]);
2205                     let actual = IpHeaders::read(&mut cursor).unwrap();
2206                     assert_eq!(actual.0, header);
2207                     assert_eq!(actual.1, header.next_header().unwrap());
2208                 }
2209 
2210                 // read error ihl smaller then header
2211                 {
2212                     let mut buffer = buffer.clone();
2213                     // inject bad ihl
2214                     buffer[0] = (buffer[0] & 0b1111_0000) | bad_ihl;
2215                     let mut cursor = Cursor::new(&buffer[..]);
2216                     assert_eq!(
2217                         IpHeaders::read(&mut cursor)
2218                         .unwrap_err()
2219                         .content()
2220                         .unwrap(),
2221                         Ip(Ipv4HeaderLengthSmallerThanHeader{
2222                             ihl: bad_ihl
2223                         })
2224                     );
2225                 }
2226 
2227                 // total length smaller the header
2228                 {
2229                     let bad_total_len = (v4.header_len() - 1) as u16;
2230 
2231                     let mut buffer = buffer.clone();
2232                     // inject bad total_len
2233                     let bad_total_len_be = bad_total_len.to_be_bytes();
2234                     buffer[2] = bad_total_len_be[0];
2235                     buffer[3] = bad_total_len_be[1];
2236                     let mut cursor = Cursor::new(&buffer[..]);
2237                     assert_eq!(
2238                         IpHeaders::read(&mut cursor)
2239                         .unwrap_err()
2240                         .len()
2241                         .unwrap(),
2242                         LenError{
2243                             required_len: v4.header_len(),
2244                             len: bad_total_len as usize,
2245                             len_source: LenSource::Ipv4HeaderTotalLen,
2246                             layer: Layer::Ipv4Packet,
2247                             layer_start_offset: 0,
2248                         }
2249                     );
2250                 }
2251 
2252                 // read len error ipv4
2253                 {
2254                     let mut cursor = Cursor::new(&buffer[..1]);
2255                     assert!(
2256                         IpHeaders::read(&mut cursor)
2257                         .unwrap_err()
2258                         .io()
2259                         .is_some()
2260                     );
2261                 }
2262 
2263                 // read error ipv4 extensions
2264                 if v4_exts.header_len() > 0 {
2265                     let mut cursor = Cursor::new(&buffer[..v4.header_len() + 1]);
2266                     IpHeaders::read(&mut cursor).unwrap_err();
2267                 }
2268 
2269                 // len error in extensions
2270                 if v4_exts.auth.is_some() {
2271                     let bad_total_len = (buffer.len() - 1) as u16;
2272 
2273                     let mut buffer = buffer.clone();
2274                     // inject bad total_len
2275                     let bad_total_len_be = bad_total_len.to_be_bytes();
2276                     buffer[2] = bad_total_len_be[0];
2277                     buffer[3] = bad_total_len_be[1];
2278                     let mut cursor = Cursor::new(&buffer[..]);
2279                     assert_eq!(
2280                         IpHeaders::read(&mut cursor)
2281                         .unwrap_err()
2282                         .len()
2283                         .unwrap(),
2284                         LenError{
2285                             required_len: buffer.len() - v4.header_len(),
2286                             len: bad_total_len as usize - v4.header_len(),
2287                             len_source: LenSource::Ipv4HeaderTotalLen,
2288                             layer: Layer::IpAuthHeader,
2289                             layer_start_offset: v4.header_len(),
2290                         }
2291                     );
2292                 }
2293 
2294                 // extension content error
2295                 if v4_exts.auth.is_some() {
2296                     let mut buffer = buffer.clone();
2297                     // inject zero as header len
2298                     buffer[v4.header_len() + 1] = 0;
2299                     let mut cursor = Cursor::new(&buffer[..]);
2300                     assert_eq!(
2301                         IpHeaders::read(&mut cursor)
2302                         .unwrap_err()
2303                         .content()
2304                         .unwrap(),
2305                         HeadersError::Ipv4Ext(
2306                             err::ip_auth::HeaderError::ZeroPayloadLen
2307                         )
2308                     );
2309                 }
2310             }
2311 
2312             // v6
2313             {
2314                 let header = combine_v6(&v6, &v6_exts, &[]);
2315                 let mut buffer = Vec::with_capacity(header.header_len());
2316                 header.write(&mut buffer).unwrap();
2317 
2318                 // ok case
2319                 {
2320                     let mut cursor = Cursor::new(&buffer[..]);
2321                     let actual = IpHeaders::read(&mut cursor).unwrap();
2322                     assert_eq!(actual.0, header);
2323                     assert_eq!(actual.1, header.next_header().unwrap());
2324                 }
2325 
2326                 // io error in v6 header section
2327                 {
2328                     let mut cursor = Cursor::new(&buffer[..1]);
2329                     assert!(
2330                         IpHeaders::read(&mut cursor).unwrap_err().io().is_some()
2331                     );
2332                 }
2333 
2334                 // io error ipv6 extensions
2335                 if v6_exts.header_len() > 0 {
2336                     let mut cursor = Cursor::new(&buffer[..Ipv6Header::LEN + 1]);
2337                     assert!(
2338                         IpHeaders::read(&mut cursor).unwrap_err().io().is_some()
2339                     );
2340                 }
2341 
2342                 // len error in ipv6 extensions
2343                 if v6_exts.header_len() > 0 {
2344                     // inject an invalid length
2345                     let mut buffer = buffer.clone();
2346                     let bad_payload_len = (buffer.len() - header.header_len()) as u16;
2347                     let bad_payload_len_be = bad_payload_len.to_be_bytes();
2348                     buffer[4] = bad_payload_len_be[0];
2349                     buffer[5] = bad_payload_len_be[1];
2350                     // expect a length error
2351                     let mut cursor = Cursor::new(&buffer[..]);
2352                     assert!(
2353                         IpHeaders::read(&mut cursor).unwrap_err().len().is_some()
2354                     );
2355                 }
2356 
2357                 // extension content error
2358                 if let Some(auth) = v6_exts.auth.as_ref() {
2359                     // only do it if auth is the last header
2360                     if v6_exts.routing.is_none() {
2361                         // inject zero as header len
2362                         let mut buffer = buffer.clone();
2363                         let auth_offset = buffer.len() - auth.header_len();
2364                         buffer[auth_offset + 1] = 0;
2365                         let mut cursor = Cursor::new(&buffer[..]);
2366                         assert_eq!(
2367                             IpHeaders::read(&mut cursor)
2368                             .unwrap_err()
2369                             .content()
2370                             .unwrap(),
2371                             HeadersError::Ipv6Ext(err::ipv6_exts::HeaderError::IpAuth(
2372                                 err::ip_auth::HeaderError::ZeroPayloadLen
2373                             ))
2374                         );
2375                     }
2376                 }
2377             }
2378         }
2379     }
2380 
2381     proptest! {
2382         #[test]
2383         fn write(
2384             v4 in ipv4_any(),
2385             v4_exts in ipv4_extensions_any(),
2386             v6 in ipv6_any(),
2387             v6_exts in ipv6_extensions_any(),
2388         ) {
2389             // v4
2390             {
2391                 let header = combine_v4(&v4, &v4_exts, &[]);
2392                 let mut buffer = Vec::with_capacity(header.header_len());
2393                 header.write(&mut buffer).unwrap();
2394 
2395                 let actual = IpHeaders::from_slice(&buffer).unwrap().0;
2396                 assert_eq!(header, actual);
2397 
2398                 // write error v4 header
2399                 {
2400                     let mut buffer = [0u8;1];
2401                     let mut cursor = Cursor::new(&mut buffer[..]);
2402                     assert!(
2403                         header.write(&mut cursor)
2404                         .unwrap_err()
2405                         .io()
2406                         .is_some()
2407                     );
2408                 }
2409 
2410                 // write io error v4 extension headers
2411                 if v4_exts.header_len() > 0 {
2412                     let mut buffer = [0u8;Ipv4Header::MAX_LEN + 1];
2413                     let mut cursor = Cursor::new(&mut buffer[..v4.header_len() + 1]);
2414                     assert!(
2415                         header.write(&mut cursor)
2416                         .unwrap_err()
2417                         .io()
2418                         .is_some()
2419                     );
2420                 }
2421 
2422                 // write content error v4 extension headers
2423                 if v4_exts.header_len() > 0 {
2424                     // cause a missing reference error
2425                     let header = IpHeaders::Ipv4(
2426                         {
2427                             let mut v4 = v4.clone();
2428                             // skips extension header
2429                             v4.protocol = ip_number::UDP;
2430                             v4.total_len = (v4.header_len() + v4_exts.header_len()) as u16;
2431                             v4.header_checksum = v4.calc_header_checksum();
2432                             v4
2433                         },
2434                         v4_exts.clone(),
2435                     );
2436                     let mut buffer = [0u8;Ipv4Header::MAX_LEN + IpAuthHeader::MAX_LEN];
2437                     let mut cursor = Cursor::new(&mut buffer[..]);
2438                     assert!(header.write(&mut cursor).is_err());
2439                 }
2440             }
2441 
2442             // v6
2443             {
2444                 let header = combine_v6(&v6, &v6_exts, &[]);
2445 
2446                 // normal write
2447                 let mut buffer = Vec::with_capacity(header.header_len());
2448                 header.write(&mut buffer).unwrap();
2449 
2450                 let actual = IpHeaders::from_slice(&buffer).unwrap().0;
2451                 assert_eq!(header, actual);
2452 
2453                 // write error v6 header
2454                 {
2455                     let mut buffer = [0u8;1];
2456                     let mut cursor = Cursor::new(&mut buffer[..]);
2457                     assert!(
2458                         header.write(&mut cursor)
2459                         .unwrap_err()
2460                         .io()
2461                         .is_some()
2462                     );
2463                 }
2464 
2465                 // write error v6 extension headers
2466                 if v6_exts.header_len() > 0 {
2467                     let mut buffer = [0u8;Ipv6Header::LEN + 1];
2468                     let mut cursor = Cursor::new(&mut buffer[..]);
2469                     assert!(
2470                         header.write(&mut cursor)
2471                         .unwrap_err()
2472                         .io()
2473                         .is_some()
2474                     );
2475                 }
2476                 // write content error v4 extension headers
2477                 if v6_exts.header_len() > 0 {
2478                     // cause a missing reference error
2479                     let header = IpHeaders::Ipv6(
2480                         {
2481                             let mut v6 = v6.clone();
2482                             // skips extension header
2483                             v6.next_header = ip_number::UDP;
2484                             v6.payload_length = v6_exts.header_len() as u16;
2485                             v6
2486                         },
2487                         v6_exts.clone(),
2488                     );
2489                     let mut buffer = [0u8;Ipv4Header::MAX_LEN + IpAuthHeader::MAX_LEN];
2490                     let mut cursor = Cursor::new(&mut buffer[..]);
2491                     assert!(header.write(&mut cursor).is_err());
2492                 }
2493             }
2494         }
2495     }
2496 
2497     proptest! {
2498         #[test]
2499         fn header_len(
2500             v4 in ipv4_any(),
2501             v4_exts in ipv4_extensions_any(),
2502             v6 in ipv6_any(),
2503             v6_exts in ipv6_extensions_any(),
2504         ) {
2505             assert_eq!(
2506                 v4.header_len() + v4_exts.header_len(),
2507                 IpHeaders::Ipv4(v4, v4_exts).header_len()
2508             );
2509             assert_eq!(
2510                 Ipv6Header::LEN + v6_exts.header_len(),
2511                 IpHeaders::Ipv6(v6, v6_exts).header_len()
2512             );
2513         }
2514     }
2515 
2516     proptest! {
2517         #[test]
2518         fn next_header(
2519             v4 in ipv4_any(),
2520             v4_exts in ipv4_extensions_any(),
2521             v6 in ipv6_any(),
2522             v6_exts in ipv6_extensions_any(),
2523             post_header in ip_number_any()
2524                 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(),
2525                     |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x)
2526                 )
2527         ) {
2528             {
2529                 let mut header = v4.clone();
2530                 let mut exts = v4_exts.clone();
2531                 header.protocol = exts.set_next_headers(post_header);
2532                 assert_eq!(
2533                     Ok(post_header),
2534                     IpHeaders::Ipv4(header, exts).next_header()
2535                 );
2536             }
2537             {
2538                 let mut header = v6.clone();
2539                 let mut exts = v6_exts.clone();
2540                 header.next_header = exts.set_next_headers(post_header);
2541                 assert_eq!(
2542                     Ok(post_header),
2543                     IpHeaders::Ipv6(header, exts).next_header()
2544                 );
2545             }
2546         }
2547     }
2548 
2549     // TODO set_next_headers
2550 
2551     proptest! {
2552         #[test]
2553         fn set_payload_len(
2554             v4 in ipv4_any(),
2555             v4_exts in ipv4_extensions_any(),
2556             v6 in ipv6_any(),
2557             v6_exts in ipv6_extensions_any(),
2558             payload_len in 0usize..10
2559         ) {
2560             // ipv4 (with valid payload length)
2561             {
2562                 let mut actual = IpHeaders::Ipv4(
2563                     v4.clone(),
2564                     v4_exts.clone()
2565                 );
2566                 actual.set_payload_len(payload_len).unwrap();
2567 
2568                 assert_eq!(
2569                     actual,
2570                     IpHeaders::Ipv4(
2571                         {
2572                             let mut re = v4.clone();
2573                             re.set_payload_len(v4_exts.header_len() + payload_len).unwrap();
2574                             re
2575                         },
2576                         v4_exts.clone()
2577                     )
2578                 );
2579             }
2580             // ipv6 (with valid payload length)
2581             {
2582                 let mut actual = IpHeaders::Ipv6(
2583                     v6.clone(),
2584                     v6_exts.clone()
2585                 );
2586                 actual.set_payload_len(payload_len).unwrap();
2587 
2588                 assert_eq!(
2589                     actual,
2590                     IpHeaders::Ipv6(
2591                         {
2592                             let mut re = v6.clone();
2593                             re.set_payload_length(v6_exts.header_len() + payload_len).unwrap();
2594                             re
2595                         },
2596                         v6_exts.clone()
2597                     )
2598                 );
2599             }
2600 
2601             // v4 (with invalid size)
2602             {
2603                 let mut actual = IpHeaders::Ipv4(
2604                     v4.clone(),
2605                     v4_exts.clone()
2606                 );
2607                 assert!(actual.set_payload_len(usize::MAX).is_err());
2608             }
2609 
2610             // v6 (with invalid size)
2611             {
2612                 let mut actual = IpHeaders::Ipv6(
2613                     v6.clone(),
2614                     v6_exts.clone()
2615                 );
2616                 assert!(actual.set_payload_len(usize::MAX).is_err());
2617             }
2618         }
2619     }
2620 
2621     proptest! {
2622         #[test]
2623         fn is_fragmenting_payload(
2624             v4 in ipv4_any(),
2625             v4_exts in ipv4_extensions_any(),
2626             v6 in ipv6_any(),
2627             v6_exts in ipv6_extensions_any()
2628         ) {
2629             // ipv4
2630             assert_eq!(
2631                 v4.is_fragmenting_payload(),
2632                 IpHeaders::Ipv4(v4.clone(), v4_exts.clone()).is_fragmenting_payload()
2633             );
2634 
2635             // ipv6
2636             assert_eq!(
2637                 v6_exts.is_fragmenting_payload(),
2638                 IpHeaders::Ipv6(v6.clone(), v6_exts.clone()).is_fragmenting_payload()
2639             );
2640         }
2641     }
2642 }
2643