Skip to main content

packet_formats/
ipv4.rs

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