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

etherparse/net/
lax_ip_slice.rs

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