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