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}