1 use crate::*; 2 use core::slice::from_raw_parts; 3 4 /// Slice containing the IPv6 extension headers present after the ip header. 5 /// 6 /// Currently supported: 7 /// * Authentication Header 8 /// * Hop by Hop Options Header 9 /// * Destination Options Header (before and after routing headers) 10 /// * Routing Header 11 /// * Fragment 12 /// * Authentication Header 13 /// 14 /// Currently not supported: 15 /// * Encapsulating Security Payload Header (ESP) 16 /// * Host Identity Protocol (HIP) 17 /// * IP Mobility 18 /// * Site Multihoming by IPv6 Intermediation (SHIM6) 19 #[derive(Clone, Debug, Eq, PartialEq, Default)] 20 pub struct Ipv6ExtensionsSlice<'a> { 21 /// IP protocol number of the first header present in the slice. 22 first_header: Option<IpNumber>, 23 /// True if a fragment header is present in the ipv6 header extensions that causes the payload to be fragmented. 24 fragmented: bool, 25 /// Slice containing ipv6 extension headers. 26 slice: &'a [u8], 27 } 28 29 impl<'a> Ipv6ExtensionsSlice<'a> { 30 /// Collects all ipv6 extension headers in a slice & checks if 31 /// a fragmentation header that fragments the packet is present. from_slice( start_ip_number: IpNumber, start_slice: &'a [u8], ) -> Result<(Ipv6ExtensionsSlice<'a>, IpNumber, &'a [u8]), err::ipv6_exts::HeaderSliceError>32 pub fn from_slice( 33 start_ip_number: IpNumber, 34 start_slice: &'a [u8], 35 ) -> Result<(Ipv6ExtensionsSlice<'a>, IpNumber, &'a [u8]), err::ipv6_exts::HeaderSliceError> 36 { 37 let mut rest = start_slice; 38 let mut next_header = start_ip_number; 39 let mut fragmented = false; 40 41 use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*}; 42 use ip_number::*; 43 44 // the hop by hop header is required to occur directly after the ipv6 header 45 if IPV6_HOP_BY_HOP == next_header { 46 let slice = Ipv6RawExtHeaderSlice::from_slice(rest).map_err(Len)?; 47 rest = &rest[slice.slice().len()..]; 48 next_header = slice.next_header(); 49 } 50 51 loop { 52 match next_header { 53 IPV6_HOP_BY_HOP => { 54 return Err(Content(HopByHopNotAtStart)); 55 } 56 IPV6_DEST_OPTIONS | IPV6_ROUTE => { 57 let slice = Ipv6RawExtHeaderSlice::from_slice(rest) 58 .map_err(|err| Len(err.add_offset(start_slice.len() - rest.len())))?; 59 // SAFETY: 60 // Ipv6RawExtHeaderSlice::from_slice always generates 61 // a subslice from the given slice rest. Therefor it is guaranteed 62 // that len is always greater or equal the len of rest. 63 rest = unsafe { 64 let len = slice.slice().len(); 65 from_raw_parts(rest.as_ptr().add(len), rest.len() - len) 66 }; 67 next_header = slice.next_header(); 68 } 69 IPV6_FRAG => { 70 let slice = Ipv6FragmentHeaderSlice::from_slice(rest) 71 .map_err(|err| Len(err.add_offset(start_slice.len() - rest.len())))?; 72 // SAFETY: 73 // Ipv6FragmentHeaderSlice::from_slice always generates 74 // a subslice from the given slice rest. Therefor it is guaranteed 75 // that len is always greater or equal the len of rest. 76 rest = unsafe { 77 let len = slice.slice().len(); 78 from_raw_parts(rest.as_ptr().add(len), rest.len() - len) 79 }; 80 next_header = slice.next_header(); 81 82 // check if the fragment header actually causes fragmentation 83 fragmented = fragmented || slice.is_fragmenting_payload(); 84 } 85 AUTH => { 86 let slice = IpAuthHeaderSlice::from_slice(rest).map_err(|err| { 87 use err::ip_auth::HeaderSliceError as I; 88 match err { 89 I::Len(err) => Len(err.add_offset(start_slice.len() - rest.len())), 90 I::Content(err) => Content(IpAuth(err)), 91 } 92 })?; 93 // SAFETY: 94 // IpAuthHeaderSlice::from_slice always generates 95 // a subslice from the given slice rest. Therefor it is guaranteed 96 // that len is always greater or equal the len of rest. 97 rest = unsafe { 98 let len = slice.slice().len(); 99 from_raw_parts(rest.as_ptr().add(len), rest.len() - len) 100 }; 101 next_header = slice.next_header(); 102 } 103 // done parsing, the next header is not a known/supported header extension 104 _ => break, 105 } 106 } 107 108 Ok(( 109 Ipv6ExtensionsSlice { 110 first_header: if rest.len() != start_slice.len() { 111 Some(start_ip_number) 112 } else { 113 None 114 }, 115 fragmented, 116 slice: &start_slice[..start_slice.len() - rest.len()], 117 }, 118 next_header, 119 rest, 120 )) 121 } 122 123 /// Collects all ipv6 extension headers in a slice until an error 124 /// is encountered or a "non IP extension header" is found and 125 /// returns the successfully parsed parts (+ the unparsed slice 126 /// it's `IpNumber` and the error if one occurred). 127 /// 128 /// The returned values are 129 /// 130 /// * [`Ipv6ExtensionsSlice`] containing the successfully parsed IPv6 extension headers 131 /// * [`IpNumber`] of unparsed data 132 /// * Slice with unparsed data 133 /// * Optional with error if there was an error wich stoped the parsing. from_slice_lax( start_ip_number: IpNumber, start_slice: &'a [u8], ) -> ( Ipv6ExtensionsSlice<'a>, IpNumber, &'a [u8], Option<(err::ipv6_exts::HeaderSliceError, err::Layer)>, )134 pub fn from_slice_lax( 135 start_ip_number: IpNumber, 136 start_slice: &'a [u8], 137 ) -> ( 138 Ipv6ExtensionsSlice<'a>, 139 IpNumber, 140 &'a [u8], 141 Option<(err::ipv6_exts::HeaderSliceError, err::Layer)>, 142 ) { 143 let mut rest = start_slice; 144 let mut next_header = start_ip_number; 145 let mut error = None; 146 let mut fragmented = false; 147 148 use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*}; 149 use ip_number::*; 150 151 // the hop by hop header is required to occur directly after the ipv6 header 152 if IPV6_HOP_BY_HOP == next_header { 153 match Ipv6RawExtHeaderSlice::from_slice(rest) { 154 Ok(slice) => { 155 rest = &rest[slice.slice().len()..]; 156 next_header = slice.next_header(); 157 } 158 Err(err) => { 159 error = Some((Len(err), err::Layer::Ipv6HopByHopHeader)); 160 } 161 } 162 } 163 164 while error.is_none() { 165 match next_header { 166 IPV6_HOP_BY_HOP => { 167 error = Some((Content(HopByHopNotAtStart), err::Layer::Ipv6HopByHopHeader)); 168 break; 169 } 170 IPV6_DEST_OPTIONS | IPV6_ROUTE => { 171 let slice = match Ipv6RawExtHeaderSlice::from_slice(rest) { 172 Ok(s) => s, 173 Err(err) => { 174 error = Some(( 175 Len(err.add_offset(start_slice.len() - rest.len())), 176 if next_header == IPV6_DEST_OPTIONS { 177 err::Layer::Ipv6DestOptionsHeader 178 } else { 179 err::Layer::Ipv6RouteHeader 180 }, 181 )); 182 break; 183 } 184 }; 185 // SAFETY: 186 // Ipv6RawExtHeaderSlice::from_slice always generates 187 // a subslice from the given slice rest. Therefor it is guranteed 188 // that len is always greater or equal the len of rest. 189 rest = unsafe { 190 let len = slice.slice().len(); 191 from_raw_parts(rest.as_ptr().add(len), rest.len() - len) 192 }; 193 next_header = slice.next_header(); 194 } 195 IPV6_FRAG => { 196 let slice = match Ipv6FragmentHeaderSlice::from_slice(rest) { 197 Ok(s) => s, 198 Err(err) => { 199 error = Some(( 200 Len(err.add_offset(start_slice.len() - rest.len())), 201 err::Layer::Ipv6FragHeader, 202 )); 203 break; 204 } 205 }; 206 207 // SAFETY: 208 // Ipv6FragmentHeaderSlice::from_slice always generates 209 // a subslice from the given slice rest. Therefor it is guranteed 210 // that len is always greater or equal the len of rest. 211 rest = unsafe { 212 let len = slice.slice().len(); 213 from_raw_parts(rest.as_ptr().add(len), rest.len() - len) 214 }; 215 next_header = slice.next_header(); 216 217 // check if the fragment header actually causes fragmentation 218 fragmented = fragmented || slice.is_fragmenting_payload(); 219 } 220 AUTH => { 221 use err::ip_auth::HeaderSliceError as I; 222 let slice = match IpAuthHeaderSlice::from_slice(rest) { 223 Ok(s) => s, 224 Err(err) => { 225 error = Some(( 226 match err { 227 I::Len(err) => { 228 Len(err.add_offset(start_slice.len() - rest.len())) 229 } 230 I::Content(err) => Content(IpAuth(err)), 231 }, 232 err::Layer::IpAuthHeader, 233 )); 234 break; 235 } 236 }; 237 // SAFETY: 238 // IpAuthHeaderSlice::from_slice always generates 239 // a subslice from the given slice rest. Therefor it is guranteed 240 // that len is always greater or equal the len of rest. 241 rest = unsafe { 242 let len = slice.slice().len(); 243 from_raw_parts(rest.as_ptr().add(len), rest.len() - len) 244 }; 245 next_header = slice.next_header(); 246 } 247 // done parsing, the next header is not a known/supported header extension 248 _ => break, 249 } 250 } 251 252 ( 253 Ipv6ExtensionsSlice { 254 first_header: if rest.len() != start_slice.len() { 255 Some(start_ip_number) 256 } else { 257 None 258 }, 259 fragmented, 260 slice: &start_slice[..start_slice.len() - rest.len()], 261 }, 262 next_header, 263 rest, 264 error, 265 ) 266 } 267 268 /// Returns true if a fragmentation header is present in 269 /// the extensions that fragments the payload. 270 /// 271 /// Note: A fragmentation header can still be present 272 /// even if the return value is false in case the fragmentation 273 /// headers don't fragment the payload. This is the case if 274 /// the offset of all fragmentation header is 0 and the 275 /// more fragment bit is not set. 276 #[inline] is_fragmenting_payload(&self) -> bool277 pub fn is_fragmenting_payload(&self) -> bool { 278 self.fragmented 279 } 280 281 /// Returns the ip protocol number of the first header in the slice 282 /// if the slice contains an ipv6 extension header. If no ipv6 header 283 /// is present None is returned. 284 /// 285 /// None is only returned if the slice length of this struct is 0. 286 #[inline] first_header(&self) -> Option<IpNumber>287 pub fn first_header(&self) -> Option<IpNumber> { 288 self.first_header 289 } 290 291 /// Slice containing the ipv6 extension headers. 292 #[inline] slice(&self) -> &'a [u8]293 pub fn slice(&self) -> &'a [u8] { 294 self.slice 295 } 296 297 /// Returns true if no IPv6 extension header is present (slice is empty). 298 #[inline] is_empty(&self) -> bool299 pub fn is_empty(&self) -> bool { 300 self.slice.is_empty() 301 } 302 } 303 304 impl<'a> IntoIterator for Ipv6ExtensionsSlice<'a> { 305 type Item = Ipv6ExtensionSlice<'a>; 306 type IntoIter = Ipv6ExtensionSliceIter<'a>; 307 into_iter(self) -> Self::IntoIter308 fn into_iter(self) -> Self::IntoIter { 309 Ipv6ExtensionSliceIter { 310 // map the next header None value to some non ipv6 ext header 311 // value. 312 next_header: self.first_header.unwrap_or(ip_number::UDP), 313 rest: self.slice, 314 } 315 } 316 } 317 318 #[cfg(test)] 319 mod test { 320 use super::ipv6_exts_test_helpers::*; 321 use super::*; 322 use crate::ip_number::*; 323 use crate::test_gens::*; 324 use alloc::{borrow::ToOwned, vec::Vec}; 325 use proptest::prelude::*; 326 327 proptest! { 328 #[test] 329 fn from_slice( 330 header_size in any::<u8>(), 331 post_header in ip_number_any() 332 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(), 333 |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x) 334 ) 335 ) { 336 use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*}; 337 338 // no extension headers filled 339 { 340 let some_data = [1,2,3,4]; 341 let actual = Ipv6ExtensionsSlice::from_slice(UDP, &some_data).unwrap(); 342 assert_eq!(actual.0.is_fragmenting_payload(), false); 343 assert_eq!(actual.0.first_header(), None); 344 assert_eq!(actual.0.slice().len(), 0); 345 assert_eq!(actual.1, UDP); 346 assert_eq!(actual.2, &some_data); 347 } 348 349 /// Run a test with the given ip numbers 350 fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) { 351 // setup test payload 352 let e = ExtensionTestPayload::new( 353 ip_numbers, 354 header_sizes 355 ); 356 357 if e.ip_numbers[1..].iter().any(|&x| x == IPV6_HOP_BY_HOP) { 358 // a hop by hop header that is not at the start triggers an error 359 assert_eq!( 360 Ipv6ExtensionsSlice::from_slice(ip_numbers[0], e.slice()).unwrap_err(), 361 Content(HopByHopNotAtStart) 362 ); 363 } else { 364 // normal read 365 let (header, next, rest) = Ipv6ExtensionsSlice::from_slice(ip_numbers[0], e.slice()).unwrap(); 366 assert_eq!(header.first_header(), Some(ip_numbers[0])); 367 assert_eq!(header.slice(), e.slice()); 368 assert_eq!(next, *ip_numbers.last().unwrap()); 369 assert_eq!(rest, &e.slice()[e.slice().len()..]); 370 371 // unexpected end of slice 372 { 373 let offset: usize = e.lengths[..e.lengths.len() - 1].into_iter().sum(); 374 375 assert_eq!( 376 Ipv6ExtensionsSlice::from_slice(ip_numbers[0], &e.slice()[..e.slice().len() - 1]).unwrap_err(), 377 Len(err::LenError { 378 required_len: e.slice().len() - offset, 379 len: e.slice().len() - offset - 1, 380 len_source: LenSource::Slice, 381 layer: match ip_numbers[ip_numbers.len() - 2] { 382 AUTH => err::Layer::IpAuthHeader, 383 IPV6_FRAG => err::Layer::Ipv6FragHeader, 384 _ => err::Layer::Ipv6ExtHeader 385 }, 386 layer_start_offset: offset, 387 }) 388 ); 389 } 390 } 391 } 392 393 // test the parsing of different extension header combinations 394 for first_header in &EXTENSION_KNOWN_IP_NUMBERS { 395 396 // single header parsing 397 run_test( 398 &[*first_header, post_header], 399 &[header_size], 400 ); 401 402 for second_header in &EXTENSION_KNOWN_IP_NUMBERS { 403 404 // double header parsing 405 run_test( 406 &[*first_header, *second_header, post_header], 407 &[header_size], 408 ); 409 410 for third_header in &EXTENSION_KNOWN_IP_NUMBERS { 411 // tripple header parsing 412 run_test( 413 &[*first_header, *second_header, *third_header, post_header], 414 &[header_size], 415 ); 416 } 417 } 418 } 419 } 420 } 421 422 proptest! { 423 #[test] 424 fn from_slice_lax( 425 header_size in any::<u8>(), 426 post_header in ip_number_any() 427 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(), 428 |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x) 429 ) 430 ) { 431 use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*}; 432 433 // no extension headers filled 434 { 435 let some_data = [1,2,3,4]; 436 let actual = Ipv6ExtensionsSlice::from_slice_lax(UDP, &some_data); 437 assert_eq!(actual.0.is_fragmenting_payload(), false); 438 assert_eq!(actual.0.first_header(), None); 439 assert_eq!(actual.0.slice().len(), 0); 440 assert_eq!(actual.1, UDP); 441 assert_eq!(actual.2, &some_data); 442 } 443 444 /// Run a test with the given ip numbers 445 fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) { 446 // setup test payload 447 let e = ExtensionTestPayload::new( 448 ip_numbers, 449 header_sizes 450 ); 451 452 if e.ip_numbers[1..].iter().any(|&x| x == IPV6_HOP_BY_HOP) { 453 // a hop by hop header that is not at the start triggers an error 454 assert_eq!( 455 Ipv6ExtensionsSlice::from_slice_lax(ip_numbers[0], e.slice()).3.unwrap(), 456 (Content(HopByHopNotAtStart), err::Layer::Ipv6HopByHopHeader) 457 ); 458 } else { 459 // normal read 460 let actual_normal = Ipv6ExtensionsSlice::from_slice_lax(ip_numbers[0], e.slice()); 461 assert_eq!(actual_normal.0.first_header(), Some(ip_numbers[0])); 462 assert_eq!(actual_normal.0.slice(), e.slice()); 463 assert_eq!(actual_normal.1, *ip_numbers.last().unwrap()); 464 assert_eq!(actual_normal.2, &[]); 465 466 // unexpected end of slice 467 { 468 let offset: usize = e.lengths[..e.lengths.len() - 1].into_iter().sum(); 469 470 let actual = Ipv6ExtensionsSlice::from_slice_lax( 471 ip_numbers[0], 472 &e.slice()[..e.slice().len() - 1] 473 ); 474 assert_eq!(&e.slice()[offset..e.slice().len() - 1], actual.2); 475 assert_eq!( 476 actual.3.unwrap().0, 477 Len(err::LenError { 478 required_len: e.slice().len() - offset, 479 len: e.slice().len() - offset - 1, 480 len_source: LenSource::Slice, 481 layer: match ip_numbers[ip_numbers.len() - 2] { 482 AUTH => err::Layer::IpAuthHeader, 483 IPV6_FRAG => err::Layer::Ipv6FragHeader, 484 _ => err::Layer::Ipv6ExtHeader 485 }, 486 layer_start_offset: offset, 487 }) 488 ); 489 } 490 } 491 } 492 493 // test the parsing of different extension header combinations 494 for first_header in &EXTENSION_KNOWN_IP_NUMBERS { 495 496 // single header parsing 497 run_test( 498 &[*first_header, post_header], 499 &[header_size], 500 ); 501 502 for second_header in &EXTENSION_KNOWN_IP_NUMBERS { 503 504 // double header parsing 505 run_test( 506 &[*first_header, *second_header, post_header], 507 &[header_size], 508 ); 509 510 for third_header in &EXTENSION_KNOWN_IP_NUMBERS { 511 // tripple header parsing 512 run_test( 513 &[*first_header, *second_header, *third_header, post_header], 514 &[header_size], 515 ); 516 } 517 } 518 } 519 520 // test that the auth content error gets forwarded 521 { 522 let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap(); 523 let mut bytes = auth.to_bytes(); 524 // inject an invalid len value 525 bytes[1] = 0; 526 let actual = Ipv6ExtensionsSlice::from_slice_lax(AUTH, &bytes); 527 528 use err::ipv6_exts::HeaderError::IpAuth; 529 use err::ip_auth::HeaderError::ZeroPayloadLen; 530 assert_eq!(actual.0.slice(), &[]); 531 assert_eq!(actual.1, AUTH); 532 assert_eq!(actual.2, &bytes[..]); 533 assert_eq!(actual.3.unwrap().0.content().unwrap(), &IpAuth(ZeroPayloadLen)); 534 } 535 } 536 } 537 538 proptest! { 539 #[test] 540 fn is_fragmenting_payload( 541 hop_by_hop_options in ipv6_raw_ext_any(), 542 destination_options in ipv6_raw_ext_any(), 543 routing in ipv6_raw_ext_any(), 544 auth in ip_auth_any(), 545 final_destination_options in ipv6_raw_ext_any() 546 ) { 547 // no fragment header 548 { 549 let mut exts = Ipv6Extensions{ 550 hop_by_hop_options: Some(hop_by_hop_options), 551 destination_options: Some(destination_options), 552 routing: Some( 553 Ipv6RoutingExtensions { 554 routing, 555 final_destination_options: Some(final_destination_options), 556 } 557 ), 558 fragment: None, 559 auth: Some(auth), 560 }; 561 let first_ip_number = exts.set_next_headers(UDP); 562 563 let mut bytes = Vec::with_capacity(exts.header_len()); 564 exts.write(&mut bytes, first_ip_number).unwrap(); 565 566 let (header, _, _) = Ipv6ExtensionsSlice::from_slice(first_ip_number, &bytes).unwrap(); 567 assert_eq!(false, header.is_fragmenting_payload()); 568 } 569 570 // different variants of the fragment header with 571 // variants that fragment and variants that don't fragment 572 let frag_variants : [(bool, Ipv6FragmentHeader);4] = [ 573 (false, Ipv6FragmentHeader::new(UDP, 0.try_into().unwrap(), false, 123)), 574 (true, Ipv6FragmentHeader::new(UDP, 2.try_into().unwrap(), false, 123)), 575 (true, Ipv6FragmentHeader::new(UDP, 0.try_into().unwrap(), true, 123)), 576 (true, Ipv6FragmentHeader::new(UDP, 3.try_into().unwrap(), true, 123)), 577 ]; 578 579 for (first_expected, first_header) in frag_variants.iter() { 580 // single fragment header 581 { 582 let bytes = first_header.to_bytes(); 583 let (header, _, _) = Ipv6ExtensionsSlice::from_slice(IPV6_FRAG, &bytes).unwrap(); 584 assert_eq!(*first_expected, header.is_fragmenting_payload()); 585 } 586 // two fragment headers 587 for (second_expected, second_header) in frag_variants.iter() { 588 let mut first_mod = first_header.clone(); 589 first_mod.next_header = IPV6_FRAG; 590 let mut bytes = Vec::with_capacity(first_mod.header_len() + second_header.header_len()); 591 bytes.extend_from_slice(&first_mod.to_bytes()); 592 bytes.extend_from_slice(&second_header.to_bytes()); 593 594 let (header, _, _) = Ipv6ExtensionsSlice::from_slice(IPV6_FRAG, &bytes).unwrap(); 595 assert_eq!( 596 *first_expected || *second_expected, 597 header.is_fragmenting_payload() 598 ); 599 } 600 } 601 } 602 } 603 604 #[test] is_empty()605 fn is_empty() { 606 // empty 607 { 608 let slice = Ipv6ExtensionsSlice::from_slice(ip_number::UDP, &[]) 609 .unwrap() 610 .0; 611 assert!(slice.is_empty()); 612 } 613 614 // fragment 615 { 616 let bytes = 617 Ipv6FragmentHeader::new(ip_number::UDP, IpFragOffset::ZERO, true, 0).to_bytes(); 618 let slice = Ipv6ExtensionsSlice::from_slice(ip_number::IPV6_FRAG, &bytes) 619 .unwrap() 620 .0; 621 assert_eq!(false, slice.is_empty()); 622 } 623 } 624 625 #[test] debug()626 fn debug() { 627 use alloc::format; 628 629 let a: Ipv6ExtensionsSlice = Default::default(); 630 assert_eq!( 631 "Ipv6ExtensionsSlice { first_header: None, fragmented: false, slice: [] }", 632 &format!("{:?}", a) 633 ); 634 } 635 636 #[test] clone_eq()637 fn clone_eq() { 638 let a: Ipv6ExtensionsSlice = Default::default(); 639 assert_eq!(a, a.clone()); 640 } 641 642 #[test] default()643 fn default() { 644 let a: Ipv6ExtensionsSlice = Default::default(); 645 assert_eq!(a.is_fragmenting_payload(), false); 646 assert_eq!(a.first_header(), None); 647 assert_eq!(a.slice().len(), 0); 648 } 649 } 650