1 use super::super::*; 2 use crate::err::ipv6_exts::ExtPayloadLenError; 3 use arrayvec::ArrayVec; 4 use core::fmt::{Debug, Formatter}; 5 6 /// Deprecated. Use [Ipv6RawExtHeader] instead. 7 #[deprecated( 8 since = "0.14.0", 9 note = "Please use the type Ipv6RawExtHeader instead" 10 )] 11 pub type Ipv6RawExtensionHeader = Ipv6RawExtHeader; 12 13 /// Raw IPv6 extension header (undecoded payload). 14 /// 15 /// IPv6 extension header with only minimal data interpretation. NOTE only ipv6 header 16 /// extensions with the first two bytes representing the next header and the header length 17 /// in 8-octets (- 8 octets) can be represented with this struct. This excludes the "Authentication 18 /// Header" (AH) and "Encapsulating Security Payload" (ESP). 19 /// 20 /// The following headers can be represented in a [`Ipv6RawExtHeader`]: 21 /// * Hop by Hop 22 /// * Destination Options 23 /// * Routing 24 /// * Mobility 25 /// * Host Identity Protocol 26 /// * Shim6 Protocol 27 #[derive(Clone)] 28 pub struct Ipv6RawExtHeader { 29 /// IP protocol number specifying the next header or transport layer protocol. 30 /// 31 /// See [IpNumber] or [ip_number] for a definition of the known values. 32 pub next_header: IpNumber, 33 /// Length of the extension header in 8 octets (minus the first 8 octets). 34 header_length: u8, 35 //// The data contained in the extension header (excluding next_header & hdr length). 36 payload_buffer: [u8; 0xff * 8 + 6], 37 } 38 39 impl Debug for Ipv6RawExtHeader { fmt(&self, f: &mut Formatter) -> Result<(), core::fmt::Error>40 fn fmt(&self, f: &mut Formatter) -> Result<(), core::fmt::Error> { 41 let mut s = f.debug_struct("Ipv6RawExtHeader"); 42 s.field("next_header", &self.next_header); 43 s.field("payload", &self.payload()); 44 s.finish() 45 } 46 } 47 48 impl PartialEq for Ipv6RawExtHeader { eq(&self, other: &Self) -> bool49 fn eq(&self, other: &Self) -> bool { 50 self.next_header == other.next_header && self.payload() == other.payload() 51 } 52 } 53 54 impl Eq for Ipv6RawExtHeader {} 55 56 impl Default for Ipv6RawExtHeader { default() -> Self57 fn default() -> Self { 58 Ipv6RawExtHeader { 59 next_header: IpNumber(255), 60 header_length: 0, 61 payload_buffer: [0; 0xff * 8 + 6], 62 } 63 } 64 } 65 66 impl Ipv6RawExtHeader { 67 /// Minimum length of an raw IPv6 extension header in bytes/octets. 68 pub const MIN_LEN: usize = 8; 69 70 /// Maximum length of an raw IPv6 extension header in bytes/octets. 71 /// 72 /// This number is calculated by multiplying the maximum "hdr ext len" 73 /// (0xff) with 8 and adding 8. As RFC8200 states that "hdr ext len" is 74 /// defined as "8-bit unsigned integer. Length of the Hop-by-Hop Options 75 /// header in 8-octet units, not including the first 8 octets." 76 pub const MAX_LEN: usize = 8 + (8 * 0xff); 77 78 /// Minimum length of a [Ipv6RawExtHeader] payload 79 pub const MIN_PAYLOAD_LEN: usize = 6; 80 81 /// Maximum length of a [Ipv6RawExtHeader] the payload 82 pub const MAX_PAYLOAD_LEN: usize = 0xff * 8 + 6; 83 84 /// Returns true if the given header type ip number can be represented in an `Ipv6ExtensionHeader`. header_type_supported(next_header: IpNumber) -> bool85 pub fn header_type_supported(next_header: IpNumber) -> bool { 86 use crate::ip_number::*; 87 matches!( 88 next_header, 89 IPV6_HOP_BY_HOP | IPV6_ROUTE | IPV6_DEST_OPTIONS | MOBILITY | HIP | SHIM6 90 ) 91 } 92 93 /// Creates an generic IPv6 extension header with the given data. 94 /// 95 /// # Arguments 96 /// 97 /// * `next_header` - type of content after this header (protocol number) 98 /// * `payload` - slice containing the data of the header. This must NOT contain the `next header` and `extended header length` fields of the header. 99 /// 100 /// Note that `payload` must have at least the length of 6 bytes and only supports 101 /// length increases in steps of 8. This measn that the following expression must be true `(payload.len() + 2) % 8 == 0`. 102 /// The maximum length of the payload is `2046` bytes ([`Ipv6RawExtHeader::MAX_PAYLOAD_LEN`]). 103 /// 104 /// If a payload with a non supported length is provided a [`crate::err::ipv6_exts::ExtPayloadLenError`] is returned. new_raw( next_header: IpNumber, payload: &[u8], ) -> Result<Ipv6RawExtHeader, ExtPayloadLenError>105 pub fn new_raw( 106 next_header: IpNumber, 107 payload: &[u8], 108 ) -> Result<Ipv6RawExtHeader, ExtPayloadLenError> { 109 use ExtPayloadLenError::*; 110 if payload.len() < Self::MIN_PAYLOAD_LEN { 111 Err(TooSmall(payload.len())) 112 } else if payload.len() > Self::MAX_PAYLOAD_LEN { 113 Err(TooBig(payload.len())) 114 } else if 0 != (payload.len() + 2) % 8 { 115 Err(Unaligned(payload.len())) 116 } else { 117 let mut result = Ipv6RawExtHeader { 118 next_header, 119 header_length: ((payload.len() - 6) / 8) as u8, 120 payload_buffer: [0; Self::MAX_PAYLOAD_LEN], 121 }; 122 result.payload_buffer[..payload.len()].copy_from_slice(payload); 123 Ok(result) 124 } 125 } 126 127 /// Read an Ipv6ExtensionHeader from a slice and return the header & unused parts of the slice. from_slice(slice: &[u8]) -> Result<(Ipv6RawExtHeader, &[u8]), err::LenError>128 pub fn from_slice(slice: &[u8]) -> Result<(Ipv6RawExtHeader, &[u8]), err::LenError> { 129 let s = Ipv6RawExtHeaderSlice::from_slice(slice)?; 130 let rest = &slice[s.slice().len()..]; 131 let header = s.to_header(); 132 Ok((header, rest)) 133 } 134 135 /// Return a slice containing the current payload. This does NOT contain 136 /// the `next_header` and `header_length` fields. But everything after these 137 /// two fields. payload(&self) -> &[u8]138 pub fn payload(&self) -> &[u8] { 139 &self.payload_buffer[..(6 + usize::from(self.header_length) * 8)] 140 } 141 142 /// Sets the payload (content of the header after the `next_header` & `header_length` fields). 143 /// 144 /// Note that `payload` must have at least the length of 6 bytes and only supports 145 /// length increases in steps of 8. This measn that the following expression must be true `(payload.len() + 2) % 8 == 0`. 146 /// The maximum length of the payload is `2046` bytes ([`crate::Ipv6RawExtHeader::MAX_PAYLOAD_LEN`]). 147 /// 148 /// If a payload with a non supported length is provided a [`crate::err::ipv6_exts::ExtPayloadLenError`] is returned and the payload of the header is not changed. set_payload(&mut self, payload: &[u8]) -> Result<(), ExtPayloadLenError>149 pub fn set_payload(&mut self, payload: &[u8]) -> Result<(), ExtPayloadLenError> { 150 use ExtPayloadLenError::*; 151 if payload.len() < Self::MIN_PAYLOAD_LEN { 152 Err(TooSmall(payload.len())) 153 } else if payload.len() > Self::MAX_PAYLOAD_LEN { 154 Err(TooBig(payload.len())) 155 } else if 0 != (payload.len() + 2) % 8 { 156 Err(Unaligned(payload.len())) 157 } else { 158 self.payload_buffer[..payload.len()].copy_from_slice(payload); 159 self.header_length = ((payload.len() - 6) / 8) as u8; 160 Ok(()) 161 } 162 } 163 164 /// Read an fragment header from the current reader position. 165 #[cfg(feature = "std")] 166 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] read<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, ) -> Result<Ipv6RawExtHeader, std::io::Error>167 pub fn read<T: std::io::Read + std::io::Seek + Sized>( 168 reader: &mut T, 169 ) -> Result<Ipv6RawExtHeader, std::io::Error> { 170 let (next_header, header_length) = { 171 let mut d: [u8; 2] = [0; 2]; 172 reader.read_exact(&mut d)?; 173 (IpNumber(d[0]), d[1]) 174 }; 175 176 Ok(Ipv6RawExtHeader { 177 next_header, 178 header_length, 179 payload_buffer: { 180 let mut buffer = [0; 0xff * 8 + 6]; 181 reader.read_exact(&mut buffer[..usize::from(header_length) * 8 + 6])?; 182 buffer 183 }, 184 }) 185 } 186 187 /// Read an fragment header from the current limited reader position. 188 #[cfg(feature = "std")] 189 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] read_limited<T: std::io::Read + std::io::Seek + Sized>( reader: &mut crate::io::LimitedReader<T>, ) -> Result<Ipv6RawExtHeader, err::io::LimitedReadError>190 pub fn read_limited<T: std::io::Read + std::io::Seek + Sized>( 191 reader: &mut crate::io::LimitedReader<T>, 192 ) -> Result<Ipv6RawExtHeader, err::io::LimitedReadError> { 193 // set layer start 194 reader.start_layer(err::Layer::Ipv6ExtHeader); 195 196 // read next & len 197 let (next_header, header_length) = { 198 let mut d: [u8; 2] = [0; 2]; 199 reader.read_exact(&mut d)?; 200 (IpNumber(d[0]), d[1]) 201 }; 202 203 Ok(Ipv6RawExtHeader { 204 next_header, 205 header_length, 206 payload_buffer: { 207 let mut buffer = [0; 0xff * 8 + 6]; 208 reader.read_exact(&mut buffer[..usize::from(header_length) * 8 + 6])?; 209 buffer 210 }, 211 }) 212 } 213 214 /// Writes a given IPv6 extension header to the current position. 215 #[cfg(feature = "std")] 216 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] write<W: std::io::Write + Sized>(&self, writer: &mut W) -> Result<(), std::io::Error>217 pub fn write<W: std::io::Write + Sized>(&self, writer: &mut W) -> Result<(), std::io::Error> { 218 writer.write_all(&[self.next_header.0, self.header_length])?; 219 writer.write_all(self.payload())?; 220 Ok(()) 221 } 222 223 /// Returns the serialized header. to_bytes(&self) -> ArrayVec<u8,224 pub fn to_bytes(&self) -> ArrayVec<u8, { Ipv6RawExtHeader::MAX_LEN }> { 225 let mut result = ArrayVec::new(); 226 result.extend([self.next_header.0, self.header_length]); 227 // Unwrap Panic Safety: 228 // The following unwrap should never panic, as 229 // the payload length can at most have the size max 230 // header length - 2 and as the internal buffer used to 231 // store the payload data has exactly this size. 232 result.try_extend_from_slice(self.payload()).unwrap(); 233 result 234 } 235 236 /// Length of the header in bytes. header_len(&self) -> usize237 pub fn header_len(&self) -> usize { 238 2 + (6 + usize::from(self.header_length) * 8) 239 } 240 } 241 242 #[cfg(test)] 243 mod test { 244 use super::*; 245 use crate::test_gens::*; 246 use alloc::{format, vec::Vec}; 247 use proptest::prelude::*; 248 use std::io::Cursor; 249 250 #[test] default()251 fn default() { 252 let default_header = Ipv6RawExtHeader { 253 ..Default::default() 254 }; 255 256 assert_eq!(default_header.next_header, IpNumber(255)); 257 assert_eq!(default_header.header_length, 0); 258 assert_eq!(default_header.payload_buffer, [0; 0xff * 8 + 6]) 259 } 260 261 proptest! { 262 #[test] 263 fn debug(header in ipv6_raw_ext_any()) { 264 assert_eq!( 265 format!("{:?}", header), 266 format!( 267 "Ipv6RawExtHeader {{ next_header: {:?}, payload: {:?} }}", 268 header.next_header, 269 header.payload() 270 ) 271 ); 272 } 273 } 274 275 proptest! { 276 #[test] 277 fn clone_eq(header in ipv6_raw_ext_any()) { 278 assert_eq!(header.clone(), header); 279 } 280 } 281 282 #[test] header_type_supported()283 fn header_type_supported() { 284 use ip_number::*; 285 for value in 0..=u8::MAX { 286 let expected_supported = match IpNumber(value) { 287 IPV6_HOP_BY_HOP | IPV6_DEST_OPTIONS | IPV6_ROUTE | MOBILITY | HIP | SHIM6 => true, 288 _ => false, 289 }; 290 assert_eq!( 291 expected_supported, 292 Ipv6RawExtHeader::header_type_supported(IpNumber(value)) 293 ); 294 } 295 } 296 297 proptest! { 298 #[test] 299 fn new_raw(header in ipv6_raw_ext_any()) { 300 use ExtPayloadLenError::*; 301 302 // ok 303 { 304 let actual = Ipv6RawExtHeader::new_raw(header.next_header, header.payload()).unwrap(); 305 assert_eq!(actual.next_header, header.next_header); 306 assert_eq!(actual.payload(), header.payload()); 307 } 308 309 // smaller then minimum 310 for len in 0..Ipv6RawExtHeader::MIN_PAYLOAD_LEN { 311 assert_eq!( 312 Ipv6RawExtHeader::new_raw(header.next_header, &header.payload()[..len]).unwrap_err(), 313 TooSmall(len) 314 ); 315 } 316 317 // bigger then maximum 318 { 319 let bytes = [0u8;Ipv6RawExtHeader::MAX_PAYLOAD_LEN + 1]; 320 assert_eq!( 321 Ipv6RawExtHeader::new_raw(header.next_header, &bytes).unwrap_err(), 322 TooBig(bytes.len()) 323 ); 324 } 325 326 // non aligned payload 327 { 328 let mut bytes = header.to_bytes(); 329 bytes.pop().unwrap(); 330 bytes.pop().unwrap(); 331 332 for offset in 1..8 { 333 if offset + header.header_len() < Ipv6RawExtHeader::MAX_LEN { 334 bytes.push(0); 335 assert_eq!( 336 Ipv6RawExtHeader::new_raw(header.next_header, &bytes).unwrap_err(), 337 Unaligned(bytes.len()) 338 ); 339 } 340 } 341 } 342 } 343 } 344 345 proptest! { 346 #[test] 347 fn from_slice(header in ipv6_raw_ext_any()) { 348 // ok 349 { 350 let mut bytes = Vec::with_capacity(header.header_len() + 2); 351 bytes.extend_from_slice(&header.to_bytes()); 352 bytes.push(1); 353 bytes.push(2); 354 355 let (actual_header, actual_rest) = Ipv6RawExtHeader::from_slice(&bytes).unwrap(); 356 assert_eq!(actual_header, header); 357 assert_eq!(actual_rest, &[1, 2]); 358 } 359 360 // length error 361 { 362 let bytes = header.to_bytes(); 363 for len in 0..bytes.len() { 364 assert_eq!( 365 Ipv6RawExtHeader::from_slice(&bytes[..len]).unwrap_err(), 366 err::LenError{ 367 required_len: if len < Ipv6RawExtHeader::MIN_LEN { 368 Ipv6RawExtHeader::MIN_LEN 369 } else { 370 header.header_len() 371 }, 372 len: len, 373 len_source: LenSource::Slice, 374 layer: err::Layer::Ipv6ExtHeader, 375 layer_start_offset: 0, 376 } 377 ); 378 } 379 } 380 } 381 } 382 383 proptest! { 384 #[test] 385 fn set_payload( 386 header_a in ipv6_raw_ext_any(), 387 header_b in ipv6_raw_ext_any() 388 ) { 389 use ExtPayloadLenError::*; 390 // ok 391 { 392 let mut actual = header_a.clone(); 393 actual.set_payload(header_b.payload()).unwrap(); 394 assert_eq!(actual.payload(), header_b.payload()); 395 } 396 397 // smaller then minimum 398 for len in 0..Ipv6RawExtHeader::MIN_PAYLOAD_LEN { 399 let mut actual = header_a.clone(); 400 assert_eq!( 401 actual.set_payload(&header_b.payload()[..len]).unwrap_err(), 402 TooSmall(len) 403 ); 404 assert_eq!(actual.payload(), header_a.payload()); 405 } 406 407 // bigger then maximum 408 { 409 let bytes = [0u8;Ipv6RawExtHeader::MAX_PAYLOAD_LEN + 1]; 410 let mut actual = header_a.clone(); 411 assert_eq!( 412 actual.set_payload(&bytes).unwrap_err(), 413 TooBig(bytes.len()) 414 ); 415 } 416 417 // non aligned payload 418 { 419 let mut bytes = header_b.to_bytes(); 420 bytes.pop().unwrap(); 421 bytes.pop().unwrap(); 422 423 for offset in 1..8 { 424 if offset + header_b.header_len() < Ipv6RawExtHeader::MAX_LEN { 425 bytes.push(0); 426 let mut actual = header_a.clone(); 427 assert_eq!( 428 actual.set_payload(&bytes).unwrap_err(), 429 Unaligned(bytes.len()) 430 ); 431 } 432 } 433 } 434 } 435 } 436 437 proptest! { 438 #[test] 439 fn read(header in ipv6_raw_ext_any()) { 440 // ok 441 { 442 let bytes = header.to_bytes(); 443 let mut cursor = Cursor::new(&bytes[..]); 444 let actual = Ipv6RawExtHeader::read(&mut cursor).unwrap(); 445 assert_eq!(actual, header); 446 } 447 448 // length error 449 { 450 let bytes = header.to_bytes(); 451 for len in 0..bytes.len() { 452 let mut cursor = Cursor::new(&bytes[..len]); 453 assert!(Ipv6RawExtHeader::read(&mut cursor).is_err()); 454 } 455 } 456 } 457 } 458 459 proptest! { 460 #[test] 461 fn write(header in ipv6_raw_ext_any()) { 462 // ok case 463 { 464 let mut buffer = [0u8;Ipv6RawExtHeader::MAX_LEN]; 465 let len = { 466 let mut cursor = Cursor::new(&mut buffer[..]); 467 header.write(&mut cursor).unwrap(); 468 cursor.position() as usize 469 }; 470 let (dec_header, dec_rest) = Ipv6RawExtHeader::from_slice(&buffer[..len]).unwrap(); 471 assert_eq!(header, dec_header); 472 assert_eq!(dec_rest, &[]); 473 } 474 475 // length error 476 for len in 0..header.header_len() { 477 let mut buffer = [0u8;Ipv6RawExtHeader::MAX_LEN]; 478 let mut cursor = Cursor::new(&mut buffer[..len]); 479 assert!(header.write(&mut cursor).is_err()); 480 } 481 } 482 } 483 484 proptest! { 485 #[test] 486 fn to_bytes(header in ipv6_raw_ext_any()) { 487 let bytes = header.to_bytes(); 488 assert_eq!(bytes[0], header.next_header.0); 489 assert_eq!(bytes[1], header.header_length); 490 assert_eq!(&bytes[2..], header.payload()); 491 } 492 } 493 494 proptest! { 495 #[test] 496 fn header_len(header in ipv6_raw_ext_any()) { 497 assert_eq!(header.header_len(), header.to_bytes().len()); 498 } 499 } 500 } 501