1 use crate::{ 2 err::{ipv6_exts::*, Layer}, 3 *, 4 }; 5 6 /// IPv6 extension headers present after the ip header. 7 /// 8 /// Currently supported: 9 /// 10 /// * Authentication Header 11 /// * Hop by Hop Options Header 12 /// * Destination Options Header (before and after routing headers) 13 /// * Routing Header 14 /// * Fragment 15 /// * Authentication Header 16 /// 17 /// Currently not supported: 18 /// 19 /// * Encapsulating Security Payload Header (ESP) 20 /// * Host Identity Protocol (HIP) 21 /// * IP Mobility 22 /// * Site Multihoming by IPv6 Intermediation (SHIM6) 23 #[derive(Clone, Debug, Eq, PartialEq, Default)] 24 pub struct Ipv6Extensions { 25 pub hop_by_hop_options: Option<Ipv6RawExtHeader>, 26 pub destination_options: Option<Ipv6RawExtHeader>, 27 pub routing: Option<Ipv6RoutingExtensions>, 28 pub fragment: Option<Ipv6FragmentHeader>, 29 pub auth: Option<IpAuthHeader>, 30 } 31 32 impl Ipv6Extensions { 33 /// Minimum length required for extension header in bytes/octets. 34 /// Which is zero as no extension headers are required. 35 pub const MIN_LEN: usize = 0; 36 37 /// Maximum summed up length of all extension headers in bytes/octets. 38 pub const MAX_LEN: usize = Ipv6RawExtHeader::MAX_LEN * 2 39 + Ipv6RoutingExtensions::MAX_LEN 40 + Ipv6FragmentHeader::LEN 41 + IpAuthHeader::MAX_LEN; 42 43 /// Reads as many extension headers as possible from the slice. 44 /// 45 /// Returns the found ipv6 extension headers, the next header ip number after the read 46 /// headers and a slice containing the rest of the packet after the read headers. 47 /// 48 /// Note that this function can only handle ipv6 extensions if each extension header does 49 /// occur at most once, except for destination options headers which are allowed to 50 /// exist once in front of a routing header and once after a routing header. 51 /// 52 /// In case that more extension headers then can fit into a `Ipv6Extensions` struct are 53 /// encountered, the parsing is stoped at the point where the data would no longer fit into 54 /// the struct. In such a scenario a struct with the data that could be parsed is returned 55 /// together with the next header ip number and slice containing the unparsed data. 56 /// 57 /// It is in the responsibility of the caller to handle a scenario like this. 58 /// 59 /// The reason that no error is generated, is that even though according to RFC 8200 packets 60 /// "should" not contain more then one occurence of an extension header the RFC also specifies 61 /// that "IPv6 nodes must accept and attempt to process extension headers in any order and 62 /// occurring any number of times in the same packet". So packets with multiple headers "should" 63 /// not exist, but are still valid IPv6 packets. As such this function does not generate a 64 /// parsing error, as it is not an invalid packet, but if packets like these are encountered 65 /// the user of this function has to themself decide how to handle packets like these. 66 /// 67 /// The only exception is if an hop by hop header is located somewhere else then directly at 68 /// the start. In this case an `ReadError::Ipv6HopByHopHeaderNotAtStart` error is generated as 69 /// the hop by hop header is required to be located directly after the IPv6 header according 70 /// to RFC 8200. from_slice( start_ip_number: IpNumber, slice: &[u8], ) -> Result<(Ipv6Extensions, IpNumber, &[u8]), err::ipv6_exts::HeaderSliceError>71 pub fn from_slice( 72 start_ip_number: IpNumber, 73 slice: &[u8], 74 ) -> Result<(Ipv6Extensions, IpNumber, &[u8]), err::ipv6_exts::HeaderSliceError> { 75 let mut result: Ipv6Extensions = Default::default(); 76 let mut rest = slice; 77 let mut next_header = start_ip_number; 78 79 use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*}; 80 use ip_number::*; 81 82 // the hop by hop header is required to occur directly after the ipv6 header 83 if IPV6_HOP_BY_HOP == next_header { 84 let slice = Ipv6RawExtHeaderSlice::from_slice(rest).map_err(Len)?; 85 rest = &rest[slice.slice().len()..]; 86 next_header = slice.next_header(); 87 result.hop_by_hop_options = Some(slice.to_header()); 88 } 89 90 loop { 91 match next_header { 92 IPV6_HOP_BY_HOP => { 93 return Err(Content(HopByHopNotAtStart)); 94 } 95 IPV6_DEST_OPTIONS => { 96 if let Some(ref mut routing) = result.routing { 97 // if the routing header is already present 98 // this this a "final destination options" header 99 if routing.final_destination_options.is_some() { 100 // more then one header of this type found -> abort parsing 101 return Ok((result, next_header, rest)); 102 } else { 103 let slice = Ipv6RawExtHeaderSlice::from_slice(rest) 104 .map_err(|err| Len(err.add_offset(slice.len() - rest.len())))?; 105 rest = &rest[slice.slice().len()..]; 106 next_header = slice.next_header(); 107 routing.final_destination_options = Some(slice.to_header()); 108 } 109 } else if result.destination_options.is_some() { 110 // more then one header of this type found -> abort parsing 111 return Ok((result, next_header, rest)); 112 } else { 113 let slice = Ipv6RawExtHeaderSlice::from_slice(rest) 114 .map_err(|err| Len(err.add_offset(slice.len() - rest.len())))?; 115 rest = &rest[slice.slice().len()..]; 116 next_header = slice.next_header(); 117 result.destination_options = Some(slice.to_header()); 118 } 119 } 120 IPV6_ROUTE => { 121 if result.routing.is_some() { 122 // more then one header of this type found -> abort parsing 123 return Ok((result, next_header, rest)); 124 } else { 125 let slice = Ipv6RawExtHeaderSlice::from_slice(rest) 126 .map_err(|err| Len(err.add_offset(slice.len() - rest.len())))?; 127 rest = &rest[slice.slice().len()..]; 128 next_header = slice.next_header(); 129 result.routing = Some(Ipv6RoutingExtensions { 130 routing: slice.to_header(), 131 final_destination_options: None, 132 }); 133 } 134 } 135 IPV6_FRAG => { 136 if result.fragment.is_some() { 137 // more then one header of this type found -> abort parsing 138 return Ok((result, next_header, rest)); 139 } else { 140 let slice = Ipv6FragmentHeaderSlice::from_slice(rest) 141 .map_err(|err| Len(err.add_offset(slice.len() - rest.len())))?; 142 rest = &rest[slice.slice().len()..]; 143 next_header = slice.next_header(); 144 result.fragment = Some(slice.to_header()); 145 } 146 } 147 AUTH => { 148 if result.auth.is_some() { 149 // more then one header of this type found -> abort parsing 150 return Ok((result, next_header, rest)); 151 } else { 152 let slice = IpAuthHeaderSlice::from_slice(rest).map_err(|err| { 153 use err::ip_auth::HeaderSliceError as I; 154 use err::ipv6_exts::HeaderError as O; 155 match err { 156 I::Len(err) => Len(err.add_offset(slice.len() - rest.len())), 157 I::Content(err) => Content(O::IpAuth(err)), 158 } 159 })?; 160 rest = &rest[slice.slice().len()..]; 161 next_header = slice.next_header(); 162 result.auth = Some(slice.to_header()); 163 } 164 } 165 _ => { 166 // done parsing, the next header is not a known header extension 167 return Ok((result, next_header, rest)); 168 } 169 } 170 } 171 //should not be hit 172 } 173 174 /// Reads as many extension headers as possible from the slice until a non IPv6 extension 175 /// header or an error gets encountered. 176 /// 177 /// This function differs from [`Ipv6Extensions::from_slice`] in that it returns the successfully 178 /// parsed parts together with the error. While [`Ipv6Extensions::from_slice`] only returns an 179 /// error. 180 /// 181 /// Note that this function (same as [`Ipv6Extensions::from_slice`]) will stop parsing as soon 182 /// as more headers then can be stored in [`Ipv6Extensions`] are encountered. E.g. if there is 183 /// more then one "auth" header the function returns as soon as the second "auth" header is 184 /// encountered. from_slice_lax( start_ip_number: IpNumber, slice: &[u8], ) -> ( Ipv6Extensions, IpNumber, &[u8], Option<(err::ipv6_exts::HeaderSliceError, err::Layer)>, )185 pub fn from_slice_lax( 186 start_ip_number: IpNumber, 187 slice: &[u8], 188 ) -> ( 189 Ipv6Extensions, 190 IpNumber, 191 &[u8], 192 Option<(err::ipv6_exts::HeaderSliceError, err::Layer)>, 193 ) { 194 let mut result: Ipv6Extensions = Default::default(); 195 let mut rest = slice; 196 let mut next_header = start_ip_number; 197 198 use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*}; 199 use ip_number::*; 200 201 // the hop by hop header is required to occur directly after the ipv6 header 202 if IPV6_HOP_BY_HOP == next_header { 203 match Ipv6RawExtHeaderSlice::from_slice(rest) { 204 Ok(slice) => { 205 rest = &rest[slice.slice().len()..]; 206 next_header = slice.next_header(); 207 result.hop_by_hop_options = Some(slice.to_header()); 208 } 209 Err(error) => { 210 return ( 211 result, 212 next_header, 213 rest, 214 Some((Len(error), Layer::Ipv6HopByHopHeader)), 215 ); 216 } 217 } 218 } 219 220 loop { 221 match next_header { 222 IPV6_HOP_BY_HOP => { 223 return ( 224 result, 225 next_header, 226 rest, 227 Some((Content(HopByHopNotAtStart), Layer::Ipv6HopByHopHeader)), 228 ); 229 } 230 IPV6_DEST_OPTIONS => { 231 if let Some(ref mut routing) = result.routing { 232 // if the routing header is already present 233 // this this a "final destination options" header 234 if routing.final_destination_options.is_some() { 235 // more then one header of this type found -> abort parsing 236 return (result, next_header, rest, None); 237 } else { 238 match Ipv6RawExtHeaderSlice::from_slice(rest) { 239 Ok(slice) => { 240 rest = &rest[slice.slice().len()..]; 241 next_header = slice.next_header(); 242 routing.final_destination_options = Some(slice.to_header()); 243 } 244 Err(err) => { 245 return ( 246 result, 247 next_header, 248 rest, 249 Some(( 250 Len(err.add_offset(slice.len() - rest.len())), 251 Layer::Ipv6DestOptionsHeader, 252 )), 253 ); 254 } 255 } 256 } 257 } else if result.destination_options.is_some() { 258 // more then one header of this type found -> abort parsing 259 return (result, next_header, rest, None); 260 } else { 261 match Ipv6RawExtHeaderSlice::from_slice(rest) { 262 Ok(slice) => { 263 rest = &rest[slice.slice().len()..]; 264 next_header = slice.next_header(); 265 result.destination_options = Some(slice.to_header()); 266 } 267 Err(err) => { 268 return ( 269 result, 270 next_header, 271 rest, 272 Some(( 273 Len(err.add_offset(slice.len() - rest.len())), 274 Layer::Ipv6DestOptionsHeader, 275 )), 276 ); 277 } 278 } 279 } 280 } 281 IPV6_ROUTE => { 282 if result.routing.is_some() { 283 // more then one header of this type found -> abort parsing 284 return (result, next_header, rest, None); 285 } else { 286 match Ipv6RawExtHeaderSlice::from_slice(rest) { 287 Ok(slice) => { 288 rest = &rest[slice.slice().len()..]; 289 next_header = slice.next_header(); 290 result.routing = Some(Ipv6RoutingExtensions { 291 routing: slice.to_header(), 292 final_destination_options: None, 293 }); 294 } 295 Err(err) => { 296 return ( 297 result, 298 next_header, 299 rest, 300 Some(( 301 Len(err.add_offset(slice.len() - rest.len())), 302 Layer::Ipv6RouteHeader, 303 )), 304 ); 305 } 306 } 307 } 308 } 309 IPV6_FRAG => { 310 if result.fragment.is_some() { 311 // more then one header of this type found -> abort parsing 312 return (result, next_header, rest, None); 313 } else { 314 match Ipv6FragmentHeaderSlice::from_slice(rest) { 315 Ok(slice) => { 316 rest = &rest[slice.slice().len()..]; 317 next_header = slice.next_header(); 318 result.fragment = Some(slice.to_header()); 319 } 320 Err(err) => { 321 return ( 322 result, 323 next_header, 324 rest, 325 Some(( 326 Len(err.add_offset(slice.len() - rest.len())), 327 Layer::Ipv6FragHeader, 328 )), 329 ); 330 } 331 } 332 } 333 } 334 AUTH => { 335 if result.auth.is_some() { 336 // more then one header of this type found -> abort parsing 337 return (result, next_header, rest, None); 338 } else { 339 match IpAuthHeaderSlice::from_slice(rest) { 340 Ok(slice) => { 341 rest = &rest[slice.slice().len()..]; 342 next_header = slice.next_header(); 343 result.auth = Some(slice.to_header()); 344 } 345 Err(err) => { 346 use err::ip_auth::HeaderSliceError as I; 347 use err::ipv6_exts::HeaderError as O; 348 return ( 349 result, 350 next_header, 351 rest, 352 Some(( 353 match err { 354 I::Len(err) => { 355 Len(err.add_offset(slice.len() - rest.len())) 356 } 357 I::Content(err) => Content(O::IpAuth(err)), 358 }, 359 Layer::IpAuthHeader, 360 )), 361 ); 362 } 363 } 364 } 365 } 366 _ => { 367 // done parsing, the next header is not a known header extension 368 return (result, next_header, rest, None); 369 } 370 } 371 } 372 //should not be hit 373 } 374 375 /// Reads as many extension headers as possible from the reader and returns the found ipv6 376 /// extension headers and the next header ip number. 377 /// 378 /// If no extension headers are present an unfilled struct and the original `first_header` 379 /// ip number is returned. 380 /// 381 /// Note that this function can only handle ipv6 extensions if each extension header does 382 /// occur at most once, except for destination options headers which are allowed to 383 /// exist once in front of a routing header and once after a routing header. 384 /// 385 /// In case that more extension headers then can fit into a `Ipv6Extensions` struct are 386 /// encountered, the parsing is stoped at the point where the data would no longer fit into 387 /// the struct. In such a scenario a struct with the data that could be parsed is returned 388 /// together with the next header ip number that identfies which header could be read next. 389 /// 390 /// It is in the responsibility of the caller to handle a scenario like this. 391 /// 392 /// The reason that no error is generated, is that even though according to RFC 8200, packets 393 /// "should" not contain more then one occurence of an extension header, the RFC also specifies 394 /// that "IPv6 nodes must accept and attempt to process extension headers in any order and 395 /// occurring any number of times in the same packet". So packets with multiple headers "should" 396 /// not exist, but are still valid IPv6 packets. As such this function does not generate a 397 /// parsing error, as it is not an invalid packet, but if packets like these are encountered 398 /// the user of this function has to themself decide how to handle packets like these. 399 /// 400 /// The only exception is if an hop by hop header is located somewhere else then directly at 401 /// the start. In this case an `ReadError::Ipv6HopByHopHeaderNotAtStart` error is generated as 402 /// the hop by hop header is required to be located directly after the IPv6 header according 403 /// to RFC 8200. 404 #[cfg(feature = "std")] 405 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] read<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, start_ip_number: IpNumber, ) -> Result<(Ipv6Extensions, IpNumber), err::ipv6_exts::HeaderReadError>406 pub fn read<T: std::io::Read + std::io::Seek + Sized>( 407 reader: &mut T, 408 start_ip_number: IpNumber, 409 ) -> Result<(Ipv6Extensions, IpNumber), err::ipv6_exts::HeaderReadError> { 410 let mut result: Ipv6Extensions = Default::default(); 411 let mut next_protocol = start_ip_number; 412 413 use err::ipv6_exts::{HeaderError::*, HeaderReadError::*}; 414 use ip_number::*; 415 416 // the hop by hop header is required to occur directly after the ipv6 header 417 if IPV6_HOP_BY_HOP == next_protocol { 418 let header = Ipv6RawExtHeader::read(reader).map_err(Io)?; 419 next_protocol = header.next_header; 420 result.hop_by_hop_options = Some(header); 421 } 422 423 loop { 424 match next_protocol { 425 IPV6_HOP_BY_HOP => { 426 return Err(Content(HopByHopNotAtStart)); 427 } 428 IPV6_DEST_OPTIONS => { 429 if let Some(ref mut routing) = result.routing { 430 // if the routing header is already present 431 // asume this is a "final destination options" header 432 if routing.final_destination_options.is_some() { 433 // more then one header of this type found -> abort parsing 434 return Ok((result, next_protocol)); 435 } else { 436 let header = Ipv6RawExtHeader::read(reader).map_err(Io)?; 437 next_protocol = header.next_header; 438 routing.final_destination_options = Some(header); 439 } 440 } else if result.destination_options.is_some() { 441 // more then one header of this type found -> abort parsing 442 return Ok((result, next_protocol)); 443 } else { 444 let header = Ipv6RawExtHeader::read(reader).map_err(Io)?; 445 next_protocol = header.next_header; 446 result.destination_options = Some(header); 447 } 448 } 449 IPV6_ROUTE => { 450 if result.routing.is_some() { 451 // more then one header of this type found -> abort parsing 452 return Ok((result, next_protocol)); 453 } else { 454 let header = Ipv6RawExtHeader::read(reader).map_err(Io)?; 455 next_protocol = header.next_header; 456 result.routing = Some(Ipv6RoutingExtensions { 457 routing: header, 458 final_destination_options: None, 459 }); 460 } 461 } 462 IPV6_FRAG => { 463 if result.fragment.is_some() { 464 // more then one header of this type found -> abort parsing 465 return Ok((result, next_protocol)); 466 } else { 467 let header = Ipv6FragmentHeader::read(reader).map_err(Io)?; 468 next_protocol = header.next_header; 469 result.fragment = Some(header); 470 } 471 } 472 AUTH => { 473 if result.auth.is_some() { 474 // more then one header of this type found -> abort parsing 475 return Ok((result, next_protocol)); 476 } else { 477 let header = IpAuthHeader::read(reader).map_err(|err| { 478 use err::ip_auth::HeaderReadError as I; 479 match err { 480 I::Io(err) => Io(err), 481 I::Content(err) => Content(IpAuth(err)), 482 } 483 })?; 484 next_protocol = header.next_header; 485 result.auth = Some(header); 486 } 487 } 488 _ => { 489 // done parsing, the next header is not a known header extension 490 return Ok((result, next_protocol)); 491 } 492 } 493 } 494 495 //should not be hit 496 } 497 498 /// Reads as many extension headers as possible from the limited reader and returns the found ipv6 499 /// extension headers and the next header ip number. 500 /// 501 /// If no extension headers are present an unfilled struct and the original `first_header` 502 /// ip number is returned. 503 /// 504 /// Note that this function can only handle ipv6 extensions if each extension header does 505 /// occur at most once, except for destination options headers which are allowed to 506 /// exist once in front of a routing header and once after a routing header. 507 /// 508 /// In case that more extension headers then can fit into a `Ipv6Extensions` struct are 509 /// encountered, the parsing is stoped at the point where the data would no longer fit into 510 /// the struct. In such a scenario a struct with the data that could be parsed is returned 511 /// together with the next header ip number that identfies which header could be read next. 512 /// 513 /// It is in the responsibility of the caller to handle a scenario like this. 514 /// 515 /// The reason that no error is generated, is that even though according to RFC 8200, packets 516 /// "should" not contain more then one occurence of an extension header, the RFC also specifies 517 /// that "IPv6 nodes must accept and attempt to process extension headers in any order and 518 /// occurring any number of times in the same packet". So packets with multiple headers "should" 519 /// not exist, but are still valid IPv6 packets. As such this function does not generate a 520 /// parsing error, as it is not an invalid packet, but if packets like these are encountered 521 /// the user of this function has to themself decide how to handle packets like these. 522 /// 523 /// The only exception is if an hop by hop header is located somewhere else then directly at 524 /// the start. In this case an `ReadError::Ipv6HopByHopHeaderNotAtStart` error is generated as 525 /// the hop by hop header is required to be located directly after the IPv6 header according 526 /// to RFC 8200. 527 #[cfg(feature = "std")] 528 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] read_limited<T: std::io::Read + std::io::Seek + Sized>( reader: &mut crate::io::LimitedReader<T>, start_ip_number: IpNumber, ) -> Result<(Ipv6Extensions, IpNumber), HeaderLimitedReadError>529 pub fn read_limited<T: std::io::Read + std::io::Seek + Sized>( 530 reader: &mut crate::io::LimitedReader<T>, 531 start_ip_number: IpNumber, 532 ) -> Result<(Ipv6Extensions, IpNumber), HeaderLimitedReadError> { 533 use ip_number::*; 534 use HeaderError::*; 535 use HeaderLimitedReadError::*; 536 537 fn map_limited_err(err: err::io::LimitedReadError) -> HeaderLimitedReadError { 538 use crate::err::io::LimitedReadError as I; 539 match err { 540 I::Io(err) => Io(err), 541 I::Len(err) => Len(err), 542 } 543 } 544 545 // start decoding 546 let mut result: Ipv6Extensions = Default::default(); 547 let mut next_protocol = start_ip_number; 548 549 // the hop by hop header is required to occur directly after the ipv6 header 550 if IPV6_HOP_BY_HOP == next_protocol { 551 let header = Ipv6RawExtHeader::read_limited(reader).map_err(map_limited_err)?; 552 next_protocol = header.next_header; 553 result.hop_by_hop_options = Some(header); 554 } 555 556 loop { 557 match next_protocol { 558 IPV6_HOP_BY_HOP => { 559 return Err(Content(HopByHopNotAtStart)); 560 } 561 IPV6_DEST_OPTIONS => { 562 if let Some(ref mut routing) = result.routing { 563 // if the routing header is already present 564 // asume this is a "final destination options" header 565 if routing.final_destination_options.is_some() { 566 // more then one header of this type found -> abort parsing 567 return Ok((result, next_protocol)); 568 } else { 569 let header = 570 Ipv6RawExtHeader::read_limited(reader).map_err(map_limited_err)?; 571 next_protocol = header.next_header; 572 routing.final_destination_options = Some(header); 573 } 574 } else if result.destination_options.is_some() { 575 // more then one header of this type found -> abort parsing 576 return Ok((result, next_protocol)); 577 } else { 578 let header = 579 Ipv6RawExtHeader::read_limited(reader).map_err(map_limited_err)?; 580 next_protocol = header.next_header; 581 result.destination_options = Some(header); 582 } 583 } 584 IPV6_ROUTE => { 585 if result.routing.is_some() { 586 // more then one header of this type found -> abort parsing 587 return Ok((result, next_protocol)); 588 } else { 589 let header = 590 Ipv6RawExtHeader::read_limited(reader).map_err(map_limited_err)?; 591 next_protocol = header.next_header; 592 result.routing = Some(Ipv6RoutingExtensions { 593 routing: header, 594 final_destination_options: None, 595 }); 596 } 597 } 598 IPV6_FRAG => { 599 if result.fragment.is_some() { 600 // more then one header of this type found -> abort parsing 601 return Ok((result, next_protocol)); 602 } else { 603 let header = 604 Ipv6FragmentHeader::read_limited(reader).map_err(map_limited_err)?; 605 next_protocol = header.next_header; 606 result.fragment = Some(header); 607 } 608 } 609 AUTH => { 610 if result.auth.is_some() { 611 // more then one header of this type found -> abort parsing 612 return Ok((result, next_protocol)); 613 } else { 614 let header = IpAuthHeader::read_limited(reader).map_err(|err| { 615 use err::ip_auth::HeaderLimitedReadError as I; 616 match err { 617 I::Io(err) => Io(err), 618 I::Len(err) => Len(err), 619 I::Content(err) => Content(IpAuth(err)), 620 } 621 })?; 622 next_protocol = header.next_header; 623 result.auth = Some(header); 624 } 625 } 626 _ => { 627 // done parsing, the next header is not a known header extension 628 return Ok((result, next_protocol)); 629 } 630 } 631 } 632 633 //should not be hit 634 } 635 636 /// Writes the given headers to a writer based on the order defined in 637 /// the next_header fields of the headers and the first header_id 638 /// passed to this function. 639 /// 640 /// It is required that all next header are correctly set in the headers 641 /// and no other ipv6 header extensions follow this header. If this is not 642 /// the case an [`err::ipv6_exts::HeaderWriteError::Content`] error is 643 /// returned. 644 #[cfg(feature = "std")] 645 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] write<T: std::io::Write + Sized>( &self, writer: &mut T, first_header: IpNumber, ) -> Result<(), err::ipv6_exts::HeaderWriteError>646 pub fn write<T: std::io::Write + Sized>( 647 &self, 648 writer: &mut T, 649 first_header: IpNumber, 650 ) -> Result<(), err::ipv6_exts::HeaderWriteError> { 651 use err::ipv6_exts::ExtsWalkError::*; 652 use err::ipv6_exts::HeaderWriteError::*; 653 use ip_number::*; 654 655 /// Struct flagging if a header needs to be written. 656 struct NeedsWrite { 657 pub hop_by_hop_options: bool, 658 pub destination_options: bool, 659 pub routing: bool, 660 pub fragment: bool, 661 pub auth: bool, 662 pub final_destination_options: bool, 663 } 664 665 let mut needs_write = NeedsWrite { 666 hop_by_hop_options: self.hop_by_hop_options.is_some(), 667 destination_options: self.destination_options.is_some(), 668 routing: self.routing.is_some(), 669 fragment: self.fragment.is_some(), 670 auth: self.auth.is_some(), 671 final_destination_options: if let Some(ref routing) = self.routing { 672 routing.final_destination_options.is_some() 673 } else { 674 false 675 }, 676 }; 677 678 let mut next_header = first_header; 679 let mut route_written = false; 680 681 // check if hop by hop header should be written first 682 if IPV6_HOP_BY_HOP == next_header { 683 let header = &self.hop_by_hop_options.as_ref().unwrap(); 684 header.write(writer).map_err(Io)?; 685 next_header = header.next_header; 686 needs_write.hop_by_hop_options = false; 687 } 688 689 loop { 690 match next_header { 691 IPV6_HOP_BY_HOP => { 692 // Only trigger a "hop by hop not at start" error 693 // if we actually still have to write a hop by hop header. 694 // 695 // The ip number for hop by hop is 0, which could be used 696 // as a placeholder by user and later replaced. So let's 697 // not be overzealous and allow a next header with hop 698 // by hop if it is not part of this extensions struct. 699 if needs_write.hop_by_hop_options { 700 // the hop by hop header is only allowed at the start 701 return Err(Content(HopByHopNotAtStart)); 702 } else { 703 break; 704 } 705 } 706 IPV6_DEST_OPTIONS => { 707 // the destination options are allowed to be written twice 708 // once before a routing header and once after. 709 if route_written { 710 if needs_write.final_destination_options { 711 let header = &self 712 .routing 713 .as_ref() 714 .unwrap() 715 .final_destination_options 716 .as_ref() 717 .unwrap(); 718 header.write(writer).map_err(Io)?; 719 next_header = header.next_header; 720 needs_write.final_destination_options = false; 721 } else { 722 break; 723 } 724 } else if needs_write.destination_options { 725 let header = &self.destination_options.as_ref().unwrap(); 726 header.write(writer).map_err(Io)?; 727 next_header = header.next_header; 728 needs_write.destination_options = false; 729 } else { 730 break; 731 } 732 } 733 IPV6_ROUTE => { 734 if needs_write.routing { 735 let header = &self.routing.as_ref().unwrap().routing; 736 header.write(writer).map_err(Io)?; 737 next_header = header.next_header; 738 needs_write.routing = false; 739 // for destination options 740 route_written = true; 741 } else { 742 break; 743 } 744 } 745 IPV6_FRAG => { 746 if needs_write.fragment { 747 let header = &self.fragment.as_ref().unwrap(); 748 header.write(writer).map_err(Io)?; 749 next_header = header.next_header; 750 needs_write.fragment = false; 751 } else { 752 break; 753 } 754 } 755 AUTH => { 756 if needs_write.auth { 757 let header = &self.auth.as_ref().unwrap(); 758 header.write(writer).map_err(Io)?; 759 next_header = header.next_header; 760 needs_write.auth = false; 761 } else { 762 break; 763 } 764 } 765 _ => { 766 // reached an unknown next_header id, proceed to check if everything was written 767 break; 768 } 769 } 770 } 771 772 // check that all header have been written 773 if needs_write.hop_by_hop_options { 774 Err(Content(ExtNotReferenced { 775 missing_ext: IpNumber::IPV6_HEADER_HOP_BY_HOP, 776 })) 777 } else if needs_write.destination_options { 778 Err(Content(ExtNotReferenced { 779 missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS, 780 })) 781 } else if needs_write.routing { 782 Err(Content(ExtNotReferenced { 783 missing_ext: IpNumber::IPV6_ROUTE_HEADER, 784 })) 785 } else if needs_write.fragment { 786 Err(Content(ExtNotReferenced { 787 missing_ext: IpNumber::IPV6_FRAGMENTATION_HEADER, 788 })) 789 } else if needs_write.auth { 790 Err(Content(ExtNotReferenced { 791 missing_ext: IpNumber::AUTHENTICATION_HEADER, 792 })) 793 } else if needs_write.final_destination_options { 794 Err(Content(ExtNotReferenced { 795 missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS, 796 })) 797 } else { 798 Ok(()) 799 } 800 } 801 802 /// Length of the all present headers in bytes. header_len(&self) -> usize803 pub fn header_len(&self) -> usize { 804 let mut result = 0; 805 806 if let Some(ref header) = self.hop_by_hop_options { 807 result += header.header_len(); 808 } 809 if let Some(ref header) = self.destination_options { 810 result += header.header_len(); 811 } 812 if let Some(ref header) = self.routing { 813 result += header.routing.header_len(); 814 if let Some(ref header) = header.final_destination_options { 815 result += header.header_len(); 816 } 817 } 818 if let Some(ref header) = self.fragment { 819 result += header.header_len(); 820 } 821 if let Some(ref header) = self.auth { 822 result += header.header_len(); 823 } 824 825 result 826 } 827 828 /// Sets all the next_header fields of the headers based on the adviced default order 829 /// with the given protocol number as last "next header" value. The return value is the protocol 830 /// number of the first existing extension header that should be entered in the ipv6 header as 831 /// next_header. 832 /// 833 /// If no extension headers are present the value of the argument is returned. set_next_headers(&mut self, last_protocol_number: IpNumber) -> IpNumber834 pub fn set_next_headers(&mut self, last_protocol_number: IpNumber) -> IpNumber { 835 use ip_number::*; 836 837 let mut next = last_protocol_number; 838 839 // go through the proposed order of extension headers from 840 // RFC 8200 backwards. The header order defined in RFC8200 is: 841 // 842 // * IPv6 header 843 // * Hop-by-Hop Options header 844 // * Destination Options header 845 // * Routing header 846 // * Fragment header 847 // * Authentication header 848 // * Encapsulating Security Payload header 849 // * Destination Options header 850 // * Upper-Layer header 851 // 852 if let Some(ref mut routing) = self.routing { 853 if let Some(ref mut header) = routing.final_destination_options { 854 header.next_header = next; 855 next = IPV6_DEST_OPTIONS; 856 } 857 } 858 if let Some(ref mut header) = self.auth { 859 header.next_header = next; 860 next = AUTH; 861 } 862 if let Some(ref mut header) = self.fragment { 863 header.next_header = next; 864 next = IPV6_FRAG; 865 } 866 if let Some(ref mut routing) = self.routing { 867 routing.routing.next_header = next; 868 next = IPV6_ROUTE; 869 } 870 if let Some(ref mut header) = self.destination_options { 871 header.next_header = next; 872 next = IPV6_DEST_OPTIONS; 873 } 874 if let Some(ref mut header) = self.hop_by_hop_options { 875 header.next_header = next; 876 next = IPV6_HOP_BY_HOP; 877 } 878 879 next 880 } 881 882 /// Return next header based on the extension headers and 883 /// the first ip protocol number. next_header(&self, first_next_header: IpNumber) -> Result<IpNumber, ExtsWalkError>884 pub fn next_header(&self, first_next_header: IpNumber) -> Result<IpNumber, ExtsWalkError> { 885 use ip_number::*; 886 use ExtsWalkError::*; 887 888 /// Struct flagging if a header needs to be referenced. 889 struct OutstandingRef { 890 pub hop_by_hop_options: bool, 891 pub destination_options: bool, 892 pub routing: bool, 893 pub fragment: bool, 894 pub auth: bool, 895 pub final_destination_options: bool, 896 } 897 898 let mut outstanding_refs = OutstandingRef { 899 hop_by_hop_options: self.hop_by_hop_options.is_some(), 900 destination_options: self.destination_options.is_some(), 901 routing: self.routing.is_some(), 902 fragment: self.fragment.is_some(), 903 auth: self.auth.is_some(), 904 final_destination_options: if let Some(ref routing) = self.routing { 905 routing.final_destination_options.is_some() 906 } else { 907 false 908 }, 909 }; 910 911 let mut next = first_next_header; 912 let mut route_refed = false; 913 914 // check if hop by hop header should be written first 915 if IPV6_HOP_BY_HOP == next { 916 if let Some(ref header) = self.hop_by_hop_options { 917 next = header.next_header; 918 outstanding_refs.hop_by_hop_options = false; 919 } 920 } 921 922 loop { 923 match next { 924 IPV6_HOP_BY_HOP => { 925 // Only trigger a "hop by hop not at start" error 926 // if we actually still have to write a hop by hop header. 927 // 928 // The ip number for hop by hop is 0, which could be used 929 // as a placeholder by user and later replaced. So let's 930 // not be overzealous and allow a next header with hop 931 // by hop if it is not part of this extensions struct. 932 if outstanding_refs.hop_by_hop_options { 933 // the hop by hop header is only allowed at the start 934 return Err(HopByHopNotAtStart); 935 } else { 936 break; 937 } 938 } 939 IPV6_DEST_OPTIONS => { 940 // the destination options are allowed to be written twice 941 // once before a routing header and once after. 942 if route_refed { 943 if outstanding_refs.final_destination_options { 944 let header = &self 945 .routing 946 .as_ref() 947 .unwrap() 948 .final_destination_options 949 .as_ref() 950 .unwrap(); 951 next = header.next_header; 952 outstanding_refs.final_destination_options = false; 953 } else { 954 break; 955 } 956 } else if outstanding_refs.destination_options { 957 let header = &self.destination_options.as_ref().unwrap(); 958 next = header.next_header; 959 outstanding_refs.destination_options = false; 960 } else { 961 break; 962 } 963 } 964 IPV6_ROUTE => { 965 if outstanding_refs.routing { 966 let header = &self.routing.as_ref().unwrap().routing; 967 next = header.next_header; 968 outstanding_refs.routing = false; 969 // for destination options 970 route_refed = true; 971 } else { 972 break; 973 } 974 } 975 IPV6_FRAG => { 976 if outstanding_refs.fragment { 977 let header = &self.fragment.as_ref().unwrap(); 978 next = header.next_header; 979 outstanding_refs.fragment = false; 980 } else { 981 break; 982 } 983 } 984 AUTH => { 985 if outstanding_refs.auth { 986 let header = &self.auth.as_ref().unwrap(); 987 next = header.next_header; 988 outstanding_refs.auth = false; 989 } else { 990 break; 991 } 992 } 993 _ => break, 994 } 995 } 996 997 // assume all done 998 if outstanding_refs.hop_by_hop_options { 999 return Err(ExtNotReferenced { 1000 missing_ext: IpNumber::IPV6_HEADER_HOP_BY_HOP, 1001 }); 1002 } 1003 if outstanding_refs.destination_options { 1004 return Err(ExtNotReferenced { 1005 missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS, 1006 }); 1007 } 1008 if outstanding_refs.routing { 1009 return Err(ExtNotReferenced { 1010 missing_ext: IpNumber::IPV6_ROUTE_HEADER, 1011 }); 1012 } 1013 if outstanding_refs.fragment { 1014 return Err(ExtNotReferenced { 1015 missing_ext: IpNumber::IPV6_FRAGMENTATION_HEADER, 1016 }); 1017 } 1018 if outstanding_refs.auth { 1019 return Err(ExtNotReferenced { 1020 missing_ext: IpNumber::AUTHENTICATION_HEADER, 1021 }); 1022 } 1023 if outstanding_refs.final_destination_options { 1024 return Err(ExtNotReferenced { 1025 missing_ext: IpNumber::IPV6_DESTINATION_OPTIONS, 1026 }); 1027 } 1028 1029 Ok(next) 1030 } 1031 1032 /// Returns true if a fragmentation header is present in 1033 /// the extensions that fragments the payload. 1034 /// 1035 /// Note: A fragmentation header can still be present 1036 /// even if the return value is false in case the fragmentation 1037 /// headers don't fragment the payload. This is the case if 1038 /// the offset of all fragmentation header is 0 and the 1039 /// more fragment bit is not set. 1040 #[inline] is_fragmenting_payload(&self) -> bool1041 pub fn is_fragmenting_payload(&self) -> bool { 1042 if let Some(frag) = self.fragment.as_ref() { 1043 frag.is_fragmenting_payload() 1044 } else { 1045 false 1046 } 1047 } 1048 1049 /// Returns true if no IPv6 extension header is present (all fields `None`). 1050 #[inline] is_empty(&self) -> bool1051 pub fn is_empty(&self) -> bool { 1052 self.hop_by_hop_options.is_none() 1053 && self.destination_options.is_none() 1054 && self.routing.is_none() 1055 && self.fragment.is_none() 1056 && self.auth.is_none() 1057 } 1058 } 1059 1060 #[cfg(test)] 1061 pub mod ipv6_exts_test_helpers { 1062 use super::*; 1063 use crate::ip_number::*; 1064 use alloc::vec::Vec; 1065 1066 /// IP numbers that are assigned ipv6 header extensions. 1067 pub const EXTENSION_KNOWN_IP_NUMBERS: [IpNumber; 5] = [ 1068 AUTH, 1069 IPV6_DEST_OPTIONS, 1070 IPV6_HOP_BY_HOP, 1071 IPV6_FRAG, 1072 IPV6_ROUTE, 1073 ]; 1074 1075 /// Helper struct that generates test data with dummy 1076 /// extension header data. 1077 pub struct ExtensionTestPayload { 1078 pub ip_numbers: Vec<IpNumber>, 1079 pub lengths: Vec<usize>, 1080 pub data: Vec<u8>, 1081 } 1082 1083 impl ExtensionTestPayload { new(ip_numbers: &[IpNumber], header_sizes: &[u8]) -> ExtensionTestPayload1084 pub fn new(ip_numbers: &[IpNumber], header_sizes: &[u8]) -> ExtensionTestPayload { 1085 assert!(ip_numbers.len() > 1); 1086 assert!(header_sizes.len() > 0); 1087 1088 let mut result = ExtensionTestPayload { 1089 ip_numbers: ip_numbers.to_vec(), 1090 lengths: Vec::with_capacity(ip_numbers.len() - 1), 1091 data: Vec::with_capacity((ip_numbers.len() - 1) * (0xff * 8 + 8)), 1092 }; 1093 for i in 0..ip_numbers.len() - 1 { 1094 result.add_payload( 1095 ip_numbers[i], 1096 ip_numbers[i + 1], 1097 header_sizes[i % header_sizes.len()], 1098 ) 1099 } 1100 result 1101 } 1102 slice(&self) -> &[u8]1103 pub fn slice(&self) -> &[u8] { 1104 &self.data 1105 } 1106 add_payload(&mut self, ip_number: IpNumber, next_header: IpNumber, header_ext_len: u8)1107 fn add_payload(&mut self, ip_number: IpNumber, next_header: IpNumber, header_ext_len: u8) { 1108 match ip_number { 1109 IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS => { 1110 // insert next header & size 1111 let mut raw: [u8; 0xff * 8 + 8] = [0; 0xff * 8 + 8]; 1112 raw[0] = next_header.0; 1113 raw[1] = header_ext_len; 1114 1115 // insert payload 1116 self.data 1117 .extend_from_slice(&raw[..8 + usize::from(header_ext_len) * 8]); 1118 self.lengths.push(8 + usize::from(header_ext_len) * 8); 1119 } 1120 IPV6_FRAG => { 1121 // generate payload 1122 let mut raw: [u8; 8] = [0; 8]; 1123 raw[0] = next_header.0; 1124 raw[1] = 0; 1125 1126 // insert payload 1127 self.data.extend_from_slice(&raw[..8]); 1128 self.lengths.push(8); 1129 } 1130 AUTH => { 1131 let mut raw: [u8; 0xff * 4 + 8] = [0; 0xff * 4 + 8]; 1132 raw[0] = next_header.0; 1133 // authentfication header len is defined as 1134 // '32-bit words (4-byteunits), minus "2"' 1135 let len = if header_ext_len > 0 { 1136 raw[1] = header_ext_len; 1137 usize::from(header_ext_len) * 4 1138 } else { 1139 // auth has a minimum size of 1 1140 raw[1] = 1; 1141 4 1142 } + 8; 1143 self.data.extend_from_slice(&raw[..len]); 1144 self.lengths.push(len); 1145 } 1146 _ => unreachable!(), 1147 } 1148 } 1149 1150 /// Returns true of the payload will trigger a "hop by hop not 1151 /// at start" error which is not ignored because of an early 1152 /// parsing abort. exts_hop_by_hop_error(&self) -> bool1153 pub fn exts_hop_by_hop_error(&self) -> bool { 1154 struct ReadState { 1155 dest_opt: bool, 1156 routing: bool, 1157 final_dest_opt: bool, 1158 frag: bool, 1159 auth: bool, 1160 } 1161 1162 // state if a header type has already been read 1163 let mut read = ReadState { 1164 dest_opt: false, 1165 routing: false, 1166 final_dest_opt: false, 1167 frag: false, 1168 auth: false, 1169 }; 1170 1171 for i in 0..self.ip_numbers.len() { 1172 match self.ip_numbers[i] { 1173 IPV6_HOP_BY_HOP => { 1174 if i != 0 { 1175 return true; 1176 } 1177 } 1178 IPV6_ROUTE => { 1179 if read.routing { 1180 return false; 1181 } else { 1182 read.routing = true; 1183 } 1184 } 1185 IPV6_DEST_OPTIONS => { 1186 // check the kind of destination options (aka is it before or after the routing header) 1187 if read.routing { 1188 // final dest opt 1189 if read.final_dest_opt { 1190 return false; 1191 } else { 1192 read.final_dest_opt = true; 1193 } 1194 } else { 1195 // dst opt 1196 if read.dest_opt { 1197 return false; 1198 } else { 1199 read.dest_opt = true; 1200 } 1201 } 1202 } 1203 IPV6_FRAG => { 1204 if read.frag { 1205 return false; 1206 } else { 1207 read.frag = true; 1208 } 1209 } 1210 AUTH => { 1211 if read.auth { 1212 return false; 1213 } else { 1214 read.auth = true; 1215 } 1216 } 1217 _ => return false, 1218 } 1219 } 1220 return false; 1221 } 1222 1223 /// Checks the if the extensions match the expected values based 1224 /// on this test payload. assert_extensions( &self, exts: &Ipv6Extensions, ) -> (usize, Option<IpNumber>, IpNumber)1225 pub fn assert_extensions( 1226 &self, 1227 exts: &Ipv6Extensions, 1228 ) -> (usize, Option<IpNumber>, IpNumber) { 1229 struct ReadState { 1230 hop_by_hop: bool, 1231 dest_opt: bool, 1232 routing: bool, 1233 final_dest_opt: bool, 1234 frag: bool, 1235 auth: bool, 1236 } 1237 1238 // state if a header type has already been read 1239 let mut read = ReadState { 1240 hop_by_hop: false, 1241 dest_opt: false, 1242 routing: false, 1243 final_dest_opt: false, 1244 frag: false, 1245 auth: false, 1246 }; 1247 1248 let mut slice = &self.data[..]; 1249 let mut last_decoded = None; 1250 let mut post_header = self.ip_numbers[0]; 1251 1252 for i in 0..self.ip_numbers.len() - 1 { 1253 let mut stop = false; 1254 match self.ip_numbers[i] { 1255 IPV6_HOP_BY_HOP => { 1256 assert!(false == read.hop_by_hop); 1257 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap(); 1258 assert_eq!(&header, exts.hop_by_hop_options.as_ref().unwrap()); 1259 slice = rest; 1260 read.hop_by_hop = true; 1261 last_decoded = Some(IPV6_HOP_BY_HOP); 1262 } 1263 IPV6_ROUTE => { 1264 if read.routing { 1265 stop = true; 1266 } else { 1267 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap(); 1268 assert_eq!(&header, &exts.routing.as_ref().unwrap().routing); 1269 slice = rest; 1270 read.routing = true; 1271 last_decoded = Some(IPV6_ROUTE); 1272 } 1273 } 1274 IPV6_DEST_OPTIONS => { 1275 // check the kind of destination options (aka is it before or after the routing header) 1276 if read.routing { 1277 // final dest opt 1278 if read.final_dest_opt { 1279 stop = true; 1280 } else { 1281 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap(); 1282 assert_eq!( 1283 &header, 1284 exts.routing 1285 .as_ref() 1286 .unwrap() 1287 .final_destination_options 1288 .as_ref() 1289 .unwrap() 1290 ); 1291 slice = rest; 1292 read.final_dest_opt = true; 1293 last_decoded = Some(IPV6_DEST_OPTIONS); 1294 } 1295 } else { 1296 // dst opt 1297 if read.dest_opt { 1298 stop = true; 1299 } else { 1300 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap(); 1301 assert_eq!(&header, exts.destination_options.as_ref().unwrap()); 1302 slice = rest; 1303 read.dest_opt = true; 1304 last_decoded = Some(IPV6_DEST_OPTIONS); 1305 } 1306 } 1307 } 1308 IPV6_FRAG => { 1309 if read.frag { 1310 // duplicate header -> stop 1311 stop = true; 1312 } else { 1313 let (header, rest) = Ipv6FragmentHeader::from_slice(slice).unwrap(); 1314 assert_eq!(&header, exts.fragment.as_ref().unwrap()); 1315 slice = rest; 1316 read.frag = true; 1317 last_decoded = Some(IPV6_FRAG); 1318 } 1319 } 1320 AUTH => { 1321 if read.auth { 1322 // duplicate header -> stop 1323 stop = true; 1324 } else { 1325 let (header, rest) = IpAuthHeader::from_slice(slice).unwrap(); 1326 assert_eq!(&header, exts.auth.as_ref().unwrap()); 1327 slice = rest; 1328 read.auth = true; 1329 last_decoded = Some(AUTH); 1330 } 1331 } 1332 _ => { 1333 // non extension header -> stop 1334 stop = true; 1335 } 1336 } 1337 if stop { 1338 post_header = self.ip_numbers[i]; 1339 break; 1340 } else { 1341 post_header = self.ip_numbers[i + 1]; 1342 } 1343 } 1344 1345 // check the non parsed headers are not present 1346 if false == read.hop_by_hop { 1347 assert!(exts.hop_by_hop_options.is_none()); 1348 } 1349 if false == read.dest_opt { 1350 assert!(exts.destination_options.is_none()); 1351 } 1352 if false == read.routing { 1353 assert!(exts.routing.is_none()); 1354 } else { 1355 if false == read.final_dest_opt { 1356 assert!(exts 1357 .routing 1358 .as_ref() 1359 .unwrap() 1360 .final_destination_options 1361 .is_none()); 1362 } 1363 } 1364 if false == read.frag { 1365 assert!(exts.fragment.is_none()); 1366 } 1367 if false == read.auth { 1368 assert!(exts.auth.is_none()); 1369 } 1370 1371 (self.data.len() - slice.len(), last_decoded, post_header) 1372 } 1373 1374 /// Return the expected lax from slice result and ipnumber which caused 1375 /// an error. lax_extensions_for_len( &self, limiting_len: usize, ) -> (Ipv6Extensions, IpNumber, &[u8], Option<IpNumber>)1376 pub fn lax_extensions_for_len( 1377 &self, 1378 limiting_len: usize, 1379 ) -> (Ipv6Extensions, IpNumber, &[u8], Option<IpNumber>) { 1380 // state if a header type has already been read 1381 let mut exts: Ipv6Extensions = Default::default(); 1382 let mut post_header = *self.ip_numbers.first().unwrap(); 1383 let mut slice = &self.data[..]; 1384 1385 for i in 0..self.ip_numbers.len() - 1 { 1386 // check if the limiting size gets hit 1387 if self.slice().len() - slice.len() + self.lengths[i] > limiting_len { 1388 return ( 1389 exts, 1390 self.ip_numbers[i], 1391 &self.slice()[self.slice().len() - slice.len()..limiting_len], 1392 Some(self.ip_numbers[i]), 1393 ); 1394 } 1395 1396 let mut stop = false; 1397 match self.ip_numbers[i] { 1398 IPV6_HOP_BY_HOP => { 1399 assert!(exts.hop_by_hop_options.is_none()); 1400 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap(); 1401 exts.hop_by_hop_options = Some(header); 1402 slice = rest; 1403 } 1404 IPV6_ROUTE => { 1405 if exts.routing.is_some() { 1406 stop = true; 1407 } else { 1408 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap(); 1409 exts.routing = Some(Ipv6RoutingExtensions { 1410 routing: header, 1411 final_destination_options: None, 1412 }); 1413 slice = rest; 1414 } 1415 } 1416 IPV6_DEST_OPTIONS => { 1417 // check the kind of destination options (aka is it before or after the routing header) 1418 if let Some(routing) = exts.routing.as_mut() { 1419 // final dest opt 1420 if routing.final_destination_options.is_some() { 1421 stop = true; 1422 } else { 1423 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap(); 1424 routing.final_destination_options = Some(header); 1425 slice = rest; 1426 } 1427 } else { 1428 // dst opt 1429 if exts.destination_options.is_some() { 1430 stop = true; 1431 } else { 1432 let (header, rest) = Ipv6RawExtHeader::from_slice(slice).unwrap(); 1433 exts.destination_options = Some(header); 1434 slice = rest; 1435 } 1436 } 1437 } 1438 IPV6_FRAG => { 1439 if exts.fragment.is_some() { 1440 // duplicate header -> stop 1441 stop = true; 1442 } else { 1443 let (header, rest) = Ipv6FragmentHeader::from_slice(slice).unwrap(); 1444 exts.fragment = Some(header); 1445 slice = rest; 1446 } 1447 } 1448 AUTH => { 1449 if exts.auth.is_some() { 1450 // duplicate header -> stop 1451 stop = true; 1452 } else { 1453 let (header, rest) = IpAuthHeader::from_slice(slice).unwrap(); 1454 exts.auth = Some(header); 1455 slice = rest; 1456 } 1457 } 1458 _ => { 1459 // non extension header -> stop 1460 stop = true; 1461 } 1462 } 1463 if stop { 1464 post_header = self.ip_numbers[i]; 1465 break; 1466 } else { 1467 post_header = self.ip_numbers[i + 1]; 1468 } 1469 } 1470 1471 ( 1472 exts, 1473 post_header, 1474 &self.slice()[self.slice().len() - slice.len()..limiting_len], 1475 None, 1476 ) 1477 } 1478 } 1479 1480 /// extension header data. 1481 #[derive(Clone)] 1482 pub struct ExtensionTestHeaders { 1483 pub ip_numbers: Vec<IpNumber>, 1484 pub data: Ipv6Extensions, 1485 } 1486 1487 impl ExtensionTestHeaders { new(ip_numbers: &[IpNumber], header_sizes: &[u8]) -> ExtensionTestHeaders1488 pub fn new(ip_numbers: &[IpNumber], header_sizes: &[u8]) -> ExtensionTestHeaders { 1489 assert!(ip_numbers.len() > 1); 1490 assert!(header_sizes.len() > 0); 1491 1492 let mut result = ExtensionTestHeaders { 1493 ip_numbers: ip_numbers.to_vec(), 1494 data: Default::default(), 1495 }; 1496 for i in 0..ip_numbers.len() - 1 { 1497 let succ = result.add_payload( 1498 ip_numbers[i], 1499 ip_numbers[i + 1], 1500 header_sizes[i % header_sizes.len()], 1501 ); 1502 if false == succ { 1503 // write was not possible (duplicate) 1504 // reduce the list so the current ip number 1505 // is the final one 1506 result.ip_numbers.truncate(i + 1); 1507 break; 1508 } 1509 } 1510 result 1511 } 1512 introduce_missing_ref(&mut self, new_header: IpNumber) -> IpNumber1513 pub fn introduce_missing_ref(&mut self, new_header: IpNumber) -> IpNumber { 1514 assert!(self.ip_numbers.len() >= 2); 1515 1516 // set the next_header of the last extension header and return the id 1517 if self.ip_numbers.len() >= 3 { 1518 match self.ip_numbers[self.ip_numbers.len() - 3] { 1519 IPV6_HOP_BY_HOP => { 1520 self.data.hop_by_hop_options.as_mut().unwrap().next_header = new_header; 1521 } 1522 IPV6_DEST_OPTIONS => { 1523 if self.ip_numbers[..self.ip_numbers.len() - 3] 1524 .iter() 1525 .any(|&x| x == IPV6_ROUTE) 1526 { 1527 self.data 1528 .routing 1529 .as_mut() 1530 .unwrap() 1531 .final_destination_options 1532 .as_mut() 1533 .unwrap() 1534 .next_header = new_header; 1535 } else { 1536 self.data.destination_options.as_mut().unwrap().next_header = 1537 new_header; 1538 } 1539 } 1540 IPV6_ROUTE => { 1541 self.data.routing.as_mut().unwrap().routing.next_header = new_header; 1542 } 1543 IPV6_FRAG => { 1544 self.data.fragment.as_mut().unwrap().next_header = new_header; 1545 } 1546 AUTH => { 1547 self.data.auth.as_mut().unwrap().next_header = new_header; 1548 } 1549 _ => unreachable!(), 1550 } 1551 match self.ip_numbers[self.ip_numbers.len() - 2] { 1552 IPV6_HOP_BY_HOP => IpNumber::IPV6_HEADER_HOP_BY_HOP, 1553 IPV6_DEST_OPTIONS => IpNumber::IPV6_DESTINATION_OPTIONS, 1554 IPV6_ROUTE => IpNumber::IPV6_ROUTE_HEADER, 1555 IPV6_FRAG => IpNumber::IPV6_FRAGMENTATION_HEADER, 1556 AUTH => IpNumber::AUTHENTICATION_HEADER, 1557 _ => unreachable!(), 1558 } 1559 } else { 1560 // rewrite start number in case it is just one extension header 1561 let missing = self.ip_numbers[0]; 1562 self.ip_numbers[0] = new_header; 1563 match missing { 1564 IPV6_HOP_BY_HOP => IpNumber::IPV6_HEADER_HOP_BY_HOP, 1565 IPV6_DEST_OPTIONS => IpNumber::IPV6_DESTINATION_OPTIONS, 1566 IPV6_ROUTE => IpNumber::IPV6_ROUTE_HEADER, 1567 IPV6_FRAG => IpNumber::IPV6_FRAGMENTATION_HEADER, 1568 AUTH => IpNumber::AUTHENTICATION_HEADER, 1569 _ => unreachable!(), 1570 } 1571 } 1572 } 1573 add_payload( &mut self, ip_number: IpNumber, next_header: IpNumber, header_ext_len: u8, ) -> bool1574 fn add_payload( 1575 &mut self, 1576 ip_number: IpNumber, 1577 next_header: IpNumber, 1578 header_ext_len: u8, 1579 ) -> bool { 1580 match ip_number { 1581 IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS => { 1582 use Ipv6RawExtHeader as R; 1583 let payload: [u8; R::MAX_PAYLOAD_LEN] = [0; R::MAX_PAYLOAD_LEN]; 1584 let len = usize::from(header_ext_len) * 8 + 6; 1585 1586 let raw = Ipv6RawExtHeader::new_raw(next_header, &payload[..len]).unwrap(); 1587 match ip_number { 1588 IPV6_HOP_BY_HOP => { 1589 if self.data.hop_by_hop_options.is_none() { 1590 self.data.hop_by_hop_options = Some(raw); 1591 true 1592 } else { 1593 false 1594 } 1595 } 1596 IPV6_ROUTE => { 1597 if self.data.routing.is_none() { 1598 self.data.routing = Some(Ipv6RoutingExtensions { 1599 routing: raw, 1600 final_destination_options: None, 1601 }); 1602 true 1603 } else { 1604 false 1605 } 1606 } 1607 IPV6_DEST_OPTIONS => { 1608 if let Some(ref mut route) = self.data.routing { 1609 if route.final_destination_options.is_none() { 1610 route.final_destination_options = Some(raw); 1611 true 1612 } else { 1613 false 1614 } 1615 } else { 1616 // dest option 1617 if self.data.destination_options.is_none() { 1618 self.data.destination_options = Some(raw); 1619 true 1620 } else { 1621 false 1622 } 1623 } 1624 } 1625 _ => unreachable!(), 1626 } 1627 } 1628 IPV6_FRAG => { 1629 if self.data.fragment.is_none() { 1630 self.data.fragment = Some(Ipv6FragmentHeader::new( 1631 next_header, 1632 IpFragOffset::ZERO, 1633 true, 1634 123, 1635 )); 1636 true 1637 } else { 1638 false 1639 } 1640 } 1641 AUTH => { 1642 if self.data.auth.is_none() { 1643 use IpAuthHeader as A; 1644 1645 let mut len = usize::from(header_ext_len) * 4; 1646 if len > A::MAX_ICV_LEN { 1647 len = A::MAX_ICV_LEN; 1648 } 1649 let raw_icv: [u8; A::MAX_ICV_LEN] = [0; A::MAX_ICV_LEN]; 1650 self.data.auth = Some( 1651 IpAuthHeader::new(next_header, 123, 234, &raw_icv[..len]).unwrap(), 1652 ); 1653 true 1654 } else { 1655 false 1656 } 1657 } 1658 _ => unreachable!(), 1659 } 1660 } 1661 } 1662 } 1663 1664 #[cfg(test)] 1665 mod test { 1666 use super::ipv6_exts_test_helpers::*; 1667 use super::*; 1668 use crate::ip_number::*; 1669 use crate::test_gens::*; 1670 use alloc::{borrow::ToOwned, vec::Vec}; 1671 use proptest::prelude::*; 1672 1673 proptest! { 1674 #[test] 1675 fn from_slice( 1676 header_size in any::<u8>(), 1677 post_header in ip_number_any() 1678 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(), 1679 |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x) 1680 ) 1681 ) { 1682 use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*}; 1683 1684 // no extension headers filled 1685 { 1686 let some_data = [1,2,3,4]; 1687 let actual = Ipv6Extensions::from_slice(post_header, &some_data).unwrap(); 1688 assert_eq!(actual.0, Default::default()); 1689 assert_eq!(actual.1, post_header); 1690 assert_eq!(actual.2, &some_data); 1691 } 1692 1693 /// Run a test with the given ip numbers 1694 fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) { 1695 // setup test payload 1696 let e = ExtensionTestPayload::new( 1697 ip_numbers, 1698 header_sizes 1699 ); 1700 1701 if e.exts_hop_by_hop_error() { 1702 // a hop by hop header that is not at the start triggers an error 1703 assert_eq!( 1704 Ipv6Extensions::from_slice(ip_numbers[0], e.slice()).unwrap_err(), 1705 Content(HopByHopNotAtStart) 1706 ); 1707 } else { 1708 // normal read 1709 let (header, next, rest) = Ipv6Extensions::from_slice(ip_numbers[0], e.slice()).unwrap(); 1710 let (read_len, last_header, expected_post_header) = e.assert_extensions(&header); 1711 assert_eq!(next, expected_post_header); 1712 assert_eq!(rest, &e.slice()[read_len..]); 1713 1714 // unexpected end of slice 1715 { 1716 let mut offset: usize = 0; 1717 for l in &e.lengths { 1718 if offset + l >= read_len { 1719 break; 1720 } 1721 offset += l; 1722 } 1723 1724 assert_eq!( 1725 Ipv6Extensions::from_slice(ip_numbers[0], &e.slice()[..read_len - 1]).unwrap_err(), 1726 Len(err::LenError { 1727 required_len: read_len - offset, 1728 len: read_len - offset - 1, 1729 len_source: LenSource::Slice, 1730 layer: match last_header.unwrap() { 1731 AUTH => err::Layer::IpAuthHeader, 1732 IPV6_FRAG => err::Layer::Ipv6FragHeader, 1733 _ => err::Layer::Ipv6ExtHeader 1734 }, 1735 layer_start_offset: offset, 1736 }) 1737 ); 1738 } 1739 } 1740 } 1741 1742 // test the parsing of different extension header combinations 1743 for first_header in &EXTENSION_KNOWN_IP_NUMBERS { 1744 1745 // single header parsing 1746 run_test( 1747 &[*first_header, post_header], 1748 &[header_size], 1749 ); 1750 1751 for second_header in &EXTENSION_KNOWN_IP_NUMBERS { 1752 1753 // double header parsing 1754 run_test( 1755 &[*first_header, *second_header, post_header], 1756 &[header_size], 1757 ); 1758 1759 for third_header in &EXTENSION_KNOWN_IP_NUMBERS { 1760 // tripple header parsing 1761 run_test( 1762 &[*first_header, *second_header, *third_header, post_header], 1763 &[header_size], 1764 ); 1765 } 1766 } 1767 } 1768 1769 // test that the auth content error gets forwarded 1770 { 1771 let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap(); 1772 let mut bytes = auth.to_bytes(); 1773 // inject an invalid len value 1774 bytes[1] = 0; 1775 let actual = Ipv6Extensions::from_slice(AUTH, &bytes).unwrap_err(); 1776 1777 use err::ipv6_exts::HeaderError::IpAuth; 1778 use err::ip_auth::HeaderError::ZeroPayloadLen; 1779 assert_eq!(actual, Content(IpAuth(ZeroPayloadLen))); 1780 } 1781 } 1782 } 1783 1784 proptest! { 1785 #[test] 1786 fn from_slice_lax( 1787 header_size in any::<u8>(), 1788 post_header in ip_number_any() 1789 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(), 1790 |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x) 1791 ) 1792 ) { 1793 use err::ipv6_exts::{HeaderError::*, HeaderSliceError::*}; 1794 1795 // no extension headers filled 1796 { 1797 let some_data = [1,2,3,4]; 1798 let actual = Ipv6Extensions::from_slice_lax(post_header, &some_data); 1799 assert_eq!(actual.0, Default::default()); 1800 assert_eq!(actual.1, post_header); 1801 assert_eq!(actual.2, &some_data); 1802 assert!(actual.3.is_none()); 1803 } 1804 1805 /// Run a test with the given ip numbers 1806 fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) { 1807 // setup test payload 1808 let e = ExtensionTestPayload::new( 1809 ip_numbers, 1810 header_sizes 1811 ); 1812 1813 if e.exts_hop_by_hop_error() { 1814 // a hop by hop header that is not at the start triggers an error 1815 let actual = Ipv6Extensions::from_slice_lax(ip_numbers[0], e.slice()); 1816 assert_eq!(actual.3.unwrap(), (Content(HopByHopNotAtStart), Layer::Ipv6HopByHopHeader)); 1817 } else { 1818 // normal read 1819 let norm_actual = Ipv6Extensions::from_slice_lax(ip_numbers[0], e.slice()); 1820 let norm_expected = e.lax_extensions_for_len(e.slice().len()); 1821 assert_eq!(norm_actual.0, norm_expected.0); 1822 assert_eq!(norm_actual.1, norm_expected.1); 1823 assert_eq!(norm_actual.2, norm_expected.2); 1824 assert!(norm_actual.3.is_none()); 1825 1826 // unexpected end of slice 1827 if norm_actual.0.header_len() > 0 { 1828 1829 let norm_len = norm_actual.0.header_len(); 1830 let actual = Ipv6Extensions::from_slice_lax(ip_numbers[0], &e.slice()[..norm_len - 1]); 1831 1832 let expected = e.lax_extensions_for_len(norm_len - 1); 1833 assert_eq!(actual.0, expected.0); 1834 assert_eq!(actual.1, expected.1); 1835 assert_eq!(actual.2, expected.2); 1836 let len_err = actual.3.unwrap().0.len_error().unwrap().clone(); 1837 assert_eq!(len_err.len, norm_len - 1 - expected.0.header_len()); 1838 assert_eq!(len_err.len_source, LenSource::Slice); 1839 assert_eq!( 1840 len_err.layer, 1841 match expected.3.unwrap() { 1842 AUTH => err::Layer::IpAuthHeader, 1843 IPV6_FRAG => err::Layer::Ipv6FragHeader, 1844 _ => err::Layer::Ipv6ExtHeader 1845 } 1846 ); 1847 assert_eq!(len_err.layer_start_offset, expected.0.header_len()); 1848 } 1849 } 1850 } 1851 1852 // test the parsing of different extension header combinations 1853 for first_header in &EXTENSION_KNOWN_IP_NUMBERS { 1854 1855 // single header parsing 1856 run_test( 1857 &[*first_header, post_header], 1858 &[header_size], 1859 ); 1860 1861 for second_header in &EXTENSION_KNOWN_IP_NUMBERS { 1862 1863 // double header parsing 1864 run_test( 1865 &[*first_header, *second_header, post_header], 1866 &[header_size], 1867 ); 1868 1869 for third_header in &EXTENSION_KNOWN_IP_NUMBERS { 1870 // tripple header parsing 1871 run_test( 1872 &[*first_header, *second_header, *third_header, post_header], 1873 &[header_size], 1874 ); 1875 } 1876 } 1877 } 1878 1879 // test that the auth content error gets forwarded 1880 { 1881 let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap(); 1882 let mut bytes = auth.to_bytes(); 1883 // inject an invalid len value 1884 bytes[1] = 0; 1885 let actual = Ipv6Extensions::from_slice_lax(AUTH, &bytes); 1886 assert_eq!(0, actual.0.header_len()); 1887 assert_eq!(AUTH, actual.1); 1888 assert_eq!(&bytes[..], actual.2); 1889 1890 use err::ipv6_exts::HeaderError::IpAuth; 1891 use err::ip_auth::HeaderError::ZeroPayloadLen; 1892 assert_eq!(actual.3.unwrap(), (Content(IpAuth(ZeroPayloadLen)), Layer::IpAuthHeader)); 1893 } 1894 } 1895 } 1896 1897 proptest! { 1898 #[test] 1899 fn read( 1900 header_size in any::<u8>(), 1901 post_header in ip_number_any() 1902 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(), 1903 |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x) 1904 ) 1905 ) { 1906 use err::ipv6_exts::HeaderError::*; 1907 use std::io::Cursor; 1908 1909 // no extension headers filled 1910 { 1911 let mut cursor = Cursor::new(&[]); 1912 let actual = Ipv6Extensions::read(&mut cursor, post_header).unwrap(); 1913 assert_eq!(actual.0, Default::default()); 1914 assert_eq!(actual.1, post_header); 1915 assert_eq!(0, cursor.position()); 1916 } 1917 1918 /// Run a test with the given ip numbers 1919 fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) { 1920 // setup test payload 1921 let e = ExtensionTestPayload::new( 1922 ip_numbers, 1923 header_sizes 1924 ); 1925 let mut cursor = Cursor::new(e.slice()); 1926 1927 if e.exts_hop_by_hop_error() { 1928 // a hop by hop header that is not at the start triggers an error 1929 assert_eq!( 1930 Ipv6Extensions::read(&mut cursor, ip_numbers[0]).unwrap_err().content_error().unwrap(), 1931 HopByHopNotAtStart 1932 ); 1933 } else { 1934 // normal read 1935 let (header, next) = Ipv6Extensions::read(&mut cursor, ip_numbers[0]).unwrap(); 1936 let (read_len, _, expected_post_header) = e.assert_extensions(&header); 1937 assert_eq!(next, expected_post_header); 1938 assert_eq!(cursor.position() as usize, read_len); 1939 1940 // unexpected end of slice 1941 { 1942 let mut short_cursor = Cursor::new(&e.slice()[..read_len - 1]); 1943 assert!( 1944 Ipv6Extensions::read(&mut short_cursor, ip_numbers[0]) 1945 .unwrap_err() 1946 .io_error() 1947 .is_some() 1948 ); 1949 } 1950 } 1951 } 1952 1953 // test the parsing of different extension header combinations 1954 for first_header in &EXTENSION_KNOWN_IP_NUMBERS { 1955 1956 // single header parsing 1957 run_test( 1958 &[*first_header, post_header], 1959 &[header_size], 1960 ); 1961 1962 for second_header in &EXTENSION_KNOWN_IP_NUMBERS { 1963 1964 // double header parsing 1965 run_test( 1966 &[*first_header, *second_header, post_header], 1967 &[header_size], 1968 ); 1969 1970 for third_header in &EXTENSION_KNOWN_IP_NUMBERS { 1971 // tripple header parsing 1972 run_test( 1973 &[*first_header, *second_header, *third_header, post_header], 1974 &[header_size], 1975 ); 1976 } 1977 } 1978 } 1979 1980 // test that the auth content error gets forwarded 1981 { 1982 let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap(); 1983 let mut bytes = auth.to_bytes(); 1984 // inject an invalid len value 1985 bytes[1] = 0; 1986 let mut cursor = Cursor::new(&bytes[..]); 1987 let actual = Ipv6Extensions::read(&mut cursor, AUTH).unwrap_err(); 1988 1989 use err::ipv6_exts::HeaderError::IpAuth; 1990 use err::ip_auth::HeaderError::ZeroPayloadLen; 1991 assert_eq!(actual.content_error().unwrap(), IpAuth(ZeroPayloadLen)); 1992 } 1993 } 1994 } 1995 1996 proptest! { 1997 #[test] 1998 fn read_limited( 1999 header_size in any::<u8>(), 2000 post_header in ip_number_any() 2001 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(), 2002 |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x) 2003 ) 2004 ) { 2005 use err::ipv6_exts::HeaderError::*; 2006 use err::Layer; 2007 use std::io::Cursor; 2008 use crate::io::LimitedReader; 2009 2010 // no extension headers filled 2011 { 2012 let mut reader = LimitedReader::new( 2013 Cursor::new(&[]), 2014 0, 2015 LenSource::Slice, 2016 0, 2017 Layer::Ipv6Header 2018 ); 2019 let actual = Ipv6Extensions::read_limited(&mut reader, post_header).unwrap(); 2020 assert_eq!(actual.0, Default::default()); 2021 assert_eq!(actual.1, post_header); 2022 assert_eq!(0, reader.read_len()); 2023 } 2024 2025 /// Run a test with the given ip numbers 2026 fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8]) { 2027 // setup test payload 2028 let e = ExtensionTestPayload::new( 2029 ip_numbers, 2030 header_sizes 2031 ); 2032 let mut reader = LimitedReader::new( 2033 Cursor::new(e.slice()), 2034 e.slice().len(), 2035 LenSource::Slice, 2036 0, 2037 Layer::Ipv6Header 2038 ); 2039 2040 if e.exts_hop_by_hop_error() { 2041 // a hop by hop header that is not at the start triggers an error 2042 assert_eq!( 2043 Ipv6Extensions::read_limited(&mut reader, ip_numbers[0]).unwrap_err().content().unwrap(), 2044 HopByHopNotAtStart 2045 ); 2046 } else { 2047 // normal read 2048 let (header, next) = Ipv6Extensions::read_limited(&mut reader, ip_numbers[0]).unwrap(); 2049 let (read_len, _, expected_post_header) = e.assert_extensions(&header); 2050 assert_eq!(next, expected_post_header); 2051 assert_eq!(reader.read_len() + reader.layer_offset(), read_len); 2052 2053 // io error unexpected end 2054 { 2055 let mut short_reader = LimitedReader::new( 2056 Cursor::new(&e.slice()[..read_len - 1]), 2057 read_len, 2058 LenSource::Slice, 2059 0, 2060 Layer::Ipv6Header 2061 ); 2062 2063 assert!( 2064 Ipv6Extensions::read_limited(&mut short_reader, ip_numbers[0]) 2065 .unwrap_err() 2066 .io() 2067 .is_some() 2068 ); 2069 } 2070 2071 // len error 2072 { 2073 let mut short_reader = LimitedReader::new( 2074 Cursor::new(e.slice()), 2075 read_len - 1, 2076 LenSource::Slice, 2077 0, 2078 Layer::Ipv6Header 2079 ); 2080 2081 assert!( 2082 Ipv6Extensions::read_limited(&mut short_reader, ip_numbers[0]) 2083 .unwrap_err() 2084 .len() 2085 .is_some() 2086 ); 2087 } 2088 } 2089 } 2090 2091 // test the parsing of different extension header combinations 2092 for first_header in &EXTENSION_KNOWN_IP_NUMBERS { 2093 2094 // single header parsing 2095 run_test( 2096 &[*first_header, post_header], 2097 &[header_size], 2098 ); 2099 2100 for second_header in &EXTENSION_KNOWN_IP_NUMBERS { 2101 2102 // double header parsing 2103 run_test( 2104 &[*first_header, *second_header, post_header], 2105 &[header_size], 2106 ); 2107 2108 for third_header in &EXTENSION_KNOWN_IP_NUMBERS { 2109 // tripple header parsing 2110 run_test( 2111 &[*first_header, *second_header, *third_header, post_header], 2112 &[header_size], 2113 ); 2114 } 2115 } 2116 } 2117 2118 // test that the auth content error gets forwarded 2119 { 2120 let auth = IpAuthHeader::new(post_header, 0, 0, &[]).unwrap(); 2121 let mut bytes = auth.to_bytes(); 2122 // inject an invalid len value 2123 bytes[1] = 0; 2124 let mut reader = LimitedReader::new( 2125 Cursor::new(&bytes[..]), 2126 bytes.len(), 2127 LenSource::Slice, 2128 0, 2129 Layer::Ipv6Header 2130 ); 2131 let actual = Ipv6Extensions::read_limited(&mut reader, AUTH).unwrap_err(); 2132 2133 use err::ipv6_exts::HeaderError::IpAuth; 2134 use err::ip_auth::HeaderError::ZeroPayloadLen; 2135 assert_eq!(actual.content().unwrap(), IpAuth(ZeroPayloadLen)); 2136 } 2137 } 2138 } 2139 2140 proptest! { 2141 #[test] 2142 fn write( 2143 header_size in any::<u8>(), 2144 post_header in ip_number_any() 2145 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(), 2146 |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x) 2147 ) 2148 ) { 2149 // no extension headers filled 2150 { 2151 let exts : Ipv6Extensions = Default::default(); 2152 let mut buffer = Vec::new(); 2153 exts.write(&mut buffer, post_header).unwrap(); 2154 assert_eq!(0, buffer.len()); 2155 } 2156 2157 /// Run a test with the given ip numbers 2158 fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8], post_header: IpNumber) { 2159 use std::io::Cursor; 2160 use crate::err::ipv6_exts::ExtsWalkError::*; 2161 2162 // setup test header 2163 let e = ExtensionTestHeaders::new( 2164 ip_numbers, 2165 header_sizes 2166 ); 2167 2168 if e.ip_numbers[1..e.ip_numbers.len()-1].iter().any(|&x| x == IPV6_HOP_BY_HOP) { 2169 // a hop by hop header that is not at the start triggers an error 2170 let mut writer = Vec::with_capacity(e.data.header_len()); 2171 assert_eq!( 2172 e.data.write(&mut writer, e.ip_numbers[0]).unwrap_err().content().unwrap(), 2173 &HopByHopNotAtStart 2174 ); 2175 } else { 2176 // normal write 2177 { 2178 let mut writer = Vec::with_capacity(e.data.header_len()); 2179 e.data.write(&mut writer, e.ip_numbers[0]).unwrap(); 2180 2181 if *e.ip_numbers.last().unwrap() != IPV6_HOP_BY_HOP { 2182 // decoding if there will be no duplicate hop by hop error 2183 // will be triggered 2184 let (read, read_next, _) = Ipv6Extensions::from_slice( 2185 e.ip_numbers[0], 2186 &writer 2187 ).unwrap(); 2188 assert_eq!(e.data, read); 2189 assert_eq!(*e.ip_numbers.last().unwrap(), read_next); 2190 } 2191 } 2192 2193 // write error 2194 { 2195 let mut buffer = Vec::with_capacity(e.data.header_len() - 1); 2196 buffer.resize(e.data.header_len() - 1, 0); 2197 let mut cursor = Cursor::new(&mut buffer[..]); 2198 2199 let err = e.data.write( 2200 &mut cursor, 2201 e.ip_numbers[0] 2202 ).unwrap_err(); 2203 2204 assert!(err.io().is_some()); 2205 } 2206 2207 // missing reference (skip the last header) 2208 { 2209 use crate::err::ipv6_exts::ExtsWalkError::ExtNotReferenced; 2210 2211 let mut missing_ref = e.clone(); 2212 let missing_ext = missing_ref.introduce_missing_ref(post_header); 2213 2214 let mut writer = Vec::with_capacity(e.data.header_len()); 2215 let err = missing_ref.data.write( 2216 &mut writer, 2217 missing_ref.ip_numbers[0] 2218 ).unwrap_err(); 2219 2220 assert_eq!( 2221 err.content().unwrap(), 2222 &ExtNotReferenced{ missing_ext } 2223 ); 2224 } 2225 } 2226 } 2227 2228 // test the parsing of different extension header combinations 2229 for first_header in &EXTENSION_KNOWN_IP_NUMBERS { 2230 2231 // single header parsing 2232 run_test( 2233 &[*first_header, post_header], 2234 &[header_size], 2235 post_header, 2236 ); 2237 2238 for second_header in &EXTENSION_KNOWN_IP_NUMBERS { 2239 2240 // double header parsing 2241 run_test( 2242 &[*first_header, *second_header, post_header], 2243 &[header_size], 2244 post_header, 2245 ); 2246 2247 for third_header in &EXTENSION_KNOWN_IP_NUMBERS { 2248 // tripple header parsing 2249 run_test( 2250 &[*first_header, *second_header, *third_header, post_header], 2251 &[header_size], 2252 post_header, 2253 ); 2254 } 2255 } 2256 } 2257 } 2258 } 2259 2260 proptest! { 2261 #[test] 2262 fn header_len( 2263 hop_by_hop_options in ipv6_raw_ext_any(), 2264 destination_options in ipv6_raw_ext_any(), 2265 routing in ipv6_raw_ext_any(), 2266 fragment in ipv6_fragment_any(), 2267 auth in ip_auth_any(), 2268 final_destination_options in ipv6_raw_ext_any(), 2269 ) { 2270 // None 2271 { 2272 let exts : Ipv6Extensions = Default::default(); 2273 assert_eq!(0, exts.header_len()); 2274 } 2275 2276 // All filled 2277 { 2278 let exts = Ipv6Extensions{ 2279 hop_by_hop_options: Some(hop_by_hop_options.clone()), 2280 destination_options: Some(destination_options.clone()), 2281 routing: Some( 2282 Ipv6RoutingExtensions{ 2283 routing: routing.clone(), 2284 final_destination_options: Some(final_destination_options.clone()), 2285 } 2286 ), 2287 fragment: Some(fragment.clone()), 2288 auth: Some(auth.clone()), 2289 }; 2290 assert_eq!( 2291 exts.header_len(), 2292 ( 2293 hop_by_hop_options.header_len() + 2294 destination_options.header_len() + 2295 routing.header_len() + 2296 final_destination_options.header_len() + 2297 fragment.header_len() + 2298 auth.header_len() 2299 ) 2300 ); 2301 } 2302 2303 // Routing without final destination options 2304 { 2305 let exts = Ipv6Extensions{ 2306 hop_by_hop_options: Some(hop_by_hop_options.clone()), 2307 destination_options: Some(destination_options.clone()), 2308 routing: Some( 2309 Ipv6RoutingExtensions{ 2310 routing: routing.clone(), 2311 final_destination_options: None, 2312 } 2313 ), 2314 fragment: Some(fragment.clone()), 2315 auth: Some(auth.clone()), 2316 }; 2317 assert_eq!( 2318 exts.header_len(), 2319 ( 2320 hop_by_hop_options.header_len() + 2321 destination_options.header_len() + 2322 routing.header_len() + 2323 fragment.header_len() + 2324 auth.header_len() 2325 ) 2326 ); 2327 } 2328 } 2329 } 2330 2331 proptest! { 2332 #[test] 2333 fn set_next_headers( 2334 hop_by_hop_options in ipv6_raw_ext_any(), 2335 destination_options in ipv6_raw_ext_any(), 2336 routing in ipv6_raw_ext_any(), 2337 fragment in ipv6_fragment_any(), 2338 auth in ip_auth_any(), 2339 final_destination_options in ipv6_raw_ext_any(), 2340 post_header in ip_number_any() 2341 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(), 2342 |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x) 2343 ), 2344 ) { 2345 // none filled 2346 { 2347 let mut exts : Ipv6Extensions = Default::default(); 2348 assert_eq!(post_header, exts.set_next_headers(post_header)); 2349 assert!(exts.hop_by_hop_options.is_none()); 2350 assert!(exts.destination_options.is_none()); 2351 assert!(exts.routing.is_none()); 2352 assert!(exts.fragment.is_none()); 2353 assert!(exts.auth.is_none()); 2354 } 2355 2356 // all filled 2357 { 2358 let mut exts = Ipv6Extensions{ 2359 hop_by_hop_options: Some(hop_by_hop_options.clone()), 2360 destination_options: Some(destination_options.clone()), 2361 routing: Some( 2362 Ipv6RoutingExtensions{ 2363 routing: routing.clone(), 2364 final_destination_options: Some(final_destination_options.clone()), 2365 } 2366 ), 2367 fragment: Some(fragment.clone()), 2368 auth: Some(auth.clone()), 2369 }; 2370 assert_eq!(IPV6_HOP_BY_HOP, exts.set_next_headers(post_header)); 2371 2372 assert_eq!(IPV6_DEST_OPTIONS, exts.hop_by_hop_options.as_ref().unwrap().next_header); 2373 assert_eq!(IPV6_ROUTE, exts.destination_options.as_ref().unwrap().next_header); 2374 assert_eq!(IPV6_FRAG, exts.routing.as_ref().unwrap().routing.next_header); 2375 assert_eq!(AUTH, exts.fragment.as_ref().unwrap().next_header); 2376 assert_eq!(IPV6_DEST_OPTIONS, exts.auth.as_ref().unwrap().next_header); 2377 assert_eq!(post_header, exts.routing.as_ref().unwrap().final_destination_options.as_ref().unwrap().next_header); 2378 } 2379 } 2380 } 2381 2382 proptest! { 2383 #[test] 2384 fn next_header( 2385 header_size in any::<u8>(), 2386 post_header in ip_number_any() 2387 .prop_filter("Must be a non ipv6 header relevant ip number".to_owned(), 2388 |v| !EXTENSION_KNOWN_IP_NUMBERS.iter().any(|&x| v == &x) 2389 ),) 2390 { 2391 // test empty 2392 { 2393 let exts : Ipv6Extensions = Default::default(); 2394 assert_eq!(post_header, exts.next_header(post_header).unwrap()); 2395 } 2396 2397 /// Run a test with the given ip numbers 2398 fn run_test(ip_numbers: &[IpNumber], header_sizes: &[u8], post_header: IpNumber) { 2399 // setup test header 2400 let e = ExtensionTestHeaders::new( 2401 ip_numbers, 2402 header_sizes 2403 ); 2404 2405 if e.ip_numbers[1..e.ip_numbers.len()-1].iter().any(|&x| x == IPV6_HOP_BY_HOP) { 2406 // a hop by hop header that is not at the start triggers an error 2407 use crate::err::ipv6_exts::ExtsWalkError::HopByHopNotAtStart; 2408 assert_eq!( 2409 e.data.next_header(e.ip_numbers[0]).unwrap_err(), 2410 HopByHopNotAtStart 2411 ); 2412 } else { 2413 // normal header 2414 assert_eq!( 2415 *e.ip_numbers.last().unwrap(), 2416 e.data.next_header(e.ip_numbers[0]).unwrap() 2417 ); 2418 2419 // missing reference (skip the last header) 2420 { 2421 use crate::err::ipv6_exts::ExtsWalkError::ExtNotReferenced; 2422 2423 let mut missing_ref = e.clone(); 2424 let missing_ext = missing_ref.introduce_missing_ref(post_header); 2425 assert_eq!( 2426 missing_ref.data.next_header(missing_ref.ip_numbers[0]).unwrap_err(), 2427 ExtNotReferenced{ missing_ext } 2428 ); 2429 } 2430 } 2431 } 2432 2433 // test the parsing of different extension header combinations 2434 for first_header in &EXTENSION_KNOWN_IP_NUMBERS { 2435 2436 // single header parsing 2437 run_test( 2438 &[*first_header, post_header], 2439 &[header_size], 2440 post_header, 2441 ); 2442 2443 for second_header in &EXTENSION_KNOWN_IP_NUMBERS { 2444 2445 // double header parsing 2446 run_test( 2447 &[*first_header, *second_header, post_header], 2448 &[header_size], 2449 post_header, 2450 ); 2451 2452 for third_header in &EXTENSION_KNOWN_IP_NUMBERS { 2453 // tripple header parsing 2454 run_test( 2455 &[*first_header, *second_header, *third_header, post_header], 2456 &[header_size], 2457 post_header, 2458 ); 2459 } 2460 } 2461 } 2462 } 2463 } 2464 2465 #[test] is_fragmenting_payload()2466 fn is_fragmenting_payload() { 2467 // empty 2468 assert_eq!( 2469 false, 2470 Ipv6Extensions { 2471 hop_by_hop_options: None, 2472 destination_options: None, 2473 routing: None, 2474 fragment: None, 2475 auth: None, 2476 } 2477 .is_fragmenting_payload() 2478 ); 2479 2480 // non fragmenting frag header 2481 assert_eq!( 2482 false, 2483 Ipv6Extensions { 2484 hop_by_hop_options: None, 2485 destination_options: None, 2486 routing: None, 2487 fragment: Some(Ipv6FragmentHeader::new( 2488 ip_number::UDP, 2489 IpFragOffset::ZERO, 2490 false, 2491 0 2492 )), 2493 auth: None, 2494 } 2495 .is_fragmenting_payload() 2496 ); 2497 2498 // fragmenting frag header 2499 assert!(Ipv6Extensions { 2500 hop_by_hop_options: None, 2501 destination_options: None, 2502 routing: None, 2503 fragment: Some(Ipv6FragmentHeader::new( 2504 ip_number::UDP, 2505 IpFragOffset::ZERO, 2506 true, 2507 0 2508 )), 2509 auth: None, 2510 } 2511 .is_fragmenting_payload()); 2512 } 2513 2514 #[test] is_empty()2515 fn is_empty() { 2516 // empty 2517 assert!(Ipv6Extensions { 2518 hop_by_hop_options: None, 2519 destination_options: None, 2520 routing: None, 2521 fragment: None, 2522 auth: None, 2523 } 2524 .is_empty()); 2525 2526 // hop_by_hop_options 2527 assert_eq!( 2528 false, 2529 Ipv6Extensions { 2530 hop_by_hop_options: Some( 2531 Ipv6RawExtHeader::new_raw(ip_number::UDP, &[1, 2, 3, 4, 5, 6]).unwrap() 2532 ), 2533 destination_options: None, 2534 routing: None, 2535 fragment: None, 2536 auth: None, 2537 } 2538 .is_empty() 2539 ); 2540 2541 // destination_options 2542 assert_eq!( 2543 false, 2544 Ipv6Extensions { 2545 hop_by_hop_options: None, 2546 destination_options: Some( 2547 Ipv6RawExtHeader::new_raw(ip_number::UDP, &[1, 2, 3, 4, 5, 6]).unwrap() 2548 ), 2549 routing: None, 2550 fragment: None, 2551 auth: None, 2552 } 2553 .is_empty() 2554 ); 2555 2556 // routing 2557 assert_eq!( 2558 false, 2559 Ipv6Extensions { 2560 hop_by_hop_options: None, 2561 destination_options: None, 2562 routing: Some(Ipv6RoutingExtensions { 2563 routing: Ipv6RawExtHeader::new_raw(ip_number::UDP, &[1, 2, 3, 4, 5, 6]) 2564 .unwrap(), 2565 final_destination_options: None, 2566 }), 2567 fragment: None, 2568 auth: None, 2569 } 2570 .is_empty() 2571 ); 2572 2573 // fragment 2574 assert_eq!( 2575 false, 2576 Ipv6Extensions { 2577 hop_by_hop_options: None, 2578 destination_options: None, 2579 routing: None, 2580 fragment: Some(Ipv6FragmentHeader::new( 2581 ip_number::UDP, 2582 IpFragOffset::ZERO, 2583 true, 2584 0 2585 )), 2586 auth: None, 2587 } 2588 .is_empty() 2589 ); 2590 2591 // auth 2592 assert_eq!( 2593 false, 2594 Ipv6Extensions { 2595 hop_by_hop_options: None, 2596 destination_options: None, 2597 routing: None, 2598 fragment: None, 2599 auth: Some(IpAuthHeader::new(ip_number::UDP, 0, 0, &[]).unwrap()), 2600 } 2601 .is_empty() 2602 ); 2603 } 2604 2605 #[test] debug()2606 fn debug() { 2607 use alloc::format; 2608 2609 let a: Ipv6Extensions = Default::default(); 2610 assert_eq!( 2611 &format!( 2612 "Ipv6Extensions {{ hop_by_hop_options: {:?}, destination_options: {:?}, routing: {:?}, fragment: {:?}, auth: {:?} }}", 2613 a.hop_by_hop_options, 2614 a.destination_options, 2615 a.routing, 2616 a.fragment, 2617 a.auth, 2618 ), 2619 &format!("{:?}", a) 2620 ); 2621 } 2622 2623 #[test] clone_eq()2624 fn clone_eq() { 2625 let a: Ipv6Extensions = Default::default(); 2626 assert_eq!(a, a.clone()); 2627 } 2628 2629 #[test] default()2630 fn default() { 2631 let a: Ipv6Extensions = Default::default(); 2632 assert_eq!(a.hop_by_hop_options, None); 2633 assert_eq!(a.destination_options, None); 2634 assert_eq!(a.routing, None); 2635 assert_eq!(a.fragment, None); 2636 assert_eq!(a.auth, None); 2637 } 2638 } 2639