1 use core::slice::from_raw_parts; 2 #[cfg(feature = "std")] 3 use std::net::Ipv4Addr; 4 5 use crate::*; 6 7 /// A slice containing an ipv4 header of a network package. 8 #[derive(Copy, Clone, Debug, Eq, PartialEq)] 9 pub struct Ipv4HeaderSlice<'a> { 10 slice: &'a [u8], 11 } 12 13 impl<'a> Ipv4HeaderSlice<'a> { 14 /// Creates a slice containing an ipv4 header (including header options). 15 /// 16 /// If you also want to have the payload & ip extension headers correctly 17 /// seperated you can use 18 /// 19 /// * [`crate::Ipv4Slice::from_slice`] (just identifies slice ranges) 20 /// * [`crate::IpHeaders::from_ipv4_slice`] (unpacks all fields) 21 /// 22 /// or 23 /// 24 /// * [`crate::IpHeaders::from_ipv4_slice_lax`] 25 /// * [`crate::LaxIpv4Slice::from_slice`] 26 /// 27 /// for a laxer version which falls back to slice length only when the total_length 28 /// field in the header is inconsistent. from_slice(slice: &'a [u8]) -> Result<Ipv4HeaderSlice<'a>, err::ipv4::HeaderSliceError>29 pub fn from_slice(slice: &'a [u8]) -> Result<Ipv4HeaderSlice<'a>, err::ipv4::HeaderSliceError> { 30 use err::ipv4::HeaderError::*; 31 use err::ipv4::HeaderSliceError::*; 32 33 // check length 34 if slice.len() < Ipv4Header::MIN_LEN { 35 return Err(Len(err::LenError { 36 required_len: Ipv4Header::MIN_LEN, 37 len: slice.len(), 38 len_source: LenSource::Slice, 39 layer: err::Layer::Ipv4Header, 40 layer_start_offset: 0, 41 })); 42 } 43 44 // read version & ihl 45 let (version_number, ihl) = unsafe { 46 let value = slice.get_unchecked(0); 47 (value >> 4, value & 0xf) 48 }; 49 50 // check version 51 if 4 != version_number { 52 return Err(Content(UnexpectedVersion { version_number })); 53 } 54 55 // check that the ihl is correct 56 if ihl < 5 { 57 return Err(Content(HeaderLengthSmallerThanHeader { ihl })); 58 } 59 60 // check that the slice contains enough data for the entire header + options 61 let header_length = (usize::from(ihl)) * 4; 62 if slice.len() < header_length { 63 return Err(Len(err::LenError { 64 required_len: header_length, 65 len: slice.len(), 66 len_source: LenSource::Slice, 67 layer: err::Layer::Ipv4Header, 68 layer_start_offset: 0, 69 })); 70 } 71 72 //all good 73 Ok(Ipv4HeaderSlice { 74 // SAFETY: 75 // Safe as the slice length is checked to be at least 76 // header_length or greater above. 77 slice: unsafe { from_raw_parts(slice.as_ptr(), header_length) }, 78 }) 79 } 80 81 /// Converts the given slice into a ipv4 header slice WITHOUT any 82 /// checks to ensure that the data present is an ipv4 header or that the 83 /// slice length is matching the header length. 84 /// 85 /// If you are not sure what this means, use [`Ipv4HeaderSlice::from_slice`] 86 /// instead. 87 /// 88 /// # Safety 89 /// 90 /// It must ensured that the slice exactly contains the IPv4 header 91 /// and the ihl (intra header length) & total length must be consistent. 92 #[inline] from_slice_unchecked(slice: &[u8]) -> Ipv4HeaderSlice93 pub(crate) unsafe fn from_slice_unchecked(slice: &[u8]) -> Ipv4HeaderSlice { 94 Ipv4HeaderSlice { slice } 95 } 96 97 /// Returns the slice containing the ipv4 header 98 #[inline] slice(&self) -> &'a [u8]99 pub fn slice(&self) -> &'a [u8] { 100 self.slice 101 } 102 103 /// Read the "version" field of the IPv4 header (should be 4). 104 #[inline] version(&self) -> u8105 pub fn version(&self) -> u8 { 106 // SAFETY: 107 // Safe as the slice length is checked to be at least 108 // Ipv4Header::MIN_LEN (20) in the constructor. 109 unsafe { *self.slice.get_unchecked(0) >> 4 } 110 } 111 112 /// Read the "ip header length" (length of the ipv4 header + options in multiples of 4 bytes). 113 #[inline] ihl(&self) -> u8114 pub fn ihl(&self) -> u8 { 115 // SAFETY: 116 // Safe as the slice length is checked to be at least 117 // Ipv4Header::MIN_LEN (20) in the constructor. 118 unsafe { *self.slice.get_unchecked(0) & 0xf } 119 } 120 121 /// Read the "differentiated_services_code_point" from the slice. 122 #[inline] dcp(&self) -> Ipv4Dscp123 pub fn dcp(&self) -> Ipv4Dscp { 124 // SAFETY: 125 // get_unchecked: Safe as the slice length is checked to be at least 126 // Ipv4Header::MIN_LEN (20) in the constructor. 127 // new_unchecked: Safe as the bitshift by 2 guarantees that the passed 128 // value is not bigger then 6 bits. 129 unsafe { Ipv4Dscp::new_unchecked(*self.slice.get_unchecked(1) >> 2) } 130 } 131 132 /// Read the "explicit_congestion_notification" from the slice. 133 #[inline] ecn(&self) -> Ipv4Ecn134 pub fn ecn(&self) -> Ipv4Ecn { 135 // SAFETY: 136 // get_unchecked: Safe as the slice length is checked to be at least 137 // Ipv4Header::MIN_LEN (20) in the constructor. 138 // new_unchecked: Safe as value has been bitmasked to two bits. 139 unsafe { Ipv4Ecn::new_unchecked(*self.slice.get_unchecked(1) & 0b0000_0011) } 140 } 141 142 /// Read the "total length" from the slice (total length of ip header + payload). 143 #[inline] total_len(&self) -> u16144 pub fn total_len(&self) -> u16 { 145 // SAFETY: 146 // Safe as the slice length is checked to be at least 147 // Ipv4Header::MIN_LEN (20) in the constructor. 148 unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(2)) } 149 } 150 151 /// Determine the payload length based on the ihl & total_length 152 /// field of the header. 153 /// 154 /// # Example Usage 155 /// 156 /// ``` 157 /// use etherparse::{Ipv4Header, Ipv4HeaderSlice}; 158 /// 159 /// let bytes = Ipv4Header{ 160 /// // the payload len will be calculated by subtracting the 161 /// // header length from the total length 162 /// total_len: Ipv4Header::MIN_LEN as u16 + 100, 163 /// ..Default::default() 164 /// }.to_bytes(); 165 /// 166 /// let slice = Ipv4HeaderSlice::from_slice(&bytes).unwrap(); 167 /// assert_eq!(Ok(100), slice.payload_len()); 168 /// 169 /// // error case 170 /// let bad_bytes = Ipv4Header { 171 /// // total len should also include the header, in case it does 172 /// // not it is not possible to calculate the payload length 173 /// total_len: Ipv4Header::MIN_LEN as u16 - 1, 174 /// ..Default::default() 175 /// }.to_bytes(); 176 /// 177 /// let bad_slice = Ipv4HeaderSlice::from_slice(&bad_bytes).unwrap(); 178 /// // in case the total_len is smaller then the header itself an 179 /// // error is returned 180 /// use etherparse::{err::{LenError, Layer}, LenSource}; 181 /// assert_eq!( 182 /// bad_slice.payload_len(), 183 /// Err(LenError { 184 /// required_len: Ipv4Header::MIN_LEN, 185 /// len: Ipv4Header::MIN_LEN - 1, 186 /// len_source: LenSource::Ipv4HeaderTotalLen, 187 /// layer: Layer::Ipv4Packet, 188 /// layer_start_offset: 0, 189 /// }) 190 /// ); 191 /// ``` 192 #[inline] payload_len(&self) -> Result<u16, err::LenError>193 pub fn payload_len(&self) -> Result<u16, err::LenError> { 194 let total_len = self.total_len(); 195 // SAFETY: slice.len() can be at most be 60 (verified in from_slice) so a 196 // cast to u16 is safe. 197 let header_len = self.slice.len() as u16; 198 if header_len <= total_len { 199 Ok(total_len - header_len) 200 } else { 201 use err::{Layer, LenError}; 202 Err(LenError { 203 required_len: header_len.into(), 204 len: total_len.into(), 205 len_source: LenSource::Ipv4HeaderTotalLen, 206 layer: Layer::Ipv4Packet, 207 layer_start_offset: 0, 208 }) 209 } 210 } 211 212 /// Read the "identification" field from the slice. 213 #[inline] identification(&self) -> u16214 pub fn identification(&self) -> u16 { 215 // SAFETY: 216 // Safe as the slice length is checked to be at least 217 // Ipv4Header::MIN_LEN (20) in the constructor. 218 unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(4)) } 219 } 220 221 /// Read the "dont fragment" flag from the slice. 222 #[inline] dont_fragment(&self) -> bool223 pub fn dont_fragment(&self) -> bool { 224 // SAFETY: 225 // Safe as the slice length is checked to be at least 226 // Ipv4Header::MIN_LEN (20) in the constructor. 227 unsafe { 0 != (*self.slice.get_unchecked(6) & 0x40) } 228 } 229 230 /// Read the "more fragments" flag from the slice. 231 #[inline] more_fragments(&self) -> bool232 pub fn more_fragments(&self) -> bool { 233 // SAFETY: 234 // Safe as the slice length is checked to be at least 235 // Ipv4Header::MIN_LEN (20) in the constructor. 236 unsafe { 0 != (*self.slice.get_unchecked(6) & 0x20) } 237 } 238 239 /// Read the "fragment_offset" field from the slice. 240 #[inline] fragments_offset(&self) -> IpFragOffset241 pub fn fragments_offset(&self) -> IpFragOffset { 242 unsafe { 243 // SAFETY: 244 // Safe as the value is limited to be 13 bits long bellow. 245 IpFragOffset::new_unchecked(u16::from_be_bytes([ 246 // SAFETY: 247 // Safe as the slice length is checked to be at least 248 // Ipv4Header::MIN_LEN (20) in the constructor. 249 *self.slice.get_unchecked(6) & 0x1f, 250 *self.slice.get_unchecked(7), 251 ])) 252 } 253 } 254 255 /// Read the "time_to_live" field from the slice. 256 #[inline] ttl(&self) -> u8257 pub fn ttl(&self) -> u8 { 258 // SAFETY: 259 // Safe as the slice length is checked to be at least 260 // Ipv4Header::MIN_LEN (20) in the constructor. 261 unsafe { *self.slice.get_unchecked(8) } 262 } 263 264 /// Read the "protocol" field from the slice. 265 #[inline] protocol(&self) -> IpNumber266 pub fn protocol(&self) -> IpNumber { 267 // SAFETY: 268 // Safe as the slice length is checked to be at least 269 // Ipv4Header::MIN_LEN (20) in the constructor. 270 IpNumber(unsafe { *self.slice.get_unchecked(9) }) 271 } 272 273 /// Read the "header checksum" field from the slice. 274 #[inline] header_checksum(&self) -> u16275 pub fn header_checksum(&self) -> u16 { 276 // SAFETY: 277 // Safe as the slice length is checked to be at least 278 // Ipv4Header::MIN_LEN (20) in the constructor. 279 unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(10)) } 280 } 281 282 /// Returns a slice containing the ipv4 source address. 283 #[inline] source(&self) -> [u8; 4]284 pub fn source(&self) -> [u8; 4] { 285 // SAFETY: 286 // Safe as the slice length is checked to be at least 287 // Ipv4Header::MIN_LEN (20) in the constructor. 288 unsafe { get_unchecked_4_byte_array(self.slice.as_ptr().add(12)) } 289 } 290 291 /// Return the ipv4 source address as an std::net::Ipv4Addr 292 #[cfg(feature = "std")] 293 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 294 #[inline] source_addr(&self) -> Ipv4Addr295 pub fn source_addr(&self) -> Ipv4Addr { 296 Ipv4Addr::from(self.source()) 297 } 298 299 /// Returns a slice containing the ipv4 source address. 300 #[inline] destination(&self) -> [u8; 4]301 pub fn destination(&self) -> [u8; 4] { 302 // SAFETY: 303 // Safe as the slice length is checked to be at least 304 // Ipv4Header::MIN_LEN (20) in the constructor. 305 unsafe { get_unchecked_4_byte_array(self.slice.as_ptr().add(16)) } 306 } 307 308 /// Return the ipv4 destination address as an std::net::Ipv4Addr 309 #[cfg(feature = "std")] 310 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] 311 #[inline] destination_addr(&self) -> Ipv4Addr312 pub fn destination_addr(&self) -> Ipv4Addr { 313 Ipv4Addr::from(self.destination()) 314 } 315 316 /// Returns a slice containing the ipv4 header options (empty when there are no options). 317 #[inline] options(&self) -> &'a [u8]318 pub fn options(&self) -> &'a [u8] { 319 // SAFETY: 320 // Safe as the slice length is checked to be at least 321 // Ipv4Header::MIN_LEN (20) in the constructor. 322 unsafe { from_raw_parts(self.slice.as_ptr().add(20), self.slice.len() - 20) } 323 } 324 325 /// Returns true if the payload is fragmented. 326 /// 327 /// Either data is missing (more_fragments set) or there is 328 /// an fragment offset. 329 #[inline] is_fragmenting_payload(&self) -> bool330 pub fn is_fragmenting_payload(&self) -> bool { 331 self.more_fragments() || (0 != self.fragments_offset().value()) 332 } 333 334 /// Decode all the fields and copy the results to a Ipv4Header struct 335 #[inline] to_header(&self) -> Ipv4Header336 pub fn to_header(&self) -> Ipv4Header { 337 Ipv4Header { 338 dscp: self.dcp(), 339 ecn: self.ecn(), 340 total_len: self.total_len(), 341 identification: self.identification(), 342 dont_fragment: self.dont_fragment(), 343 more_fragments: self.more_fragments(), 344 fragment_offset: self.fragments_offset(), 345 time_to_live: self.ttl(), 346 protocol: self.protocol(), 347 header_checksum: self.header_checksum(), 348 source: self.source(), 349 destination: self.destination(), 350 options: { 351 let options_slice = self.options(); 352 let mut options = Ipv4Options::new(); 353 options.len = options_slice.len() as u8; 354 let target_slice: &mut [u8] = options.as_mut(); 355 target_slice.copy_from_slice(options_slice); 356 options 357 }, 358 } 359 } 360 } 361 362 #[cfg(test)] 363 mod test { 364 use crate::{test_gens::*, *}; 365 use alloc::{format, vec::Vec}; 366 use arrayvec::ArrayVec; 367 use proptest::prelude::*; 368 369 #[test] debug()370 fn debug() { 371 let buffer = { 372 let header: Ipv4Header = Default::default(); 373 header.to_bytes() 374 }; 375 let slice = Ipv4HeaderSlice::from_slice(&buffer).unwrap(); 376 assert_eq!( 377 format!("{:?}", slice), 378 format!("Ipv4HeaderSlice {{ slice: {:?} }}", slice.slice()) 379 ); 380 } 381 382 proptest! { 383 #[test] 384 fn clone_eq(header in ipv4_any()) { 385 let buffer = header.to_bytes(); 386 let slice = Ipv4HeaderSlice::from_slice(&buffer).unwrap(); 387 assert_eq!(slice.clone(), slice); 388 } 389 } 390 391 proptest! { 392 #[test] 393 fn from_slice(header in ipv4_any()) { 394 use err::ipv4::HeaderError::*; 395 use err::ipv4::HeaderSliceError::*; 396 397 // ok 398 { 399 let mut buffer = ArrayVec::<u8, { Ipv4Header::MAX_LEN + 1 }>::new(); 400 buffer.try_extend_from_slice(&header.to_bytes()).unwrap(); 401 buffer.try_extend_from_slice(&[1]).unwrap(); 402 403 let actual_slice = Ipv4HeaderSlice::from_slice(&buffer).unwrap(); 404 assert_eq!(actual_slice.to_header(), header); 405 assert_eq!(actual_slice.slice(), &buffer[..header.header_len()]); 406 } 407 408 // unexpected end of slice 409 { 410 let buffer = header.to_bytes(); 411 for len in 0..header.header_len() { 412 assert_eq!( 413 Ipv4HeaderSlice::from_slice(&buffer[..len]), 414 Err(Len(err::LenError{ 415 required_len: if len < Ipv4Header::MIN_LEN { 416 Ipv4Header::MIN_LEN 417 } else { 418 header.header_len() 419 }, 420 len: len, 421 len_source: LenSource::Slice, 422 layer: err::Layer::Ipv4Header, 423 layer_start_offset: 0, 424 })) 425 ); 426 } 427 } 428 429 // version error 430 for version_number in 0u8..0b1111u8 { 431 if 4 != version_number { 432 let mut buffer = header.to_bytes(); 433 // inject the bad ihl 434 buffer[0] = (version_number << 4) | (buffer[0] & 0b1111); 435 // expect an error 436 assert_eq!( 437 Ipv4HeaderSlice::from_slice(&buffer).unwrap_err(), 438 Content(UnexpectedVersion{ 439 version_number, 440 }) 441 ); 442 } 443 } 444 445 // ihl too small error 446 for ihl in 0u8..5u8 { 447 let mut buffer = header.to_bytes(); 448 // inject the bad ihl 449 buffer[0] = (4 << 4) | ihl; 450 // expect an error 451 assert_eq!( 452 Ipv4HeaderSlice::from_slice(&buffer).unwrap_err(), 453 Content(HeaderLengthSmallerThanHeader{ 454 ihl, 455 }) 456 ); 457 } 458 } 459 } 460 461 #[test] from_slice_unchecked()462 fn from_slice_unchecked() { 463 let buffer = [0u8; 4]; 464 let slice = unsafe { Ipv4HeaderSlice::from_slice_unchecked(&buffer) }; 465 assert_eq!(slice.slice(), &buffer); 466 } 467 468 proptest! { 469 #[test] 470 fn getters(header in ipv4_any()) { 471 let buffer = header.to_bytes(); 472 let slice = Ipv4HeaderSlice::from_slice(&buffer).unwrap(); 473 474 assert_eq!(slice.slice(), &buffer[..]); 475 assert_eq!(slice.version(), 4); 476 assert_eq!(slice.ihl(), header.ihl()); 477 assert_eq!(slice.dcp(), header.dscp); 478 assert_eq!(slice.ecn(), header.ecn); 479 assert_eq!(slice.total_len(), header.total_len); 480 assert_eq!(slice.payload_len(), header.payload_len()); 481 assert_eq!(slice.identification(), header.identification); 482 assert_eq!(slice.dont_fragment(), header.dont_fragment); 483 assert_eq!(slice.more_fragments(), header.more_fragments); 484 assert_eq!(slice.fragments_offset(), header.fragment_offset); 485 assert_eq!(slice.ttl(), header.time_to_live); 486 assert_eq!(slice.protocol(), header.protocol); 487 assert_eq!(slice.header_checksum(), header.header_checksum); 488 assert_eq!(slice.source(), header.source); 489 assert_eq!(slice.destination(), header.destination); 490 assert_eq!(slice.options(), &header.options[..]); 491 } 492 } 493 494 #[cfg(feature = "std")] 495 proptest! { 496 #[test] 497 fn getters_std(header in ipv4_any()) { 498 use std::net::Ipv4Addr; 499 500 let buffer = header.to_bytes(); 501 let slice = Ipv4HeaderSlice::from_slice(&buffer).unwrap(); 502 503 assert_eq!(slice.source_addr(), Ipv4Addr::from(header.source)); 504 assert_eq!(slice.destination_addr(), Ipv4Addr::from(header.destination)); 505 } 506 } 507 508 #[test] is_fragmenting_payload()509 fn is_fragmenting_payload() { 510 // not fragmenting 511 { 512 let buffer = { 513 let mut header: Ipv4Header = Default::default(); 514 header.fragment_offset = 0.try_into().unwrap(); 515 header.more_fragments = false; 516 let mut buffer = Vec::with_capacity(header.header_len()); 517 header.write(&mut buffer).unwrap(); 518 buffer 519 }; 520 let slice = Ipv4HeaderSlice::from_slice(&buffer).unwrap(); 521 assert_eq!(false, slice.is_fragmenting_payload()); 522 } 523 524 // fragmenting based on offset 525 { 526 let buffer = { 527 let mut header: Ipv4Header = Default::default(); 528 header.fragment_offset = 1.try_into().unwrap(); 529 header.more_fragments = false; 530 let mut buffer = Vec::with_capacity(header.header_len()); 531 header.write(&mut buffer).unwrap(); 532 buffer 533 }; 534 let slice = Ipv4HeaderSlice::from_slice(&buffer).unwrap(); 535 assert!(slice.is_fragmenting_payload()); 536 } 537 538 // fragmenting based on more_fragments 539 { 540 let buffer = { 541 let mut header: Ipv4Header = Default::default(); 542 header.fragment_offset = 0.try_into().unwrap(); 543 header.more_fragments = true; 544 let mut buffer = Vec::with_capacity(header.header_len()); 545 header.write(&mut buffer).unwrap(); 546 buffer 547 }; 548 let slice = Ipv4HeaderSlice::from_slice(&buffer).unwrap(); 549 assert!(slice.is_fragmenting_payload()); 550 } 551 } 552 553 proptest! { 554 #[test] 555 fn to_header(header in ipv4_any()) { 556 let buffer = header.to_bytes(); 557 let slice = Ipv4HeaderSlice::from_slice(&buffer).unwrap(); 558 assert_eq!(slice.to_header(), header); 559 } 560 } 561 } 562