netstack3_filter/
packets.rs

1// Copyright 2024 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
5use core::convert::Infallible as Never;
6use core::fmt::Debug;
7use core::num::NonZeroU16;
8
9use net_types::ip::{
10    GenericOverIp, Ip, IpAddress, IpInvariant, IpVersionMarker, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr,
11};
12use netstack3_base::{Options, PayloadLen, SegmentHeader};
13use packet::{
14    Buf, Buffer, BufferMut, BufferProvider, BufferViewMut, DynSerializer, DynamicSerializer,
15    EitherSerializer, EmptyBuf, GrowBufferMut, InnerSerializer, LayoutBufferAlloc, Nested,
16    PacketBuilder, PacketConstraints, ParsablePacket, ParseBuffer, ParseMetadata,
17    PartialSerializeResult, PartialSerializer, SerializeError, Serializer, SliceBufViewMut,
18    TruncatingSerializer,
19};
20use packet_formats::icmp::mld::{
21    MulticastListenerDone, MulticastListenerQuery, MulticastListenerQueryV2,
22    MulticastListenerReport, MulticastListenerReportV2,
23};
24use packet_formats::icmp::ndp::options::NdpOptionBuilder;
25use packet_formats::icmp::ndp::{
26    NeighborAdvertisement, NeighborSolicitation, Redirect, RouterAdvertisement, RouterSolicitation,
27};
28use packet_formats::icmp::{
29    self, IcmpDestUnreachable, IcmpEchoReply, IcmpEchoRequest, IcmpPacketBuilder, IcmpPacketRaw,
30    IcmpPacketTypeRaw as _, IcmpTimeExceeded, Icmpv4MessageType, Icmpv4PacketRaw,
31    Icmpv4ParameterProblem, Icmpv4Redirect, Icmpv4TimestampReply, Icmpv4TimestampRequest,
32    Icmpv6MessageType, Icmpv6PacketRaw, Icmpv6PacketTooBig, Icmpv6ParameterProblem,
33};
34use packet_formats::igmp::messages::IgmpMembershipReportV3Builder;
35use packet_formats::igmp::{self, IgmpPacketBuilder};
36use packet_formats::ip::{IpExt, IpPacketBuilder, IpProto, Ipv4Proto, Ipv6Proto};
37use packet_formats::ipv4::{Ipv4Header, Ipv4Packet, Ipv4PacketRaw};
38use packet_formats::ipv6::{Ipv6Header, Ipv6Packet, Ipv6PacketRaw};
39use packet_formats::tcp::options::TcpOptionsBuilder;
40use packet_formats::tcp::{TcpSegmentBuilderWithOptions, TcpSegmentRaw};
41use packet_formats::udp::{UdpPacketBuilder, UdpPacketRaw};
42use zerocopy::{SplitByteSlice, SplitByteSliceMut};
43
44use crate::conntrack;
45
46/// An IP extension trait for the filtering crate.
47pub trait FilterIpExt: IpExt {
48    /// A marker type to add an [`IpPacket`] bound to [`Self::Packet`].
49    type FilterIpPacket<B: SplitByteSliceMut>: FilterIpPacket<Self>;
50
51    /// A marker type to add an [`IpPacket`] bound to
52    /// [`Self::PacketRaw`].
53    type FilterIpPacketRaw<B: SplitByteSliceMut>: IpPacket<Self>;
54
55    /// A no-op conversion to help the compiler identify that [`Self::Packet`]
56    /// actually implements [`IpPacket`].
57    fn as_filter_packet<B: SplitByteSliceMut>(
58        packet: &mut Self::Packet<B>,
59    ) -> &mut Self::FilterIpPacket<B>;
60
61    /// The same as [`FilterIpExt::as_filter_packet`], but for owned values.
62    fn as_filter_packet_owned<B: SplitByteSliceMut>(
63        packet: Self::Packet<B>,
64    ) -> Self::FilterIpPacket<B>;
65
66    /// The same as [`FilterIpExt::as_filter_packet_owned`], but for owned raw
67    /// values.
68    fn as_filter_packet_raw_owned<B: SplitByteSliceMut>(
69        packet: Self::PacketRaw<B>,
70    ) -> Self::FilterIpPacketRaw<B>;
71}
72
73impl FilterIpExt for Ipv4 {
74    type FilterIpPacket<B: SplitByteSliceMut> = Ipv4Packet<B>;
75    type FilterIpPacketRaw<B: SplitByteSliceMut> = Ipv4PacketRaw<B>;
76
77    #[inline]
78    fn as_filter_packet<B: SplitByteSliceMut>(packet: &mut Ipv4Packet<B>) -> &mut Ipv4Packet<B> {
79        packet
80    }
81
82    #[inline]
83    fn as_filter_packet_owned<B: SplitByteSliceMut>(
84        packet: Self::Packet<B>,
85    ) -> Self::FilterIpPacket<B> {
86        packet
87    }
88
89    #[inline]
90    fn as_filter_packet_raw_owned<B: SplitByteSliceMut>(
91        packet: Self::PacketRaw<B>,
92    ) -> Self::FilterIpPacketRaw<B> {
93        packet
94    }
95}
96
97impl FilterIpExt for Ipv6 {
98    type FilterIpPacket<B: SplitByteSliceMut> = Ipv6Packet<B>;
99    type FilterIpPacketRaw<B: SplitByteSliceMut> = Ipv6PacketRaw<B>;
100
101    #[inline]
102    fn as_filter_packet<B: SplitByteSliceMut>(packet: &mut Ipv6Packet<B>) -> &mut Ipv6Packet<B> {
103        packet
104    }
105
106    #[inline]
107    fn as_filter_packet_owned<B: SplitByteSliceMut>(
108        packet: Self::Packet<B>,
109    ) -> Self::FilterIpPacket<B> {
110        packet
111    }
112
113    #[inline]
114    fn as_filter_packet_raw_owned<B: SplitByteSliceMut>(
115        packet: Self::PacketRaw<B>,
116    ) -> Self::FilterIpPacketRaw<B> {
117        packet
118    }
119}
120
121/// An IP packet that provides header inspection.
122pub trait IpPacket<I: FilterIpExt> {
123    /// The type that provides access to transport-layer header inspection, if a
124    /// transport header is contained in the body of the IP packet.
125    type TransportPacket<'a>: MaybeTransportPacket
126    where
127        Self: 'a;
128
129    /// The type that provides access to transport-layer header modification, if a
130    /// transport header is contained in the body of the IP packet.
131    type TransportPacketMut<'a>: MaybeTransportPacketMut<I>
132    where
133        Self: 'a;
134
135    /// The type that provides access to IP- and transport-layer information
136    /// within an ICMP error packet, if this IP packet contains one.
137    type IcmpError<'a>: MaybeIcmpErrorPayload<I>
138    where
139        Self: 'a;
140
141    /// The type that provides mutable access to the message within an ICMP
142    /// error packet, if this IP packet contains one.
143    type IcmpErrorMut<'a>: MaybeIcmpErrorMut<I>
144    where
145        Self: 'a;
146
147    /// The source IP address of the packet.
148    fn src_addr(&self) -> I::Addr;
149
150    /// Sets the source IP address of the packet.
151    fn set_src_addr(&mut self, addr: I::Addr);
152
153    /// The destination IP address of the packet.
154    fn dst_addr(&self) -> I::Addr;
155
156    /// Sets the destination IP address of the packet.
157    fn set_dst_addr(&mut self, addr: I::Addr);
158
159    /// The IP protocol of the packet.
160    fn protocol(&self) -> Option<I::Proto>;
161
162    /// Returns a type that provides access to the transport-layer packet contained
163    /// in the body of the IP packet, if one exists.
164    ///
165    /// This method returns an owned type parameterized on a lifetime that is tied
166    /// to the lifetime of Self, rather than, for example, a reference to a
167    /// non-parameterized type (`&Self::TransportPacket`). This is because
168    /// implementors may need to parse the transport header from the body of the IP
169    /// packet and materialize the results into a new type when this is called, but
170    /// that type may also need to retain a reference to the backing buffer in order
171    /// to modify the transport header.
172    fn maybe_transport_packet<'a>(&'a self) -> Self::TransportPacket<'a>;
173
174    /// Returns a type that provides the ability to modify the transport-layer
175    /// packet contained in the body of the IP packet, if one exists.
176    ///
177    /// This method returns an owned type parameterized on a lifetime that is tied
178    /// to the lifetime of Self, rather than, for example, a reference to a
179    /// non-parameterized type (`&Self::TransportPacketMut`). This is because
180    /// implementors may need to parse the transport header from the body of the IP
181    /// packet and materialize the results into a new type when this is called, but
182    /// that type may also need to retain a reference to the backing buffer in order
183    /// to modify the transport header.
184    fn transport_packet_mut<'a>(&'a mut self) -> Self::TransportPacketMut<'a>;
185
186    /// Returns a type that provides the ability to access the IP- and
187    /// transport-layer headers contained within the body of the ICMP error
188    /// message, if one exists in this packet.
189    ///
190    /// NOTE: See the note on [`IpPacket::maybe_transport_packet`].
191    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a>;
192
193    /// Returns a type that provides the ability to modify the IP- and
194    /// transport-layer headers contained within the body of the ICMP error
195    /// message, if one exists in this packet.
196    ///
197    /// NOTE: See the note on [`IpPacket::transport_packet_mut`].
198    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a>;
199
200    /// The header information to be used for connection tracking.
201    ///
202    /// For the transport header, this currently returns the same information as
203    /// [`IpPacket::maybe_transport_packet`], but may be different for packets
204    /// such as ICMP errors. In that case, we care about the inner IP packet for
205    /// connection tracking, but use the outer header for filtering.
206    ///
207    /// Subtlety: For ICMP packets, only request/response messages will have
208    /// a transport packet defined (and currently only ECHO messages do). This
209    /// gets us basic tracking for free, and lets us implicitly ignore ICMP
210    /// errors, which are not meant to be tracked.
211    ///
212    /// If other ICMP message types eventually have TransportPacket impls, then
213    /// this would lead to multiple message types being mapped to the same tuple
214    /// if they happen to have the same ID.
215    fn conntrack_packet(&self) -> Option<conntrack::PacketMetadata<I>> {
216        if let Some(payload) = self.maybe_icmp_error().icmp_error_payload() {
217            // Checks whether it's reasonable that `payload` is a payload inside
218            // an ICMP error with tuple `outer`.
219            //
220            // An ICMP error can be returned from any router between the sender
221            // and the receiver, from the receiver itself, or from the netstack
222            // on send (for synthetic errors). Therefore, an originating packet
223            // (A -> B) could end up in ICMP errors that look like:
224            //
225            // B -> A | A -> B
226            // R -> A | A -> B
227            // A -> A | A -> B
228            //
229            // where R is some router along the path from A to B.
230            //
231            // Notice that in both of these cases the destination address is
232            // always A. There's no more check we can make, even if we had
233            // access to conntrack data for the payload tuple. It's valid for us
234            // to compare addresses from the outer packet and the inner payload,
235            // even in the presence of NAT, because we can think of the payload
236            // and outer tuples as having come from the same "side" of the NAT,
237            // so we can pretend that NAT isn't occurring.
238            //
239            // Even if the tuples are compatible, it's not necessarily the
240            // case that conntrack will find a corresponding connection for
241            // the packet. That would require the payload tuple to belong to a
242            // preexisting conntrack connection.
243            (self.dst_addr() == payload.src_ip).then(|| {
244                conntrack::PacketMetadata::new_from_icmp_error(
245                    payload.src_ip,
246                    payload.dst_ip,
247                    payload.src_port,
248                    payload.dst_port,
249                    I::map_ip(payload.proto, |proto| proto.into(), |proto| proto.into()),
250                )
251            })
252        } else {
253            self.maybe_transport_packet().transport_packet_data().and_then(|transport_data| {
254                Some(conntrack::PacketMetadata::new(
255                    self.src_addr(),
256                    self.dst_addr(),
257                    I::map_ip(self.protocol()?, |proto| proto.into(), |proto| proto.into()),
258                    transport_data,
259                ))
260            })
261        }
262    }
263}
264
265/// An `IpPacket` that allows to access raw packet contents.
266// TODO(https://fxbug.dev/424212358): Currently this trait relies on
267// PartialSerializer to access raw packet contents. It should be replaced with
268// direct access to the packet contents when the packet is already serialized.
269pub trait FilterIpPacket<I: FilterIpExt>: IpPacket<I> + PartialSerializer {}
270impl<I: FilterIpExt, P: IpPacket<I> + PartialSerializer> FilterIpPacket<I> for P {}
271
272/// A payload of an IP packet that may be a valid transport layer packet.
273///
274/// This trait exists to allow bubbling up the trait bound that a serializer
275/// type implement `MaybeTransportPacket` from the IP socket layer to upper
276/// layers, where it can be implemented separately on each concrete packet type
277/// depending on whether it supports packet header inspection.
278pub trait MaybeTransportPacket {
279    /// Optionally returns a type that provides access to this transport-layer
280    /// packet.
281    fn transport_packet_data(&self) -> Option<TransportPacketData>;
282}
283
284/// A payload of an IP packet that may be a valid modifiable transport layer
285/// packet.
286///
287/// This trait exists to allow bubbling up the trait bound that a serializer
288/// type implement `MaybeTransportPacketMut` from the IP socket layer to upper
289/// layers, where it can be implemented separately on each concrete packet type
290/// depending on whether it supports packet header modification.
291pub trait MaybeTransportPacketMut<I: IpExt> {
292    /// The type that provides access to transport-layer header modification, if
293    /// this is indeed a valid transport packet.
294    type TransportPacketMut<'a>: TransportPacketMut<I>
295    where
296        Self: 'a;
297
298    /// Optionally returns a type that provides mutable access to this
299    /// transport-layer packet.
300    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>>;
301}
302
303/// An equivalent of [`MaybeTransportPacketMut`] that yields dynamic references
304/// to the inner transport packet.
305///
306/// This is hand-rolled for each implementer of `MaybeTransportPacketMut`
307/// because we don't quite have a trait to blanket impl this automatically for
308/// things that need it.
309///
310/// Perhaps after unsize is stabilized this can be blanket implemented. See
311/// https://github.com/rust-lang/rust/issues/18598.
312pub trait DynamicMaybeTransportPacketMut<I: IpExt> {
313    fn dyn_transport_packet_mut(&mut self) -> Option<&mut dyn TransportPacketMut<I>>;
314}
315
316/// A payload of an ICMP error packet that may contain an IP packet.
317///
318/// See also the note on [`MaybeTransportPacket`].
319pub trait MaybeIcmpErrorPayload<I: IpExt> {
320    /// Optionally returns a type that provides access to the payload of this
321    /// ICMP error.
322    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>>;
323}
324
325/// A payload of an IP packet that may be a valid modifiable ICMP error message
326/// (i.e., one that contains the prefix of an IP packet in its payload).
327pub trait MaybeIcmpErrorMut<I: FilterIpExt> {
328    type IcmpErrorMut<'a>: IcmpErrorMut<I>
329    where
330        Self: 'a;
331
332    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>>;
333}
334
335/// An equivalent of [`MaybeIcmpErrorMut`] that yields dynamic references
336/// to the inner ICMP packet.
337///
338/// This is hand-rolled for each implementer of `MaybeIcmpErrorMut`
339/// because we don't quite have a trait to blanket impl this automatically for
340/// things that need it.
341///
342/// Perhaps after unsize is stabilized this can be blanket implemented. See
343/// https://github.com/rust-lang/rust/issues/18598.
344pub trait DynamicMaybeIcmpErrorMut<I: IpExt> {
345    fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<I>>;
346}
347
348/// A serializer that may also be a valid transport layer packet.
349pub trait TransportPacketSerializer<I: FilterIpExt>:
350    Serializer
351    + PartialSerializer
352    + MaybeTransportPacket
353    + MaybeTransportPacketMut<I>
354    + MaybeIcmpErrorPayload<I>
355    + MaybeIcmpErrorMut<I>
356{
357}
358
359impl<I, S> TransportPacketSerializer<I> for S
360where
361    I: FilterIpExt,
362    S: Serializer
363        + PartialSerializer
364        + MaybeTransportPacket
365        + MaybeTransportPacketMut<I>
366        + MaybeIcmpErrorPayload<I>
367        + MaybeIcmpErrorMut<I>,
368{
369}
370
371/// A trait allowing transport serializers to be put behind a dyn reference.
372///
373/// This is dynamic-dispatch equivalent of [`TransportPacketSerializer`]. Used
374/// in conjunction with [`DynTransportSerializer`] it allows dynamic dispatch
375/// for slow-path protocols.
376pub trait DynamicTransportSerializer<I: FilterIpExt>:
377    DynamicSerializer
378    + PartialSerializer
379    + MaybeTransportPacket
380    + DynamicMaybeTransportPacketMut<I>
381    + DynamicMaybeIcmpErrorMut<I>
382    + MaybeIcmpErrorPayload<I>
383{
384}
385
386impl<O, I> DynamicTransportSerializer<I> for O
387where
388    O: TransportPacketSerializer<I>
389        + DynamicMaybeTransportPacketMut<I>
390        + DynamicMaybeIcmpErrorMut<I>,
391    I: FilterIpExt,
392{
393}
394
395/// A concrete type around a dynamic reference to a
396/// [`DynamicTransportSerializer`].
397pub struct DynTransportSerializer<'a, I: FilterIpExt>(&'a mut dyn DynamicTransportSerializer<I>);
398
399impl<'a, I: FilterIpExt> DynTransportSerializer<'a, I> {
400    /// Creates a new [`DynTransportSerializer`] with a dynamic mutable borrow
401    /// to a serializer.
402    pub fn new(inner: &'a mut dyn DynamicTransportSerializer<I>) -> Self {
403        Self(inner)
404    }
405}
406
407impl<I: FilterIpExt> Serializer for DynTransportSerializer<'_, I> {
408    type Buffer = EmptyBuf;
409
410    fn serialize<B: GrowBufferMut, P: BufferProvider<Self::Buffer, B>>(
411        self,
412        outer: PacketConstraints,
413        provider: P,
414    ) -> Result<B, (SerializeError<P::Error>, Self)> {
415        match DynSerializer::new_dyn(self.0).serialize(outer, provider) {
416            Ok(r) => Ok(r),
417            Err((e, _)) => Err((e, self)),
418        }
419    }
420
421    fn serialize_new_buf<B: GrowBufferMut, A: LayoutBufferAlloc<B>>(
422        &self,
423        outer: PacketConstraints,
424        alloc: A,
425    ) -> Result<B, SerializeError<A::Error>> {
426        DynSerializer::new_dyn(self.0).serialize_new_buf(outer, alloc)
427    }
428}
429
430impl<'a, I: FilterIpExt> PartialSerializer for DynTransportSerializer<'a, I> {
431    fn partial_serialize(
432        &self,
433        outer: PacketConstraints,
434        buffer: &mut [u8],
435    ) -> Result<PartialSerializeResult, SerializeError<Never>> {
436        (*self.0).partial_serialize(outer, buffer)
437    }
438}
439
440impl<'a, I: FilterIpExt> MaybeTransportPacket for DynTransportSerializer<'a, I> {
441    fn transport_packet_data(&self) -> Option<TransportPacketData> {
442        (*self.0).transport_packet_data()
443    }
444}
445
446impl<'a, I: FilterIpExt> MaybeIcmpErrorPayload<I> for DynTransportSerializer<'a, I> {
447    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
448        (*self.0).icmp_error_payload()
449    }
450}
451
452impl<'a, I: FilterIpExt> MaybeIcmpErrorMut<I> for DynTransportSerializer<'a, I> {
453    type IcmpErrorMut<'b>
454        = &'b mut dyn DynamicIcmpErrorMut<I>
455    where
456        Self: 'b;
457
458    fn icmp_error_mut(&mut self) -> Option<Self::IcmpErrorMut<'_>> {
459        (*self.0).dyn_icmp_error_mut()
460    }
461}
462
463impl<'a, I: FilterIpExt> MaybeTransportPacketMut<I> for DynTransportSerializer<'a, I> {
464    type TransportPacketMut<'b>
465        = &'b mut dyn TransportPacketMut<I>
466    where
467        Self: 'b;
468
469    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
470        (*self.0).dyn_transport_packet_mut()
471    }
472}
473
474impl<T: ?Sized> MaybeTransportPacket for &T
475where
476    T: MaybeTransportPacket,
477{
478    fn transport_packet_data(&self) -> Option<TransportPacketData> {
479        (**self).transport_packet_data()
480    }
481}
482
483impl<T: ?Sized, I: IpExt> MaybeIcmpErrorPayload<I> for &T
484where
485    T: MaybeIcmpErrorPayload<I>,
486{
487    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
488        (**self).icmp_error_payload()
489    }
490}
491
492impl<T: ?Sized> MaybeTransportPacket for &mut T
493where
494    T: MaybeTransportPacket,
495{
496    fn transport_packet_data(&self) -> Option<TransportPacketData> {
497        (**self).transport_packet_data()
498    }
499}
500
501impl<I: IpExt, T: ?Sized> MaybeTransportPacketMut<I> for &mut T
502where
503    T: MaybeTransportPacketMut<I>,
504{
505    type TransportPacketMut<'a>
506        = T::TransportPacketMut<'a>
507    where
508        Self: 'a;
509
510    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
511        (**self).transport_packet_mut()
512    }
513}
514
515impl<I: FilterIpExt, T: ?Sized> MaybeIcmpErrorMut<I> for &mut T
516where
517    T: MaybeIcmpErrorMut<I>,
518{
519    type IcmpErrorMut<'a>
520        = T::IcmpErrorMut<'a>
521    where
522        Self: 'a;
523
524    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
525        (**self).icmp_error_mut()
526    }
527}
528
529impl<I: FilterIpExt, T: ?Sized> IcmpErrorMut<I> for &mut T
530where
531    T: IcmpErrorMut<I>,
532{
533    type InnerPacket<'a>
534        = T::InnerPacket<'a>
535    where
536        Self: 'a;
537
538    fn recalculate_checksum(&mut self) -> bool {
539        (**self).recalculate_checksum()
540    }
541
542    fn inner_packet<'a>(&'a mut self) -> Option<Self::InnerPacket<'a>> {
543        (**self).inner_packet()
544    }
545}
546
547impl<I: IpExt, T: TransportPacketMut<I>> MaybeTransportPacketMut<I> for Option<T> {
548    type TransportPacketMut<'a>
549        = &'a mut T
550    where
551        Self: 'a;
552
553    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
554        self.as_mut()
555    }
556}
557
558impl<I: FilterIpExt, T> MaybeIcmpErrorMut<I> for Option<T>
559where
560    T: IcmpErrorMut<I>,
561{
562    type IcmpErrorMut<'a>
563        = &'a mut T
564    where
565        Self: 'a;
566
567    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
568        self.as_mut()
569    }
570}
571
572/// A concrete enum to hold all of the transport packet data that could possibly be usefully
573/// extracted from a packet.
574#[derive(Debug, Clone, GenericOverIp, PartialEq, Eq)]
575#[generic_over_ip()]
576pub enum TransportPacketData {
577    Tcp { src_port: u16, dst_port: u16, segment: SegmentHeader, payload_len: usize },
578    Generic { src_port: u16, dst_port: u16 },
579}
580
581impl TransportPacketData {
582    pub fn src_port(&self) -> u16 {
583        match self {
584            TransportPacketData::Tcp { src_port, .. }
585            | TransportPacketData::Generic { src_port, .. } => *src_port,
586        }
587    }
588
589    pub fn dst_port(&self) -> u16 {
590        match self {
591            TransportPacketData::Tcp { dst_port, .. }
592            | TransportPacketData::Generic { dst_port, .. } => *dst_port,
593        }
594    }
595
596    pub fn tcp_segment_and_len(&self) -> Option<(&SegmentHeader, usize)> {
597        match self {
598            TransportPacketData::Tcp { segment, payload_len, .. } => Some((&segment, *payload_len)),
599            TransportPacketData::Generic { .. } => None,
600        }
601    }
602
603    fn parse_in_ip_packet<I: IpExt, B: ParseBuffer>(
604        src_ip: I::Addr,
605        dst_ip: I::Addr,
606        proto: I::Proto,
607        body: B,
608    ) -> Option<TransportPacketData> {
609        I::map_ip(
610            (src_ip, dst_ip, proto, IpInvariant(body)),
611            |(src_ip, dst_ip, proto, IpInvariant(body))| {
612                parse_transport_header_in_ipv4_packet(src_ip, dst_ip, proto, body)
613            },
614            |(src_ip, dst_ip, proto, IpInvariant(body))| {
615                parse_transport_header_in_ipv6_packet(src_ip, dst_ip, proto, body)
616            },
617        )
618    }
619}
620
621/// A transport layer packet that provides header modification.
622//
623// TODO(https://fxbug.dev/341128580): make this trait more expressive for the
624// differences between transport protocols.
625pub trait TransportPacketMut<I: IpExt> {
626    /// Set the source port or identifier of the packet.
627    fn set_src_port(&mut self, port: NonZeroU16);
628
629    /// Set the destination port or identifier of the packet.
630    fn set_dst_port(&mut self, port: NonZeroU16);
631
632    /// Update the source IP address in the pseudo header.
633    fn update_pseudo_header_src_addr(&mut self, old: I::Addr, new: I::Addr);
634
635    /// Update the destination IP address in the pseudo header.
636    fn update_pseudo_header_dst_addr(&mut self, old: I::Addr, new: I::Addr);
637}
638
639/// An ICMP error packet that provides mutable access to the contained IP
640/// packet.
641pub trait IcmpErrorMut<I: FilterIpExt> {
642    type InnerPacket<'a>: IpPacket<I>
643    where
644        Self: 'a;
645
646    /// Fully recalculate the checksum of this ICMP packet.
647    ///
648    /// Returns whether the checksum was successfully written.
649    ///
650    /// Must be called after modifying the IP packet contained within this ICMP
651    /// error to ensure the checksum stays correct.
652    fn recalculate_checksum(&mut self) -> bool;
653
654    /// Returns an [`IpPacket`] of the packet contained within this error, if
655    /// one is present.
656    fn inner_packet<'a>(&'a mut self) -> Option<Self::InnerPacket<'a>>;
657}
658
659/// An equivalent of [`IcmpErrorMut`] that provides a `dyn-compatible` API for
660/// ICMP errors.
661///
662/// This has the same shape as [`IcmpErrorMut`] except for the associated type,
663/// forcing the inner packet type to something that is workable for all
664/// implementations.
665pub trait DynamicIcmpErrorMut<I: FilterIpExt> {
666    fn dyn_recalculate_checksum(&mut self) -> bool;
667    fn dyn_inner_packet(&mut self) -> Option<I::FilterIpPacketRaw<&mut [u8]>>;
668}
669
670impl<'a, I: FilterIpExt> IcmpErrorMut<I> for dyn DynamicIcmpErrorMut<I> + 'a {
671    type InnerPacket<'b>
672        = I::FilterIpPacketRaw<&'b mut [u8]>
673    where
674        Self: 'b;
675
676    fn recalculate_checksum(&mut self) -> bool {
677        self.dyn_recalculate_checksum()
678    }
679    fn inner_packet<'b>(&'b mut self) -> Option<Self::InnerPacket<'b>> {
680        self.dyn_inner_packet()
681    }
682}
683
684impl<B: SplitByteSliceMut> IpPacket<Ipv4> for Ipv4Packet<B> {
685    type TransportPacket<'a>
686        = &'a Self
687    where
688        Self: 'a;
689    type TransportPacketMut<'a>
690        = Option<ParsedTransportHeaderMut<'a, Ipv4>>
691    where
692        B: 'a;
693    type IcmpError<'a>
694        = &'a Self
695    where
696        Self: 'a;
697    type IcmpErrorMut<'a>
698        = Option<ParsedIcmpErrorMut<'a, Ipv4>>
699    where
700        B: 'a;
701
702    fn src_addr(&self) -> Ipv4Addr {
703        self.src_ip()
704    }
705
706    fn set_src_addr(&mut self, addr: Ipv4Addr) {
707        let old = self.src_addr();
708        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
709            packet.update_pseudo_header_src_addr(old, addr);
710        }
711
712        self.set_src_ip_and_update_checksum(addr);
713    }
714
715    fn dst_addr(&self) -> Ipv4Addr {
716        self.dst_ip()
717    }
718
719    fn set_dst_addr(&mut self, addr: Ipv4Addr) {
720        let old = self.dst_addr();
721        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
722            packet.update_pseudo_header_dst_addr(old, addr);
723        }
724
725        self.set_dst_ip_and_update_checksum(addr);
726    }
727
728    fn protocol(&self) -> Option<Ipv4Proto> {
729        Some(self.proto())
730    }
731
732    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
733        self
734    }
735
736    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
737        ParsedTransportHeaderMut::parse_in_ipv4_packet(
738            self.proto(),
739            SliceBufViewMut::new(self.body_mut()),
740        )
741    }
742
743    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
744        self
745    }
746
747    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
748        ParsedIcmpErrorMut::parse_in_ipv4_packet(
749            self.src_addr(),
750            self.dst_addr(),
751            self.proto(),
752            SliceBufViewMut::new(self.body_mut()),
753        )
754    }
755}
756
757impl<B: SplitByteSlice> MaybeTransportPacket for Ipv4Packet<B> {
758    fn transport_packet_data(&self) -> Option<TransportPacketData> {
759        parse_transport_header_in_ipv4_packet(
760            self.src_ip(),
761            self.dst_ip(),
762            self.proto(),
763            self.body(),
764        )
765    }
766}
767
768impl<B: SplitByteSlice> MaybeIcmpErrorPayload<Ipv4> for Ipv4Packet<B> {
769    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<Ipv4>> {
770        ParsedIcmpErrorPayload::parse_in_outer_ipv4_packet(self.proto(), Buf::new(self.body(), ..))
771    }
772}
773
774impl<B: SplitByteSliceMut> IpPacket<Ipv4> for Ipv4PacketRaw<B> {
775    type TransportPacket<'a>
776        = &'a Self
777    where
778        Self: 'a;
779    type TransportPacketMut<'a>
780        = Option<ParsedTransportHeaderMut<'a, Ipv4>>
781    where
782        B: 'a;
783    type IcmpError<'a>
784        = &'a Self
785    where
786        Self: 'a;
787    type IcmpErrorMut<'a>
788        = Option<ParsedIcmpErrorMut<'a, Ipv4>>
789    where
790        B: 'a;
791
792    fn src_addr(&self) -> Ipv4Addr {
793        self.src_ip()
794    }
795
796    fn set_src_addr(&mut self, addr: Ipv4Addr) {
797        let old = self.src_ip();
798        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
799            packet.update_pseudo_header_src_addr(old, addr);
800        }
801
802        self.set_src_ip_and_update_checksum(addr);
803    }
804
805    fn dst_addr(&self) -> Ipv4Addr {
806        self.dst_ip()
807    }
808
809    fn set_dst_addr(&mut self, addr: Ipv4Addr) {
810        let old = self.dst_ip();
811        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
812            packet.update_pseudo_header_dst_addr(old, addr);
813        }
814
815        self.set_dst_ip_and_update_checksum(addr);
816    }
817
818    fn protocol(&self) -> Option<Ipv4Proto> {
819        Some(self.proto())
820    }
821
822    fn maybe_transport_packet<'a>(&'a self) -> Self::TransportPacket<'a> {
823        self
824    }
825
826    fn transport_packet_mut<'a>(&'a mut self) -> Self::TransportPacketMut<'a> {
827        ParsedTransportHeaderMut::parse_in_ipv4_packet(
828            self.proto(),
829            SliceBufViewMut::new(self.body_mut()),
830        )
831    }
832
833    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
834        self
835    }
836
837    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
838        ParsedIcmpErrorMut::parse_in_ipv4_packet(
839            self.src_addr(),
840            self.dst_addr(),
841            self.proto(),
842            SliceBufViewMut::new(self.body_mut()),
843        )
844    }
845}
846
847impl<B: SplitByteSlice> MaybeTransportPacket for Ipv4PacketRaw<B> {
848    fn transport_packet_data(&self) -> Option<TransportPacketData> {
849        parse_transport_header_in_ipv4_packet(
850            self.src_ip(),
851            self.dst_ip(),
852            self.proto(),
853            // We don't particularly care whether we have the full packet, since
854            // we're only looking at transport headers.
855            self.body().into_inner(),
856        )
857    }
858}
859
860impl<B: SplitByteSlice> MaybeIcmpErrorPayload<Ipv4> for Ipv4PacketRaw<B> {
861    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<Ipv4>> {
862        ParsedIcmpErrorPayload::parse_in_outer_ipv4_packet(
863            self.proto(),
864            // We don't particularly care whether we have the full packet, since
865            // we're only looking at transport headers.
866            Buf::new(self.body().into_inner(), ..),
867        )
868    }
869}
870
871impl<B: SplitByteSliceMut> IpPacket<Ipv6> for Ipv6Packet<B> {
872    type TransportPacket<'a>
873        = &'a Self
874    where
875        Self: 'a;
876    type TransportPacketMut<'a>
877        = Option<ParsedTransportHeaderMut<'a, Ipv6>>
878    where
879        B: 'a;
880    type IcmpError<'a>
881        = &'a Self
882    where
883        Self: 'a;
884    type IcmpErrorMut<'a>
885        = Option<ParsedIcmpErrorMut<'a, Ipv6>>
886    where
887        B: 'a;
888
889    fn src_addr(&self) -> Ipv6Addr {
890        self.src_ip()
891    }
892
893    fn set_src_addr(&mut self, addr: Ipv6Addr) {
894        let old = self.src_addr();
895        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
896            packet.update_pseudo_header_src_addr(old, addr);
897        }
898
899        self.set_src_ip(addr);
900    }
901
902    fn dst_addr(&self) -> Ipv6Addr {
903        self.dst_ip()
904    }
905
906    fn set_dst_addr(&mut self, addr: Ipv6Addr) {
907        let old = self.dst_addr();
908        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
909            packet.update_pseudo_header_dst_addr(old, addr);
910        }
911
912        self.set_dst_ip(addr);
913    }
914
915    fn protocol(&self) -> Option<Ipv6Proto> {
916        Some(self.proto())
917    }
918
919    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
920        self
921    }
922
923    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
924        ParsedTransportHeaderMut::parse_in_ipv6_packet(
925            self.proto(),
926            SliceBufViewMut::new(self.body_mut()),
927        )
928    }
929
930    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
931        self
932    }
933
934    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
935        ParsedIcmpErrorMut::parse_in_ipv6_packet(
936            self.src_addr(),
937            self.dst_addr(),
938            self.proto(),
939            SliceBufViewMut::new(self.body_mut()),
940        )
941    }
942}
943
944impl<B: SplitByteSlice> MaybeTransportPacket for Ipv6Packet<B> {
945    fn transport_packet_data(&self) -> Option<TransportPacketData> {
946        parse_transport_header_in_ipv6_packet(
947            self.src_ip(),
948            self.dst_ip(),
949            self.proto(),
950            self.body(),
951        )
952    }
953}
954
955impl<B: SplitByteSlice> MaybeIcmpErrorPayload<Ipv6> for Ipv6Packet<B> {
956    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<Ipv6>> {
957        ParsedIcmpErrorPayload::parse_in_outer_ipv6_packet(self.proto(), Buf::new(self.body(), ..))
958    }
959}
960
961impl<B: SplitByteSliceMut> IpPacket<Ipv6> for Ipv6PacketRaw<B> {
962    type TransportPacket<'a>
963        = &'a Self
964    where
965        Self: 'a;
966    type TransportPacketMut<'a>
967        = Option<ParsedTransportHeaderMut<'a, Ipv6>>
968    where
969        B: 'a;
970    type IcmpError<'a>
971        = &'a Self
972    where
973        Self: 'a;
974    type IcmpErrorMut<'a>
975        = Option<ParsedIcmpErrorMut<'a, Ipv6>>
976    where
977        B: 'a;
978
979    fn src_addr(&self) -> Ipv6Addr {
980        self.src_ip()
981    }
982
983    fn set_src_addr(&mut self, addr: Ipv6Addr) {
984        let old = self.src_ip();
985        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
986            packet.update_pseudo_header_src_addr(old, addr);
987        }
988
989        self.set_src_ip(addr);
990    }
991
992    fn dst_addr(&self) -> Ipv6Addr {
993        self.dst_ip()
994    }
995
996    fn set_dst_addr(&mut self, addr: Ipv6Addr) {
997        let old = self.dst_ip();
998        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
999            packet.update_pseudo_header_dst_addr(old, addr);
1000        }
1001
1002        self.set_dst_ip(addr);
1003    }
1004
1005    fn protocol(&self) -> Option<Ipv6Proto> {
1006        self.proto().ok()
1007    }
1008
1009    fn maybe_transport_packet<'a>(&'a self) -> Self::TransportPacket<'a> {
1010        self
1011    }
1012
1013    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
1014        let proto = self.proto().ok()?;
1015        let body = self.body_mut()?;
1016        ParsedTransportHeaderMut::parse_in_ipv6_packet(proto, SliceBufViewMut::new(body))
1017    }
1018
1019    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
1020        self
1021    }
1022
1023    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
1024        let src_addr = self.src_addr();
1025        let dst_addr = self.dst_addr();
1026        let proto = self.proto().ok()?;
1027        let body = self.body_mut()?;
1028
1029        ParsedIcmpErrorMut::parse_in_ipv6_packet(
1030            src_addr,
1031            dst_addr,
1032            proto,
1033            SliceBufViewMut::new(body),
1034        )
1035    }
1036}
1037
1038impl<B: SplitByteSlice> MaybeTransportPacket for Ipv6PacketRaw<B> {
1039    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1040        let (body, proto) = self.body_proto().ok()?;
1041        parse_transport_header_in_ipv6_packet(
1042            self.src_ip(),
1043            self.dst_ip(),
1044            proto,
1045            body.into_inner(),
1046        )
1047    }
1048}
1049
1050impl<B: SplitByteSlice> MaybeIcmpErrorPayload<Ipv6> for Ipv6PacketRaw<B> {
1051    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<Ipv6>> {
1052        let (body, proto) = self.body_proto().ok()?;
1053        ParsedIcmpErrorPayload::parse_in_outer_ipv6_packet(proto, Buf::new(body.into_inner(), ..))
1054    }
1055}
1056
1057/// An outgoing IP packet that has not yet been wrapped into an outer serializer
1058/// type.
1059#[derive(Debug, PartialEq, GenericOverIp)]
1060#[generic_over_ip(I, Ip)]
1061pub struct TxPacket<'a, I: IpExt, S> {
1062    src_addr: I::Addr,
1063    dst_addr: I::Addr,
1064    protocol: I::Proto,
1065    serializer: &'a mut S,
1066}
1067
1068impl<'a, I: IpExt, S> TxPacket<'a, I, S> {
1069    /// Create a new [`TxPacket`] from its IP header fields and payload.
1070    pub fn new(
1071        src_addr: I::Addr,
1072        dst_addr: I::Addr,
1073        protocol: I::Proto,
1074        serializer: &'a mut S,
1075    ) -> Self {
1076        Self { src_addr, dst_addr, protocol, serializer }
1077    }
1078
1079    /// The source IP address of the packet.
1080    pub fn src_addr(&self) -> I::Addr {
1081        self.src_addr
1082    }
1083
1084    /// The destination IP address of the packet.
1085    pub fn dst_addr(&self) -> I::Addr {
1086        self.dst_addr
1087    }
1088}
1089
1090impl<I: FilterIpExt, S: TransportPacketSerializer<I>> IpPacket<I> for TxPacket<'_, I, S> {
1091    type TransportPacket<'a>
1092        = &'a S
1093    where
1094        Self: 'a;
1095    type TransportPacketMut<'a>
1096        = &'a mut S
1097    where
1098        Self: 'a;
1099    type IcmpError<'a>
1100        = &'a S
1101    where
1102        Self: 'a;
1103    type IcmpErrorMut<'a>
1104        = &'a mut S
1105    where
1106        Self: 'a;
1107
1108    fn src_addr(&self) -> I::Addr {
1109        self.src_addr
1110    }
1111
1112    fn set_src_addr(&mut self, addr: I::Addr) {
1113        let old = core::mem::replace(&mut self.src_addr, addr);
1114        if let Some(mut packet) = self.transport_packet_mut().transport_packet_mut() {
1115            packet.update_pseudo_header_src_addr(old, addr);
1116        }
1117    }
1118
1119    fn dst_addr(&self) -> I::Addr {
1120        self.dst_addr
1121    }
1122
1123    fn set_dst_addr(&mut self, addr: I::Addr) {
1124        let old = core::mem::replace(&mut self.dst_addr, addr);
1125        if let Some(mut packet) = self.transport_packet_mut().transport_packet_mut() {
1126            packet.update_pseudo_header_dst_addr(old, addr);
1127        }
1128    }
1129
1130    fn protocol(&self) -> Option<I::Proto> {
1131        Some(self.protocol)
1132    }
1133
1134    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
1135        self.serializer
1136    }
1137
1138    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
1139        self.serializer
1140    }
1141
1142    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
1143        self.serializer
1144    }
1145
1146    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
1147        self.serializer
1148    }
1149}
1150
1151/// Implements `PartialSerializer` for a reference to a `PartialSerializer`
1152/// implementation. It's not possible to provide a blanket implementation for
1153/// references directly (i.e. for `&S`) since it would conflict with the
1154/// implementation for `FragmentedBuffer`.
1155pub struct PartialSerializeRef<'a, S> {
1156    reference: &'a S,
1157}
1158
1159impl<'a, S: PartialSerializer> PartialSerializer for PartialSerializeRef<'a, S> {
1160    fn partial_serialize(
1161        &self,
1162        outer: PacketConstraints,
1163        buffer: &mut [u8],
1164    ) -> Result<PartialSerializeResult, SerializeError<Never>> {
1165        self.reference.partial_serialize(outer, buffer)
1166    }
1167}
1168
1169/// Value used in place of TTL in a partially-serialized TxPacket.
1170const TX_PACKET_NO_TTL: u8 = 0;
1171
1172/// `TxPacket` is used for eBPF CGROUP_EGRESS filters. At that level the packet
1173/// is not fragmented yet, so we don't have a final packet serializer, but the
1174/// eBPF filters want to see a serialized packet. We provide `PartialSerialize`,
1175/// which allows to serialize just the packet headers - that's enough for most
1176/// eBPF programs. TTL is not known here, so the field is set to 64.
1177impl<I: FilterIpExt, S: TransportPacketSerializer<I> + PartialSerializer> PartialSerializer
1178    for TxPacket<'_, I, S>
1179{
1180    fn partial_serialize(
1181        &self,
1182        outer: PacketConstraints,
1183        buffer: &mut [u8],
1184    ) -> Result<PartialSerializeResult, SerializeError<Never>> {
1185        let packet_builder =
1186            I::PacketBuilder::new(self.src_addr, self.dst_addr, TX_PACKET_NO_TTL, self.protocol);
1187        packet_builder
1188            .wrap_body(PartialSerializeRef { reference: self.serializer })
1189            .partial_serialize(outer, buffer)
1190    }
1191}
1192
1193/// An incoming IP packet that is being forwarded.
1194#[derive(Debug, PartialEq, GenericOverIp)]
1195#[generic_over_ip(I, Ip)]
1196pub struct ForwardedPacket<I: IpExt, B> {
1197    src_addr: I::Addr,
1198    dst_addr: I::Addr,
1199    protocol: I::Proto,
1200    transport_header_offset: usize,
1201    buffer: B,
1202}
1203
1204impl<I: IpExt, B: BufferMut> ForwardedPacket<I, B> {
1205    /// Create a new [`ForwardedPacket`] from its IP header fields and payload.
1206    ///
1207    /// `meta` is used to revert `buffer` back to the IP header for further
1208    /// serialization, and to mark where the transport header starts in
1209    /// `buffer`. It _must_ have originated from a previously parsed IP packet
1210    /// on `buffer`.
1211    pub fn new(
1212        src_addr: I::Addr,
1213        dst_addr: I::Addr,
1214        protocol: I::Proto,
1215        meta: ParseMetadata,
1216        mut buffer: B,
1217    ) -> Self {
1218        let transport_header_offset = meta.header_len();
1219        buffer.undo_parse(meta);
1220        Self { src_addr, dst_addr, protocol, transport_header_offset, buffer }
1221    }
1222
1223    /// Discard the metadata carried by the [`ForwardedPacket`] and return the
1224    /// inner buffer.
1225    ///
1226    /// The returned buffer is guaranteed to contain a valid IP frame, the
1227    /// start of the buffer points at the start of the IP header.
1228    pub fn into_buffer(self) -> B {
1229        self.buffer
1230    }
1231
1232    /// Returns a reference to the forwarded buffer.
1233    ///
1234    /// The returned reference is guaranteed to contain a valid IP frame, the
1235    /// start of the buffer points at the start of the IP header.
1236    pub fn buffer(&self) -> &B {
1237        &self.buffer
1238    }
1239}
1240
1241impl<I: IpExt, B: BufferMut> Serializer for ForwardedPacket<I, B> {
1242    type Buffer = <B as Serializer>::Buffer;
1243
1244    fn serialize<G: packet::GrowBufferMut, P: packet::BufferProvider<Self::Buffer, G>>(
1245        self,
1246        outer: packet::PacketConstraints,
1247        provider: P,
1248    ) -> Result<G, (packet::SerializeError<P::Error>, Self)> {
1249        let Self { src_addr, dst_addr, protocol, transport_header_offset, buffer } = self;
1250        buffer.serialize(outer, provider).map_err(|(err, buffer)| {
1251            (err, Self { src_addr, dst_addr, protocol, transport_header_offset, buffer })
1252        })
1253    }
1254
1255    fn serialize_new_buf<BB: GrowBufferMut, A: LayoutBufferAlloc<BB>>(
1256        &self,
1257        outer: packet::PacketConstraints,
1258        alloc: A,
1259    ) -> Result<BB, packet::SerializeError<A::Error>> {
1260        self.buffer.serialize_new_buf(outer, alloc)
1261    }
1262}
1263
1264impl<I: IpExt, B: BufferMut> PartialSerializer for ForwardedPacket<I, B> {
1265    fn partial_serialize(
1266        &self,
1267        _outer: PacketConstraints,
1268        mut buffer: &mut [u8],
1269    ) -> Result<PartialSerializeResult, SerializeError<Never>> {
1270        let mut buffer = &mut buffer;
1271        Ok(PartialSerializeResult {
1272            bytes_written: buffer.write_bytes_front_allow_partial(self.buffer.as_ref()),
1273            total_size: self.buffer.len(),
1274        })
1275    }
1276}
1277
1278impl<I: FilterIpExt, B: BufferMut> IpPacket<I> for ForwardedPacket<I, B> {
1279    type TransportPacket<'a>
1280        = &'a Self
1281    where
1282        Self: 'a;
1283    type TransportPacketMut<'a>
1284        = Option<ParsedTransportHeaderMut<'a, I>>
1285    where
1286        Self: 'a;
1287    type IcmpError<'a>
1288        = &'a Self
1289    where
1290        Self: 'a;
1291
1292    type IcmpErrorMut<'a>
1293        = Option<ParsedIcmpErrorMut<'a, I>>
1294    where
1295        Self: 'a;
1296
1297    fn src_addr(&self) -> I::Addr {
1298        self.src_addr
1299    }
1300
1301    fn set_src_addr(&mut self, addr: I::Addr) {
1302        // Re-parse the IP header so we can modify it in place.
1303        I::map_ip::<_, ()>(
1304            (IpInvariant(self.buffer.as_mut()), addr),
1305            |(IpInvariant(buffer), addr)| {
1306                let mut packet = Ipv4PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
1307                    .expect("ForwardedPacket must have been created from a valid IP packet");
1308                packet.set_src_ip_and_update_checksum(addr);
1309            },
1310            |(IpInvariant(buffer), addr)| {
1311                let mut packet = Ipv6PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
1312                    .expect("ForwardedPacket must have been created from a valid IP packet");
1313                packet.set_src_ip(addr);
1314            },
1315        );
1316
1317        let old = self.src_addr;
1318        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
1319            packet.update_pseudo_header_src_addr(old, addr);
1320        }
1321
1322        self.src_addr = addr;
1323    }
1324
1325    fn dst_addr(&self) -> I::Addr {
1326        self.dst_addr
1327    }
1328
1329    fn set_dst_addr(&mut self, addr: I::Addr) {
1330        // Re-parse the IP header so we can modify it in place.
1331        I::map_ip::<_, ()>(
1332            (IpInvariant(self.buffer.as_mut()), addr),
1333            |(IpInvariant(buffer), addr)| {
1334                let mut packet = Ipv4PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
1335                    .expect("ForwardedPacket must have been created from a valid IP packet");
1336                packet.set_dst_ip_and_update_checksum(addr);
1337            },
1338            |(IpInvariant(buffer), addr)| {
1339                let mut packet = Ipv6PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
1340                    .expect("ForwardedPacket must have been created from a valid IP packet");
1341                packet.set_dst_ip(addr);
1342            },
1343        );
1344
1345        let old = self.dst_addr;
1346        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
1347            packet.update_pseudo_header_dst_addr(old, addr);
1348        }
1349
1350        self.dst_addr = addr;
1351    }
1352
1353    fn protocol(&self) -> Option<I::Proto> {
1354        Some(self.protocol)
1355    }
1356
1357    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
1358        self
1359    }
1360
1361    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
1362        let ForwardedPacket { src_addr: _, dst_addr: _, protocol, buffer, transport_header_offset } =
1363            self;
1364        ParsedTransportHeaderMut::<I>::parse_in_ip_packet(
1365            *protocol,
1366            SliceBufViewMut::new(&mut buffer.as_mut()[*transport_header_offset..]),
1367        )
1368    }
1369
1370    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
1371        self
1372    }
1373
1374    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
1375        let ForwardedPacket { src_addr, dst_addr, protocol, buffer, transport_header_offset } =
1376            self;
1377
1378        ParsedIcmpErrorMut::<I>::parse_in_ip_packet(
1379            *src_addr,
1380            *dst_addr,
1381            *protocol,
1382            SliceBufViewMut::new(&mut buffer.as_mut()[*transport_header_offset..]),
1383        )
1384    }
1385}
1386
1387impl<I: IpExt, B: BufferMut> MaybeTransportPacket for ForwardedPacket<I, B> {
1388    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1389        let ForwardedPacket { protocol, buffer, src_addr, dst_addr, transport_header_offset } =
1390            self;
1391        TransportPacketData::parse_in_ip_packet::<I, _>(
1392            *src_addr,
1393            *dst_addr,
1394            *protocol,
1395            Buf::new(&buffer.as_ref()[*transport_header_offset..], ..),
1396        )
1397    }
1398}
1399
1400impl<I: IpExt, B: BufferMut> MaybeIcmpErrorPayload<I> for ForwardedPacket<I, B> {
1401    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1402        let Self { src_addr: _, dst_addr: _, protocol, transport_header_offset, buffer } = self;
1403        ParsedIcmpErrorPayload::parse_in_outer_ip_packet(
1404            *protocol,
1405            Buf::new(&buffer.as_ref()[*transport_header_offset..], ..),
1406        )
1407    }
1408}
1409
1410impl<I: FilterIpExt, S: TransportPacketSerializer<I>, B: IpPacketBuilder<I>> IpPacket<I>
1411    for Nested<S, B>
1412{
1413    type TransportPacket<'a>
1414        = &'a S
1415    where
1416        Self: 'a;
1417    type TransportPacketMut<'a>
1418        = &'a mut S
1419    where
1420        Self: 'a;
1421    type IcmpError<'a>
1422        = &'a S
1423    where
1424        Self: 'a;
1425    type IcmpErrorMut<'a>
1426        = &'a mut S
1427    where
1428        Self: 'a;
1429
1430    fn src_addr(&self) -> I::Addr {
1431        self.outer().src_ip()
1432    }
1433
1434    fn set_src_addr(&mut self, addr: I::Addr) {
1435        let old = self.outer().src_ip();
1436        self.outer_mut().set_src_ip(addr);
1437        if let Some(mut packet) = self.transport_packet_mut().transport_packet_mut() {
1438            packet.update_pseudo_header_src_addr(old, addr);
1439        }
1440    }
1441
1442    fn dst_addr(&self) -> I::Addr {
1443        self.outer().dst_ip()
1444    }
1445
1446    fn set_dst_addr(&mut self, addr: I::Addr) {
1447        let old = self.outer().dst_ip();
1448        self.outer_mut().set_dst_ip(addr);
1449        if let Some(mut packet) = self.transport_packet_mut().transport_packet_mut() {
1450            packet.update_pseudo_header_dst_addr(old, addr);
1451        }
1452    }
1453
1454    fn protocol(&self) -> Option<I::Proto> {
1455        Some(self.outer().proto())
1456    }
1457
1458    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
1459        self.inner()
1460    }
1461
1462    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
1463        self.inner_mut()
1464    }
1465
1466    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
1467        self.inner()
1468    }
1469
1470    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
1471        self.inner_mut()
1472    }
1473}
1474
1475impl<I: IpExt, T: ?Sized> TransportPacketMut<I> for &mut T
1476where
1477    T: TransportPacketMut<I>,
1478{
1479    fn set_src_port(&mut self, port: NonZeroU16) {
1480        (*self).set_src_port(port);
1481    }
1482
1483    fn set_dst_port(&mut self, port: NonZeroU16) {
1484        (*self).set_dst_port(port);
1485    }
1486
1487    fn update_pseudo_header_src_addr(&mut self, old: I::Addr, new: I::Addr) {
1488        (*self).update_pseudo_header_src_addr(old, new);
1489    }
1490
1491    fn update_pseudo_header_dst_addr(&mut self, old: I::Addr, new: I::Addr) {
1492        (*self).update_pseudo_header_dst_addr(old, new);
1493    }
1494}
1495
1496impl<I: FilterIpExt> IpPacket<I> for Never {
1497    type TransportPacket<'a>
1498        = Never
1499    where
1500        Self: 'a;
1501    type TransportPacketMut<'a>
1502        = Never
1503    where
1504        Self: 'a;
1505    type IcmpError<'a>
1506        = Never
1507    where
1508        Self: 'a;
1509    type IcmpErrorMut<'a>
1510        = Never
1511    where
1512        Self: 'a;
1513
1514    fn src_addr(&self) -> I::Addr {
1515        match *self {}
1516    }
1517
1518    fn set_src_addr(&mut self, _addr: I::Addr) {
1519        match *self {}
1520    }
1521
1522    fn dst_addr(&self) -> I::Addr {
1523        match *self {}
1524    }
1525
1526    fn protocol(&self) -> Option<I::Proto> {
1527        match *self {}
1528    }
1529
1530    fn set_dst_addr(&mut self, _addr: I::Addr) {
1531        match *self {}
1532    }
1533
1534    fn maybe_transport_packet<'a>(&'a self) -> Self::TransportPacket<'a> {
1535        match *self {}
1536    }
1537
1538    fn transport_packet_mut<'a>(&'a mut self) -> Self::TransportPacketMut<'a> {
1539        match *self {}
1540    }
1541
1542    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
1543        match *self {}
1544    }
1545
1546    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
1547        match *self {}
1548    }
1549}
1550
1551impl MaybeTransportPacket for Never {
1552    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1553        match *self {}
1554    }
1555}
1556
1557impl<I: IpExt> MaybeTransportPacketMut<I> for Never {
1558    type TransportPacketMut<'a>
1559        = Never
1560    where
1561        Self: 'a;
1562
1563    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1564        match *self {}
1565    }
1566}
1567
1568impl<I: IpExt> TransportPacketMut<I> for Never {
1569    fn set_src_port(&mut self, _: NonZeroU16) {
1570        match *self {}
1571    }
1572
1573    fn set_dst_port(&mut self, _: NonZeroU16) {
1574        match *self {}
1575    }
1576
1577    fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {
1578        match *self {}
1579    }
1580
1581    fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {
1582        match *self {}
1583    }
1584}
1585
1586impl<I: IpExt> MaybeIcmpErrorPayload<I> for Never {
1587    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1588        match *self {}
1589    }
1590}
1591
1592impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for Never {
1593    type IcmpErrorMut<'a>
1594        = Never
1595    where
1596        Self: 'a;
1597
1598    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
1599        match *self {}
1600    }
1601}
1602
1603impl<I: FilterIpExt> IcmpErrorMut<I> for Never {
1604    type InnerPacket<'a>
1605        = Never
1606    where
1607        Self: 'a;
1608
1609    fn inner_packet<'a>(&'a mut self) -> Option<Self::InnerPacket<'a>> {
1610        match *self {}
1611    }
1612
1613    fn recalculate_checksum(&mut self) -> bool {
1614        match *self {}
1615    }
1616}
1617
1618impl<A: IpAddress, Inner> MaybeTransportPacket for Nested<Inner, UdpPacketBuilder<A>> {
1619    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1620        Some(TransportPacketData::Generic {
1621            src_port: self.outer().src_port().map_or(0, NonZeroU16::get),
1622            dst_port: self.outer().dst_port().map_or(0, NonZeroU16::get),
1623        })
1624    }
1625}
1626
1627impl<I: IpExt, Inner> MaybeTransportPacketMut<I> for Nested<Inner, UdpPacketBuilder<I::Addr>> {
1628    type TransportPacketMut<'a>
1629        = &'a mut Self
1630    where
1631        Self: 'a;
1632
1633    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1634        Some(self)
1635    }
1636}
1637
1638impl<I: IpExt, Inner> TransportPacketMut<I> for Nested<Inner, UdpPacketBuilder<I::Addr>> {
1639    fn set_src_port(&mut self, port: NonZeroU16) {
1640        self.outer_mut().set_src_port(port.get());
1641    }
1642
1643    fn set_dst_port(&mut self, port: NonZeroU16) {
1644        self.outer_mut().set_dst_port(port);
1645    }
1646
1647    fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
1648        self.outer_mut().set_src_ip(new);
1649    }
1650
1651    fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
1652        self.outer_mut().set_dst_ip(new);
1653    }
1654}
1655
1656impl<A: IpAddress, I: IpExt, Inner> MaybeIcmpErrorPayload<I>
1657    for Nested<Inner, UdpPacketBuilder<A>>
1658{
1659    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1660        None
1661    }
1662}
1663
1664impl<A: IpAddress, I: FilterIpExt, Inner> MaybeIcmpErrorMut<I>
1665    for Nested<Inner, UdpPacketBuilder<A>>
1666{
1667    type IcmpErrorMut<'a>
1668        = Never
1669    where
1670        Self: 'a;
1671
1672    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
1673        None
1674    }
1675}
1676
1677impl<'a, A: IpAddress, Inner: PayloadLen> MaybeTransportPacket
1678    for Nested<Inner, TcpSegmentBuilderWithOptions<A, TcpOptionsBuilder<'a>>>
1679{
1680    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1681        Some(TransportPacketData::Tcp {
1682            src_port: self.outer().src_port().map_or(0, NonZeroU16::get),
1683            dst_port: self.outer().dst_port().map_or(0, NonZeroU16::get),
1684            segment: self.outer().try_into().ok()?,
1685            payload_len: self.inner().len(),
1686        })
1687    }
1688}
1689
1690impl<I: IpExt, Outer, Inner> MaybeTransportPacketMut<I>
1691    for Nested<Inner, TcpSegmentBuilderWithOptions<I::Addr, Outer>>
1692{
1693    type TransportPacketMut<'a>
1694        = &'a mut Self
1695    where
1696        Self: 'a;
1697
1698    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1699        Some(self)
1700    }
1701}
1702
1703impl<I: IpExt, Outer, Inner> TransportPacketMut<I>
1704    for Nested<Inner, TcpSegmentBuilderWithOptions<I::Addr, Outer>>
1705{
1706    fn set_src_port(&mut self, port: NonZeroU16) {
1707        self.outer_mut().set_src_port(port);
1708    }
1709
1710    fn set_dst_port(&mut self, port: NonZeroU16) {
1711        self.outer_mut().set_dst_port(port);
1712    }
1713
1714    fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
1715        self.outer_mut().set_src_ip(new);
1716    }
1717
1718    fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
1719        self.outer_mut().set_dst_ip(new);
1720    }
1721}
1722
1723impl<A: IpAddress, I: IpExt, Inner, O> MaybeIcmpErrorPayload<I>
1724    for Nested<Inner, TcpSegmentBuilderWithOptions<A, O>>
1725{
1726    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1727        None
1728    }
1729}
1730
1731impl<A: IpAddress, I: FilterIpExt, Inner, O> MaybeIcmpErrorMut<I>
1732    for Nested<Inner, TcpSegmentBuilderWithOptions<A, O>>
1733{
1734    type IcmpErrorMut<'a>
1735        = Never
1736    where
1737        Self: 'a;
1738
1739    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
1740        None
1741    }
1742}
1743
1744impl<I: IpExt, Inner, M: IcmpMessage<I>> MaybeTransportPacket
1745    for Nested<Inner, IcmpPacketBuilder<I, M>>
1746{
1747    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1748        self.outer().message().transport_packet_data()
1749    }
1750}
1751
1752impl<I: IpExt, Inner, M: IcmpMessage<I>> MaybeTransportPacketMut<I>
1753    for Nested<Inner, IcmpPacketBuilder<I, M>>
1754{
1755    type TransportPacketMut<'a>
1756        = &'a mut IcmpPacketBuilder<I, M>
1757    where
1758        M: 'a,
1759        Inner: 'a;
1760
1761    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1762        Some(self.outer_mut())
1763    }
1764}
1765
1766impl<I: IpExt, Inner, M: IcmpMessage<I>> DynamicMaybeTransportPacketMut<I>
1767    for Nested<Inner, IcmpPacketBuilder<I, M>>
1768{
1769    fn dyn_transport_packet_mut(&mut self) -> Option<&mut dyn TransportPacketMut<I>> {
1770        MaybeTransportPacketMut::transport_packet_mut(self).map(|x| x as _)
1771    }
1772}
1773
1774impl<I: IpExt, M: IcmpMessage<I>> TransportPacketMut<I> for IcmpPacketBuilder<I, M> {
1775    fn set_src_port(&mut self, id: NonZeroU16) {
1776        if M::IS_REWRITABLE {
1777            let _: u16 = self.message_mut().update_icmp_id(id.get());
1778        }
1779    }
1780
1781    fn set_dst_port(&mut self, id: NonZeroU16) {
1782        if M::IS_REWRITABLE {
1783            let _: u16 = self.message_mut().update_icmp_id(id.get());
1784        }
1785    }
1786
1787    fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
1788        self.set_src_ip(new);
1789    }
1790
1791    fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
1792        self.set_dst_ip(new);
1793    }
1794}
1795
1796impl<Inner, I: IpExt> MaybeIcmpErrorPayload<I>
1797    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoRequest>>
1798{
1799    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1800        None
1801    }
1802}
1803
1804impl<Inner, I: FilterIpExt> MaybeIcmpErrorMut<I>
1805    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoRequest>>
1806{
1807    type IcmpErrorMut<'a>
1808        = Never
1809    where
1810        Self: 'a;
1811
1812    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
1813        None
1814    }
1815}
1816
1817impl<Inner, I: FilterIpExt> DynamicMaybeIcmpErrorMut<I>
1818    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoRequest>>
1819{
1820    fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<I>> {
1821        MaybeIcmpErrorMut::<I>::icmp_error_mut(self).map(|x| match x {})
1822    }
1823}
1824
1825impl<Inner, I: IpExt> MaybeIcmpErrorPayload<I>
1826    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoReply>>
1827{
1828    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1829        None
1830    }
1831}
1832
1833impl<Inner, I: FilterIpExt> MaybeIcmpErrorMut<I>
1834    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoReply>>
1835{
1836    type IcmpErrorMut<'a>
1837        = Never
1838    where
1839        Self: 'a;
1840
1841    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
1842        None
1843    }
1844}
1845
1846impl<Inner, I: FilterIpExt> DynamicMaybeIcmpErrorMut<I>
1847    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoReply>>
1848{
1849    fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<I>> {
1850        MaybeIcmpErrorMut::<I>::icmp_error_mut(self).map(|x| match x {})
1851    }
1852}
1853
1854/// An ICMP message type that may allow for transport-layer packet inspection.
1855pub trait IcmpMessage<I: IpExt>: icmp::IcmpMessage<I> + MaybeTransportPacket {
1856    /// Whether this ICMP message supports rewriting the ID.
1857    const IS_REWRITABLE: bool;
1858
1859    /// The same as [`IcmpMessage::IS_REWRITABLE`], but for when you have an
1860    /// object, rather than a type.
1861    fn is_rewritable(&self) -> bool {
1862        Self::IS_REWRITABLE
1863    }
1864
1865    /// Sets the ICMP ID for the message, returning the previous value.
1866    ///
1867    /// The ICMP ID is both the *src* AND *dst* ports for conntrack entries.
1868    fn update_icmp_id(&mut self, id: u16) -> u16;
1869}
1870
1871// TODO(https://fxbug.dev/341128580): connection tracking will probably want to
1872// special case ICMP echo packets to ensure that a new connection is only ever
1873// created from an echo request, and not an echo response. We need to provide a
1874// way for conntrack to differentiate between the two.
1875impl MaybeTransportPacket for IcmpEchoReply {
1876    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1877        Some(TransportPacketData::Generic { src_port: self.id(), dst_port: self.id() })
1878    }
1879}
1880
1881impl<I: IpExt> IcmpMessage<I> for IcmpEchoReply {
1882    const IS_REWRITABLE: bool = true;
1883
1884    fn update_icmp_id(&mut self, id: u16) -> u16 {
1885        let old = self.id();
1886        self.set_id(id);
1887        old
1888    }
1889}
1890
1891// TODO(https://fxbug.dev/341128580): connection tracking will probably want to
1892// special case ICMP echo packets to ensure that a new connection is only ever
1893// created from an echo request, and not an echo response. We need to provide a
1894// way for conntrack to differentiate between the two.
1895impl MaybeTransportPacket for IcmpEchoRequest {
1896    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1897        Some(TransportPacketData::Generic { src_port: self.id(), dst_port: self.id() })
1898    }
1899}
1900
1901impl<I: IpExt> IcmpMessage<I> for IcmpEchoRequest {
1902    const IS_REWRITABLE: bool = true;
1903
1904    fn update_icmp_id(&mut self, id: u16) -> u16 {
1905        let old = self.id();
1906        self.set_id(id);
1907        old
1908    }
1909}
1910
1911macro_rules! unsupported_icmp_message_type {
1912    ($message:ty, $($ips:ty),+) => {
1913        impl MaybeTransportPacket for $message {
1914            fn transport_packet_data(&self) -> Option<TransportPacketData> {
1915                None
1916            }
1917        }
1918
1919        $(
1920            impl IcmpMessage<$ips> for $message {
1921                const IS_REWRITABLE: bool = false;
1922
1923                fn update_icmp_id(&mut self, _: u16) -> u16 {
1924                    unreachable!("non-echo ICMP packets should never be rewritten")
1925                }
1926            }
1927        )+
1928    };
1929}
1930
1931unsupported_icmp_message_type!(Icmpv4TimestampRequest, Ipv4);
1932unsupported_icmp_message_type!(Icmpv4TimestampReply, Ipv4);
1933unsupported_icmp_message_type!(NeighborSolicitation, Ipv6);
1934unsupported_icmp_message_type!(NeighborAdvertisement, Ipv6);
1935unsupported_icmp_message_type!(RouterSolicitation, Ipv6);
1936unsupported_icmp_message_type!(MulticastListenerDone, Ipv6);
1937unsupported_icmp_message_type!(MulticastListenerReport, Ipv6);
1938unsupported_icmp_message_type!(MulticastListenerReportV2, Ipv6);
1939unsupported_icmp_message_type!(MulticastListenerQuery, Ipv6);
1940unsupported_icmp_message_type!(MulticastListenerQueryV2, Ipv6);
1941unsupported_icmp_message_type!(RouterAdvertisement, Ipv6);
1942// This isn't considered an error because, unlike ICMPv4, an ICMPv6 Redirect
1943// message doesn't contain an IP packet payload (RFC 2461 Section 4.5).
1944unsupported_icmp_message_type!(Redirect, Ipv6);
1945
1946/// Implement For ICMP message that aren't errors.
1947macro_rules! non_error_icmp_message_type {
1948    ($message:ty, $ip:ty) => {
1949        impl<Inner> MaybeIcmpErrorPayload<$ip> for Nested<Inner, IcmpPacketBuilder<$ip, $message>> {
1950            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<$ip>> {
1951                None
1952            }
1953        }
1954
1955        impl<Inner> MaybeIcmpErrorMut<$ip> for Nested<Inner, IcmpPacketBuilder<$ip, $message>> {
1956            type IcmpErrorMut<'a>
1957                = Never
1958            where
1959                Self: 'a;
1960
1961            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
1962                None
1963            }
1964        }
1965
1966        impl<Inner> DynamicMaybeIcmpErrorMut<$ip>
1967            for Nested<Inner, IcmpPacketBuilder<$ip, $message>>
1968        {
1969            fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<$ip>> {
1970                MaybeIcmpErrorMut::icmp_error_mut(self).map(|x| match x {})
1971            }
1972        }
1973    };
1974}
1975
1976non_error_icmp_message_type!(Icmpv4TimestampRequest, Ipv4);
1977non_error_icmp_message_type!(Icmpv4TimestampReply, Ipv4);
1978non_error_icmp_message_type!(RouterSolicitation, Ipv6);
1979non_error_icmp_message_type!(RouterAdvertisement, Ipv6);
1980non_error_icmp_message_type!(NeighborSolicitation, Ipv6);
1981non_error_icmp_message_type!(NeighborAdvertisement, Ipv6);
1982non_error_icmp_message_type!(MulticastListenerReport, Ipv6);
1983non_error_icmp_message_type!(MulticastListenerDone, Ipv6);
1984non_error_icmp_message_type!(MulticastListenerReportV2, Ipv6);
1985
1986macro_rules! icmp_error_message {
1987    ($message:ty, $($ips:ty),+) => {
1988        impl MaybeTransportPacket for $message {
1989            fn transport_packet_data(&self) -> Option<TransportPacketData> {
1990                None
1991            }
1992        }
1993
1994        $(
1995            impl IcmpMessage<$ips> for $message {
1996                const IS_REWRITABLE: bool = false;
1997
1998                fn update_icmp_id(&mut self, _: u16) -> u16 {
1999                    unreachable!("non-echo ICMP packets should never be rewritten")
2000                }
2001            }
2002        )+
2003    };
2004}
2005
2006icmp_error_message!(IcmpDestUnreachable, Ipv4, Ipv6);
2007icmp_error_message!(IcmpTimeExceeded, Ipv4, Ipv6);
2008icmp_error_message!(Icmpv4ParameterProblem, Ipv4);
2009icmp_error_message!(Icmpv4Redirect, Ipv4);
2010icmp_error_message!(Icmpv6ParameterProblem, Ipv6);
2011icmp_error_message!(Icmpv6PacketTooBig, Ipv6);
2012
2013macro_rules! icmpv4_error_message {
2014    ($message: ty) => {
2015        impl<Inner: AsRef<[u8]>> MaybeIcmpErrorPayload<Ipv4>
2016            for Nested<Inner, IcmpPacketBuilder<Ipv4, $message>>
2017        {
2018            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<Ipv4>> {
2019                ParsedIcmpErrorPayload::parse_in_icmpv4_error(Buf::new(self.inner(), ..))
2020            }
2021        }
2022
2023        impl<Inner: BufferMut> MaybeIcmpErrorMut<Ipv4>
2024            for Nested<Inner, IcmpPacketBuilder<Ipv4, $message>>
2025        {
2026            type IcmpErrorMut<'a>
2027                = &'a mut Self
2028            where
2029                Self: 'a;
2030
2031            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2032                Some(self)
2033            }
2034        }
2035
2036        impl<Inner: BufferMut> DynamicMaybeIcmpErrorMut<Ipv4>
2037            for Nested<Inner, IcmpPacketBuilder<Ipv4, $message>>
2038        {
2039            fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<Ipv4>> {
2040                MaybeIcmpErrorMut::icmp_error_mut(self).map(|x| x as _)
2041            }
2042        }
2043
2044        impl<Inner: BufferMut> IcmpErrorMut<Ipv4>
2045            for Nested<Inner, IcmpPacketBuilder<Ipv4, $message>>
2046        {
2047            type InnerPacket<'a>
2048                = Ipv4PacketRaw<&'a mut [u8]>
2049            where
2050                Self: 'a;
2051
2052            fn recalculate_checksum(&mut self) -> bool {
2053                // Checksum is calculated during serialization.
2054                true
2055            }
2056
2057            fn inner_packet<'a>(&'a mut self) -> Option<Self::InnerPacket<'a>> {
2058                let packet =
2059                    Ipv4PacketRaw::parse_mut(SliceBufViewMut::new(self.inner_mut().as_mut()), ())
2060                        .ok()?;
2061
2062                Some(packet)
2063            }
2064        }
2065
2066        impl<Inner: BufferMut> DynamicIcmpErrorMut<Ipv4>
2067            for Nested<Inner, IcmpPacketBuilder<Ipv4, $message>>
2068        {
2069            fn dyn_recalculate_checksum(&mut self) -> bool {
2070                self.recalculate_checksum()
2071            }
2072
2073            fn dyn_inner_packet(&mut self) -> Option<Ipv4PacketRaw<&mut [u8]>> {
2074                self.inner_packet()
2075            }
2076        }
2077    };
2078}
2079
2080icmpv4_error_message!(IcmpDestUnreachable);
2081icmpv4_error_message!(Icmpv4Redirect);
2082icmpv4_error_message!(IcmpTimeExceeded);
2083icmpv4_error_message!(Icmpv4ParameterProblem);
2084
2085macro_rules! icmpv6_error_message {
2086    ($message: ty) => {
2087        impl<Inner: Buffer> MaybeIcmpErrorPayload<Ipv6>
2088            for Nested<TruncatingSerializer<Inner>, IcmpPacketBuilder<Ipv6, $message>>
2089        {
2090            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<Ipv6>> {
2091                ParsedIcmpErrorPayload::parse_in_icmpv6_error(Buf::new(self.inner().buffer(), ..))
2092            }
2093        }
2094
2095        impl<Inner: BufferMut> MaybeIcmpErrorMut<Ipv6>
2096            for Nested<TruncatingSerializer<Inner>, IcmpPacketBuilder<Ipv6, $message>>
2097        {
2098            type IcmpErrorMut<'a>
2099                = &'a mut Self
2100            where
2101                Self: 'a;
2102
2103            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2104                Some(self)
2105            }
2106        }
2107
2108        impl<Inner: BufferMut> DynamicMaybeIcmpErrorMut<Ipv6>
2109            for Nested<TruncatingSerializer<Inner>, IcmpPacketBuilder<Ipv6, $message>>
2110        {
2111            fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<Ipv6>> {
2112                MaybeIcmpErrorMut::icmp_error_mut(self).map(|x| x as _)
2113            }
2114        }
2115
2116        impl<Inner: BufferMut> IcmpErrorMut<Ipv6>
2117            for Nested<TruncatingSerializer<Inner>, IcmpPacketBuilder<Ipv6, $message>>
2118        {
2119            type InnerPacket<'a>
2120                = Ipv6PacketRaw<&'a mut [u8]>
2121            where
2122                Self: 'a;
2123
2124            fn recalculate_checksum(&mut self) -> bool {
2125                // Checksum is calculated during serialization.
2126                true
2127            }
2128
2129            fn inner_packet<'a>(&'a mut self) -> Option<Self::InnerPacket<'a>> {
2130                let packet = Ipv6PacketRaw::parse_mut(
2131                    SliceBufViewMut::new(self.inner_mut().buffer_mut().as_mut()),
2132                    (),
2133                )
2134                .ok()?;
2135
2136                Some(packet)
2137            }
2138        }
2139
2140        impl<Inner: BufferMut> DynamicIcmpErrorMut<Ipv6>
2141            for Nested<TruncatingSerializer<Inner>, IcmpPacketBuilder<Ipv6, $message>>
2142        {
2143            fn dyn_recalculate_checksum(&mut self) -> bool {
2144                self.recalculate_checksum()
2145            }
2146
2147            fn dyn_inner_packet(&mut self) -> Option<Ipv6PacketRaw<&mut [u8]>> {
2148                self.inner_packet()
2149            }
2150        }
2151    };
2152}
2153
2154icmpv6_error_message!(IcmpDestUnreachable);
2155icmpv6_error_message!(Icmpv6PacketTooBig);
2156icmpv6_error_message!(IcmpTimeExceeded);
2157icmpv6_error_message!(Icmpv6ParameterProblem);
2158
2159impl<M: igmp::MessageType<EmptyBuf>> MaybeIcmpErrorMut<Ipv4>
2160    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2161{
2162    type IcmpErrorMut<'a>
2163        = Never
2164    where
2165        Self: 'a;
2166
2167    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2168        None
2169    }
2170}
2171
2172impl<M: igmp::MessageType<EmptyBuf>> DynamicMaybeIcmpErrorMut<Ipv4>
2173    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2174{
2175    fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<Ipv4>> {
2176        self.icmp_error_mut().map(|x| match x {})
2177    }
2178}
2179
2180impl<M: igmp::MessageType<EmptyBuf>> MaybeTransportPacket
2181    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2182{
2183    fn transport_packet_data(&self) -> Option<TransportPacketData> {
2184        None
2185    }
2186}
2187
2188impl<M: igmp::MessageType<EmptyBuf>> DynamicMaybeTransportPacketMut<Ipv4>
2189    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2190{
2191    fn dyn_transport_packet_mut(&mut self) -> Option<&mut dyn TransportPacketMut<Ipv4>> {
2192        self.transport_packet_mut().map(|x| match x {})
2193    }
2194}
2195
2196impl<M: igmp::MessageType<EmptyBuf>> MaybeTransportPacketMut<Ipv4>
2197    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2198{
2199    type TransportPacketMut<'a>
2200        = Never
2201    where
2202        M: 'a;
2203
2204    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
2205        None
2206    }
2207}
2208
2209impl<I: IpExt, M: igmp::MessageType<EmptyBuf>> MaybeIcmpErrorPayload<I>
2210    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2211{
2212    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
2213        None
2214    }
2215}
2216
2217impl<I> MaybeTransportPacket for InnerSerializer<IgmpMembershipReportV3Builder<I>, EmptyBuf> {
2218    fn transport_packet_data(&self) -> Option<TransportPacketData> {
2219        None
2220    }
2221}
2222
2223impl<I> MaybeTransportPacketMut<Ipv4>
2224    for InnerSerializer<IgmpMembershipReportV3Builder<I>, EmptyBuf>
2225{
2226    type TransportPacketMut<'a>
2227        = Never
2228    where
2229        I: 'a;
2230
2231    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
2232        None
2233    }
2234}
2235
2236impl<I> DynamicMaybeTransportPacketMut<Ipv4>
2237    for InnerSerializer<IgmpMembershipReportV3Builder<I>, EmptyBuf>
2238{
2239    fn dyn_transport_packet_mut(&mut self) -> Option<&mut dyn TransportPacketMut<Ipv4>> {
2240        self.transport_packet_mut().map(|x| match x {})
2241    }
2242}
2243
2244impl<I: IpExt, II, B> MaybeIcmpErrorPayload<I>
2245    for InnerSerializer<IgmpMembershipReportV3Builder<II>, B>
2246{
2247    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
2248        None
2249    }
2250}
2251
2252impl<I, B> MaybeIcmpErrorMut<Ipv4> for InnerSerializer<IgmpMembershipReportV3Builder<I>, B> {
2253    type IcmpErrorMut<'a>
2254        = Never
2255    where
2256        Self: 'a;
2257
2258    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2259        None
2260    }
2261}
2262
2263impl<I, B> DynamicMaybeIcmpErrorMut<Ipv4> for InnerSerializer<IgmpMembershipReportV3Builder<I>, B> {
2264    fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<Ipv4>> {
2265        self.icmp_error_mut().map(|x| match x {})
2266    }
2267}
2268
2269impl<I> MaybeTransportPacket
2270    for EitherSerializer<
2271        EmptyBuf,
2272        InnerSerializer<packet::records::RecordSequenceBuilder<NdpOptionBuilder<'_>, I>, EmptyBuf>,
2273    >
2274{
2275    fn transport_packet_data(&self) -> Option<TransportPacketData> {
2276        None
2277    }
2278}
2279
2280/// An unsanitized IP packet body.
2281///
2282/// Allows packets from raw IP sockets (with a user provided IP body), to be
2283/// tracked from the filtering module.
2284#[derive(GenericOverIp)]
2285#[generic_over_ip(I, Ip)]
2286pub struct RawIpBody<I: IpExt, B: ParseBuffer> {
2287    /// The IANA protocol of the inner message. This may be, but is not required
2288    /// to be, a transport protocol.
2289    protocol: I::Proto,
2290    /// The source IP addr of the packet. Required by
2291    /// [`ParsedTransportHeaderMut`] to recompute checksums.
2292    src_addr: I::Addr,
2293    /// The destination IP addr of the packet. Required by
2294    /// [`ParsedTransportHeaderMut`] to recompute checksums.
2295    dst_addr: I::Addr,
2296    /// The body of the IP packet. The body is expected to be a message of type
2297    /// `protocol`, but is not guaranteed to be valid.
2298    body: B,
2299    /// The parsed transport data contained within `body`. Only `Some` if body
2300    /// is a valid transport header.
2301    transport_packet_data: Option<TransportPacketData>,
2302}
2303
2304impl<I: IpExt, B: ParseBuffer> RawIpBody<I, B> {
2305    /// Construct a new [`RawIpBody`] from it's parts.
2306    pub fn new(
2307        protocol: I::Proto,
2308        src_addr: I::Addr,
2309        dst_addr: I::Addr,
2310        body: B,
2311    ) -> RawIpBody<I, B> {
2312        let transport_packet_data = TransportPacketData::parse_in_ip_packet::<I, _>(
2313            src_addr,
2314            dst_addr,
2315            protocol,
2316            Buf::new(&body, ..),
2317        );
2318        RawIpBody { protocol, src_addr, dst_addr, body, transport_packet_data }
2319    }
2320}
2321
2322impl<I: IpExt, B: ParseBuffer> MaybeTransportPacket for RawIpBody<I, B> {
2323    fn transport_packet_data(&self) -> Option<TransportPacketData> {
2324        self.transport_packet_data.clone()
2325    }
2326}
2327
2328impl<I: IpExt, B: BufferMut> MaybeTransportPacketMut<I> for RawIpBody<I, B> {
2329    type TransportPacketMut<'a>
2330        = ParsedTransportHeaderMut<'a, I>
2331    where
2332        Self: 'a;
2333
2334    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
2335        let RawIpBody { protocol, src_addr: _, dst_addr: _, body, transport_packet_data: _ } = self;
2336        ParsedTransportHeaderMut::<I>::parse_in_ip_packet(
2337            *protocol,
2338            SliceBufViewMut::new(body.as_mut()),
2339        )
2340    }
2341}
2342
2343impl<I: IpExt, B: ParseBuffer> MaybeIcmpErrorPayload<I> for RawIpBody<I, B> {
2344    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
2345        ParsedIcmpErrorPayload::parse_in_outer_ip_packet(self.protocol, Buf::new(&self.body, ..))
2346    }
2347}
2348
2349impl<I: FilterIpExt, B: BufferMut> MaybeIcmpErrorMut<I> for RawIpBody<I, B> {
2350    type IcmpErrorMut<'a>
2351        = ParsedIcmpErrorMut<'a, I>
2352    where
2353        Self: 'a;
2354
2355    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2356        let RawIpBody { protocol, src_addr, dst_addr, body, transport_packet_data: _ } = self;
2357
2358        ParsedIcmpErrorMut::parse_in_ip_packet(
2359            *src_addr,
2360            *dst_addr,
2361            *protocol,
2362            SliceBufViewMut::new(body.as_mut()),
2363        )
2364    }
2365}
2366
2367impl<I: IpExt, B: BufferMut> Serializer for RawIpBody<I, B> {
2368    type Buffer = <B as Serializer>::Buffer;
2369
2370    fn serialize<G: GrowBufferMut, P: BufferProvider<Self::Buffer, G>>(
2371        self,
2372        outer: PacketConstraints,
2373        provider: P,
2374    ) -> Result<G, (SerializeError<P::Error>, Self)> {
2375        let Self { protocol, src_addr, dst_addr, body, transport_packet_data } = self;
2376        body.serialize(outer, provider).map_err(|(err, body)| {
2377            (err, Self { protocol, src_addr, dst_addr, body, transport_packet_data })
2378        })
2379    }
2380
2381    fn serialize_new_buf<BB: GrowBufferMut, A: LayoutBufferAlloc<BB>>(
2382        &self,
2383        outer: PacketConstraints,
2384        alloc: A,
2385    ) -> Result<BB, SerializeError<A::Error>> {
2386        self.body.serialize_new_buf(outer, alloc)
2387    }
2388}
2389
2390impl<I: IpExt, B: BufferMut> PartialSerializer for RawIpBody<I, B> {
2391    fn partial_serialize(
2392        &self,
2393        _outer: PacketConstraints,
2394        buffer: &mut [u8],
2395    ) -> Result<PartialSerializeResult, SerializeError<Never>> {
2396        let bytes_to_copy = core::cmp::min(self.body.len(), buffer.len());
2397        buffer[..bytes_to_copy].copy_from_slice(&self.body.as_ref()[..bytes_to_copy]);
2398        Ok(PartialSerializeResult { bytes_written: bytes_to_copy, total_size: self.body.len() })
2399    }
2400}
2401
2402fn parse_transport_header_in_ipv4_packet<B: ParseBuffer>(
2403    src_ip: Ipv4Addr,
2404    dst_ip: Ipv4Addr,
2405    proto: Ipv4Proto,
2406    body: B,
2407) -> Option<TransportPacketData> {
2408    match proto {
2409        Ipv4Proto::Proto(IpProto::Udp) => parse_udp_header::<_, Ipv4>(body),
2410        Ipv4Proto::Proto(IpProto::Tcp) => parse_tcp_header::<_, Ipv4>(body, src_ip, dst_ip),
2411        Ipv4Proto::Icmp => parse_icmpv4_header(body),
2412        Ipv4Proto::Proto(IpProto::Reserved) | Ipv4Proto::Igmp | Ipv4Proto::Other(_) => None,
2413    }
2414}
2415
2416fn parse_transport_header_in_ipv6_packet<B: ParseBuffer>(
2417    src_ip: Ipv6Addr,
2418    dst_ip: Ipv6Addr,
2419    proto: Ipv6Proto,
2420    body: B,
2421) -> Option<TransportPacketData> {
2422    match proto {
2423        Ipv6Proto::Proto(IpProto::Udp) => parse_udp_header::<_, Ipv6>(body),
2424        Ipv6Proto::Proto(IpProto::Tcp) => parse_tcp_header::<_, Ipv6>(body, src_ip, dst_ip),
2425        Ipv6Proto::Icmpv6 => parse_icmpv6_header(body),
2426        Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::NoNextHeader | Ipv6Proto::Other(_) => None,
2427    }
2428}
2429
2430fn parse_udp_header<B: ParseBuffer, I: Ip>(mut body: B) -> Option<TransportPacketData> {
2431    let packet = body.parse_with::<_, UdpPacketRaw<_>>(I::VERSION_MARKER).ok()?;
2432    Some(TransportPacketData::Generic {
2433        src_port: packet.src_port().map(NonZeroU16::get).unwrap_or(0),
2434        // NB: UDP packets must have a specified (nonzero) destination port, so
2435        // if this packet has a destination port of 0, it is malformed.
2436        dst_port: packet.dst_port()?.get(),
2437    })
2438}
2439
2440fn parse_tcp_header<B: ParseBuffer, I: IpExt>(
2441    mut body: B,
2442    src_ip: I::Addr,
2443    dst_ip: I::Addr,
2444) -> Option<TransportPacketData> {
2445    // NOTE: By using TcpSegmentRaw here, we're opting into getting invalid data
2446    // (for example, if the checksum isn't valid). As a team, we've decided
2447    // that's okay for now, since the worst that happens is we filter or
2448    // conntrack a packet incorrectly and the end host rejects it.
2449    //
2450    // This will be fixed at some point as part of a larger effort to ensure
2451    // that checksums are validated exactly once (and hopefully via checksum
2452    // offloading).
2453    let packet = body.parse::<TcpSegmentRaw<_>>().ok()?;
2454
2455    let (builder, options, body) = packet.into_builder_options(src_ip, dst_ip)?;
2456    let options = Options::try_from_options(&builder, &options).ok()?;
2457
2458    let segment = SegmentHeader::from_builder_options(&builder, options).ok()?;
2459
2460    Some(TransportPacketData::Tcp {
2461        src_port: builder.src_port().map(NonZeroU16::get).unwrap_or(0),
2462        dst_port: builder.dst_port().map(NonZeroU16::get).unwrap_or(0),
2463        segment,
2464        payload_len: body.len(),
2465    })
2466}
2467
2468fn parse_icmpv4_header<B: ParseBuffer>(mut body: B) -> Option<TransportPacketData> {
2469    match icmp::peek_message_type(body.as_ref()).ok()? {
2470        Icmpv4MessageType::EchoRequest => {
2471            let packet = body.parse::<IcmpPacketRaw<Ipv4, _, IcmpEchoRequest>>().ok()?;
2472            packet.message().transport_packet_data()
2473        }
2474        Icmpv4MessageType::EchoReply => {
2475            let packet = body.parse::<IcmpPacketRaw<Ipv4, _, IcmpEchoReply>>().ok()?;
2476            packet.message().transport_packet_data()
2477        }
2478        // ICMP errors have a separate parsing path.
2479        Icmpv4MessageType::DestUnreachable
2480        | Icmpv4MessageType::Redirect
2481        | Icmpv4MessageType::TimeExceeded
2482        | Icmpv4MessageType::ParameterProblem => None,
2483        // NOTE: If these are parsed, then without further work, conntrack won't
2484        // be able to differentiate between these and ECHO message with the same
2485        // ID.
2486        Icmpv4MessageType::TimestampRequest | Icmpv4MessageType::TimestampReply => None,
2487    }
2488}
2489
2490fn parse_icmpv6_header<B: ParseBuffer>(mut body: B) -> Option<TransportPacketData> {
2491    match icmp::peek_message_type(body.as_ref()).ok()? {
2492        Icmpv6MessageType::EchoRequest => {
2493            let packet = body.parse::<IcmpPacketRaw<Ipv6, _, IcmpEchoRequest>>().ok()?;
2494            packet.message().transport_packet_data()
2495        }
2496        Icmpv6MessageType::EchoReply => {
2497            let packet = body.parse::<IcmpPacketRaw<Ipv6, _, IcmpEchoReply>>().ok()?;
2498            packet.message().transport_packet_data()
2499        }
2500        // ICMP errors have a separate parsing path.
2501        Icmpv6MessageType::DestUnreachable
2502        | Icmpv6MessageType::PacketTooBig
2503        | Icmpv6MessageType::TimeExceeded
2504        | Icmpv6MessageType::ParameterProblem => None,
2505        Icmpv6MessageType::RouterSolicitation
2506        | Icmpv6MessageType::RouterAdvertisement
2507        | Icmpv6MessageType::NeighborSolicitation
2508        | Icmpv6MessageType::NeighborAdvertisement
2509        | Icmpv6MessageType::Redirect
2510        | Icmpv6MessageType::MulticastListenerQuery
2511        | Icmpv6MessageType::MulticastListenerReport
2512        | Icmpv6MessageType::MulticastListenerDone
2513        | Icmpv6MessageType::MulticastListenerReportV2 => None,
2514    }
2515}
2516
2517/// A transport header that has been parsed from a byte buffer and provides
2518/// mutable access to its contents.
2519#[derive(GenericOverIp)]
2520#[generic_over_ip(I, Ip)]
2521pub enum ParsedTransportHeaderMut<'a, I: IpExt> {
2522    Tcp(TcpSegmentRaw<&'a mut [u8]>),
2523    Udp(UdpPacketRaw<&'a mut [u8]>),
2524    Icmp(I::IcmpPacketTypeRaw<&'a mut [u8]>),
2525}
2526
2527impl<'a> ParsedTransportHeaderMut<'a, Ipv4> {
2528    fn parse_in_ipv4_packet<BV: BufferViewMut<&'a mut [u8]>>(
2529        proto: Ipv4Proto,
2530        body: BV,
2531    ) -> Option<Self> {
2532        match proto {
2533            Ipv4Proto::Proto(IpProto::Udp) => {
2534                Some(Self::Udp(UdpPacketRaw::parse_mut(body, IpVersionMarker::<Ipv4>::new()).ok()?))
2535            }
2536            Ipv4Proto::Proto(IpProto::Tcp) => {
2537                Some(Self::Tcp(TcpSegmentRaw::parse_mut(body, ()).ok()?))
2538            }
2539            Ipv4Proto::Icmp => Some(Self::Icmp(Icmpv4PacketRaw::parse_mut(body, ()).ok()?)),
2540            Ipv4Proto::Proto(IpProto::Reserved) | Ipv4Proto::Igmp | Ipv4Proto::Other(_) => None,
2541        }
2542    }
2543}
2544
2545impl<'a> ParsedTransportHeaderMut<'a, Ipv6> {
2546    fn parse_in_ipv6_packet<BV: BufferViewMut<&'a mut [u8]>>(
2547        proto: Ipv6Proto,
2548        body: BV,
2549    ) -> Option<Self> {
2550        match proto {
2551            Ipv6Proto::Proto(IpProto::Udp) => {
2552                Some(Self::Udp(UdpPacketRaw::parse_mut(body, IpVersionMarker::<Ipv6>::new()).ok()?))
2553            }
2554            Ipv6Proto::Proto(IpProto::Tcp) => {
2555                Some(Self::Tcp(TcpSegmentRaw::parse_mut(body, ()).ok()?))
2556            }
2557            Ipv6Proto::Icmpv6 => Some(Self::Icmp(Icmpv6PacketRaw::parse_mut(body, ()).ok()?)),
2558            Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::NoNextHeader | Ipv6Proto::Other(_) => {
2559                None
2560            }
2561        }
2562    }
2563}
2564
2565impl<'a, I: IpExt> ParsedTransportHeaderMut<'a, I> {
2566    fn parse_in_ip_packet<BV: BufferViewMut<&'a mut [u8]>>(
2567        proto: I::Proto,
2568        body: BV,
2569    ) -> Option<Self> {
2570        I::map_ip(
2571            (proto, IpInvariant(body)),
2572            |(proto, IpInvariant(body))| {
2573                ParsedTransportHeaderMut::<'a, Ipv4>::parse_in_ipv4_packet(proto, body)
2574            },
2575            |(proto, IpInvariant(body))| {
2576                ParsedTransportHeaderMut::<'a, Ipv6>::parse_in_ipv6_packet(proto, body)
2577            },
2578        )
2579    }
2580
2581    fn update_pseudo_header_address(&mut self, old: I::Addr, new: I::Addr) {
2582        match self {
2583            Self::Tcp(segment) => segment.update_checksum_pseudo_header_address(old, new),
2584            Self::Udp(packet) => {
2585                packet.update_checksum_pseudo_header_address(old, new);
2586            }
2587            Self::Icmp(packet) => {
2588                packet.update_checksum_pseudo_header_address(old, new);
2589            }
2590        }
2591    }
2592}
2593
2594/// An inner IP packet contained within an ICMP error.
2595#[derive(Debug, PartialEq, Eq, GenericOverIp)]
2596#[generic_over_ip(I, Ip)]
2597pub struct ParsedIcmpErrorPayload<I: IpExt> {
2598    src_ip: I::Addr,
2599    dst_ip: I::Addr,
2600    // Hold the ports directly instead of TransportPacketData. In case of an
2601    // ICMP error, we don't update conntrack connection state, so there's no
2602    // reason to keep the extra information.
2603    src_port: u16,
2604    dst_port: u16,
2605    proto: I::Proto,
2606}
2607
2608impl ParsedIcmpErrorPayload<Ipv4> {
2609    fn parse_in_outer_ipv4_packet<B>(protocol: Ipv4Proto, mut body: B) -> Option<Self>
2610    where
2611        B: ParseBuffer,
2612    {
2613        match protocol {
2614            Ipv4Proto::Proto(_) | Ipv4Proto::Igmp | Ipv4Proto::Other(_) => None,
2615            Ipv4Proto::Icmp => {
2616                let message = body.parse::<Icmpv4PacketRaw<_>>().ok()?;
2617                let message_body = match &message {
2618                    Icmpv4PacketRaw::EchoRequest(_)
2619                    | Icmpv4PacketRaw::EchoReply(_)
2620                    | Icmpv4PacketRaw::TimestampRequest(_)
2621                    | Icmpv4PacketRaw::TimestampReply(_) => return None,
2622
2623                    Icmpv4PacketRaw::DestUnreachable(inner) => inner.message_body(),
2624                    Icmpv4PacketRaw::Redirect(inner) => inner.message_body(),
2625                    Icmpv4PacketRaw::TimeExceeded(inner) => inner.message_body(),
2626                    Icmpv4PacketRaw::ParameterProblem(inner) => inner.message_body(),
2627                };
2628
2629                Self::parse_in_icmpv4_error(Buf::new(message_body, ..))
2630            }
2631        }
2632    }
2633
2634    fn parse_in_icmpv4_error<B>(mut body: B) -> Option<Self>
2635    where
2636        B: ParseBuffer,
2637    {
2638        let packet = body.parse::<Ipv4PacketRaw<_>>().ok()?;
2639
2640        let src_ip = packet.get_header_prefix().src_ip();
2641        let dst_ip = packet.get_header_prefix().dst_ip();
2642        let proto = packet.proto();
2643        let transport_data = parse_transport_header_in_ipv4_packet(
2644            src_ip,
2645            dst_ip,
2646            proto,
2647            packet.body().into_inner(),
2648        )?;
2649        Some(Self {
2650            src_ip,
2651            dst_ip,
2652            src_port: transport_data.src_port(),
2653            dst_port: transport_data.dst_port(),
2654            proto,
2655        })
2656    }
2657}
2658
2659impl ParsedIcmpErrorPayload<Ipv6> {
2660    fn parse_in_outer_ipv6_packet<B>(protocol: Ipv6Proto, mut body: B) -> Option<Self>
2661    where
2662        B: ParseBuffer,
2663    {
2664        match protocol {
2665            Ipv6Proto::NoNextHeader | Ipv6Proto::Proto(_) | Ipv6Proto::Other(_) => None,
2666
2667            Ipv6Proto::Icmpv6 => {
2668                let message = body.parse::<Icmpv6PacketRaw<_>>().ok()?;
2669                let message_body = match &message {
2670                    Icmpv6PacketRaw::EchoRequest(_)
2671                    | Icmpv6PacketRaw::EchoReply(_)
2672                    | Icmpv6PacketRaw::Ndp(_)
2673                    | Icmpv6PacketRaw::Mld(_) => return None,
2674
2675                    Icmpv6PacketRaw::DestUnreachable(inner) => inner.message_body(),
2676                    Icmpv6PacketRaw::PacketTooBig(inner) => inner.message_body(),
2677                    Icmpv6PacketRaw::TimeExceeded(inner) => inner.message_body(),
2678                    Icmpv6PacketRaw::ParameterProblem(inner) => inner.message_body(),
2679                };
2680
2681                Self::parse_in_icmpv6_error(Buf::new(message_body, ..))
2682            }
2683        }
2684    }
2685
2686    fn parse_in_icmpv6_error<B>(mut body: B) -> Option<Self>
2687    where
2688        B: ParseBuffer,
2689    {
2690        let packet = body.parse::<Ipv6PacketRaw<_>>().ok()?;
2691
2692        let src_ip = packet.get_fixed_header().src_ip();
2693        let dst_ip = packet.get_fixed_header().dst_ip();
2694        let proto = packet.proto().ok()?;
2695        let transport_data = parse_transport_header_in_ipv6_packet(
2696            src_ip,
2697            dst_ip,
2698            proto,
2699            packet.body().ok()?.into_inner(),
2700        )?;
2701        Some(Self {
2702            src_ip,
2703            dst_ip,
2704            src_port: transport_data.src_port(),
2705            dst_port: transport_data.dst_port(),
2706            proto,
2707        })
2708    }
2709}
2710
2711impl<I: IpExt> ParsedIcmpErrorPayload<I> {
2712    fn parse_in_outer_ip_packet<B>(proto: I::Proto, body: B) -> Option<Self>
2713    where
2714        B: ParseBuffer,
2715    {
2716        I::map_ip(
2717            (proto, IpInvariant(body)),
2718            |(proto, IpInvariant(body))| {
2719                ParsedIcmpErrorPayload::<Ipv4>::parse_in_outer_ipv4_packet(proto, body)
2720            },
2721            |(proto, IpInvariant(body))| {
2722                ParsedIcmpErrorPayload::<Ipv6>::parse_in_outer_ipv6_packet(proto, body)
2723            },
2724        )
2725    }
2726}
2727
2728/// An ICMP error packet that provides mutable access to the contained IP
2729/// packet.
2730#[derive(GenericOverIp)]
2731#[generic_over_ip(I, Ip)]
2732pub struct ParsedIcmpErrorMut<'a, I: IpExt> {
2733    src_ip: I::Addr,
2734    dst_ip: I::Addr,
2735    message: I::IcmpPacketTypeRaw<&'a mut [u8]>,
2736}
2737
2738impl<'a> ParsedIcmpErrorMut<'a, Ipv4> {
2739    fn parse_in_ipv4_packet<BV: BufferViewMut<&'a mut [u8]>>(
2740        src_ip: Ipv4Addr,
2741        dst_ip: Ipv4Addr,
2742        proto: Ipv4Proto,
2743        body: BV,
2744    ) -> Option<Self> {
2745        match proto {
2746            Ipv4Proto::Proto(_) | Ipv4Proto::Igmp | Ipv4Proto::Other(_) => None,
2747            Ipv4Proto::Icmp => {
2748                let message = Icmpv4PacketRaw::parse_mut(body, ()).ok()?;
2749                match message {
2750                    Icmpv4PacketRaw::EchoRequest(_)
2751                    | Icmpv4PacketRaw::EchoReply(_)
2752                    | Icmpv4PacketRaw::TimestampRequest(_)
2753                    | Icmpv4PacketRaw::TimestampReply(_) => None,
2754
2755                    Icmpv4PacketRaw::DestUnreachable(_)
2756                    | Icmpv4PacketRaw::Redirect(_)
2757                    | Icmpv4PacketRaw::TimeExceeded(_)
2758                    | Icmpv4PacketRaw::ParameterProblem(_) => {
2759                        Some(Self { src_ip, dst_ip, message })
2760                    }
2761                }
2762            }
2763        }
2764    }
2765}
2766
2767impl<'a> ParsedIcmpErrorMut<'a, Ipv6> {
2768    fn parse_in_ipv6_packet<BV: BufferViewMut<&'a mut [u8]>>(
2769        src_ip: Ipv6Addr,
2770        dst_ip: Ipv6Addr,
2771        proto: Ipv6Proto,
2772        body: BV,
2773    ) -> Option<Self> {
2774        match proto {
2775            Ipv6Proto::NoNextHeader | Ipv6Proto::Proto(_) | Ipv6Proto::Other(_) => None,
2776
2777            Ipv6Proto::Icmpv6 => {
2778                let message = Icmpv6PacketRaw::parse_mut(body, ()).ok()?;
2779                match message {
2780                    Icmpv6PacketRaw::EchoRequest(_)
2781                    | Icmpv6PacketRaw::EchoReply(_)
2782                    | Icmpv6PacketRaw::Ndp(_)
2783                    | Icmpv6PacketRaw::Mld(_) => None,
2784
2785                    Icmpv6PacketRaw::DestUnreachable(_)
2786                    | Icmpv6PacketRaw::PacketTooBig(_)
2787                    | Icmpv6PacketRaw::TimeExceeded(_)
2788                    | Icmpv6PacketRaw::ParameterProblem(_) => {
2789                        Some(Self { src_ip, dst_ip, message })
2790                    }
2791                }
2792            }
2793        }
2794    }
2795}
2796
2797impl<'a, I: FilterIpExt> ParsedIcmpErrorMut<'a, I> {
2798    fn parse_in_ip_packet<BV: BufferViewMut<&'a mut [u8]>>(
2799        src_ip: I::Addr,
2800        dst_ip: I::Addr,
2801        proto: I::Proto,
2802        body: BV,
2803    ) -> Option<Self> {
2804        I::map_ip(
2805            (src_ip, dst_ip, proto, IpInvariant(body)),
2806            |(src_ip, dst_ip, proto, IpInvariant(body))| {
2807                ParsedIcmpErrorMut::<'a, Ipv4>::parse_in_ipv4_packet(src_ip, dst_ip, proto, body)
2808            },
2809            |(src_ip, dst_ip, proto, IpInvariant(body))| {
2810                ParsedIcmpErrorMut::<'a, Ipv6>::parse_in_ipv6_packet(src_ip, dst_ip, proto, body)
2811            },
2812        )
2813    }
2814}
2815
2816impl<'a, I: FilterIpExt> IcmpErrorMut<I> for ParsedIcmpErrorMut<'a, I> {
2817    type InnerPacket<'b>
2818        = I::FilterIpPacketRaw<&'b mut [u8]>
2819    where
2820        Self: 'b;
2821
2822    fn inner_packet<'b>(&'b mut self) -> Option<Self::InnerPacket<'b>> {
2823        Some(I::as_filter_packet_raw_owned(
2824            I::PacketRaw::parse_mut(SliceBufViewMut::new(self.message.message_body_mut()), ())
2825                .ok()?,
2826        ))
2827    }
2828
2829    fn recalculate_checksum(&mut self) -> bool {
2830        let Self { src_ip, dst_ip, message } = self;
2831        message.try_write_checksum(*src_ip, *dst_ip)
2832    }
2833}
2834
2835/// A helper trait to extract [`IcmpMessage`] impls from parsed ICMP messages.
2836trait IcmpMessageImplHelper<I: IpExt> {
2837    fn message_impl_mut(&mut self) -> &mut impl IcmpMessage<I>;
2838}
2839
2840impl<I: IpExt, B: SplitByteSliceMut, M: IcmpMessage<I>> IcmpMessageImplHelper<I>
2841    for IcmpPacketRaw<I, B, M>
2842{
2843    fn message_impl_mut(&mut self) -> &mut impl IcmpMessage<I> {
2844        self.message_mut()
2845    }
2846}
2847
2848impl<'a, I: IpExt> TransportPacketMut<I> for ParsedTransportHeaderMut<'a, I> {
2849    fn set_src_port(&mut self, port: NonZeroU16) {
2850        match self {
2851            ParsedTransportHeaderMut::Tcp(segment) => segment.set_src_port(port),
2852            ParsedTransportHeaderMut::Udp(packet) => packet.set_src_port(port.get()),
2853            ParsedTransportHeaderMut::Icmp(packet) => {
2854                I::map_ip::<_, ()>(
2855                    packet,
2856                    |packet| {
2857                        packet_formats::icmpv4_dispatch!(
2858                            packet: raw,
2859                            p => {
2860                                let message = p.message_impl_mut();
2861                                if  message.is_rewritable() {
2862                                    let old = message.update_icmp_id(port.get());
2863                                    p.update_checksum_header_field_u16(old, port.get())
2864                                }
2865                            }
2866                        );
2867                    },
2868                    |packet| {
2869                        packet_formats::icmpv6_dispatch!(
2870                            packet: raw,
2871                            p => {
2872                                let message = p.message_impl_mut();
2873                                if  message.is_rewritable() {
2874                                    let old = message.update_icmp_id(port.get());
2875                                    p.update_checksum_header_field_u16(old, port.get())
2876                                }
2877                            }
2878                        );
2879                    },
2880                );
2881            }
2882        }
2883    }
2884
2885    fn set_dst_port(&mut self, port: NonZeroU16) {
2886        match self {
2887            ParsedTransportHeaderMut::Tcp(segment) => segment.set_dst_port(port),
2888            ParsedTransportHeaderMut::Udp(packet) => packet.set_dst_port(port),
2889            ParsedTransportHeaderMut::Icmp(packet) => {
2890                I::map_ip::<_, ()>(
2891                    packet,
2892                    |packet| {
2893                        packet_formats::icmpv4_dispatch!(
2894                            packet:raw,
2895                            p => {
2896                                let message = p.message_impl_mut();
2897                                if  message.is_rewritable() {
2898                                    let old = message.update_icmp_id(port.get());
2899                                    p.update_checksum_header_field_u16(old, port.get())
2900                                }
2901                            }
2902                        );
2903                    },
2904                    |packet| {
2905                        packet_formats::icmpv6_dispatch!(
2906                            packet:raw,
2907                            p => {
2908                                let message = p.message_impl_mut();
2909                                if  message.is_rewritable() {
2910                                    let old = message.update_icmp_id(port.get());
2911                                    p.update_checksum_header_field_u16(old, port.get())
2912                                }
2913                            }
2914                        );
2915                    },
2916                );
2917            }
2918        }
2919    }
2920
2921    fn update_pseudo_header_src_addr(&mut self, old: I::Addr, new: I::Addr) {
2922        self.update_pseudo_header_address(old, new);
2923    }
2924
2925    fn update_pseudo_header_dst_addr(&mut self, old: I::Addr, new: I::Addr) {
2926        self.update_pseudo_header_address(old, new);
2927    }
2928}
2929
2930#[cfg(any(test, feature = "testutils"))]
2931pub mod testutil {
2932    use super::*;
2933
2934    // Note that we could choose to implement `MaybeTransportPacket` for these
2935    // opaque byte buffer types by parsing them as we do incoming buffers, but since
2936    // these implementations are only for use in netstack3_core unit tests, there is
2937    // no expectation that filtering or connection tracking actually be performed.
2938    // If that changes at some point, we could replace these with "real"
2939    // implementations.
2940
2941    impl<B: BufferMut> MaybeTransportPacket for Nested<B, ()> {
2942        fn transport_packet_data(&self) -> Option<TransportPacketData> {
2943            unimplemented!()
2944        }
2945    }
2946
2947    impl<I: IpExt, B: BufferMut> MaybeTransportPacketMut<I> for Nested<B, ()> {
2948        type TransportPacketMut<'a>
2949            = Never
2950        where
2951            B: 'a;
2952
2953        fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
2954            unimplemented!()
2955        }
2956    }
2957
2958    impl<I: IpExt, B: BufferMut> MaybeIcmpErrorPayload<I> for Nested<B, ()> {
2959        fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
2960            unimplemented!()
2961        }
2962    }
2963
2964    impl<I: FilterIpExt, B: BufferMut> MaybeIcmpErrorMut<I> for Nested<B, ()> {
2965        type IcmpErrorMut<'a>
2966            = Never
2967        where
2968            Self: 'a;
2969
2970        fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2971            unimplemented!()
2972        }
2973    }
2974
2975    impl MaybeTransportPacket for InnerSerializer<&[u8], EmptyBuf> {
2976        fn transport_packet_data(&self) -> Option<TransportPacketData> {
2977            None
2978        }
2979    }
2980
2981    impl<I: IpExt> MaybeTransportPacketMut<I> for InnerSerializer<&[u8], EmptyBuf> {
2982        type TransportPacketMut<'a>
2983            = Never
2984        where
2985            Self: 'a;
2986
2987        fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
2988            None
2989        }
2990    }
2991
2992    impl<I: IpExt> MaybeIcmpErrorPayload<I> for InnerSerializer<&[u8], EmptyBuf> {
2993        fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
2994            None
2995        }
2996    }
2997
2998    impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for InnerSerializer<&[u8], EmptyBuf> {
2999        type IcmpErrorMut<'a>
3000            = Never
3001        where
3002            Self: 'a;
3003
3004        fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3005            None
3006        }
3007    }
3008
3009    #[cfg(test)]
3010    pub(crate) mod internal {
3011        use alloc::vec::Vec;
3012        use net_declare::{net_ip_v4, net_ip_v6, net_subnet_v4, net_subnet_v6};
3013        use net_types::ip::Subnet;
3014        use netstack3_base::{SeqNum, UnscaledWindowSize};
3015        use packet::{PacketBuilder as _, PartialPacketBuilder as _, TruncateDirection};
3016        use packet_formats::icmp::{Icmpv4DestUnreachableCode, Icmpv6DestUnreachableCode};
3017
3018        use super::*;
3019
3020        pub trait TestIpExt: FilterIpExt {
3021            const SRC_IP: Self::Addr;
3022            const SRC_PORT: u16 = 1234;
3023            const DST_IP: Self::Addr;
3024            const DST_PORT: u16 = 9876;
3025            const SRC_IP_2: Self::Addr;
3026            const DST_IP_2: Self::Addr;
3027            const DST_IP_3: Self::Addr;
3028            const IP_OUTSIDE_SUBNET: Self::Addr;
3029            const SUBNET: Subnet<Self::Addr>;
3030            const PACKET_TTL: u8 = u8::MAX;
3031        }
3032
3033        impl TestIpExt for Ipv4 {
3034            const SRC_IP: Self::Addr = net_ip_v4!("192.0.2.1");
3035            const DST_IP: Self::Addr = net_ip_v4!("192.0.2.2");
3036            const SRC_IP_2: Self::Addr = net_ip_v4!("192.0.2.3");
3037            const DST_IP_2: Self::Addr = net_ip_v4!("192.0.2.4");
3038            const DST_IP_3: Self::Addr = net_ip_v4!("192.0.2.6");
3039            const IP_OUTSIDE_SUBNET: Self::Addr = net_ip_v4!("192.0.3.1");
3040            const SUBNET: Subnet<Self::Addr> = net_subnet_v4!("192.0.2.0/24");
3041        }
3042
3043        impl TestIpExt for Ipv6 {
3044            const SRC_IP: Self::Addr = net_ip_v6!("2001:db8::1");
3045            const DST_IP: Self::Addr = net_ip_v6!("2001:db8::2");
3046            const SRC_IP_2: Self::Addr = net_ip_v6!("2001:db8::3");
3047            const DST_IP_2: Self::Addr = net_ip_v6!("2001:db8::4");
3048            const DST_IP_3: Self::Addr = net_ip_v6!("2001:db8::6");
3049            const IP_OUTSIDE_SUBNET: Self::Addr = net_ip_v6!("2001:db8:ffff::1");
3050            const SUBNET: Subnet<Self::Addr> = net_subnet_v6!("2001:db8::/64");
3051        }
3052
3053        #[derive(Clone, Debug, PartialEq)]
3054        pub struct FakeIpPacket<I: FilterIpExt, T>
3055        where
3056            for<'a> &'a T: TransportPacketExt<I>,
3057        {
3058            pub src_ip: I::Addr,
3059            pub dst_ip: I::Addr,
3060            pub body: T,
3061        }
3062
3063        impl<I: FilterIpExt> FakeIpPacket<I, FakeUdpPacket> {
3064            pub(crate) fn reply(&self) -> Self {
3065                Self { src_ip: self.dst_ip, dst_ip: self.src_ip, body: self.body.reply() }
3066            }
3067        }
3068
3069        pub trait TransportPacketExt<I: IpExt>:
3070            MaybeTransportPacket + MaybeIcmpErrorPayload<I>
3071        {
3072            fn proto() -> Option<I::Proto>;
3073            fn len(&self) -> usize;
3074        }
3075
3076        impl<I: FilterIpExt, T> IpPacket<I> for FakeIpPacket<I, T>
3077        where
3078            for<'a> &'a T: TransportPacketExt<I>,
3079            for<'a> &'a mut T: MaybeTransportPacketMut<I> + MaybeIcmpErrorMut<I>,
3080        {
3081            type TransportPacket<'a>
3082                = &'a T
3083            where
3084                T: 'a;
3085            type TransportPacketMut<'a>
3086                = &'a mut T
3087            where
3088                T: 'a;
3089            type IcmpError<'a>
3090                = &'a T
3091            where
3092                T: 'a;
3093            type IcmpErrorMut<'a>
3094                = &'a mut T
3095            where
3096                T: 'a;
3097
3098            fn src_addr(&self) -> I::Addr {
3099                self.src_ip
3100            }
3101
3102            fn set_src_addr(&mut self, addr: I::Addr) {
3103                self.src_ip = addr;
3104            }
3105
3106            fn dst_addr(&self) -> I::Addr {
3107                self.dst_ip
3108            }
3109
3110            fn set_dst_addr(&mut self, addr: I::Addr) {
3111                self.dst_ip = addr;
3112            }
3113
3114            fn protocol(&self) -> Option<I::Proto> {
3115                <&T>::proto()
3116            }
3117
3118            fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
3119                &self.body
3120            }
3121
3122            fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
3123                &mut self.body
3124            }
3125
3126            fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
3127                &self.body
3128            }
3129
3130            fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
3131                &mut self.body
3132            }
3133        }
3134
3135        impl<I: TestIpExt, T> PartialSerializer for FakeIpPacket<I, T>
3136        where
3137            for<'a> &'a T: TransportPacketExt<I>,
3138        {
3139            fn partial_serialize(
3140                &self,
3141                _outer: PacketConstraints,
3142                buffer: &mut [u8],
3143            ) -> Result<PartialSerializeResult, SerializeError<Never>> {
3144                let Some(proto) = <&T>::proto() else {
3145                    return Ok(PartialSerializeResult { bytes_written: 0, total_size: 0 });
3146                };
3147                let builder = I::PacketBuilder::new(self.src_ip, self.dst_ip, I::PACKET_TTL, proto);
3148                let constraints = builder.constraints();
3149                let body_len = (&self.body).len();
3150
3151                if constraints.header_len() > buffer.len() {
3152                    return Ok(PartialSerializeResult {
3153                        bytes_written: 0,
3154                        total_size: constraints.header_len() + body_len,
3155                    });
3156                }
3157                builder.partial_serialize(body_len, buffer);
3158
3159                Ok(PartialSerializeResult {
3160                    bytes_written: constraints.header_len(),
3161                    total_size: constraints.header_len() + body_len,
3162                })
3163            }
3164        }
3165
3166        #[derive(Clone, Debug, PartialEq)]
3167        pub struct FakeTcpSegment {
3168            pub src_port: u16,
3169            pub dst_port: u16,
3170            pub segment: SegmentHeader,
3171            pub payload_len: usize,
3172        }
3173
3174        impl<I: FilterIpExt> TransportPacketExt<I> for &FakeTcpSegment {
3175            fn proto() -> Option<I::Proto> {
3176                Some(I::map_ip_out(
3177                    (),
3178                    |()| Ipv4Proto::Proto(IpProto::Tcp),
3179                    |()| Ipv6Proto::Proto(IpProto::Tcp),
3180                ))
3181            }
3182
3183            fn len(&self) -> usize {
3184                packet_formats::tcp::HDR_PREFIX_LEN + self.payload_len
3185            }
3186        }
3187
3188        impl MaybeTransportPacket for &FakeTcpSegment {
3189            fn transport_packet_data(&self) -> Option<TransportPacketData> {
3190                Some(TransportPacketData::Tcp {
3191                    src_port: self.src_port,
3192                    dst_port: self.dst_port,
3193                    segment: self.segment.clone(),
3194                    payload_len: self.payload_len,
3195                })
3196            }
3197        }
3198
3199        impl<I: IpExt> MaybeTransportPacketMut<I> for FakeTcpSegment {
3200            type TransportPacketMut<'a> = &'a mut Self;
3201
3202            fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3203                Some(self)
3204            }
3205        }
3206
3207        impl<I: IpExt> TransportPacketMut<I> for FakeTcpSegment {
3208            fn set_src_port(&mut self, port: NonZeroU16) {
3209                self.src_port = port.get();
3210            }
3211
3212            fn set_dst_port(&mut self, port: NonZeroU16) {
3213                self.dst_port = port.get();
3214            }
3215
3216            fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {}
3217
3218            fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {}
3219        }
3220
3221        impl<I: IpExt> MaybeIcmpErrorPayload<I> for FakeTcpSegment {
3222            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3223                None
3224            }
3225        }
3226
3227        impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for FakeTcpSegment {
3228            type IcmpErrorMut<'a>
3229                = Never
3230            where
3231                Self: 'a;
3232
3233            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3234                None
3235            }
3236        }
3237
3238        #[derive(Clone, Debug, PartialEq)]
3239        pub struct FakeUdpPacket {
3240            pub src_port: u16,
3241            pub dst_port: u16,
3242        }
3243
3244        impl FakeUdpPacket {
3245            const PAYLOAD_LEN: usize = 4;
3246
3247            fn reply(&self) -> Self {
3248                Self { src_port: self.dst_port, dst_port: self.src_port }
3249            }
3250        }
3251
3252        impl<I: FilterIpExt> TransportPacketExt<I> for &FakeUdpPacket {
3253            fn proto() -> Option<I::Proto> {
3254                Some(I::map_ip_out(
3255                    (),
3256                    |()| Ipv4Proto::Proto(IpProto::Udp),
3257                    |()| Ipv6Proto::Proto(IpProto::Udp),
3258                ))
3259            }
3260
3261            fn len(&self) -> usize {
3262                packet_formats::udp::HEADER_BYTES + FakeUdpPacket::PAYLOAD_LEN
3263            }
3264        }
3265
3266        impl MaybeTransportPacket for &FakeUdpPacket {
3267            fn transport_packet_data(&self) -> Option<TransportPacketData> {
3268                Some(TransportPacketData::Generic {
3269                    src_port: self.src_port,
3270                    dst_port: self.dst_port,
3271                })
3272            }
3273        }
3274
3275        impl<I: IpExt> MaybeTransportPacketMut<I> for FakeUdpPacket {
3276            type TransportPacketMut<'a> = &'a mut Self;
3277
3278            fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3279                Some(self)
3280            }
3281        }
3282
3283        impl<I: IpExt> TransportPacketMut<I> for FakeUdpPacket {
3284            fn set_src_port(&mut self, port: NonZeroU16) {
3285                self.src_port = port.get();
3286            }
3287
3288            fn set_dst_port(&mut self, port: NonZeroU16) {
3289                self.dst_port = port.get();
3290            }
3291
3292            fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {}
3293
3294            fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {}
3295        }
3296
3297        impl<I: IpExt> MaybeIcmpErrorPayload<I> for FakeUdpPacket {
3298            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3299                None
3300            }
3301        }
3302
3303        impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for FakeUdpPacket {
3304            type IcmpErrorMut<'a>
3305                = Never
3306            where
3307                Self: 'a;
3308
3309            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3310                None
3311            }
3312        }
3313
3314        #[derive(Clone, Debug, PartialEq)]
3315        pub struct FakeNullPacket;
3316
3317        impl<I: IpExt> TransportPacketExt<I> for &FakeNullPacket {
3318            fn proto() -> Option<I::Proto> {
3319                None
3320            }
3321
3322            fn len(&self) -> usize {
3323                0
3324            }
3325        }
3326
3327        impl MaybeTransportPacket for &FakeNullPacket {
3328            fn transport_packet_data(&self) -> Option<TransportPacketData> {
3329                None
3330            }
3331        }
3332
3333        impl<I: IpExt> MaybeTransportPacketMut<I> for FakeNullPacket {
3334            type TransportPacketMut<'a> = Never;
3335
3336            fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3337                None
3338            }
3339        }
3340
3341        impl<I: IpExt> MaybeIcmpErrorPayload<I> for FakeNullPacket {
3342            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3343                None
3344            }
3345        }
3346
3347        impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for FakeNullPacket {
3348            type IcmpErrorMut<'a>
3349                = Never
3350            where
3351                Self: 'a;
3352
3353            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3354                None
3355            }
3356        }
3357
3358        pub struct FakeIcmpEchoRequest {
3359            pub id: u16,
3360        }
3361
3362        impl<I: FilterIpExt> TransportPacketExt<I> for &FakeIcmpEchoRequest {
3363            fn proto() -> Option<I::Proto> {
3364                Some(I::map_ip_out((), |()| Ipv4Proto::Icmp, |()| Ipv6Proto::Icmpv6))
3365            }
3366
3367            fn len(&self) -> usize {
3368                // ICMP header is 8 bytes.
3369                8
3370            }
3371        }
3372
3373        impl MaybeTransportPacket for &FakeIcmpEchoRequest {
3374            fn transport_packet_data(&self) -> Option<TransportPacketData> {
3375                Some(TransportPacketData::Generic { src_port: self.id, dst_port: 0 })
3376            }
3377        }
3378
3379        impl<I: IpExt> MaybeTransportPacketMut<I> for FakeIcmpEchoRequest {
3380            type TransportPacketMut<'a> = &'a mut Self;
3381
3382            fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3383                Some(self)
3384            }
3385        }
3386
3387        impl<I: IpExt> TransportPacketMut<I> for FakeIcmpEchoRequest {
3388            fn set_src_port(&mut self, port: NonZeroU16) {
3389                self.id = port.get();
3390            }
3391
3392            fn set_dst_port(&mut self, _: NonZeroU16) {
3393                panic!("cannot set destination port for ICMP echo request")
3394            }
3395
3396            fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {}
3397
3398            fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {}
3399        }
3400
3401        impl<I: IpExt> MaybeIcmpErrorPayload<I> for FakeIcmpEchoRequest {
3402            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3403                None
3404            }
3405        }
3406
3407        impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for FakeIcmpEchoRequest {
3408            type IcmpErrorMut<'a>
3409                = Never
3410            where
3411                Self: 'a;
3412
3413            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3414                None
3415            }
3416        }
3417
3418        pub trait ArbitraryValue {
3419            fn arbitrary_value() -> Self;
3420        }
3421
3422        impl<I, T> ArbitraryValue for FakeIpPacket<I, T>
3423        where
3424            I: TestIpExt,
3425            T: ArbitraryValue,
3426            for<'a> &'a T: TransportPacketExt<I>,
3427        {
3428            fn arbitrary_value() -> Self {
3429                FakeIpPacket { src_ip: I::SRC_IP, dst_ip: I::DST_IP, body: T::arbitrary_value() }
3430            }
3431        }
3432
3433        impl ArbitraryValue for FakeTcpSegment {
3434            fn arbitrary_value() -> Self {
3435                FakeTcpSegment {
3436                    src_port: 33333,
3437                    dst_port: 44444,
3438                    segment: SegmentHeader::arbitrary_value(),
3439                    payload_len: 8888,
3440                }
3441            }
3442        }
3443
3444        impl ArbitraryValue for FakeUdpPacket {
3445            fn arbitrary_value() -> Self {
3446                FakeUdpPacket { src_port: 33333, dst_port: 44444 }
3447            }
3448        }
3449
3450        impl ArbitraryValue for FakeNullPacket {
3451            fn arbitrary_value() -> Self {
3452                FakeNullPacket
3453            }
3454        }
3455
3456        impl ArbitraryValue for FakeIcmpEchoRequest {
3457            fn arbitrary_value() -> Self {
3458                FakeIcmpEchoRequest { id: 1 }
3459            }
3460        }
3461
3462        impl ArbitraryValue for SegmentHeader {
3463            fn arbitrary_value() -> Self {
3464                SegmentHeader {
3465                    seq: SeqNum::new(55555),
3466                    wnd: UnscaledWindowSize::from(1234),
3467                    ..Default::default()
3468                }
3469            }
3470        }
3471
3472        pub(crate) trait IcmpErrorMessage<I: FilterIpExt> {
3473            type Serializer: TransportPacketSerializer<I, Buffer: packet::ReusableBuffer>
3474                + Debug
3475                + PartialEq;
3476
3477            fn proto() -> I::Proto {
3478                I::map_ip((), |()| Ipv4Proto::Icmp, |()| Ipv6Proto::Icmpv6)
3479            }
3480
3481            fn make_serializer(
3482                src_ip: I::Addr,
3483                dst_ip: I::Addr,
3484                inner: Vec<u8>,
3485            ) -> Self::Serializer;
3486
3487            fn make_serializer_truncated(
3488                src_ip: I::Addr,
3489                dst_ip: I::Addr,
3490                mut payload: Vec<u8>,
3491                truncate_payload: Option<usize>,
3492            ) -> Self::Serializer {
3493                if let Some(len) = truncate_payload {
3494                    payload.truncate(len);
3495                }
3496
3497                Self::make_serializer(src_ip, dst_ip, payload)
3498            }
3499        }
3500
3501        pub(crate) struct Icmpv4DestUnreachableError;
3502
3503        impl IcmpErrorMessage<Ipv4> for Icmpv4DestUnreachableError {
3504            type Serializer = Nested<Buf<Vec<u8>>, IcmpPacketBuilder<Ipv4, IcmpDestUnreachable>>;
3505
3506            fn make_serializer(
3507                src_ip: Ipv4Addr,
3508                dst_ip: Ipv4Addr,
3509                payload: Vec<u8>,
3510            ) -> Self::Serializer {
3511                IcmpPacketBuilder::<Ipv4, IcmpDestUnreachable>::new(
3512                    src_ip,
3513                    dst_ip,
3514                    Icmpv4DestUnreachableCode::DestHostUnreachable,
3515                    IcmpDestUnreachable::default(),
3516                )
3517                .wrap_body(Buf::new(payload, ..))
3518            }
3519        }
3520
3521        pub(crate) struct Icmpv6DestUnreachableError;
3522
3523        impl IcmpErrorMessage<Ipv6> for Icmpv6DestUnreachableError {
3524            type Serializer = Nested<
3525                TruncatingSerializer<Buf<Vec<u8>>>,
3526                IcmpPacketBuilder<Ipv6, IcmpDestUnreachable>,
3527            >;
3528
3529            fn make_serializer(
3530                src_ip: Ipv6Addr,
3531                dst_ip: Ipv6Addr,
3532                payload: Vec<u8>,
3533            ) -> Self::Serializer {
3534                IcmpPacketBuilder::<Ipv6, IcmpDestUnreachable>::new(
3535                    src_ip,
3536                    dst_ip,
3537                    Icmpv6DestUnreachableCode::AddrUnreachable,
3538                    IcmpDestUnreachable::default(),
3539                )
3540                .wrap_body(TruncatingSerializer::new(
3541                    Buf::new(payload, ..),
3542                    TruncateDirection::DiscardBack,
3543                ))
3544            }
3545        }
3546    }
3547
3548    /// Creates a new `IpPacket` with the specified addresses and body.
3549    pub fn new_filter_egress_ip_packet<I: FilterIpExt, S: TransportPacketSerializer<I>>(
3550        src_addr: I::Addr,
3551        dst_addr: I::Addr,
3552        protocol: I::Proto,
3553        body: &'_ mut S,
3554    ) -> impl FilterIpPacket<I> + use<'_, I, S> {
3555        TxPacket::new(src_addr, dst_addr, protocol, body)
3556    }
3557}
3558
3559#[cfg(test)]
3560mod tests {
3561    use alloc::vec::Vec;
3562    use core::fmt::Debug;
3563    use core::marker::PhantomData;
3564    use netstack3_base::{SeqNum, UnscaledWindowSize};
3565
3566    use assert_matches::assert_matches;
3567    use ip_test_macro::ip_test;
3568    use packet::{
3569        EmptyBuf, FragmentedBuffer as _, InnerPacketBuilder as _, PacketBuilder as _,
3570        ParseBufferMut, PartialSerializer,
3571    };
3572    use packet_formats::icmp::IcmpZeroCode;
3573    use packet_formats::tcp::TcpSegmentBuilder;
3574    use test_case::{test_case, test_matrix};
3575
3576    use crate::conntrack;
3577
3578    use super::testutil::internal::{
3579        IcmpErrorMessage, Icmpv4DestUnreachableError, Icmpv6DestUnreachableError, TestIpExt,
3580    };
3581    use super::*;
3582
3583    const SRC_PORT: NonZeroU16 = NonZeroU16::new(11111).unwrap();
3584    const DST_PORT: NonZeroU16 = NonZeroU16::new(22222).unwrap();
3585    const SRC_PORT_2: NonZeroU16 = NonZeroU16::new(44444).unwrap();
3586    const DST_PORT_2: NonZeroU16 = NonZeroU16::new(55555).unwrap();
3587
3588    const SEQ_NUM: u32 = 1;
3589    const ACK_NUM: Option<u32> = Some(2);
3590    const WINDOW_SIZE: u16 = 3u16;
3591
3592    trait Protocol {
3593        const HEADER_SIZE: usize;
3594
3595        type Serializer<'a, I: FilterIpExt>: TransportPacketSerializer<I, Buffer: packet::ReusableBuffer>
3596            + MaybeTransportPacketMut<I>
3597            + Debug
3598            + PartialEq;
3599
3600        fn proto<I: IpExt>() -> I::Proto;
3601
3602        fn make_serializer_with_ports_data<'a, I: FilterIpExt>(
3603            src_ip: I::Addr,
3604            dst_ip: I::Addr,
3605            src_port: NonZeroU16,
3606            dst_port: NonZeroU16,
3607            data: &'a [u8],
3608        ) -> Self::Serializer<'a, I>;
3609
3610        fn make_serializer_with_ports<'a, I: FilterIpExt>(
3611            src_ip: I::Addr,
3612            dst_ip: I::Addr,
3613            src_port: NonZeroU16,
3614            dst_port: NonZeroU16,
3615        ) -> Self::Serializer<'a, I> {
3616            Self::make_serializer_with_ports_data(src_ip, dst_ip, src_port, dst_port, &[1, 2, 3])
3617        }
3618
3619        fn make_serializer<'a, I: FilterIpExt>(
3620            src_ip: I::Addr,
3621            dst_ip: I::Addr,
3622        ) -> Self::Serializer<'a, I> {
3623            Self::make_serializer_with_ports(src_ip, dst_ip, SRC_PORT, DST_PORT)
3624        }
3625
3626        fn make_packet<I: FilterIpExt>(src_ip: I::Addr, dst_ip: I::Addr) -> Vec<u8> {
3627            Self::make_packet_with_ports::<I>(src_ip, dst_ip, SRC_PORT, DST_PORT)
3628        }
3629
3630        fn make_packet_with_ports<I: FilterIpExt>(
3631            src_ip: I::Addr,
3632            dst_ip: I::Addr,
3633            src_port: NonZeroU16,
3634            dst_port: NonZeroU16,
3635        ) -> Vec<u8> {
3636            Self::make_serializer_with_ports::<I>(src_ip, dst_ip, src_port, dst_port)
3637                .serialize_vec_outer()
3638                .expect("serialize packet")
3639                .unwrap_b()
3640                .into_inner()
3641        }
3642
3643        fn make_ip_packet_with_ports_data<I: FilterIpExt>(
3644            src_ip: I::Addr,
3645            dst_ip: I::Addr,
3646            src_port: NonZeroU16,
3647            dst_port: NonZeroU16,
3648            data: &[u8],
3649        ) -> Vec<u8> {
3650            I::PacketBuilder::new(src_ip, dst_ip, u8::MAX, Self::proto::<I>())
3651                .wrap_body(Self::make_serializer_with_ports_data::<I>(
3652                    src_ip, dst_ip, src_port, dst_port, data,
3653                ))
3654                .serialize_vec_outer()
3655                .expect("serialize packet")
3656                .unwrap_b()
3657                .into_inner()
3658        }
3659    }
3660
3661    struct Udp;
3662
3663    impl Protocol for Udp {
3664        const HEADER_SIZE: usize = 8;
3665
3666        type Serializer<'a, I: FilterIpExt> =
3667            Nested<InnerSerializer<&'a [u8], EmptyBuf>, UdpPacketBuilder<I::Addr>>;
3668
3669        fn proto<I: IpExt>() -> I::Proto {
3670            IpProto::Udp.into()
3671        }
3672
3673        fn make_serializer_with_ports_data<'a, I: FilterIpExt>(
3674            src_ip: I::Addr,
3675            dst_ip: I::Addr,
3676            src_port: NonZeroU16,
3677            dst_port: NonZeroU16,
3678            data: &'a [u8],
3679        ) -> Self::Serializer<'a, I> {
3680            UdpPacketBuilder::new(src_ip, dst_ip, Some(src_port), dst_port)
3681                .wrap_body(data.into_serializer())
3682        }
3683    }
3684
3685    // The `TcpSegmentBuilder` impls are test-only on purpose, and removing this
3686    // restriction should be thought through.
3687    //
3688    // TCP state tracking depends on being able to read TCP options, but
3689    // TcpSegmentBuilder does not have this information. If a TcpSegmentBuilder
3690    // passes through filtering with options tracked separately, then these will
3691    // not be seen by conntrack and could lead to state desynchronization.
3692    impl<A: IpAddress, Inner: PayloadLen> MaybeTransportPacket for Nested<Inner, TcpSegmentBuilder<A>> {
3693        fn transport_packet_data(&self) -> Option<TransportPacketData> {
3694            Some(TransportPacketData::Tcp {
3695                src_port: TcpSegmentBuilder::src_port(self.outer()).map_or(0, NonZeroU16::get),
3696                dst_port: TcpSegmentBuilder::dst_port(self.outer()).map_or(0, NonZeroU16::get),
3697                segment: self.outer().try_into().ok()?,
3698                payload_len: self.inner().len(),
3699            })
3700        }
3701    }
3702
3703    impl<I: IpExt, Inner> MaybeTransportPacketMut<I> for Nested<Inner, TcpSegmentBuilder<I::Addr>> {
3704        type TransportPacketMut<'a>
3705            = &'a mut Self
3706        where
3707            Self: 'a;
3708
3709        fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3710            Some(self)
3711        }
3712    }
3713
3714    impl<I: IpExt, Inner> TransportPacketMut<I> for Nested<Inner, TcpSegmentBuilder<I::Addr>> {
3715        fn set_src_port(&mut self, port: NonZeroU16) {
3716            self.outer_mut().set_src_port(port);
3717        }
3718
3719        fn set_dst_port(&mut self, port: NonZeroU16) {
3720            self.outer_mut().set_dst_port(port);
3721        }
3722
3723        fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
3724            self.outer_mut().set_src_ip(new);
3725        }
3726
3727        fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
3728            self.outer_mut().set_dst_ip(new);
3729        }
3730    }
3731
3732    impl<A: IpAddress, I: IpExt, Inner> MaybeIcmpErrorPayload<I>
3733        for Nested<Inner, TcpSegmentBuilder<A>>
3734    {
3735        fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3736            None
3737        }
3738    }
3739
3740    impl<A: IpAddress, I: FilterIpExt, Inner> MaybeIcmpErrorMut<I>
3741        for Nested<Inner, TcpSegmentBuilder<A>>
3742    {
3743        type IcmpErrorMut<'a>
3744            = Never
3745        where
3746            Self: 'a;
3747
3748        fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3749            None
3750        }
3751    }
3752
3753    enum Tcp {}
3754
3755    impl Protocol for Tcp {
3756        const HEADER_SIZE: usize = 20;
3757
3758        type Serializer<'a, I: FilterIpExt> =
3759            Nested<InnerSerializer<&'a [u8], EmptyBuf>, TcpSegmentBuilder<I::Addr>>;
3760
3761        fn proto<I: IpExt>() -> I::Proto {
3762            IpProto::Tcp.into()
3763        }
3764
3765        fn make_serializer_with_ports_data<'a, I: FilterIpExt>(
3766            src_ip: I::Addr,
3767            dst_ip: I::Addr,
3768            src_port: NonZeroU16,
3769            dst_port: NonZeroU16,
3770            data: &'a [u8],
3771        ) -> Self::Serializer<'a, I> {
3772            TcpSegmentBuilder::new(
3773                src_ip,
3774                dst_ip,
3775                src_port,
3776                dst_port,
3777                SEQ_NUM,
3778                ACK_NUM,
3779                WINDOW_SIZE,
3780            )
3781            .wrap_body(data.into_serializer())
3782        }
3783    }
3784
3785    enum IcmpEchoRequest {}
3786
3787    impl Protocol for IcmpEchoRequest {
3788        const HEADER_SIZE: usize = 8;
3789
3790        type Serializer<'a, I: FilterIpExt> = Nested<
3791            InnerSerializer<&'a [u8], EmptyBuf>,
3792            IcmpPacketBuilder<I, icmp::IcmpEchoRequest>,
3793        >;
3794
3795        fn proto<I: IpExt>() -> I::Proto {
3796            I::map_ip((), |()| Ipv4Proto::Icmp, |()| Ipv6Proto::Icmpv6)
3797        }
3798
3799        fn make_serializer_with_ports_data<'a, I: FilterIpExt>(
3800            src_ip: I::Addr,
3801            dst_ip: I::Addr,
3802            src_port: NonZeroU16,
3803            _dst_port: NonZeroU16,
3804            data: &'a [u8],
3805        ) -> Self::Serializer<'a, I> {
3806            IcmpPacketBuilder::<I, _>::new(
3807                src_ip,
3808                dst_ip,
3809                IcmpZeroCode,
3810                icmp::IcmpEchoRequest::new(/* id */ src_port.get(), /* seq */ 0),
3811            )
3812            .wrap_body(data.into_serializer())
3813        }
3814    }
3815
3816    enum IcmpEchoReply {}
3817
3818    impl Protocol for IcmpEchoReply {
3819        const HEADER_SIZE: usize = 8;
3820
3821        type Serializer<'a, I: FilterIpExt> =
3822            Nested<InnerSerializer<&'a [u8], EmptyBuf>, IcmpPacketBuilder<I, icmp::IcmpEchoReply>>;
3823
3824        fn proto<I: IpExt>() -> I::Proto {
3825            I::map_ip((), |()| Ipv4Proto::Icmp, |()| Ipv6Proto::Icmpv6)
3826        }
3827
3828        fn make_serializer_with_ports_data<'a, I: FilterIpExt>(
3829            src_ip: I::Addr,
3830            dst_ip: I::Addr,
3831            _src_port: NonZeroU16,
3832            dst_port: NonZeroU16,
3833            data: &'a [u8],
3834        ) -> Self::Serializer<'a, I> {
3835            IcmpPacketBuilder::<I, _>::new(
3836                src_ip,
3837                dst_ip,
3838                IcmpZeroCode,
3839                icmp::IcmpEchoReply::new(/* id */ dst_port.get(), /* seq */ 0),
3840            )
3841            .wrap_body(data.into_serializer())
3842        }
3843    }
3844
3845    enum TransportPacketDataProtocol {
3846        Tcp,
3847        Udp,
3848        IcmpEchoRequest,
3849    }
3850
3851    impl TransportPacketDataProtocol {
3852        fn make_packet<I: TestIpExt>(&self, src_ip: I::Addr, dst_ip: I::Addr) -> Vec<u8> {
3853            match self {
3854                TransportPacketDataProtocol::Tcp => Tcp::make_packet::<I>(src_ip, dst_ip),
3855                TransportPacketDataProtocol::Udp => Udp::make_packet::<I>(src_ip, dst_ip),
3856                TransportPacketDataProtocol::IcmpEchoRequest => {
3857                    IcmpEchoRequest::make_packet::<I>(src_ip, dst_ip)
3858                }
3859            }
3860        }
3861
3862        fn make_ip_packet_with_ports_data<I: TestIpExt>(
3863            &self,
3864            src_ip: I::Addr,
3865            dst_ip: I::Addr,
3866            src_port: NonZeroU16,
3867            dst_port: NonZeroU16,
3868            data: &[u8],
3869        ) -> Vec<u8> {
3870            match self {
3871                TransportPacketDataProtocol::Tcp => Tcp::make_ip_packet_with_ports_data::<I>(
3872                    src_ip, dst_ip, src_port, dst_port, data,
3873                ),
3874                TransportPacketDataProtocol::Udp => Udp::make_ip_packet_with_ports_data::<I>(
3875                    src_ip, dst_ip, src_port, dst_port, data,
3876                ),
3877                TransportPacketDataProtocol::IcmpEchoRequest => {
3878                    IcmpEchoRequest::make_ip_packet_with_ports_data::<I>(
3879                        src_ip, dst_ip, src_port, dst_port, data,
3880                    )
3881                }
3882            }
3883        }
3884
3885        fn proto<I: TestIpExt>(&self) -> I::Proto {
3886            match self {
3887                TransportPacketDataProtocol::Tcp => Tcp::proto::<I>(),
3888                TransportPacketDataProtocol::Udp => Udp::proto::<I>(),
3889                TransportPacketDataProtocol::IcmpEchoRequest => IcmpEchoRequest::proto::<I>(),
3890            }
3891        }
3892    }
3893
3894    #[ip_test(I)]
3895    #[test_case(TransportPacketDataProtocol::Udp)]
3896    #[test_case(TransportPacketDataProtocol::Tcp)]
3897    #[test_case(TransportPacketDataProtocol::IcmpEchoRequest)]
3898    fn transport_packet_data_from_serialized<I: TestIpExt>(proto: TransportPacketDataProtocol) {
3899        let expected_data = match proto {
3900            TransportPacketDataProtocol::Tcp => TransportPacketData::Tcp {
3901                src_port: SRC_PORT.get(),
3902                dst_port: DST_PORT.get(),
3903                segment: SegmentHeader {
3904                    seq: SeqNum::new(SEQ_NUM),
3905                    ack: ACK_NUM.map(SeqNum::new),
3906                    wnd: UnscaledWindowSize::from(WINDOW_SIZE),
3907                    ..Default::default()
3908                },
3909                payload_len: 3,
3910            },
3911            TransportPacketDataProtocol::Udp => {
3912                TransportPacketData::Generic { src_port: SRC_PORT.get(), dst_port: DST_PORT.get() }
3913            }
3914            TransportPacketDataProtocol::IcmpEchoRequest => {
3915                TransportPacketData::Generic { src_port: SRC_PORT.get(), dst_port: SRC_PORT.get() }
3916            }
3917        };
3918
3919        let buf = proto.make_packet::<I>(I::SRC_IP, I::DST_IP);
3920        let parsed_data = TransportPacketData::parse_in_ip_packet::<I, _>(
3921            I::SRC_IP,
3922            I::DST_IP,
3923            proto.proto::<I>(),
3924            buf.as_slice(),
3925        )
3926        .expect("failed to parse transport packet data");
3927
3928        assert_eq!(parsed_data, expected_data);
3929    }
3930
3931    enum PacketType {
3932        FullyParsed,
3933        Raw,
3934    }
3935
3936    #[ip_test(I)]
3937    #[test_matrix(
3938        [
3939            TransportPacketDataProtocol::Udp,
3940            TransportPacketDataProtocol::Tcp,
3941            TransportPacketDataProtocol::IcmpEchoRequest,
3942        ],
3943        [
3944            PacketType::FullyParsed,
3945            PacketType::Raw
3946        ]
3947    )]
3948    fn conntrack_packet_data_from_ip_packet<I: TestIpExt>(
3949        proto: TransportPacketDataProtocol,
3950        packet_type: PacketType,
3951    ) where
3952        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
3953        for<'a> I::PacketRaw<&'a mut [u8]>: IpPacket<I>,
3954    {
3955        let expected_data = match proto {
3956            TransportPacketDataProtocol::Tcp => conntrack::PacketMetadata::new(
3957                I::SRC_IP,
3958                I::DST_IP,
3959                conntrack::TransportProtocol::Tcp,
3960                TransportPacketData::Tcp {
3961                    src_port: SRC_PORT.get(),
3962                    dst_port: DST_PORT.get(),
3963                    segment: SegmentHeader {
3964                        seq: SeqNum::new(SEQ_NUM),
3965                        ack: ACK_NUM.map(SeqNum::new),
3966                        wnd: UnscaledWindowSize::from(WINDOW_SIZE),
3967                        ..Default::default()
3968                    },
3969                    payload_len: 3,
3970                },
3971            ),
3972            TransportPacketDataProtocol::Udp => conntrack::PacketMetadata::new(
3973                I::SRC_IP,
3974                I::DST_IP,
3975                conntrack::TransportProtocol::Udp,
3976                TransportPacketData::Generic { src_port: SRC_PORT.get(), dst_port: DST_PORT.get() },
3977            ),
3978            TransportPacketDataProtocol::IcmpEchoRequest => conntrack::PacketMetadata::new(
3979                I::SRC_IP,
3980                I::DST_IP,
3981                conntrack::TransportProtocol::Icmp,
3982                TransportPacketData::Generic { src_port: SRC_PORT.get(), dst_port: SRC_PORT.get() },
3983            ),
3984        };
3985
3986        let mut buf = proto.make_ip_packet_with_ports_data::<I>(
3987            I::SRC_IP,
3988            I::DST_IP,
3989            SRC_PORT,
3990            DST_PORT,
3991            &[1, 2, 3],
3992        );
3993
3994        let parsed_data = match packet_type {
3995            PacketType::FullyParsed => {
3996                let packet = I::Packet::parse_mut(SliceBufViewMut::new(buf.as_mut()), ())
3997                    .expect("parse IP packet");
3998                packet.conntrack_packet().expect("packet should be trackable")
3999            }
4000            PacketType::Raw => {
4001                let packet = I::PacketRaw::parse_mut(SliceBufViewMut::new(buf.as_mut()), ())
4002                    .expect("parse IP packet");
4003                packet.conntrack_packet().expect("packet should be trackable")
4004            }
4005        };
4006
4007        assert_eq!(parsed_data, expected_data);
4008    }
4009
4010    #[ip_test(I)]
4011    #[test_case(PhantomData::<Udp>)]
4012    #[test_case(PhantomData::<Tcp>)]
4013    #[test_case(PhantomData::<IcmpEchoRequest>)]
4014    fn update_pseudo_header_address_updates_checksum<I: TestIpExt, P: Protocol>(
4015        _proto: PhantomData<P>,
4016    ) {
4017        let mut buf = P::make_packet::<I>(I::SRC_IP, I::DST_IP);
4018        let view = SliceBufViewMut::new(&mut buf);
4019
4020        let mut packet = ParsedTransportHeaderMut::<I>::parse_in_ip_packet(P::proto::<I>(), view)
4021            .expect("parse transport header");
4022        packet.update_pseudo_header_src_addr(I::SRC_IP, I::SRC_IP_2);
4023        packet.update_pseudo_header_dst_addr(I::DST_IP, I::DST_IP_2);
4024        // Drop the packet because it's holding a mutable borrow of `buf` which
4025        // we need to assert equality later.
4026        drop(packet);
4027
4028        let equivalent = P::make_packet::<I>(I::SRC_IP_2, I::DST_IP_2);
4029
4030        assert_eq!(equivalent, buf);
4031    }
4032
4033    #[ip_test(I)]
4034    #[test_case(PhantomData::<Udp>, true, true)]
4035    #[test_case(PhantomData::<Tcp>, true, true)]
4036    #[test_case(PhantomData::<IcmpEchoRequest>, true, false)]
4037    #[test_case(PhantomData::<IcmpEchoReply>, false, true)]
4038    fn parsed_packet_update_src_dst_port_updates_checksum<I: TestIpExt, P: Protocol>(
4039        _proto: PhantomData<P>,
4040        update_src_port: bool,
4041        update_dst_port: bool,
4042    ) {
4043        let mut buf = P::make_packet_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT);
4044        let view = SliceBufViewMut::new(&mut buf);
4045
4046        let mut packet = ParsedTransportHeaderMut::<I>::parse_in_ip_packet(P::proto::<I>(), view)
4047            .expect("parse transport header");
4048        let expected_src_port = if update_src_port {
4049            packet.set_src_port(SRC_PORT_2);
4050            SRC_PORT_2
4051        } else {
4052            SRC_PORT
4053        };
4054        let expected_dst_port = if update_dst_port {
4055            packet.set_dst_port(DST_PORT_2);
4056            DST_PORT_2
4057        } else {
4058            DST_PORT
4059        };
4060        drop(packet);
4061
4062        let equivalent = P::make_packet_with_ports::<I>(
4063            I::SRC_IP,
4064            I::DST_IP,
4065            expected_src_port,
4066            expected_dst_port,
4067        );
4068
4069        assert_eq!(equivalent, buf);
4070    }
4071
4072    #[ip_test(I)]
4073    #[test_case(PhantomData::<Udp>)]
4074    #[test_case(PhantomData::<Tcp>)]
4075    fn serializer_update_src_dst_port_updates_checksum<I: TestIpExt, P: Protocol>(
4076        _proto: PhantomData<P>,
4077    ) {
4078        let mut serializer =
4079            P::make_serializer_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT);
4080        let mut packet =
4081            serializer.transport_packet_mut().expect("packet should support rewriting");
4082        packet.set_src_port(SRC_PORT_2);
4083        packet.set_dst_port(DST_PORT_2);
4084        drop(packet);
4085
4086        let equivalent =
4087            P::make_serializer_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT_2, DST_PORT_2);
4088
4089        assert_eq!(equivalent, serializer);
4090    }
4091
4092    #[ip_test(I)]
4093    fn icmp_echo_request_update_id_port_updates_checksum<I: TestIpExt>() {
4094        let mut serializer = IcmpPacketBuilder::<I, _>::new(
4095            I::SRC_IP,
4096            I::DST_IP,
4097            IcmpZeroCode,
4098            icmp::IcmpEchoRequest::new(SRC_PORT.get(), /* seq */ 0),
4099        )
4100        .wrap_body(EmptyBuf);
4101        serializer
4102            .transport_packet_mut()
4103            .expect("packet should support rewriting")
4104            .set_src_port(SRC_PORT_2);
4105
4106        let equivalent = IcmpPacketBuilder::<I, _>::new(
4107            I::SRC_IP,
4108            I::DST_IP,
4109            IcmpZeroCode,
4110            icmp::IcmpEchoRequest::new(SRC_PORT_2.get(), /* seq */ 0),
4111        )
4112        .wrap_body(EmptyBuf);
4113
4114        assert_eq!(equivalent, serializer);
4115    }
4116
4117    #[ip_test(I)]
4118    fn icmp_echo_reply_update_id_port_updates_checksum<I: TestIpExt>() {
4119        let mut serializer = IcmpPacketBuilder::<I, _>::new(
4120            I::SRC_IP,
4121            I::DST_IP,
4122            IcmpZeroCode,
4123            icmp::IcmpEchoReply::new(SRC_PORT.get(), /* seq */ 0),
4124        )
4125        .wrap_body(EmptyBuf);
4126        serializer
4127            .transport_packet_mut()
4128            .expect("packet should support rewriting")
4129            .set_dst_port(SRC_PORT_2);
4130
4131        let equivalent = IcmpPacketBuilder::<I, _>::new(
4132            I::SRC_IP,
4133            I::DST_IP,
4134            IcmpZeroCode,
4135            icmp::IcmpEchoReply::new(SRC_PORT_2.get(), /* seq */ 0),
4136        )
4137        .wrap_body(EmptyBuf);
4138
4139        assert_eq!(equivalent, serializer);
4140    }
4141
4142    fn ip_packet<I: TestIpExt, P: Protocol>(src: I::Addr, dst: I::Addr) -> Buf<Vec<u8>> {
4143        Buf::new(P::make_packet::<I>(src, dst), ..)
4144            .wrap_in(I::PacketBuilder::new(src, dst, I::PACKET_TTL, P::proto::<I>()))
4145            .serialize_vec_outer()
4146            .expect("serialize IP packet")
4147            .unwrap_b()
4148    }
4149
4150    #[ip_test(I)]
4151    #[test_matrix(
4152        [
4153            PhantomData::<Udp>,
4154            PhantomData::<Tcp>,
4155            PhantomData::<IcmpEchoRequest>,
4156        ],
4157        [
4158            PacketType::FullyParsed,
4159            PacketType::Raw
4160        ]
4161    )]
4162    fn ip_packet_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(
4163        _proto: PhantomData<P>,
4164        packet_type: PacketType,
4165    ) where
4166        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
4167        for<'a> I::PacketRaw<&'a mut [u8]>: IpPacket<I>,
4168    {
4169        let mut buf = ip_packet::<I, P>(I::SRC_IP, I::DST_IP).into_inner();
4170
4171        match packet_type {
4172            PacketType::FullyParsed => {
4173                let mut packet = I::Packet::parse_mut(SliceBufViewMut::new(&mut buf), ())
4174                    .expect("parse IP packet");
4175                packet.set_src_addr(I::SRC_IP_2);
4176                packet.set_dst_addr(I::DST_IP_2);
4177            }
4178            PacketType::Raw => {
4179                let mut packet = I::PacketRaw::parse_mut(SliceBufViewMut::new(&mut buf), ())
4180                    .expect("parse IP packet");
4181                packet.set_src_addr(I::SRC_IP_2);
4182                packet.set_dst_addr(I::DST_IP_2);
4183            }
4184        }
4185
4186        let equivalent = ip_packet::<I, P>(I::SRC_IP_2, I::DST_IP_2).into_inner();
4187
4188        assert_eq!(equivalent, buf);
4189    }
4190
4191    #[ip_test(I)]
4192    #[test_case(PhantomData::<Udp>)]
4193    #[test_case(PhantomData::<Tcp>)]
4194    #[test_case(PhantomData::<IcmpEchoRequest>)]
4195    fn forwarded_packet_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(
4196        _proto: PhantomData<P>,
4197    ) {
4198        let mut buffer = ip_packet::<I, P>(I::SRC_IP, I::DST_IP);
4199        let meta = buffer.parse::<I::Packet<_>>().expect("parse IP packet").parse_metadata();
4200        let mut packet =
4201            ForwardedPacket::<I, _>::new(I::SRC_IP, I::DST_IP, P::proto::<I>(), meta, buffer);
4202        packet.set_src_addr(I::SRC_IP_2);
4203        packet.set_dst_addr(I::DST_IP_2);
4204
4205        let mut buffer = ip_packet::<I, P>(I::SRC_IP_2, I::DST_IP_2);
4206        let meta = buffer.parse::<I::Packet<_>>().expect("parse IP packet").parse_metadata();
4207        let equivalent =
4208            ForwardedPacket::<I, _>::new(I::SRC_IP_2, I::DST_IP_2, P::proto::<I>(), meta, buffer);
4209
4210        assert_eq!(equivalent, packet);
4211    }
4212
4213    #[ip_test(I)]
4214    #[test_case(PhantomData::<Udp>)]
4215    #[test_case(PhantomData::<Tcp>)]
4216    #[test_case(PhantomData::<IcmpEchoRequest>)]
4217    fn tx_packet_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(
4218        _proto: PhantomData<P>,
4219    ) {
4220        let mut body = P::make_serializer::<I>(I::SRC_IP, I::DST_IP);
4221        let mut packet = TxPacket::<I, _>::new(I::SRC_IP, I::DST_IP, P::proto::<I>(), &mut body);
4222        packet.set_src_addr(I::SRC_IP_2);
4223        packet.set_dst_addr(I::DST_IP_2);
4224
4225        let mut equivalent_body = P::make_serializer::<I>(I::SRC_IP_2, I::DST_IP_2);
4226        let equivalent =
4227            TxPacket::new(I::SRC_IP_2, I::DST_IP_2, P::proto::<I>(), &mut equivalent_body);
4228
4229        assert_eq!(equivalent, packet);
4230    }
4231
4232    #[ip_test(I)]
4233    #[test_case(PhantomData::<Udp>)]
4234    #[test_case(PhantomData::<Tcp>)]
4235    #[test_case(PhantomData::<IcmpEchoRequest>)]
4236    fn nested_serializer_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(
4237        _proto: PhantomData<P>,
4238    ) {
4239        let mut packet =
4240            I::PacketBuilder::new(I::SRC_IP, I::DST_IP, I::PACKET_TTL, P::proto::<I>())
4241                .wrap_body(P::make_serializer::<I>(I::SRC_IP, I::DST_IP));
4242        packet.set_src_addr(I::SRC_IP_2);
4243        packet.set_dst_addr(I::DST_IP_2);
4244
4245        let equivalent = P::make_serializer::<I>(I::SRC_IP_2, I::DST_IP_2).wrap_in(
4246            I::PacketBuilder::new(I::SRC_IP_2, I::DST_IP_2, I::PACKET_TTL, P::proto::<I>()),
4247        );
4248
4249        assert_eq!(equivalent, packet);
4250    }
4251
4252    #[ip_test(I)]
4253    #[test_matrix(
4254         [
4255             PhantomData::<Udp>,
4256             PhantomData::<Tcp>,
4257             PhantomData::<IcmpEchoRequest>,
4258         ],
4259         [
4260             PacketType::FullyParsed,
4261             PacketType::Raw
4262         ]
4263     )]
4264    fn no_icmp_error_for_normal_ip_packet<I: TestIpExt, P: Protocol>(
4265        _proto: PhantomData<P>,
4266        packet_type: PacketType,
4267    ) where
4268        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
4269        for<'a> I::PacketRaw<&'a mut [u8]>: IpPacket<I>,
4270    {
4271        let mut buf = ip_packet::<I, P>(I::SRC_IP, I::DST_IP).into_inner();
4272        let icmp_error = match packet_type {
4273            PacketType::FullyParsed => {
4274                let packet = I::Packet::parse_mut(SliceBufViewMut::new(&mut buf), ())
4275                    .expect("parse IP packet");
4276                let icmp_payload = packet.maybe_icmp_error().icmp_error_payload();
4277
4278                icmp_payload
4279            }
4280            PacketType::Raw => {
4281                let packet = I::PacketRaw::parse_mut(SliceBufViewMut::new(&mut buf), ())
4282                    .expect("parse IP packet");
4283                let icmp_payload = packet.maybe_icmp_error().icmp_error_payload();
4284
4285                icmp_payload
4286            }
4287        };
4288
4289        assert_matches!(icmp_error, None);
4290    }
4291
4292    #[ip_test(I)]
4293    #[test_matrix(
4294         [
4295             PhantomData::<Udp>,
4296             PhantomData::<Tcp>,
4297             PhantomData::<IcmpEchoRequest>,
4298         ],
4299         [
4300             PacketType::FullyParsed,
4301             PacketType::Raw
4302         ]
4303     )]
4304    fn no_icmp_error_mut_for_normal_ip_packet<I: TestIpExt, P: Protocol>(
4305        _proto: PhantomData<P>,
4306        packet_type: PacketType,
4307    ) where
4308        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
4309        for<'a> I::PacketRaw<&'a mut [u8]>: IpPacket<I>,
4310    {
4311        let mut buf = ip_packet::<I, P>(I::SRC_IP, I::DST_IP).into_inner();
4312        match packet_type {
4313            PacketType::FullyParsed => {
4314                let mut packet = I::Packet::parse_mut(SliceBufViewMut::new(&mut buf), ())
4315                    .expect("parse IP packet");
4316                assert!(packet.icmp_error_mut().icmp_error_mut().is_none());
4317            }
4318            PacketType::Raw => {
4319                let mut packet = I::PacketRaw::parse_mut(SliceBufViewMut::new(&mut buf), ())
4320                    .expect("parse IP packet");
4321                assert!(packet.icmp_error_mut().icmp_error_mut().is_none());
4322            }
4323        }
4324    }
4325
4326    #[ip_test(I)]
4327    #[test_case(TransportPacketDataProtocol::Udp)]
4328    #[test_case(TransportPacketDataProtocol::Tcp)]
4329    #[test_case(TransportPacketDataProtocol::IcmpEchoRequest)]
4330    fn no_icmp_error_for_normal_bytes<I: TestIpExt>(proto: TransportPacketDataProtocol) {
4331        let buf = proto.make_packet::<I>(I::SRC_IP, I::DST_IP);
4332
4333        assert_matches!(
4334            ParsedIcmpErrorPayload::<I>::parse_in_outer_ip_packet(
4335                proto.proto::<I>(),
4336                buf.as_slice(),
4337            ),
4338            None
4339        );
4340    }
4341
4342    #[ip_test(I)]
4343    #[test_case(TransportPacketDataProtocol::Udp)]
4344    #[test_case(TransportPacketDataProtocol::Tcp)]
4345    #[test_case(TransportPacketDataProtocol::IcmpEchoRequest)]
4346    fn no_icmp_error_mut_for_normal_bytes<I: TestIpExt>(proto: TransportPacketDataProtocol) {
4347        let mut buf = proto.make_packet::<I>(I::SRC_IP, I::DST_IP);
4348
4349        assert!(
4350            ParsedIcmpErrorMut::<I>::parse_in_ip_packet(
4351                I::SRC_IP,
4352                I::DST_IP,
4353                proto.proto::<I>(),
4354                SliceBufViewMut::new(&mut buf),
4355            )
4356            .is_none()
4357        );
4358    }
4359
4360    #[ip_test(I)]
4361    #[test_case(PhantomData::<Udp>)]
4362    #[test_case(PhantomData::<Tcp>)]
4363    #[test_case(PhantomData::<IcmpEchoRequest>)]
4364    fn no_icmp_error_for_normal_serializer<I: TestIpExt, P: Protocol>(_proto: PhantomData<P>) {
4365        let serializer =
4366            P::make_serializer_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT);
4367
4368        assert_matches!(serializer.icmp_error_payload(), None);
4369    }
4370
4371    #[ip_test(I)]
4372    #[test_case(PhantomData::<Udp>)]
4373    #[test_case(PhantomData::<Tcp>)]
4374    #[test_case(PhantomData::<IcmpEchoRequest>)]
4375    fn no_icmp_error_mut_for_normal_serializer<I: TestIpExt, P: Protocol>(_proto: PhantomData<P>) {
4376        let mut serializer =
4377            P::make_serializer_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT);
4378
4379        assert!(serializer.icmp_error_mut().is_none());
4380    }
4381
4382    #[test_matrix(
4383        [
4384            PhantomData::<Icmpv4DestUnreachableError>,
4385            PhantomData::<Icmpv6DestUnreachableError>,
4386        ],
4387        [
4388            TransportPacketDataProtocol::Udp,
4389            TransportPacketDataProtocol::Tcp,
4390            TransportPacketDataProtocol::IcmpEchoRequest,
4391        ],
4392        [
4393            PacketType::FullyParsed,
4394            PacketType::Raw,
4395        ],
4396        [
4397            false,
4398            true,
4399        ]
4400    )]
4401    fn icmp_error_from_bytes<I: TestIpExt, IE: IcmpErrorMessage<I>>(
4402        _icmp_error: PhantomData<IE>,
4403        proto: TransportPacketDataProtocol,
4404        packet_type: PacketType,
4405        truncate_message: bool,
4406    ) {
4407        let serializer = IE::make_serializer_truncated(
4408            I::DST_IP_2,
4409            I::SRC_IP,
4410            proto.make_ip_packet_with_ports_data::<I>(
4411                I::SRC_IP,
4412                I::DST_IP,
4413                SRC_PORT,
4414                DST_PORT,
4415                &[0xAB; 5000],
4416            ),
4417            // Try with a truncated and full body to make sure we don't fail
4418            // when a partial payload is present. In these cases, the ICMP error
4419            // payload checksum can't be validated, though we want to be sure
4420            // it's updated as if it were correct.
4421            truncate_message.then_some(1280),
4422        )
4423        .wrap_in(I::PacketBuilder::new(I::DST_IP_2, I::SRC_IP, u8::MAX, IE::proto()));
4424
4425        let mut bytes: Buf<Vec<u8>> = serializer.serialize_vec_outer().unwrap().unwrap_b();
4426        let icmp_payload = match packet_type {
4427            PacketType::FullyParsed => {
4428                let packet = I::as_filter_packet_owned(bytes.parse_mut::<I::Packet<_>>().unwrap());
4429                let icmp_payload =
4430                    packet.maybe_icmp_error().icmp_error_payload().expect("no ICMP error found");
4431
4432                icmp_payload
4433            }
4434            PacketType::Raw => {
4435                let packet =
4436                    I::as_filter_packet_raw_owned(bytes.parse_mut::<I::PacketRaw<_>>().unwrap());
4437                let icmp_payload =
4438                    packet.maybe_icmp_error().icmp_error_payload().expect("no ICMP error found");
4439
4440                icmp_payload
4441            }
4442        };
4443
4444        let expected = match proto {
4445            TransportPacketDataProtocol::Tcp | TransportPacketDataProtocol::Udp => {
4446                ParsedIcmpErrorPayload {
4447                    src_ip: I::SRC_IP,
4448                    dst_ip: I::DST_IP,
4449                    src_port: SRC_PORT.get(),
4450                    dst_port: DST_PORT.get(),
4451                    proto: proto.proto::<I>(),
4452                }
4453            }
4454            TransportPacketDataProtocol::IcmpEchoRequest => {
4455                ParsedIcmpErrorPayload {
4456                    src_ip: I::SRC_IP,
4457                    dst_ip: I::DST_IP,
4458                    // NOTE: These are intentionally the same because of how
4459                    // ICMP tracking works.
4460                    src_port: SRC_PORT.get(),
4461                    dst_port: SRC_PORT.get(),
4462                    proto: proto.proto::<I>(),
4463                }
4464            }
4465        };
4466
4467        assert_eq!(icmp_payload, expected);
4468    }
4469
4470    #[test_matrix(
4471        [
4472            PhantomData::<Icmpv4DestUnreachableError>,
4473            PhantomData::<Icmpv6DestUnreachableError>,
4474        ],
4475        [
4476            TransportPacketDataProtocol::Udp,
4477            TransportPacketDataProtocol::Tcp,
4478            TransportPacketDataProtocol::IcmpEchoRequest,
4479        ],
4480        [
4481            false,
4482            true,
4483        ]
4484    )]
4485    fn icmp_error_from_serializer<I: TestIpExt, IE: IcmpErrorMessage<I>>(
4486        _icmp_error: PhantomData<IE>,
4487        proto: TransportPacketDataProtocol,
4488        truncate_message: bool,
4489    ) {
4490        let serializer = IE::make_serializer_truncated(
4491            I::DST_IP_2,
4492            I::SRC_IP,
4493            proto.make_ip_packet_with_ports_data::<I>(
4494                I::SRC_IP,
4495                I::DST_IP,
4496                SRC_PORT,
4497                DST_PORT,
4498                &[0xAB; 5000],
4499            ),
4500            // Try with a truncated and full body to make sure we don't fail
4501            // when a partial payload is present. In these cases, the ICMP error
4502            // payload checksum can't be validated, though we want to be sure
4503            // it's updated as if it were correct.
4504            truncate_message.then_some(1280),
4505        );
4506
4507        let actual =
4508            serializer.icmp_error_payload().expect("serializer should contain an IP packet");
4509
4510        let expected = match proto {
4511            TransportPacketDataProtocol::Tcp | TransportPacketDataProtocol::Udp => {
4512                ParsedIcmpErrorPayload::<I> {
4513                    src_ip: I::SRC_IP,
4514                    dst_ip: I::DST_IP,
4515                    src_port: SRC_PORT.get(),
4516                    dst_port: DST_PORT.get(),
4517                    proto: proto.proto::<I>(),
4518                }
4519            }
4520            TransportPacketDataProtocol::IcmpEchoRequest => ParsedIcmpErrorPayload::<I> {
4521                src_ip: I::SRC_IP,
4522                dst_ip: I::DST_IP,
4523                // NOTE: These are intentionally the same because of how ICMP
4524                // tracking works.
4525                src_port: SRC_PORT.get(),
4526                dst_port: SRC_PORT.get(),
4527                proto: proto.proto::<I>(),
4528            },
4529        };
4530
4531        assert_eq!(actual, expected);
4532    }
4533
4534    #[test_matrix(
4535        [
4536            PhantomData::<Icmpv4DestUnreachableError>,
4537            PhantomData::<Icmpv6DestUnreachableError>,
4538        ],
4539        [
4540            TransportPacketDataProtocol::Udp,
4541            TransportPacketDataProtocol::Tcp,
4542            TransportPacketDataProtocol::IcmpEchoRequest,
4543        ],
4544        [
4545            PacketType::FullyParsed,
4546            PacketType::Raw,
4547        ],
4548        [
4549            false,
4550            true,
4551        ]
4552    )]
4553    fn conntrack_packet_icmp_error_from_bytes<I: TestIpExt, IE: IcmpErrorMessage<I>>(
4554        _icmp_error: PhantomData<IE>,
4555        proto: TransportPacketDataProtocol,
4556        packet_type: PacketType,
4557        truncate_message: bool,
4558    ) {
4559        let serializer = IE::make_serializer_truncated(
4560            I::DST_IP_2,
4561            I::SRC_IP,
4562            proto.make_ip_packet_with_ports_data::<I>(
4563                I::SRC_IP,
4564                I::DST_IP,
4565                SRC_PORT,
4566                DST_PORT,
4567                &[0xAB; 5000],
4568            ),
4569            // Try with a truncated and full body to make sure we don't fail
4570            // when a partial payload is present. In these cases, the ICMP error
4571            // payload checksum can't be validated, though we want to be sure
4572            // it's updated as if it were correct.
4573            truncate_message.then_some(1280),
4574        )
4575        .wrap_in(I::PacketBuilder::new(I::DST_IP_2, I::SRC_IP, u8::MAX, IE::proto()));
4576
4577        let mut bytes: Buf<Vec<u8>> = serializer.serialize_vec_outer().unwrap().unwrap_b();
4578
4579        let conntrack_packet = match packet_type {
4580            PacketType::FullyParsed => {
4581                let packet = I::as_filter_packet_owned(bytes.parse_mut::<I::Packet<_>>().unwrap());
4582                packet.conntrack_packet().unwrap()
4583            }
4584            PacketType::Raw => {
4585                let packet =
4586                    I::as_filter_packet_raw_owned(bytes.parse_mut::<I::PacketRaw<_>>().unwrap());
4587                packet.conntrack_packet().unwrap()
4588            }
4589        };
4590
4591        let expected = match proto {
4592            TransportPacketDataProtocol::Tcp | TransportPacketDataProtocol::Udp => {
4593                conntrack::PacketMetadata::new_from_icmp_error(
4594                    I::SRC_IP,
4595                    I::DST_IP,
4596                    SRC_PORT.get(),
4597                    DST_PORT.get(),
4598                    I::map_ip(proto.proto::<I>(), |proto| proto.into(), |proto| proto.into()),
4599                )
4600            }
4601            TransportPacketDataProtocol::IcmpEchoRequest => {
4602                conntrack::PacketMetadata::new_from_icmp_error(
4603                    I::SRC_IP,
4604                    I::DST_IP,
4605                    // NOTE: These are intentionally the same because of how
4606                    // ICMP tracking works.
4607                    SRC_PORT.get(),
4608                    SRC_PORT.get(),
4609                    I::map_ip(proto.proto::<I>(), |proto| proto.into(), |proto| proto.into()),
4610                )
4611            }
4612        };
4613
4614        assert_eq!(conntrack_packet, expected);
4615    }
4616
4617    #[test_matrix(
4618        [
4619            PhantomData::<Icmpv4DestUnreachableError>,
4620            PhantomData::<Icmpv6DestUnreachableError>,
4621        ],
4622        [
4623            TransportPacketDataProtocol::Udp,
4624            TransportPacketDataProtocol::Tcp,
4625            TransportPacketDataProtocol::IcmpEchoRequest,
4626        ],
4627        [
4628            PacketType::FullyParsed,
4629            PacketType::Raw,
4630        ],
4631        [
4632            false,
4633            true,
4634        ]
4635    )]
4636    fn no_conntrack_packet_for_incompatible_outer_and_payload<
4637        I: TestIpExt,
4638        IE: IcmpErrorMessage<I>,
4639    >(
4640        _icmp_error: PhantomData<IE>,
4641        proto: TransportPacketDataProtocol,
4642        packet_type: PacketType,
4643        truncate_message: bool,
4644    ) {
4645        // In order for the outer packet to have the tuple (DST_IP_2, SRC_IP_2),
4646        // the host sending the error must have seen a packet with a source
4647        // address of SRC_IP_2, but we know that can't be right because the
4648        // payload of the packet contains a packet with a source address of
4649        // SRC_IP.
4650        let serializer = IE::make_serializer_truncated(
4651            I::DST_IP_2,
4652            I::SRC_IP_2,
4653            proto.make_ip_packet_with_ports_data::<I>(
4654                I::SRC_IP,
4655                I::DST_IP,
4656                SRC_PORT,
4657                DST_PORT,
4658                &[0xAB; 5000],
4659            ),
4660            // Try with a truncated and full body to make sure we don't fail
4661            // when a partial payload is present. In these cases, the ICMP error
4662            // payload checksum can't be validated, though we want to be sure
4663            // it's updated as if it were correct.
4664            truncate_message.then_some(1280),
4665        )
4666        .wrap_in(I::PacketBuilder::new(I::DST_IP_2, I::SRC_IP_2, u8::MAX, IE::proto()));
4667
4668        let mut bytes: Buf<Vec<u8>> = serializer.serialize_vec_outer().unwrap().unwrap_b();
4669
4670        let conntrack_packet = match packet_type {
4671            PacketType::FullyParsed => {
4672                let packet = I::as_filter_packet_owned(bytes.parse_mut::<I::Packet<_>>().unwrap());
4673                packet.conntrack_packet()
4674            }
4675            PacketType::Raw => {
4676                let packet =
4677                    I::as_filter_packet_raw_owned(bytes.parse_mut::<I::PacketRaw<_>>().unwrap());
4678                packet.conntrack_packet()
4679            }
4680        };
4681
4682        // Because the outer and payload tuples aren't compatible, we shouldn't
4683        // get a conntrack packet back.
4684        assert_matches!(conntrack_packet, None);
4685    }
4686
4687    #[test_matrix(
4688        [
4689            PhantomData::<Icmpv4DestUnreachableError>,
4690            PhantomData::<Icmpv6DestUnreachableError>,
4691        ],
4692        [
4693            TransportPacketDataProtocol::Udp,
4694            TransportPacketDataProtocol::Tcp,
4695            TransportPacketDataProtocol::IcmpEchoRequest,
4696        ],
4697        [
4698            false,
4699            true,
4700        ]
4701    )]
4702    fn icmp_error_mut_from_serializer<I: TestIpExt, IE: IcmpErrorMessage<I>>(
4703        _icmp_error: PhantomData<IE>,
4704        proto: TransportPacketDataProtocol,
4705        truncate_message: bool,
4706    ) where
4707        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
4708    {
4709        const LEN: usize = 5000;
4710
4711        let mut payload_bytes = proto.make_ip_packet_with_ports_data::<I>(
4712            I::SRC_IP,
4713            I::DST_IP,
4714            SRC_PORT,
4715            DST_PORT,
4716            &[0xAB; LEN],
4717        );
4718
4719        // Try with a truncated and full body to make sure we don't fail when a
4720        // partial payload is present.
4721        if truncate_message {
4722            payload_bytes.truncate(1280);
4723        }
4724
4725        let mut serializer = IE::make_serializer(I::SRC_IP, I::DST_IP, payload_bytes)
4726            .wrap_in(I::PacketBuilder::new(I::SRC_IP, I::DST_IP, u8::MAX, IE::proto()));
4727
4728        {
4729            let mut icmp_packet = serializer
4730                .icmp_error_mut()
4731                .icmp_error_mut()
4732                .expect("couldn't find an inner ICMP error");
4733
4734            {
4735                let mut inner_packet = icmp_packet.inner_packet().expect("no inner packet");
4736
4737                inner_packet.set_src_addr(I::SRC_IP_2);
4738                inner_packet.set_dst_addr(I::DST_IP_2);
4739            }
4740
4741            // Since this is just a serializer, there's no thing to be recalculated,
4742            // but this should still never fail.
4743            assert!(icmp_packet.recalculate_checksum());
4744        }
4745
4746        let mut expected_payload_bytes = proto.make_ip_packet_with_ports_data::<I>(
4747            I::SRC_IP_2,
4748            I::DST_IP_2,
4749            SRC_PORT,
4750            DST_PORT,
4751            &[0xAB; LEN],
4752        );
4753
4754        // Try with a truncated and full body to make sure we don't fail when a
4755        // partial payload is present.
4756        if truncate_message {
4757            expected_payload_bytes.truncate(1280);
4758        }
4759
4760        let expected_serializer = IE::make_serializer(I::SRC_IP, I::DST_IP, expected_payload_bytes)
4761            // We never updated the outer IPs, so they should still be
4762            // their original values.
4763            .wrap_in(I::PacketBuilder::new(I::SRC_IP, I::DST_IP, u8::MAX, IE::proto()));
4764
4765        let actual_bytes = serializer.serialize_vec_outer().unwrap().unwrap_b();
4766        let expected_bytes = expected_serializer.serialize_vec_outer().unwrap().unwrap_b();
4767
4768        assert_eq!(actual_bytes, expected_bytes);
4769    }
4770
4771    #[test_matrix(
4772        [
4773            PhantomData::<Icmpv4DestUnreachableError>,
4774            PhantomData::<Icmpv6DestUnreachableError>,
4775        ],
4776        [
4777            TransportPacketDataProtocol::Udp,
4778            TransportPacketDataProtocol::Tcp,
4779            TransportPacketDataProtocol::IcmpEchoRequest,
4780        ],
4781        [
4782            PacketType::FullyParsed,
4783            PacketType::Raw,
4784        ],
4785        [
4786            false,
4787            true,
4788        ]
4789    )]
4790    fn icmp_error_mut_from_bytes<I: TestIpExt, IE: IcmpErrorMessage<I>>(
4791        _icmp_error: PhantomData<IE>,
4792        proto: TransportPacketDataProtocol,
4793        packet_type: PacketType,
4794        truncate_message: bool,
4795    ) where
4796        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
4797    {
4798        const LEN: usize = 5000;
4799
4800        let mut payload_bytes = proto.make_ip_packet_with_ports_data::<I>(
4801            I::SRC_IP,
4802            I::DST_IP,
4803            SRC_PORT,
4804            DST_PORT,
4805            &[0xAB; LEN],
4806        );
4807
4808        // Try with a truncated and full body to make sure we don't fail when a
4809        // partial payload is present.
4810        if truncate_message {
4811            payload_bytes.truncate(1280);
4812        }
4813
4814        let serializer = IE::make_serializer(I::SRC_IP, I::DST_IP, payload_bytes)
4815            .wrap_in(I::PacketBuilder::new(I::SRC_IP, I::DST_IP, u8::MAX, IE::proto()));
4816
4817        let mut bytes = serializer.serialize_vec_outer().unwrap().unwrap_b().into_inner();
4818
4819        {
4820            fn modify_packet<I: TestIpExt, P: IpPacket<I>>(mut packet: P) {
4821                let mut icmp_error = packet.icmp_error_mut();
4822                let mut icmp_error =
4823                    icmp_error.icmp_error_mut().expect("couldn't find an inner ICMP error");
4824
4825                {
4826                    let mut inner_packet = icmp_error.inner_packet().expect("no inner packet");
4827
4828                    inner_packet.set_src_addr(I::SRC_IP_2);
4829                    inner_packet.set_dst_addr(I::DST_IP_2);
4830                }
4831
4832                assert!(icmp_error.recalculate_checksum());
4833            }
4834
4835            let mut bytes = Buf::new(&mut bytes, ..);
4836
4837            match packet_type {
4838                PacketType::FullyParsed => {
4839                    let packet =
4840                        I::as_filter_packet_owned(bytes.parse_mut::<I::Packet<_>>().unwrap());
4841                    modify_packet(packet);
4842                }
4843                PacketType::Raw => {
4844                    let packet = I::as_filter_packet_raw_owned(
4845                        bytes.parse_mut::<I::PacketRaw<_>>().unwrap(),
4846                    );
4847                    modify_packet(packet);
4848                }
4849            }
4850        }
4851
4852        let mut expected_payload_bytes = proto.make_ip_packet_with_ports_data::<I>(
4853            I::SRC_IP_2,
4854            I::DST_IP_2,
4855            SRC_PORT,
4856            DST_PORT,
4857            &[0xAB; LEN],
4858        );
4859
4860        if truncate_message {
4861            expected_payload_bytes.truncate(1280);
4862        }
4863
4864        let expected_serializer = IE::make_serializer(I::SRC_IP, I::DST_IP, expected_payload_bytes)
4865            // We never updated the outer IPs, so they should still be
4866            // their original values.
4867            .wrap_in(I::PacketBuilder::new(I::SRC_IP, I::DST_IP, u8::MAX, IE::proto()));
4868
4869        let expected_bytes =
4870            expected_serializer.serialize_vec_outer().unwrap().unwrap_b().into_inner();
4871
4872        assert_eq!(bytes, expected_bytes);
4873    }
4874
4875    #[ip_test(I)]
4876    #[test_case(PhantomData::<Udp>)]
4877    #[test_case(PhantomData::<Tcp>)]
4878    #[test_case(PhantomData::<IcmpEchoRequest>)]
4879    fn tx_packet_partial_serialize<I: TestIpExt, P: Protocol>(_proto: PhantomData<P>) {
4880        const DATA: &[u8] = b"Packet Body";
4881        let mut body =
4882            P::make_serializer_with_ports_data::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT, DATA);
4883        let packet = TxPacket::<I, _>::new(I::SRC_IP, I::DST_IP, P::proto::<I>(), &mut body);
4884
4885        let mut buf = [0u8; 128];
4886        let result = PartialSerializer::partial_serialize(
4887            &packet,
4888            PacketConstraints::UNCONSTRAINED,
4889            &mut buf,
4890        )
4891        .unwrap();
4892
4893        let whole_packet =
4894            P::make_serializer_with_ports_data::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT, DATA)
4895                .wrap_in(I::PacketBuilder::new(
4896                    I::SRC_IP,
4897                    I::DST_IP,
4898                    TX_PACKET_NO_TTL,
4899                    P::proto::<I>(),
4900                ))
4901                .serialize_vec_outer()
4902                .expect("serialize packet")
4903                .unwrap_b()
4904                .into_inner();
4905
4906        assert_eq!(result.total_size, whole_packet.len());
4907        assert_eq!(result.bytes_written, I::MIN_HEADER_LENGTH + P::HEADER_SIZE);
4908
4909        // Count the number of bytes that are different in the partially
4910        // serialized packet.
4911        let num_bytes_differ = buf[..result.bytes_written]
4912            .iter()
4913            .zip(whole_packet[..result.bytes_written].iter())
4914            .map(|(a, b)| if a != b { 1 } else { 0 })
4915            .sum::<usize>();
4916
4917        // Partial serializer doesn't calculate packet checksum. IPv6 header
4918        // doesn't contain a checksum, but IPv4 header and transport layer
4919        // headers contain 2 bytes for checksum each. Only these bytes may
4920        // differ from a fully-serialized packet.
4921        let checksum_bytes = I::map_ip((), |()| 4, |()| 2);
4922        assert!(num_bytes_differ <= checksum_bytes);
4923    }
4924
4925    #[ip_test(I)]
4926    #[test_case(PhantomData::<Udp>)]
4927    #[test_case(PhantomData::<Tcp>)]
4928    #[test_case(PhantomData::<IcmpEchoRequest>)]
4929    fn forwarded_packet_partial_serialize<I: TestIpExt, P: Protocol>(_proto: PhantomData<P>) {
4930        let mut packet_buf = ip_packet::<I, P>(I::SRC_IP, I::DST_IP);
4931        let packet_bytes = packet_buf.to_flattened_vec();
4932        let packet_len = packet_bytes.len();
4933        let meta = packet_buf.parse::<I::Packet<_>>().expect("parse IP packet").parse_metadata();
4934        let packet =
4935            ForwardedPacket::<I, _>::new(I::SRC_IP, I::DST_IP, P::proto::<I>(), meta, packet_buf);
4936
4937        for i in 1..(packet_len + 1) {
4938            let mut buf = alloc::vec![0u8; i];
4939            let result =
4940                packet.partial_serialize(PacketConstraints::UNCONSTRAINED, buf.as_mut_slice());
4941
4942            let bytes_written = if i >= packet_len { packet_len } else { i };
4943            assert_eq!(
4944                result,
4945                Ok(PartialSerializeResult { bytes_written, total_size: packet_len })
4946            );
4947            assert_eq!(buf[..bytes_written], packet_bytes[..bytes_written]);
4948        }
4949    }
4950}