Skip to main content

packet_formats/
ipv4.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Parsing and serialization of IPv4 packets.
6//!
7//! The IPv4 packet format is defined in [RFC 791 Section 3.1].
8//!
9//! [RFC 791 Section 3.1]: https://datatracker.ietf.org/doc/html/rfc791#section-3.1
10
11use alloc::vec::Vec;
12use core::borrow::Borrow;
13use core::convert::Infallible as Never;
14use core::fmt::{self, Debug, Formatter};
15use core::ops::Range;
16
17use internet_checksum::Checksum;
18use log::debug;
19use net_types::ip::{GenericOverIp, IpAddress, Ipv4, Ipv4Addr, Ipv4SourceAddr, Ipv6Addr};
20use packet::records::RecordsIter;
21use packet::records::options::{OptionSequenceBuilder, OptionsRaw};
22use packet::{
23    BufferProvider, BufferView, BufferViewMut, EmptyBuf, FragmentedBytesMut, FromRaw,
24    GrowBufferMut, InnerPacketBuilder, LayoutBufferAlloc, MaybeParsed, PacketBuilder,
25    PacketConstraints, ParsablePacket, ParseMetadata, PartialPacketBuilder, PartialSerializeResult,
26    PartialSerializer, SerializeError, SerializeTarget, Serializer,
27};
28use zerocopy::byteorder::network_endian::U16;
29use zerocopy::{
30    FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, SplitByteSliceMut, Unaligned,
31};
32
33use crate::error::ParseError;
34use crate::ip::{
35    DscpAndEcn, FragmentOffset, IpExt, IpPacketBuilder, IpProto, Ipv4Proto, Ipv6Proto, Nat64Error,
36    Nat64TranslationResult,
37};
38use crate::ipv6::Ipv6PacketBuilder;
39use crate::tcp::{TcpParseArgs, TcpSegment};
40use crate::udp::{UdpPacket, UdpParseArgs};
41
42pub(crate) use self::inner::IPV4_MIN_HDR_LEN;
43use self::options::{Ipv4Option, Ipv4OptionsImpl};
44
45/// The length of the fixed prefix of an IPv4 header (preceding the options).
46pub const HDR_PREFIX_LEN: usize = 20;
47
48/// The maximum length of an IPv4 header.
49pub const MAX_HDR_LEN: usize = 60;
50
51/// The maximum length for options in an IPv4 header.
52pub const MAX_OPTIONS_LEN: usize = MAX_HDR_LEN - HDR_PREFIX_LEN;
53
54/// The range of bytes within an IPv4 header buffer that the fragment data fields uses.
55const IPV4_FRAGMENT_DATA_BYTE_RANGE: Range<usize> = 4..8;
56
57/// The type of an IPv4 packet fragment.
58#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
59#[allow(missing_docs)]
60pub enum Ipv4FragmentType {
61    InitialFragment,
62    NonInitialFragment,
63}
64
65/// The prefix of the IPv4 header which precedes any header options and the
66/// body.
67#[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
68#[repr(C)]
69pub struct HeaderPrefix {
70    version_ihl: u8,
71    dscp_and_ecn: DscpAndEcn,
72    total_len: U16,
73    id: U16,
74    flags_frag_off: [u8; 2],
75    ttl: u8,
76    proto: u8,
77    hdr_checksum: [u8; 2],
78    src_ip: Ipv4Addr,
79    dst_ip: Ipv4Addr,
80}
81
82const IP_VERSION: u8 = 4;
83const VERSION_OFFSET: u8 = 4;
84const IHL_MASK: u8 = 0xF;
85const IHL_MAX: u8 = (1 << VERSION_OFFSET) - 1;
86const FLAGS_OFFSET: u8 = 13;
87const FLAGS_MAX: u8 = (1 << (16 - FLAGS_OFFSET)) - 1;
88const FRAG_OFF_MAX: u16 = (1 << FLAGS_OFFSET) - 1;
89
90impl HeaderPrefix {
91    #[allow(clippy::too_many_arguments)]
92    fn new(
93        ihl: u8,
94        dscp_and_ecn: DscpAndEcn,
95        total_len: u16,
96        id: u16,
97        flags: u8,
98        frag_off: u16,
99        ttl: u8,
100        proto: u8,
101        hdr_checksum: [u8; 2],
102        src_ip: Ipv4Addr,
103        dst_ip: Ipv4Addr,
104    ) -> HeaderPrefix {
105        debug_assert!(ihl <= IHL_MAX);
106        debug_assert!(flags <= FLAGS_MAX);
107        debug_assert!(frag_off <= FRAG_OFF_MAX);
108
109        HeaderPrefix {
110            version_ihl: (IP_VERSION << VERSION_OFFSET) | ihl,
111            dscp_and_ecn,
112            total_len: U16::new(total_len),
113            id: U16::new(id),
114            flags_frag_off: ((u16::from(flags) << FLAGS_OFFSET) | frag_off).to_be_bytes(),
115            ttl,
116            proto,
117            src_ip,
118            dst_ip,
119            hdr_checksum,
120        }
121    }
122
123    fn version(&self) -> u8 {
124        self.version_ihl >> VERSION_OFFSET
125    }
126
127    /// Get the Internet Header Length (IHL).
128    pub(crate) fn ihl(&self) -> u8 {
129        self.version_ihl & IHL_MASK
130    }
131
132    /// The More Fragments (MF) flag.
133    pub(crate) fn mf_flag(&self) -> bool {
134        // `FLAGS_OFFSET` refers to the offset within the 2-byte array
135        // containing both the flags and the fragment offset. Since we're
136        // accessing the first byte directly, we shift by an extra `FLAGS_OFFSET
137        // - 8` bits, not by an extra `FLAGS_OFFSET` bits.
138        self.flags_frag_off[0] & (1 << ((FLAGS_OFFSET - 8) + MF_FLAG_OFFSET)) > 0
139    }
140}
141
142/// Provides common access to IPv4 header fields.
143///
144/// `Ipv4Header` provides access to IPv4 header fields as a common
145/// implementation for both [`Ipv4Packet`] and [`Ipv4PacketRaw`].
146pub trait Ipv4Header {
147    /// Gets a reference to the IPv4 [`HeaderPrefix`].
148    fn get_header_prefix(&self) -> &HeaderPrefix;
149
150    /// The Differentiated Services Code Point (DSCP) and the Explicit Congestion Notification (ECN).
151    fn dscp_and_ecn(&self) -> DscpAndEcn {
152        self.get_header_prefix().dscp_and_ecn
153    }
154
155    /// The identification.
156    fn id(&self) -> u16 {
157        self.get_header_prefix().id.get()
158    }
159
160    /// The Don't Fragment (DF) flag.
161    fn df_flag(&self) -> bool {
162        // the flags are the top 3 bits, so we need to shift by an extra 5 bits
163        self.get_header_prefix().flags_frag_off[0] & (1 << (5 + DF_FLAG_OFFSET)) > 0
164    }
165
166    /// The More Fragments (MF) flag.
167    fn mf_flag(&self) -> bool {
168        self.get_header_prefix().mf_flag()
169    }
170
171    /// The fragment offset.
172    fn fragment_offset(&self) -> FragmentOffset {
173        FragmentOffset::new_with_lsb(U16::from_bytes(self.get_header_prefix().flags_frag_off).get())
174    }
175
176    /// The fragment type.
177    ///
178    /// `p.fragment_type()` returns [`Ipv4FragmentType::InitialFragment`] if
179    /// `p.fragment_offset() == 0` and [`Ipv4FragmentType::NonInitialFragment`]
180    /// otherwise.
181    fn fragment_type(&self) -> Ipv4FragmentType {
182        match self.fragment_offset().into_raw() {
183            0 => Ipv4FragmentType::InitialFragment,
184            _ => Ipv4FragmentType::NonInitialFragment,
185        }
186    }
187
188    /// The Time To Live (TTL).
189    fn ttl(&self) -> u8 {
190        self.get_header_prefix().ttl
191    }
192
193    /// The IP Protocol.
194    ///
195    /// `proto` returns the `Ipv4Proto` from the protocol field.
196    fn proto(&self) -> Ipv4Proto {
197        Ipv4Proto::from(self.get_header_prefix().proto)
198    }
199
200    /// The source IP address.
201    fn src_ip(&self) -> Ipv4Addr {
202        self.get_header_prefix().src_ip
203    }
204
205    /// The destination IP address.
206    fn dst_ip(&self) -> Ipv4Addr {
207        self.get_header_prefix().dst_ip
208    }
209
210    /// Construct a builder with the same contents as this header.
211    fn builder(&self) -> Ipv4PacketBuilder {
212        let mut s = Ipv4PacketBuilder {
213            id: self.id(),
214            dscp_and_ecn: self.dscp_and_ecn(),
215            flags: 0,
216            frag_off: self.fragment_offset().into_raw(),
217            ttl: self.ttl(),
218            proto: self.get_header_prefix().proto.into(),
219            src_ip: self.src_ip(),
220            dst_ip: self.dst_ip(),
221        };
222        s.df_flag(self.df_flag());
223        s.mf_flag(self.mf_flag());
224        s
225    }
226}
227
228impl Ipv4Header for HeaderPrefix {
229    fn get_header_prefix(&self) -> &HeaderPrefix {
230        self
231    }
232}
233
234/// An IPv4 packet.
235///
236/// An `Ipv4Packet` shares its underlying memory with the byte slice it was
237/// parsed from or serialized to, meaning that no copying or extra allocation is
238/// necessary.
239///
240/// An `Ipv4Packet` - whether parsed using `parse` or created using
241/// `Ipv4PacketBuilder` - maintains the invariant that the checksum is always
242/// valid.
243pub struct Ipv4Packet<B> {
244    hdr_prefix: Ref<B, HeaderPrefix>,
245    options: Options<B>,
246    body: B,
247}
248
249impl<B: SplitByteSlice, I: IpExt> GenericOverIp<I> for Ipv4Packet<B> {
250    type Type = <I as IpExt>::Packet<B>;
251}
252
253impl<B: SplitByteSlice> Ipv4Header for Ipv4Packet<B> {
254    fn get_header_prefix(&self) -> &HeaderPrefix {
255        &self.hdr_prefix
256    }
257}
258
259impl<B: SplitByteSlice> PartialSerializer for Ipv4Packet<B> {
260    fn partial_serialize(
261        &self,
262        _outer: PacketConstraints,
263        mut buffer: &mut [u8],
264    ) -> Result<PartialSerializeResult, SerializeError<Never>> {
265        let hdr_prefix = Ref::bytes(&self.hdr_prefix);
266        let options = self.options.bytes();
267
268        let mut buffer = &mut buffer;
269        let bytes_written = buffer.write_bytes_front_allow_partial(hdr_prefix)
270            + buffer.write_bytes_front_allow_partial(options)
271            + buffer.write_bytes_front_allow_partial(&self.body);
272        let total_size = hdr_prefix.len() + options.len() + self.body.len();
273
274        Ok(PartialSerializeResult { bytes_written, total_size })
275    }
276}
277
278impl<B: SplitByteSlice> ParsablePacket<B, ()> for Ipv4Packet<B> {
279    type Error = ParseError;
280
281    fn parse_metadata(&self) -> ParseMetadata {
282        ParseMetadata::from_packet(self.header_len(), self.body.len(), 0)
283    }
284
285    fn parse<BV: BufferView<B>>(buffer: BV, _args: ()) -> Result<Self, ParseError> {
286        Ipv4PacketRaw::<B>::parse(buffer, ()).and_then(Ipv4Packet::try_from_raw)
287    }
288}
289
290impl<B: SplitByteSlice> FromRaw<Ipv4PacketRaw<B>, ()> for Ipv4Packet<B> {
291    type Error = ParseError;
292
293    fn try_from_raw_with(raw: Ipv4PacketRaw<B>, _args: ()) -> Result<Self, Self::Error> {
294        // TODO(https://fxbug.dev/42157630): Some of the errors below should return an
295        // `ParameterProblem` error instead of a `ParseError`.
296        let hdr_prefix = raw.hdr_prefix;
297        let hdr_bytes = (hdr_prefix.ihl() * 4) as usize;
298
299        if hdr_bytes < HDR_PREFIX_LEN {
300            return debug_err!(Err(ParseError::Format), "invalid IHL: {}", hdr_prefix.ihl());
301        }
302
303        let options = match raw.options {
304            MaybeParsed::Incomplete(_) => {
305                return debug_err!(Err(ParseError::Format), "Incomplete options");
306            }
307            MaybeParsed::Complete(unchecked) => Options::try_from_raw(unchecked)
308                .map_err(|e| debug_err!(e, "malformed options: {:?}", e))?,
309        };
310
311        if hdr_prefix.version() != 4 {
312            return debug_err!(
313                Err(ParseError::Format),
314                "unexpected IP version: {}",
315                hdr_prefix.version()
316            );
317        }
318
319        let body = match raw.body {
320            MaybeParsed::Incomplete(_) => {
321                if hdr_prefix.mf_flag() {
322                    return debug_err!(
323                        Err(ParseError::NotSupported),
324                        "fragmentation not supported"
325                    );
326                } else {
327                    return debug_err!(Err(ParseError::Format), "Incomplete body");
328                }
329            }
330            MaybeParsed::Complete(bytes) => bytes,
331        };
332
333        let packet = Ipv4Packet { hdr_prefix, options, body };
334        if packet.compute_header_checksum() != [0, 0] {
335            return debug_err!(Err(ParseError::Checksum), "invalid checksum");
336        }
337        Ok(packet)
338    }
339}
340
341fn compute_header_checksum(hdr_prefix: &[u8], options: &[u8]) -> [u8; 2] {
342    let mut c = Checksum::new();
343    c.add_bytes(hdr_prefix);
344    c.add_bytes(options);
345    c.checksum()
346}
347
348impl<B: SplitByteSlice> Ipv4Packet<B> {
349    /// Iterate over the IPv4 header options.
350    pub fn iter_options(&self) -> impl Iterator<Item = Ipv4Option<'_>> {
351        self.options.iter()
352    }
353
354    // Compute the header checksum, skipping the checksum field itself.
355    fn compute_header_checksum(&self) -> [u8; 2] {
356        compute_header_checksum(Ref::bytes(&self.hdr_prefix), self.options.bytes())
357    }
358
359    /// The packet body.
360    pub fn body(&self) -> &[u8] {
361        &self.body
362    }
363
364    /// The size of the header prefix and options.
365    pub fn header_len(&self) -> usize {
366        Ref::bytes(&self.hdr_prefix).len() + self.options.bytes().len()
367    }
368
369    /// The source IP address represented as an [`Ipv4SourceAddr`].
370    ///
371    /// Unlike [`IpHeader::src_ip`], `src_ipv4` returns an `Ipv4SourceAddr`,
372    /// which represents the valid values that a source address can take.
373    pub fn src_ipv4(&self) -> Option<Ipv4SourceAddr> {
374        Ipv4SourceAddr::new(self.src_ip())
375    }
376
377    /// Return a buffer that is a copy of the header bytes in this
378    /// packet, but patched to be not fragmented.
379    ///
380    /// Return a buffer of this packet's header and options with
381    /// the fragment data zeroed out.
382    pub fn copy_header_bytes_for_fragment(&self) -> Vec<u8> {
383        let expected_bytes_len = self.header_len();
384        let mut bytes = Vec::with_capacity(expected_bytes_len);
385
386        bytes.extend_from_slice(Ref::bytes(&self.hdr_prefix));
387        bytes.extend_from_slice(self.options.bytes());
388
389        // `bytes`'s length should be exactly `expected_bytes_len`.
390        assert_eq!(bytes.len(), expected_bytes_len);
391
392        // Zero out the fragment data.
393        bytes[IPV4_FRAGMENT_DATA_BYTE_RANGE].copy_from_slice(&[0; 4][..]);
394
395        bytes
396    }
397
398    /// Performs the header translation part of NAT64 as described in [RFC
399    /// 7915].
400    ///
401    /// `nat64_translate` follows the rules described in RFC 7915 to construct
402    /// the IPv6 equivalent of this IPv4 packet. If the payload is a TCP segment
403    /// or a UDP packet, its checksum will be updated. If the payload is an
404    /// ICMPv4 packet, it will be converted to the equivalent ICMPv6 packet.
405    /// For all other payloads, the payload will be unchanged, and IP header will
406    /// be translated. On success, a [`Serializer`] is returned which describes
407    /// the new packet to be sent.
408    ///
409    /// Note that the IPv4 TTL/IPv6 Hop Limit field is not modified. It is the
410    /// caller's responsibility to decrement and process this field per RFC
411    /// 7915.
412    ///
413    /// In some cases, the packet has no IPv6 equivalent, in which case the
414    /// value [`Nat64TranslationResult::Drop`] will be returned, instructing the
415    /// caller to silently drop the packet.
416    ///
417    /// # Errors
418    ///
419    /// `nat64_translate` will return an error if support has not yet been
420    /// implemented for translation a particular IP protocol.
421    ///
422    /// [RFC 7915]: https://datatracker.ietf.org/doc/html/rfc7915
423    pub fn nat64_translate(
424        &self,
425        v6_src_addr: Ipv6Addr,
426        v6_dst_addr: Ipv6Addr,
427    ) -> Nat64TranslationResult<impl Serializer<Buffer = EmptyBuf> + Debug + '_, Nat64Error> {
428        // A single `Serializer` type so that all possible return values from
429        // this function have the same type.
430        #[derive(Debug)]
431        enum Nat64Serializer<T, U, O> {
432            Tcp(T),
433            Udp(U),
434            Other(O),
435        }
436
437        impl<T, U, O> Serializer for Nat64Serializer<T, U, O>
438        where
439            T: Serializer<Buffer = EmptyBuf>,
440            U: Serializer<Buffer = EmptyBuf>,
441            O: Serializer<Buffer = EmptyBuf>,
442        {
443            type Buffer = EmptyBuf;
444            fn serialize<B, P>(
445                self,
446                outer: PacketConstraints,
447                provider: P,
448            ) -> Result<B, (SerializeError<P::Error>, Self)>
449            where
450                B: GrowBufferMut,
451                P: BufferProvider<Self::Buffer, B>,
452            {
453                match self {
454                    Nat64Serializer::Tcp(serializer) => serializer
455                        .serialize(outer, provider)
456                        .map_err(|(err, ser)| (err, Nat64Serializer::Tcp(ser))),
457                    Nat64Serializer::Udp(serializer) => serializer
458                        .serialize(outer, provider)
459                        .map_err(|(err, ser)| (err, Nat64Serializer::Udp(ser))),
460                    Nat64Serializer::Other(serializer) => serializer
461                        .serialize(outer, provider)
462                        .map_err(|(err, ser)| (err, Nat64Serializer::Other(ser))),
463                }
464            }
465
466            fn serialize_new_buf<B: GrowBufferMut, A: LayoutBufferAlloc<B>>(
467                &self,
468                outer: PacketConstraints,
469                alloc: A,
470            ) -> Result<B, SerializeError<A::Error>> {
471                match self {
472                    Nat64Serializer::Tcp(serializer) => serializer.serialize_new_buf(outer, alloc),
473                    Nat64Serializer::Udp(serializer) => serializer.serialize_new_buf(outer, alloc),
474                    Nat64Serializer::Other(serializer) => {
475                        serializer.serialize_new_buf(outer, alloc)
476                    }
477                }
478            }
479        }
480
481        let v6_builder = |v6_proto| {
482            let mut builder =
483                Ipv6PacketBuilder::new(v6_src_addr, v6_dst_addr, self.ttl(), v6_proto);
484            builder.dscp_and_ecn(self.dscp_and_ecn());
485            builder.flowlabel(0);
486            builder
487        };
488
489        match self.proto() {
490            Ipv4Proto::Igmp => {
491                // As per RFC 7915 Section 4.2, silently drop all IGMP packets:
492                Nat64TranslationResult::Drop
493            }
494
495            Ipv4Proto::Proto(IpProto::Tcp) => {
496                let v6_pkt_builder = v6_builder(Ipv6Proto::Proto(IpProto::Tcp));
497                let args = TcpParseArgs::new(self.src_ip(), self.dst_ip());
498                match TcpSegment::parse(&mut self.body.as_bytes(), args) {
499                    Ok(tcp) => {
500                        // Creating a new tcp_serializer for IPv6 packet from
501                        // the existing one ensures that checksum is
502                        // updated due to changed IP addresses.
503                        let tcp_serializer =
504                            Nat64Serializer::Tcp(tcp.into_serializer(v6_src_addr, v6_dst_addr));
505                        Nat64TranslationResult::Forward(v6_pkt_builder.wrap_body(tcp_serializer))
506                    }
507                    Err(msg) => {
508                        debug!("Parsing of TCP segment failed: {:?}", msg);
509
510                        // This means we can't create a TCP segment builder with
511                        // updated checksum. Parsing may fail due to a variety of
512                        // reasons, including incorrect checksum in incoming packet.
513                        // We should still return a packet with IP payload copied
514                        // as is from IPv4 to IPv6.
515                        let common_serializer =
516                            Nat64Serializer::Other(self.body().into_serializer());
517                        Nat64TranslationResult::Forward(v6_pkt_builder.wrap_body(common_serializer))
518                    }
519                }
520            }
521
522            Ipv4Proto::Proto(IpProto::Udp) => {
523                let v6_pkt_builder = v6_builder(Ipv6Proto::Proto(IpProto::Udp));
524                let args = UdpParseArgs::new(self.src_ip(), self.dst_ip());
525                match UdpPacket::parse(&mut self.body.as_bytes(), args) {
526                    Ok(udp) => {
527                        // Creating a new udp_serializer for IPv6 packet from
528                        // the existing one ensures that checksum is
529                        // updated due to changed IP addresses.
530                        let udp_serializer =
531                            Nat64Serializer::Udp(udp.into_serializer(v6_src_addr, v6_dst_addr));
532                        Nat64TranslationResult::Forward(v6_pkt_builder.wrap_body(udp_serializer))
533                    }
534                    Err(msg) => {
535                        debug!("Parsing of UDP packet failed: {:?}", msg);
536
537                        // This means we can't create a UDP packet builder with
538                        // updated checksum. Parsing may fail due to a variety of
539                        // reasons, including incorrect checksum in incoming packet.
540                        // We should still return a packet with IP payload copied
541                        // as is from IPv4 to IPv6.
542                        let common_serializer =
543                            Nat64Serializer::Other(self.body().into_serializer());
544                        Nat64TranslationResult::Forward(v6_pkt_builder.wrap_body(common_serializer))
545                    }
546                }
547            }
548
549            Ipv4Proto::Icmp => Nat64TranslationResult::Err(Nat64Error::NotImplemented),
550
551            // As per the RFC, for all other protocols, an IPv6 must be forwarded, even if the
552            // transport-layer checksum update is not implemented. It's expected to fail
553            // checksum verification on receiver end, but still packet must be forwarded for
554            // 'troubleshooting and ease of debugging'.
555            Ipv4Proto::Other(val) => {
556                let v6_pkt_builder = v6_builder(Ipv6Proto::Other(val));
557                let common_serializer = Nat64Serializer::Other(self.body().into_serializer());
558                Nat64TranslationResult::Forward(v6_pkt_builder.wrap_body(common_serializer))
559            }
560
561            // Don't forward packets that use IANA's reserved protocol; they're
562            // invalid.
563            Ipv4Proto::Proto(IpProto::Reserved) => Nat64TranslationResult::Drop,
564        }
565    }
566
567    /// Copies the packet (Header + Options + Body) into a `Vec`.
568    pub fn to_vec(&self) -> Vec<u8> {
569        let Ipv4Packet { hdr_prefix, options, body } = self;
570        let mut buf = Vec::with_capacity(
571            Ref::bytes(&hdr_prefix).len() + options.bytes().len() + body.as_bytes().len(),
572        );
573        buf.extend(Ref::bytes(&hdr_prefix));
574        buf.extend(options.bytes());
575        buf.extend(body.as_bytes());
576        buf
577    }
578}
579
580impl<B: SplitByteSliceMut> Ipv4Packet<B> {
581    /// Set the source IP address.
582    ///
583    /// Set the source IP address and update the header checksum accordingly.
584    pub fn set_src_ip_and_update_checksum(&mut self, addr: Ipv4Addr) {
585        let old_bytes = self.hdr_prefix.src_ip.bytes();
586        self.hdr_prefix.hdr_checksum =
587            internet_checksum::update(self.hdr_prefix.hdr_checksum, &old_bytes, addr.bytes());
588        self.hdr_prefix.src_ip = addr;
589    }
590
591    /// Set the destination IP address.
592    ///
593    /// Set the destination IP address and update the header checksum accordingly.
594    pub fn set_dst_ip_and_update_checksum(&mut self, addr: Ipv4Addr) {
595        let old_bytes = self.hdr_prefix.dst_ip.bytes();
596        self.hdr_prefix.hdr_checksum =
597            internet_checksum::update(self.hdr_prefix.hdr_checksum, &old_bytes, addr.bytes());
598        self.hdr_prefix.dst_ip = addr;
599    }
600
601    /// Set the Time To Live (TTL).
602    ///
603    /// Set the TTL and update the header checksum accordingly.
604    pub fn set_ttl(&mut self, ttl: u8) {
605        // See the internet_checksum::update documentation for why we need to
606        // provide two bytes which are at an even byte offset from the beginning
607        // of the header.
608        let old_bytes = [self.hdr_prefix.ttl, self.hdr_prefix.proto];
609        let new_bytes = [ttl, self.hdr_prefix.proto];
610        self.hdr_prefix.hdr_checksum =
611            internet_checksum::update(self.hdr_prefix.hdr_checksum, &old_bytes, &new_bytes);
612        self.hdr_prefix.ttl = ttl;
613    }
614
615    /// The packet body.
616    pub fn body_mut(&mut self) -> &mut [u8] {
617        &mut self.body
618    }
619
620    /// Provides simultaneous access to header prefix, options, and mutable
621    /// body.
622    pub fn parts_with_body_mut(&mut self) -> (&HeaderPrefix, &Options<B>, &mut [u8]) {
623        (&self.hdr_prefix, &self.options, &mut self.body)
624    }
625}
626
627impl<B> Debug for Ipv4Packet<B>
628where
629    B: SplitByteSlice,
630{
631    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
632        f.debug_struct("Ipv4Packet")
633            .field("src_ip", &self.src_ip())
634            .field("dst_ip", &self.dst_ip())
635            .field("id", &self.id())
636            .field("ttl", &self.ttl())
637            .field("proto", &self.proto())
638            .field("frag_off", &self.fragment_offset())
639            .field("dscp", &self.dscp_and_ecn().dscp())
640            .field("ecn", &self.dscp_and_ecn().ecn())
641            .field("mf_flag", &self.mf_flag())
642            .field("df_flag", &self.df_flag())
643            .field("body", &alloc::format!("<{} bytes>", self.body.len()))
644            .finish()
645    }
646}
647
648/// A partially parsed and not yet validated IPv4 packet.
649///
650/// `Ipv4PacketRaw` provides minimal parsing of an IPv4 packet, namely
651/// it only requires that the fixed header part ([`HeaderPrefix`]) be retrieved,
652/// all the other parts of the packet may be missing when attempting to create
653/// it.
654///
655/// [`Ipv4Packet`] provides a [`FromRaw`] implementation that can be used to
656/// validate an `Ipv4PacketRaw`.
657pub struct Ipv4PacketRaw<B> {
658    hdr_prefix: Ref<B, HeaderPrefix>,
659    options: MaybeParsed<OptionsRaw<B, Ipv4OptionsImpl>, B>,
660    body: MaybeParsed<B, B>,
661}
662
663impl<B> Ipv4PacketRaw<B> {
664    /// Returns a mutable reference to the body bytes of this [`Ipv4PacketRaw`].
665    ///
666    /// Might not be complete if a full packet was not received.
667    pub fn body_mut(&mut self) -> &mut B {
668        match &mut self.body {
669            MaybeParsed::Complete(b) => b,
670            MaybeParsed::Incomplete(b) => b,
671        }
672    }
673}
674
675impl<B: SplitByteSlice> Ipv4Header for Ipv4PacketRaw<B> {
676    fn get_header_prefix(&self) -> &HeaderPrefix {
677        &self.hdr_prefix
678    }
679}
680
681impl<B: SplitByteSlice> ParsablePacket<B, ()> for Ipv4PacketRaw<B> {
682    type Error = ParseError;
683
684    fn parse_metadata(&self) -> ParseMetadata {
685        let header_len = Ref::bytes(&self.hdr_prefix).len() + self.options.len();
686        ParseMetadata::from_packet(header_len, self.body.len(), 0)
687    }
688
689    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> Result<Self, ParseError> {
690        let hdr_prefix = buffer
691            .take_obj_front::<HeaderPrefix>()
692            .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?;
693        let hdr_bytes = (hdr_prefix.ihl() * 4) as usize;
694
695        let options = MaybeParsed::take_from_buffer_with(
696            &mut buffer,
697            // If the subtraction hdr_bytes - HDR_PREFIX_LEN would have been
698            // negative, that would imply that IHL has an invalid value. Even
699            // though this will end up being MaybeParsed::Complete, the IHL
700            // value is validated when transforming Ipv4PacketRaw to Ipv4Packet.
701            hdr_bytes.saturating_sub(HDR_PREFIX_LEN),
702            OptionsRaw::new,
703        );
704
705        let total_len: usize = hdr_prefix.total_len.get().into();
706        let body_len = total_len.saturating_sub(hdr_bytes);
707        if buffer.len() > body_len {
708            // Discard the padding left by the previous layer. This unwrap is
709            // safe because of the check against total_len.
710            let _: B = buffer.take_back(buffer.len() - body_len).unwrap();
711        }
712
713        let body = MaybeParsed::new_with_min_len(buffer.into_rest(), body_len);
714
715        Ok(Self { hdr_prefix, options, body })
716    }
717}
718
719impl<B> Ipv4PacketRaw<B> {
720    /// Gets the maybe parsed options from the raw packet.
721    pub fn options(&self) -> &MaybeParsed<OptionsRaw<B, Ipv4OptionsImpl>, B> {
722        &self.options
723    }
724}
725
726impl<B: SplitByteSlice> Ipv4PacketRaw<B> {
727    /// Return the body.
728    ///
729    /// `body` returns [`MaybeParsed::Complete`] if the entire body is present
730    /// (as determined by the header's "total length" and "internet header
731    /// length" fields), and [`MaybeParsed::Incomplete`] otherwise.
732    pub fn body(&self) -> MaybeParsed<&[u8], &[u8]> {
733        self.body.as_ref().map(|b| b.deref()).map_incomplete(|b| b.deref())
734    }
735
736    /// Consumes `self` returning the body.
737    ///
738    /// See [`Ipv4PacketRaw::body`] for details on parsing completeness.
739    pub fn into_body(self) -> MaybeParsed<B, B> {
740        self.body
741    }
742}
743
744impl<B: SplitByteSliceMut> Ipv4PacketRaw<B> {
745    /// Set the source IP address.
746    ///
747    /// Set the source IP address and update the header checksum accordingly.
748    pub fn set_src_ip_and_update_checksum(&mut self, addr: Ipv4Addr) {
749        let old_bytes = self.hdr_prefix.src_ip.bytes();
750        self.hdr_prefix.hdr_checksum =
751            internet_checksum::update(self.hdr_prefix.hdr_checksum, &old_bytes, addr.bytes());
752        self.hdr_prefix.src_ip = addr;
753    }
754
755    /// Set the destination IP address.
756    ///
757    /// Set the destination IP address and update the header checksum accordingly.
758    pub fn set_dst_ip_and_update_checksum(&mut self, addr: Ipv4Addr) {
759        let old_bytes = self.hdr_prefix.dst_ip.bytes();
760        self.hdr_prefix.hdr_checksum =
761            internet_checksum::update(self.hdr_prefix.hdr_checksum, &old_bytes, addr.bytes());
762        self.hdr_prefix.dst_ip = addr;
763    }
764}
765
766/// A records parser for IPv4 options.
767///
768/// See [`Options`] for more details.
769///
770/// [`Options`]: packet::records::options::Options
771pub type Options<B> = packet::records::options::Options<B, Ipv4OptionsImpl>;
772
773/// Options provided to [`Ipv4PacketBuilderWithOptions::new`] exceed
774/// [`MAX_OPTIONS_LEN`] when serialized.
775#[derive(Debug)]
776pub struct Ipv4OptionsTooLongError;
777
778/// A PacketBuilder for Ipv4 Packets but with options.
779#[derive(Debug, Clone)]
780pub struct Ipv4PacketBuilderWithOptions<'a, I> {
781    prefix_builder: Ipv4PacketBuilder,
782    options: OptionSequenceBuilder<Ipv4Option<'a>, I>,
783}
784
785impl<'a, I> Ipv4PacketBuilderWithOptions<'a, I>
786where
787    I: Iterator + Clone,
788    I::Item: Borrow<Ipv4Option<'a>>,
789{
790    /// Creates a new IPv4 packet builder without options.
791    ///
792    /// Returns `Err` if the packet header would exceed the maximum length of
793    /// [`MAX_HDR_LEN`]. This happens if the `options`, when serialized, would
794    /// exceed [`MAX_OPTIONS_LEN`].
795    pub fn new<T: IntoIterator<IntoIter = I>>(
796        prefix_builder: Ipv4PacketBuilder,
797        options: T,
798    ) -> Result<Ipv4PacketBuilderWithOptions<'a, I>, Ipv4OptionsTooLongError> {
799        let options = OptionSequenceBuilder::new(options.into_iter());
800        if options.serialized_len() > MAX_OPTIONS_LEN {
801            return Err(Ipv4OptionsTooLongError);
802        }
803        Ok(Ipv4PacketBuilderWithOptions { prefix_builder, options })
804    }
805
806    fn aligned_options_len(&self) -> usize {
807        // Round up to the next 4-byte boundary.
808        crate::utils::round_to_next_multiple_of_four(self.options.serialized_len())
809    }
810
811    /// Returns a reference to the prefix builder.
812    pub fn prefix_builder(&self) -> &Ipv4PacketBuilder {
813        &self.prefix_builder
814    }
815
816    /// Returns a mutable reference to the prefix builder.
817    pub fn prefix_builder_mut(&mut self) -> &mut Ipv4PacketBuilder {
818        &mut self.prefix_builder
819    }
820
821    /// Returns a reference to the options used to create this builder.
822    pub fn options(&self) -> &I {
823        self.options.records()
824    }
825
826    /// Maps this builder optionally maintaining only the options that are meant
827    /// to be copied on all fragments.
828    ///
829    /// If `first_fragment` is `true`, all options are maintained, otherwise
830    /// only the options meant to be copied on all fragments will be yielded.
831    pub fn with_fragment_options(
832        self,
833        first_fragment: bool,
834    ) -> Ipv4PacketBuilderWithOptions<'a, impl Iterator<Item: Borrow<Ipv4Option<'a>>> + Clone> {
835        let Self { prefix_builder, options } = self;
836        Ipv4PacketBuilderWithOptions {
837            prefix_builder,
838            // We don't need to run the check on the builder options again since
839            // we're strictly removing options.
840            options: OptionSequenceBuilder::new(
841                options
842                    .records()
843                    .clone()
844                    .filter(move |opt| first_fragment || opt.borrow().copied()),
845            ),
846        }
847    }
848}
849
850impl<'a, B> Ipv4PacketBuilderWithOptions<'a, RecordsIter<'a, B, Ipv4OptionsImpl>> {
851    /// Creates a new `Ipv4PacketBuilderWithOptions` with a known-to-be-valid
852    /// iterator of IPv4 options records.
853    pub fn new_with_records_iter(
854        prefix_builder: Ipv4PacketBuilder,
855        iter: RecordsIter<'a, B, Ipv4OptionsImpl>,
856    ) -> Self {
857        Self { prefix_builder, options: OptionSequenceBuilder::new(iter) }
858    }
859}
860
861impl<'a, I> PacketBuilder for Ipv4PacketBuilderWithOptions<'a, I>
862where
863    I: Iterator + Clone,
864    I::Item: Borrow<Ipv4Option<'a>>,
865{
866    fn constraints(&self) -> PacketConstraints {
867        let header_len = IPV4_MIN_HDR_LEN + self.aligned_options_len();
868        assert_eq!(header_len % 4, 0);
869        PacketConstraints::new(header_len, 0, 0, (1 << 16) - 1 - header_len)
870    }
871
872    fn serialize(&self, target: &mut SerializeTarget<'_>, body: FragmentedBytesMut<'_, '_>) {
873        let opt_len = self.aligned_options_len();
874        // `take_back_zero` consumes the extent of the receiving slice, but that
875        // behavior is undesirable here: `prefix_builder.serialize` also needs
876        // to write into the header. To avoid changing the extent of
877        // target.header, we re-slice header before calling `take_back_zero`;
878        // the re-slice will be consumed, but `target.header` is unaffected.
879        let mut header = &mut &mut target.header[..];
880        let opts = header.take_back_zero(opt_len).expect("too few bytes for Ipv4 options");
881        let Ipv4PacketBuilderWithOptions { prefix_builder, options } = self;
882        options.serialize_into(opts);
883        prefix_builder.serialize(target, body);
884    }
885}
886
887impl<'a, I> PartialPacketBuilder for Ipv4PacketBuilderWithOptions<'a, I>
888where
889    I: Iterator + Clone,
890    I::Item: Borrow<Ipv4Option<'a>>,
891{
892    fn partial_serialize(&self, body_len: usize, header: &mut [u8]) {
893        let Ipv4PacketBuilderWithOptions { prefix_builder, options } = self;
894        prefix_builder.partial_serialize(body_len, header);
895        let options_slice = &mut header[IPV4_MIN_HDR_LEN..];
896        assert_eq!(options_slice.len(), self.aligned_options_len());
897        options.serialize_into(options_slice);
898    }
899}
900
901impl<'a, I> IpPacketBuilder<Ipv4> for Ipv4PacketBuilderWithOptions<'a, I>
902where
903    I: Default + Debug + Clone + Iterator<Item: Borrow<Ipv4Option<'a>>>,
904{
905    fn new(src_ip: Ipv4Addr, dst_ip: Ipv4Addr, ttl: u8, proto: Ipv4Proto) -> Self {
906        Ipv4PacketBuilderWithOptions::new(
907            Ipv4PacketBuilder::new(src_ip, dst_ip, ttl, proto),
908            I::default(),
909        )
910        .expect("packet builder with no options should be valid")
911    }
912
913    fn src_ip(&self) -> Ipv4Addr {
914        self.prefix_builder.src_ip
915    }
916
917    fn set_src_ip(&mut self, addr: Ipv4Addr) {
918        self.prefix_builder.set_src_ip(addr);
919    }
920
921    fn dst_ip(&self) -> Ipv4Addr {
922        self.prefix_builder.dst_ip
923    }
924
925    fn set_dst_ip(&mut self, addr: Ipv4Addr) {
926        self.prefix_builder.set_dst_ip(addr);
927    }
928
929    fn proto(&self) -> Ipv4Proto {
930        self.prefix_builder.proto
931    }
932
933    fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
934        self.prefix_builder.set_dscp_and_ecn(dscp_and_ecn)
935    }
936}
937
938/// A builder for IPv4 packets.
939#[derive(Debug, Clone, Eq, PartialEq)]
940pub struct Ipv4PacketBuilder {
941    id: u16,
942    dscp_and_ecn: DscpAndEcn,
943    flags: u8,
944    frag_off: u16,
945    ttl: u8,
946    proto: Ipv4Proto,
947    src_ip: Ipv4Addr,
948    dst_ip: Ipv4Addr,
949}
950
951impl Ipv4PacketBuilder {
952    /// Construct a new `Ipv4PacketBuilder`.
953    pub fn new<S: Into<Ipv4Addr>, D: Into<Ipv4Addr>>(
954        src_ip: S,
955        dst_ip: D,
956        ttl: u8,
957        proto: Ipv4Proto,
958    ) -> Ipv4PacketBuilder {
959        Ipv4PacketBuilder {
960            id: 0,
961            dscp_and_ecn: DscpAndEcn::default(),
962            flags: 0,
963            frag_off: 0,
964            ttl,
965            proto: proto,
966            src_ip: src_ip.into(),
967            dst_ip: dst_ip.into(),
968        }
969    }
970
971    /// Sets DSCP and ECN fields.
972    pub fn dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
973        self.dscp_and_ecn = dscp_and_ecn;
974    }
975
976    /// Set the ID field.
977    pub fn id(&mut self, id: u16) {
978        self.id = id
979    }
980
981    /// Set the Don't Fragment (DF) flag.
982    pub fn df_flag(&mut self, df: bool) {
983        if df {
984            self.flags |= 1 << DF_FLAG_OFFSET;
985        } else {
986            self.flags &= !(1 << DF_FLAG_OFFSET);
987        }
988    }
989
990    /// Set the More Fragments (MF) flag.
991    pub fn mf_flag(&mut self, mf: bool) {
992        if mf {
993            self.flags |= 1 << MF_FLAG_OFFSET;
994        } else {
995            self.flags &= !(1 << MF_FLAG_OFFSET);
996        }
997    }
998
999    /// Set the fragment offset.
1000    pub fn fragment_offset(&mut self, fragment_offset: FragmentOffset) {
1001        self.frag_off = fragment_offset.into_raw();
1002    }
1003
1004    /// Returns the configured Don't Fragment (DF) flag.
1005    pub fn read_df_flag(&self) -> bool {
1006        (self.flags & (1 << DF_FLAG_OFFSET)) != 0
1007    }
1008
1009    fn get_header_prefix(&self, header_len: usize, total_len: usize) -> HeaderPrefix {
1010        assert_eq!(header_len % 4, 0);
1011        let ihl: u8 = u8::try_from(header_len / 4).expect("Header too large");
1012
1013        // As Per [RFC 6864 Section 2]:
1014        //
1015        //   > The IPv4 ID field is thus meaningful only for non-atomic datagrams --
1016        //   > either those datagrams that have already been fragmented or those for
1017        //   > which fragmentation remains permitted...
1018        //   >
1019        //   > ...Non-atomic datagrams: (DF==0)||(MF==1)||(frag_offset>0)
1020        //
1021        // [RFC 6864 Section 2]: https://tools.ietf.org/html/rfc6864#section-2
1022        let id = if ((self.flags & (1 << DF_FLAG_OFFSET)) == 0)
1023            || ((self.flags & (1 << MF_FLAG_OFFSET)) == 1)
1024            || (self.frag_off > 0)
1025        {
1026            self.id
1027        } else {
1028            0
1029        };
1030
1031        HeaderPrefix::new(
1032            ihl,
1033            self.dscp_and_ecn,
1034            {
1035                // The caller promises to supply a body whose length does not
1036                // exceed max_body_len. Doing this as a debug_assert (rather
1037                // than an assert) is fine because, with debug assertions
1038                // disabled, we'll just write an incorrect header value, which
1039                // is acceptable if the caller has violated their contract.
1040                debug_assert!(total_len <= core::u16::MAX as usize);
1041                total_len as u16
1042            },
1043            id,
1044            self.flags,
1045            self.frag_off,
1046            self.ttl,
1047            self.proto.into(),
1048            [0, 0], // header checksum
1049            self.src_ip,
1050            self.dst_ip,
1051        )
1052    }
1053}
1054
1055impl PacketBuilder for Ipv4PacketBuilder {
1056    fn constraints(&self) -> PacketConstraints {
1057        PacketConstraints::new(IPV4_MIN_HDR_LEN, 0, 0, (1 << 16) - 1 - IPV4_MIN_HDR_LEN)
1058    }
1059
1060    fn serialize(&self, target: &mut SerializeTarget<'_>, body: FragmentedBytesMut<'_, '_>) {
1061        let header_len = target.header.len();
1062        let total_len = header_len + body.len();
1063        let mut hdr_prefix = self.get_header_prefix(header_len, total_len);
1064        let options = &target.header[HDR_PREFIX_LEN..];
1065        let checksum = compute_header_checksum(hdr_prefix.as_bytes(), options);
1066        hdr_prefix.hdr_checksum = checksum;
1067        let mut header = &mut target.header;
1068        header.write_obj_front(&hdr_prefix).expect("too few bytes for IPv4 header prefix");
1069    }
1070}
1071
1072impl PartialPacketBuilder for Ipv4PacketBuilder {
1073    fn partial_serialize(&self, body_len: usize, mut header: &mut [u8]) {
1074        let total_len = header.len() + body_len;
1075        let hdr_prefix = self.get_header_prefix(header.len(), total_len);
1076        (&mut header).write_obj_front(&hdr_prefix).expect("too few bytes for IPv4 header prefix");
1077    }
1078}
1079
1080impl IpPacketBuilder<Ipv4> for Ipv4PacketBuilder {
1081    fn new(src_ip: Ipv4Addr, dst_ip: Ipv4Addr, ttl: u8, proto: Ipv4Proto) -> Self {
1082        Ipv4PacketBuilder::new(src_ip, dst_ip, ttl, proto)
1083    }
1084
1085    fn src_ip(&self) -> Ipv4Addr {
1086        self.src_ip
1087    }
1088
1089    fn set_src_ip(&mut self, addr: Ipv4Addr) {
1090        self.src_ip = addr;
1091    }
1092
1093    fn dst_ip(&self) -> Ipv4Addr {
1094        self.dst_ip
1095    }
1096
1097    fn set_dst_ip(&mut self, addr: Ipv4Addr) {
1098        self.dst_ip = addr;
1099    }
1100
1101    fn proto(&self) -> Ipv4Proto {
1102        self.proto
1103    }
1104
1105    fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1106        self.dscp_and_ecn = dscp_and_ecn;
1107    }
1108}
1109
1110// bit positions into the flags bits
1111const DF_FLAG_OFFSET: u8 = 1;
1112const MF_FLAG_OFFSET: u8 = 0;
1113
1114/// Reassembles a fragmented IPv4 packet into a parsed IPv4 packet.
1115///
1116/// # Panics
1117///
1118/// Panics if the provided header is too small to hold a valid header.
1119pub(crate) fn reassemble_fragmented_packet<
1120    B: SplitByteSliceMut,
1121    BV: BufferViewMut<B>,
1122    I: Iterator<Item = Vec<u8>>,
1123>(
1124    mut buffer: BV,
1125    header: Vec<u8>,
1126    body_fragments: I,
1127) -> Result<(), ParseError> {
1128    assert!(header.len() >= HDR_PREFIX_LEN);
1129
1130    let bytes = buffer.as_mut();
1131
1132    // First, copy over the header data.
1133    bytes[0..header.len()].copy_from_slice(&header[..]);
1134    let mut byte_count = header.len();
1135
1136    // Next, copy over the body fragments.
1137    for p in body_fragments {
1138        bytes[byte_count..byte_count + p.len()].copy_from_slice(&p[..]);
1139        byte_count += p.len();
1140    }
1141
1142    // Fix up the IPv4 header
1143
1144    // Make sure that the packet length is not more than the maximum
1145    // possible IPv4 packet length.
1146    if byte_count > usize::from(core::u16::MAX) {
1147        return debug_err!(
1148            Err(ParseError::Format),
1149            "fragmented packet length of {} bytes is too large",
1150            byte_count
1151        );
1152    }
1153
1154    // We know the call to `unwrap` will not fail because we verified the length
1155    // of `header` and copied it's bytes into `bytes`.
1156    let mut header_ref = Ref::<_, HeaderPrefix>::from_prefix(bytes).unwrap().0;
1157
1158    let options_bytes = &header[HDR_PREFIX_LEN..header.len()];
1159
1160    // Update the total length field.
1161    header_ref.total_len.set(u16::try_from(byte_count).unwrap());
1162
1163    // Zero out fragment related data since we will now have a
1164    // reassembled packet that does not need reassembly.
1165    header_ref.flags_frag_off = [0; 2];
1166
1167    // Update header checksum.
1168    header_ref.hdr_checksum = [0; 2];
1169    header_ref.hdr_checksum = compute_header_checksum(header_ref.as_bytes(), options_bytes);
1170
1171    Ok(())
1172}
1173
1174/// Parsing and serialization of IPv4 options.
1175pub mod options {
1176    use byteorder::{ByteOrder, NetworkEndian};
1177    use packet::BufferViewMut;
1178    use packet::records::options::{
1179        OptionBuilder, OptionLayout, OptionParseErr, OptionParseLayout, OptionsImpl,
1180    };
1181    use zerocopy::byteorder::network_endian::U16;
1182
1183    const OPTION_KIND_EOL: u8 = 0;
1184    const OPTION_KIND_NOP: u8 = 1;
1185    const OPTION_KIND_RTRALRT: u8 = 148;
1186
1187    const OPTION_RTRALRT_LEN: usize = 2;
1188
1189    /// An IPv4 header option.
1190    ///
1191    /// See [Wikipedia] or [RFC 791] for more details.
1192    ///
1193    /// [Wikipedia]: https://en.wikipedia.org/wiki/IPv4#Options
1194    /// [RFC 791]: https://tools.ietf.org/html/rfc791#page-15
1195    #[derive(PartialEq, Eq, Debug, Clone)]
1196    #[allow(missing_docs)]
1197    pub enum Ipv4Option<'a> {
1198        /// Used to tell routers to inspect the packet.
1199        ///
1200        /// Used by IGMP host messages per [RFC 2236 section 2].
1201        ///
1202        /// [RFC 2236 section 2]: https://tools.ietf.org/html/rfc2236#section-2
1203        RouterAlert { data: u16 },
1204
1205        /// An unrecognized IPv4 option.
1206        // The maximum header length is 60 bytes, and the fixed-length header is 20
1207        // bytes, so there are 40 bytes for the options. That leaves a maximum
1208        // options size of 1 kind byte + 1 length byte + 38 data bytes. Data for an
1209        // unrecognized option kind.
1210        //
1211        // Any unrecognized option kind will have its data parsed using this
1212        // variant. This allows code to copy unrecognized options into packets when
1213        // forwarding.
1214        //
1215        // `data`'s length is in the range [0, 38].
1216        Unrecognized { kind: u8, data: &'a [u8] },
1217    }
1218
1219    impl<'a> Ipv4Option<'a> {
1220        /// Returns whether this option should be copied on all fragments.
1221        pub fn copied(&self) -> bool {
1222            match self {
1223                // The router alert option is copied on all fragments. See
1224                // https://datatracker.ietf.org/doc/html/rfc2113#section-2.1.
1225                // It is embedded in our definition of OPTION_KIND_RTRALRT.
1226                Ipv4Option::RouterAlert { .. } => true,
1227                Ipv4Option::Unrecognized { kind, .. } => *kind & (1 << 7) != 0,
1228            }
1229        }
1230    }
1231
1232    /// An implementation of [`OptionsImpl`] for IPv4 options.
1233    #[derive(Debug, Clone)]
1234    pub struct Ipv4OptionsImpl;
1235
1236    impl OptionLayout for Ipv4OptionsImpl {
1237        type KindLenField = u8;
1238    }
1239
1240    impl OptionParseLayout for Ipv4OptionsImpl {
1241        type Error = OptionParseErr;
1242        const END_OF_OPTIONS: Option<u8> = Some(0);
1243        const NOP: Option<u8> = Some(1);
1244    }
1245
1246    impl OptionsImpl for Ipv4OptionsImpl {
1247        type Option<'a> = Ipv4Option<'a>;
1248
1249        fn parse<'a>(kind: u8, data: &'a [u8]) -> Result<Option<Ipv4Option<'a>>, OptionParseErr> {
1250            match kind {
1251                self::OPTION_KIND_EOL | self::OPTION_KIND_NOP => {
1252                    unreachable!("records::options::Options promises to handle EOL and NOP")
1253                }
1254                self::OPTION_KIND_RTRALRT => {
1255                    if data.len() == OPTION_RTRALRT_LEN {
1256                        Ok(Some(Ipv4Option::RouterAlert { data: NetworkEndian::read_u16(data) }))
1257                    } else {
1258                        Err(OptionParseErr)
1259                    }
1260                }
1261                kind => {
1262                    if data.len() > 38 {
1263                        Err(OptionParseErr)
1264                    } else {
1265                        Ok(Some(Ipv4Option::Unrecognized { kind, data }))
1266                    }
1267                }
1268            }
1269        }
1270    }
1271
1272    impl<'a> OptionBuilder for Ipv4Option<'a> {
1273        type Layout = Ipv4OptionsImpl;
1274
1275        fn serialized_len(&self) -> usize {
1276            match self {
1277                Ipv4Option::RouterAlert { .. } => OPTION_RTRALRT_LEN,
1278                Ipv4Option::Unrecognized { data, .. } => data.len(),
1279            }
1280        }
1281
1282        fn option_kind(&self) -> u8 {
1283            match self {
1284                Ipv4Option::RouterAlert { .. } => OPTION_KIND_RTRALRT,
1285                Ipv4Option::Unrecognized { kind, .. } => *kind,
1286            }
1287        }
1288
1289        fn serialize_into(&self, mut buffer: &mut [u8]) {
1290            match self {
1291                Ipv4Option::Unrecognized { data, .. } => buffer.copy_from_slice(data),
1292                Ipv4Option::RouterAlert { data } => {
1293                    (&mut buffer).write_obj_front(&U16::new(*data)).unwrap()
1294                }
1295            };
1296        }
1297    }
1298
1299    #[cfg(test)]
1300    mod test {
1301        use packet::records::RecordBuilder;
1302        use packet::records::options::Options;
1303
1304        use super::*;
1305
1306        #[test]
1307        fn test_serialize_router_alert() {
1308            let mut buffer = [0u8; 4];
1309            let option = Ipv4Option::RouterAlert { data: 0 };
1310            <Ipv4Option<'_> as RecordBuilder>::serialize_into(&option, &mut buffer);
1311            assert_eq!(buffer[0], 148);
1312            assert_eq!(buffer[1], 4);
1313            assert_eq!(buffer[2], 0);
1314            assert_eq!(buffer[3], 0);
1315        }
1316
1317        #[test]
1318        fn test_parse_router_alert() {
1319            let mut buffer: Vec<u8> = vec![148, 4, 0, 0];
1320            let options = Options::<_, Ipv4OptionsImpl>::parse(buffer.as_mut()).unwrap();
1321            let rtralt = options.iter().next().unwrap();
1322            assert_eq!(rtralt, Ipv4Option::RouterAlert { data: 0 });
1323        }
1324    }
1325}
1326
1327mod inner {
1328    /// The minimum length of an IPv4 header.
1329    pub const IPV4_MIN_HDR_LEN: usize = super::HDR_PREFIX_LEN;
1330}
1331
1332/// IPv4 packet parsing and serialization test utilities.
1333pub mod testutil {
1334    pub use super::inner::IPV4_MIN_HDR_LEN;
1335
1336    /// The offset to the TTL field within an IPv4 header, in bytes.
1337    pub const IPV4_TTL_OFFSET: usize = 8;
1338
1339    /// The offset to the checksum field within an IPv4 header, in bytes.
1340    pub const IPV4_CHECKSUM_OFFSET: usize = 10;
1341}
1342
1343#[cfg(test)]
1344mod tests {
1345    use net_types::ethernet::Mac;
1346    use packet::{Buf, FragmentedBuffer, ParseBuffer};
1347
1348    use super::*;
1349    use crate::ethernet::{
1350        ETHERNET_MIN_BODY_LEN_NO_TAG, EtherType, EthernetFrame, EthernetFrameBuilder,
1351        EthernetFrameLengthCheck,
1352    };
1353    use crate::testutil::*;
1354
1355    const DEFAULT_SRC_MAC: Mac = Mac::new([1, 2, 3, 4, 5, 6]);
1356    const DEFAULT_DST_MAC: Mac = Mac::new([7, 8, 9, 0, 1, 2]);
1357    const DEFAULT_SRC_IP: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
1358    const DEFAULT_DST_IP: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
1359    // 2001:DB8::1
1360    const DEFAULT_V6_SRC_IP: Ipv6Addr = Ipv6Addr::new([0x2001, 0x0db8, 0, 0, 0, 0, 0, 1]);
1361    // 2001:DB8::2
1362    const DEFAULT_V6_DST_IP: Ipv6Addr = Ipv6Addr::new([0x2001, 0x0db8, 0, 0, 0, 0, 0, 2]);
1363
1364    #[test]
1365    fn test_parse_serialize_full_tcp() {
1366        use crate::testdata::tls_client_hello_v4::*;
1367
1368        let mut buf = ETHERNET_FRAME.bytes;
1369        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1370        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1371
1372        let mut body = frame.body();
1373        let packet = body.parse::<Ipv4Packet<_>>().unwrap();
1374        verify_ipv4_packet(&packet, IPV4_PACKET);
1375
1376        // Verify serialization via builders.
1377        let buffer = packet
1378            .body()
1379            .into_serializer()
1380            .wrap_in(packet.builder())
1381            .wrap_in(frame.builder())
1382            .serialize_vec_outer()
1383            .unwrap();
1384        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1385
1386        // Verify serialization via `to_vec`.
1387        assert_eq!(&packet.to_vec()[..], IPV4_PACKET.bytes);
1388    }
1389
1390    #[test]
1391    fn test_parse_serialize_full_udp() {
1392        use crate::testdata::dns_request_v4::*;
1393
1394        let mut buf = ETHERNET_FRAME.bytes;
1395        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1396        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1397
1398        let mut body = frame.body();
1399        let packet = body.parse::<Ipv4Packet<_>>().unwrap();
1400        verify_ipv4_packet(&packet, IPV4_PACKET);
1401
1402        // Verify serialization via builders.
1403        let buffer = packet
1404            .body()
1405            .into_serializer()
1406            .wrap_in(packet.builder())
1407            .wrap_in(frame.builder())
1408            .serialize_vec_outer()
1409            .unwrap();
1410        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1411
1412        // Verify serialization via `to_vec`.
1413        assert_eq!(&packet.to_vec()[..], IPV4_PACKET.bytes);
1414    }
1415
1416    #[test]
1417    fn test_parse_serialize_with_options() {
1418        // NB; Use IGMPv2 as test data arbitrarily, because it includes IP
1419        // header options.
1420        use crate::testdata::igmpv2_membership::report::*;
1421
1422        let mut buf = IP_PACKET_BYTES;
1423        let packet = buf.parse::<Ipv4Packet<_>>().unwrap();
1424        assert_eq!(packet.iter_options().count(), 1);
1425
1426        // NB: Don't verify serialization via builders, as they omit IP header
1427        // options.
1428
1429        // Verify serialization via `to_vec`.
1430        assert_eq!(&packet.to_vec()[..], IP_PACKET_BYTES);
1431    }
1432
1433    fn hdr_prefix_to_bytes(hdr_prefix: HeaderPrefix) -> [u8; 20] {
1434        zerocopy::transmute!(hdr_prefix)
1435    }
1436
1437    // Return a new HeaderPrefix with reasonable defaults, including a valid
1438    // header checksum.
1439    fn new_hdr_prefix() -> HeaderPrefix {
1440        HeaderPrefix::new(
1441            5,
1442            DscpAndEcn::default(),
1443            20,
1444            0x0102,
1445            0,
1446            0,
1447            0x03,
1448            IpProto::Tcp.into(),
1449            [0xa6, 0xcf],
1450            DEFAULT_SRC_IP,
1451            DEFAULT_DST_IP,
1452        )
1453    }
1454
1455    #[test]
1456    fn test_parse() {
1457        let mut bytes = &hdr_prefix_to_bytes(new_hdr_prefix())[..];
1458        let packet = bytes.parse::<Ipv4Packet<_>>().unwrap();
1459        assert_eq!(packet.id(), 0x0102);
1460        assert_eq!(packet.ttl(), 0x03);
1461        assert_eq!(packet.proto(), IpProto::Tcp.into());
1462        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1463        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1464        assert_eq!(packet.body(), []);
1465    }
1466
1467    #[test]
1468    fn test_parse_padding() {
1469        // Test that we properly discard post-packet padding.
1470        let mut buffer = Buf::new(Vec::new(), ..)
1471            .wrap_in(Ipv4PacketBuilder::new(DEFAULT_DST_IP, DEFAULT_DST_IP, 0, IpProto::Tcp.into()))
1472            .wrap_in(EthernetFrameBuilder::new(
1473                DEFAULT_SRC_MAC,
1474                DEFAULT_DST_MAC,
1475                EtherType::Ipv4,
1476                ETHERNET_MIN_BODY_LEN_NO_TAG,
1477            ))
1478            .serialize_vec_outer()
1479            .unwrap();
1480        let _: EthernetFrame<_> =
1481            buffer.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1482        // Test that the Ethernet body is the minimum length, which far exceeds
1483        // the IPv4 packet header size of 20 bytes (without options).
1484        assert_eq!(buffer.len(), 46);
1485        let packet = buffer.parse::<Ipv4Packet<_>>().unwrap();
1486        // Test that we've properly discarded the post-packet padding, and have
1487        // an empty body.
1488        assert_eq!(packet.body().len(), 0);
1489        // Test that we not only ignored the padding, but properly consumed it
1490        // from the underlying buffer as we're required to do by the
1491        // ParsablePacket contract.
1492        assert_eq!(buffer.len(), 0);
1493    }
1494
1495    #[test]
1496    fn test_parse_error() {
1497        // Set the version to 5. The version must be 4.
1498        let mut hdr_prefix = new_hdr_prefix();
1499        hdr_prefix.version_ihl = (5 << 4) | 5;
1500        assert_eq!(
1501            (&hdr_prefix_to_bytes(hdr_prefix)[..]).parse::<Ipv4Packet<_>>().unwrap_err(),
1502            ParseError::Format.into()
1503        );
1504
1505        // Set the IHL to 4, implying a header length of 16. This is smaller
1506        // than the minimum of 20.
1507        let mut hdr_prefix = new_hdr_prefix();
1508        hdr_prefix.version_ihl = (4 << 4) | 4;
1509        assert_eq!(
1510            (&hdr_prefix_to_bytes(hdr_prefix)[..]).parse::<Ipv4Packet<_>>().unwrap_err(),
1511            ParseError::Format.into()
1512        );
1513
1514        // Set the IHL to 6, implying a header length of 24. This is larger than
1515        // the actual packet length of 20.
1516        let mut hdr_prefix = new_hdr_prefix();
1517        hdr_prefix.version_ihl = (4 << 4) | 6;
1518        assert_eq!(
1519            (&hdr_prefix_to_bytes(hdr_prefix)[..]).parse::<Ipv4Packet<_>>().unwrap_err(),
1520            ParseError::Format.into()
1521        );
1522    }
1523
1524    // Return a stock Ipv4PacketBuilder with reasonable default values.
1525    fn new_builder() -> Ipv4PacketBuilder {
1526        Ipv4PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, 64, IpProto::Tcp.into())
1527    }
1528
1529    #[test]
1530    fn test_fragment_type() {
1531        fn test_fragment_type_helper(fragment_offset: u16, expect_fragment_type: Ipv4FragmentType) {
1532            let mut builder = new_builder();
1533            builder.fragment_offset(FragmentOffset::new(fragment_offset).unwrap());
1534
1535            let mut buf = [0; IPV4_MIN_HDR_LEN]
1536                .into_serializer()
1537                .wrap_in(builder)
1538                .serialize_vec_outer()
1539                .unwrap();
1540
1541            let packet = buf.parse::<Ipv4Packet<_>>().unwrap();
1542            assert_eq!(packet.fragment_type(), expect_fragment_type);
1543        }
1544
1545        test_fragment_type_helper(0x0000, Ipv4FragmentType::InitialFragment);
1546        test_fragment_type_helper(0x0008, Ipv4FragmentType::NonInitialFragment);
1547    }
1548
1549    #[test]
1550    fn test_serialize() {
1551        let mut builder = new_builder();
1552        builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
1553        builder.id(0x0405);
1554        builder.df_flag(true);
1555        builder.mf_flag(true);
1556        builder.fragment_offset(FragmentOffset::new(0x0607).unwrap());
1557
1558        let mut buf = (&[0, 1, 2, 3, 3, 4, 5, 7, 8, 9])
1559            .into_serializer()
1560            .wrap_in(builder)
1561            .serialize_vec_outer()
1562            .unwrap();
1563        assert_eq!(
1564            buf.as_ref(),
1565            [
1566                69, 75, 0, 30, 4, 5, 102, 7, 64, 6, 0, 112, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 3,
1567                4, 5, 7, 8, 9
1568            ]
1569        );
1570        let packet = buf.parse::<Ipv4Packet<_>>().unwrap();
1571        assert_eq!(packet.dscp_and_ecn().dscp(), 0x12);
1572        assert_eq!(packet.dscp_and_ecn().ecn(), 3);
1573        assert_eq!(packet.id(), 0x0405);
1574        assert!(packet.df_flag());
1575        assert!(packet.mf_flag());
1576        assert_eq!(packet.fragment_offset().into_raw(), 0x0607);
1577        assert_eq!(packet.fragment_type(), Ipv4FragmentType::NonInitialFragment);
1578    }
1579
1580    #[test]
1581    fn test_partial_serialize() {
1582        let mut builder = new_builder();
1583        builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
1584        builder.id(0x0405);
1585        builder.df_flag(true);
1586        builder.mf_flag(true);
1587        builder.fragment_offset(FragmentOffset::new(0x0607).unwrap());
1588        let body = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
1589        let packet = (&body).into_serializer().wrap_in(builder);
1590        const HEADER_LEN: usize = 20;
1591
1592        // Note that this header is different from the one in test_serialize
1593        // because the checksum is not calculated.
1594        const HEADER: [u8; HEADER_LEN] =
1595            [69, 75, 0, 30, 4, 5, 102, 7, 64, 6, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8];
1596        let mut expected_partial = HEADER.to_vec();
1597        expected_partial.resize(expected_partial.len() + body.len(), 0);
1598
1599        for i in 1..expected_partial.len() {
1600            let mut buf = vec![0u8; i];
1601            let result =
1602                packet.partial_serialize(PacketConstraints::UNCONSTRAINED, buf.as_mut_slice());
1603
1604            // PartialSerializer serializes the header only if the buffer is
1605            // large enough to fit the whole header.
1606            let bytes_written = if i >= HEADER_LEN { HEADER_LEN } else { 0 };
1607            assert_eq!(
1608                result,
1609                Ok(PartialSerializeResult { bytes_written, total_size: body.len() + HEADER_LEN })
1610            );
1611            if bytes_written > 0 {
1612                assert_eq!(buf, expected_partial[..i]);
1613            }
1614        }
1615    }
1616
1617    #[test]
1618    fn test_serialize_id_unset() {
1619        let mut builder = new_builder();
1620        builder.id(0x0405);
1621        builder.df_flag(true);
1622
1623        let mut buf = (&[0, 1, 2, 3, 3, 4, 5, 7, 8, 9])
1624            .into_serializer()
1625            .wrap_in(builder)
1626            .serialize_vec_outer()
1627            .unwrap();
1628        let packet = buf.parse::<Ipv4Packet<_>>().unwrap();
1629        assert_eq!(packet.id(), 0);
1630        assert!(packet.df_flag());
1631        assert_eq!(packet.mf_flag(), false);
1632        assert_eq!(packet.fragment_offset().into_raw(), 0);
1633        assert_eq!(packet.fragment_type(), Ipv4FragmentType::InitialFragment);
1634    }
1635
1636    #[test]
1637    fn test_serialize_zeroes() {
1638        // Test that Ipv4PacketBuilder::serialize properly zeroes memory before
1639        // serializing the header.
1640        let mut buf_0 = [0; IPV4_MIN_HDR_LEN];
1641        let _: Buf<&mut [u8]> = Buf::new(&mut buf_0[..], IPV4_MIN_HDR_LEN..)
1642            .wrap_in(new_builder())
1643            .serialize_vec_outer()
1644            .unwrap()
1645            .unwrap_a();
1646        let mut buf_1 = [0xFF; IPV4_MIN_HDR_LEN];
1647        let _: Buf<&mut [u8]> = Buf::new(&mut buf_1[..], IPV4_MIN_HDR_LEN..)
1648            .wrap_in(new_builder())
1649            .serialize_vec_outer()
1650            .unwrap()
1651            .unwrap_a();
1652        assert_eq!(buf_0, buf_1);
1653    }
1654
1655    #[test]
1656    #[should_panic(expected = "(SizeLimitExceeded, Nested { inner: Buf { buf:")]
1657    fn test_serialize_panic_packet_length() {
1658        // Test that a packet which is longer than 2^16 - 1 bytes is rejected.
1659        let _: Buf<&mut [u8]> = Buf::new(&mut [0; (1 << 16) - IPV4_MIN_HDR_LEN][..], ..)
1660            .wrap_in(new_builder())
1661            .serialize_vec_outer()
1662            .unwrap()
1663            .unwrap_a();
1664    }
1665
1666    #[test]
1667    fn test_copy_header_bytes_for_fragment() {
1668        let hdr_prefix = new_hdr_prefix();
1669        let mut bytes = hdr_prefix_to_bytes(hdr_prefix);
1670        let mut buf = &bytes[..];
1671        let packet = buf.parse::<Ipv4Packet<_>>().unwrap();
1672        let copied_bytes = packet.copy_header_bytes_for_fragment();
1673        bytes[IPV4_FRAGMENT_DATA_BYTE_RANGE].copy_from_slice(&[0; 4][..]);
1674        assert_eq!(&copied_bytes[..], &bytes[..]);
1675    }
1676
1677    #[test]
1678    fn test_partial_parsing() {
1679        use core::ops::Deref as _;
1680
1681        // Try something with only the header, but that would have a larger
1682        // body:
1683        let mut hdr_prefix = new_hdr_prefix();
1684        hdr_prefix.total_len = U16::new(256);
1685        let mut bytes = hdr_prefix_to_bytes(hdr_prefix)[..].to_owned();
1686        const PAYLOAD: &[u8] = &[1, 2, 3, 4, 5];
1687        bytes.extend(PAYLOAD);
1688        let mut buf = &bytes[..];
1689        let packet = buf.parse::<Ipv4PacketRaw<_>>().unwrap();
1690        let Ipv4PacketRaw { hdr_prefix, options, body } = &packet;
1691        assert_eq!(Ref::bytes(&hdr_prefix), &bytes[0..20]);
1692        assert_eq!(options.as_ref().complete().unwrap().deref(), []);
1693        // We must've captured the incomplete bytes in body:
1694        assert_eq!(body, &MaybeParsed::Incomplete(PAYLOAD));
1695        // validation should fail:
1696        assert!(Ipv4Packet::try_from_raw(packet).is_err());
1697
1698        // Try something with the header plus incomplete options:
1699        let mut hdr_prefix = new_hdr_prefix();
1700        hdr_prefix.version_ihl = (4 << 4) | 10;
1701        let bytes = hdr_prefix_to_bytes(hdr_prefix);
1702        let mut buf = &bytes[..];
1703        let packet = buf.parse::<Ipv4PacketRaw<_>>().unwrap();
1704        let Ipv4PacketRaw { hdr_prefix, options, body } = &packet;
1705        assert_eq!(Ref::bytes(&hdr_prefix), bytes);
1706        assert_eq!(options.as_ref().incomplete().unwrap(), &[]);
1707        assert_eq!(body.complete().unwrap(), []);
1708        // validation should fail:
1709        assert!(Ipv4Packet::try_from_raw(packet).is_err());
1710
1711        // Try an incomplete header:
1712        let hdr_prefix = new_hdr_prefix();
1713        let bytes = &hdr_prefix_to_bytes(hdr_prefix);
1714        let mut buf = &bytes[0..10];
1715        assert!(buf.parse::<Ipv4PacketRaw<_>>().is_err());
1716    }
1717
1718    fn create_ipv4_and_ipv6_builders(
1719        proto_v4: Ipv4Proto,
1720        proto_v6: Ipv6Proto,
1721    ) -> (Ipv4PacketBuilder, Ipv6PacketBuilder) {
1722        const IP_DSCP_AND_ECN: DscpAndEcn = DscpAndEcn::new(0x12, 3);
1723        const IP_TTL: u8 = 64;
1724
1725        let mut ipv4_builder =
1726            Ipv4PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, IP_TTL, proto_v4);
1727        ipv4_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
1728        ipv4_builder.id(0x0405);
1729        ipv4_builder.df_flag(true);
1730        ipv4_builder.mf_flag(false);
1731        ipv4_builder.fragment_offset(FragmentOffset::ZERO);
1732
1733        let mut ipv6_builder =
1734            Ipv6PacketBuilder::new(DEFAULT_V6_SRC_IP, DEFAULT_V6_DST_IP, IP_TTL, proto_v6);
1735        ipv6_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
1736        ipv6_builder.flowlabel(0);
1737
1738        (ipv4_builder, ipv6_builder)
1739    }
1740
1741    fn create_tcp_ipv4_and_ipv6_pkt()
1742    -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
1743        use crate::tcp::TcpSegmentBuilder;
1744        use core::num::NonZeroU16;
1745
1746        let tcp_src_port: NonZeroU16 = NonZeroU16::new(20).unwrap();
1747        let tcp_dst_port: NonZeroU16 = NonZeroU16::new(30).unwrap();
1748        const TCP_SEQ_NUM: u32 = 4321;
1749        const TCP_ACK_NUM: Option<u32> = Some(1234);
1750        const TCP_WINDOW_SIZE: u16 = 12345;
1751        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
1752
1753        let (ipv4_builder, ipv6_builder) =
1754            create_ipv4_and_ipv6_builders(IpProto::Tcp.into(), IpProto::Tcp.into());
1755
1756        let tcp_builder = TcpSegmentBuilder::new(
1757            DEFAULT_SRC_IP,
1758            DEFAULT_DST_IP,
1759            tcp_src_port,
1760            tcp_dst_port,
1761            TCP_SEQ_NUM,
1762            TCP_ACK_NUM,
1763            TCP_WINDOW_SIZE,
1764        );
1765
1766        let v4_pkt_buf = (&PAYLOAD)
1767            .into_serializer()
1768            .wrap_in(tcp_builder)
1769            .wrap_in(ipv4_builder)
1770            .serialize_vec_outer()
1771            .unwrap();
1772
1773        let v6_tcp_builder = TcpSegmentBuilder::new(
1774            DEFAULT_V6_SRC_IP,
1775            DEFAULT_V6_DST_IP,
1776            tcp_src_port,
1777            tcp_dst_port,
1778            TCP_SEQ_NUM,
1779            TCP_ACK_NUM,
1780            TCP_WINDOW_SIZE,
1781        );
1782
1783        let v6_pkt_buf = (&PAYLOAD)
1784            .into_serializer()
1785            .wrap_in(v6_tcp_builder)
1786            .wrap_in(ipv6_builder)
1787            .serialize_vec_outer()
1788            .unwrap();
1789
1790        (v4_pkt_buf, v6_pkt_buf)
1791    }
1792
1793    #[test]
1794    fn test_nat64_translate_tcp() {
1795        let (mut v4_pkt_buf, expected_v6_pkt_buf) = create_tcp_ipv4_and_ipv6_pkt();
1796
1797        let parsed_v4_packet = v4_pkt_buf.parse::<Ipv4Packet<_>>().unwrap();
1798        let nat64_translation_result =
1799            parsed_v4_packet.nat64_translate(DEFAULT_V6_SRC_IP, DEFAULT_V6_DST_IP);
1800
1801        let serializable_pkt = match nat64_translation_result {
1802            Nat64TranslationResult::Forward(s) => s,
1803            _ => panic!("Nat64TranslationResult not of Forward type!"),
1804        };
1805
1806        let translated_v6_pkt_buf = serializable_pkt.serialize_vec_outer().unwrap();
1807
1808        assert_eq!(
1809            expected_v6_pkt_buf.to_flattened_vec(),
1810            translated_v6_pkt_buf.to_flattened_vec()
1811        );
1812    }
1813
1814    fn create_udp_ipv4_and_ipv6_pkt()
1815    -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
1816        use crate::udp::UdpPacketBuilder;
1817        use core::num::NonZeroU16;
1818
1819        let udp_src_port: NonZeroU16 = NonZeroU16::new(35000).unwrap();
1820        let udp_dst_port: NonZeroU16 = NonZeroU16::new(53).unwrap();
1821        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
1822
1823        let (ipv4_builder, ipv6_builder) =
1824            create_ipv4_and_ipv6_builders(IpProto::Udp.into(), IpProto::Udp.into());
1825
1826        let udp_builder =
1827            UdpPacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, Some(udp_src_port), udp_dst_port);
1828
1829        let v4_pkt_buf = (&PAYLOAD)
1830            .into_serializer()
1831            .wrap_in(udp_builder)
1832            .wrap_in(ipv4_builder)
1833            .serialize_vec_outer()
1834            .unwrap();
1835
1836        let v6_udp_builder = UdpPacketBuilder::new(
1837            DEFAULT_V6_SRC_IP,
1838            DEFAULT_V6_DST_IP,
1839            Some(udp_src_port),
1840            udp_dst_port,
1841        );
1842
1843        let v6_pkt_buf = (&PAYLOAD)
1844            .into_serializer()
1845            .wrap_in(v6_udp_builder)
1846            .wrap_in(ipv6_builder)
1847            .serialize_vec_outer()
1848            .unwrap();
1849
1850        (v4_pkt_buf, v6_pkt_buf)
1851    }
1852
1853    #[test]
1854    fn test_nat64_translate_udp() {
1855        let (mut v4_pkt_buf, expected_v6_pkt_buf) = create_udp_ipv4_and_ipv6_pkt();
1856
1857        let parsed_v4_packet = v4_pkt_buf.parse::<Ipv4Packet<_>>().unwrap();
1858        let nat64_translation_result =
1859            parsed_v4_packet.nat64_translate(DEFAULT_V6_SRC_IP, DEFAULT_V6_DST_IP);
1860
1861        let serializable_pkt = match nat64_translation_result {
1862            Nat64TranslationResult::Forward(s) => s,
1863            _ => panic!(
1864                "Nat64TranslationResult not of Forward type: {:?} ",
1865                nat64_translation_result
1866            ),
1867        };
1868
1869        let translated_v6_pkt_buf = serializable_pkt.serialize_vec_outer().unwrap();
1870
1871        assert_eq!(
1872            expected_v6_pkt_buf.to_flattened_vec(),
1873            translated_v6_pkt_buf.to_flattened_vec()
1874        );
1875    }
1876
1877    #[test]
1878    fn test_nat64_translate_non_tcp_udp_icmp() {
1879        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
1880
1881        let (ipv4_builder, ipv6_builder) =
1882            create_ipv4_and_ipv6_builders(Ipv4Proto::Other(50), Ipv6Proto::Other(50));
1883
1884        let mut v4_pkt_buf =
1885            (&PAYLOAD).into_serializer().wrap_in(ipv4_builder).serialize_vec_outer().unwrap();
1886
1887        let expected_v6_pkt_buf =
1888            (&PAYLOAD).into_serializer().wrap_in(ipv6_builder).serialize_vec_outer().unwrap();
1889
1890        let translated_v6_pkt_buf = {
1891            let parsed_v4_packet = v4_pkt_buf.parse::<Ipv4Packet<_>>().unwrap();
1892
1893            let nat64_translation_result =
1894                parsed_v4_packet.nat64_translate(DEFAULT_V6_SRC_IP, DEFAULT_V6_DST_IP);
1895
1896            let serializable_pkt = match nat64_translation_result {
1897                Nat64TranslationResult::Forward(s) => s,
1898                _ => panic!(
1899                    "Nat64TranslationResult not of Forward type: {:?} ",
1900                    nat64_translation_result
1901                ),
1902            };
1903
1904            let translated_buf = serializable_pkt.serialize_vec_outer().unwrap();
1905
1906            translated_buf
1907        };
1908
1909        assert_eq!(
1910            expected_v6_pkt_buf.to_flattened_vec(),
1911            translated_v6_pkt_buf.to_flattened_vec()
1912        );
1913    }
1914
1915    #[test]
1916    fn test_partial_serialize_parsed() {
1917        let packet_bytes = [
1918            69, 75, 0, 30, 4, 5, 102, 7, 64, 6, 0, 112, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 3, 4,
1919            5, 7, 8, 9,
1920        ];
1921        let packet_len = packet_bytes.len();
1922        let mut packet_bytes_copy = packet_bytes;
1923        let mut packet_bytes_ref: &mut [u8] = &mut packet_bytes_copy[..];
1924        let packet = packet_bytes_ref.parse::<Ipv4Packet<_>>().unwrap();
1925
1926        for i in 1..(packet_len + 1) {
1927            let mut buf = vec![0u8; i];
1928            let result =
1929                packet.partial_serialize(PacketConstraints::UNCONSTRAINED, buf.as_mut_slice());
1930
1931            let bytes_written = if i >= packet_len { packet_len } else { i };
1932            assert_eq!(
1933                result,
1934                Ok(PartialSerializeResult { bytes_written, total_size: packet_len })
1935            );
1936            assert_eq!(buf[..bytes_written], packet_bytes[..bytes_written]);
1937        }
1938    }
1939}