Thanks to visit codestin.com
Credit goes to docs.rs

etherparse/net/
ipv4_header.rs

1use crate::{
2    err::{ValueTooBigError, ValueType},
3    *,
4};
5use 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 use case 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)]
36pub struct Ipv4Header {
37    /// Differentiated Services Code Point
38    pub dscp: IpDscp,
39    /// Explicit Congestion Notification
40    pub ecn: IpEcn,
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
69impl 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    /// ```
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]
192    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]
229    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]
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    /// ```
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]
344    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    )]
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    )]
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]
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 separate 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 separated 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.
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")))]
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")))]
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                IpDscp::new_unchecked(dscp)
467            },
468            ecn: unsafe {
469                // Safe as only 2 bits were used to decode the
470                // ecn value
471                IpEcn::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")))]
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")))]
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).
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 separate arguments
590    #[cfg(feature = "std")]
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.
646    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]
681    pub fn is_fragmenting_payload(&self) -> bool {
682        self.more_fragments || (0 != self.fragment_offset.value())
683    }
684}
685
686impl Default for Ipv4Header {
687    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)]
707mod 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]
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]
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)]
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]
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]
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}