1 use crate::{err::ipv4_exts::ExtsWalkError, *}; 2 3 /// IPv4 extension headers present after the ip header. 4 /// 5 /// Currently supported: 6 /// * Authentication Header 7 /// 8 /// Currently not supported: 9 /// - Encapsulating Security Payload Header (ESP) 10 #[derive(Clone, Debug, Eq, PartialEq, Default)] 11 pub struct Ipv4Extensions { 12 pub auth: Option<IpAuthHeader>, 13 } 14 15 impl Ipv4Extensions { 16 /// Minimum length required for extension header in bytes/octets. 17 /// Which is zero as no extension headers are required. 18 pub const MIN_LEN: usize = 0; 19 20 /// Maximum summed up length of all extension headers in bytes/octets. 21 pub const MAX_LEN: usize = IpAuthHeader::MAX_LEN; 22 23 /// Read all known ipv4 extensions and return an `Ipv4Extensions` with the 24 /// identified slices, the final ip number and a slice pointing to the non parsed data. from_slice( start_ip_number: IpNumber, slice: &[u8], ) -> Result<(Ipv4Extensions, IpNumber, &[u8]), err::ip_auth::HeaderSliceError>25 pub fn from_slice( 26 start_ip_number: IpNumber, 27 slice: &[u8], 28 ) -> Result<(Ipv4Extensions, IpNumber, &[u8]), err::ip_auth::HeaderSliceError> { 29 Ipv4ExtensionsSlice::from_slice(start_ip_number, slice).map(|v| (v.0.to_header(), v.1, v.2)) 30 } 31 32 /// Collects all known ipv4 extension headers in a slice until an error 33 /// is encountered or a "non IP extension header" is found and 34 /// returns the successfully parsed parts (+ the unparsed slice 35 /// it's [`IpNumber`] and the error if one occurred). 36 /// 37 /// The returned values are 38 /// 39 /// * [`Ipv4Extensions`] containing the successfully parsed IPv6 extension headers 40 /// * [`IpNumber`] of unparsed data 41 /// * Slice with unparsed data 42 /// * Optional with error if there was an error wich stoped the parsing. 43 /// 44 /// # Examples 45 /// 46 /// ``` 47 /// use etherparse::{Ipv4Extensions, IpAuthHeader, ip_number::{UDP, AUTHENTICATION_HEADER}}; 48 /// 49 /// let auth_header = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap(); 50 /// let data = auth_header.to_bytes(); 51 /// 52 /// let (ipv4_exts, next_ip_num, next_data, err) = 53 /// Ipv4Extensions::from_slice_lax(AUTHENTICATION_HEADER, &data); 54 /// 55 /// // authentication header is separated and no error occurred 56 /// assert!(ipv4_exts.auth.is_some()); 57 /// assert_eq!(next_ip_num, UDP); 58 /// assert_eq!(next_data, &[]); 59 /// assert!(err.is_none()); 60 /// ``` 61 /// 62 /// It is also ok to pass in a "non ip extension": 63 /// 64 /// ``` 65 /// use etherparse::{Ipv4Extensions, ip_number::UDP}; 66 /// 67 /// let data = [0,1,2,3]; 68 /// // passing a non "ip extension header" ip number 69 /// let (ipv4_exts, next_ip_num, next_data, err) = 70 /// Ipv4Extensions::from_slice_lax(UDP, &data); 71 /// 72 /// // the original data gets returned as UDP is not a 73 /// // an IP extension header 74 /// assert!(ipv4_exts.is_empty()); 75 /// assert_eq!(next_ip_num, UDP); 76 /// assert_eq!(next_data, &data); 77 /// // no errors gets triggered as the data is valid 78 /// assert!(err.is_none()); 79 /// ``` 80 /// 81 /// In case an error occurred the original data gets 82 /// returned together with the error: 83 /// 84 /// ``` 85 /// use etherparse::{ 86 /// Ipv4Extensions, 87 /// IpAuthHeader, 88 /// ip_number::AUTHENTICATION_HEADER, 89 /// LenSource, 90 /// err::{ip_auth::HeaderSliceError::Len, LenError, Layer} 91 /// }; 92 /// 93 /// // providing not enough data 94 /// let (ipv4_exts, next_ip_num, next_data, err) = 95 /// Ipv4Extensions::from_slice_lax(AUTHENTICATION_HEADER, &[]); 96 /// 97 /// // original data will be returned with no data parsed 98 /// assert!(ipv4_exts.is_empty()); 99 /// assert_eq!(next_ip_num, AUTHENTICATION_HEADER); 100 /// assert_eq!(next_data, &[]); 101 /// // the error that stopped the parsing will also be returned 102 /// assert_eq!(err, Some(Len(LenError{ 103 /// required_len: IpAuthHeader::MIN_LEN, 104 /// len: 0, 105 /// len_source: LenSource::Slice, 106 /// layer: Layer::IpAuthHeader, 107 /// layer_start_offset: 0, 108 /// }))); 109 /// ``` from_slice_lax( start_ip_number: IpNumber, start_slice: &[u8], ) -> ( Ipv4Extensions, IpNumber, &[u8], Option<err::ip_auth::HeaderSliceError>, )110 pub fn from_slice_lax( 111 start_ip_number: IpNumber, 112 start_slice: &[u8], 113 ) -> ( 114 Ipv4Extensions, 115 IpNumber, 116 &[u8], 117 Option<err::ip_auth::HeaderSliceError>, 118 ) { 119 let (slice, next_ip_number, next_data, error) = 120 Ipv4ExtensionsSlice::from_slice_lax(start_ip_number, start_slice); 121 (slice.to_header(), next_ip_number, next_data, error) 122 } 123 124 /// Reads the known ipv4 extension headers from the reader and returns the 125 /// headers together with the internet protocol number identifying the protocol 126 /// that will be next. 127 #[cfg(feature = "std")] 128 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] read<T: std::io::Read + Sized>( reader: &mut T, start_ip_number: IpNumber, ) -> Result<(Ipv4Extensions, IpNumber), err::ip_auth::HeaderReadError>129 pub fn read<T: std::io::Read + Sized>( 130 reader: &mut T, 131 start_ip_number: IpNumber, 132 ) -> Result<(Ipv4Extensions, IpNumber), err::ip_auth::HeaderReadError> { 133 use ip_number::*; 134 if AUTH == start_ip_number { 135 let header = IpAuthHeader::read(reader)?; 136 let next_ip_number = header.next_header; 137 Ok((Ipv4Extensions { auth: Some(header) }, next_ip_number)) 138 } else { 139 Ok((Default::default(), start_ip_number)) 140 } 141 } 142 143 /// Reads the known ipv4 extension headers from a length limited reader and returns the 144 /// headers together with the internet protocol number identifying the protocol 145 /// that will be next. 146 #[cfg(feature = "std")] 147 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] read_limited<T: std::io::Read + Sized>( reader: &mut crate::io::LimitedReader<T>, start_ip_number: IpNumber, ) -> Result<(Ipv4Extensions, IpNumber), err::ip_auth::HeaderLimitedReadError>148 pub fn read_limited<T: std::io::Read + Sized>( 149 reader: &mut crate::io::LimitedReader<T>, 150 start_ip_number: IpNumber, 151 ) -> Result<(Ipv4Extensions, IpNumber), err::ip_auth::HeaderLimitedReadError> { 152 use ip_number::*; 153 if AUTH == start_ip_number { 154 let header = IpAuthHeader::read_limited(reader)?; 155 let next_ip_number = header.next_header; 156 Ok((Ipv4Extensions { auth: Some(header) }, next_ip_number)) 157 } else { 158 Ok((Default::default(), start_ip_number)) 159 } 160 } 161 162 /// Write the extensions to the writer. 163 #[cfg(feature = "std")] 164 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] write<T: std::io::Write + Sized>( &self, writer: &mut T, start_ip_number: IpNumber, ) -> Result<(), err::ipv4_exts::HeaderWriteError>165 pub fn write<T: std::io::Write + Sized>( 166 &self, 167 writer: &mut T, 168 start_ip_number: IpNumber, 169 ) -> Result<(), err::ipv4_exts::HeaderWriteError> { 170 use err::ipv4_exts::{ExtsWalkError::*, HeaderWriteError::*}; 171 use ip_number::*; 172 match self.auth { 173 Some(ref header) => { 174 if AUTH == start_ip_number { 175 header.write(writer).map_err(Io) 176 } else { 177 Err(Content(ExtNotReferenced { 178 missing_ext: IpNumber::AUTHENTICATION_HEADER, 179 })) 180 } 181 } 182 None => Ok(()), 183 } 184 } 185 186 ///Length of the all present headers in bytes. header_len(&self) -> usize187 pub fn header_len(&self) -> usize { 188 if let Some(ref header) = self.auth { 189 header.header_len() 190 } else { 191 0 192 } 193 } 194 195 /// Sets all the next_header fields of the headers based on the adviced default order 196 /// with the given protocol number as last "next header" value. The return value is the protocol 197 /// number of the first existing extension header that should be entered in the ipv4 header as 198 /// protocol_number. 199 /// 200 /// If no extension headers are present the value of the argument is returned. set_next_headers(&mut self, last_protocol_number: IpNumber) -> IpNumber201 pub fn set_next_headers(&mut self, last_protocol_number: IpNumber) -> IpNumber { 202 use ip_number::*; 203 204 let mut next = last_protocol_number; 205 206 if let Some(ref mut header) = self.auth { 207 header.next_header = next; 208 next = AUTH; 209 } 210 211 next 212 } 213 214 /// Return next header based on the extension headers and 215 /// the first ip protocol number. 216 /// 217 /// In case a header is never referenced a 218 /// [`err::ipv4_exts::ExtsWalkError::ExtNotReferenced`] is returned. next_header(&self, first_next_header: IpNumber) -> Result<IpNumber, ExtsWalkError>219 pub fn next_header(&self, first_next_header: IpNumber) -> Result<IpNumber, ExtsWalkError> { 220 use ip_number::*; 221 if let Some(ref auth) = self.auth { 222 if first_next_header == AUTH { 223 Ok(auth.next_header) 224 } else { 225 Err(ExtsWalkError::ExtNotReferenced { 226 missing_ext: IpNumber::AUTHENTICATION_HEADER, 227 }) 228 } 229 } else { 230 Ok(first_next_header) 231 } 232 } 233 234 /// Returns true if no IPv4 extension header is present (all fields `None`). 235 #[inline] is_empty(&self) -> bool236 pub fn is_empty(&self) -> bool { 237 self.auth.is_none() 238 } 239 } 240 241 #[cfg(test)] 242 mod test { 243 use super::*; 244 use crate::ip_number::*; 245 use crate::test_gens::*; 246 use alloc::vec::Vec; 247 use proptest::prelude::*; 248 use std::io::Cursor; 249 250 #[test] from_slice()251 fn from_slice() { 252 let auth_header = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap(); 253 254 let buffer = { 255 let mut buffer = Vec::with_capacity(auth_header.header_len()); 256 auth_header.write(&mut buffer).unwrap(); 257 buffer.push(1); 258 buffer.push(2); 259 buffer 260 }; 261 262 // no auth header 263 { 264 let (header, next, rest) = Ipv4Extensions::from_slice(TCP, &buffer).unwrap(); 265 assert!(header.auth.is_none()); 266 assert_eq!(TCP, next); 267 assert_eq!(rest, &buffer); 268 } 269 270 // with auth header 271 { 272 let (actual, next, rest) = Ipv4Extensions::from_slice(AUTH, &buffer).unwrap(); 273 assert_eq!(actual.auth.unwrap(), auth_header); 274 assert_eq!(UDP, next); 275 assert_eq!(rest, &buffer[auth_header.header_len()..]); 276 } 277 278 // too small 279 { 280 use err::ip_auth::HeaderSliceError::Len; 281 const AUTH_HEADER_LEN: usize = 12; 282 assert_eq!( 283 Ipv4Extensions::from_slice(AUTH, &buffer[..auth_header.header_len() - 1]) 284 .unwrap_err(), 285 Len(err::LenError { 286 required_len: AUTH_HEADER_LEN, 287 len: auth_header.header_len() - 1, 288 len_source: LenSource::Slice, 289 layer: err::Layer::IpAuthHeader, 290 layer_start_offset: 0, 291 }) 292 ); 293 } 294 } 295 296 proptest! { 297 #[test] 298 fn from_slice_lax(auth in ip_auth_any()) { 299 use crate::ip_number::{UDP, AUTHENTICATION_HEADER}; 300 use crate::err::{*, ip_auth::HeaderSliceError::Len}; 301 302 // normal read 303 { 304 let data = auth.to_bytes(); 305 306 let (ipv4_exts, next_ip_num, next_data, err) = 307 Ipv4Extensions::from_slice_lax(AUTHENTICATION_HEADER, &data); 308 309 // authentication header is separated and no error occurred 310 assert_eq!(ipv4_exts.auth, Some(auth.clone())); 311 assert_eq!(next_ip_num, auth.next_header); 312 assert_eq!(next_data, &[]); 313 assert!(err.is_none()); 314 } 315 // normal read with no extension header 316 { 317 let data = [0,1,2,3]; 318 // passing a non "ip extension header" ip number 319 let (ipv4_exts, next_ip_num, next_data, err) = 320 Ipv4Extensions::from_slice_lax(UDP, &data); 321 322 // the original data gets returned as UDP is not a 323 // an IP extension header 324 assert!(ipv4_exts.is_empty()); 325 assert_eq!(next_ip_num, UDP); 326 assert_eq!(next_data, &data); 327 // no errors gets triggered as the data is valid 328 assert!(err.is_none()); 329 } 330 // len error during parsing 331 { 332 // providing not enough data 333 let (ipv4_exts, next_ip_num, next_data, err) = 334 Ipv4Extensions::from_slice_lax(AUTHENTICATION_HEADER, &[]); 335 336 // original data will be returned with no data parsed 337 assert!(ipv4_exts.is_empty()); 338 assert_eq!(next_ip_num, AUTHENTICATION_HEADER); 339 assert_eq!(next_data, &[]); 340 // the error that stopped the parsing will also be returned 341 assert_eq!(err, Some(Len(LenError{ 342 required_len: IpAuthHeader::MIN_LEN, 343 len: 0, 344 len_source: LenSource::Slice, 345 layer: Layer::IpAuthHeader, 346 layer_start_offset: 0, 347 }))); 348 } 349 } 350 } 351 352 proptest! { 353 #[test] 354 fn read(auth in ip_auth_any()) { 355 // None 356 { 357 let mut cursor = Cursor::new(&[]); 358 let (actual, next) = Ipv4Extensions::read(&mut cursor, UDP).unwrap(); 359 assert_eq!(next, UDP); 360 assert_eq!( 361 actual, 362 Ipv4Extensions{ 363 auth: None, 364 } 365 ); 366 } 367 368 // Some sucessfull 369 { 370 let buffer = { 371 let mut buffer = Vec::with_capacity(auth.header_len()); 372 auth.write(&mut buffer).unwrap(); 373 buffer.push(1); 374 buffer 375 }; 376 let mut cursor = Cursor::new(&buffer); 377 let (actual, next) = Ipv4Extensions::read(&mut cursor, AUTH).unwrap(); 378 assert_eq!(auth.header_len(), cursor.position() as usize); 379 assert_eq!(next, auth.next_header); 380 assert_eq!( 381 actual, 382 Ipv4Extensions{ 383 auth: Some(auth.clone()), 384 } 385 ); 386 } 387 388 // Some error 389 { 390 let mut cursor = Cursor::new(&[]); 391 assert!(Ipv4Extensions::read(&mut cursor, AUTH).is_err()); 392 } 393 } 394 } 395 396 #[test] write()397 fn write() { 398 // None 399 { 400 let mut buffer = Vec::new(); 401 Ipv4Extensions { auth: None } 402 .write(&mut buffer, UDP) 403 .unwrap(); 404 assert_eq!(0, buffer.len()); 405 } 406 407 // Some 408 let auth_header = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap(); 409 { 410 let mut buffer = Vec::with_capacity(auth_header.header_len()); 411 Ipv4Extensions { 412 auth: Some(auth_header.clone()), 413 } 414 .write(&mut buffer, AUTH) 415 .unwrap(); 416 let (read_header, _) = IpAuthHeader::from_slice(&buffer).unwrap(); 417 assert_eq!(auth_header, read_header); 418 } 419 420 // Some bad start number 421 { 422 use crate::err::ipv4_exts::ExtsWalkError::ExtNotReferenced; 423 424 let mut buffer = Vec::new(); 425 let err = Ipv4Extensions { 426 auth: Some(auth_header.clone()), 427 } 428 .write(&mut buffer, UDP) 429 .unwrap_err(); 430 assert_eq!( 431 err.content().unwrap(), 432 &ExtNotReferenced { 433 missing_ext: IpNumber::AUTHENTICATION_HEADER, 434 } 435 ); 436 } 437 438 // Some: Write error 439 { 440 let mut buffer = Vec::with_capacity(auth_header.header_len() - 1); 441 buffer.resize(auth_header.header_len() - 1, 0); 442 let mut cursor = Cursor::new(&mut buffer[..]); 443 let err = Ipv4Extensions { 444 auth: Some(auth_header.clone()), 445 } 446 .write(&mut cursor, AUTH) 447 .unwrap_err(); 448 assert!(err.io().is_some()); 449 } 450 } 451 452 #[test] header_len()453 fn header_len() { 454 // None 455 assert_eq!(0, Ipv4Extensions { auth: None }.header_len()); 456 457 // Some 458 { 459 let auth = IpAuthHeader::new(UDP, 0, 0, &[]).unwrap(); 460 assert_eq!( 461 auth.header_len(), 462 Ipv4Extensions { auth: Some(auth) }.header_len() 463 ); 464 } 465 // Some with paylaod 466 { 467 let auth = IpAuthHeader::new(UDP, 0, 0, &[1, 2, 3, 4]).unwrap(); 468 assert_eq!( 469 auth.header_len(), 470 Ipv4Extensions { auth: Some(auth) }.header_len() 471 ); 472 } 473 } 474 475 #[test] set_next_headers()476 fn set_next_headers() { 477 // None 478 { 479 let mut exts = Ipv4Extensions { auth: None }; 480 assert_eq!(UDP, exts.set_next_headers(UDP)); 481 } 482 483 // Some 484 { 485 let mut exts = Ipv4Extensions { 486 auth: Some(IpAuthHeader::new(TCP, 0, 0, &[]).unwrap()), 487 }; 488 assert_eq!(TCP, exts.auth.as_ref().unwrap().next_header); 489 // change from TCP to UDP 490 let re = exts.set_next_headers(UDP); 491 assert_eq!(AUTH, re); 492 assert_eq!(UDP, exts.auth.as_ref().unwrap().next_header); 493 } 494 } 495 496 #[test] next_header()497 fn next_header() { 498 // None 499 { 500 let exts = Ipv4Extensions { auth: None }; 501 assert_eq!(UDP, exts.next_header(UDP).unwrap()); 502 } 503 // Some 504 { 505 let exts = Ipv4Extensions { 506 auth: Some(IpAuthHeader::new(TCP, 0, 0, &[]).unwrap()), 507 }; 508 509 // auth referenced 510 assert_eq!(TCP, exts.next_header(AUTH).unwrap()); 511 512 // auth not referenced (error) 513 use crate::err::ipv4_exts::ExtsWalkError::ExtNotReferenced; 514 assert_eq!( 515 ExtNotReferenced { 516 missing_ext: IpNumber::AUTHENTICATION_HEADER 517 }, 518 exts.next_header(TCP).unwrap_err() 519 ); 520 } 521 } 522 523 #[test] is_empty()524 fn is_empty() { 525 // empty 526 assert!(Ipv4Extensions { auth: None }.is_empty()); 527 528 // auth 529 assert_eq!( 530 false, 531 Ipv4Extensions { 532 auth: Some(IpAuthHeader::new(ip_number::UDP, 0, 0, &[]).unwrap()), 533 } 534 .is_empty() 535 ); 536 } 537 538 proptest! { 539 #[test] 540 fn debug(auth in ip_auth_any()) { 541 use alloc::format; 542 543 // None 544 assert_eq!( 545 &format!("Ipv4Extensions {{ auth: {:?} }}", Option::<IpAuthHeader>::None), 546 &format!( 547 "{:?}", 548 Ipv4Extensions { 549 auth: None, 550 } 551 ) 552 ); 553 554 // Some 555 assert_eq!( 556 &format!("Ipv4Extensions {{ auth: {:?} }}", Some(auth.clone())), 557 &format!( 558 "{:?}", 559 Ipv4Extensions { 560 auth: Some(auth.clone()), 561 } 562 ) 563 ); 564 } 565 } 566 567 proptest! { 568 #[test] 569 fn clone_eq(auth in ip_auth_any()) { 570 // None 571 { 572 let header = Ipv4Extensions{ 573 auth: None, 574 }; 575 assert_eq!( 576 header.clone(), 577 Ipv4Extensions{ 578 auth: None, 579 } 580 ); 581 } 582 583 // Some 584 { 585 let header = Ipv4Extensions{ 586 auth: Some(auth.clone()), 587 }; 588 assert_eq!( 589 header.clone(), 590 Ipv4Extensions{ 591 auth: Some(auth.clone()), 592 } 593 ); 594 } 595 } 596 } 597 } 598