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