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