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