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