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