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