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