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