1 use crate::{ 2 err::{ipv6, ipv6_exts}, 3 *, 4 }; 5 6 /// Slice containing laxly separated IPv6 headers & payload. 7 /// 8 /// Compared to the normal [`Ipv6Slice`] this slice allows the 9 /// payload to incomplete/cut off and errors to be present in 10 /// the IpPayload. 11 /// 12 /// The main usecases for "laxly" parsed slices are are: 13 /// 14 /// * Parsing packets that have been cut off. This is, for example, useful to 15 /// parse packets returned via ICMP as these usually only contain the start. 16 /// * Parsing packets where the `total_len` (for IPv4) have not yet been set. 17 /// This can be useful when parsing packets which have been recorded in a 18 /// layer before the length field was set (e.g. before the operating 19 /// system set the length fields). 20 #[derive(Clone, Debug, Eq, PartialEq)] 21 pub struct LaxIpv6Slice<'a> { 22 pub(crate) header: Ipv6HeaderSlice<'a>, 23 pub(crate) exts: Ipv6ExtensionsSlice<'a>, 24 pub(crate) payload: LaxIpPayloadSlice<'a>, 25 } 26 27 impl<'a> LaxIpv6Slice<'a> { 28 /// Seperate an IPv6 header (+ extensions) & the payload from the given slice with 29 /// less strict length checks (useful for cut off packet or for packets with 30 /// unset length fields). 31 /// 32 /// If you want to only receive correct IpPayloads use [`crate::Ipv4Slice::from_slice`] 33 /// instead. 34 /// 35 /// The main usecases for this functions are: 36 /// 37 /// * Parsing packets that have been cut off. This is, for example, useful to 38 /// parse packets returned via ICMP as these usually only contain the start. 39 /// * Parsing packets where the `payload_length` (in the IPv6 header) has not 40 /// yet been set. This can be useful when parsing packets which have been 41 /// recorded in a layer before the length field was set (e.g. before the operating 42 /// system set the length fields). 43 /// 44 /// # Differences to `from_slice`: 45 /// 46 /// There are two main differences: 47 /// 48 /// * Errors in the expansion headers will only stop the parsing and return an `Ok` 49 /// with the successfully parsed parts and the error as optional. Only if an 50 /// unrecoverable error is encountered in the IP header itself an `Err` is returned. 51 /// In the normal `Ipv4Slice::from_slice` function an `Err` is returned if an error is 52 /// encountered in an exteions header. 53 /// * `LaxIpv4Slice::from_slice` ignores inconsistent `payload_length` values. When the 54 /// `payload_length` value in the IPv6 header is inconsistant the length of 55 /// the given slice is used as a substitute. 56 /// 57 /// You can check if the slice length was used as a substitude by checking 58 /// if the `len_source` value in the returned [`IpPayloadSlice`] is set to 59 /// [`LenSource::Slice`]. If a substitution was not needed `len_source` 60 /// is set to [`LenSource::Ipv6HeaderPayloadLen`]. 61 /// 62 /// # When is the slice length used as a fallback? 63 /// 64 /// The slice length is used as a fallback/substitude if the `payload_length` 65 /// field in the IPv6 header is 66 /// 67 /// * Bigger then the given slice (payload cannot fully be seperated). 68 /// * The value `0`. from_slice( slice: &'a [u8], ) -> Result< ( LaxIpv6Slice<'a>, Option<(ipv6_exts::HeaderSliceError, err::Layer)>, ), ipv6::HeaderSliceError, >69 pub fn from_slice( 70 slice: &'a [u8], 71 ) -> Result< 72 ( 73 LaxIpv6Slice<'a>, 74 Option<(ipv6_exts::HeaderSliceError, err::Layer)>, 75 ), 76 ipv6::HeaderSliceError, 77 > { 78 // try reading the header 79 let header = Ipv6HeaderSlice::from_slice(slice)?; 80 81 // restrict slice by the length specified in the header 82 let (header_payload, len_source, incomplete) = 83 if 0 == header.payload_length() && slice.len() > Ipv6Header::LEN { 84 // In case the payload_length is 0 assume that the entire 85 // rest of the slice is part of the packet until the jumbogram 86 // parameters can be parsed. 87 88 // TODO: Add payload length parsing from the jumbogram 89 ( 90 unsafe { 91 core::slice::from_raw_parts( 92 slice.as_ptr().add(Ipv6Header::LEN), 93 slice.len() - Ipv6Header::LEN, 94 ) 95 }, 96 LenSource::Slice, 97 false, 98 ) 99 } else { 100 let payload_len = usize::from(header.payload_length()); 101 let expected_len = Ipv6Header::LEN + payload_len; 102 if slice.len() < expected_len { 103 ( 104 unsafe { 105 core::slice::from_raw_parts( 106 slice.as_ptr().add(Ipv6Header::LEN), 107 slice.len() - Ipv6Header::LEN, 108 ) 109 }, 110 LenSource::Slice, 111 true, 112 ) 113 } else { 114 ( 115 unsafe { 116 core::slice::from_raw_parts( 117 slice.as_ptr().add(Ipv6Header::LEN), 118 payload_len, 119 ) 120 }, 121 LenSource::Ipv6HeaderPayloadLen, 122 false, 123 ) 124 } 125 }; 126 127 // parse extension headers 128 let (exts, payload_ip_number, payload, mut ext_stop_err) = 129 Ipv6ExtensionsSlice::from_slice_lax(header.next_header(), header_payload); 130 131 // modify length errors 132 if let Some((ipv6_exts::HeaderSliceError::Len(err), _)) = &mut ext_stop_err { 133 err.len_source = len_source; 134 err.layer_start_offset += Ipv6Header::LEN; 135 }; 136 137 let fragmented = exts.is_fragmenting_payload(); 138 Ok(( 139 LaxIpv6Slice { 140 header, 141 exts, 142 payload: LaxIpPayloadSlice { 143 incomplete, 144 ip_number: payload_ip_number, 145 fragmented, 146 len_source, 147 payload, 148 }, 149 }, 150 ext_stop_err, 151 )) 152 } 153 154 /// Returns a slice containing the IPv6 header. 155 #[inline] header(&self) -> Ipv6HeaderSlice<'a>156 pub fn header(&self) -> Ipv6HeaderSlice<'a> { 157 self.header 158 } 159 160 /// Returns a slice containing the IPv6 extension headers. 161 #[inline] extensions(&self) -> &Ipv6ExtensionsSlice<'a>162 pub fn extensions(&self) -> &Ipv6ExtensionsSlice<'a> { 163 &self.exts 164 } 165 166 /// Returns a slice containing the data after the IPv6 header 167 /// and IPv6 extensions headers. 168 #[inline] payload(&self) -> &LaxIpPayloadSlice<'a>169 pub fn payload(&self) -> &LaxIpPayloadSlice<'a> { 170 &self.payload 171 } 172 173 /// Returns true if the payload is flagged as being fragmented. 174 #[inline] is_payload_fragmented(&self) -> bool175 pub fn is_payload_fragmented(&self) -> bool { 176 self.payload.fragmented 177 } 178 } 179 180 #[cfg(test)] 181 mod test { 182 use super::*; 183 use crate::{ 184 err::{Layer, LenError}, 185 ip_number::{AUTH, IGMP, UDP}, 186 test_gens::*, 187 }; 188 use alloc::{format, vec::Vec}; 189 use proptest::prelude::*; 190 191 proptest! { 192 #[test] 193 fn debug_clone_eq( 194 ipv6_base in ipv6_any(), 195 auth_base in ip_auth_any() 196 ) { 197 let mut auth = auth_base.clone(); 198 auth.next_header = IGMP; 199 let payload: [u8;4] = [1,2,3,4]; 200 let mut data = Vec::with_capacity( 201 ipv6_base.header_len() + 202 auth.header_len() + 203 payload.len() 204 ); 205 let mut ipv6 = ipv6_base.clone(); 206 ipv6.next_header = AUTH; 207 ipv6.payload_length = (auth.header_len() + payload.len()) as u16; 208 data.extend_from_slice(&ipv6.to_bytes()); 209 data.extend_from_slice(&auth.to_bytes()); 210 data.extend_from_slice(&payload); 211 212 // decode packet 213 let (slice, _) = LaxIpv6Slice::from_slice(&data).unwrap(); 214 215 // check debug output 216 prop_assert_eq!( 217 format!("{:?}", slice), 218 format!( 219 "LaxIpv6Slice {{ header: {:?}, exts: {:?}, payload: {:?} }}", 220 slice.header(), 221 slice.extensions(), 222 slice.payload() 223 ) 224 ); 225 prop_assert_eq!(slice.clone(), slice); 226 } 227 } 228 229 proptest! { 230 #[test] 231 fn from_slice( 232 ipv6_base in ipv6_any(), 233 auth_base in ip_auth_any() 234 ) { 235 let payload: [u8;6] = [1,2,3,4,5,6]; 236 237 // build packets 238 let data_without_ext = { 239 let mut data = Vec::with_capacity( 240 ipv6_base.header_len() + 241 payload.len() + 242 4 243 ); 244 let mut ipv6 = ipv6_base.clone(); 245 ipv6.payload_length = (payload.len()) as u16; 246 ipv6.next_header = UDP; 247 data.extend_from_slice(&ipv6.to_bytes()); 248 data.extend_from_slice(&payload); 249 data.extend_from_slice(&[0,0,0,0]); 250 data 251 }; 252 let data_with_ext = { 253 let payload: [u8;6] = [1,2,3,4,5,6]; 254 let mut data = Vec::with_capacity( 255 ipv6_base.header_len() + 256 auth_base.header_len() + 257 payload.len() + 258 4 259 ); 260 let mut ipv6 = ipv6_base.clone(); 261 ipv6.payload_length = (auth_base.header_len() + payload.len()) as u16; 262 ipv6.next_header = AUTH; 263 let mut auth = auth_base.clone(); 264 auth.next_header = UDP; 265 data.extend_from_slice(&ipv6.to_bytes()); 266 data.extend_from_slice(&auth.to_bytes()); 267 data.extend_from_slice(&payload); 268 data.extend_from_slice(&[0,0,0,0]); 269 data 270 }; 271 272 // parsing without extensions (normal length) 273 { 274 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data_without_ext).unwrap(); 275 prop_assert_eq!(None, actual_stop_err); 276 prop_assert_eq!(actual.header().slice(), &data_without_ext[..ipv6_base.header_len()]); 277 prop_assert!(actual.extensions().first_header().is_none()); 278 prop_assert_eq!( 279 actual.payload(), 280 &LaxIpPayloadSlice{ 281 incomplete: false, 282 ip_number: UDP.into(), 283 fragmented: false, 284 len_source: LenSource::Ipv6HeaderPayloadLen, 285 payload: &payload, 286 } 287 ); 288 } 289 290 // parsing with extensions (normal length) 291 { 292 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data_with_ext).unwrap(); 293 prop_assert_eq!(None, actual_stop_err); 294 prop_assert_eq!(actual.header().slice(), &data_with_ext[..ipv6_base.header_len()]); 295 let (expected, _, _) = Ipv6ExtensionsSlice::from_slice(AUTH, &data_with_ext[ipv6_base.header_len()..]).unwrap(); 296 prop_assert_eq!( 297 actual.extensions(), 298 &expected 299 ); 300 prop_assert_eq!( 301 actual.payload(), 302 &LaxIpPayloadSlice{ 303 incomplete: false, 304 ip_number: UDP.into(), 305 fragmented: false, 306 len_source: LenSource::Ipv6HeaderPayloadLen, 307 payload: &payload, 308 } 309 ); 310 } 311 312 // parsing without extensions (zero length, fallback to slice length) 313 { 314 // inject zero as payload length 315 let mut data = data_without_ext.clone(); 316 data[4] = 0; 317 data[5] = 0; 318 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data).unwrap(); 319 prop_assert_eq!(None, actual_stop_err); 320 prop_assert_eq!(actual.header().slice(), &data[..ipv6_base.header_len()]); 321 prop_assert!(actual.extensions().first_header().is_none()); 322 prop_assert_eq!( 323 actual.payload(), 324 &LaxIpPayloadSlice{ 325 incomplete: false, 326 ip_number: UDP.into(), 327 fragmented: false, 328 len_source: LenSource::Slice, 329 payload: &data[ipv6_base.header_len()..], 330 } 331 ); 332 } 333 334 // parsing with extensions (zero length, fallback to slice length) 335 { 336 // inject zero as payload length 337 let mut data = data_with_ext.clone(); 338 data[4] = 0; 339 data[5] = 0; 340 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data).unwrap(); 341 prop_assert_eq!(None, actual_stop_err); 342 prop_assert_eq!(actual.header().slice(), &data[..ipv6_base.header_len()]); 343 let (expected, _, _) = Ipv6ExtensionsSlice::from_slice(AUTH, &data[ipv6_base.header_len()..]).unwrap(); 344 prop_assert_eq!( 345 actual.extensions(), 346 &expected 347 ); 348 prop_assert_eq!( 349 actual.payload(), 350 &LaxIpPayloadSlice{ 351 incomplete: false, 352 ip_number: UDP.into(), 353 fragmented: false, 354 len_source: LenSource::Slice, 355 payload: &data[ipv6_base.header_len() + auth_base.header_len()..], 356 } 357 ); 358 } 359 360 // header content error 361 { 362 use crate::err::ipv6::HeaderError; 363 // inject invalid ip version 364 let mut data = data_without_ext.clone(); 365 data[0] = data[0] & 0x0f; // version 0 366 prop_assert_eq!( 367 LaxIpv6Slice::from_slice(&data).unwrap_err(), 368 ipv6::HeaderSliceError::Content( 369 HeaderError::UnexpectedVersion{ version_number: 0 } 370 ) 371 ); 372 } 373 374 // header length error 375 for len in 0..Ipv6Header::LEN { 376 prop_assert_eq!( 377 LaxIpv6Slice::from_slice(&data_without_ext[..len]).unwrap_err(), 378 ipv6::HeaderSliceError::Len( 379 LenError{ 380 required_len: Ipv6Header::LEN, 381 len, 382 len_source: LenSource::Slice, 383 layer: Layer::Ipv6Header, 384 layer_start_offset: 0 385 } 386 ) 387 ); 388 } 389 390 // payload length larger then slice (fallback to slice length) 391 { 392 let len = ipv6_base.header_len() + payload.len() - 1; 393 let (actual , actual_stop_err) = LaxIpv6Slice::from_slice(&data_without_ext[..len]).unwrap(); 394 prop_assert_eq!(actual_stop_err, None); 395 prop_assert_eq!(actual.header().slice(), &data_without_ext[..ipv6_base.header_len()]); 396 prop_assert_eq!( 397 0, 398 actual.extensions().slice().len() 399 ); 400 prop_assert_eq!( 401 actual.payload(), 402 &LaxIpPayloadSlice{ 403 incomplete: true, 404 ip_number: UDP.into(), 405 fragmented: false, 406 len_source: LenSource::Slice, 407 payload: &data_without_ext[ipv6_base.header_len()..len], 408 } 409 ); 410 } 411 412 // payload length error auth header 413 { 414 use crate::err::{LenError, Layer}; 415 416 let required_len = ipv6_base.header_len() + auth_base.header_len(); 417 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data_with_ext[..required_len - 1]).unwrap(); 418 prop_assert_eq!( 419 actual_stop_err.unwrap(), 420 ( 421 ipv6_exts::HeaderSliceError::Len(LenError{ 422 required_len: required_len - Ipv6Header::LEN, 423 len: required_len - Ipv6Header::LEN - 1, 424 len_source: LenSource::Slice, 425 layer: Layer::IpAuthHeader, 426 layer_start_offset: Ipv6Header::LEN, 427 }), 428 err::Layer::IpAuthHeader 429 ) 430 ); 431 prop_assert_eq!(actual.header().slice(), &data_with_ext[..ipv6_base.header_len()]); 432 prop_assert_eq!( 433 actual.payload(), 434 &LaxIpPayloadSlice{ 435 incomplete: true, 436 ip_number: AUTH, 437 fragmented: false, 438 len_source: LenSource::Slice, 439 payload: &data_with_ext[ipv6_base.header_len()..required_len - 1], 440 } 441 ); 442 } 443 444 // auth length error 445 { 446 use crate::err::{LenError, Layer}; 447 448 // inject payload length that is smaller then the auth header 449 let mut data = data_with_ext.clone(); 450 let payload_len_too_small = auth_base.header_len() - 1; 451 { 452 let plts = (payload_len_too_small as u16).to_be_bytes(); 453 data[4] = plts[0]; 454 data[5] = plts[1]; 455 } 456 457 let (actual, actual_stop_err) = LaxIpv6Slice::from_slice(&data).unwrap(); 458 prop_assert_eq!( 459 actual_stop_err.unwrap(), 460 ( 461 ipv6_exts::HeaderSliceError::Len( 462 LenError{ 463 required_len: auth_base.header_len(), 464 len: auth_base.header_len() - 1, 465 len_source: LenSource::Ipv6HeaderPayloadLen, 466 layer: Layer::IpAuthHeader, 467 layer_start_offset: ipv6_base.header_len(), 468 } 469 ), 470 err::Layer::IpAuthHeader 471 ) 472 ); 473 prop_assert_eq!(actual.header().slice(), &data[..ipv6_base.header_len()]); 474 prop_assert_eq!( 475 actual.payload(), 476 &LaxIpPayloadSlice{ 477 incomplete: false, 478 ip_number: AUTH, 479 fragmented: false, 480 len_source: LenSource::Ipv6HeaderPayloadLen, 481 payload: &data[ipv6_base.header_len()..ipv6_base.header_len() + payload_len_too_small], 482 } 483 ); 484 } 485 486 // auth content error 487 { 488 use crate::err::{ip_auth, ipv6_exts}; 489 490 // inject zero as auth header length 491 let mut data = data_with_ext.clone(); 492 data[ipv6_base.header_len() + 1] = 0; 493 494 let (actual, actual_stop_error) = LaxIpv6Slice::from_slice(&data).unwrap(); 495 496 prop_assert_eq!( 497 actual_stop_error.unwrap(), 498 ( 499 ipv6_exts::HeaderSliceError::Content(ipv6_exts::HeaderError::IpAuth( 500 ip_auth::HeaderError::ZeroPayloadLen 501 )), 502 err::Layer::IpAuthHeader 503 ) 504 ); 505 prop_assert_eq!( 506 actual.header().slice(), 507 &data[..ipv6_base.header_len()] 508 ); 509 prop_assert_eq!( 510 actual.payload(), 511 &LaxIpPayloadSlice{ 512 incomplete: false, 513 ip_number: AUTH, 514 fragmented: false, 515 len_source: LenSource::Ipv6HeaderPayloadLen, 516 payload: &data[ipv6_base.header_len()..ipv6_base.header_len() + auth_base.header_len() + payload.len()], 517 } 518 ); 519 } 520 } 521 } 522 523 #[test] is_payload_fragmented()524 fn is_payload_fragmented() { 525 use crate::ip_number::{IPV6_FRAG, UDP}; 526 527 // not fragmented 528 { 529 let data = Ipv6Header { 530 traffic_class: 0, 531 flow_label: 1.try_into().unwrap(), 532 payload_length: 0, 533 next_header: UDP, 534 hop_limit: 4, 535 source: [0; 16], 536 destination: [0; 16], 537 } 538 .to_bytes(); 539 assert_eq!( 540 false, 541 LaxIpv6Slice::from_slice(&data) 542 .unwrap() 543 .0 544 .is_payload_fragmented() 545 ); 546 } 547 548 // fragmented 549 { 550 let ipv6_frag = Ipv6FragmentHeader { 551 next_header: UDP, 552 fragment_offset: 0.try_into().unwrap(), 553 more_fragments: true, 554 identification: 0, 555 }; 556 let ipv6 = Ipv6Header { 557 traffic_class: 0, 558 flow_label: 1.try_into().unwrap(), 559 payload_length: ipv6_frag.header_len() as u16, 560 next_header: IPV6_FRAG, 561 hop_limit: 4, 562 source: [0; 16], 563 destination: [0; 16], 564 }; 565 566 let mut data = Vec::with_capacity(ipv6.header_len() + ipv6_frag.header_len()); 567 data.extend_from_slice(&ipv6.to_bytes()); 568 data.extend_from_slice(&ipv6_frag.to_bytes()); 569 assert!(Ipv6Slice::from_slice(&data) 570 .unwrap() 571 .is_payload_fragmented()); 572 } 573 } 574 } 575