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    /// Whether this packet was reassembled from fragments.
1255    reassembled: bool,
1256}
1257
1258impl<I: IpExt, B: BufferMut> ForwardedPacket<I, B> {
1259    /// Create a new [`ForwardedPacket`] from its IP header fields and payload.
1260    ///
1261    /// `meta` is used to revert `buffer` back to the IP header for further
1262    /// serialization, and to mark where the transport header starts in
1263    /// `buffer`. It _must_ have originated from a previously parsed IP packet
1264    /// on `buffer`.
1265    pub fn new(
1266        src_addr: I::Addr,
1267        dst_addr: I::Addr,
1268        protocol: I::Proto,
1269        meta: ParseMetadata,
1270        mut buffer: B,
1271        reassembled: bool,
1272    ) -> Self {
1273        let transport_header_offset = meta.header_len();
1274        buffer.undo_parse(meta);
1275        Self { src_addr, dst_addr, protocol, transport_header_offset, buffer, reassembled }
1276    }
1277
1278    /// Returns whether this forwarded packet was reassembled from fragments.
1279    pub fn reassembled(&self) -> bool {
1280        self.reassembled
1281    }
1282
1283    /// Discard the metadata carried by the [`ForwardedPacket`] and return the
1284    /// inner buffer.
1285    ///
1286    /// The returned buffer 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 into_buffer(self) -> B {
1289        self.buffer
1290    }
1291
1292    /// Returns a reference to the forwarded buffer.
1293    ///
1294    /// The returned reference is guaranteed to contain a valid IP frame, the
1295    /// start of the buffer points at the start of the IP header.
1296    pub fn buffer(&self) -> &B {
1297        &self.buffer
1298    }
1299}
1300
1301impl<I: IpExt, B: BufferMut + NetworkSerializer> Serializer<NetworkSerializationContext>
1302    for ForwardedPacket<I, B>
1303{
1304    type Buffer = <B as Serializer<NetworkSerializationContext>>::Buffer;
1305
1306    fn serialize<G: packet::GrowBufferMut, P: packet::BufferProvider<Self::Buffer, G>>(
1307        self,
1308        context: &mut NetworkSerializationContext,
1309        constraints: packet::PacketConstraints,
1310        provider: P,
1311    ) -> Result<G, (packet::SerializeError<P::Error>, Self)> {
1312        let Self { src_addr, dst_addr, protocol, transport_header_offset, buffer, reassembled } =
1313            self;
1314        buffer.serialize(context, constraints, provider).map_err(|(err, buffer)| {
1315            (
1316                err,
1317                Self { src_addr, dst_addr, protocol, transport_header_offset, buffer, reassembled },
1318            )
1319        })
1320    }
1321
1322    fn serialize_new_buf<BB: GrowBufferMut, A: LayoutBufferAlloc<BB>>(
1323        &self,
1324        context: &mut NetworkSerializationContext,
1325        outer: packet::PacketConstraints,
1326        alloc: A,
1327    ) -> Result<BB, packet::SerializeError<A::Error>> {
1328        self.buffer.serialize_new_buf(context, outer, alloc)
1329    }
1330}
1331
1332impl<I: IpExt, B: BufferMut + NetworkSerializer> NestableSerializer for ForwardedPacket<I, B> {}
1333
1334impl<C: SerializationContext, I: IpExt, B: BufferMut> PartialSerializer<C>
1335    for ForwardedPacket<I, B>
1336{
1337    fn partial_serialize<BB: GrowBufferMut + ContiguousBuffer, A: LayoutBufferAlloc<BB>>(
1338        &self,
1339        _context: &mut C,
1340        _alloc: A,
1341    ) -> Result<PartialSerializeResult<'_, BB>, SerializeError<A::Error>> {
1342        Ok(PartialSerializeResult::Slice(self.buffer.as_ref()))
1343    }
1344
1345    fn partial_serialize_new_buf<BB: GrowBufferMut, A: LayoutBufferAlloc<BB>>(
1346        &self,
1347        _context: &mut C,
1348        constraints: PacketConstraints,
1349        alloc: A,
1350    ) -> Result<(BB, usize), SerializeError<A::Error>> {
1351        let bytes_to_copy = cmp::min(
1352            self.buffer.as_ref().len(),
1353            self.transport_header_offset + TRANSPORT_HEADER_MAX_SIZE,
1354        );
1355        let mut buffer = alloc.layout_alloc(constraints.header_len(), bytes_to_copy, 0)?;
1356        buffer.with_parts_mut(|_prefix, mut body, _suffix| {
1357            body.copy_from_slice(&self.buffer.as_ref()[..bytes_to_copy]);
1358        });
1359        Ok((buffer, self.buffer.as_ref().len()))
1360    }
1361}
1362
1363impl<I: FilterIpExt, B: BufferMut> IpPacket<I> for ForwardedPacket<I, B> {
1364    type TransportPacket<'a>
1365        = &'a Self
1366    where
1367        Self: 'a;
1368    type TransportPacketMut<'a>
1369        = Option<ParsedTransportHeaderMut<'a, I>>
1370    where
1371        Self: 'a;
1372    type IcmpError<'a>
1373        = &'a Self
1374    where
1375        Self: 'a;
1376
1377    type IcmpErrorMut<'a>
1378        = Option<ParsedIcmpErrorMut<'a, I>>
1379    where
1380        Self: 'a;
1381
1382    fn src_addr(&self) -> I::Addr {
1383        self.src_addr
1384    }
1385
1386    fn set_src_addr(&mut self, addr: I::Addr) {
1387        // Re-parse the IP header so we can modify it in place.
1388        I::map_ip::<_, ()>(
1389            (IpInvariant(self.buffer.as_mut()), addr),
1390            |(IpInvariant(buffer), addr)| {
1391                let mut packet = Ipv4PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
1392                    .expect("ForwardedPacket must have been created from a valid IP packet");
1393                packet.set_src_ip_and_update_checksum(addr);
1394            },
1395            |(IpInvariant(buffer), addr)| {
1396                let mut packet = Ipv6PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
1397                    .expect("ForwardedPacket must have been created from a valid IP packet");
1398                packet.set_src_ip(addr);
1399            },
1400        );
1401
1402        let old = self.src_addr;
1403        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
1404            packet.update_pseudo_header_src_addr(old, addr);
1405        }
1406
1407        self.src_addr = addr;
1408    }
1409
1410    fn dst_addr(&self) -> I::Addr {
1411        self.dst_addr
1412    }
1413
1414    fn set_dst_addr(&mut self, addr: I::Addr) {
1415        // Re-parse the IP header so we can modify it in place.
1416        I::map_ip::<_, ()>(
1417            (IpInvariant(self.buffer.as_mut()), addr),
1418            |(IpInvariant(buffer), addr)| {
1419                let mut packet = Ipv4PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
1420                    .expect("ForwardedPacket must have been created from a valid IP packet");
1421                packet.set_dst_ip_and_update_checksum(addr);
1422            },
1423            |(IpInvariant(buffer), addr)| {
1424                let mut packet = Ipv6PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
1425                    .expect("ForwardedPacket must have been created from a valid IP packet");
1426                packet.set_dst_ip(addr);
1427            },
1428        );
1429
1430        let old = self.dst_addr;
1431        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
1432            packet.update_pseudo_header_dst_addr(old, addr);
1433        }
1434
1435        self.dst_addr = addr;
1436    }
1437
1438    fn protocol(&self) -> Option<I::Proto> {
1439        Some(self.protocol)
1440    }
1441
1442    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
1443        self
1444    }
1445
1446    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
1447        let ForwardedPacket {
1448            src_addr: _,
1449            dst_addr: _,
1450            protocol,
1451            buffer,
1452            transport_header_offset,
1453            reassembled: _,
1454        } = self;
1455        ParsedTransportHeaderMut::<I>::parse_in_ip_packet(
1456            *protocol,
1457            SliceBufViewMut::new(&mut buffer.as_mut()[*transport_header_offset..]),
1458        )
1459    }
1460
1461    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
1462        self
1463    }
1464
1465    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
1466        let ForwardedPacket {
1467            src_addr,
1468            dst_addr,
1469            protocol,
1470            buffer,
1471            transport_header_offset,
1472            reassembled: _,
1473        } = self;
1474
1475        ParsedIcmpErrorMut::<I>::parse_in_ip_packet(
1476            *src_addr,
1477            *dst_addr,
1478            *protocol,
1479            SliceBufViewMut::new(&mut buffer.as_mut()[*transport_header_offset..]),
1480        )
1481    }
1482}
1483
1484impl<I: IpExt, B: BufferMut> MaybeTransportPacket for ForwardedPacket<I, B> {
1485    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1486        let ForwardedPacket {
1487            protocol,
1488            buffer,
1489            src_addr,
1490            dst_addr,
1491            transport_header_offset,
1492            reassembled: _,
1493        } = self;
1494        TransportPacketData::parse_in_ip_packet::<I, _>(
1495            *src_addr,
1496            *dst_addr,
1497            *protocol,
1498            Buf::new(&buffer.as_ref()[*transport_header_offset..], ..),
1499        )
1500    }
1501}
1502
1503impl<I: IpExt, B: BufferMut> MaybeIcmpErrorPayload<I> for ForwardedPacket<I, B> {
1504    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1505        let Self {
1506            src_addr: _,
1507            dst_addr: _,
1508            protocol,
1509            transport_header_offset,
1510            buffer,
1511            reassembled: _,
1512        } = self;
1513        ParsedIcmpErrorPayload::parse_in_outer_ip_packet(
1514            *protocol,
1515            Buf::new(&buffer.as_ref()[*transport_header_offset..], ..),
1516        )
1517    }
1518}
1519
1520impl<
1521    I: FilterIpExt,
1522    S: TransportPacketSerializer<I>,
1523    B: IpPacketBuilder<NetworkSerializationContext, I>,
1524> IpPacket<I> for Nested<S, B>
1525{
1526    type TransportPacket<'a>
1527        = &'a S
1528    where
1529        Self: 'a;
1530    type TransportPacketMut<'a>
1531        = &'a mut S
1532    where
1533        Self: 'a;
1534    type IcmpError<'a>
1535        = &'a S
1536    where
1537        Self: 'a;
1538    type IcmpErrorMut<'a>
1539        = &'a mut S
1540    where
1541        Self: 'a;
1542
1543    fn src_addr(&self) -> I::Addr {
1544        self.outer().src_ip()
1545    }
1546
1547    fn set_src_addr(&mut self, addr: I::Addr) {
1548        let old = self.outer().src_ip();
1549        self.outer_mut().set_src_ip(addr);
1550        if let Some(mut packet) = self.transport_packet_mut().transport_packet_mut() {
1551            packet.update_pseudo_header_src_addr(old, addr);
1552        }
1553    }
1554
1555    fn dst_addr(&self) -> I::Addr {
1556        self.outer().dst_ip()
1557    }
1558
1559    fn set_dst_addr(&mut self, addr: I::Addr) {
1560        let old = self.outer().dst_ip();
1561        self.outer_mut().set_dst_ip(addr);
1562        if let Some(mut packet) = self.transport_packet_mut().transport_packet_mut() {
1563            packet.update_pseudo_header_dst_addr(old, addr);
1564        }
1565    }
1566
1567    fn protocol(&self) -> Option<I::Proto> {
1568        Some(self.outer().proto())
1569    }
1570
1571    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
1572        self.inner()
1573    }
1574
1575    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
1576        self.inner_mut()
1577    }
1578
1579    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
1580        self.inner()
1581    }
1582
1583    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
1584        self.inner_mut()
1585    }
1586}
1587
1588impl<I: IpExt, T: ?Sized> TransportPacketMut<I> for &mut T
1589where
1590    T: TransportPacketMut<I>,
1591{
1592    fn set_src_port(&mut self, port: NonZeroU16) {
1593        (*self).set_src_port(port);
1594    }
1595
1596    fn set_dst_port(&mut self, port: NonZeroU16) {
1597        (*self).set_dst_port(port);
1598    }
1599
1600    fn update_pseudo_header_src_addr(&mut self, old: I::Addr, new: I::Addr) {
1601        (*self).update_pseudo_header_src_addr(old, new);
1602    }
1603
1604    fn update_pseudo_header_dst_addr(&mut self, old: I::Addr, new: I::Addr) {
1605        (*self).update_pseudo_header_dst_addr(old, new);
1606    }
1607}
1608
1609impl<I: FilterIpExt> IpPacket<I> for Never {
1610    type TransportPacket<'a>
1611        = Never
1612    where
1613        Self: 'a;
1614    type TransportPacketMut<'a>
1615        = Never
1616    where
1617        Self: 'a;
1618    type IcmpError<'a>
1619        = Never
1620    where
1621        Self: 'a;
1622    type IcmpErrorMut<'a>
1623        = Never
1624    where
1625        Self: 'a;
1626
1627    fn src_addr(&self) -> I::Addr {
1628        match *self {}
1629    }
1630
1631    fn set_src_addr(&mut self, _addr: I::Addr) {
1632        match *self {}
1633    }
1634
1635    fn dst_addr(&self) -> I::Addr {
1636        match *self {}
1637    }
1638
1639    fn protocol(&self) -> Option<I::Proto> {
1640        match *self {}
1641    }
1642
1643    fn set_dst_addr(&mut self, _addr: I::Addr) {
1644        match *self {}
1645    }
1646
1647    fn maybe_transport_packet<'a>(&'a self) -> Self::TransportPacket<'a> {
1648        match *self {}
1649    }
1650
1651    fn transport_packet_mut<'a>(&'a mut self) -> Self::TransportPacketMut<'a> {
1652        match *self {}
1653    }
1654
1655    fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
1656        match *self {}
1657    }
1658
1659    fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
1660        match *self {}
1661    }
1662}
1663
1664impl MaybeTransportPacket for Never {
1665    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1666        match *self {}
1667    }
1668}
1669
1670impl<I: IpExt> MaybeTransportPacketMut<I> for Never {
1671    type TransportPacketMut<'a>
1672        = Never
1673    where
1674        Self: 'a;
1675
1676    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1677        match *self {}
1678    }
1679}
1680
1681impl<I: IpExt> TransportPacketMut<I> for Never {
1682    fn set_src_port(&mut self, _: NonZeroU16) {
1683        match *self {}
1684    }
1685
1686    fn set_dst_port(&mut self, _: NonZeroU16) {
1687        match *self {}
1688    }
1689
1690    fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {
1691        match *self {}
1692    }
1693
1694    fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {
1695        match *self {}
1696    }
1697}
1698
1699impl<I: IpExt> MaybeIcmpErrorPayload<I> for Never {
1700    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1701        match *self {}
1702    }
1703}
1704
1705impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for Never {
1706    type IcmpErrorMut<'a>
1707        = Never
1708    where
1709        Self: 'a;
1710
1711    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
1712        match *self {}
1713    }
1714}
1715
1716impl<I: FilterIpExt> IcmpErrorMut<I> for Never {
1717    type InnerPacket<'a>
1718        = Never
1719    where
1720        Self: 'a;
1721
1722    fn inner_packet<'a>(&'a mut self) -> Option<Self::InnerPacket<'a>> {
1723        match *self {}
1724    }
1725
1726    fn recalculate_checksum(&mut self) -> bool {
1727        match *self {}
1728    }
1729}
1730
1731impl<A: IpAddress, Inner> MaybeTransportPacket for Nested<Inner, UdpPacketBuilder<A>> {
1732    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1733        Some(TransportPacketData::Generic {
1734            src_port: self.outer().src_port().map_or(0, NonZeroU16::get),
1735            dst_port: self.outer().dst_port().map_or(0, NonZeroU16::get),
1736        })
1737    }
1738}
1739
1740impl<I: IpExt, Inner> MaybeTransportPacketMut<I> for Nested<Inner, UdpPacketBuilder<I::Addr>> {
1741    type TransportPacketMut<'a>
1742        = &'a mut Self
1743    where
1744        Self: 'a;
1745
1746    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1747        Some(self)
1748    }
1749}
1750
1751impl<I: IpExt, Inner> TransportPacketMut<I> for Nested<Inner, UdpPacketBuilder<I::Addr>> {
1752    fn set_src_port(&mut self, port: NonZeroU16) {
1753        self.outer_mut().set_src_port(port.get());
1754    }
1755
1756    fn set_dst_port(&mut self, port: NonZeroU16) {
1757        self.outer_mut().set_dst_port(port);
1758    }
1759
1760    fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
1761        self.outer_mut().set_src_ip(new);
1762    }
1763
1764    fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
1765        self.outer_mut().set_dst_ip(new);
1766    }
1767}
1768
1769impl<A: IpAddress, I: IpExt, Inner> MaybeIcmpErrorPayload<I>
1770    for Nested<Inner, UdpPacketBuilder<A>>
1771{
1772    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1773        None
1774    }
1775}
1776
1777impl<A: IpAddress, I: FilterIpExt, Inner> MaybeIcmpErrorMut<I>
1778    for Nested<Inner, UdpPacketBuilder<A>>
1779{
1780    type IcmpErrorMut<'a>
1781        = Never
1782    where
1783        Self: 'a;
1784
1785    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
1786        None
1787    }
1788}
1789
1790impl<'a, A: IpAddress, Inner: PayloadLen> MaybeTransportPacket
1791    for Nested<Inner, TcpSegmentBuilderWithOptions<A, TcpOptionsBuilder<'a>>>
1792{
1793    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1794        Some(TransportPacketData::Tcp {
1795            src_port: self.outer().src_port().map_or(0, NonZeroU16::get),
1796            dst_port: self.outer().dst_port().map_or(0, NonZeroU16::get),
1797            segment: self.outer().try_into().ok()?,
1798            payload_len: self.inner().len(),
1799        })
1800    }
1801}
1802
1803impl<I: IpExt, Outer, Inner> MaybeTransportPacketMut<I>
1804    for Nested<Inner, TcpSegmentBuilderWithOptions<I::Addr, Outer>>
1805{
1806    type TransportPacketMut<'a>
1807        = &'a mut Self
1808    where
1809        Self: 'a;
1810
1811    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1812        Some(self)
1813    }
1814}
1815
1816impl<I: IpExt, Outer, Inner> TransportPacketMut<I>
1817    for Nested<Inner, TcpSegmentBuilderWithOptions<I::Addr, Outer>>
1818{
1819    fn set_src_port(&mut self, port: NonZeroU16) {
1820        self.outer_mut().set_src_port(port);
1821    }
1822
1823    fn set_dst_port(&mut self, port: NonZeroU16) {
1824        self.outer_mut().set_dst_port(port);
1825    }
1826
1827    fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
1828        self.outer_mut().set_src_ip(new);
1829    }
1830
1831    fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
1832        self.outer_mut().set_dst_ip(new);
1833    }
1834}
1835
1836impl<A: IpAddress, I: IpExt, Inner, O> MaybeIcmpErrorPayload<I>
1837    for Nested<Inner, TcpSegmentBuilderWithOptions<A, O>>
1838{
1839    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1840        None
1841    }
1842}
1843
1844impl<A: IpAddress, I: FilterIpExt, Inner, O> MaybeIcmpErrorMut<I>
1845    for Nested<Inner, TcpSegmentBuilderWithOptions<A, O>>
1846{
1847    type IcmpErrorMut<'a>
1848        = Never
1849    where
1850        Self: 'a;
1851
1852    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
1853        None
1854    }
1855}
1856
1857impl<I: IpExt, Inner, M: IcmpMessage<I>> MaybeTransportPacket
1858    for Nested<Inner, IcmpPacketBuilder<I, M>>
1859{
1860    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1861        self.outer().message().transport_packet_data()
1862    }
1863}
1864
1865impl<I: IpExt, Inner, M: IcmpMessage<I>> MaybeTransportPacketMut<I>
1866    for Nested<Inner, IcmpPacketBuilder<I, M>>
1867{
1868    type TransportPacketMut<'a>
1869        = &'a mut IcmpPacketBuilder<I, M>
1870    where
1871        M: 'a,
1872        Inner: 'a;
1873
1874    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1875        Some(self.outer_mut())
1876    }
1877}
1878
1879impl<I: IpExt, Inner, M: IcmpMessage<I>> DynamicMaybeTransportPacketMut<I>
1880    for Nested<Inner, IcmpPacketBuilder<I, M>>
1881{
1882    fn dyn_transport_packet_mut(&mut self) -> Option<&mut dyn TransportPacketMut<I>> {
1883        MaybeTransportPacketMut::transport_packet_mut(self).map(|x| x as _)
1884    }
1885}
1886
1887impl<I: IpExt, M: IcmpMessage<I>> TransportPacketMut<I> for IcmpPacketBuilder<I, M> {
1888    fn set_src_port(&mut self, id: NonZeroU16) {
1889        if M::IS_REWRITABLE {
1890            let _: u16 = self.message_mut().update_icmp_id(id.get());
1891        }
1892    }
1893
1894    fn set_dst_port(&mut self, id: NonZeroU16) {
1895        if M::IS_REWRITABLE {
1896            let _: u16 = self.message_mut().update_icmp_id(id.get());
1897        }
1898    }
1899
1900    fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
1901        self.set_src_ip(new);
1902    }
1903
1904    fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
1905        self.set_dst_ip(new);
1906    }
1907}
1908
1909impl<Inner, I: IpExt> MaybeIcmpErrorPayload<I>
1910    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoRequest>>
1911{
1912    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1913        None
1914    }
1915}
1916
1917impl<Inner, I: FilterIpExt> MaybeIcmpErrorMut<I>
1918    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoRequest>>
1919{
1920    type IcmpErrorMut<'a>
1921        = Never
1922    where
1923        Self: 'a;
1924
1925    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
1926        None
1927    }
1928}
1929
1930impl<Inner, I: FilterIpExt> DynamicMaybeIcmpErrorMut<I>
1931    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoRequest>>
1932{
1933    fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<I>> {
1934        MaybeIcmpErrorMut::<I>::icmp_error_mut(self).map(|x| match x {})
1935    }
1936}
1937
1938impl<Inner, I: IpExt> MaybeIcmpErrorPayload<I>
1939    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoReply>>
1940{
1941    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
1942        None
1943    }
1944}
1945
1946impl<Inner, I: FilterIpExt> MaybeIcmpErrorMut<I>
1947    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoReply>>
1948{
1949    type IcmpErrorMut<'a>
1950        = Never
1951    where
1952        Self: 'a;
1953
1954    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
1955        None
1956    }
1957}
1958
1959impl<Inner, I: FilterIpExt> DynamicMaybeIcmpErrorMut<I>
1960    for Nested<Inner, IcmpPacketBuilder<I, IcmpEchoReply>>
1961{
1962    fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<I>> {
1963        MaybeIcmpErrorMut::<I>::icmp_error_mut(self).map(|x| match x {})
1964    }
1965}
1966
1967/// An ICMP message type that may allow for transport-layer packet inspection.
1968pub trait IcmpMessage<I: IpExt>: icmp::IcmpMessage<I> + MaybeTransportPacket {
1969    /// Whether this ICMP message supports rewriting the ID.
1970    const IS_REWRITABLE: bool;
1971
1972    /// The same as [`IcmpMessage::IS_REWRITABLE`], but for when you have an
1973    /// object, rather than a type.
1974    fn is_rewritable(&self) -> bool {
1975        Self::IS_REWRITABLE
1976    }
1977
1978    /// Sets the ICMP ID for the message, returning the previous value.
1979    ///
1980    /// The ICMP ID is both the *src* AND *dst* ports for conntrack entries.
1981    fn update_icmp_id(&mut self, id: u16) -> u16;
1982}
1983
1984// TODO(https://fxbug.dev/341128580): connection tracking will probably want to
1985// special case ICMP echo packets to ensure that a new connection is only ever
1986// created from an echo request, and not an echo response. We need to provide a
1987// way for conntrack to differentiate between the two.
1988impl MaybeTransportPacket for IcmpEchoReply {
1989    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1990        Some(TransportPacketData::Generic { src_port: self.id(), dst_port: self.id() })
1991    }
1992}
1993
1994impl<I: IpExt> IcmpMessage<I> for IcmpEchoReply {
1995    const IS_REWRITABLE: bool = true;
1996
1997    fn update_icmp_id(&mut self, id: u16) -> u16 {
1998        let old = self.id();
1999        self.set_id(id);
2000        old
2001    }
2002}
2003
2004// TODO(https://fxbug.dev/341128580): connection tracking will probably want to
2005// special case ICMP echo packets to ensure that a new connection is only ever
2006// created from an echo request, and not an echo response. We need to provide a
2007// way for conntrack to differentiate between the two.
2008impl MaybeTransportPacket for IcmpEchoRequest {
2009    fn transport_packet_data(&self) -> Option<TransportPacketData> {
2010        Some(TransportPacketData::Generic { src_port: self.id(), dst_port: self.id() })
2011    }
2012}
2013
2014impl<I: IpExt> IcmpMessage<I> for IcmpEchoRequest {
2015    const IS_REWRITABLE: bool = true;
2016
2017    fn update_icmp_id(&mut self, id: u16) -> u16 {
2018        let old = self.id();
2019        self.set_id(id);
2020        old
2021    }
2022}
2023
2024macro_rules! unsupported_icmp_message_type {
2025    ($message:ty, $($ips:ty),+) => {
2026        impl MaybeTransportPacket for $message {
2027            fn transport_packet_data(&self) -> Option<TransportPacketData> {
2028                None
2029            }
2030        }
2031
2032        $(
2033            impl IcmpMessage<$ips> for $message {
2034                const IS_REWRITABLE: bool = false;
2035
2036                fn update_icmp_id(&mut self, _: u16) -> u16 {
2037                    unreachable!("non-echo ICMP packets should never be rewritten")
2038                }
2039            }
2040        )+
2041    };
2042}
2043
2044unsupported_icmp_message_type!(Icmpv4TimestampRequest, Ipv4);
2045unsupported_icmp_message_type!(Icmpv4TimestampReply, Ipv4);
2046unsupported_icmp_message_type!(NeighborSolicitation, Ipv6);
2047unsupported_icmp_message_type!(NeighborAdvertisement, Ipv6);
2048unsupported_icmp_message_type!(RouterSolicitation, Ipv6);
2049unsupported_icmp_message_type!(MulticastListenerDone, Ipv6);
2050unsupported_icmp_message_type!(MulticastListenerReport, Ipv6);
2051unsupported_icmp_message_type!(MulticastListenerReportV2, Ipv6);
2052unsupported_icmp_message_type!(MulticastListenerQuery, Ipv6);
2053unsupported_icmp_message_type!(MulticastListenerQueryV2, Ipv6);
2054unsupported_icmp_message_type!(RouterAdvertisement, Ipv6);
2055// This isn't considered an error because, unlike ICMPv4, an ICMPv6 Redirect
2056// message doesn't contain an IP packet payload (RFC 2461 Section 4.5).
2057unsupported_icmp_message_type!(Redirect, Ipv6);
2058
2059/// Implement For ICMP message that aren't errors.
2060macro_rules! non_error_icmp_message_type {
2061    ($message:ty, $ip:ty) => {
2062        impl<Inner> MaybeIcmpErrorPayload<$ip> for Nested<Inner, IcmpPacketBuilder<$ip, $message>> {
2063            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<$ip>> {
2064                None
2065            }
2066        }
2067
2068        impl<Inner> MaybeIcmpErrorMut<$ip> for Nested<Inner, IcmpPacketBuilder<$ip, $message>> {
2069            type IcmpErrorMut<'a>
2070                = Never
2071            where
2072                Self: 'a;
2073
2074            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2075                None
2076            }
2077        }
2078
2079        impl<Inner> DynamicMaybeIcmpErrorMut<$ip>
2080            for Nested<Inner, IcmpPacketBuilder<$ip, $message>>
2081        {
2082            fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<$ip>> {
2083                MaybeIcmpErrorMut::icmp_error_mut(self).map(|x| match x {})
2084            }
2085        }
2086    };
2087}
2088
2089non_error_icmp_message_type!(Icmpv4TimestampRequest, Ipv4);
2090non_error_icmp_message_type!(Icmpv4TimestampReply, Ipv4);
2091non_error_icmp_message_type!(RouterSolicitation, Ipv6);
2092non_error_icmp_message_type!(RouterAdvertisement, Ipv6);
2093non_error_icmp_message_type!(NeighborSolicitation, Ipv6);
2094non_error_icmp_message_type!(NeighborAdvertisement, Ipv6);
2095non_error_icmp_message_type!(MulticastListenerReport, Ipv6);
2096non_error_icmp_message_type!(MulticastListenerDone, Ipv6);
2097non_error_icmp_message_type!(MulticastListenerReportV2, Ipv6);
2098
2099macro_rules! icmp_error_message {
2100    ($message:ty, $($ips:ty),+) => {
2101        impl MaybeTransportPacket for $message {
2102            fn transport_packet_data(&self) -> Option<TransportPacketData> {
2103                None
2104            }
2105        }
2106
2107        $(
2108            impl IcmpMessage<$ips> for $message {
2109                const IS_REWRITABLE: bool = false;
2110
2111                fn update_icmp_id(&mut self, _: u16) -> u16 {
2112                    unreachable!("non-echo ICMP packets should never be rewritten")
2113                }
2114            }
2115        )+
2116    };
2117}
2118
2119icmp_error_message!(IcmpDestUnreachable, Ipv4, Ipv6);
2120icmp_error_message!(IcmpTimeExceeded, Ipv4, Ipv6);
2121icmp_error_message!(Icmpv4ParameterProblem, Ipv4);
2122icmp_error_message!(Icmpv4Redirect, Ipv4);
2123icmp_error_message!(Icmpv6ParameterProblem, Ipv6);
2124icmp_error_message!(Icmpv6PacketTooBig, Ipv6);
2125
2126macro_rules! icmpv4_error_message {
2127    ($message: ty) => {
2128        impl<Inner: AsRef<[u8]>> MaybeIcmpErrorPayload<Ipv4>
2129            for Nested<Inner, IcmpPacketBuilder<Ipv4, $message>>
2130        {
2131            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<Ipv4>> {
2132                ParsedIcmpErrorPayload::parse_in_icmpv4_error(Buf::new(self.inner(), ..))
2133            }
2134        }
2135
2136        impl<Inner: BufferMut> MaybeIcmpErrorMut<Ipv4>
2137            for Nested<Inner, IcmpPacketBuilder<Ipv4, $message>>
2138        {
2139            type IcmpErrorMut<'a>
2140                = &'a mut Self
2141            where
2142                Self: 'a;
2143
2144            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2145                Some(self)
2146            }
2147        }
2148
2149        impl<Inner: BufferMut> DynamicMaybeIcmpErrorMut<Ipv4>
2150            for Nested<Inner, IcmpPacketBuilder<Ipv4, $message>>
2151        {
2152            fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<Ipv4>> {
2153                MaybeIcmpErrorMut::icmp_error_mut(self).map(|x| x as _)
2154            }
2155        }
2156
2157        impl<Inner: BufferMut> IcmpErrorMut<Ipv4>
2158            for Nested<Inner, IcmpPacketBuilder<Ipv4, $message>>
2159        {
2160            type InnerPacket<'a>
2161                = Ipv4PacketRaw<&'a mut [u8]>
2162            where
2163                Self: 'a;
2164
2165            fn recalculate_checksum(&mut self) -> bool {
2166                // Checksum is calculated during serialization.
2167                true
2168            }
2169
2170            fn inner_packet<'a>(&'a mut self) -> Option<Self::InnerPacket<'a>> {
2171                let packet =
2172                    Ipv4PacketRaw::parse_mut(SliceBufViewMut::new(self.inner_mut().as_mut()), ())
2173                        .ok()?;
2174
2175                Some(packet)
2176            }
2177        }
2178
2179        impl<Inner: BufferMut> DynamicIcmpErrorMut<Ipv4>
2180            for Nested<Inner, IcmpPacketBuilder<Ipv4, $message>>
2181        {
2182            fn dyn_recalculate_checksum(&mut self) -> bool {
2183                self.recalculate_checksum()
2184            }
2185
2186            fn dyn_inner_packet(&mut self) -> Option<Ipv4PacketRaw<&mut [u8]>> {
2187                self.inner_packet()
2188            }
2189        }
2190    };
2191}
2192
2193icmpv4_error_message!(IcmpDestUnreachable);
2194icmpv4_error_message!(Icmpv4Redirect);
2195icmpv4_error_message!(IcmpTimeExceeded);
2196icmpv4_error_message!(Icmpv4ParameterProblem);
2197
2198macro_rules! icmpv6_error_message {
2199    ($message: ty) => {
2200        impl<Inner: Buffer> MaybeIcmpErrorPayload<Ipv6>
2201            for Nested<TruncatingSerializer<Inner>, IcmpPacketBuilder<Ipv6, $message>>
2202        {
2203            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<Ipv6>> {
2204                ParsedIcmpErrorPayload::parse_in_icmpv6_error(Buf::new(self.inner().buffer(), ..))
2205            }
2206        }
2207
2208        impl<Inner: BufferMut> MaybeIcmpErrorMut<Ipv6>
2209            for Nested<TruncatingSerializer<Inner>, IcmpPacketBuilder<Ipv6, $message>>
2210        {
2211            type IcmpErrorMut<'a>
2212                = &'a mut Self
2213            where
2214                Self: 'a;
2215
2216            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2217                Some(self)
2218            }
2219        }
2220
2221        impl<Inner: BufferMut> DynamicMaybeIcmpErrorMut<Ipv6>
2222            for Nested<TruncatingSerializer<Inner>, IcmpPacketBuilder<Ipv6, $message>>
2223        {
2224            fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<Ipv6>> {
2225                MaybeIcmpErrorMut::icmp_error_mut(self).map(|x| x as _)
2226            }
2227        }
2228
2229        impl<Inner: BufferMut> IcmpErrorMut<Ipv6>
2230            for Nested<TruncatingSerializer<Inner>, IcmpPacketBuilder<Ipv6, $message>>
2231        {
2232            type InnerPacket<'a>
2233                = Ipv6PacketRaw<&'a mut [u8]>
2234            where
2235                Self: 'a;
2236
2237            fn recalculate_checksum(&mut self) -> bool {
2238                // Checksum is calculated during serialization.
2239                true
2240            }
2241
2242            fn inner_packet<'a>(&'a mut self) -> Option<Self::InnerPacket<'a>> {
2243                let packet = Ipv6PacketRaw::parse_mut(
2244                    SliceBufViewMut::new(self.inner_mut().buffer_mut().as_mut()),
2245                    (),
2246                )
2247                .ok()?;
2248
2249                Some(packet)
2250            }
2251        }
2252
2253        impl<Inner: BufferMut> DynamicIcmpErrorMut<Ipv6>
2254            for Nested<TruncatingSerializer<Inner>, IcmpPacketBuilder<Ipv6, $message>>
2255        {
2256            fn dyn_recalculate_checksum(&mut self) -> bool {
2257                self.recalculate_checksum()
2258            }
2259
2260            fn dyn_inner_packet(&mut self) -> Option<Ipv6PacketRaw<&mut [u8]>> {
2261                self.inner_packet()
2262            }
2263        }
2264    };
2265}
2266
2267icmpv6_error_message!(IcmpDestUnreachable);
2268icmpv6_error_message!(Icmpv6PacketTooBig);
2269icmpv6_error_message!(IcmpTimeExceeded);
2270icmpv6_error_message!(Icmpv6ParameterProblem);
2271
2272impl<M: igmp::MessageType<EmptyBuf>> MaybeIcmpErrorMut<Ipv4>
2273    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2274{
2275    type IcmpErrorMut<'a>
2276        = Never
2277    where
2278        Self: 'a;
2279
2280    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2281        None
2282    }
2283}
2284
2285impl<M: igmp::MessageType<EmptyBuf>> DynamicMaybeIcmpErrorMut<Ipv4>
2286    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2287{
2288    fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<Ipv4>> {
2289        self.icmp_error_mut().map(|x| match x {})
2290    }
2291}
2292
2293impl<M: igmp::MessageType<EmptyBuf>> MaybeTransportPacket
2294    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2295{
2296    fn transport_packet_data(&self) -> Option<TransportPacketData> {
2297        None
2298    }
2299}
2300
2301impl<M: igmp::MessageType<EmptyBuf>> DynamicMaybeTransportPacketMut<Ipv4>
2302    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2303{
2304    fn dyn_transport_packet_mut(&mut self) -> Option<&mut dyn TransportPacketMut<Ipv4>> {
2305        self.transport_packet_mut().map(|x| match x {})
2306    }
2307}
2308
2309impl<M: igmp::MessageType<EmptyBuf>> MaybeTransportPacketMut<Ipv4>
2310    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2311{
2312    type TransportPacketMut<'a>
2313        = Never
2314    where
2315        M: 'a;
2316
2317    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
2318        None
2319    }
2320}
2321
2322impl<I: IpExt, M: igmp::MessageType<EmptyBuf>> MaybeIcmpErrorPayload<I>
2323    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
2324{
2325    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
2326        None
2327    }
2328}
2329
2330impl<I> MaybeTransportPacket for InnerSerializer<IgmpMembershipReportV3Builder<I>, EmptyBuf> {
2331    fn transport_packet_data(&self) -> Option<TransportPacketData> {
2332        None
2333    }
2334}
2335
2336impl<I> MaybeTransportPacketMut<Ipv4>
2337    for InnerSerializer<IgmpMembershipReportV3Builder<I>, EmptyBuf>
2338{
2339    type TransportPacketMut<'a>
2340        = Never
2341    where
2342        I: 'a;
2343
2344    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
2345        None
2346    }
2347}
2348
2349impl<I> DynamicMaybeTransportPacketMut<Ipv4>
2350    for InnerSerializer<IgmpMembershipReportV3Builder<I>, EmptyBuf>
2351{
2352    fn dyn_transport_packet_mut(&mut self) -> Option<&mut dyn TransportPacketMut<Ipv4>> {
2353        self.transport_packet_mut().map(|x| match x {})
2354    }
2355}
2356
2357impl<I: IpExt, II, B> MaybeIcmpErrorPayload<I>
2358    for InnerSerializer<IgmpMembershipReportV3Builder<II>, B>
2359{
2360    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
2361        None
2362    }
2363}
2364
2365impl<I, B> MaybeIcmpErrorMut<Ipv4> for InnerSerializer<IgmpMembershipReportV3Builder<I>, B> {
2366    type IcmpErrorMut<'a>
2367        = Never
2368    where
2369        Self: 'a;
2370
2371    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2372        None
2373    }
2374}
2375
2376impl<I, B> DynamicMaybeIcmpErrorMut<Ipv4> for InnerSerializer<IgmpMembershipReportV3Builder<I>, B> {
2377    fn dyn_icmp_error_mut(&mut self) -> Option<&mut dyn DynamicIcmpErrorMut<Ipv4>> {
2378        self.icmp_error_mut().map(|x| match x {})
2379    }
2380}
2381
2382impl<I> MaybeTransportPacket
2383    for EitherSerializer<
2384        EmptyBuf,
2385        InnerSerializer<packet::records::RecordSequenceBuilder<NdpOptionBuilder<'_>, I>, EmptyBuf>,
2386    >
2387{
2388    fn transport_packet_data(&self) -> Option<TransportPacketData> {
2389        None
2390    }
2391}
2392
2393/// An unsanitized IP packet body.
2394///
2395/// Allows packets from raw IP sockets (with a user provided IP body), to be
2396/// tracked from the filtering module.
2397#[derive(GenericOverIp)]
2398#[generic_over_ip(I, Ip)]
2399pub struct RawIpBody<I: IpExt, B: ParseBuffer> {
2400    /// The IANA protocol of the inner message. This may be, but is not required
2401    /// to be, a transport protocol.
2402    protocol: I::Proto,
2403    /// The source IP addr of the packet. Required by
2404    /// [`ParsedTransportHeaderMut`] to recompute checksums.
2405    src_addr: I::Addr,
2406    /// The destination IP addr of the packet. Required by
2407    /// [`ParsedTransportHeaderMut`] to recompute checksums.
2408    dst_addr: I::Addr,
2409    /// The body of the IP packet. The body is expected to be a message of type
2410    /// `protocol`, but is not guaranteed to be valid.
2411    body: B,
2412    /// The parsed transport data contained within `body`. Only `Some` if body
2413    /// is a valid transport header.
2414    transport_packet_data: Option<TransportPacketData>,
2415}
2416
2417impl<I: IpExt, B: ParseBuffer> RawIpBody<I, B> {
2418    /// Construct a new [`RawIpBody`] from it's parts.
2419    pub fn new(
2420        protocol: I::Proto,
2421        src_addr: I::Addr,
2422        dst_addr: I::Addr,
2423        body: B,
2424    ) -> RawIpBody<I, B> {
2425        let transport_packet_data = TransportPacketData::parse_in_ip_packet::<I, _>(
2426            src_addr,
2427            dst_addr,
2428            protocol,
2429            Buf::new(&body, ..),
2430        );
2431        RawIpBody { protocol, src_addr, dst_addr, body, transport_packet_data }
2432    }
2433}
2434
2435impl<I: IpExt, B: ParseBuffer> MaybeTransportPacket for RawIpBody<I, B> {
2436    fn transport_packet_data(&self) -> Option<TransportPacketData> {
2437        self.transport_packet_data.clone()
2438    }
2439}
2440
2441impl<I: IpExt, B: BufferMut> MaybeTransportPacketMut<I> for RawIpBody<I, B> {
2442    type TransportPacketMut<'a>
2443        = ParsedTransportHeaderMut<'a, I>
2444    where
2445        Self: 'a;
2446
2447    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
2448        let RawIpBody { protocol, src_addr: _, dst_addr: _, body, transport_packet_data: _ } = self;
2449        ParsedTransportHeaderMut::<I>::parse_in_ip_packet(
2450            *protocol,
2451            SliceBufViewMut::new(body.as_mut()),
2452        )
2453    }
2454}
2455
2456impl<I: IpExt, B: ParseBuffer> MaybeIcmpErrorPayload<I> for RawIpBody<I, B> {
2457    fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
2458        ParsedIcmpErrorPayload::parse_in_outer_ip_packet(self.protocol, Buf::new(&self.body, ..))
2459    }
2460}
2461
2462impl<I: FilterIpExt, B: BufferMut> MaybeIcmpErrorMut<I> for RawIpBody<I, B> {
2463    type IcmpErrorMut<'a>
2464        = ParsedIcmpErrorMut<'a, I>
2465    where
2466        Self: 'a;
2467
2468    fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
2469        let RawIpBody { protocol, src_addr, dst_addr, body, transport_packet_data: _ } = self;
2470
2471        ParsedIcmpErrorMut::parse_in_ip_packet(
2472            *src_addr,
2473            *dst_addr,
2474            *protocol,
2475            SliceBufViewMut::new(body.as_mut()),
2476        )
2477    }
2478}
2479
2480impl<I: IpExt, B: BufferMut + NetworkSerializer> Serializer<NetworkSerializationContext>
2481    for RawIpBody<I, B>
2482{
2483    type Buffer = <B as Serializer<NetworkSerializationContext>>::Buffer;
2484
2485    fn serialize<G: GrowBufferMut, P: BufferProvider<Self::Buffer, G>>(
2486        self,
2487        context: &mut NetworkSerializationContext,
2488        constraints: PacketConstraints,
2489        provider: P,
2490    ) -> Result<G, (SerializeError<P::Error>, Self)> {
2491        let Self { protocol, src_addr, dst_addr, body, transport_packet_data } = self;
2492        body.serialize(context, constraints, provider).map_err(|(err, body)| {
2493            (err, Self { protocol, src_addr, dst_addr, body, transport_packet_data })
2494        })
2495    }
2496
2497    fn serialize_new_buf<BB: GrowBufferMut, A: LayoutBufferAlloc<BB>>(
2498        &self,
2499        context: &mut NetworkSerializationContext,
2500        outer: PacketConstraints,
2501        alloc: A,
2502    ) -> Result<BB, SerializeError<A::Error>> {
2503        self.body.serialize_new_buf(context, outer, alloc)
2504    }
2505}
2506
2507impl<I: IpExt, B: BufferMut + NetworkSerializer> NestableSerializer for RawIpBody<I, B> {}
2508
2509impl<I: IpExt, B: BufferMut> PartialSerializer<NetworkSerializationContext> for RawIpBody<I, B> {
2510    fn partial_serialize<BB: GrowBufferMut + ContiguousBuffer, A: LayoutBufferAlloc<BB>>(
2511        &self,
2512        _context: &mut NetworkSerializationContext,
2513        _alloc: A,
2514    ) -> Result<PartialSerializeResult<'_, BB>, SerializeError<A::Error>> {
2515        Ok(PartialSerializeResult::Slice(self.body.as_ref()))
2516    }
2517
2518    fn partial_serialize_new_buf<BB: GrowBufferMut, A: LayoutBufferAlloc<BB>>(
2519        &self,
2520        _context: &mut NetworkSerializationContext,
2521        constraints: PacketConstraints,
2522        alloc: A,
2523    ) -> Result<(BB, usize), SerializeError<A::Error>> {
2524        let bytes_to_copy = cmp::min(self.body.len(), TRANSPORT_HEADER_MAX_SIZE);
2525        let header_len = constraints.header_len();
2526        let mut buffer = alloc.layout_alloc(header_len, bytes_to_copy, 0)?;
2527        buffer.with_parts_mut(|_prefix, mut body, _suffix| {
2528            body.copy_from_slice(&self.body.as_ref()[..bytes_to_copy]);
2529        });
2530        let total_size = cmp::max(
2531            constraints.min_body_len(),
2532            cmp::min(self.body.len(), constraints.max_body_len()),
2533        );
2534        Ok((buffer, total_size))
2535    }
2536}
2537
2538fn parse_transport_header_in_ipv4_packet<B: ParseBuffer>(
2539    src_ip: Ipv4Addr,
2540    dst_ip: Ipv4Addr,
2541    proto: Ipv4Proto,
2542    body: B,
2543) -> Option<TransportPacketData> {
2544    match proto {
2545        Ipv4Proto::Proto(IpProto::Udp) => parse_udp_header::<_, Ipv4>(body),
2546        Ipv4Proto::Proto(IpProto::Tcp) => parse_tcp_header::<_, Ipv4>(body, src_ip, dst_ip),
2547        Ipv4Proto::Icmp => parse_icmpv4_header(body),
2548        Ipv4Proto::Proto(IpProto::Reserved) | Ipv4Proto::Igmp | Ipv4Proto::Other(_) => None,
2549    }
2550}
2551
2552fn parse_transport_header_in_ipv6_packet<B: ParseBuffer>(
2553    src_ip: Ipv6Addr,
2554    dst_ip: Ipv6Addr,
2555    proto: Ipv6Proto,
2556    body: B,
2557) -> Option<TransportPacketData> {
2558    match proto {
2559        Ipv6Proto::Proto(IpProto::Udp) => parse_udp_header::<_, Ipv6>(body),
2560        Ipv6Proto::Proto(IpProto::Tcp) => parse_tcp_header::<_, Ipv6>(body, src_ip, dst_ip),
2561        Ipv6Proto::Icmpv6 => parse_icmpv6_header(body),
2562        Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::NoNextHeader | Ipv6Proto::Other(_) => None,
2563    }
2564}
2565
2566fn parse_udp_header<B: ParseBuffer, I: Ip>(mut body: B) -> Option<TransportPacketData> {
2567    let packet = body.parse_with::<_, UdpPacketRaw<_>>(I::VERSION_MARKER).ok()?;
2568    Some(TransportPacketData::Generic {
2569        src_port: packet.src_port().map(NonZeroU16::get).unwrap_or(0),
2570        // NB: UDP packets must have a specified (nonzero) destination port, so
2571        // if this packet has a destination port of 0, it is malformed.
2572        dst_port: packet.dst_port()?.get(),
2573    })
2574}
2575
2576fn parse_tcp_header<B: ParseBuffer, I: IpExt>(
2577    mut body: B,
2578    src_ip: I::Addr,
2579    dst_ip: I::Addr,
2580) -> Option<TransportPacketData> {
2581    // NOTE: By using TcpSegmentRaw here, we're opting into getting invalid data
2582    // (for example, if the checksum isn't valid). As a team, we've decided
2583    // that's okay for now, since the worst that happens is we filter or
2584    // conntrack a packet incorrectly and the end host rejects it.
2585    //
2586    // This will be fixed at some point as part of a larger effort to ensure
2587    // that checksums are validated exactly once (and hopefully via checksum
2588    // offloading).
2589    let packet = body.parse::<TcpSegmentRaw<_>>().ok()?;
2590
2591    let (fallback_src_port, fallback_dst_port) = packet.flow_header().src_dst();
2592    let fallback =
2593        TransportPacketData::Generic { src_port: fallback_src_port, dst_port: fallback_dst_port };
2594
2595    // TODO(https://fxbug.dev/328064909): When we enable configurable dropping of
2596    // invalid packets, we're going to want to bubble up the detection of a
2597    // truncated packet or invalid flags into the hooks in logic.rs (maybe coming
2598    // out of `IpPacket::conntrack_packet()`).
2599    let (builder, options_res, body) = match packet.into_builder_options(src_ip, dst_ip) {
2600        Ok(x) => x,
2601        Err(_) => return Some(fallback),
2602    };
2603    let options = match options_res {
2604        Ok(options) => options,
2605        Err((options, _err)) => options,
2606    };
2607    let options = match Options::try_from_options(&builder, &options) {
2608        Ok(x) => x,
2609        Err(MalformedFlags { .. }) => return Some(fallback),
2610    };
2611
2612    let segment = match SegmentHeader::from_builder_options(&builder, options) {
2613        Ok(x) => x,
2614        Err(MalformedFlags { .. }) => return Some(fallback),
2615    };
2616
2617    Some(TransportPacketData::Tcp {
2618        src_port: builder.src_port().map(NonZeroU16::get).unwrap_or(0),
2619        dst_port: builder.dst_port().map(NonZeroU16::get).unwrap_or(0),
2620        segment,
2621        payload_len: body.len(),
2622    })
2623}
2624
2625fn parse_icmpv4_header<B: ParseBuffer>(mut body: B) -> Option<TransportPacketData> {
2626    match icmp::peek_message_type(body.as_ref()).ok()? {
2627        Icmpv4MessageType::EchoRequest => {
2628            let packet = body.parse::<IcmpPacketRaw<Ipv4, _, IcmpEchoRequest>>().ok()?;
2629            packet.message().transport_packet_data()
2630        }
2631        Icmpv4MessageType::EchoReply => {
2632            let packet = body.parse::<IcmpPacketRaw<Ipv4, _, IcmpEchoReply>>().ok()?;
2633            packet.message().transport_packet_data()
2634        }
2635        // ICMP errors have a separate parsing path.
2636        Icmpv4MessageType::DestUnreachable
2637        | Icmpv4MessageType::Redirect
2638        | Icmpv4MessageType::TimeExceeded
2639        | Icmpv4MessageType::ParameterProblem => None,
2640        // NOTE: If these are parsed, then without further work, conntrack won't
2641        // be able to differentiate between these and ECHO message with the same
2642        // ID.
2643        Icmpv4MessageType::TimestampRequest | Icmpv4MessageType::TimestampReply => None,
2644    }
2645}
2646
2647fn parse_icmpv6_header<B: ParseBuffer>(mut body: B) -> Option<TransportPacketData> {
2648    match icmp::peek_message_type(body.as_ref()).ok()? {
2649        Icmpv6MessageType::EchoRequest => {
2650            let packet = body.parse::<IcmpPacketRaw<Ipv6, _, IcmpEchoRequest>>().ok()?;
2651            packet.message().transport_packet_data()
2652        }
2653        Icmpv6MessageType::EchoReply => {
2654            let packet = body.parse::<IcmpPacketRaw<Ipv6, _, IcmpEchoReply>>().ok()?;
2655            packet.message().transport_packet_data()
2656        }
2657        // ICMP errors have a separate parsing path.
2658        Icmpv6MessageType::DestUnreachable
2659        | Icmpv6MessageType::PacketTooBig
2660        | Icmpv6MessageType::TimeExceeded
2661        | Icmpv6MessageType::ParameterProblem => None,
2662        Icmpv6MessageType::RouterSolicitation
2663        | Icmpv6MessageType::RouterAdvertisement
2664        | Icmpv6MessageType::NeighborSolicitation
2665        | Icmpv6MessageType::NeighborAdvertisement
2666        | Icmpv6MessageType::Redirect
2667        | Icmpv6MessageType::MulticastListenerQuery
2668        | Icmpv6MessageType::MulticastListenerReport
2669        | Icmpv6MessageType::MulticastListenerDone
2670        | Icmpv6MessageType::MulticastListenerReportV2 => None,
2671    }
2672}
2673
2674/// A transport header that has been parsed from a byte buffer and provides
2675/// mutable access to its contents.
2676#[derive(GenericOverIp)]
2677#[generic_over_ip(I, Ip)]
2678pub enum ParsedTransportHeaderMut<'a, I: IpExt> {
2679    Tcp(TcpSegmentRaw<&'a mut [u8]>),
2680    Udp(UdpPacketRaw<&'a mut [u8]>),
2681    Icmp(I::IcmpPacketTypeRaw<&'a mut [u8]>),
2682}
2683
2684impl<'a> ParsedTransportHeaderMut<'a, Ipv4> {
2685    fn parse_in_ipv4_packet<BV: BufferViewMut<&'a mut [u8]>>(
2686        proto: Ipv4Proto,
2687        body: BV,
2688    ) -> Option<Self> {
2689        match proto {
2690            Ipv4Proto::Proto(IpProto::Udp) => {
2691                Some(Self::Udp(UdpPacketRaw::parse_mut(body, IpVersionMarker::<Ipv4>::new()).ok()?))
2692            }
2693            Ipv4Proto::Proto(IpProto::Tcp) => {
2694                Some(Self::Tcp(TcpSegmentRaw::parse_mut(body, ()).ok()?))
2695            }
2696            Ipv4Proto::Icmp => Some(Self::Icmp(Icmpv4PacketRaw::parse_mut(body, ()).ok()?)),
2697            Ipv4Proto::Proto(IpProto::Reserved) | Ipv4Proto::Igmp | Ipv4Proto::Other(_) => None,
2698        }
2699    }
2700}
2701
2702impl<'a> ParsedTransportHeaderMut<'a, Ipv6> {
2703    fn parse_in_ipv6_packet<BV: BufferViewMut<&'a mut [u8]>>(
2704        proto: Ipv6Proto,
2705        body: BV,
2706    ) -> Option<Self> {
2707        match proto {
2708            Ipv6Proto::Proto(IpProto::Udp) => {
2709                Some(Self::Udp(UdpPacketRaw::parse_mut(body, IpVersionMarker::<Ipv6>::new()).ok()?))
2710            }
2711            Ipv6Proto::Proto(IpProto::Tcp) => {
2712                Some(Self::Tcp(TcpSegmentRaw::parse_mut(body, ()).ok()?))
2713            }
2714            Ipv6Proto::Icmpv6 => Some(Self::Icmp(Icmpv6PacketRaw::parse_mut(body, ()).ok()?)),
2715            Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::NoNextHeader | Ipv6Proto::Other(_) => {
2716                None
2717            }
2718        }
2719    }
2720}
2721
2722impl<'a, I: IpExt> ParsedTransportHeaderMut<'a, I> {
2723    fn parse_in_ip_packet<BV: BufferViewMut<&'a mut [u8]>>(
2724        proto: I::Proto,
2725        body: BV,
2726    ) -> Option<Self> {
2727        I::map_ip(
2728            (proto, IpInvariant(body)),
2729            |(proto, IpInvariant(body))| {
2730                ParsedTransportHeaderMut::<'a, Ipv4>::parse_in_ipv4_packet(proto, body)
2731            },
2732            |(proto, IpInvariant(body))| {
2733                ParsedTransportHeaderMut::<'a, Ipv6>::parse_in_ipv6_packet(proto, body)
2734            },
2735        )
2736    }
2737
2738    fn update_pseudo_header_address(&mut self, old: I::Addr, new: I::Addr) {
2739        match self {
2740            Self::Tcp(segment) => segment.update_checksum_pseudo_header_address(old, new),
2741            Self::Udp(packet) => {
2742                packet.update_checksum_pseudo_header_address(old, new);
2743            }
2744            Self::Icmp(packet) => {
2745                packet.update_checksum_pseudo_header_address(old, new);
2746            }
2747        }
2748    }
2749}
2750
2751/// An inner IP packet contained within an ICMP error.
2752#[derive(Debug, PartialEq, Eq, GenericOverIp)]
2753#[generic_over_ip(I, Ip)]
2754pub struct ParsedIcmpErrorPayload<I: IpExt> {
2755    src_ip: I::Addr,
2756    dst_ip: I::Addr,
2757    // Hold the ports directly instead of TransportPacketData. In case of an
2758    // ICMP error, we don't update conntrack connection state, so there's no
2759    // reason to keep the extra information.
2760    src_port: u16,
2761    dst_port: u16,
2762    proto: I::Proto,
2763}
2764
2765impl ParsedIcmpErrorPayload<Ipv4> {
2766    fn parse_in_outer_ipv4_packet<B>(protocol: Ipv4Proto, mut body: B) -> Option<Self>
2767    where
2768        B: ParseBuffer,
2769    {
2770        match protocol {
2771            Ipv4Proto::Proto(_) | Ipv4Proto::Igmp | Ipv4Proto::Other(_) => None,
2772            Ipv4Proto::Icmp => {
2773                let message = body.parse::<Icmpv4PacketRaw<_>>().ok()?;
2774                let message_body = match &message {
2775                    Icmpv4PacketRaw::EchoRequest(_)
2776                    | Icmpv4PacketRaw::EchoReply(_)
2777                    | Icmpv4PacketRaw::TimestampRequest(_)
2778                    | Icmpv4PacketRaw::TimestampReply(_) => return None,
2779
2780                    Icmpv4PacketRaw::DestUnreachable(inner) => inner.message_body(),
2781                    Icmpv4PacketRaw::Redirect(inner) => inner.message_body(),
2782                    Icmpv4PacketRaw::TimeExceeded(inner) => inner.message_body(),
2783                    Icmpv4PacketRaw::ParameterProblem(inner) => inner.message_body(),
2784                };
2785
2786                Self::parse_in_icmpv4_error(Buf::new(message_body, ..))
2787            }
2788        }
2789    }
2790
2791    fn parse_in_icmpv4_error<B>(mut body: B) -> Option<Self>
2792    where
2793        B: ParseBuffer,
2794    {
2795        let packet = body.parse::<Ipv4PacketRaw<_>>().ok()?;
2796
2797        let src_ip = packet.get_header_prefix().src_ip();
2798        let dst_ip = packet.get_header_prefix().dst_ip();
2799        let proto = packet.proto();
2800        let transport_data = parse_transport_header_in_ipv4_packet(
2801            src_ip,
2802            dst_ip,
2803            proto,
2804            packet.body().into_inner(),
2805        )?;
2806        Some(Self {
2807            src_ip,
2808            dst_ip,
2809            src_port: transport_data.src_port(),
2810            dst_port: transport_data.dst_port(),
2811            proto,
2812        })
2813    }
2814}
2815
2816impl ParsedIcmpErrorPayload<Ipv6> {
2817    fn parse_in_outer_ipv6_packet<B>(protocol: Ipv6Proto, mut body: B) -> Option<Self>
2818    where
2819        B: ParseBuffer,
2820    {
2821        match protocol {
2822            Ipv6Proto::NoNextHeader | Ipv6Proto::Proto(_) | Ipv6Proto::Other(_) => None,
2823
2824            Ipv6Proto::Icmpv6 => {
2825                let message = body.parse::<Icmpv6PacketRaw<_>>().ok()?;
2826                let message_body = match &message {
2827                    Icmpv6PacketRaw::EchoRequest(_)
2828                    | Icmpv6PacketRaw::EchoReply(_)
2829                    | Icmpv6PacketRaw::Ndp(_)
2830                    | Icmpv6PacketRaw::Mld(_) => return None,
2831
2832                    Icmpv6PacketRaw::DestUnreachable(inner) => inner.message_body(),
2833                    Icmpv6PacketRaw::PacketTooBig(inner) => inner.message_body(),
2834                    Icmpv6PacketRaw::TimeExceeded(inner) => inner.message_body(),
2835                    Icmpv6PacketRaw::ParameterProblem(inner) => inner.message_body(),
2836                };
2837
2838                Self::parse_in_icmpv6_error(Buf::new(message_body, ..))
2839            }
2840        }
2841    }
2842
2843    fn parse_in_icmpv6_error<B>(mut body: B) -> Option<Self>
2844    where
2845        B: ParseBuffer,
2846    {
2847        let packet = body.parse::<Ipv6PacketRaw<_>>().ok()?;
2848
2849        let src_ip = packet.get_fixed_header().src_ip();
2850        let dst_ip = packet.get_fixed_header().dst_ip();
2851        let proto = packet.proto().ok()?;
2852        let transport_data = parse_transport_header_in_ipv6_packet(
2853            src_ip,
2854            dst_ip,
2855            proto,
2856            packet.body().ok()?.into_inner(),
2857        )?;
2858        Some(Self {
2859            src_ip,
2860            dst_ip,
2861            src_port: transport_data.src_port(),
2862            dst_port: transport_data.dst_port(),
2863            proto,
2864        })
2865    }
2866}
2867
2868impl<I: IpExt> ParsedIcmpErrorPayload<I> {
2869    fn parse_in_outer_ip_packet<B>(proto: I::Proto, body: B) -> Option<Self>
2870    where
2871        B: ParseBuffer,
2872    {
2873        I::map_ip(
2874            (proto, IpInvariant(body)),
2875            |(proto, IpInvariant(body))| {
2876                ParsedIcmpErrorPayload::<Ipv4>::parse_in_outer_ipv4_packet(proto, body)
2877            },
2878            |(proto, IpInvariant(body))| {
2879                ParsedIcmpErrorPayload::<Ipv6>::parse_in_outer_ipv6_packet(proto, body)
2880            },
2881        )
2882    }
2883}
2884
2885/// An ICMP error packet that provides mutable access to the contained IP
2886/// packet.
2887#[derive(GenericOverIp)]
2888#[generic_over_ip(I, Ip)]
2889pub struct ParsedIcmpErrorMut<'a, I: IpExt> {
2890    src_ip: I::Addr,
2891    dst_ip: I::Addr,
2892    message: I::IcmpPacketTypeRaw<&'a mut [u8]>,
2893}
2894
2895impl<'a> ParsedIcmpErrorMut<'a, Ipv4> {
2896    fn parse_in_ipv4_packet<BV: BufferViewMut<&'a mut [u8]>>(
2897        src_ip: Ipv4Addr,
2898        dst_ip: Ipv4Addr,
2899        proto: Ipv4Proto,
2900        body: BV,
2901    ) -> Option<Self> {
2902        match proto {
2903            Ipv4Proto::Proto(_) | Ipv4Proto::Igmp | Ipv4Proto::Other(_) => None,
2904            Ipv4Proto::Icmp => {
2905                let message = Icmpv4PacketRaw::parse_mut(body, ()).ok()?;
2906                match message {
2907                    Icmpv4PacketRaw::EchoRequest(_)
2908                    | Icmpv4PacketRaw::EchoReply(_)
2909                    | Icmpv4PacketRaw::TimestampRequest(_)
2910                    | Icmpv4PacketRaw::TimestampReply(_) => None,
2911
2912                    Icmpv4PacketRaw::DestUnreachable(_)
2913                    | Icmpv4PacketRaw::Redirect(_)
2914                    | Icmpv4PacketRaw::TimeExceeded(_)
2915                    | Icmpv4PacketRaw::ParameterProblem(_) => {
2916                        Some(Self { src_ip, dst_ip, message })
2917                    }
2918                }
2919            }
2920        }
2921    }
2922}
2923
2924impl<'a> ParsedIcmpErrorMut<'a, Ipv6> {
2925    fn parse_in_ipv6_packet<BV: BufferViewMut<&'a mut [u8]>>(
2926        src_ip: Ipv6Addr,
2927        dst_ip: Ipv6Addr,
2928        proto: Ipv6Proto,
2929        body: BV,
2930    ) -> Option<Self> {
2931        match proto {
2932            Ipv6Proto::NoNextHeader | Ipv6Proto::Proto(_) | Ipv6Proto::Other(_) => None,
2933
2934            Ipv6Proto::Icmpv6 => {
2935                let message = Icmpv6PacketRaw::parse_mut(body, ()).ok()?;
2936                match message {
2937                    Icmpv6PacketRaw::EchoRequest(_)
2938                    | Icmpv6PacketRaw::EchoReply(_)
2939                    | Icmpv6PacketRaw::Ndp(_)
2940                    | Icmpv6PacketRaw::Mld(_) => None,
2941
2942                    Icmpv6PacketRaw::DestUnreachable(_)
2943                    | Icmpv6PacketRaw::PacketTooBig(_)
2944                    | Icmpv6PacketRaw::TimeExceeded(_)
2945                    | Icmpv6PacketRaw::ParameterProblem(_) => {
2946                        Some(Self { src_ip, dst_ip, message })
2947                    }
2948                }
2949            }
2950        }
2951    }
2952}
2953
2954impl<'a, I: FilterIpExt> ParsedIcmpErrorMut<'a, I> {
2955    fn parse_in_ip_packet<BV: BufferViewMut<&'a mut [u8]>>(
2956        src_ip: I::Addr,
2957        dst_ip: I::Addr,
2958        proto: I::Proto,
2959        body: BV,
2960    ) -> Option<Self> {
2961        I::map_ip(
2962            (src_ip, dst_ip, proto, IpInvariant(body)),
2963            |(src_ip, dst_ip, proto, IpInvariant(body))| {
2964                ParsedIcmpErrorMut::<'a, Ipv4>::parse_in_ipv4_packet(src_ip, dst_ip, proto, body)
2965            },
2966            |(src_ip, dst_ip, proto, IpInvariant(body))| {
2967                ParsedIcmpErrorMut::<'a, Ipv6>::parse_in_ipv6_packet(src_ip, dst_ip, proto, body)
2968            },
2969        )
2970    }
2971}
2972
2973impl<'a, I: FilterIpExt> IcmpErrorMut<I> for ParsedIcmpErrorMut<'a, I> {
2974    type InnerPacket<'b>
2975        = I::FilterIpPacketRaw<&'b mut [u8]>
2976    where
2977        Self: 'b;
2978
2979    fn inner_packet<'b>(&'b mut self) -> Option<Self::InnerPacket<'b>> {
2980        Some(I::as_filter_packet_raw_owned(
2981            I::PacketRaw::parse_mut(SliceBufViewMut::new(self.message.message_body_mut()), ())
2982                .ok()?,
2983        ))
2984    }
2985
2986    fn recalculate_checksum(&mut self) -> bool {
2987        let Self { src_ip, dst_ip, message } = self;
2988        message.try_write_checksum(*src_ip, *dst_ip)
2989    }
2990}
2991
2992/// A helper trait to extract [`IcmpMessage`] impls from parsed ICMP messages.
2993trait IcmpMessageImplHelper<I: IpExt> {
2994    fn message_impl_mut(&mut self) -> &mut impl IcmpMessage<I>;
2995}
2996
2997impl<I: IpExt, B: SplitByteSliceMut, M: IcmpMessage<I>> IcmpMessageImplHelper<I>
2998    for IcmpPacketRaw<I, B, M>
2999{
3000    fn message_impl_mut(&mut self) -> &mut impl IcmpMessage<I> {
3001        self.message_mut()
3002    }
3003}
3004
3005impl<'a, I: IpExt> TransportPacketMut<I> for ParsedTransportHeaderMut<'a, I> {
3006    fn set_src_port(&mut self, port: NonZeroU16) {
3007        match self {
3008            ParsedTransportHeaderMut::Tcp(segment) => segment.set_src_port(port),
3009            ParsedTransportHeaderMut::Udp(packet) => packet.set_src_port(port.get()),
3010            ParsedTransportHeaderMut::Icmp(packet) => {
3011                I::map_ip::<_, ()>(
3012                    packet,
3013                    |packet| {
3014                        packet_formats::icmpv4_dispatch!(
3015                            packet: raw,
3016                            p => {
3017                                let message = p.message_impl_mut();
3018                                if  message.is_rewritable() {
3019                                    let old = message.update_icmp_id(port.get());
3020                                    p.update_checksum_header_field_u16(old, port.get())
3021                                }
3022                            }
3023                        );
3024                    },
3025                    |packet| {
3026                        packet_formats::icmpv6_dispatch!(
3027                            packet: raw,
3028                            p => {
3029                                let message = p.message_impl_mut();
3030                                if  message.is_rewritable() {
3031                                    let old = message.update_icmp_id(port.get());
3032                                    p.update_checksum_header_field_u16(old, port.get())
3033                                }
3034                            }
3035                        );
3036                    },
3037                );
3038            }
3039        }
3040    }
3041
3042    fn set_dst_port(&mut self, port: NonZeroU16) {
3043        match self {
3044            ParsedTransportHeaderMut::Tcp(segment) => segment.set_dst_port(port),
3045            ParsedTransportHeaderMut::Udp(packet) => packet.set_dst_port(port),
3046            ParsedTransportHeaderMut::Icmp(packet) => {
3047                I::map_ip::<_, ()>(
3048                    packet,
3049                    |packet| {
3050                        packet_formats::icmpv4_dispatch!(
3051                            packet:raw,
3052                            p => {
3053                                let message = p.message_impl_mut();
3054                                if  message.is_rewritable() {
3055                                    let old = message.update_icmp_id(port.get());
3056                                    p.update_checksum_header_field_u16(old, port.get())
3057                                }
3058                            }
3059                        );
3060                    },
3061                    |packet| {
3062                        packet_formats::icmpv6_dispatch!(
3063                            packet:raw,
3064                            p => {
3065                                let message = p.message_impl_mut();
3066                                if  message.is_rewritable() {
3067                                    let old = message.update_icmp_id(port.get());
3068                                    p.update_checksum_header_field_u16(old, port.get())
3069                                }
3070                            }
3071                        );
3072                    },
3073                );
3074            }
3075        }
3076    }
3077
3078    fn update_pseudo_header_src_addr(&mut self, old: I::Addr, new: I::Addr) {
3079        self.update_pseudo_header_address(old, new);
3080    }
3081
3082    fn update_pseudo_header_dst_addr(&mut self, old: I::Addr, new: I::Addr) {
3083        self.update_pseudo_header_address(old, new);
3084    }
3085}
3086
3087#[cfg(any(test, feature = "testutils"))]
3088pub mod testutil {
3089    use super::*;
3090
3091    // Note that we could choose to implement `MaybeTransportPacket` for these
3092    // opaque byte buffer types by parsing them as we do incoming buffers, but since
3093    // these implementations are only for use in netstack3_core unit tests, there is
3094    // no expectation that filtering or connection tracking actually be performed.
3095    // If that changes at some point, we could replace these with "real"
3096    // implementations.
3097
3098    impl<B: BufferMut> MaybeTransportPacket for Nested<B, ()> {
3099        fn transport_packet_data(&self) -> Option<TransportPacketData> {
3100            unimplemented!()
3101        }
3102    }
3103
3104    impl<I: IpExt, B: BufferMut> MaybeTransportPacketMut<I> for Nested<B, ()> {
3105        type TransportPacketMut<'a>
3106            = Never
3107        where
3108            B: 'a;
3109
3110        fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3111            unimplemented!()
3112        }
3113    }
3114
3115    impl<I: IpExt, B: BufferMut> MaybeIcmpErrorPayload<I> for Nested<B, ()> {
3116        fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3117            unimplemented!()
3118        }
3119    }
3120
3121    impl<I: FilterIpExt, B: BufferMut> MaybeIcmpErrorMut<I> for Nested<B, ()> {
3122        type IcmpErrorMut<'a>
3123            = Never
3124        where
3125            Self: 'a;
3126
3127        fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3128            unimplemented!()
3129        }
3130    }
3131
3132    impl MaybeTransportPacket for InnerSerializer<&[u8], EmptyBuf> {
3133        fn transport_packet_data(&self) -> Option<TransportPacketData> {
3134            None
3135        }
3136    }
3137
3138    impl<I: IpExt> MaybeTransportPacketMut<I> for InnerSerializer<&[u8], EmptyBuf> {
3139        type TransportPacketMut<'a>
3140            = Never
3141        where
3142            Self: 'a;
3143
3144        fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3145            None
3146        }
3147    }
3148
3149    impl<I: IpExt> MaybeIcmpErrorPayload<I> for InnerSerializer<&[u8], EmptyBuf> {
3150        fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3151            None
3152        }
3153    }
3154
3155    impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for InnerSerializer<&[u8], EmptyBuf> {
3156        type IcmpErrorMut<'a>
3157            = Never
3158        where
3159            Self: 'a;
3160
3161        fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3162            None
3163        }
3164    }
3165
3166    #[cfg(test)]
3167    pub(crate) mod internal {
3168        use alloc::vec::Vec;
3169        use net_declare::{net_ip_v4, net_ip_v6, net_subnet_v4, net_subnet_v6};
3170        use net_types::ip::Subnet;
3171        use netstack3_base::{SeqNum, UnscaledWindowSize};
3172        use packet::{PartialPacketBuilder as _, TruncateDirection};
3173        use packet_formats::icmp::{Icmpv4DestUnreachableCode, Icmpv6DestUnreachableCode};
3174
3175        use super::*;
3176
3177        pub trait TestIpExt: FilterIpExt {
3178            const SRC_IP: Self::Addr;
3179            const SRC_PORT: u16 = 1234;
3180            const DST_IP: Self::Addr;
3181            const DST_PORT: u16 = 9876;
3182            const SRC_IP_2: Self::Addr;
3183            const DST_IP_2: Self::Addr;
3184            const DST_IP_3: Self::Addr;
3185            const IP_OUTSIDE_SUBNET: Self::Addr;
3186            const SUBNET: Subnet<Self::Addr>;
3187            const PACKET_TTL: u8 = u8::MAX;
3188        }
3189
3190        impl TestIpExt for Ipv4 {
3191            const SRC_IP: Self::Addr = net_ip_v4!("192.0.2.1");
3192            const DST_IP: Self::Addr = net_ip_v4!("192.0.2.2");
3193            const SRC_IP_2: Self::Addr = net_ip_v4!("192.0.2.3");
3194            const DST_IP_2: Self::Addr = net_ip_v4!("192.0.2.4");
3195            const DST_IP_3: Self::Addr = net_ip_v4!("192.0.2.6");
3196            const IP_OUTSIDE_SUBNET: Self::Addr = net_ip_v4!("192.0.3.1");
3197            const SUBNET: Subnet<Self::Addr> = net_subnet_v4!("192.0.2.0/24");
3198        }
3199
3200        impl TestIpExt for Ipv6 {
3201            const SRC_IP: Self::Addr = net_ip_v6!("2001:db8::1");
3202            const DST_IP: Self::Addr = net_ip_v6!("2001:db8::2");
3203            const SRC_IP_2: Self::Addr = net_ip_v6!("2001:db8::3");
3204            const DST_IP_2: Self::Addr = net_ip_v6!("2001:db8::4");
3205            const DST_IP_3: Self::Addr = net_ip_v6!("2001:db8::6");
3206            const IP_OUTSIDE_SUBNET: Self::Addr = net_ip_v6!("2001:db8:ffff::1");
3207            const SUBNET: Subnet<Self::Addr> = net_subnet_v6!("2001:db8::/64");
3208        }
3209
3210        #[derive(Clone, Debug, PartialEq)]
3211        pub struct FakeIpPacket<I: FilterIpExt, T>
3212        where
3213            for<'a> &'a T: TransportPacketExt<I>,
3214        {
3215            pub src_ip: I::Addr,
3216            pub dst_ip: I::Addr,
3217            pub body: T,
3218        }
3219
3220        impl<I: FilterIpExt> FakeIpPacket<I, FakeUdpPacket> {
3221            pub(crate) fn reply(&self) -> Self {
3222                Self { src_ip: self.dst_ip, dst_ip: self.src_ip, body: self.body.reply() }
3223            }
3224        }
3225
3226        pub trait TransportPacketExt<I: IpExt>:
3227            MaybeTransportPacket + MaybeIcmpErrorPayload<I>
3228        {
3229            fn proto() -> Option<I::Proto>;
3230            fn len(&self) -> usize;
3231        }
3232
3233        impl<I: FilterIpExt, T> IpPacket<I> for FakeIpPacket<I, T>
3234        where
3235            for<'a> &'a T: TransportPacketExt<I>,
3236            for<'a> &'a mut T: MaybeTransportPacketMut<I> + MaybeIcmpErrorMut<I>,
3237        {
3238            type TransportPacket<'a>
3239                = &'a T
3240            where
3241                T: 'a;
3242            type TransportPacketMut<'a>
3243                = &'a mut T
3244            where
3245                T: 'a;
3246            type IcmpError<'a>
3247                = &'a T
3248            where
3249                T: 'a;
3250            type IcmpErrorMut<'a>
3251                = &'a mut T
3252            where
3253                T: 'a;
3254
3255            fn src_addr(&self) -> I::Addr {
3256                self.src_ip
3257            }
3258
3259            fn set_src_addr(&mut self, addr: I::Addr) {
3260                self.src_ip = addr;
3261            }
3262
3263            fn dst_addr(&self) -> I::Addr {
3264                self.dst_ip
3265            }
3266
3267            fn set_dst_addr(&mut self, addr: I::Addr) {
3268                self.dst_ip = addr;
3269            }
3270
3271            fn protocol(&self) -> Option<I::Proto> {
3272                <&T>::proto()
3273            }
3274
3275            fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
3276                &self.body
3277            }
3278
3279            fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
3280                &mut self.body
3281            }
3282
3283            fn maybe_icmp_error<'a>(&'a self) -> Self::IcmpError<'a> {
3284                &self.body
3285            }
3286
3287            fn icmp_error_mut<'a>(&'a mut self) -> Self::IcmpErrorMut<'a> {
3288                &mut self.body
3289            }
3290        }
3291
3292        impl<I: TestIpExt, T> PartialSerializer<NetworkSerializationContext> for FakeIpPacket<I, T>
3293        where
3294            for<'a> &'a T: TransportPacketExt<I>,
3295        {
3296            fn partial_serialize_new_buf<B: GrowBufferMut, A: LayoutBufferAlloc<B>>(
3297                &self,
3298                context: &mut NetworkSerializationContext,
3299                constraints: PacketConstraints,
3300                alloc: A,
3301            ) -> Result<(B, usize), SerializeError<A::Error>> {
3302                assert!(constraints == PacketConstraints::UNCONSTRAINED);
3303
3304                let Some(proto) = <&T>::proto() else {
3305                    let buffer = alloc.layout_alloc(0, 0, 0)?;
3306                    return Ok((buffer, 0));
3307                };
3308                let builder = I::PacketBuilder::new(self.src_ip, self.dst_ip, I::PACKET_TTL, proto);
3309                let constraints = builder.constraints();
3310                let header_len = constraints.header_len();
3311                let body_len = (&self.body).len();
3312
3313                let mut buffer = alloc.layout_alloc(header_len, 0, 0)?;
3314                buffer.with_parts_mut(|prefix, _body, _suffix| {
3315                    builder.partial_serialize(context, body_len, prefix);
3316                });
3317
3318                Ok((buffer, header_len + body_len))
3319            }
3320        }
3321
3322        #[derive(Clone, Debug, PartialEq)]
3323        pub struct FakeTcpSegment {
3324            pub src_port: u16,
3325            pub dst_port: u16,
3326            pub segment: SegmentHeader,
3327            pub payload_len: usize,
3328        }
3329
3330        impl<I: FilterIpExt> TransportPacketExt<I> for &FakeTcpSegment {
3331            fn proto() -> Option<I::Proto> {
3332                Some(I::map_ip_out(
3333                    (),
3334                    |()| Ipv4Proto::Proto(IpProto::Tcp),
3335                    |()| Ipv6Proto::Proto(IpProto::Tcp),
3336                ))
3337            }
3338
3339            fn len(&self) -> usize {
3340                packet_formats::tcp::HDR_PREFIX_LEN + self.payload_len
3341            }
3342        }
3343
3344        impl MaybeTransportPacket for &FakeTcpSegment {
3345            fn transport_packet_data(&self) -> Option<TransportPacketData> {
3346                Some(TransportPacketData::Tcp {
3347                    src_port: self.src_port,
3348                    dst_port: self.dst_port,
3349                    segment: self.segment.clone(),
3350                    payload_len: self.payload_len,
3351                })
3352            }
3353        }
3354
3355        impl<I: IpExt> MaybeTransportPacketMut<I> for FakeTcpSegment {
3356            type TransportPacketMut<'a> = &'a mut Self;
3357
3358            fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3359                Some(self)
3360            }
3361        }
3362
3363        impl<I: IpExt> TransportPacketMut<I> for FakeTcpSegment {
3364            fn set_src_port(&mut self, port: NonZeroU16) {
3365                self.src_port = port.get();
3366            }
3367
3368            fn set_dst_port(&mut self, port: NonZeroU16) {
3369                self.dst_port = port.get();
3370            }
3371
3372            fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {}
3373
3374            fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {}
3375        }
3376
3377        impl<I: IpExt> MaybeIcmpErrorPayload<I> for FakeTcpSegment {
3378            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3379                None
3380            }
3381        }
3382
3383        impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for FakeTcpSegment {
3384            type IcmpErrorMut<'a>
3385                = Never
3386            where
3387                Self: 'a;
3388
3389            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3390                None
3391            }
3392        }
3393
3394        #[derive(Clone, Debug, PartialEq)]
3395        pub struct FakeUdpPacket {
3396            pub src_port: u16,
3397            pub dst_port: u16,
3398        }
3399
3400        impl FakeUdpPacket {
3401            const PAYLOAD_LEN: usize = 4;
3402
3403            fn reply(&self) -> Self {
3404                Self { src_port: self.dst_port, dst_port: self.src_port }
3405            }
3406        }
3407
3408        impl<I: FilterIpExt> TransportPacketExt<I> for &FakeUdpPacket {
3409            fn proto() -> Option<I::Proto> {
3410                Some(I::map_ip_out(
3411                    (),
3412                    |()| Ipv4Proto::Proto(IpProto::Udp),
3413                    |()| Ipv6Proto::Proto(IpProto::Udp),
3414                ))
3415            }
3416
3417            fn len(&self) -> usize {
3418                packet_formats::udp::HEADER_BYTES + FakeUdpPacket::PAYLOAD_LEN
3419            }
3420        }
3421
3422        impl MaybeTransportPacket for &FakeUdpPacket {
3423            fn transport_packet_data(&self) -> Option<TransportPacketData> {
3424                Some(TransportPacketData::Generic {
3425                    src_port: self.src_port,
3426                    dst_port: self.dst_port,
3427                })
3428            }
3429        }
3430
3431        impl<I: IpExt> MaybeTransportPacketMut<I> for FakeUdpPacket {
3432            type TransportPacketMut<'a> = &'a mut Self;
3433
3434            fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3435                Some(self)
3436            }
3437        }
3438
3439        impl<I: IpExt> TransportPacketMut<I> for FakeUdpPacket {
3440            fn set_src_port(&mut self, port: NonZeroU16) {
3441                self.src_port = port.get();
3442            }
3443
3444            fn set_dst_port(&mut self, port: NonZeroU16) {
3445                self.dst_port = port.get();
3446            }
3447
3448            fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {}
3449
3450            fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {}
3451        }
3452
3453        impl<I: IpExt> MaybeIcmpErrorPayload<I> for FakeUdpPacket {
3454            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3455                None
3456            }
3457        }
3458
3459        impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for FakeUdpPacket {
3460            type IcmpErrorMut<'a>
3461                = Never
3462            where
3463                Self: 'a;
3464
3465            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3466                None
3467            }
3468        }
3469
3470        #[derive(Clone, Debug, PartialEq)]
3471        pub struct FakeNullPacket;
3472
3473        impl<I: IpExt> TransportPacketExt<I> for &FakeNullPacket {
3474            fn proto() -> Option<I::Proto> {
3475                None
3476            }
3477
3478            fn len(&self) -> usize {
3479                0
3480            }
3481        }
3482
3483        impl MaybeTransportPacket for &FakeNullPacket {
3484            fn transport_packet_data(&self) -> Option<TransportPacketData> {
3485                None
3486            }
3487        }
3488
3489        impl<I: IpExt> MaybeTransportPacketMut<I> for FakeNullPacket {
3490            type TransportPacketMut<'a> = Never;
3491
3492            fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3493                None
3494            }
3495        }
3496
3497        impl<I: IpExt> MaybeIcmpErrorPayload<I> for FakeNullPacket {
3498            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3499                None
3500            }
3501        }
3502
3503        impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for FakeNullPacket {
3504            type IcmpErrorMut<'a>
3505                = Never
3506            where
3507                Self: 'a;
3508
3509            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3510                None
3511            }
3512        }
3513
3514        pub struct FakeIcmpEchoRequest {
3515            pub id: u16,
3516        }
3517
3518        impl<I: FilterIpExt> TransportPacketExt<I> for &FakeIcmpEchoRequest {
3519            fn proto() -> Option<I::Proto> {
3520                Some(I::map_ip_out((), |()| Ipv4Proto::Icmp, |()| Ipv6Proto::Icmpv6))
3521            }
3522
3523            fn len(&self) -> usize {
3524                // ICMP header is 8 bytes.
3525                8
3526            }
3527        }
3528
3529        impl MaybeTransportPacket for &FakeIcmpEchoRequest {
3530            fn transport_packet_data(&self) -> Option<TransportPacketData> {
3531                Some(TransportPacketData::Generic { src_port: self.id, dst_port: 0 })
3532            }
3533        }
3534
3535        impl<I: IpExt> MaybeTransportPacketMut<I> for FakeIcmpEchoRequest {
3536            type TransportPacketMut<'a> = &'a mut Self;
3537
3538            fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3539                Some(self)
3540            }
3541        }
3542
3543        impl<I: IpExt> TransportPacketMut<I> for FakeIcmpEchoRequest {
3544            fn set_src_port(&mut self, port: NonZeroU16) {
3545                self.id = port.get();
3546            }
3547
3548            fn set_dst_port(&mut self, _: NonZeroU16) {
3549                panic!("cannot set destination port for ICMP echo request")
3550            }
3551
3552            fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {}
3553
3554            fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {}
3555        }
3556
3557        impl<I: IpExt> MaybeIcmpErrorPayload<I> for FakeIcmpEchoRequest {
3558            fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3559                None
3560            }
3561        }
3562
3563        impl<I: FilterIpExt> MaybeIcmpErrorMut<I> for FakeIcmpEchoRequest {
3564            type IcmpErrorMut<'a>
3565                = Never
3566            where
3567                Self: 'a;
3568
3569            fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3570                None
3571            }
3572        }
3573
3574        pub trait ArbitraryValue {
3575            fn arbitrary_value() -> Self;
3576        }
3577
3578        impl<I, T> ArbitraryValue for FakeIpPacket<I, T>
3579        where
3580            I: TestIpExt,
3581            T: ArbitraryValue,
3582            for<'a> &'a T: TransportPacketExt<I>,
3583        {
3584            fn arbitrary_value() -> Self {
3585                FakeIpPacket { src_ip: I::SRC_IP, dst_ip: I::DST_IP, body: T::arbitrary_value() }
3586            }
3587        }
3588
3589        impl ArbitraryValue for FakeTcpSegment {
3590            fn arbitrary_value() -> Self {
3591                FakeTcpSegment {
3592                    src_port: 33333,
3593                    dst_port: 44444,
3594                    segment: SegmentHeader::arbitrary_value(),
3595                    payload_len: 8888,
3596                }
3597            }
3598        }
3599
3600        impl ArbitraryValue for FakeUdpPacket {
3601            fn arbitrary_value() -> Self {
3602                FakeUdpPacket { src_port: 33333, dst_port: 44444 }
3603            }
3604        }
3605
3606        impl ArbitraryValue for FakeNullPacket {
3607            fn arbitrary_value() -> Self {
3608                FakeNullPacket
3609            }
3610        }
3611
3612        impl ArbitraryValue for FakeIcmpEchoRequest {
3613            fn arbitrary_value() -> Self {
3614                FakeIcmpEchoRequest { id: 1 }
3615            }
3616        }
3617
3618        impl ArbitraryValue for SegmentHeader {
3619            fn arbitrary_value() -> Self {
3620                SegmentHeader {
3621                    seq: SeqNum::new(55555),
3622                    wnd: UnscaledWindowSize::from(1234),
3623                    ..Default::default()
3624                }
3625            }
3626        }
3627
3628        pub(crate) trait IcmpErrorMessage<I: FilterIpExt> {
3629            type Serializer: TransportPacketSerializer<I, Buffer: packet::ReusableBuffer>
3630                + Debug
3631                + PartialEq;
3632
3633            fn proto() -> I::Proto {
3634                I::map_ip((), |()| Ipv4Proto::Icmp, |()| Ipv6Proto::Icmpv6)
3635            }
3636
3637            fn make_serializer(
3638                src_ip: I::Addr,
3639                dst_ip: I::Addr,
3640                inner: Vec<u8>,
3641            ) -> Self::Serializer;
3642
3643            fn make_serializer_truncated(
3644                src_ip: I::Addr,
3645                dst_ip: I::Addr,
3646                mut payload: Vec<u8>,
3647                truncate_payload: Option<usize>,
3648            ) -> Self::Serializer {
3649                if let Some(len) = truncate_payload {
3650                    payload.truncate(len);
3651                }
3652
3653                Self::make_serializer(src_ip, dst_ip, payload)
3654            }
3655        }
3656
3657        pub(crate) struct Icmpv4DestUnreachableError;
3658
3659        impl IcmpErrorMessage<Ipv4> for Icmpv4DestUnreachableError {
3660            type Serializer = Nested<Buf<Vec<u8>>, IcmpPacketBuilder<Ipv4, IcmpDestUnreachable>>;
3661
3662            fn make_serializer(
3663                src_ip: Ipv4Addr,
3664                dst_ip: Ipv4Addr,
3665                payload: Vec<u8>,
3666            ) -> Self::Serializer {
3667                IcmpPacketBuilder::<Ipv4, IcmpDestUnreachable>::new(
3668                    src_ip,
3669                    dst_ip,
3670                    Icmpv4DestUnreachableCode::DestHostUnreachable,
3671                    IcmpDestUnreachable::default(),
3672                )
3673                .wrap_body(Buf::new(payload, ..))
3674            }
3675        }
3676
3677        pub(crate) struct Icmpv6DestUnreachableError;
3678
3679        impl IcmpErrorMessage<Ipv6> for Icmpv6DestUnreachableError {
3680            type Serializer = Nested<
3681                TruncatingSerializer<Buf<Vec<u8>>>,
3682                IcmpPacketBuilder<Ipv6, IcmpDestUnreachable>,
3683            >;
3684
3685            fn make_serializer(
3686                src_ip: Ipv6Addr,
3687                dst_ip: Ipv6Addr,
3688                payload: Vec<u8>,
3689            ) -> Self::Serializer {
3690                IcmpPacketBuilder::<Ipv6, IcmpDestUnreachable>::new(
3691                    src_ip,
3692                    dst_ip,
3693                    Icmpv6DestUnreachableCode::AddrUnreachable,
3694                    IcmpDestUnreachable::default(),
3695                )
3696                .wrap_body(TruncatingSerializer::new(
3697                    Buf::new(payload, ..),
3698                    TruncateDirection::DiscardBack,
3699                ))
3700            }
3701        }
3702    }
3703
3704    /// Creates a new `IpPacket` with the specified addresses and body.
3705    pub fn new_filter_egress_ip_packet<I: FilterIpExt, S: TransportPacketSerializer<I>>(
3706        src_addr: I::Addr,
3707        dst_addr: I::Addr,
3708        protocol: I::Proto,
3709        body: &'_ mut S,
3710    ) -> impl FilterIpPacket<I> + use<'_, I, S> {
3711        TxPacket::new(src_addr, dst_addr, protocol, body)
3712    }
3713}
3714
3715#[cfg(test)]
3716mod tests {
3717    use alloc::vec::Vec;
3718    use core::fmt::Debug;
3719    use core::marker::PhantomData;
3720    use netstack3_base::{NetworkSerializationContext, SeqNum, UnscaledWindowSize};
3721
3722    use assert_matches::assert_matches;
3723    use ip_test_macro::ip_test;
3724    use packet::{
3725        EmptyBuf, FragmentedBuffer as _, InnerPacketBuilder as _, ParseBufferMut, PartialSerializer,
3726    };
3727    use packet_formats::icmp::IcmpZeroCode;
3728    use packet_formats::tcp::TcpSegmentBuilder;
3729    use test_case::{test_case, test_matrix};
3730
3731    use crate::conntrack;
3732
3733    use super::testutil::internal::{
3734        IcmpErrorMessage, Icmpv4DestUnreachableError, Icmpv6DestUnreachableError, TestIpExt,
3735    };
3736    use super::*;
3737
3738    const SRC_PORT: NonZeroU16 = NonZeroU16::new(11111).unwrap();
3739    const DST_PORT: NonZeroU16 = NonZeroU16::new(22222).unwrap();
3740    const SRC_PORT_2: NonZeroU16 = NonZeroU16::new(44444).unwrap();
3741    const DST_PORT_2: NonZeroU16 = NonZeroU16::new(55555).unwrap();
3742
3743    const SEQ_NUM: u32 = 1;
3744    const ACK_NUM: Option<u32> = Some(2);
3745    const WINDOW_SIZE: u16 = 3u16;
3746
3747    trait Protocol {
3748        const HEADER_SIZE: usize;
3749
3750        type Serializer<'a, I: FilterIpExt>: TransportPacketSerializer<I, Buffer: packet::ReusableBuffer>
3751            + MaybeTransportPacketMut<I>
3752            + Debug
3753            + PartialEq;
3754
3755        fn proto<I: IpExt>() -> I::Proto;
3756
3757        fn make_serializer_with_ports_data<'a, I: FilterIpExt>(
3758            src_ip: I::Addr,
3759            dst_ip: I::Addr,
3760            src_port: NonZeroU16,
3761            dst_port: NonZeroU16,
3762            data: &'a [u8],
3763        ) -> Self::Serializer<'a, I>;
3764
3765        fn make_serializer_with_ports<'a, I: FilterIpExt>(
3766            src_ip: I::Addr,
3767            dst_ip: I::Addr,
3768            src_port: NonZeroU16,
3769            dst_port: NonZeroU16,
3770        ) -> Self::Serializer<'a, I> {
3771            Self::make_serializer_with_ports_data(src_ip, dst_ip, src_port, dst_port, &[1, 2, 3])
3772        }
3773
3774        fn make_serializer<'a, I: FilterIpExt>(
3775            src_ip: I::Addr,
3776            dst_ip: I::Addr,
3777        ) -> Self::Serializer<'a, I> {
3778            Self::make_serializer_with_ports(src_ip, dst_ip, SRC_PORT, DST_PORT)
3779        }
3780
3781        fn make_packet<I: FilterIpExt>(src_ip: I::Addr, dst_ip: I::Addr) -> Vec<u8> {
3782            Self::make_packet_with_ports::<I>(src_ip, dst_ip, SRC_PORT, DST_PORT)
3783        }
3784
3785        fn make_packet_with_ports<I: FilterIpExt>(
3786            src_ip: I::Addr,
3787            dst_ip: I::Addr,
3788            src_port: NonZeroU16,
3789            dst_port: NonZeroU16,
3790        ) -> Vec<u8> {
3791            Self::make_serializer_with_ports::<I>(src_ip, dst_ip, src_port, dst_port)
3792                .serialize_vec_outer(&mut NetworkSerializationContext::default())
3793                .expect("serialize packet")
3794                .unwrap_b()
3795                .into_inner()
3796        }
3797
3798        fn make_ip_packet_with_ports_data<I: FilterIpExt>(
3799            src_ip: I::Addr,
3800            dst_ip: I::Addr,
3801            src_port: NonZeroU16,
3802            dst_port: NonZeroU16,
3803            data: &[u8],
3804        ) -> Vec<u8> {
3805            I::PacketBuilder::new(src_ip, dst_ip, u8::MAX, Self::proto::<I>())
3806                .wrap_body(Self::make_serializer_with_ports_data::<I>(
3807                    src_ip, dst_ip, src_port, dst_port, data,
3808                ))
3809                .serialize_vec_outer(&mut NetworkSerializationContext::default())
3810                .expect("serialize packet")
3811                .unwrap_b()
3812                .into_inner()
3813        }
3814    }
3815
3816    struct Udp;
3817
3818    impl Protocol for Udp {
3819        const HEADER_SIZE: usize = 8;
3820
3821        type Serializer<'a, I: FilterIpExt> =
3822            Nested<InnerSerializer<&'a [u8], EmptyBuf>, UdpPacketBuilder<I::Addr>>;
3823
3824        fn proto<I: IpExt>() -> I::Proto {
3825            IpProto::Udp.into()
3826        }
3827
3828        fn make_serializer_with_ports_data<'a, I: FilterIpExt>(
3829            src_ip: I::Addr,
3830            dst_ip: I::Addr,
3831            src_port: NonZeroU16,
3832            dst_port: NonZeroU16,
3833            data: &'a [u8],
3834        ) -> Self::Serializer<'a, I> {
3835            UdpPacketBuilder::new(src_ip, dst_ip, Some(src_port), dst_port)
3836                .wrap_body(data.into_serializer())
3837        }
3838    }
3839
3840    // The `TcpSegmentBuilder` impls are test-only on purpose, and removing this
3841    // restriction should be thought through.
3842    //
3843    // TCP state tracking depends on being able to read TCP options, but
3844    // TcpSegmentBuilder does not have this information. If a TcpSegmentBuilder
3845    // passes through filtering with options tracked separately, then these will
3846    // not be seen by conntrack and could lead to state desynchronization.
3847    impl<A: IpAddress, Inner: PayloadLen> MaybeTransportPacket for Nested<Inner, TcpSegmentBuilder<A>> {
3848        fn transport_packet_data(&self) -> Option<TransportPacketData> {
3849            Some(TransportPacketData::Tcp {
3850                src_port: TcpSegmentBuilder::src_port(self.outer()).map_or(0, NonZeroU16::get),
3851                dst_port: TcpSegmentBuilder::dst_port(self.outer()).map_or(0, NonZeroU16::get),
3852                segment: self.outer().try_into().ok()?,
3853                payload_len: self.inner().len(),
3854            })
3855        }
3856    }
3857
3858    impl<I: IpExt, Inner> MaybeTransportPacketMut<I> for Nested<Inner, TcpSegmentBuilder<I::Addr>> {
3859        type TransportPacketMut<'a>
3860            = &'a mut Self
3861        where
3862            Self: 'a;
3863
3864        fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
3865            Some(self)
3866        }
3867    }
3868
3869    impl<I: IpExt, Inner> TransportPacketMut<I> for Nested<Inner, TcpSegmentBuilder<I::Addr>> {
3870        fn set_src_port(&mut self, port: NonZeroU16) {
3871            self.outer_mut().set_src_port(port);
3872        }
3873
3874        fn set_dst_port(&mut self, port: NonZeroU16) {
3875            self.outer_mut().set_dst_port(port);
3876        }
3877
3878        fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
3879            self.outer_mut().set_src_ip(new);
3880        }
3881
3882        fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
3883            self.outer_mut().set_dst_ip(new);
3884        }
3885    }
3886
3887    impl<A: IpAddress, I: IpExt, Inner> MaybeIcmpErrorPayload<I>
3888        for Nested<Inner, TcpSegmentBuilder<A>>
3889    {
3890        fn icmp_error_payload(&self) -> Option<ParsedIcmpErrorPayload<I>> {
3891            None
3892        }
3893    }
3894
3895    impl<A: IpAddress, I: FilterIpExt, Inner> MaybeIcmpErrorMut<I>
3896        for Nested<Inner, TcpSegmentBuilder<A>>
3897    {
3898        type IcmpErrorMut<'a>
3899            = Never
3900        where
3901            Self: 'a;
3902
3903        fn icmp_error_mut<'a>(&'a mut self) -> Option<Self::IcmpErrorMut<'a>> {
3904            None
3905        }
3906    }
3907
3908    enum Tcp {}
3909
3910    impl Protocol for Tcp {
3911        const HEADER_SIZE: usize = 20;
3912
3913        type Serializer<'a, I: FilterIpExt> =
3914            Nested<InnerSerializer<&'a [u8], EmptyBuf>, TcpSegmentBuilder<I::Addr>>;
3915
3916        fn proto<I: IpExt>() -> I::Proto {
3917            IpProto::Tcp.into()
3918        }
3919
3920        fn make_serializer_with_ports_data<'a, I: FilterIpExt>(
3921            src_ip: I::Addr,
3922            dst_ip: I::Addr,
3923            src_port: NonZeroU16,
3924            dst_port: NonZeroU16,
3925            data: &'a [u8],
3926        ) -> Self::Serializer<'a, I> {
3927            TcpSegmentBuilder::new(
3928                src_ip,
3929                dst_ip,
3930                src_port,
3931                dst_port,
3932                SEQ_NUM,
3933                ACK_NUM,
3934                WINDOW_SIZE,
3935            )
3936            .wrap_body(data.into_serializer())
3937        }
3938    }
3939
3940    enum IcmpEchoRequest {}
3941
3942    impl Protocol for IcmpEchoRequest {
3943        const HEADER_SIZE: usize = 8;
3944
3945        type Serializer<'a, I: FilterIpExt> = Nested<
3946            InnerSerializer<&'a [u8], EmptyBuf>,
3947            IcmpPacketBuilder<I, icmp::IcmpEchoRequest>,
3948        >;
3949
3950        fn proto<I: IpExt>() -> I::Proto {
3951            I::map_ip((), |()| Ipv4Proto::Icmp, |()| Ipv6Proto::Icmpv6)
3952        }
3953
3954        fn make_serializer_with_ports_data<'a, I: FilterIpExt>(
3955            src_ip: I::Addr,
3956            dst_ip: I::Addr,
3957            src_port: NonZeroU16,
3958            _dst_port: NonZeroU16,
3959            data: &'a [u8],
3960        ) -> Self::Serializer<'a, I> {
3961            IcmpPacketBuilder::<I, _>::new(
3962                src_ip,
3963                dst_ip,
3964                IcmpZeroCode,
3965                icmp::IcmpEchoRequest::new(/* id */ src_port.get(), /* seq */ 0),
3966            )
3967            .wrap_body(data.into_serializer())
3968        }
3969    }
3970
3971    enum IcmpEchoReply {}
3972
3973    impl Protocol for IcmpEchoReply {
3974        const HEADER_SIZE: usize = 8;
3975
3976        type Serializer<'a, I: FilterIpExt> =
3977            Nested<InnerSerializer<&'a [u8], EmptyBuf>, IcmpPacketBuilder<I, icmp::IcmpEchoReply>>;
3978
3979        fn proto<I: IpExt>() -> I::Proto {
3980            I::map_ip((), |()| Ipv4Proto::Icmp, |()| Ipv6Proto::Icmpv6)
3981        }
3982
3983        fn make_serializer_with_ports_data<'a, I: FilterIpExt>(
3984            src_ip: I::Addr,
3985            dst_ip: I::Addr,
3986            _src_port: NonZeroU16,
3987            dst_port: NonZeroU16,
3988            data: &'a [u8],
3989        ) -> Self::Serializer<'a, I> {
3990            IcmpPacketBuilder::<I, _>::new(
3991                src_ip,
3992                dst_ip,
3993                IcmpZeroCode,
3994                icmp::IcmpEchoReply::new(/* id */ dst_port.get(), /* seq */ 0),
3995            )
3996            .wrap_body(data.into_serializer())
3997        }
3998    }
3999
4000    enum TransportPacketDataProtocol {
4001        Tcp,
4002        Udp,
4003        IcmpEchoRequest,
4004    }
4005
4006    impl TransportPacketDataProtocol {
4007        fn make_packet<I: TestIpExt>(&self, src_ip: I::Addr, dst_ip: I::Addr) -> Vec<u8> {
4008            match self {
4009                TransportPacketDataProtocol::Tcp => Tcp::make_packet::<I>(src_ip, dst_ip),
4010                TransportPacketDataProtocol::Udp => Udp::make_packet::<I>(src_ip, dst_ip),
4011                TransportPacketDataProtocol::IcmpEchoRequest => {
4012                    IcmpEchoRequest::make_packet::<I>(src_ip, dst_ip)
4013                }
4014            }
4015        }
4016
4017        fn make_ip_packet_with_ports_data<I: TestIpExt>(
4018            &self,
4019            src_ip: I::Addr,
4020            dst_ip: I::Addr,
4021            src_port: NonZeroU16,
4022            dst_port: NonZeroU16,
4023            data: &[u8],
4024        ) -> Vec<u8> {
4025            match self {
4026                TransportPacketDataProtocol::Tcp => Tcp::make_ip_packet_with_ports_data::<I>(
4027                    src_ip, dst_ip, src_port, dst_port, data,
4028                ),
4029                TransportPacketDataProtocol::Udp => Udp::make_ip_packet_with_ports_data::<I>(
4030                    src_ip, dst_ip, src_port, dst_port, data,
4031                ),
4032                TransportPacketDataProtocol::IcmpEchoRequest => {
4033                    IcmpEchoRequest::make_ip_packet_with_ports_data::<I>(
4034                        src_ip, dst_ip, src_port, dst_port, data,
4035                    )
4036                }
4037            }
4038        }
4039
4040        fn proto<I: TestIpExt>(&self) -> I::Proto {
4041            match self {
4042                TransportPacketDataProtocol::Tcp => Tcp::proto::<I>(),
4043                TransportPacketDataProtocol::Udp => Udp::proto::<I>(),
4044                TransportPacketDataProtocol::IcmpEchoRequest => IcmpEchoRequest::proto::<I>(),
4045            }
4046        }
4047    }
4048
4049    #[ip_test(I)]
4050    #[test_case(TransportPacketDataProtocol::Udp)]
4051    #[test_case(TransportPacketDataProtocol::Tcp)]
4052    #[test_case(TransportPacketDataProtocol::IcmpEchoRequest)]
4053    fn transport_packet_data_from_serialized<I: TestIpExt>(proto: TransportPacketDataProtocol) {
4054        let expected_data = match proto {
4055            TransportPacketDataProtocol::Tcp => TransportPacketData::Tcp {
4056                src_port: SRC_PORT.get(),
4057                dst_port: DST_PORT.get(),
4058                segment: SegmentHeader {
4059                    seq: SeqNum::new(SEQ_NUM),
4060                    ack: ACK_NUM.map(SeqNum::new),
4061                    wnd: UnscaledWindowSize::from(WINDOW_SIZE),
4062                    ..Default::default()
4063                },
4064                payload_len: 3,
4065            },
4066            TransportPacketDataProtocol::Udp => {
4067                TransportPacketData::Generic { src_port: SRC_PORT.get(), dst_port: DST_PORT.get() }
4068            }
4069            TransportPacketDataProtocol::IcmpEchoRequest => {
4070                TransportPacketData::Generic { src_port: SRC_PORT.get(), dst_port: SRC_PORT.get() }
4071            }
4072        };
4073
4074        let buf = proto.make_packet::<I>(I::SRC_IP, I::DST_IP);
4075        let parsed_data = TransportPacketData::parse_in_ip_packet::<I, _>(
4076            I::SRC_IP,
4077            I::DST_IP,
4078            proto.proto::<I>(),
4079            buf.as_slice(),
4080        )
4081        .expect("failed to parse transport packet data");
4082
4083        assert_eq!(parsed_data, expected_data);
4084    }
4085
4086    // Regression test for https://fxbug.dev/518696592.
4087    // Verifies that we still extract port information (as Tcp packet data)
4088    // even if TCP options parsing fails due to malformed options.
4089    #[ip_test(I)]
4090    fn transport_packet_data_from_serialized_invalid_tcp_options<I: TestIpExt>() {
4091        let mut buf = TransportPacketDataProtocol::Tcp.make_packet::<I>(I::SRC_IP, I::DST_IP);
4092
4093        // Normal TCP header is 20 bytes.
4094        assert!(buf.len() >= 20);
4095
4096        // data_offset is in buf[12], most significant 4 bits.
4097        // Change data_offset from 5 (20 bytes) to 6 (24 bytes) to make room for options.
4098        buf[12] = (6 << 4) | (buf[12] & 0x0F);
4099
4100        // Modify TCP header to include an invalid option [255, 0, 0, 0] at index 20.
4101        let mut new_buf = Vec::new();
4102        new_buf.extend_from_slice(&buf[..20]);
4103        new_buf.extend_from_slice(&[255, 0, 0, 0]);
4104        new_buf.extend_from_slice(&buf[20..]);
4105
4106        let parsed_data = TransportPacketData::parse_in_ip_packet::<I, _>(
4107            I::SRC_IP,
4108            I::DST_IP,
4109            IpProto::Tcp.into(),
4110            new_buf.as_slice(),
4111        );
4112
4113        assert_matches!(
4114            parsed_data,
4115            Some(TransportPacketData::Tcp { src_port, dst_port, .. }) => {
4116                assert_eq!(src_port, SRC_PORT.get());
4117                assert_eq!(dst_port, DST_PORT.get());
4118            }
4119        );
4120    }
4121
4122    // Regression test for https://fxbug.dev/518696592.
4123    // Verifies that we still extract port information (as Generic packet data)
4124    // even if TCP header parsing fails due to malformed (mutually exclusive) flags.
4125    #[ip_test(I)]
4126    fn transport_packet_data_from_serialized_malformed_tcp_flags<I: TestIpExt>() {
4127        let mut buf = TransportPacketDataProtocol::Tcp.make_packet::<I>(I::SRC_IP, I::DST_IP);
4128
4129        // Modify TCP header to include mutually exclusive flags: SYN and RST.
4130        // Normal TCP header is 20 bytes.
4131        assert!(buf.len() >= 20);
4132
4133        // Flags are in buf[13].
4134        // SYN is 0x02, RST is 0x04. Set both.
4135        buf[13] |= 0x02 | 0x04;
4136
4137        let parsed_data = TransportPacketData::parse_in_ip_packet::<I, _>(
4138            I::SRC_IP,
4139            I::DST_IP,
4140            IpProto::Tcp.into(),
4141            buf.as_slice(),
4142        );
4143
4144        assert_matches!(
4145            parsed_data,
4146            Some(TransportPacketData::Generic { src_port, dst_port }) => {
4147                assert_eq!(src_port, SRC_PORT.get());
4148                assert_eq!(dst_port, DST_PORT.get());
4149            }
4150        );
4151    }
4152
4153    enum PacketType {
4154        FullyParsed,
4155        Raw,
4156    }
4157
4158    #[ip_test(I)]
4159    #[test_matrix(
4160        [
4161            TransportPacketDataProtocol::Udp,
4162            TransportPacketDataProtocol::Tcp,
4163            TransportPacketDataProtocol::IcmpEchoRequest,
4164        ],
4165        [
4166            PacketType::FullyParsed,
4167            PacketType::Raw
4168        ]
4169    )]
4170    fn conntrack_packet_data_from_ip_packet<I: TestIpExt>(
4171        proto: TransportPacketDataProtocol,
4172        packet_type: PacketType,
4173    ) where
4174        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
4175        for<'a> I::PacketRaw<&'a mut [u8]>: IpPacket<I>,
4176    {
4177        let expected_data = match proto {
4178            TransportPacketDataProtocol::Tcp => conntrack::PacketMetadata::new(
4179                I::SRC_IP,
4180                I::DST_IP,
4181                conntrack::TransportProtocol::Tcp,
4182                TransportPacketData::Tcp {
4183                    src_port: SRC_PORT.get(),
4184                    dst_port: DST_PORT.get(),
4185                    segment: SegmentHeader {
4186                        seq: SeqNum::new(SEQ_NUM),
4187                        ack: ACK_NUM.map(SeqNum::new),
4188                        wnd: UnscaledWindowSize::from(WINDOW_SIZE),
4189                        ..Default::default()
4190                    },
4191                    payload_len: 3,
4192                },
4193            ),
4194            TransportPacketDataProtocol::Udp => conntrack::PacketMetadata::new(
4195                I::SRC_IP,
4196                I::DST_IP,
4197                conntrack::TransportProtocol::Udp,
4198                TransportPacketData::Generic { src_port: SRC_PORT.get(), dst_port: DST_PORT.get() },
4199            ),
4200            TransportPacketDataProtocol::IcmpEchoRequest => conntrack::PacketMetadata::new(
4201                I::SRC_IP,
4202                I::DST_IP,
4203                conntrack::TransportProtocol::Icmp,
4204                TransportPacketData::Generic { src_port: SRC_PORT.get(), dst_port: SRC_PORT.get() },
4205            ),
4206        };
4207
4208        let mut buf = proto.make_ip_packet_with_ports_data::<I>(
4209            I::SRC_IP,
4210            I::DST_IP,
4211            SRC_PORT,
4212            DST_PORT,
4213            &[1, 2, 3],
4214        );
4215
4216        let parsed_data = match packet_type {
4217            PacketType::FullyParsed => {
4218                let packet = I::Packet::parse_mut(SliceBufViewMut::new(buf.as_mut()), ())
4219                    .expect("parse IP packet");
4220                packet.conntrack_packet().expect("packet should be trackable")
4221            }
4222            PacketType::Raw => {
4223                let packet = I::PacketRaw::parse_mut(SliceBufViewMut::new(buf.as_mut()), ())
4224                    .expect("parse IP packet");
4225                packet.conntrack_packet().expect("packet should be trackable")
4226            }
4227        };
4228
4229        assert_eq!(parsed_data, expected_data);
4230    }
4231
4232    #[ip_test(I)]
4233    #[test_case(PhantomData::<Udp>)]
4234    #[test_case(PhantomData::<Tcp>)]
4235    #[test_case(PhantomData::<IcmpEchoRequest>)]
4236    fn update_pseudo_header_address_updates_checksum<I: TestIpExt, P: Protocol>(
4237        _proto: PhantomData<P>,
4238    ) {
4239        let mut buf = P::make_packet::<I>(I::SRC_IP, I::DST_IP);
4240        let view = SliceBufViewMut::new(&mut buf);
4241
4242        let mut packet = ParsedTransportHeaderMut::<I>::parse_in_ip_packet(P::proto::<I>(), view)
4243            .expect("parse transport header");
4244        packet.update_pseudo_header_src_addr(I::SRC_IP, I::SRC_IP_2);
4245        packet.update_pseudo_header_dst_addr(I::DST_IP, I::DST_IP_2);
4246        // Drop the packet because it's holding a mutable borrow of `buf` which
4247        // we need to assert equality later.
4248        drop(packet);
4249
4250        let equivalent = P::make_packet::<I>(I::SRC_IP_2, I::DST_IP_2);
4251
4252        assert_eq!(equivalent, buf);
4253    }
4254
4255    #[ip_test(I)]
4256    #[test_case(PhantomData::<Udp>, true, true)]
4257    #[test_case(PhantomData::<Tcp>, true, true)]
4258    #[test_case(PhantomData::<IcmpEchoRequest>, true, false)]
4259    #[test_case(PhantomData::<IcmpEchoReply>, false, true)]
4260    fn parsed_packet_update_src_dst_port_updates_checksum<I: TestIpExt, P: Protocol>(
4261        _proto: PhantomData<P>,
4262        update_src_port: bool,
4263        update_dst_port: bool,
4264    ) {
4265        let mut buf = P::make_packet_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT);
4266        let view = SliceBufViewMut::new(&mut buf);
4267
4268        let mut packet = ParsedTransportHeaderMut::<I>::parse_in_ip_packet(P::proto::<I>(), view)
4269            .expect("parse transport header");
4270        let expected_src_port = if update_src_port {
4271            packet.set_src_port(SRC_PORT_2);
4272            SRC_PORT_2
4273        } else {
4274            SRC_PORT
4275        };
4276        let expected_dst_port = if update_dst_port {
4277            packet.set_dst_port(DST_PORT_2);
4278            DST_PORT_2
4279        } else {
4280            DST_PORT
4281        };
4282        drop(packet);
4283
4284        let equivalent = P::make_packet_with_ports::<I>(
4285            I::SRC_IP,
4286            I::DST_IP,
4287            expected_src_port,
4288            expected_dst_port,
4289        );
4290
4291        assert_eq!(equivalent, buf);
4292    }
4293
4294    #[ip_test(I)]
4295    #[test_case(PhantomData::<Udp>)]
4296    #[test_case(PhantomData::<Tcp>)]
4297    fn serializer_update_src_dst_port_updates_checksum<I: TestIpExt, P: Protocol>(
4298        _proto: PhantomData<P>,
4299    ) {
4300        let mut serializer =
4301            P::make_serializer_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT);
4302        let mut packet =
4303            serializer.transport_packet_mut().expect("packet should support rewriting");
4304        packet.set_src_port(SRC_PORT_2);
4305        packet.set_dst_port(DST_PORT_2);
4306        drop(packet);
4307
4308        let equivalent =
4309            P::make_serializer_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT_2, DST_PORT_2);
4310
4311        assert_eq!(equivalent, serializer);
4312    }
4313
4314    #[ip_test(I)]
4315    fn icmp_echo_request_update_id_port_updates_checksum<I: TestIpExt>() {
4316        let mut serializer = IcmpPacketBuilder::<I, _>::new(
4317            I::SRC_IP,
4318            I::DST_IP,
4319            IcmpZeroCode,
4320            icmp::IcmpEchoRequest::new(SRC_PORT.get(), /* seq */ 0),
4321        )
4322        .wrap_body(EmptyBuf);
4323        serializer
4324            .transport_packet_mut()
4325            .expect("packet should support rewriting")
4326            .set_src_port(SRC_PORT_2);
4327
4328        let equivalent = IcmpPacketBuilder::<I, _>::new(
4329            I::SRC_IP,
4330            I::DST_IP,
4331            IcmpZeroCode,
4332            icmp::IcmpEchoRequest::new(SRC_PORT_2.get(), /* seq */ 0),
4333        )
4334        .wrap_body(EmptyBuf);
4335
4336        assert_eq!(equivalent, serializer);
4337    }
4338
4339    #[ip_test(I)]
4340    fn icmp_echo_reply_update_id_port_updates_checksum<I: TestIpExt>() {
4341        let mut serializer = IcmpPacketBuilder::<I, _>::new(
4342            I::SRC_IP,
4343            I::DST_IP,
4344            IcmpZeroCode,
4345            icmp::IcmpEchoReply::new(SRC_PORT.get(), /* seq */ 0),
4346        )
4347        .wrap_body(EmptyBuf);
4348        serializer
4349            .transport_packet_mut()
4350            .expect("packet should support rewriting")
4351            .set_dst_port(SRC_PORT_2);
4352
4353        let equivalent = IcmpPacketBuilder::<I, _>::new(
4354            I::SRC_IP,
4355            I::DST_IP,
4356            IcmpZeroCode,
4357            icmp::IcmpEchoReply::new(SRC_PORT_2.get(), /* seq */ 0),
4358        )
4359        .wrap_body(EmptyBuf);
4360
4361        assert_eq!(equivalent, serializer);
4362    }
4363
4364    fn ip_packet<I: TestIpExt, P: Protocol>(src: I::Addr, dst: I::Addr) -> Buf<Vec<u8>> {
4365        Buf::new(P::make_packet::<I>(src, dst), ..)
4366            .wrap_in(I::PacketBuilder::new(src, dst, I::PACKET_TTL, P::proto::<I>()))
4367            .serialize_vec_outer(&mut NetworkSerializationContext::default())
4368            .expect("serialize IP packet")
4369            .unwrap_b()
4370    }
4371
4372    #[ip_test(I)]
4373    #[test_matrix(
4374        [
4375            PhantomData::<Udp>,
4376            PhantomData::<Tcp>,
4377            PhantomData::<IcmpEchoRequest>,
4378        ],
4379        [
4380            PacketType::FullyParsed,
4381            PacketType::Raw
4382        ]
4383    )]
4384    fn ip_packet_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(
4385        _proto: PhantomData<P>,
4386        packet_type: PacketType,
4387    ) where
4388        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
4389        for<'a> I::PacketRaw<&'a mut [u8]>: IpPacket<I>,
4390    {
4391        let mut buf = ip_packet::<I, P>(I::SRC_IP, I::DST_IP).into_inner();
4392
4393        match packet_type {
4394            PacketType::FullyParsed => {
4395                let mut packet = I::Packet::parse_mut(SliceBufViewMut::new(&mut buf), ())
4396                    .expect("parse IP packet");
4397                packet.set_src_addr(I::SRC_IP_2);
4398                packet.set_dst_addr(I::DST_IP_2);
4399            }
4400            PacketType::Raw => {
4401                let mut packet = I::PacketRaw::parse_mut(SliceBufViewMut::new(&mut buf), ())
4402                    .expect("parse IP packet");
4403                packet.set_src_addr(I::SRC_IP_2);
4404                packet.set_dst_addr(I::DST_IP_2);
4405            }
4406        }
4407
4408        let equivalent = ip_packet::<I, P>(I::SRC_IP_2, I::DST_IP_2).into_inner();
4409
4410        assert_eq!(equivalent, buf);
4411    }
4412
4413    #[ip_test(I)]
4414    #[test_case(PhantomData::<Udp>)]
4415    #[test_case(PhantomData::<Tcp>)]
4416    #[test_case(PhantomData::<IcmpEchoRequest>)]
4417    fn forwarded_packet_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(
4418        _proto: PhantomData<P>,
4419    ) {
4420        let mut buffer = ip_packet::<I, P>(I::SRC_IP, I::DST_IP);
4421        let meta = buffer.parse::<I::Packet<_>>().expect("parse IP packet").parse_metadata();
4422        let mut packet = ForwardedPacket::<I, _>::new(
4423            I::SRC_IP,
4424            I::DST_IP,
4425            P::proto::<I>(),
4426            meta,
4427            buffer,
4428            false,
4429        );
4430        packet.set_src_addr(I::SRC_IP_2);
4431        packet.set_dst_addr(I::DST_IP_2);
4432
4433        let mut buffer = ip_packet::<I, P>(I::SRC_IP_2, I::DST_IP_2);
4434        let meta = buffer.parse::<I::Packet<_>>().expect("parse IP packet").parse_metadata();
4435        let equivalent = ForwardedPacket::<I, _>::new(
4436            I::SRC_IP_2,
4437            I::DST_IP_2,
4438            P::proto::<I>(),
4439            meta,
4440            buffer,
4441            false,
4442        );
4443
4444        assert_eq!(equivalent, packet);
4445    }
4446
4447    #[ip_test(I)]
4448    #[test_case(PhantomData::<Udp>)]
4449    #[test_case(PhantomData::<Tcp>)]
4450    #[test_case(PhantomData::<IcmpEchoRequest>)]
4451    fn tx_packet_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(
4452        _proto: PhantomData<P>,
4453    ) {
4454        let mut body = P::make_serializer::<I>(I::SRC_IP, I::DST_IP);
4455        let mut packet = TxPacket::<I, _>::new(I::SRC_IP, I::DST_IP, P::proto::<I>(), &mut body);
4456        packet.set_src_addr(I::SRC_IP_2);
4457        packet.set_dst_addr(I::DST_IP_2);
4458
4459        let mut equivalent_body = P::make_serializer::<I>(I::SRC_IP_2, I::DST_IP_2);
4460        let equivalent =
4461            TxPacket::new(I::SRC_IP_2, I::DST_IP_2, P::proto::<I>(), &mut equivalent_body);
4462
4463        assert_eq!(equivalent, packet);
4464    }
4465
4466    #[ip_test(I)]
4467    #[test_case(PhantomData::<Udp>)]
4468    #[test_case(PhantomData::<Tcp>)]
4469    #[test_case(PhantomData::<IcmpEchoRequest>)]
4470    fn nested_serializer_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(
4471        _proto: PhantomData<P>,
4472    ) {
4473        let mut packet =
4474            I::PacketBuilder::new(I::SRC_IP, I::DST_IP, I::PACKET_TTL, P::proto::<I>())
4475                .wrap_body(P::make_serializer::<I>(I::SRC_IP, I::DST_IP));
4476        packet.set_src_addr(I::SRC_IP_2);
4477        packet.set_dst_addr(I::DST_IP_2);
4478
4479        let equivalent = P::make_serializer::<I>(I::SRC_IP_2, I::DST_IP_2).wrap_in(
4480            I::PacketBuilder::new(I::SRC_IP_2, I::DST_IP_2, I::PACKET_TTL, P::proto::<I>()),
4481        );
4482
4483        assert_eq!(equivalent, packet);
4484    }
4485
4486    #[ip_test(I)]
4487    #[test_matrix(
4488         [
4489             PhantomData::<Udp>,
4490             PhantomData::<Tcp>,
4491             PhantomData::<IcmpEchoRequest>,
4492         ],
4493         [
4494             PacketType::FullyParsed,
4495             PacketType::Raw
4496         ]
4497     )]
4498    fn no_icmp_error_for_normal_ip_packet<I: TestIpExt, P: Protocol>(
4499        _proto: PhantomData<P>,
4500        packet_type: PacketType,
4501    ) where
4502        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
4503        for<'a> I::PacketRaw<&'a mut [u8]>: IpPacket<I>,
4504    {
4505        let mut buf = ip_packet::<I, P>(I::SRC_IP, I::DST_IP).into_inner();
4506        let icmp_error = match packet_type {
4507            PacketType::FullyParsed => {
4508                let packet = I::Packet::parse_mut(SliceBufViewMut::new(&mut buf), ())
4509                    .expect("parse IP packet");
4510                let icmp_payload = packet.maybe_icmp_error().icmp_error_payload();
4511
4512                icmp_payload
4513            }
4514            PacketType::Raw => {
4515                let packet = I::PacketRaw::parse_mut(SliceBufViewMut::new(&mut buf), ())
4516                    .expect("parse IP packet");
4517                let icmp_payload = packet.maybe_icmp_error().icmp_error_payload();
4518
4519                icmp_payload
4520            }
4521        };
4522
4523        assert_matches!(icmp_error, None);
4524    }
4525
4526    #[ip_test(I)]
4527    #[test_matrix(
4528         [
4529             PhantomData::<Udp>,
4530             PhantomData::<Tcp>,
4531             PhantomData::<IcmpEchoRequest>,
4532         ],
4533         [
4534             PacketType::FullyParsed,
4535             PacketType::Raw
4536         ]
4537     )]
4538    fn no_icmp_error_mut_for_normal_ip_packet<I: TestIpExt, P: Protocol>(
4539        _proto: PhantomData<P>,
4540        packet_type: PacketType,
4541    ) where
4542        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
4543        for<'a> I::PacketRaw<&'a mut [u8]>: IpPacket<I>,
4544    {
4545        let mut buf = ip_packet::<I, P>(I::SRC_IP, I::DST_IP).into_inner();
4546        match packet_type {
4547            PacketType::FullyParsed => {
4548                let mut packet = I::Packet::parse_mut(SliceBufViewMut::new(&mut buf), ())
4549                    .expect("parse IP packet");
4550                assert!(packet.icmp_error_mut().icmp_error_mut().is_none());
4551            }
4552            PacketType::Raw => {
4553                let mut packet = I::PacketRaw::parse_mut(SliceBufViewMut::new(&mut buf), ())
4554                    .expect("parse IP packet");
4555                assert!(packet.icmp_error_mut().icmp_error_mut().is_none());
4556            }
4557        }
4558    }
4559
4560    #[ip_test(I)]
4561    #[test_case(TransportPacketDataProtocol::Udp)]
4562    #[test_case(TransportPacketDataProtocol::Tcp)]
4563    #[test_case(TransportPacketDataProtocol::IcmpEchoRequest)]
4564    fn no_icmp_error_for_normal_bytes<I: TestIpExt>(proto: TransportPacketDataProtocol) {
4565        let buf = proto.make_packet::<I>(I::SRC_IP, I::DST_IP);
4566
4567        assert_matches!(
4568            ParsedIcmpErrorPayload::<I>::parse_in_outer_ip_packet(
4569                proto.proto::<I>(),
4570                buf.as_slice(),
4571            ),
4572            None
4573        );
4574    }
4575
4576    #[ip_test(I)]
4577    #[test_case(TransportPacketDataProtocol::Udp)]
4578    #[test_case(TransportPacketDataProtocol::Tcp)]
4579    #[test_case(TransportPacketDataProtocol::IcmpEchoRequest)]
4580    fn no_icmp_error_mut_for_normal_bytes<I: TestIpExt>(proto: TransportPacketDataProtocol) {
4581        let mut buf = proto.make_packet::<I>(I::SRC_IP, I::DST_IP);
4582
4583        assert!(
4584            ParsedIcmpErrorMut::<I>::parse_in_ip_packet(
4585                I::SRC_IP,
4586                I::DST_IP,
4587                proto.proto::<I>(),
4588                SliceBufViewMut::new(&mut buf),
4589            )
4590            .is_none()
4591        );
4592    }
4593
4594    #[ip_test(I)]
4595    #[test_case(PhantomData::<Udp>)]
4596    #[test_case(PhantomData::<Tcp>)]
4597    #[test_case(PhantomData::<IcmpEchoRequest>)]
4598    fn no_icmp_error_for_normal_serializer<I: TestIpExt, P: Protocol>(_proto: PhantomData<P>) {
4599        let serializer =
4600            P::make_serializer_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT);
4601
4602        assert_matches!(serializer.icmp_error_payload(), None);
4603    }
4604
4605    #[ip_test(I)]
4606    #[test_case(PhantomData::<Udp>)]
4607    #[test_case(PhantomData::<Tcp>)]
4608    #[test_case(PhantomData::<IcmpEchoRequest>)]
4609    fn no_icmp_error_mut_for_normal_serializer<I: TestIpExt, P: Protocol>(_proto: PhantomData<P>) {
4610        let mut serializer =
4611            P::make_serializer_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT);
4612
4613        assert!(serializer.icmp_error_mut().is_none());
4614    }
4615
4616    #[test_matrix(
4617        [
4618            PhantomData::<Icmpv4DestUnreachableError>,
4619            PhantomData::<Icmpv6DestUnreachableError>,
4620        ],
4621        [
4622            TransportPacketDataProtocol::Udp,
4623            TransportPacketDataProtocol::Tcp,
4624            TransportPacketDataProtocol::IcmpEchoRequest,
4625        ],
4626        [
4627            PacketType::FullyParsed,
4628            PacketType::Raw,
4629        ],
4630        [
4631            false,
4632            true,
4633        ]
4634    )]
4635    fn icmp_error_from_bytes<I: TestIpExt, IE: IcmpErrorMessage<I>>(
4636        _icmp_error: PhantomData<IE>,
4637        proto: TransportPacketDataProtocol,
4638        packet_type: PacketType,
4639        truncate_message: bool,
4640    ) {
4641        let serializer = IE::make_serializer_truncated(
4642            I::DST_IP_2,
4643            I::SRC_IP,
4644            proto.make_ip_packet_with_ports_data::<I>(
4645                I::SRC_IP,
4646                I::DST_IP,
4647                SRC_PORT,
4648                DST_PORT,
4649                &[0xAB; 5000],
4650            ),
4651            // Try with a truncated and full body to make sure we don't fail
4652            // when a partial payload is present. In these cases, the ICMP error
4653            // payload checksum can't be validated, though we want to be sure
4654            // it's updated as if it were correct.
4655            truncate_message.then_some(1280),
4656        )
4657        .wrap_in(I::PacketBuilder::new(I::DST_IP_2, I::SRC_IP, u8::MAX, IE::proto()));
4658
4659        let mut bytes: Buf<Vec<u8>> = serializer
4660            .serialize_vec_outer(&mut NetworkSerializationContext::default())
4661            .unwrap()
4662            .unwrap_b();
4663        let icmp_payload = match packet_type {
4664            PacketType::FullyParsed => {
4665                let packet = I::as_filter_packet_owned(bytes.parse_mut::<I::Packet<_>>().unwrap());
4666                let icmp_payload =
4667                    packet.maybe_icmp_error().icmp_error_payload().expect("no ICMP error found");
4668
4669                icmp_payload
4670            }
4671            PacketType::Raw => {
4672                let packet =
4673                    I::as_filter_packet_raw_owned(bytes.parse_mut::<I::PacketRaw<_>>().unwrap());
4674                let icmp_payload =
4675                    packet.maybe_icmp_error().icmp_error_payload().expect("no ICMP error found");
4676
4677                icmp_payload
4678            }
4679        };
4680
4681        let expected = match proto {
4682            TransportPacketDataProtocol::Tcp | TransportPacketDataProtocol::Udp => {
4683                ParsedIcmpErrorPayload {
4684                    src_ip: I::SRC_IP,
4685                    dst_ip: I::DST_IP,
4686                    src_port: SRC_PORT.get(),
4687                    dst_port: DST_PORT.get(),
4688                    proto: proto.proto::<I>(),
4689                }
4690            }
4691            TransportPacketDataProtocol::IcmpEchoRequest => {
4692                ParsedIcmpErrorPayload {
4693                    src_ip: I::SRC_IP,
4694                    dst_ip: I::DST_IP,
4695                    // NOTE: These are intentionally the same because of how
4696                    // ICMP tracking works.
4697                    src_port: SRC_PORT.get(),
4698                    dst_port: SRC_PORT.get(),
4699                    proto: proto.proto::<I>(),
4700                }
4701            }
4702        };
4703
4704        assert_eq!(icmp_payload, expected);
4705    }
4706
4707    #[test_matrix(
4708        [
4709            PhantomData::<Icmpv4DestUnreachableError>,
4710            PhantomData::<Icmpv6DestUnreachableError>,
4711        ],
4712        [
4713            TransportPacketDataProtocol::Udp,
4714            TransportPacketDataProtocol::Tcp,
4715            TransportPacketDataProtocol::IcmpEchoRequest,
4716        ],
4717        [
4718            false,
4719            true,
4720        ]
4721    )]
4722    fn icmp_error_from_serializer<I: TestIpExt, IE: IcmpErrorMessage<I>>(
4723        _icmp_error: PhantomData<IE>,
4724        proto: TransportPacketDataProtocol,
4725        truncate_message: bool,
4726    ) {
4727        let serializer = IE::make_serializer_truncated(
4728            I::DST_IP_2,
4729            I::SRC_IP,
4730            proto.make_ip_packet_with_ports_data::<I>(
4731                I::SRC_IP,
4732                I::DST_IP,
4733                SRC_PORT,
4734                DST_PORT,
4735                &[0xAB; 5000],
4736            ),
4737            // Try with a truncated and full body to make sure we don't fail
4738            // when a partial payload is present. In these cases, the ICMP error
4739            // payload checksum can't be validated, though we want to be sure
4740            // it's updated as if it were correct.
4741            truncate_message.then_some(1280),
4742        );
4743
4744        let actual =
4745            serializer.icmp_error_payload().expect("serializer should contain an IP packet");
4746
4747        let expected = match proto {
4748            TransportPacketDataProtocol::Tcp | TransportPacketDataProtocol::Udp => {
4749                ParsedIcmpErrorPayload::<I> {
4750                    src_ip: I::SRC_IP,
4751                    dst_ip: I::DST_IP,
4752                    src_port: SRC_PORT.get(),
4753                    dst_port: DST_PORT.get(),
4754                    proto: proto.proto::<I>(),
4755                }
4756            }
4757            TransportPacketDataProtocol::IcmpEchoRequest => ParsedIcmpErrorPayload::<I> {
4758                src_ip: I::SRC_IP,
4759                dst_ip: I::DST_IP,
4760                // NOTE: These are intentionally the same because of how ICMP
4761                // tracking works.
4762                src_port: SRC_PORT.get(),
4763                dst_port: SRC_PORT.get(),
4764                proto: proto.proto::<I>(),
4765            },
4766        };
4767
4768        assert_eq!(actual, expected);
4769    }
4770
4771    #[test_matrix(
4772        [
4773            PhantomData::<Icmpv4DestUnreachableError>,
4774            PhantomData::<Icmpv6DestUnreachableError>,
4775        ],
4776        [
4777            TransportPacketDataProtocol::Udp,
4778            TransportPacketDataProtocol::Tcp,
4779            TransportPacketDataProtocol::IcmpEchoRequest,
4780        ],
4781        [
4782            PacketType::FullyParsed,
4783            PacketType::Raw,
4784        ],
4785        [
4786            false,
4787            true,
4788        ]
4789    )]
4790    fn conntrack_packet_icmp_error_from_bytes<I: TestIpExt, IE: IcmpErrorMessage<I>>(
4791        _icmp_error: PhantomData<IE>,
4792        proto: TransportPacketDataProtocol,
4793        packet_type: PacketType,
4794        truncate_message: bool,
4795    ) {
4796        let serializer = IE::make_serializer_truncated(
4797            I::DST_IP_2,
4798            I::SRC_IP,
4799            proto.make_ip_packet_with_ports_data::<I>(
4800                I::SRC_IP,
4801                I::DST_IP,
4802                SRC_PORT,
4803                DST_PORT,
4804                &[0xAB; 5000],
4805            ),
4806            // Try with a truncated and full body to make sure we don't fail
4807            // when a partial payload is present. In these cases, the ICMP error
4808            // payload checksum can't be validated, though we want to be sure
4809            // it's updated as if it were correct.
4810            truncate_message.then_some(1280),
4811        )
4812        .wrap_in(I::PacketBuilder::new(I::DST_IP_2, I::SRC_IP, u8::MAX, IE::proto()));
4813
4814        let mut bytes: Buf<Vec<u8>> = serializer
4815            .serialize_vec_outer(&mut NetworkSerializationContext::default())
4816            .unwrap()
4817            .unwrap_b();
4818
4819        let conntrack_packet = match packet_type {
4820            PacketType::FullyParsed => {
4821                let packet = I::as_filter_packet_owned(bytes.parse_mut::<I::Packet<_>>().unwrap());
4822                packet.conntrack_packet().unwrap()
4823            }
4824            PacketType::Raw => {
4825                let packet =
4826                    I::as_filter_packet_raw_owned(bytes.parse_mut::<I::PacketRaw<_>>().unwrap());
4827                packet.conntrack_packet().unwrap()
4828            }
4829        };
4830
4831        let expected = match proto {
4832            TransportPacketDataProtocol::Tcp | TransportPacketDataProtocol::Udp => {
4833                conntrack::PacketMetadata::new_from_icmp_error(
4834                    I::SRC_IP,
4835                    I::DST_IP,
4836                    SRC_PORT.get(),
4837                    DST_PORT.get(),
4838                    I::map_ip(proto.proto::<I>(), |proto| proto.into(), |proto| proto.into()),
4839                )
4840            }
4841            TransportPacketDataProtocol::IcmpEchoRequest => {
4842                conntrack::PacketMetadata::new_from_icmp_error(
4843                    I::SRC_IP,
4844                    I::DST_IP,
4845                    // NOTE: These are intentionally the same because of how
4846                    // ICMP tracking works.
4847                    SRC_PORT.get(),
4848                    SRC_PORT.get(),
4849                    I::map_ip(proto.proto::<I>(), |proto| proto.into(), |proto| proto.into()),
4850                )
4851            }
4852        };
4853
4854        assert_eq!(conntrack_packet, expected);
4855    }
4856
4857    #[test_matrix(
4858        [
4859            PhantomData::<Icmpv4DestUnreachableError>,
4860            PhantomData::<Icmpv6DestUnreachableError>,
4861        ],
4862        [
4863            TransportPacketDataProtocol::Udp,
4864            TransportPacketDataProtocol::Tcp,
4865            TransportPacketDataProtocol::IcmpEchoRequest,
4866        ],
4867        [
4868            PacketType::FullyParsed,
4869            PacketType::Raw,
4870        ],
4871        [
4872            false,
4873            true,
4874        ]
4875    )]
4876    fn no_conntrack_packet_for_incompatible_outer_and_payload<
4877        I: TestIpExt,
4878        IE: IcmpErrorMessage<I>,
4879    >(
4880        _icmp_error: PhantomData<IE>,
4881        proto: TransportPacketDataProtocol,
4882        packet_type: PacketType,
4883        truncate_message: bool,
4884    ) {
4885        // In order for the outer packet to have the tuple (DST_IP_2, SRC_IP_2),
4886        // the host sending the error must have seen a packet with a source
4887        // address of SRC_IP_2, but we know that can't be right because the
4888        // payload of the packet contains a packet with a source address of
4889        // SRC_IP.
4890        let serializer = IE::make_serializer_truncated(
4891            I::DST_IP_2,
4892            I::SRC_IP_2,
4893            proto.make_ip_packet_with_ports_data::<I>(
4894                I::SRC_IP,
4895                I::DST_IP,
4896                SRC_PORT,
4897                DST_PORT,
4898                &[0xAB; 5000],
4899            ),
4900            // Try with a truncated and full body to make sure we don't fail
4901            // when a partial payload is present. In these cases, the ICMP error
4902            // payload checksum can't be validated, though we want to be sure
4903            // it's updated as if it were correct.
4904            truncate_message.then_some(1280),
4905        )
4906        .wrap_in(I::PacketBuilder::new(I::DST_IP_2, I::SRC_IP_2, u8::MAX, IE::proto()));
4907
4908        let mut bytes: Buf<Vec<u8>> = serializer
4909            .serialize_vec_outer(&mut NetworkSerializationContext::default())
4910            .unwrap()
4911            .unwrap_b();
4912
4913        let conntrack_packet = match packet_type {
4914            PacketType::FullyParsed => {
4915                let packet = I::as_filter_packet_owned(bytes.parse_mut::<I::Packet<_>>().unwrap());
4916                packet.conntrack_packet()
4917            }
4918            PacketType::Raw => {
4919                let packet =
4920                    I::as_filter_packet_raw_owned(bytes.parse_mut::<I::PacketRaw<_>>().unwrap());
4921                packet.conntrack_packet()
4922            }
4923        };
4924
4925        // Because the outer and payload tuples aren't compatible, we shouldn't
4926        // get a conntrack packet back.
4927        assert_matches!(conntrack_packet, None);
4928    }
4929
4930    #[test_matrix(
4931        [
4932            PhantomData::<Icmpv4DestUnreachableError>,
4933            PhantomData::<Icmpv6DestUnreachableError>,
4934        ],
4935        [
4936            TransportPacketDataProtocol::Udp,
4937            TransportPacketDataProtocol::Tcp,
4938            TransportPacketDataProtocol::IcmpEchoRequest,
4939        ],
4940        [
4941            false,
4942            true,
4943        ]
4944    )]
4945    fn icmp_error_mut_from_serializer<I: TestIpExt, IE: IcmpErrorMessage<I>>(
4946        _icmp_error: PhantomData<IE>,
4947        proto: TransportPacketDataProtocol,
4948        truncate_message: bool,
4949    ) where
4950        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
4951    {
4952        const LEN: usize = 5000;
4953
4954        let mut payload_bytes = proto.make_ip_packet_with_ports_data::<I>(
4955            I::SRC_IP,
4956            I::DST_IP,
4957            SRC_PORT,
4958            DST_PORT,
4959            &[0xAB; LEN],
4960        );
4961
4962        // Try with a truncated and full body to make sure we don't fail when a
4963        // partial payload is present.
4964        if truncate_message {
4965            payload_bytes.truncate(1280);
4966        }
4967
4968        let mut serializer = IE::make_serializer(I::SRC_IP, I::DST_IP, payload_bytes)
4969            .wrap_in(I::PacketBuilder::new(I::SRC_IP, I::DST_IP, u8::MAX, IE::proto()));
4970
4971        {
4972            let mut icmp_packet = serializer
4973                .icmp_error_mut()
4974                .icmp_error_mut()
4975                .expect("couldn't find an inner ICMP error");
4976
4977            {
4978                let mut inner_packet = icmp_packet.inner_packet().expect("no inner packet");
4979
4980                inner_packet.set_src_addr(I::SRC_IP_2);
4981                inner_packet.set_dst_addr(I::DST_IP_2);
4982            }
4983
4984            // Since this is just a serializer, there's no thing to be recalculated,
4985            // but this should still never fail.
4986            assert!(icmp_packet.recalculate_checksum());
4987        }
4988
4989        let mut expected_payload_bytes = proto.make_ip_packet_with_ports_data::<I>(
4990            I::SRC_IP_2,
4991            I::DST_IP_2,
4992            SRC_PORT,
4993            DST_PORT,
4994            &[0xAB; LEN],
4995        );
4996
4997        // Try with a truncated and full body to make sure we don't fail when a
4998        // partial payload is present.
4999        if truncate_message {
5000            expected_payload_bytes.truncate(1280);
5001        }
5002
5003        let expected_serializer = IE::make_serializer(I::SRC_IP, I::DST_IP, expected_payload_bytes)
5004            // We never updated the outer IPs, so they should still be
5005            // their original values.
5006            .wrap_in(I::PacketBuilder::new(I::SRC_IP, I::DST_IP, u8::MAX, IE::proto()));
5007
5008        let actual_bytes = serializer
5009            .serialize_vec_outer(&mut NetworkSerializationContext::default())
5010            .unwrap()
5011            .unwrap_b();
5012        let expected_bytes = expected_serializer
5013            .serialize_vec_outer(&mut NetworkSerializationContext::default())
5014            .unwrap()
5015            .unwrap_b();
5016
5017        assert_eq!(actual_bytes, expected_bytes);
5018    }
5019
5020    #[test_matrix(
5021        [
5022            PhantomData::<Icmpv4DestUnreachableError>,
5023            PhantomData::<Icmpv6DestUnreachableError>,
5024        ],
5025        [
5026            TransportPacketDataProtocol::Udp,
5027            TransportPacketDataProtocol::Tcp,
5028            TransportPacketDataProtocol::IcmpEchoRequest,
5029        ],
5030        [
5031            PacketType::FullyParsed,
5032            PacketType::Raw,
5033        ],
5034        [
5035            false,
5036            true,
5037        ]
5038    )]
5039    fn icmp_error_mut_from_bytes<I: TestIpExt, IE: IcmpErrorMessage<I>>(
5040        _icmp_error: PhantomData<IE>,
5041        proto: TransportPacketDataProtocol,
5042        packet_type: PacketType,
5043        truncate_message: bool,
5044    ) where
5045        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
5046    {
5047        const LEN: usize = 5000;
5048
5049        let mut payload_bytes = proto.make_ip_packet_with_ports_data::<I>(
5050            I::SRC_IP,
5051            I::DST_IP,
5052            SRC_PORT,
5053            DST_PORT,
5054            &[0xAB; LEN],
5055        );
5056
5057        // Try with a truncated and full body to make sure we don't fail when a
5058        // partial payload is present.
5059        if truncate_message {
5060            payload_bytes.truncate(1280);
5061        }
5062
5063        let serializer = IE::make_serializer(I::SRC_IP, I::DST_IP, payload_bytes)
5064            .wrap_in(I::PacketBuilder::new(I::SRC_IP, I::DST_IP, u8::MAX, IE::proto()));
5065
5066        let mut bytes = serializer
5067            .serialize_vec_outer(&mut NetworkSerializationContext::default())
5068            .unwrap()
5069            .unwrap_b()
5070            .into_inner();
5071
5072        {
5073            fn modify_packet<I: TestIpExt, P: IpPacket<I>>(mut packet: P) {
5074                let mut icmp_error = packet.icmp_error_mut();
5075                let mut icmp_error =
5076                    icmp_error.icmp_error_mut().expect("couldn't find an inner ICMP error");
5077
5078                {
5079                    let mut inner_packet = icmp_error.inner_packet().expect("no inner packet");
5080
5081                    inner_packet.set_src_addr(I::SRC_IP_2);
5082                    inner_packet.set_dst_addr(I::DST_IP_2);
5083                }
5084
5085                assert!(icmp_error.recalculate_checksum());
5086            }
5087
5088            let mut bytes = Buf::new(&mut bytes, ..);
5089
5090            match packet_type {
5091                PacketType::FullyParsed => {
5092                    let packet =
5093                        I::as_filter_packet_owned(bytes.parse_mut::<I::Packet<_>>().unwrap());
5094                    modify_packet(packet);
5095                }
5096                PacketType::Raw => {
5097                    let packet = I::as_filter_packet_raw_owned(
5098                        bytes.parse_mut::<I::PacketRaw<_>>().unwrap(),
5099                    );
5100                    modify_packet(packet);
5101                }
5102            }
5103        }
5104
5105        let mut expected_payload_bytes = proto.make_ip_packet_with_ports_data::<I>(
5106            I::SRC_IP_2,
5107            I::DST_IP_2,
5108            SRC_PORT,
5109            DST_PORT,
5110            &[0xAB; LEN],
5111        );
5112
5113        if truncate_message {
5114            expected_payload_bytes.truncate(1280);
5115        }
5116
5117        let expected_serializer = IE::make_serializer(I::SRC_IP, I::DST_IP, expected_payload_bytes)
5118            // We never updated the outer IPs, so they should still be
5119            // their original values.
5120            .wrap_in(I::PacketBuilder::new(I::SRC_IP, I::DST_IP, u8::MAX, IE::proto()));
5121
5122        let expected_bytes = expected_serializer
5123            .serialize_vec_outer(&mut NetworkSerializationContext::default())
5124            .unwrap()
5125            .unwrap_b()
5126            .into_inner();
5127
5128        assert_eq!(bytes, expected_bytes);
5129    }
5130
5131    #[ip_test(I)]
5132    #[test_case(PhantomData::<Udp>)]
5133    #[test_case(PhantomData::<Tcp>)]
5134    #[test_case(PhantomData::<IcmpEchoRequest>)]
5135    fn tx_packet_partial_serialize<I: TestIpExt, P: Protocol>(_proto: PhantomData<P>) {
5136        const DATA: &[u8] = b"Packet Body";
5137        let mut body =
5138            P::make_serializer_with_ports_data::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT, DATA);
5139        let packet = TxPacket::<I, _>::new(I::SRC_IP, I::DST_IP, P::proto::<I>(), &mut body);
5140
5141        let (buf, total_size) = PartialSerializer::partial_serialize_new_buf(
5142            &packet,
5143            &mut NetworkSerializationContext::default(),
5144            PacketConstraints::UNCONSTRAINED,
5145            packet::new_buf_vec,
5146        )
5147        .unwrap();
5148
5149        let whole_packet =
5150            P::make_serializer_with_ports_data::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT, DATA)
5151                .wrap_in(I::PacketBuilder::new(
5152                    I::SRC_IP,
5153                    I::DST_IP,
5154                    TX_PACKET_NO_TTL,
5155                    P::proto::<I>(),
5156                ))
5157                .serialize_vec_outer(&mut NetworkSerializationContext::default())
5158                .expect("serialize packet")
5159                .unwrap_b()
5160                .into_inner();
5161
5162        let headers_size = I::MIN_HEADER_LENGTH + P::HEADER_SIZE;
5163        assert_eq!(total_size, whole_packet.len());
5164        assert_eq!(buf.len(), headers_size);
5165
5166        // Count the number of bytes that are different in the partially
5167        // serialized packet headers.
5168        let num_bytes_differ = buf
5169            .as_ref()
5170            .iter()
5171            .zip(whole_packet[..headers_size].iter())
5172            .map(|(a, b)| if a != b { 1 } else { 0 })
5173            .sum::<usize>();
5174
5175        // Partial serializer doesn't calculate packet checksum. IPv6 header
5176        // doesn't contain a checksum, but IPv4 header and transport layer
5177        // headers contain 2 bytes for checksum each. Only these bytes may
5178        // differ from a fully-serialized packet.
5179        let checksum_bytes = I::map_ip((), |()| 4, |()| 2);
5180        assert!(num_bytes_differ <= checksum_bytes);
5181    }
5182
5183    #[ip_test(I)]
5184    #[test_case(PhantomData::<Udp>)]
5185    #[test_case(PhantomData::<Tcp>)]
5186    #[test_case(PhantomData::<IcmpEchoRequest>)]
5187    fn tx_packet_raw_ip_body_partial_serialize<I: TestIpExt, P: Protocol>(_proto: PhantomData<P>) {
5188        const DATA: &[u8] = b"Packet Body";
5189        let body_bytes =
5190            P::make_serializer_with_ports_data::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT, DATA)
5191                .serialize_vec_outer(&mut NetworkSerializationContext::default())
5192                .unwrap()
5193                .unwrap_b()
5194                .into_inner();
5195        let body_bytes_len = body_bytes.len();
5196        let mut body =
5197            RawIpBody::new(P::proto::<I>(), I::SRC_IP, I::DST_IP, Buf::new(body_bytes.clone(), ..));
5198        let packet = TxPacket::<I, _>::new(I::SRC_IP, I::DST_IP, P::proto::<I>(), &mut body);
5199
5200        let (buf, total_size) = PartialSerializer::partial_serialize_new_buf(
5201            &packet,
5202            &mut NetworkSerializationContext::default(),
5203            PacketConstraints::UNCONSTRAINED,
5204            packet::new_buf_vec,
5205        )
5206        .unwrap();
5207
5208        let whole_packet = Buf::new(body_bytes, ..)
5209            .wrap_in(I::PacketBuilder::new(I::SRC_IP, I::DST_IP, TX_PACKET_NO_TTL, P::proto::<I>()))
5210            .serialize_vec_outer(&mut NetworkSerializationContext::default())
5211            .expect("serialize packet")
5212            .unwrap_b()
5213            .into_inner();
5214
5215        let headers_size =
5216            I::MIN_HEADER_LENGTH + cmp::min(body_bytes_len, TRANSPORT_HEADER_MAX_SIZE);
5217        assert_eq!(total_size, whole_packet.len());
5218        assert_eq!(buf.len(), headers_size);
5219
5220        // Count the number of bytes that are different in the partially
5221        // serialized packet headers.
5222        let num_bytes_differ = buf
5223            .as_ref()
5224            .iter()
5225            .zip(whole_packet[..headers_size].iter())
5226            .map(|(a, b)| if a != b { 1 } else { 0 })
5227            .sum::<usize>();
5228
5229        // Partial serializer doesn't calculate packet checksum. IPv6 header
5230        // doesn't contain a checksum, but IPv4 header contains 2 bytes for checksum.
5231        // The transport header checksum is already calculated because we fully
5232        // serialized it to put in RawIpBody.
5233        let checksum_bytes = I::map_ip((), |()| 2, |()| 0);
5234        assert!(num_bytes_differ <= checksum_bytes);
5235    }
5236
5237    #[ip_test(I)]
5238    #[test_case(PhantomData::<Udp>)]
5239    #[test_case(PhantomData::<Tcp>)]
5240    #[test_case(PhantomData::<IcmpEchoRequest>)]
5241    fn forwarded_packet_partial_serialize<I: TestIpExt, P: Protocol>(_proto: PhantomData<P>) {
5242        let mut packet_buf = ip_packet::<I, P>(I::SRC_IP, I::DST_IP);
5243        let packet_bytes = packet_buf.to_flattened_vec();
5244        let meta = packet_buf.parse::<I::Packet<_>>().expect("parse IP packet").parse_metadata();
5245        let packet = ForwardedPacket::<I, _>::new(
5246            I::SRC_IP,
5247            I::DST_IP,
5248            P::proto::<I>(),
5249            meta,
5250            packet_buf,
5251            false,
5252        );
5253
5254        let result = packet
5255            .partial_serialize(&mut NetworkSerializationContext::default(), packet::new_buf_vec)
5256            .unwrap();
5257        assert_eq!(result, PartialSerializeResult::Slice(&packet_bytes[..]));
5258
5259        let (buf, total_size) = PartialSerializer::partial_serialize_new_buf(
5260            &packet,
5261            &mut NetworkSerializationContext::default(),
5262            PacketConstraints::UNCONSTRAINED,
5263            packet::new_buf_vec,
5264        )
5265        .unwrap();
5266
5267        let expected_len =
5268            cmp::min(packet_bytes.len(), meta.header_len() + TRANSPORT_HEADER_MAX_SIZE);
5269        assert_eq!(total_size, packet_bytes.len());
5270        assert_eq!(buf.as_ref(), &packet_bytes[..expected_len]);
5271    }
5272}