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