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