Skip to main content

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