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