1 use crate::{ 2 err::{ValueTooBigError, ValueType}, 3 *, 4 }; 5 use arrayvec::ArrayVec; 6 7 /// IPv4 header with options. 8 /// 9 /// # Example Usage: 10 /// 11 /// ``` 12 /// use etherparse::{Ipv4Header, IpNumber}; 13 /// 14 /// let mut header = Ipv4Header { 15 /// source: [1,2,3,4], 16 /// destination: [1,2,3,4], 17 /// time_to_live: 4, 18 /// total_len: Ipv4Header::MIN_LEN as u16 + 100, 19 /// protocol: IpNumber::UDP, 20 /// ..Default::default() 21 /// }; 22 /// 23 /// // depending on your usecase you might want to set the correct checksum 24 /// header.header_checksum = header.calc_header_checksum(); 25 /// 26 /// // header can be serialized into the "on the wire" format 27 /// // using the "write" or "to_bytes" methods 28 /// let bytes = header.to_bytes(); 29 /// 30 /// // IPv4 headers can be decoded via "read" or "from_slice" 31 /// let (decoded, slice_rest) = Ipv4Header::from_slice(&bytes).unwrap(); 32 /// assert_eq!(header, decoded); 33 /// assert_eq!(slice_rest, &[]); 34 /// ``` 35 #[derive(Clone, Debug, Eq, PartialEq, Hash)] 36 pub struct Ipv4Header { 37 /// Differentiated Services Code Point 38 pub dscp: Ipv4Dscp, 39 /// Explicit Congestion Notification 40 pub ecn: Ipv4Ecn, 41 /// Total length of the IPv4 header (including extension headers) and the payload after it. 42 pub total_len: u16, 43 /// Number used to identify packets that contain an originally fragmented packet. 44 pub identification: u16, 45 /// If set the packet is not allowed to fragmented. 46 pub dont_fragment: bool, 47 /// Indicates that the packet contains part of an fragmented message and that 48 /// additional data is needed to reconstruct the original packet. 49 pub more_fragments: bool, 50 /// In case this message contains parts of a fragmented packet the fragment 51 /// offset is the offset of payload the current message relative to the 52 /// original payload of the message. 53 pub fragment_offset: IpFragOffset, 54 /// Number of hops the packet is allowed to take before it should be discarded. 55 pub time_to_live: u8, 56 /// IP protocol number specifying the next header or transport layer protocol. 57 /// 58 /// See [IpNumber] or [ip_number] for a definitions of ids. 59 pub protocol: IpNumber, 60 pub header_checksum: u16, 61 /// IPv4 source address 62 pub source: [u8; 4], 63 /// IPv4 destination address 64 pub destination: [u8; 4], 65 /// Options in the header (in raw). 66 pub options: Ipv4Options, 67 } 68 69 impl Ipv4Header { 70 /// Minimum length of an IPv4 header in bytes/octets. 71 pub const MIN_LEN: usize = 20; 72 73 /// Minimum length of an IPv4 header in bytes/octets as an `u16`. 74 pub const MIN_LEN_U16: u16 = 20; 75 76 /// Maximum length of an IPv4 header in bytes/octets. 77 /// 78 /// This number is calculated by taking the maximum value 79 /// that the "internet header length" field supports (0xf, 80 /// as the field is only 4 bits long) and multiplying it 81 /// with 4 as the "internet header length" specifies how 82 /// many 4 bytes words are present in the header. 83 pub const MAX_LEN: usize = 0b1111 * 4; 84 85 /// Deprecated use [`Ipv4Header::MIN_LEN`] instead. 86 #[deprecated(since = "0.14.0", note = "Use `Ipv4Header::MIN_LEN` instead")] 87 pub const SERIALIZED_SIZE: usize = Ipv4Header::MIN_LEN; 88 89 /// Constructs an Ipv4Header with standard values for non specified values. 90 /// 91 /// This method is equivalent to partially initializing a struct with 92 /// default values: 93 /// 94 /// ``` 95 /// use etherparse::{Ipv4Header, IpNumber}; 96 /// 97 /// let mut header = Ipv4Header::new(100, 4, IpNumber::UDP, [1,2,3,4], [5,6,7,8]).unwrap(); 98 /// 99 /// assert_eq!( 100 /// header, 101 /// Ipv4Header { 102 /// total_len: (100 + Ipv4Header::MIN_LEN) as u16, 103 /// time_to_live: 4, 104 /// protocol: IpNumber::UDP, 105 /// source: [1,2,3,4], 106 /// destination: [5,6,7,8], 107 /// ..Default::default() 108 /// } 109 /// ); 110 /// 111 /// // for the rest of the fields the following default values will be used: 112 /// assert_eq!(0, header.dscp.value()); 113 /// assert_eq!(0, header.ecn.value()); 114 /// assert_eq!(0, header.identification); 115 /// assert_eq!(true, header.dont_fragment); 116 /// assert_eq!(false, header.more_fragments); 117 /// assert_eq!(0, header.fragment_offset.value()); 118 /// assert_eq!(0, header.header_checksum); 119 /// 120 /// // in case you also want to have a correct checksum you will have to 121 /// // additionally update it: 122 /// header.header_checksum = header.calc_header_checksum(); 123 /// ``` new( payload_len: u16, time_to_live: u8, protocol: IpNumber, source: [u8; 4], destination: [u8; 4], ) -> Result<Ipv4Header, ValueTooBigError<u16>>124 pub fn new( 125 payload_len: u16, 126 time_to_live: u8, 127 protocol: IpNumber, 128 source: [u8; 4], 129 destination: [u8; 4], 130 ) -> Result<Ipv4Header, ValueTooBigError<u16>> { 131 const MAX_PAYLOAD: u16 = u16::MAX - (Ipv4Header::MIN_LEN as u16); 132 if payload_len > MAX_PAYLOAD { 133 Err(ValueTooBigError { 134 actual: payload_len, 135 max_allowed: MAX_PAYLOAD, 136 value_type: ValueType::Ipv4PayloadLength, 137 }) 138 } else { 139 Ok(Ipv4Header { 140 dscp: Default::default(), 141 ecn: Default::default(), 142 total_len: payload_len + (Ipv4Header::MIN_LEN as u16), 143 identification: 0, 144 dont_fragment: true, 145 more_fragments: false, 146 fragment_offset: Default::default(), 147 time_to_live, 148 protocol, 149 header_checksum: 0, 150 source, 151 destination, 152 options: Default::default(), 153 }) 154 } 155 } 156 157 /// Length of the header in multiples of 4 bytes (often also called 158 /// IHL - Internet Header length). This field is part of the serialized 159 /// header and determines / is determined by the byte length of the options. 160 /// 161 /// The minimum allowed length of a header is 5 (= 20 bytes) and the 162 /// maximum length is 15 (= 60 bytes). 163 /// 164 /// ``` 165 /// use etherparse::Ipv4Header; 166 /// { 167 /// let header = Ipv4Header { 168 /// options: [].into(), 169 /// ..Default::default() 170 /// }; 171 /// // minimum IHL is 5 172 /// assert_eq!(5, header.ihl()); 173 /// } 174 /// { 175 /// let header = Ipv4Header { 176 /// options: [1,2,3,4].into(), 177 /// ..Default::default() 178 /// }; 179 /// // IHL is increased by 1 for every 4 bytes of options 180 /// assert_eq!(6, header.ihl()); 181 /// } 182 /// { 183 /// let header = Ipv4Header { 184 /// options: [0;40].into(), 185 /// ..Default::default() 186 /// }; 187 /// // maximum ihl 188 /// assert_eq!(15, header.ihl()); 189 /// } 190 /// ``` 191 #[inline] ihl(&self) -> u8192 pub fn ihl(&self) -> u8 { 193 (self.options.len_u8() / 4) + 5 194 } 195 196 /// Length of the header (includes options) in bytes. 197 /// 198 /// The minimum allowed length of a header is 5 (= 20 bytes) and the 199 /// maximum length is 15 (= 60 bytes). 200 /// 201 /// ``` 202 /// use etherparse::Ipv4Header; 203 /// { 204 /// let header = Ipv4Header { 205 /// options: [].into(), 206 /// ..Default::default() 207 /// }; 208 /// // minimum IHL is 5 209 /// assert_eq!(5, header.ihl()); 210 /// } 211 /// { 212 /// let header = Ipv4Header { 213 /// options: [1,2,3,4].into(), 214 /// ..Default::default() 215 /// }; 216 /// // IHL is increased by 1 for every 4 bytes of options 217 /// assert_eq!(6, header.ihl()); 218 /// } 219 /// { 220 /// let header = Ipv4Header { 221 /// options: [0;40].into(), 222 /// ..Default::default() 223 /// }; 224 /// // maximum ihl 225 /// assert_eq!(15, header.ihl()); 226 /// } 227 /// ``` 228 #[inline] header_len(&self) -> usize229 pub fn header_len(&self) -> usize { 230 Ipv4Header::MIN_LEN + self.options.len() 231 } 232 233 /// Determine the payload length based on the ihl & total_length 234 /// field of the header. 235 /// 236 /// # Example Usage 237 /// 238 /// ``` 239 /// use etherparse::{Ipv4Header, Ipv4HeaderSlice}; 240 /// 241 /// let header = Ipv4Header{ 242 /// // the payload len will be calculated by subtracting the 243 /// // header length from the total length 244 /// total_len: Ipv4Header::MIN_LEN as u16 + 100, 245 /// ..Default::default() 246 /// }; 247 /// 248 /// assert_eq!(Ok(100), header.payload_len()); 249 /// 250 /// // error case 251 /// let bad_header = Ipv4Header { 252 /// // total len should also include the header, in case it does 253 /// // not it is not possible to calculate the payload length 254 /// total_len: Ipv4Header::MIN_LEN as u16 - 1, 255 /// ..Default::default() 256 /// }; 257 /// 258 /// // in case the total_len is smaller then the header itself an 259 /// // error is returned 260 /// use etherparse::{LenSource, err::{LenError, Layer}}; 261 /// assert_eq!( 262 /// bad_header.payload_len(), 263 /// Err(LenError { 264 /// required_len: Ipv4Header::MIN_LEN, 265 /// len: Ipv4Header::MIN_LEN - 1, 266 /// len_source: LenSource::Ipv4HeaderTotalLen, 267 /// layer: Layer::Ipv4Packet, 268 /// layer_start_offset: 0, 269 /// }) 270 /// ); 271 /// ``` 272 #[inline] payload_len(&self) -> Result<u16, err::LenError>273 pub fn payload_len(&self) -> Result<u16, err::LenError> { 274 // SAFETY: header_len() can be at most be 60 so a cast to u16 is safe. 275 let header_len = self.header_len() as u16; 276 if header_len <= self.total_len { 277 Ok(self.total_len - header_len) 278 } else { 279 use err::{Layer, LenError}; 280 Err(LenError { 281 required_len: header_len.into(), 282 len: self.total_len.into(), 283 len_source: LenSource::Ipv4HeaderTotalLen, 284 layer: Layer::Ipv4Packet, 285 layer_start_offset: 0, 286 }) 287 } 288 } 289 290 /// Tries setting the [`Ipv4Header::total_len`] field given the length of 291 /// the payload after the header & the current options length of the header. 292 /// 293 /// If the value is not too big. Otherwise an error is returned. 294 /// 295 /// Note that the set payload length is no longer valid if you change 296 /// [`Ipv4Header::options`] length after calling [`Ipv4Header::set_payload_len`] 297 /// as it uses the length of options to calculate the `total_len` value. 298 /// 299 /// # Example Usage: 300 /// 301 /// ``` 302 /// use etherparse::Ipv4Header; 303 /// 304 /// let mut header = Ipv4Header{ 305 /// total_len: 100, // will be reset by set_payload 306 /// options: [1,2,3,4].into(), 307 /// ..Default::default() 308 /// }; 309 /// 310 /// // set_payload_len set the total_len field based on the header_len 311 /// // and given payload length 312 /// header.set_payload_len(100).unwrap(); 313 /// assert_eq!(100 + header.header_len() as u16, header.total_len); 314 /// 315 /// // in case the payload is len is bigger then can represented in the 316 /// // total_len field an error is returned 317 /// use etherparse::err::{ValueTooBigError, ValueType}; 318 /// let err = header.set_payload_len(usize::from(u16::MAX) - header.header_len() + 1); 319 /// assert_eq!( 320 /// err, 321 /// Err(ValueTooBigError { 322 /// actual: usize::from(u16::MAX) - header.header_len() + 1, 323 /// max_allowed: usize::from(u16::MAX) - header.header_len(), 324 /// value_type: ValueType::Ipv4PayloadLength 325 /// }) 326 /// ); 327 /// ``` set_payload_len(&mut self, value: usize) -> Result<(), ValueTooBigError<usize>>328 pub fn set_payload_len(&mut self, value: usize) -> Result<(), ValueTooBigError<usize>> { 329 let max_allowed = usize::from(self.max_payload_len()); 330 if value > max_allowed { 331 Err(ValueTooBigError { 332 actual: value, 333 max_allowed, 334 value_type: ValueType::Ipv4PayloadLength, 335 }) 336 } else { 337 self.total_len = (self.header_len() + value) as u16; 338 Ok(()) 339 } 340 } 341 342 /// Returns the maximum payload size based on the current options size. 343 #[inline] max_payload_len(&self) -> u16344 pub fn max_payload_len(&self) -> u16 { 345 u16::MAX - u16::from(self.options.len_u8()) - (Ipv4Header::MIN_LEN as u16) 346 } 347 348 /// Returns a slice to the options part of the header (empty if no options are present). 349 #[deprecated( 350 since = "0.14.0", 351 note = "Directly use `&(header.options[..])` instead." 352 )] options(&self) -> &[u8]353 pub fn options(&self) -> &[u8] { 354 &self.options[..] 355 } 356 357 /// Sets the options & header_length based on the provided length. 358 /// The length of the given slice must be a multiple of 4 and maximum 40 bytes. 359 /// If the length is not fulfilling these constraints, no data is set and 360 /// an error is returned. 361 #[deprecated( 362 since = "0.14.0", 363 note = "Directly set it via the header.options field instead." 364 )] set_options(&mut self, data: &[u8]) -> Result<(), err::ipv4::BadOptionsLen>365 pub fn set_options(&mut self, data: &[u8]) -> Result<(), err::ipv4::BadOptionsLen> { 366 self.options = data.try_into()?; 367 Ok(()) 368 } 369 370 /// Renamed to `Ipv4Header::from_slice` 371 #[deprecated(since = "0.10.1", note = "Renamed to `Ipv4Header::from_slice`")] 372 #[inline] read_from_slice( slice: &[u8], ) -> Result<(Ipv4Header, &[u8]), err::ipv4::HeaderSliceError>373 pub fn read_from_slice( 374 slice: &[u8], 375 ) -> Result<(Ipv4Header, &[u8]), err::ipv4::HeaderSliceError> { 376 Ipv4Header::from_slice(slice) 377 } 378 379 /// Read an Ipv4Header from a slice and return the header & unused parts 380 /// of the slice. 381 /// 382 /// Note that this function DOES NOT seperate the payload based on the 383 /// `total_length` field present in the IPv4 header. It just returns the 384 /// left over slice after the header. 385 /// 386 /// If you want to have correctly seperated payload including the IP extension 387 /// headers use 388 /// 389 /// * [`IpHeaders::from_ipv4_slice`] (decodes all the fields of the IP headers) 390 /// * [`Ipv4Slice::from_slice`] (just identifies the ranges in the slice where 391 /// the headers and payload are present) 392 /// 393 /// or 394 /// 395 /// * [`IpHeaders::from_ipv4_slice_lax`] 396 /// * [`LaxIpv4Slice::from_slice`] 397 /// 398 /// for a laxer version which falls back to slice length when the `total_length` 399 /// contains an inconsistent value. from_slice(slice: &[u8]) -> Result<(Ipv4Header, &[u8]), err::ipv4::HeaderSliceError>400 pub fn from_slice(slice: &[u8]) -> Result<(Ipv4Header, &[u8]), err::ipv4::HeaderSliceError> { 401 let header = Ipv4HeaderSlice::from_slice(slice)?.to_header(); 402 let rest = &slice[header.header_len()..]; 403 Ok((header, rest)) 404 } 405 406 /// Reads an IPv4 header from the current position (requires 407 /// crate feature `std`). 408 #[cfg(feature = "std")] 409 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] read<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, ) -> Result<Ipv4Header, err::ipv4::HeaderReadError>410 pub fn read<T: std::io::Read + std::io::Seek + Sized>( 411 reader: &mut T, 412 ) -> Result<Ipv4Header, err::ipv4::HeaderReadError> { 413 use err::ipv4::HeaderReadError::*; 414 415 let mut first_byte: [u8; 1] = [0; 1]; 416 reader.read_exact(&mut first_byte).map_err(Io)?; 417 418 let version_number = first_byte[0] >> 4; 419 if 4 != version_number { 420 use err::ipv4::HeaderError::UnexpectedVersion; 421 return Err(Content(UnexpectedVersion { version_number })); 422 } 423 Ipv4Header::read_without_version(reader, first_byte[0]) 424 } 425 426 /// Reads an IPv4 header assuming the version & ihl field have already 427 /// been read (requires crate feature `std`). 428 #[cfg(feature = "std")] 429 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] read_without_version<T: std::io::Read + std::io::Seek + Sized>( reader: &mut T, first_byte: u8, ) -> Result<Ipv4Header, err::ipv4::HeaderReadError>430 pub fn read_without_version<T: std::io::Read + std::io::Seek + Sized>( 431 reader: &mut T, 432 first_byte: u8, 433 ) -> Result<Ipv4Header, err::ipv4::HeaderReadError> { 434 use err::ipv4::HeaderError::*; 435 use err::ipv4::HeaderReadError::*; 436 437 // read the basic ipv4 header (the header options can be 438 // read only after the internet header length was read) 439 let mut header_raw = [0u8; 20]; 440 header_raw[0] = first_byte; 441 reader.read_exact(&mut header_raw[1..]).map_err(Io)?; 442 443 let ihl = header_raw[0] & 0xf; 444 445 // validate that the internet header length is big enough to 446 // contain a basic IPv4 header without options. 447 if ihl < 5 { 448 return Err(Content(HeaderLengthSmallerThanHeader { ihl })); 449 } 450 451 let (dscp, ecn) = { 452 let value = header_raw[1]; 453 (value >> 2, value & 0b0000_0011) 454 }; 455 let total_len = u16::from_be_bytes([header_raw[2], header_raw[3]]); 456 let identification = u16::from_be_bytes([header_raw[4], header_raw[5]]); 457 let (dont_fragment, more_fragments, fragments_offset) = ( 458 0 != (header_raw[6] & 0b0100_0000), 459 0 != (header_raw[6] & 0b0010_0000), 460 u16::from_be_bytes([header_raw[6] & 0b0001_1111, header_raw[7]]), 461 ); 462 Ok(Ipv4Header { 463 dscp: unsafe { 464 // Safe as only 6 bits were used to decode the 465 // dscp value 466 Ipv4Dscp::new_unchecked(dscp) 467 }, 468 ecn: unsafe { 469 // Safe as only 2 bits were used to decode the 470 // ecn value 471 Ipv4Ecn::new_unchecked(ecn) 472 }, 473 total_len, 474 identification, 475 dont_fragment, 476 more_fragments, 477 fragment_offset: unsafe { 478 // Safe as only 13 bits were used to decode the 479 // fragment offset 480 IpFragOffset::new_unchecked(fragments_offset) 481 }, 482 time_to_live: header_raw[8], 483 protocol: IpNumber(header_raw[9]), 484 header_checksum: u16::from_be_bytes([header_raw[10], header_raw[11]]), 485 source: [ 486 header_raw[12], 487 header_raw[13], 488 header_raw[14], 489 header_raw[15], 490 ], 491 destination: [ 492 header_raw[16], 493 header_raw[17], 494 header_raw[18], 495 header_raw[19], 496 ], 497 options: { 498 let mut options = Ipv4Options::new(); 499 options.len = (ihl - 5) * 4; 500 if false == options.is_empty() { 501 reader.read_exact(options.as_mut()).map_err(Io)?; 502 } 503 options 504 }, 505 }) 506 } 507 508 /// Writes a given IPv4 header to the current position (this method automatically calculates 509 /// the header length and checksum). 510 #[cfg(feature = "std")] 511 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error>512 pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> { 513 // write with recalculations 514 self.write_ipv4_header_internal(writer, self.calc_header_checksum()) 515 } 516 517 /// Writes a given IPv4 header to the current position (this method just writes the specified 518 /// checksum and does not compute it). 519 #[cfg(feature = "std")] 520 #[cfg_attr(docsrs, doc(cfg(feature = "std")))] write_raw<T: std::io::Write + Sized>( &self, writer: &mut T, ) -> Result<(), std::io::Error>521 pub fn write_raw<T: std::io::Write + Sized>( 522 &self, 523 writer: &mut T, 524 ) -> Result<(), std::io::Error> { 525 self.write_ipv4_header_internal(writer, self.header_checksum) 526 } 527 528 /// Returns the serialized header (note that this method does NOT 529 /// update & calculate the checksum). to_bytes(&self) -> ArrayVec<u8,530 pub fn to_bytes(&self) -> ArrayVec<u8, { Ipv4Header::MAX_LEN }> { 531 // prep the values for copy 532 let total_len_be = self.total_len.to_be_bytes(); 533 let id_be = self.identification.to_be_bytes(); 534 let frag_and_flags = { 535 let frag_be: [u8; 2] = self.fragment_offset.value().to_be_bytes(); 536 let flags = { 537 let mut result = 0; 538 if self.dont_fragment { 539 result |= 64; 540 } 541 if self.more_fragments { 542 result |= 32; 543 } 544 result 545 }; 546 [flags | (frag_be[0] & 0x1f), frag_be[1]] 547 }; 548 let header_checksum_be = self.header_checksum.to_be_bytes(); 549 550 #[rustfmt::skip] 551 let mut header_raw: ArrayVec<u8, { Ipv4Header::MAX_LEN } > = [ 552 (4 << 4) | self.ihl(), 553 (self.dscp.value() << 2) | self.ecn.value(), 554 total_len_be[0], 555 total_len_be[1], 556 557 id_be[0], id_be[1], frag_and_flags[0], frag_and_flags[1], 558 559 self.time_to_live, self.protocol.0, header_checksum_be[0], header_checksum_be[1], 560 self.source[0], self.source[1], self.source[2], self.source[3], 561 562 self.destination[0], self.destination[1], self.destination[2], self.destination[3], 563 self.options.buf[0], self.options.buf[1], self.options.buf[2], self.options.buf[3], 564 565 self.options.buf[4], self.options.buf[5], self.options.buf[6], self.options.buf[7], 566 self.options.buf[8], self.options.buf[9], self.options.buf[10], self.options.buf[11], 567 568 self.options.buf[12], self.options.buf[13], self.options.buf[14], self.options.buf[15], 569 self.options.buf[16], self.options.buf[17], self.options.buf[18], self.options.buf[19], 570 571 self.options.buf[20], self.options.buf[21], self.options.buf[22], self.options.buf[23], 572 self.options.buf[24], self.options.buf[25], self.options.buf[26], self.options.buf[27], 573 574 self.options.buf[28], self.options.buf[29], self.options.buf[30], self.options.buf[31], 575 self.options.buf[32], self.options.buf[33], self.options.buf[34], self.options.buf[35], 576 577 self.options.buf[36], self.options.buf[37], self.options.buf[38], self.options.buf[39], 578 ].into(); 579 580 // SAFETY: Safe as header_len() can never exceed the maximum length of an 581 // IPv4 header which is the upper limit of the array vec. 582 unsafe { 583 header_raw.set_len(self.header_len()); 584 } 585 586 header_raw 587 } 588 589 /// Write the given header with the checksum and header length specified in the seperate arguments 590 #[cfg(feature = "std")] write_ipv4_header_internal<T: std::io::Write>( &self, write: &mut T, header_checksum: u16, ) -> Result<(), std::io::Error>591 fn write_ipv4_header_internal<T: std::io::Write>( 592 &self, 593 write: &mut T, 594 header_checksum: u16, 595 ) -> Result<(), std::io::Error> { 596 let total_len_be = self.total_len.to_be_bytes(); 597 let id_be = self.identification.to_be_bytes(); 598 let frag_and_flags = { 599 let frag_be: [u8; 2] = self.fragment_offset.value().to_be_bytes(); 600 let flags = { 601 let mut result = 0; 602 if self.dont_fragment { 603 result |= 64; 604 } 605 if self.more_fragments { 606 result |= 32; 607 } 608 result 609 }; 610 [flags | (frag_be[0] & 0x1f), frag_be[1]] 611 }; 612 let header_checksum_be = header_checksum.to_be_bytes(); 613 614 let header_raw = [ 615 (4 << 4) | self.ihl(), 616 (self.dscp.value() << 2) | self.ecn.value(), 617 total_len_be[0], 618 total_len_be[1], 619 id_be[0], 620 id_be[1], 621 frag_and_flags[0], 622 frag_and_flags[1], 623 self.time_to_live, 624 self.protocol.0, 625 header_checksum_be[0], 626 header_checksum_be[1], 627 self.source[0], 628 self.source[1], 629 self.source[2], 630 self.source[3], 631 self.destination[0], 632 self.destination[1], 633 self.destination[2], 634 self.destination[3], 635 ]; 636 write.write_all(&header_raw)?; 637 638 //options 639 write.write_all(&self.options)?; 640 641 //done 642 Ok(()) 643 } 644 645 /// Calculate header checksum of the current ipv4 header. calc_header_checksum(&self) -> u16646 pub fn calc_header_checksum(&self) -> u16 { 647 checksum::Sum16BitWords::new() 648 .add_2bytes([ 649 (4 << 4) | self.ihl(), 650 (self.dscp.value() << 2) | self.ecn.value(), 651 ]) 652 .add_2bytes(self.total_len.to_be_bytes()) 653 .add_2bytes(self.identification.to_be_bytes()) 654 .add_2bytes({ 655 let frag_off_be = self.fragment_offset.value().to_be_bytes(); 656 let flags = { 657 let mut result = 0; 658 if self.dont_fragment { 659 result |= 64; 660 } 661 if self.more_fragments { 662 result |= 32; 663 } 664 result 665 }; 666 [flags | (frag_off_be[0] & 0x1f), frag_off_be[1]] 667 }) 668 .add_2bytes([self.time_to_live, self.protocol.0]) 669 .add_4bytes(self.source) 670 .add_4bytes(self.destination) 671 .add_slice(&self.options) 672 .ones_complement() 673 .to_be() 674 } 675 676 /// Returns true if the payload is fragmented. 677 /// 678 /// Either data is missing (more_fragments set) or there is 679 /// an fragment offset. 680 #[inline] is_fragmenting_payload(&self) -> bool681 pub fn is_fragmenting_payload(&self) -> bool { 682 self.more_fragments || (0 != self.fragment_offset.value()) 683 } 684 } 685 686 impl Default for Ipv4Header { default() -> Ipv4Header687 fn default() -> Ipv4Header { 688 Ipv4Header { 689 dscp: Default::default(), 690 ecn: Default::default(), 691 total_len: 0, 692 identification: 0, 693 dont_fragment: true, 694 more_fragments: false, 695 fragment_offset: Default::default(), 696 time_to_live: 0, 697 protocol: IpNumber(255), 698 header_checksum: 0, 699 source: [0; 4], 700 destination: [0; 4], 701 options: Ipv4Options::new(), 702 } 703 } 704 } 705 706 #[cfg(test)] 707 mod test { 708 use crate::{ 709 err::{Layer, LenError, ValueTooBigError, ValueType}, 710 test_gens::*, 711 *, 712 }; 713 use alloc::{format, vec::Vec}; 714 use arrayvec::ArrayVec; 715 use proptest::prelude::*; 716 use std::io::Cursor; 717 718 #[test] default()719 fn default() { 720 let default: Ipv4Header = Default::default(); 721 assert_eq!(5, default.ihl()); 722 assert_eq!(0, default.dscp.value()); 723 assert_eq!(0, default.ecn.value()); 724 assert_eq!(0, default.total_len); 725 assert_eq!(0, default.identification); 726 assert_eq!(true, default.dont_fragment); 727 assert_eq!(false, default.more_fragments); 728 assert_eq!(0, default.fragment_offset.value()); 729 assert_eq!(0, default.time_to_live); 730 assert_eq!(IpNumber(255), default.protocol); 731 assert_eq!(0, default.header_checksum); 732 assert_eq!([0; 4], default.source); 733 assert_eq!([0; 4], default.destination); 734 assert_eq!(&default.options[..], &[]); 735 } 736 737 proptest! { 738 #[test] 739 fn debug(input in ipv4_any()) { 740 assert_eq!(&format!("Ipv4Header {{ dscp: {:?}, ecn: {:?}, total_len: {}, identification: {}, dont_fragment: {}, more_fragments: {}, fragment_offset: {:?}, time_to_live: {}, protocol: {:?}, header_checksum: {}, source: {:?}, destination: {:?}, options: {:?} }}", 741 input.dscp, 742 input.ecn, 743 input.total_len, 744 input.identification, 745 input.dont_fragment, 746 input.more_fragments, 747 input.fragment_offset, 748 input.time_to_live, 749 input.protocol, 750 input.header_checksum, 751 input.source, 752 input.destination, 753 input.options 754 ), 755 &format!("{:?}", input) 756 ); 757 } 758 } 759 760 proptest! { 761 #[test] 762 fn eq(a in ipv4_any(), 763 b in ipv4_any()) 764 { 765 //check identity equality 766 assert!(a == a); 767 assert!(b == b); 768 769 //check every field 770 //differentiated_services_code_point 771 assert_eq!( 772 a.dscp == b.dscp, 773 a == { 774 let mut other = a.clone(); 775 other.dscp = b.dscp; 776 other 777 } 778 ); 779 //explicit_congestion_notification 780 assert_eq!( 781 a.ecn == b.ecn, 782 a == { 783 let mut other = a.clone(); 784 other.ecn = b.ecn; 785 other 786 } 787 ); 788 //total_len 789 assert_eq!( 790 a.total_len == b.total_len, 791 a == { 792 let mut other = a.clone(); 793 other.total_len = b.total_len; 794 other 795 } 796 ); 797 //identification 798 assert_eq!( 799 a.identification == b.identification, 800 a == { 801 let mut other = a.clone(); 802 other.identification = b.identification; 803 other 804 } 805 ); 806 //dont_fragment 807 assert_eq!( 808 a.dont_fragment == b.dont_fragment, 809 a == { 810 let mut other = a.clone(); 811 other.dont_fragment = b.dont_fragment; 812 other 813 } 814 ); 815 //more_fragments 816 assert_eq!( 817 a.more_fragments == b.more_fragments, 818 a == { 819 let mut other = a.clone(); 820 other.more_fragments = b.more_fragments; 821 other 822 } 823 ); 824 //fragments_offset 825 assert_eq!( 826 a.fragment_offset == b.fragment_offset, 827 a == { 828 let mut other = a.clone(); 829 other.fragment_offset = b.fragment_offset; 830 other 831 } 832 ); 833 //time_to_live 834 assert_eq!( 835 a.time_to_live == b.time_to_live, 836 a == { 837 let mut other = a.clone(); 838 other.time_to_live = b.time_to_live; 839 other 840 } 841 ); 842 //protocol 843 assert_eq!( 844 a.protocol == b.protocol, 845 a == { 846 let mut other = a.clone(); 847 other.protocol = b.protocol; 848 other 849 } 850 ); 851 //header_checksum 852 assert_eq!( 853 a.header_checksum == b.header_checksum, 854 a == { 855 let mut other = a.clone(); 856 other.header_checksum = b.header_checksum; 857 other 858 } 859 ); 860 //source 861 assert_eq!( 862 a.source == b.source, 863 a == { 864 let mut other = a.clone(); 865 other.source = b.source; 866 other 867 } 868 ); 869 //destination 870 assert_eq!( 871 a.destination == b.destination, 872 a == { 873 let mut other = a.clone(); 874 other.destination = b.destination; 875 other 876 } 877 ); 878 879 //options 880 assert_eq!( 881 a.options == b.options, 882 a == { 883 let mut other = a.clone(); 884 other.options = b.options; 885 other 886 } 887 ); 888 } 889 } 890 891 proptest! { 892 #[test] 893 fn hash(header in ipv4_any()) { 894 use std::collections::hash_map::DefaultHasher; 895 use core::hash::{Hash, Hasher}; 896 let a = { 897 let mut hasher = DefaultHasher::new(); 898 header.hash(&mut hasher); 899 hasher.finish() 900 }; 901 let b = { 902 let mut hasher = DefaultHasher::new(); 903 header.hash(&mut hasher); 904 hasher.finish() 905 }; 906 assert_eq!(a, b); 907 } 908 } 909 910 proptest! { 911 #[test] 912 fn new( 913 source_ip in prop::array::uniform4(any::<u8>()), 914 dest_ip in prop::array::uniform4(any::<u8>()), 915 ttl in any::<u8>(), 916 ok_payload_len in 0u16..=(u16::MAX - Ipv4Header::MIN_LEN as u16), 917 err_payload_len in (u16::MAX - Ipv4Header::MIN_LEN as u16 + 1)..=u16::MAX 918 ) { 919 // ok case 920 { 921 let result = Ipv4Header::new( 922 ok_payload_len, 923 ttl, 924 ip_number::UDP, 925 source_ip, 926 dest_ip 927 ).unwrap(); 928 929 assert_eq!(result.dscp.value(), 0); 930 assert_eq!(result.ecn.value(), 0); 931 assert_eq!(result.total_len, ok_payload_len + Ipv4Header::MIN_LEN as u16); 932 assert_eq!(result.identification, 0); 933 assert_eq!(result.dont_fragment, true); 934 assert_eq!(result.more_fragments, false); 935 assert_eq!(result.fragment_offset.value(), 0); 936 assert_eq!(result.time_to_live, ttl); 937 assert_eq!(result.protocol, ip_number::UDP); 938 assert_eq!(result.header_checksum, 0); 939 assert_eq!(result.source, source_ip); 940 assert_eq!(result.destination, dest_ip); 941 assert_eq!(result.options.as_slice(), &[]); 942 } 943 // err 944 { 945 assert_eq!( 946 Ipv4Header::new( 947 err_payload_len, 948 ttl, 949 ip_number::UDP, 950 source_ip, 951 dest_ip 952 ), 953 Err(ValueTooBigError::<u16>{ 954 actual: err_payload_len, 955 max_allowed: u16::MAX - Ipv4Header::MIN_LEN as u16, 956 value_type: ValueType::Ipv4PayloadLength, 957 }) 958 ); 959 } 960 } 961 } 962 963 proptest! { 964 #[test] 965 fn ihl(header in ipv4_any()) { 966 assert_eq!(header.ihl(), (header.header_len() / 4) as u8); 967 } 968 } 969 970 proptest! { 971 #[test] 972 fn header_len(header in ipv4_any()) { 973 assert_eq!(header.header_len(), 20 + usize::from(header.options.len())); 974 } 975 } 976 977 proptest! { 978 #[test] 979 fn payload_len( 980 header in ipv4_any() 981 ) { 982 // ok case 983 assert_eq!( 984 header.payload_len().unwrap(), 985 header.total_len - 20 - (header.options.len() as u16) 986 ); 987 // err case 988 for bad_len in 0u16..(header.header_len() as u16) { 989 let mut header = header.clone(); 990 header.total_len = bad_len; 991 assert_eq!( 992 header.payload_len().unwrap_err(), 993 LenError{ 994 required_len: header.header_len(), 995 len: bad_len.into(), 996 len_source: LenSource::Ipv4HeaderTotalLen, 997 layer: Layer::Ipv4Packet, 998 layer_start_offset: 0 999 } 1000 ); 1001 } 1002 1003 } 1004 } 1005 1006 #[test] set_payload_len()1007 fn set_payload_len() { 1008 let mut header = Ipv4Header::new(0, 0, ip_number::UDP, [0; 4], [0; 4]).unwrap(); 1009 1010 //add options (to make sure they are included in the calculation) 1011 header.options = [1, 2, 3, 4].into(); 1012 1013 //zero check 1014 assert!(header.set_payload_len(0).is_ok()); 1015 assert_eq!(header.total_len, 24); 1016 1017 //max check 1018 const MAX: usize = (core::u16::MAX as usize) - Ipv4Header::MIN_LEN - 4; 1019 assert!(header.set_payload_len(MAX).is_ok()); 1020 assert_eq!(header.total_len, core::u16::MAX); 1021 1022 const OVER_MAX: usize = MAX + 1; 1023 assert_eq!( 1024 header.set_payload_len(OVER_MAX), 1025 Err(ValueTooBigError { 1026 actual: OVER_MAX, 1027 max_allowed: usize::from(u16::MAX) - header.header_len(), 1028 value_type: ValueType::Ipv4PayloadLength 1029 }) 1030 ); 1031 } 1032 1033 proptest! { 1034 #[test] 1035 fn max_payload_len(header in ipv4_any()) { 1036 assert_eq!(header.max_payload_len(), core::u16::MAX - 20 - u16::from(header.options.len_u8())); 1037 } 1038 } 1039 1040 #[test] 1041 #[allow(deprecated)] set_options()1042 fn set_options() { 1043 //length of 1 1044 { 1045 let mut header: Ipv4Header = Default::default(); 1046 let options = [1, 2, 3, 4]; 1047 assert_eq!(header.set_options(&options), Ok(())); 1048 1049 assert_eq!(&options, header.options()); 1050 assert_eq!(24, header.header_len()); 1051 assert_eq!(0, header.total_len); 1052 assert_eq!(6, header.ihl()); 1053 1054 //length 0 1055 assert_eq!(header.set_options(&[]), Ok(())); 1056 1057 assert_eq!(&options[..0], header.options()); 1058 assert_eq!(20, header.header_len()); 1059 assert_eq!(0, header.total_len); 1060 assert_eq!(5, header.ihl()); 1061 } 1062 //maximum length (40) 1063 { 1064 let mut header: Ipv4Header = Default::default(); 1065 let options = [ 1066 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 1067 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 1068 ]; 1069 assert_eq!(header.set_options(&options), Ok(())); 1070 1071 assert_eq!(&options[..], header.options()); 1072 assert_eq!(60, header.header_len()); 1073 assert_eq!(0, header.total_len); 1074 assert_eq!(15, header.ihl()); 1075 } 1076 //errors 1077 { 1078 let buffer: [u8; 50] = [0; 50]; 1079 for len in &[ 1080 1usize, 2, 3, //unaligned 1081 5, 6, 7, 41, 44, //over max 1082 ] { 1083 let mut header: Ipv4Header = Default::default(); 1084 1085 //expect an error 1086 use self::err::ipv4::BadOptionsLen; 1087 assert_eq!( 1088 Err(BadOptionsLen { bad_len: *len }), 1089 header.set_options(&buffer[..*len]) 1090 ); 1091 1092 //check value was not taken 1093 assert_eq!(&buffer[..0], header.options()); 1094 assert_eq!(20, header.header_len()); 1095 assert_eq!(0, header.total_len); 1096 assert_eq!(5, header.ihl()); 1097 } 1098 } 1099 } 1100 1101 proptest! { 1102 #[test] 1103 #[allow(deprecated)] 1104 fn read_from_slice(ref input in ipv4_any()) { 1105 //serialize 1106 let mut buffer: Vec<u8> = Vec::with_capacity(input.header_len()); 1107 input.write_raw(&mut buffer).unwrap(); 1108 assert_eq!(input.header_len(), buffer.len()); 1109 1110 //deserialize (read_from_slice) 1111 let result = Ipv4Header::read_from_slice(&buffer).unwrap(); 1112 assert_eq!(input, &result.0); 1113 assert_eq!(&buffer[usize::from(input.header_len())..], result.1); 1114 } 1115 } 1116 1117 proptest! { 1118 #[test] 1119 fn from_slice(header in ipv4_any()) { 1120 use err::ipv4::HeaderError::*; 1121 use err::ipv4::HeaderSliceError::*; 1122 1123 // ok 1124 { 1125 let mut buffer = ArrayVec::<u8, { Ipv4Header::MAX_LEN + 1 }>::new(); 1126 buffer.try_extend_from_slice(&header.to_bytes()).unwrap(); 1127 buffer.try_extend_from_slice(&[1]).unwrap(); 1128 1129 let (actual_header, actual_rest) = Ipv4Header::from_slice(&buffer).unwrap(); 1130 assert_eq!(actual_header, header); 1131 assert_eq!(actual_rest, &[1]); 1132 } 1133 1134 // unexpected end of slice 1135 { 1136 let buffer = header.to_bytes(); 1137 for len in 0..header.header_len() { 1138 assert_eq!( 1139 Ipv4Header::from_slice(&buffer[..len]), 1140 Err(Len(err::LenError{ 1141 required_len: if len < Ipv4Header::MIN_LEN { 1142 Ipv4Header::MIN_LEN 1143 } else { 1144 header.header_len() 1145 }, 1146 len: len, 1147 len_source: LenSource::Slice, 1148 layer: err::Layer::Ipv4Header, 1149 layer_start_offset: 0, 1150 })) 1151 ); 1152 } 1153 } 1154 1155 // version error 1156 for version_number in 0u8..0b1111u8 { 1157 if 4 != version_number { 1158 let mut buffer = header.to_bytes(); 1159 // inject the bad ihl 1160 buffer[0] = (version_number << 4) | (buffer[0] & 0b1111); 1161 // expect an error 1162 assert_eq!( 1163 Ipv4Header::from_slice(&buffer).unwrap_err(), 1164 Content(UnexpectedVersion{ 1165 version_number, 1166 }) 1167 ); 1168 } 1169 } 1170 1171 // ihl too small error 1172 for ihl in 0u8..5u8 { 1173 let mut buffer = header.to_bytes(); 1174 // inject the bad ihl 1175 buffer[0] = (4 << 4) | ihl; 1176 // expect an error 1177 assert_eq!( 1178 Ipv4Header::from_slice(&buffer).unwrap_err(), 1179 Content(HeaderLengthSmallerThanHeader{ 1180 ihl, 1181 }) 1182 ); 1183 } 1184 } 1185 } 1186 1187 proptest! { 1188 #[test] 1189 fn read_and_read_without_version(header in ipv4_any()) { 1190 use err::ipv4::HeaderError::*; 1191 use std::io::Cursor; 1192 1193 // ok 1194 { 1195 let buffer = header.to_bytes(); 1196 1197 // read 1198 { 1199 let mut cursor = Cursor::new(&buffer); 1200 let actual_header = Ipv4Header::read(&mut cursor).unwrap(); 1201 assert_eq!(actual_header, header); 1202 assert_eq!(cursor.position(), header.header_len() as u64); 1203 } 1204 // read_without_version 1205 { 1206 let mut cursor = Cursor::new(&buffer[1..]); 1207 let actual_header = Ipv4Header::read_without_version(&mut cursor, buffer[0]).unwrap(); 1208 assert_eq!(actual_header, header); 1209 assert_eq!(cursor.position(), (header.header_len() - 1) as u64); 1210 } 1211 } 1212 1213 // io error 1214 { 1215 let buffer = header.to_bytes(); 1216 for len in 0..header.header_len() { 1217 // read 1218 { 1219 let mut cursor = Cursor::new(&buffer[..len]); 1220 let err = Ipv4Header::read(&mut cursor).unwrap_err(); 1221 assert!(err.io_error().is_some()); 1222 } 1223 1224 // read_without_version 1225 if len > 0 { 1226 let mut cursor = Cursor::new(&buffer[1..len]); 1227 let err = Ipv4Header::read_without_version(&mut cursor, buffer[0]).unwrap_err(); 1228 assert!(err.io_error().is_some()); 1229 } 1230 } 1231 } 1232 1233 // version error 1234 for version_number in 0u8..0b1111u8 { 1235 if 4 != version_number { 1236 let mut buffer = header.to_bytes(); 1237 // inject the bad version number 1238 buffer[0] = (version_number << 4) | (buffer[0] & 0b1111); 1239 1240 // expect an error 1241 // read 1242 { 1243 let mut cursor = Cursor::new(&buffer[..]); 1244 let err = Ipv4Header::read(&mut cursor) 1245 .unwrap_err() 1246 .content_error() 1247 .unwrap(); 1248 assert_eq!(err, UnexpectedVersion{ version_number }); 1249 } 1250 1251 // read_without_version skipped as version is not checked 1252 } 1253 } 1254 1255 // ihl too small error 1256 for ihl in 0u8..5u8 { 1257 let mut buffer = header.to_bytes(); 1258 // inject the bad ihl 1259 buffer[0] = (4 << 4) | ihl; 1260 // expect an error 1261 // read 1262 { 1263 let mut cursor = Cursor::new(&buffer[..]); 1264 let err = Ipv4Header::read(&mut cursor) 1265 .unwrap_err() 1266 .content_error() 1267 .unwrap(); 1268 assert_eq!(err, HeaderLengthSmallerThanHeader{ ihl }); 1269 } 1270 1271 // read_without_version 1272 { 1273 let mut cursor = Cursor::new(&buffer[1..]); 1274 let err = Ipv4Header::read_without_version(&mut cursor, buffer[0]) 1275 .unwrap_err() 1276 .content_error() 1277 .unwrap(); 1278 assert_eq!(err, HeaderLengthSmallerThanHeader{ ihl }); 1279 } 1280 } 1281 } 1282 } 1283 1284 proptest! { 1285 #[test] 1286 fn write(ref base_header in ipv4_any()) { 1287 use std::io::Cursor; 1288 1289 let header = { 1290 let mut header = base_header.clone(); 1291 // set the header checksum to something else to 1292 // ensure it is calculated during the write call 1293 header.header_checksum = 0; 1294 header 1295 }; 1296 1297 // normal write 1298 { 1299 //serialize 1300 let buffer = { 1301 let mut buffer: Vec<u8> = Vec::with_capacity(header.header_len()); 1302 header.write(&mut buffer).unwrap(); 1303 buffer 1304 }; 1305 assert_eq!(header.header_len(), buffer.len()); 1306 1307 //deserialize 1308 let mut cursor = Cursor::new(&buffer); 1309 let result = Ipv4Header::read(&mut cursor).unwrap(); 1310 assert_eq!(header.header_len(), cursor.position() as usize); 1311 1312 //check equivalence (with calculated checksum) 1313 let header_with_checksum = { 1314 let mut h = header.clone(); 1315 h.header_checksum = h.calc_header_checksum(); 1316 h 1317 }; 1318 assert_eq!(header_with_checksum, result); 1319 } 1320 1321 // io error 1322 for len in 0..header.header_len() { 1323 let mut buffer = [0u8; Ipv4Header::MAX_LEN]; 1324 let mut cursor = Cursor::new(&mut buffer[..len]); 1325 assert!( 1326 header.write(&mut cursor).is_err() 1327 ); 1328 } 1329 } 1330 } 1331 1332 proptest! { 1333 #[test] 1334 fn write_raw(base_header in ipv4_any()) { 1335 // normal write 1336 { 1337 //serialize 1338 let buffer = { 1339 let mut buffer: Vec<u8> = Vec::with_capacity(base_header.header_len()); 1340 base_header.write_raw(&mut buffer).unwrap(); 1341 buffer 1342 }; 1343 assert_eq!(base_header.header_len(), buffer.len()); 1344 1345 // decode and check for equality 1346 assert_eq!( 1347 Ipv4Header::from_slice(&buffer).unwrap().0, 1348 base_header 1349 ); 1350 } 1351 1352 // io error 1353 for len in 0..base_header.header_len() { 1354 let mut buffer = [0u8; Ipv4Header::MAX_LEN]; 1355 let mut cursor = Cursor::new(&mut buffer[..len]); 1356 assert!( 1357 base_header.write_raw(&mut cursor).is_err() 1358 ); 1359 } 1360 } 1361 } 1362 1363 proptest! { 1364 #[test] 1365 fn to_bytes(base_header in ipv4_any()) { 1366 let bytes = base_header.to_bytes(); 1367 assert_eq!( 1368 base_header, 1369 Ipv4HeaderSlice::from_slice(&bytes).unwrap().to_header() 1370 ); 1371 } 1372 } 1373 1374 #[test] calc_header_checksum()1375 fn calc_header_checksum() { 1376 let base: Ipv4Header = Ipv4Header::new( 1377 40, 1378 4, // ttl 1379 ip_number::UDP, 1380 [192, 168, 1, 1], // source 1381 [212, 10, 11, 123], // destination 1382 ) 1383 .unwrap(); 1384 1385 //without options 1386 { 1387 //dont_fragment && !more_fragments 1388 let header = base.clone(); 1389 assert_eq!(0xd582, header.calc_header_checksum()); 1390 // !dont_fragment && more_fragments 1391 let header = { 1392 let mut header = base.clone(); 1393 header.dont_fragment = false; 1394 header.more_fragments = true; 1395 header 1396 }; 1397 assert_eq!(0xf582, header.calc_header_checksum()); 1398 } 1399 //with options 1400 { 1401 let header = { 1402 let mut header = base.clone(); 1403 header.options = [1, 2, 3, 4, 5, 6, 7, 8].into(); 1404 header.total_len = (header.header_len() + 32) as u16; 1405 header 1406 }; 1407 assert_eq!(0xc36e, header.calc_header_checksum()); 1408 } 1409 } 1410 1411 #[test] is_fragmenting_payload()1412 fn is_fragmenting_payload() { 1413 // not fragmenting 1414 { 1415 let mut header: Ipv4Header = Default::default(); 1416 header.fragment_offset = 0.try_into().unwrap(); 1417 header.more_fragments = false; 1418 assert_eq!(false, header.is_fragmenting_payload()); 1419 } 1420 1421 // fragmenting based on offset 1422 { 1423 let mut header: Ipv4Header = Default::default(); 1424 header.fragment_offset = 1.try_into().unwrap(); 1425 header.more_fragments = false; 1426 assert!(header.is_fragmenting_payload()); 1427 } 1428 1429 // fragmenting based on more_fragments 1430 { 1431 let mut header: Ipv4Header = Default::default(); 1432 header.fragment_offset = 0.try_into().unwrap(); 1433 header.more_fragments = true; 1434 assert!(header.is_fragmenting_payload()); 1435 } 1436 } 1437 } 1438