Skip to main content

packet_formats/
ipv4.rs

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