1 use crate::{err::ValueTooBigError, *}; 2 3 /// IPv6 header according to rfc8200. 4 #[derive(Clone, Debug, Eq, PartialEq, Default)] 5 pub struct Ipv6Header { 6 pub traffic_class: u8, 7 /// If non 0 serves as a hint to router and switches with multiple outbound paths that these packets should stay on the same path, so that they will not be reordered. 8 pub flow_label: Ipv6FlowLabel, 9 ///The length of the payload and extension headers in bytes (0 in case of jumbo payloads). 10 pub payload_length: u16, 11 /// IP protocol number specifying the next header or transport layer protocol. 12 /// 13 /// See [IpNumber] or [ip_number] for a definitions of ids. 14 pub next_header: IpNumber, 15 /// The number of hops the packet can take before it is discarded. 16 pub hop_limit: u8, 17 /// IPv6 source address 18 pub source: [u8; 16], 19 /// IPv6 destination address 20 pub destination: [u8; 16], 21 } 22 23 impl Ipv6Header { 24 /// Serialized size of an IPv6 header in bytes/octets. 25 pub const LEN: usize = 40; 26 27 #[deprecated(since = "0.14.0", note = "Use `Ipv6Header::LEN` instead")] 28 pub const SERIALIZED_SIZE: usize = Ipv6Header::LEN; 29 30 /// Renamed to `Ipv6Header::from_slice` 31 #[deprecated(since = "0.10.1", note = "Renamed to `Ipv6Header::from_slice`")] 32 #[inline] read_from_slice( slice: &[u8], ) -> Result<(Ipv6Header, &[u8]), err::ipv6::HeaderSliceError>33 pub fn read_from_slice( 34 slice: &[u8], 35 ) -> Result<(Ipv6Header, &[u8]), err::ipv6::HeaderSliceError> { 36 Ipv6Header::from_slice(slice) 37 } 38 39 /// Read an Ipv6Header from a slice and return the header & unused parts of the slice. 40 /// 41 /// Note that this function DOES NOT seperate the payload based on the length 42 /// payload_length present in the IPv6 header. It just returns the left over slice 43 /// after the header. 44 /// 45 /// If you want to have correctly seperated payload including the IP extension 46 /// headers use 47 /// 48 /// * [`crate::IpHeaders::from_ipv6_slice`] (decodes all the fields of the IP headers) 49 /// * [`crate::Ipv6Slice::from_slice`] (just identifies the ranges in the slice where 50 /// the headers and payload are present) 51 /// 52 /// or 53 /// 54 /// * [`crate::IpHeaders::from_ipv6_slice_lax`] 55 /// * [`crate::Ipv6Slice::from_slice_lax`] 56 /// 57 /// for a laxer version which falls back to slice length when the `payload_length` 58 /// contains an inconsistent value. 59 #[inline] from_slice(slice: &[u8]) -> Result<(Ipv6Header, &[u8]), err::ipv6::HeaderSliceError>60 pub fn from_slice(slice: &[u8]) -> Result<(Ipv6Header, &[u8]), err::ipv6::HeaderSliceError> { 61 Ok(( 62 Ipv6HeaderSlice::from_slice(slice)?.to_header(), 63 &slice[Ipv6Header::LEN..], 64 )) 65 } 66 67 ///Reads an IPv6 header from the current position. 68 #[cfg(feature = "std")] 69 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] read<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, ) -> Result<Ipv6Header, err::ipv6::HeaderReadError>70 pub fn read<T: std::io::Read + std::io::Seek + Sized>( 71 reader: &mut T, 72 ) -> Result<Ipv6Header, err::ipv6::HeaderReadError> { 73 use err::ipv6::{HeaderError::*, HeaderReadError::*}; 74 75 let mut value: [u8; 1] = [0; 1]; 76 reader.read_exact(&mut value).map_err(Io)?; 77 let version_number = value[0] >> 4; 78 if 6 != version_number { 79 return Err(Content(UnexpectedVersion { version_number })); 80 } 81 Ipv6Header::read_without_version(reader, value[0] & 0xf).map_err(Io) 82 } 83 84 ///Reads an IPv6 header assuming the version & flow_label field have already been read. 85 #[cfg(feature = "std")] 86 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] read_without_version<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, version_rest: u8, ) -> Result<Ipv6Header, std::io::Error>87 pub fn read_without_version<T: std::io::Read + std::io::Seek + Sized>( 88 reader: &mut T, 89 version_rest: u8, 90 ) -> Result<Ipv6Header, std::io::Error> { 91 let mut buffer: [u8; 8 + 32 - 1] = [0; 8 + 32 - 1]; 92 reader.read_exact(&mut buffer[..])?; 93 94 Ok(Ipv6Header { 95 traffic_class: (version_rest << 4) | (buffer[0] >> 4), 96 flow_label: unsafe { 97 // SAFETY: Safe as the bitmask & 0 contant guarantee that the value 98 // does not exceed 20 bytes. 99 Ipv6FlowLabel::new_unchecked(u32::from_be_bytes([ 100 0, 101 buffer[0] & 0b0000_1111, 102 buffer[1], 103 buffer[2], 104 ])) 105 }, 106 payload_length: u16::from_be_bytes([buffer[3], buffer[4]]), 107 next_header: IpNumber(buffer[5]), 108 hop_limit: buffer[6], 109 #[rustfmt::skip] 110 source: [ 111 buffer[7], buffer[8], buffer[9], buffer[10], 112 buffer[11], buffer[12], buffer[13], buffer[14], 113 buffer[15], buffer[16], buffer[17], buffer[18], 114 buffer[19], buffer[20], buffer[21], buffer[22], 115 ], 116 #[rustfmt::skip] 117 destination: [ 118 buffer[23], buffer[24], buffer[25], buffer[26], 119 buffer[27], buffer[28], buffer[29], buffer[30], 120 buffer[31], buffer[32], buffer[33], buffer[34], 121 buffer[35], buffer[36], buffer[37], buffer[38], 122 ], 123 }) 124 } 125 126 ///Takes a slice and skips an ipv6 header extensions and returns the next_header ip number & the slice past the header. skip_header_extension_in_slice( slice: &[u8], next_header: IpNumber, ) -> Result<(IpNumber, &[u8]), err::LenError>127 pub fn skip_header_extension_in_slice( 128 slice: &[u8], 129 next_header: IpNumber, 130 ) -> Result<(IpNumber, &[u8]), err::LenError> { 131 use crate::ip_number::*; 132 133 // verify that a ipv6 extension is present (before 134 // validating the slice length) 135 match next_header { 136 IPV6_FRAG | AUTH | IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS | MOBILITY 137 | HIP | SHIM6 => {} 138 _ => { 139 return Ok((next_header, slice)); 140 } 141 } 142 143 if slice.len() >= 2 { 144 //determine the length 145 let len = match next_header { 146 IPV6_FRAG => 8, 147 AUTH => (usize::from(slice[1]) + 2) * 4, 148 IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS | MOBILITY | HIP | SHIM6 => { 149 (usize::from(slice[1]) + 1) * 8 150 } 151 // not a ipv6 header extension that can be skipped 152 _ => unreachable!(), 153 }; 154 155 if slice.len() < len { 156 Err(err::LenError { 157 required_len: len, 158 len: slice.len(), 159 len_source: LenSource::Slice, 160 layer: err::Layer::Ipv6ExtHeader, 161 layer_start_offset: 0, 162 }) 163 } else { 164 Ok((IpNumber(slice[0]), &slice[len..])) 165 } 166 } else { 167 Err(err::LenError { 168 required_len: 2, 169 len: slice.len(), 170 len_source: LenSource::Slice, 171 layer: err::Layer::Ipv6ExtHeader, 172 layer_start_offset: 0, 173 }) 174 } 175 } 176 177 /// Returns true if the given ip protocol number is a skippable header extension. 178 /// 179 /// A skippable header extension is an extension header for which it is known how 180 /// to determine the protocol number of the following header as well as how many 181 /// octets have to be skipped to reach the start of the following header. is_skippable_header_extension(ip_protocol_number: IpNumber) -> bool182 pub fn is_skippable_header_extension(ip_protocol_number: IpNumber) -> bool { 183 use crate::ip_number::*; 184 //Note: EncapsulatingSecurityPayload & ExperimentalAndTesting0 can not be skipped 185 matches!( 186 ip_protocol_number, 187 IPV6_HOP_BY_HOP 188 | IPV6_ROUTE 189 | IPV6_FRAG 190 | AUTH 191 | IPV6_DEST_OPTIONS 192 | MOBILITY 193 | HIP 194 | SHIM6 195 ) 196 } 197 198 ///Takes a slice & ip protocol number (identifying the first header type) and returns next_header id & the slice past after all ipv6 header extensions. skip_all_header_extensions_in_slice( slice: &[u8], next_header: IpNumber, ) -> Result<(IpNumber, &[u8]), err::LenError>199 pub fn skip_all_header_extensions_in_slice( 200 slice: &[u8], 201 next_header: IpNumber, 202 ) -> Result<(IpNumber, &[u8]), err::LenError> { 203 let mut next_header = next_header; 204 let mut rest = slice; 205 let mut offset = 0; 206 207 loop { 208 let (n_id, n_rest) = Ipv6Header::skip_header_extension_in_slice(rest, next_header) 209 .map_err(|err| err.add_offset(offset))?; 210 offset = slice.len() - n_rest.len(); 211 212 if n_rest.len() == rest.len() { 213 return Ok((next_header, rest)); 214 } else { 215 next_header = n_id; 216 rest = n_rest; 217 } 218 } 219 } 220 221 ///Skips the ipv6 header extension and returns the next ip protocol number 222 #[cfg(feature = "std")] 223 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] skip_header_extension<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, next_header: IpNumber, ) -> Result<IpNumber, std::io::Error>224 pub fn skip_header_extension<T: std::io::Read + std::io::Seek + Sized>( 225 reader: &mut T, 226 next_header: IpNumber, 227 ) -> Result<IpNumber, std::io::Error> { 228 use crate::ip_number::*; 229 230 let (next_header, rest_length) = match next_header { 231 IPV6_FRAG => { 232 let mut buf = [0; 1]; 233 reader.read_exact(&mut buf)?; 234 (IpNumber(buf[0]), 7) 235 } 236 AUTH => { 237 let mut buf = [0; 2]; 238 reader.read_exact(&mut buf)?; 239 (IpNumber(buf[0]), i64::from(buf[1]) * 4 + 6) 240 } 241 IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS | MOBILITY | HIP | SHIM6 => { 242 let mut buf = [0; 2]; 243 reader.read_exact(&mut buf)?; 244 (IpNumber(buf[0]), i64::from(buf[1]) * 8 + 6) 245 } 246 // not a ipv6 header extension that can be skipped 247 _ => return Ok(next_header), 248 }; 249 250 //Sadly seek does not return an error if the seek could not be fulfilled. 251 //Some implementations do not even truncate the returned position to the 252 //last valid one. std::io::Cursor for example just moves the position 253 //over the border of the given slice (e.g. returns position 15 even when 254 //the given slice contains only 1 element). 255 //The only option, to detect that we are in an invalid state, is to move the 256 //seek offset to one byte before the end and then execute a normal read to 257 //trigger an error. 258 reader.seek(std::io::SeekFrom::Current(rest_length - 1))?; 259 { 260 let mut buf = [0; 1]; 261 reader.read_exact(&mut buf)?; 262 } 263 Ok(next_header) 264 } 265 266 ///Skips all ipv6 header extensions and returns the next ip protocol number 267 #[cfg(feature = "std")] 268 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] skip_all_header_extensions<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, next_header: IpNumber, ) -> Result<IpNumber, std::io::Error>269 pub fn skip_all_header_extensions<T: std::io::Read + std::io::Seek + Sized>( 270 reader: &mut T, 271 next_header: IpNumber, 272 ) -> Result<IpNumber, std::io::Error> { 273 let mut next_header = next_header; 274 275 loop { 276 if Ipv6Header::is_skippable_header_extension(next_header) { 277 next_header = Ipv6Header::skip_header_extension(reader, next_header)?; 278 } else { 279 return Ok(next_header); 280 } 281 } 282 } 283 284 ///Writes a given IPv6 header to the current position. 285 #[cfg(feature = "std")] 286 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error>287 pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> { 288 writer.write_all(&self.to_bytes()) 289 } 290 291 /// Return the ipv6 source address as an std::net::Ipv6Addr 292 #[cfg(feature = "std")] 293 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 294 #[inline] source_addr(&self) -> std::net::Ipv6Addr295 pub fn source_addr(&self) -> std::net::Ipv6Addr { 296 std::net::Ipv6Addr::from(self.source) 297 } 298 299 /// Return the ipv6 destination address as an std::net::Ipv6Addr 300 #[cfg(feature = "std")] 301 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 302 #[inline] destination_addr(&self) -> std::net::Ipv6Addr303 pub fn destination_addr(&self) -> std::net::Ipv6Addr { 304 std::net::Ipv6Addr::from(self.destination) 305 } 306 307 /// Length of the serialized header in bytes. 308 /// 309 /// The function always returns the constant Ipv6Header::LEN 310 /// and exists to keep the methods consistent with other headers. 311 #[inline] header_len(&self) -> usize312 pub fn header_len(&self) -> usize { 313 Ipv6Header::LEN 314 } 315 316 /// Sets the field total_length based on the size of the payload and the options. Returns an error if the payload is too big to fit. set_payload_length(&mut self, size: usize) -> Result<(), ValueTooBigError<usize>>317 pub fn set_payload_length(&mut self, size: usize) -> Result<(), ValueTooBigError<usize>> { 318 use crate::err::ValueType; 319 // check that the total length fits into the field 320 const MAX_PAYLOAD_LENGTH: usize = u16::MAX as usize; 321 if MAX_PAYLOAD_LENGTH < size { 322 return Err(ValueTooBigError { 323 actual: size, 324 max_allowed: MAX_PAYLOAD_LENGTH, 325 value_type: ValueType::Ipv6PayloadLength, 326 }); 327 } 328 329 self.payload_length = size as u16; 330 Ok(()) 331 } 332 333 /// Returns the serialized form of the header as a statically 334 /// sized byte array. 335 #[rustfmt::skip] to_bytes(&self) -> [u8;Ipv6Header::LEN]336 pub fn to_bytes(&self) -> [u8;Ipv6Header::LEN] { 337 // serialize header 338 let flow_label_be = self.flow_label.value().to_be_bytes(); 339 let payload_len_be = self.payload_length.to_be_bytes(); 340 341 [ 342 (6 << 4) | (self.traffic_class >> 4), 343 (self.traffic_class << 4) | flow_label_be[1], 344 flow_label_be[2], 345 flow_label_be[3], 346 payload_len_be[0], 347 payload_len_be[1], 348 self.next_header.0, 349 self.hop_limit, 350 self.source[0], self.source[1], self.source[2], self.source[3], 351 self.source[4], self.source[5], self.source[6], self.source[7], 352 self.source[8], self.source[9], self.source[10], self.source[11], 353 self.source[12], self.source[13], self.source[14], self.source[15], 354 self.destination[0], self.destination[1], self.destination[2], self.destination[3], 355 self.destination[4], self.destination[5], self.destination[6], self.destination[7], 356 self.destination[8], self.destination[9], self.destination[10], self.destination[11], 357 self.destination[12], self.destination[13], self.destination[14], self.destination[15], 358 ] 359 } 360 } 361 362 #[cfg(test)] 363 mod test { 364 use crate::{ 365 err::ipv6::HeaderError::*, err::ipv6::HeaderSliceError::*, ip_number::*, test_gens::*, *, 366 }; 367 use alloc::format; 368 use arrayvec::ArrayVec; 369 use proptest::*; 370 use std::io::Cursor; 371 372 #[test] default()373 fn default() { 374 let header: Ipv6Header = Default::default(); 375 assert_eq!(0, header.traffic_class); 376 assert_eq!(0, header.flow_label.value()); 377 assert_eq!(0, header.payload_length); 378 assert_eq!(255, header.next_header.0); 379 assert_eq!(0, header.hop_limit); 380 assert_eq!([0u8; 16], header.source); 381 assert_eq!([0u8; 16], header.destination); 382 } 383 384 #[test] debug()385 fn debug() { 386 let header: Ipv6Header = Default::default(); 387 assert_eq!( 388 format!("{:?}", header), 389 format!( 390 "Ipv6Header {{ traffic_class: {}, flow_label: {:?}, payload_length: {}, next_header: {:?}, hop_limit: {}, source: {:?}, destination: {:?} }}", 391 header.traffic_class, 392 header.flow_label, 393 header.payload_length, 394 header.next_header, 395 header.hop_limit, 396 header.source, 397 header.destination 398 ) 399 ); 400 } 401 402 proptest! { 403 #[test] 404 fn clone_eq(header in ipv6_any()) { 405 assert_eq!(header.clone(), header); 406 } 407 } 408 409 proptest! { 410 #[test] 411 #[allow(deprecated)] 412 fn read_from_slice( 413 header in ipv6_any(), 414 bad_version in 0..=0b1111u8 415 ) { 416 // ok read 417 { 418 let bytes = header.to_bytes(); 419 let (actual, rest) = Ipv6Header::read_from_slice(&bytes).unwrap(); 420 assert_eq!(header, actual); 421 assert_eq!(rest, &[]); 422 } 423 424 // version error 425 if bad_version != 6 { 426 let mut bytes = header.to_bytes(); 427 // inject a bad version number 428 bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4); 429 430 assert_eq!( 431 Ipv6Header::read_from_slice(&bytes).unwrap_err(), 432 Content(UnexpectedVersion{ version_number: bad_version }) 433 ); 434 } 435 436 // length error 437 { 438 let bytes = header.to_bytes(); 439 for len in 0..bytes.len() { 440 assert_eq!( 441 Ipv6Header::read_from_slice(&bytes[..len]) 442 .unwrap_err(), 443 Len(err::LenError{ 444 required_len: Ipv6Header::LEN, 445 len: len, 446 len_source: LenSource::Slice, 447 layer: err::Layer::Ipv6Header, 448 layer_start_offset: 0, 449 }) 450 ); 451 } 452 } 453 } 454 } 455 456 proptest! { 457 #[test] 458 fn from_slice( 459 header in ipv6_any(), 460 bad_version in 0..=0b1111u8 461 ) { 462 // ok read 463 { 464 let bytes = header.to_bytes(); 465 let (actual, rest) = Ipv6Header::from_slice(&bytes).unwrap(); 466 assert_eq!(header, actual); 467 assert_eq!(rest, &[]); 468 } 469 470 // version error 471 if bad_version != 6 { 472 let mut bytes = header.to_bytes(); 473 // inject a bad version number 474 bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4); 475 476 assert_eq!( 477 Ipv6Header::from_slice(&bytes).unwrap_err(), 478 Content(UnexpectedVersion{ version_number: bad_version }) 479 ); 480 } 481 482 // length error 483 { 484 let bytes = header.to_bytes(); 485 for len in 0..bytes.len() { 486 assert_eq!( 487 Ipv6Header::from_slice(&bytes[..len]) 488 .unwrap_err(), 489 Len(err::LenError{ 490 required_len: Ipv6Header::LEN, 491 len: len, 492 len_source: LenSource::Slice, 493 layer: err::Layer::Ipv6Header, 494 layer_start_offset: 0, 495 }) 496 ); 497 } 498 } 499 } 500 } 501 502 proptest! { 503 #[test] 504 fn read( 505 header in ipv6_any(), 506 bad_version in 0..=0b1111u8 507 ) { 508 use err::ipv6::HeaderError::*; 509 510 // ok read 511 { 512 let bytes = header.to_bytes(); 513 let mut cursor = Cursor::new(&bytes[..]); 514 let actual = Ipv6Header::read(&mut cursor).unwrap(); 515 assert_eq!(header, actual); 516 assert_eq!(cursor.position(), bytes.len() as u64); 517 } 518 519 // version error 520 if bad_version != 6 { 521 let mut bytes = header.to_bytes(); 522 // inject a bad version number 523 bytes[0] = (0b1111 & bytes[0]) | (bad_version << 4); 524 525 let mut cursor = Cursor::new(&bytes[..]); 526 assert_eq!( 527 Ipv6Header::read(&mut cursor) 528 .unwrap_err() 529 .content_error() 530 .unwrap(), 531 UnexpectedVersion { 532 version_number: bad_version, 533 } 534 ); 535 } 536 537 // io error 538 { 539 let bytes = header.to_bytes(); 540 for len in 0..bytes.len() { 541 let mut cursor = Cursor::new(&bytes[..len]); 542 assert!(Ipv6Header::read(&mut cursor).is_err()); 543 } 544 } 545 } 546 } 547 548 proptest! { 549 #[test] 550 fn read_without_version(header in ipv6_any()) { 551 // ok read 552 { 553 let bytes = header.to_bytes(); 554 let mut cursor = Cursor::new(&bytes[1..]); 555 let actual = Ipv6Header::read_without_version(&mut cursor, bytes[0] & 0xf).unwrap(); 556 assert_eq!(header, actual); 557 assert_eq!(cursor.position(), bytes.len() as u64 - 1); 558 } 559 560 // io error 561 { 562 let bytes = header.to_bytes(); 563 for len in 1..bytes.len() { 564 let mut cursor = Cursor::new(&bytes[1..len]); 565 assert!(Ipv6Header::read_without_version(&mut cursor, bytes[0] & 0xf).is_err()); 566 } 567 } 568 } 569 } 570 571 proptest! { 572 #[test] 573 fn skip_header_extension_in_slice( 574 generic in ipv6_raw_ext_any(), 575 frag in ipv6_fragment_any(), 576 auth in ip_auth_any() 577 ) { 578 const GENERICS: [IpNumber;7] = [ 579 IPV6_HOP_BY_HOP, 580 IPV6_DEST_OPTIONS, 581 IPV6_ROUTE, 582 IPV6_DEST_OPTIONS, 583 MOBILITY, 584 HIP, 585 SHIM6, 586 ]; 587 588 // generic headers 589 for g in GENERICS { 590 let bytes = generic.to_bytes(); 591 // ok case 592 { 593 let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, g).unwrap(); 594 assert_eq!(next, generic.next_header); 595 assert_eq!(rest, &[]); 596 } 597 // length error 598 for len in 0..bytes.len() { 599 assert_eq!( 600 Ipv6Header::skip_header_extension_in_slice(&bytes[..len], g).unwrap_err(), 601 err::LenError { 602 required_len: if len < 2 { 603 2 604 } else { 605 bytes.len() 606 }, 607 len: len, 608 len_source: LenSource::Slice, 609 layer: err::Layer::Ipv6ExtHeader, 610 layer_start_offset: 0, 611 } 612 ); 613 } 614 } 615 // frag header 616 { 617 let bytes = frag.to_bytes(); 618 // ok case 619 { 620 let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, IPV6_FRAG).unwrap(); 621 assert_eq!(next, frag.next_header); 622 assert_eq!(rest, &[]); 623 } 624 // length error 625 for len in 0..bytes.len() { 626 assert_eq!( 627 Ipv6Header::skip_header_extension_in_slice(&bytes[..len], IPV6_FRAG).unwrap_err(), 628 err::LenError { 629 required_len: if len < 2 { 630 2 631 } else { 632 bytes.len() 633 }, 634 len: len, 635 len_source: LenSource::Slice, 636 layer: err::Layer::Ipv6ExtHeader, 637 layer_start_offset: 0, 638 } 639 ); 640 } 641 } 642 643 // auth header 644 { 645 let bytes = auth.to_bytes(); 646 // ok case 647 { 648 let (next, rest) = Ipv6Header::skip_header_extension_in_slice(&bytes, AUTH).unwrap(); 649 assert_eq!(next, auth.next_header); 650 assert_eq!(rest, &[]); 651 } 652 // length error 653 for len in 0..bytes.len() { 654 assert_eq!( 655 Ipv6Header::skip_header_extension_in_slice(&bytes[..len], AUTH).unwrap_err(), 656 err::LenError { 657 required_len: if len < 2 { 658 2 659 } else { 660 bytes.len() 661 }, 662 len: len, 663 len_source: LenSource::Slice, 664 layer: err::Layer::Ipv6ExtHeader, 665 layer_start_offset: 0, 666 } 667 ); 668 } 669 } 670 } 671 } 672 673 #[test] is_skippable_header_extension()674 fn is_skippable_header_extension() { 675 for i in 0..0xffu8 { 676 let expected = match IpNumber(i) { 677 IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_FRAG | AUTH | IPV6_DEST_OPTIONS | MOBILITY 678 | HIP | SHIM6 => true, 679 _ => false, 680 }; 681 assert_eq!( 682 expected, 683 Ipv6Header::is_skippable_header_extension(IpNumber(i)) 684 ); 685 } 686 } 687 688 proptest! { 689 #[test] 690 fn skip_all_header_extensions_in_slice( 691 hop_by_hop in ipv6_raw_ext_any(), 692 dst_opt1 in ipv6_raw_ext_any(), 693 route in ipv6_raw_ext_any(), 694 frag in ipv6_fragment_any(), 695 auth in ip_auth_any(), 696 dst_opt2 in ipv6_raw_ext_any(), 697 mobility in ipv6_raw_ext_any(), 698 hip in ipv6_raw_ext_any(), 699 shim6 in ipv6_raw_ext_any() 700 ) { 701 // no extension header 702 { 703 let (next, rest) = Ipv6Header::skip_all_header_extensions_in_slice(&[], UDP).unwrap(); 704 assert_eq!(UDP, next); 705 assert_eq!(rest, &[]); 706 } 707 708 // setup a buffer with all extension headers present 709 let buffer = { 710 let mut buffer = ArrayVec::<u8, { 711 Ipv6RawExtHeader::MAX_LEN * 8 + IpAuthHeader::MAX_LEN 712 }>::new(); 713 714 // based on RFC 8200 4.1. Extension Header Order 715 // & IANA https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml 716 // 717 // IPV6_HOP_BY_HOP, 718 // IPV6_DEST_OPTIONS, 719 // IPV6_ROUTE, 720 // IPV6_FRAG, 721 // AUTH, 722 // IPV6_DEST_OPTIONS, 723 // MOBILITY, 724 // HIP, 725 // SHIM6, 726 727 let mut hop_by_hop = hop_by_hop.clone(); 728 hop_by_hop.next_header = IPV6_DEST_OPTIONS; 729 buffer.extend(hop_by_hop.to_bytes()); 730 731 let mut dst_opt1 = dst_opt1.clone(); 732 dst_opt1.next_header = IPV6_ROUTE; 733 buffer.extend(dst_opt1.to_bytes()); 734 735 let mut route = route.clone(); 736 route.next_header = IPV6_FRAG; 737 buffer.extend(route.to_bytes()); 738 739 let mut frag = frag.clone(); 740 frag.next_header = AUTH; 741 buffer.extend(frag.to_bytes()); 742 743 let mut auth = auth.clone(); 744 auth.next_header = IPV6_DEST_OPTIONS; 745 buffer.extend(auth.to_bytes()); 746 747 let mut dst_opt2 = dst_opt2.clone(); 748 dst_opt2.next_header = MOBILITY; 749 buffer.extend(dst_opt2.to_bytes()); 750 751 let mut mobility = mobility.clone(); 752 mobility.next_header = HIP; 753 buffer.extend(mobility.to_bytes()); 754 755 let mut hip = hip.clone(); 756 hip.next_header = SHIM6; 757 buffer.extend(hip.to_bytes()); 758 759 let mut shim6 = shim6.clone(); 760 shim6.next_header = TCP; 761 buffer.extend(shim6.to_bytes()); 762 763 buffer 764 }; 765 766 // ok skip case with all extension headers 767 { 768 let (next, rest) = Ipv6Header::skip_all_header_extensions_in_slice(&buffer, IPV6_HOP_BY_HOP).unwrap(); 769 assert_eq!(next, TCP); 770 assert_eq!(rest, &[]); 771 } 772 773 // length error 774 { 775 let len_ranges: [usize;9] = [ 776 hop_by_hop.header_len(), 777 dst_opt1.header_len(), 778 route.header_len(), 779 frag.header_len(), 780 auth.header_len(), 781 dst_opt2.header_len(), 782 mobility.header_len(), 783 hip.header_len(), 784 shim6.header_len() 785 ]; 786 let get_expected = |len: usize| -> usize{ 787 let mut curr = 0; 788 for next in &len_ranges { 789 if len < curr { 790 break; 791 } 792 if len < curr + 2 { 793 curr += 2; 794 break; 795 } 796 curr += next; 797 } 798 curr 799 }; 800 801 let get_offset = |len: usize| -> usize{ 802 let mut curr = 0; 803 for next in &len_ranges { 804 if len < curr + next { 805 break; 806 } 807 curr += next; 808 } 809 curr 810 }; 811 812 for len in 0..buffer.len() { 813 assert_eq!( 814 Ipv6Header::skip_all_header_extensions_in_slice(&buffer[..len], IPV6_HOP_BY_HOP) 815 .unwrap_err(), 816 err::LenError { 817 required_len: get_expected(len) - get_offset(len), 818 len: len - get_offset(len), 819 len_source: LenSource::Slice, 820 layer: err::Layer::Ipv6ExtHeader, 821 layer_start_offset: get_offset(len), 822 } 823 ); 824 } 825 } 826 } 827 } 828 829 #[test] skip_header_extension()830 fn skip_header_extension() { 831 use crate::ip_number::*; 832 { 833 let buffer: [u8; 8] = [0; 8]; 834 let mut cursor = Cursor::new(&buffer); 835 assert_eq!( 836 Ipv6Header::skip_header_extension(&mut cursor, ICMP).unwrap(), 837 ICMP 838 ); 839 assert_eq!(0, cursor.position()); 840 } 841 { 842 let buffer: [u8; 8] = [0; 8]; 843 let mut cursor = Cursor::new(&buffer); 844 assert_eq!( 845 Ipv6Header::skip_header_extension(&mut cursor, IPV6_HOP_BY_HOP).unwrap(), 846 IpNumber(0) 847 ); 848 assert_eq!(8, cursor.position()); 849 } 850 { 851 #[rustfmt::skip] 852 let buffer: [u8; 8 * 3] = [ 853 4, 2, 0, 0, 0, 0, 0, 0, 854 0, 0, 0, 0, 0, 0, 0, 0, 855 0, 0, 0, 0, 0, 0, 0, 0, 856 ]; 857 let mut cursor = Cursor::new(&buffer); 858 assert_eq!( 859 Ipv6Header::skip_header_extension(&mut cursor, IPV6_ROUTE).unwrap(), 860 IpNumber(4) 861 ); 862 assert_eq!(8 * 3, cursor.position()); 863 } 864 { 865 //fragmentation header has a fixed size -> the 2 should be ignored 866 #[rustfmt::skip] 867 let buffer: [u8; 8 * 3] = [ 868 4, 2, 0, 0, 0, 0, 0, 0, 869 0, 0, 0, 0, 0, 0, 0, 0, 870 0, 0, 0, 0, 0, 0, 0, 0, 871 ]; 872 let mut cursor = Cursor::new(&buffer); 873 assert_eq!( 874 Ipv6Header::skip_header_extension(&mut cursor, IPV6_FRAG).unwrap(), 875 IpNumber(4) 876 ); 877 assert_eq!(8, cursor.position()); 878 } 879 } 880 881 proptest! { 882 #[test] 883 fn skip_all_header_extensions( 884 hop_by_hop in ipv6_raw_ext_any(), 885 dst_opt1 in ipv6_raw_ext_any(), 886 route in ipv6_raw_ext_any(), 887 frag in ipv6_fragment_any(), 888 auth in ip_auth_any(), 889 dst_opt2 in ipv6_raw_ext_any(), 890 mobility in ipv6_raw_ext_any(), 891 hip in ipv6_raw_ext_any(), 892 shim6 in ipv6_raw_ext_any() 893 ) { 894 // no extension header 895 { 896 let mut cursor = Cursor::new(&[]); 897 let next = Ipv6Header::skip_all_header_extensions(&mut cursor, UDP).unwrap(); 898 assert_eq!(UDP, next); 899 assert_eq!(0, cursor.position()); 900 } 901 902 // setup a buffer with all extension headers present 903 let buffer = { 904 let mut buffer = ArrayVec::<u8, { 905 Ipv6RawExtHeader::MAX_LEN * 8 + IpAuthHeader::MAX_LEN 906 }>::new(); 907 908 // based on RFC 8200 4.1. Extension Header Order 909 // & IANA https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml 910 // 911 // IPV6_HOP_BY_HOP, 912 // IPV6_DEST_OPTIONS, 913 // IPV6_ROUTE, 914 // IPV6_FRAG, 915 // AUTH, 916 // IPV6_DEST_OPTIONS, 917 // MOBILITY, 918 // HIP, 919 // SHIM6, 920 921 let mut hop_by_hop = hop_by_hop.clone(); 922 hop_by_hop.next_header = IPV6_DEST_OPTIONS; 923 buffer.extend(hop_by_hop.to_bytes()); 924 925 let mut dst_opt1 = dst_opt1.clone(); 926 dst_opt1.next_header = IPV6_ROUTE; 927 buffer.extend(dst_opt1.to_bytes()); 928 929 let mut route = route.clone(); 930 route.next_header = IPV6_FRAG; 931 buffer.extend(route.to_bytes()); 932 933 let mut frag = frag.clone(); 934 frag.next_header = AUTH; 935 buffer.extend(frag.to_bytes()); 936 937 let mut auth = auth.clone(); 938 auth.next_header = IPV6_DEST_OPTIONS; 939 buffer.extend(auth.to_bytes()); 940 941 let mut dst_opt2 = dst_opt2.clone(); 942 dst_opt2.next_header = MOBILITY; 943 buffer.extend(dst_opt2.to_bytes()); 944 945 let mut mobility = mobility.clone(); 946 mobility.next_header = HIP; 947 buffer.extend(mobility.to_bytes()); 948 949 let mut hip = hip.clone(); 950 hip.next_header = SHIM6; 951 buffer.extend(hip.to_bytes()); 952 953 let mut shim6 = shim6.clone(); 954 shim6.next_header = TCP; 955 buffer.extend(shim6.to_bytes()); 956 957 buffer 958 }; 959 960 // ok skip case with all extension headers 961 { 962 let mut cursor = Cursor::new(&buffer); 963 let last = Ipv6Header::skip_all_header_extensions(&mut cursor, IPV6_HOP_BY_HOP).unwrap(); 964 assert_eq!(last, TCP); 965 assert_eq!(cursor.position(), buffer.len() as u64); 966 } 967 968 // length error 969 for len in 0..buffer.len() { 970 let mut cursor = Cursor::new(&buffer[..len]); 971 assert!( 972 Ipv6Header::skip_all_header_extensions(&mut cursor, IPV6_HOP_BY_HOP) 973 .is_err() 974 ); 975 } 976 } 977 } 978 979 proptest! { 980 #[test] 981 fn write(header in ipv6_any()) { 982 let mut buffer = [0u8;Ipv6Header::LEN]; 983 let len = { 984 let mut cursor = Cursor::new(&mut buffer[..]); 985 header.write(&mut cursor).unwrap(); 986 cursor.position() as usize 987 }; 988 assert_eq!(len, header.header_len()); 989 assert_eq!( 990 Ipv6Header::from_slice(&buffer[..len]).unwrap().0, 991 header 992 ); 993 } 994 } 995 996 proptest! { 997 #[test] 998 fn source_addr(header in ipv6_any()) { 999 assert_eq!( 1000 header.source_addr().octets(), 1001 header.source 1002 ); 1003 } 1004 } 1005 1006 proptest! { 1007 #[test] 1008 fn destination_addr(header in ipv6_any()) { 1009 assert_eq!( 1010 header.destination_addr().octets(), 1011 header.destination 1012 ); 1013 } 1014 } 1015 1016 proptest! { 1017 #[test] 1018 fn to_bytes(header in ipv6_any()) { 1019 let bytes = header.to_bytes(); 1020 assert_eq!( 1021 Ipv6Header::from_slice(&bytes).unwrap().0, 1022 header 1023 ); 1024 } 1025 } 1026 } 1027