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