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::num::NonZeroU16;
8
9use net_types::ip::{GenericOverIp, Ip, IpAddress, IpInvariant, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
10use netstack3_base::{Options, PayloadLen, SegmentHeader};
11use packet::records::options::OptionSequenceBuilder;
12use packet::{
13    Buf, BufferAlloc, BufferMut, BufferProvider, BufferViewMut, EitherSerializer, EmptyBuf,
14    GrowBufferMut, InnerSerializer, Nested, PacketConstraints, ParsablePacket, ParseBuffer,
15    ParseMetadata, ReusableBuffer, SerializeError, Serializer, SliceBufViewMut,
16};
17use packet_formats::icmp::mld::{
18    MulticastListenerDone, MulticastListenerQuery, MulticastListenerQueryV2,
19    MulticastListenerReport, MulticastListenerReportV2,
20};
21use packet_formats::icmp::ndp::options::NdpOptionBuilder;
22use packet_formats::icmp::ndp::{
23    NeighborAdvertisement, NeighborSolicitation, Redirect, RouterAdvertisement, RouterSolicitation,
24};
25use packet_formats::icmp::{
26    self, IcmpDestUnreachable, IcmpEchoReply, IcmpEchoRequest, IcmpPacketBuilder, IcmpPacketRaw,
27    IcmpPacketTypeRaw as _, IcmpTimeExceeded, Icmpv4MessageType, Icmpv4PacketRaw,
28    Icmpv4ParameterProblem, Icmpv4Redirect, Icmpv4TimestampReply, Icmpv4TimestampRequest,
29    Icmpv6MessageType, Icmpv6PacketRaw, Icmpv6PacketTooBig, Icmpv6ParameterProblem,
30};
31use packet_formats::igmp::messages::IgmpMembershipReportV3Builder;
32use packet_formats::igmp::{self, IgmpPacketBuilder};
33use packet_formats::ip::{IpExt, IpPacket as _, IpPacketBuilder, IpProto, Ipv4Proto, Ipv6Proto};
34use packet_formats::ipv4::{Ipv4Packet, Ipv4PacketRaw};
35use packet_formats::ipv6::{Ipv6Packet, Ipv6PacketRaw};
36use packet_formats::tcp::options::TcpOption;
37use packet_formats::tcp::{TcpParseArgs, TcpSegment, TcpSegmentBuilderWithOptions, TcpSegmentRaw};
38use packet_formats::udp::{UdpPacket, UdpPacketBuilder, UdpPacketRaw, UdpParseArgs};
39use zerocopy::{SplitByteSlice, SplitByteSliceMut};
40
41/// An IP extension trait for the filtering crate.
42pub trait FilterIpExt: IpExt {
43    /// A marker type to add an [`IpPacket`] bound to [`Self::Packet`].
44    type FilterIpPacket<B: SplitByteSliceMut>: IpPacket<Self>;
45
46    /// A no-op conversion to help the compiler identify that [`Self::Packet`]
47    /// actually implements [`IpPacket`].
48    fn as_filter_packet<B: SplitByteSliceMut>(
49        packet: &mut Self::Packet<B>,
50    ) -> &mut Self::FilterIpPacket<B>;
51}
52
53impl FilterIpExt for Ipv4 {
54    type FilterIpPacket<B: SplitByteSliceMut> = Ipv4Packet<B>;
55
56    #[inline]
57    fn as_filter_packet<B: SplitByteSliceMut>(packet: &mut Ipv4Packet<B>) -> &mut Ipv4Packet<B> {
58        packet
59    }
60}
61
62impl FilterIpExt for Ipv6 {
63    type FilterIpPacket<B: SplitByteSliceMut> = Ipv6Packet<B>;
64
65    #[inline]
66    fn as_filter_packet<B: SplitByteSliceMut>(packet: &mut Ipv6Packet<B>) -> &mut Ipv6Packet<B> {
67        packet
68    }
69}
70
71/// An IP packet that provides header inspection.
72pub trait IpPacket<I: IpExt> {
73    /// The type that provides access to transport-layer header inspection, if a
74    /// transport header is contained in the body of the IP packet.
75    type TransportPacket<'a>: MaybeTransportPacket
76    where
77        Self: 'a;
78
79    /// The type that provides access to transport-layer header modification, if a
80    /// transport header is contained in the body of the IP packet.
81    type TransportPacketMut<'a>: MaybeTransportPacketMut<I>
82    where
83        Self: 'a;
84
85    /// The source IP address of the packet.
86    fn src_addr(&self) -> I::Addr;
87
88    /// Sets the source IP address of the packet.
89    fn set_src_addr(&mut self, addr: I::Addr);
90
91    /// The destination IP address of the packet.
92    fn dst_addr(&self) -> I::Addr;
93
94    /// Sets the destination IP address of the packet.
95    fn set_dst_addr(&mut self, addr: I::Addr);
96
97    /// The IP protocol of the packet.
98    fn protocol(&self) -> I::Proto;
99
100    /// Returns a type that provides access to the transport-layer packet contained
101    /// in the body of the IP packet, if one exists.
102    ///
103    /// This method returns an owned type parameterized on a lifetime that is tied
104    /// to the lifetime of Self, rather than, for example, a reference to a
105    /// non-parameterized type (`&Self::TransportPacket`). This is because
106    /// implementors may need to parse the transport header from the body of the IP
107    /// packet and materialize the results into a new type when this is called, but
108    /// that type may also need to retain a reference to the backing buffer in order
109    /// to modify the transport header.
110    fn maybe_transport_packet<'a>(&'a self) -> Self::TransportPacket<'a>;
111
112    /// Returns a type that provides the ability to modify the transport-layer
113    /// packet contained in the body of the IP packet, if one exists.
114    ///
115    /// This method returns an owned type parameterized on a lifetime that is tied
116    /// to the lifetime of Self, rather than, for example, a reference to a
117    /// non-parameterized type (`&Self::TransportPacketMut`). This is because
118    /// implementors may need to parse the transport header from the body of the IP
119    /// packet and materialize the results into a new type when this is called, but
120    /// that type may also need to retain a reference to the backing buffer in order
121    /// to modify the transport header.
122    fn transport_packet_mut<'a>(&'a mut self) -> Self::TransportPacketMut<'a>;
123}
124
125/// A payload of an IP packet that may be a valid transport layer packet.
126///
127/// This trait exists to allow bubbling up the trait bound that a serializer
128/// type implement `MaybeTransportPacket` from the IP socket layer to upper
129/// layers, where it can be implemented separately on each concrete packet type
130/// depending on whether it supports packet header inspection.
131pub trait MaybeTransportPacket {
132    /// Optionally returns a type that provides access to this transport-layer
133    /// packet.
134    fn transport_packet_data(&self) -> Option<TransportPacketData>;
135}
136
137/// A payload of an IP packet that may be a valid modifiable transport layer
138/// packet.
139///
140/// This trait exists to allow bubbling up the trait bound that a serializer
141/// type implement `MaybeTransportPacketMut` from the IP socket layer to upper
142/// layers, where it can be implemented separately on each concrete packet type
143/// depending on whether it supports packet header modification.
144pub trait MaybeTransportPacketMut<I: IpExt> {
145    /// The type that provides access to transport-layer header modification, if
146    /// this is indeed a valid transport packet.
147    type TransportPacketMut<'a>: TransportPacketMut<I>
148    where
149        Self: 'a;
150
151    /// Optionally returns a type that provides mutable access to this
152    /// transport-layer packet.
153    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>>;
154}
155
156/// A serializer that may also be a valid transport layer packet.
157pub trait TransportPacketSerializer<I: IpExt>:
158    Serializer + MaybeTransportPacket + MaybeTransportPacketMut<I>
159{
160}
161
162impl<I, S> TransportPacketSerializer<I> for S
163where
164    I: IpExt,
165    S: Serializer + MaybeTransportPacket + MaybeTransportPacketMut<I>,
166{
167}
168
169impl<T: ?Sized> MaybeTransportPacket for &T
170where
171    T: MaybeTransportPacket,
172{
173    fn transport_packet_data(&self) -> Option<TransportPacketData> {
174        (**self).transport_packet_data()
175    }
176}
177
178impl<T: ?Sized> MaybeTransportPacket for &mut T
179where
180    T: MaybeTransportPacket,
181{
182    fn transport_packet_data(&self) -> Option<TransportPacketData> {
183        (**self).transport_packet_data()
184    }
185}
186
187impl<I: IpExt, T: ?Sized> MaybeTransportPacketMut<I> for &mut T
188where
189    T: MaybeTransportPacketMut<I>,
190{
191    type TransportPacketMut<'a>
192        = T::TransportPacketMut<'a>
193    where
194        Self: 'a;
195
196    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
197        (**self).transport_packet_mut()
198    }
199}
200
201impl<I: IpExt, T: TransportPacketMut<I>> MaybeTransportPacketMut<I> for Option<T> {
202    type TransportPacketMut<'a>
203        = &'a mut T
204    where
205        Self: 'a;
206
207    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
208        self.as_mut()
209    }
210}
211
212/// A concrete enum to hold all of the transport packet data that could possibly be usefully
213/// extracted from a packet.
214#[derive(Debug, Clone, GenericOverIp, PartialEq, Eq)]
215#[generic_over_ip()]
216pub enum TransportPacketData {
217    Tcp { src_port: u16, dst_port: u16, segment: SegmentHeader, payload_len: usize },
218    Generic { src_port: u16, dst_port: u16 },
219}
220
221impl TransportPacketData {
222    pub fn src_port(&self) -> u16 {
223        match self {
224            TransportPacketData::Tcp { src_port, .. }
225            | TransportPacketData::Generic { src_port, .. } => *src_port,
226        }
227    }
228
229    pub fn dst_port(&self) -> u16 {
230        match self {
231            TransportPacketData::Tcp { dst_port, .. }
232            | TransportPacketData::Generic { dst_port, .. } => *dst_port,
233        }
234    }
235
236    pub fn tcp_segment_and_len(&self) -> Option<(&SegmentHeader, usize)> {
237        match self {
238            TransportPacketData::Tcp { segment, payload_len, .. } => Some((&segment, *payload_len)),
239            TransportPacketData::Generic { .. } => None,
240        }
241    }
242
243    fn parse_in_ip_packet<I: IpExt, B: ParseBuffer>(
244        src_ip: I::Addr,
245        dst_ip: I::Addr,
246        proto: I::Proto,
247        body: B,
248    ) -> Option<TransportPacketData> {
249        I::map_ip(
250            (src_ip, dst_ip, proto, IpInvariant(body)),
251            |(src_ip, dst_ip, proto, IpInvariant(body))| {
252                parse_transport_header_in_ipv4_packet(src_ip, dst_ip, proto, body)
253            },
254            |(src_ip, dst_ip, proto, IpInvariant(body))| {
255                parse_transport_header_in_ipv6_packet(src_ip, dst_ip, proto, body)
256            },
257        )
258    }
259}
260
261/// A transport layer packet that provides header modification.
262//
263// TODO(https://fxbug.dev/341128580): make this trait more expressive for the
264// differences between transport protocols.
265pub trait TransportPacketMut<I: IpExt> {
266    /// Set the source port or identifier of the packet.
267    fn set_src_port(&mut self, port: NonZeroU16);
268
269    /// Set the destination port or identifier of the packet.
270    fn set_dst_port(&mut self, port: NonZeroU16);
271
272    /// Update the source IP address in the pseudo header.
273    fn update_pseudo_header_src_addr(&mut self, old: I::Addr, new: I::Addr);
274
275    /// Update the destination IP address in the pseudo header.
276    fn update_pseudo_header_dst_addr(&mut self, old: I::Addr, new: I::Addr);
277}
278
279impl<B: SplitByteSliceMut> IpPacket<Ipv4> for Ipv4Packet<B> {
280    type TransportPacket<'a>
281        = &'a Self
282    where
283        Self: 'a;
284    type TransportPacketMut<'a>
285        = Option<ParsedTransportHeaderMut<'a, Ipv4>>
286    where
287        B: 'a;
288
289    fn src_addr(&self) -> Ipv4Addr {
290        self.src_ip()
291    }
292
293    fn set_src_addr(&mut self, addr: Ipv4Addr) {
294        let old = self.src_addr();
295        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
296            packet.update_pseudo_header_src_addr(old, addr);
297        }
298        // NB: it is important that we do not update the IP layer header until
299        // after parsing the transport header, because if we change the source
300        // address in the IP header and then attempt to parse the transport
301        // header using that address for checksum validation, parsing will fail.
302        //
303        // TODO(https://fxbug.dev/341340810): use raw packet parsing for all
304        // transport header updates, which is less expensive and would allow
305        // updating the IP and transport headers to be order-independent.
306        self.set_src_ip_and_update_checksum(addr);
307    }
308
309    fn dst_addr(&self) -> Ipv4Addr {
310        self.dst_ip()
311    }
312
313    fn set_dst_addr(&mut self, addr: Ipv4Addr) {
314        let old = self.dst_addr();
315        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
316            packet.update_pseudo_header_dst_addr(old, addr);
317        }
318        // NB: it is important that we do not update the IP layer header until
319        // after parsing the transport header, because if we change the
320        // destination address in the IP header and then attempt to parse the
321        // transport header using that address for checksum validation, parsing
322        // will fail.
323        //
324        // TODO(https://fxbug.dev/341340810): use raw packet parsing for all
325        // transport header updates, which is less expensive and would allow
326        // updating the IP and transport headers to be order-independent.
327        self.set_dst_ip_and_update_checksum(addr);
328    }
329
330    fn protocol(&self) -> Ipv4Proto {
331        self.proto()
332    }
333
334    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
335        self
336    }
337
338    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
339        ParsedTransportHeaderMut::parse_in_ipv4_packet(
340            self.src_ip(),
341            self.dst_ip(),
342            self.proto(),
343            SliceBufViewMut::new(self.body_mut()),
344        )
345    }
346}
347
348impl<B: SplitByteSlice> MaybeTransportPacket for Ipv4Packet<B> {
349    fn transport_packet_data(&self) -> Option<TransportPacketData> {
350        parse_transport_header_in_ipv4_packet(
351            self.src_ip(),
352            self.dst_ip(),
353            self.proto(),
354            self.body(),
355        )
356    }
357}
358
359impl<B: SplitByteSliceMut> IpPacket<Ipv6> for Ipv6Packet<B> {
360    type TransportPacket<'a>
361        = &'a Self
362    where
363        Self: 'a;
364    type TransportPacketMut<'a>
365        = Option<ParsedTransportHeaderMut<'a, Ipv6>>
366    where
367        B: 'a;
368
369    fn src_addr(&self) -> Ipv6Addr {
370        self.src_ip()
371    }
372
373    fn set_src_addr(&mut self, addr: Ipv6Addr) {
374        let old = self.src_addr();
375        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
376            packet.update_pseudo_header_src_addr(old, addr);
377        }
378        // NB: it is important that we do not update the IP layer header until
379        // after parsing the transport header, because if we change the source
380        // address in the IP header and then attempt to parse the transport
381        // header using that address for checksum validation, parsing will fail.
382        //
383        // TODO(https://fxbug.dev/341340810): use raw packet parsing for all
384        // transport header updates, which is less expensive and would allow
385        // updating the IP and transport headers to be order-independent.
386        self.set_src_ip(addr);
387    }
388
389    fn dst_addr(&self) -> Ipv6Addr {
390        self.dst_ip()
391    }
392
393    fn set_dst_addr(&mut self, addr: Ipv6Addr) {
394        let old = self.dst_addr();
395        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
396            packet.update_pseudo_header_dst_addr(old, addr);
397        }
398        // NB: it is important that we do not update the IP layer header until
399        // after parsing the transport header, because if we change the
400        // destination address in the IP header and then attempt to parse the
401        // transport header using that address for checksum validation, parsing
402        // will fail.
403        //
404        // TODO(https://fxbug.dev/341340810): use raw packet parsing for all
405        // transport header updates, which is less expensive and would allow
406        // updating the IP and transport headers to be order-independent.
407        self.set_dst_ip(addr);
408    }
409
410    fn protocol(&self) -> Ipv6Proto {
411        self.proto()
412    }
413
414    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
415        self
416    }
417
418    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
419        ParsedTransportHeaderMut::parse_in_ipv6_packet(
420            self.src_ip(),
421            self.dst_ip(),
422            self.proto(),
423            SliceBufViewMut::new(self.body_mut()),
424        )
425    }
426}
427
428impl<B: SplitByteSlice> MaybeTransportPacket for Ipv6Packet<B> {
429    fn transport_packet_data(&self) -> Option<TransportPacketData> {
430        parse_transport_header_in_ipv6_packet(
431            self.src_ip(),
432            self.dst_ip(),
433            self.proto(),
434            self.body(),
435        )
436    }
437}
438
439/// An outgoing IP packet that has not yet been wrapped into an outer serializer
440/// type.
441#[derive(Debug, PartialEq, GenericOverIp)]
442#[generic_over_ip(I, Ip)]
443pub struct TxPacket<'a, I: IpExt, S> {
444    src_addr: I::Addr,
445    dst_addr: I::Addr,
446    protocol: I::Proto,
447    serializer: &'a mut S,
448}
449
450impl<'a, I: IpExt, S> TxPacket<'a, I, S> {
451    /// Create a new [`TxPacket`] from its IP header fields and payload.
452    pub fn new(
453        src_addr: I::Addr,
454        dst_addr: I::Addr,
455        protocol: I::Proto,
456        serializer: &'a mut S,
457    ) -> Self {
458        Self { src_addr, dst_addr, protocol, serializer }
459    }
460
461    /// The source IP address of the packet.
462    pub fn src_addr(&self) -> I::Addr {
463        self.src_addr
464    }
465
466    /// The destination IP address of the packet.
467    pub fn dst_addr(&self) -> I::Addr {
468        self.dst_addr
469    }
470}
471
472impl<I: IpExt, S: TransportPacketSerializer<I>> IpPacket<I> for TxPacket<'_, I, S> {
473    type TransportPacket<'a>
474        = &'a S
475    where
476        Self: 'a;
477    type TransportPacketMut<'a>
478        = &'a mut S
479    where
480        Self: 'a;
481
482    fn src_addr(&self) -> I::Addr {
483        self.src_addr
484    }
485
486    fn set_src_addr(&mut self, addr: I::Addr) {
487        let old = core::mem::replace(&mut self.src_addr, addr);
488        if let Some(mut packet) = self.transport_packet_mut().transport_packet_mut() {
489            packet.update_pseudo_header_src_addr(old, addr);
490        }
491    }
492
493    fn dst_addr(&self) -> I::Addr {
494        self.dst_addr
495    }
496
497    fn set_dst_addr(&mut self, addr: I::Addr) {
498        let old = core::mem::replace(&mut self.dst_addr, addr);
499        if let Some(mut packet) = self.transport_packet_mut().transport_packet_mut() {
500            packet.update_pseudo_header_dst_addr(old, addr);
501        }
502    }
503
504    fn protocol(&self) -> I::Proto {
505        self.protocol
506    }
507
508    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
509        self.serializer
510    }
511
512    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
513        self.serializer
514    }
515}
516
517/// An incoming IP packet that is being forwarded.
518#[derive(Debug, PartialEq, GenericOverIp)]
519#[generic_over_ip(I, Ip)]
520pub struct ForwardedPacket<I: IpExt, B> {
521    src_addr: I::Addr,
522    dst_addr: I::Addr,
523    protocol: I::Proto,
524    transport_header_offset: usize,
525    buffer: B,
526}
527
528impl<I: IpExt, B: BufferMut> ForwardedPacket<I, B> {
529    /// Create a new [`ForwardedPacket`] from its IP header fields and payload.
530    ///
531    /// `meta` is used to revert `buffer` back to the IP header for further
532    /// serialization, and to mark where the transport header starts in
533    /// `buffer`. It _must_ have originated from a previously parsed IP packet
534    /// on `buffer`.
535    pub fn new(
536        src_addr: I::Addr,
537        dst_addr: I::Addr,
538        protocol: I::Proto,
539        meta: ParseMetadata,
540        mut buffer: B,
541    ) -> Self {
542        let transport_header_offset = meta.header_len();
543        buffer.undo_parse(meta);
544        Self { src_addr, dst_addr, protocol, transport_header_offset, buffer }
545    }
546
547    /// Discard the metadata carried by the [`ForwardedPacket`] and return the
548    /// inner buffer.
549    ///
550    /// The returned buffer is guaranteed to contain a valid IP frame, the
551    /// start of the buffer points at the start of the IP header.
552    pub fn into_buffer(self) -> B {
553        self.buffer
554    }
555
556    /// Returns a reference to the forwarded buffer.
557    ///
558    /// The returned reference is guaranteed to contain a valid IP frame, the
559    /// start of the buffer points at the start of the IP header.
560    pub fn buffer(&self) -> &B {
561        &self.buffer
562    }
563}
564
565impl<I: IpExt, B: BufferMut> Serializer for ForwardedPacket<I, B> {
566    type Buffer = <B as Serializer>::Buffer;
567
568    fn serialize<G: packet::GrowBufferMut, P: packet::BufferProvider<Self::Buffer, G>>(
569        self,
570        outer: packet::PacketConstraints,
571        provider: P,
572    ) -> Result<G, (packet::SerializeError<P::Error>, Self)> {
573        let Self { src_addr, dst_addr, protocol, transport_header_offset, buffer } = self;
574        buffer.serialize(outer, provider).map_err(|(err, buffer)| {
575            (err, Self { src_addr, dst_addr, protocol, transport_header_offset, buffer })
576        })
577    }
578
579    fn serialize_new_buf<BB: packet::ReusableBuffer, A: packet::BufferAlloc<BB>>(
580        &self,
581        outer: packet::PacketConstraints,
582        alloc: A,
583    ) -> Result<BB, packet::SerializeError<A::Error>> {
584        self.buffer.serialize_new_buf(outer, alloc)
585    }
586}
587
588impl<I: IpExt, B: BufferMut> IpPacket<I> for ForwardedPacket<I, B> {
589    type TransportPacket<'a>
590        = &'a Self
591    where
592        Self: 'a;
593    type TransportPacketMut<'a>
594        = Option<ParsedTransportHeaderMut<'a, I>>
595    where
596        Self: 'a;
597
598    fn src_addr(&self) -> I::Addr {
599        self.src_addr
600    }
601
602    fn set_src_addr(&mut self, addr: I::Addr) {
603        // Re-parse the IP header so we can modify it in place.
604        I::map_ip::<_, ()>(
605            (IpInvariant(self.buffer.as_mut()), addr),
606            |(IpInvariant(buffer), addr)| {
607                let mut packet = Ipv4PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
608                    .expect("ForwardedPacket must have been created from a valid IP packet");
609                packet.set_src_ip_and_update_checksum(addr);
610            },
611            |(IpInvariant(buffer), addr)| {
612                let mut packet = Ipv6PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
613                    .expect("ForwardedPacket must have been created from a valid IP packet");
614                packet.set_src_ip(addr);
615            },
616        );
617
618        let old = self.src_addr;
619        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
620            packet.update_pseudo_header_src_addr(old, addr);
621        }
622        // NB: it is important that we do not update this until after parsing
623        // the transport header, because if we change the source address and
624        // then attempt to parse the transport header using that address for
625        // checksum validation, parsing will fail.
626        //
627        // TODO(https://fxbug.dev/341340810): use raw packet parsing for all
628        // transport header updates, which is less expensive and would allow
629        // updating the IP and transport headers to be order-independent.
630        self.src_addr = addr;
631    }
632
633    fn dst_addr(&self) -> I::Addr {
634        self.dst_addr
635    }
636
637    fn set_dst_addr(&mut self, addr: I::Addr) {
638        // Re-parse the IP header so we can modify it in place.
639        I::map_ip::<_, ()>(
640            (IpInvariant(self.buffer.as_mut()), addr),
641            |(IpInvariant(buffer), addr)| {
642                let mut packet = Ipv4PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
643                    .expect("ForwardedPacket must have been created from a valid IP packet");
644                packet.set_dst_ip_and_update_checksum(addr);
645            },
646            |(IpInvariant(buffer), addr)| {
647                let mut packet = Ipv6PacketRaw::parse_mut(SliceBufViewMut::new(buffer), ())
648                    .expect("ForwardedPacket must have been created from a valid IP packet");
649                packet.set_dst_ip(addr);
650            },
651        );
652
653        let old = self.dst_addr;
654        if let Some(packet) = self.transport_packet_mut().transport_packet_mut() {
655            packet.update_pseudo_header_dst_addr(old, addr);
656        }
657        // NB: it is important that we do not update this until after parsing
658        // the transport header, because if we change the destination address
659        // and then attempt to parse the transport header using that address for
660        // checksum validation, parsing will fail.
661        //
662        // TODO(https://fxbug.dev/341340810): use raw packet parsing for all
663        // transport header updates, which is less expensive and would allow
664        // updating the IP and transport headers to be order-independent.
665        self.dst_addr = addr;
666    }
667
668    fn protocol(&self) -> I::Proto {
669        self.protocol
670    }
671
672    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
673        self
674    }
675
676    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
677        let ForwardedPacket { src_addr, dst_addr, protocol, buffer, transport_header_offset } =
678            self;
679        ParsedTransportHeaderMut::<I>::parse_in_ip_packet(
680            *src_addr,
681            *dst_addr,
682            *protocol,
683            SliceBufViewMut::new(&mut buffer.as_mut()[*transport_header_offset..]),
684        )
685    }
686}
687
688impl<I: IpExt, B: BufferMut> MaybeTransportPacket for ForwardedPacket<I, B> {
689    fn transport_packet_data(&self) -> Option<TransportPacketData> {
690        let ForwardedPacket { protocol, buffer, src_addr, dst_addr, transport_header_offset } =
691            self;
692        TransportPacketData::parse_in_ip_packet::<I, _>(
693            *src_addr,
694            *dst_addr,
695            *protocol,
696            Buf::new(&buffer.as_ref()[*transport_header_offset..], ..),
697        )
698    }
699}
700
701impl<I: IpExt, S: TransportPacketSerializer<I>, B: IpPacketBuilder<I>> IpPacket<I>
702    for Nested<S, B>
703{
704    type TransportPacket<'a>
705        = &'a S
706    where
707        Self: 'a;
708    type TransportPacketMut<'a>
709        = &'a mut S
710    where
711        Self: 'a;
712
713    fn src_addr(&self) -> I::Addr {
714        self.outer().src_ip()
715    }
716
717    fn set_src_addr(&mut self, addr: I::Addr) {
718        let old = self.outer().src_ip();
719        self.outer_mut().set_src_ip(addr);
720        if let Some(mut packet) = self.transport_packet_mut().transport_packet_mut() {
721            packet.update_pseudo_header_src_addr(old, addr);
722        }
723    }
724
725    fn dst_addr(&self) -> I::Addr {
726        self.outer().dst_ip()
727    }
728
729    fn set_dst_addr(&mut self, addr: I::Addr) {
730        let old = self.outer().dst_ip();
731        self.outer_mut().set_dst_ip(addr);
732        if let Some(mut packet) = self.transport_packet_mut().transport_packet_mut() {
733            packet.update_pseudo_header_dst_addr(old, addr);
734        }
735    }
736
737    fn protocol(&self) -> I::Proto {
738        self.outer().proto()
739    }
740
741    fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
742        self.inner()
743    }
744
745    fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
746        self.inner_mut()
747    }
748}
749
750impl<I: IpExt, T: ?Sized> TransportPacketMut<I> for &mut T
751where
752    T: TransportPacketMut<I>,
753{
754    fn set_src_port(&mut self, port: NonZeroU16) {
755        (*self).set_src_port(port);
756    }
757
758    fn set_dst_port(&mut self, port: NonZeroU16) {
759        (*self).set_dst_port(port);
760    }
761
762    fn update_pseudo_header_src_addr(&mut self, old: I::Addr, new: I::Addr) {
763        (*self).update_pseudo_header_src_addr(old, new);
764    }
765
766    fn update_pseudo_header_dst_addr(&mut self, old: I::Addr, new: I::Addr) {
767        (*self).update_pseudo_header_dst_addr(old, new);
768    }
769}
770
771impl MaybeTransportPacket for Never {
772    fn transport_packet_data(&self) -> Option<TransportPacketData> {
773        match *self {}
774    }
775}
776
777impl<I: IpExt> MaybeTransportPacketMut<I> for Never {
778    type TransportPacketMut<'a>
779        = Never
780    where
781        Self: 'a;
782
783    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
784        match *self {}
785    }
786}
787
788impl<I: IpExt> TransportPacketMut<I> for Never {
789    fn set_src_port(&mut self, _: NonZeroU16) {
790        match *self {}
791    }
792
793    fn set_dst_port(&mut self, _: NonZeroU16) {
794        match *self {}
795    }
796
797    fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {
798        match *self {}
799    }
800
801    fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {
802        match *self {}
803    }
804}
805
806impl<A: IpAddress, Inner> MaybeTransportPacket for Nested<Inner, UdpPacketBuilder<A>> {
807    fn transport_packet_data(&self) -> Option<TransportPacketData> {
808        Some(TransportPacketData::Generic {
809            src_port: self.outer().src_port().map_or(0, NonZeroU16::get),
810            dst_port: self.outer().dst_port().map_or(0, NonZeroU16::get),
811        })
812    }
813}
814
815impl<I: IpExt, Inner> MaybeTransportPacketMut<I> for Nested<Inner, UdpPacketBuilder<I::Addr>> {
816    type TransportPacketMut<'a>
817        = &'a mut Self
818    where
819        Self: 'a;
820
821    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
822        Some(self)
823    }
824}
825
826impl<I: IpExt, Inner> TransportPacketMut<I> for Nested<Inner, UdpPacketBuilder<I::Addr>> {
827    fn set_src_port(&mut self, port: NonZeroU16) {
828        self.outer_mut().set_src_port(port.get());
829    }
830
831    fn set_dst_port(&mut self, port: NonZeroU16) {
832        self.outer_mut().set_dst_port(port);
833    }
834
835    fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
836        self.outer_mut().set_src_ip(new);
837    }
838
839    fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
840        self.outer_mut().set_dst_ip(new);
841    }
842}
843
844impl<'a, A: IpAddress, Inner: PayloadLen, I> MaybeTransportPacket
845    for Nested<Inner, TcpSegmentBuilderWithOptions<A, OptionSequenceBuilder<TcpOption<'a>, I>>>
846where
847    I: Iterator + Clone,
848    I::Item: Borrow<TcpOption<'a>>,
849{
850    fn transport_packet_data(&self) -> Option<TransportPacketData> {
851        Some(TransportPacketData::Tcp {
852            src_port: self.outer().src_port().map_or(0, NonZeroU16::get),
853            dst_port: self.outer().dst_port().map_or(0, NonZeroU16::get),
854            segment: self.outer().try_into().ok()?,
855            payload_len: self.inner().len(),
856        })
857    }
858}
859
860impl<I: IpExt, Outer, Inner> MaybeTransportPacketMut<I>
861    for Nested<Inner, TcpSegmentBuilderWithOptions<I::Addr, Outer>>
862{
863    type TransportPacketMut<'a>
864        = &'a mut Self
865    where
866        Self: 'a;
867
868    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
869        Some(self)
870    }
871}
872
873impl<I: IpExt, Outer, Inner> TransportPacketMut<I>
874    for Nested<Inner, TcpSegmentBuilderWithOptions<I::Addr, Outer>>
875{
876    fn set_src_port(&mut self, port: NonZeroU16) {
877        self.outer_mut().set_src_port(port);
878    }
879
880    fn set_dst_port(&mut self, port: NonZeroU16) {
881        self.outer_mut().set_dst_port(port);
882    }
883
884    fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
885        self.outer_mut().set_src_ip(new);
886    }
887
888    fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
889        self.outer_mut().set_dst_ip(new);
890    }
891}
892
893impl<I: IpExt, Inner, M: IcmpMessage<I>> MaybeTransportPacket
894    for Nested<Inner, IcmpPacketBuilder<I, M>>
895{
896    fn transport_packet_data(&self) -> Option<TransportPacketData> {
897        self.outer().message().transport_packet_data()
898    }
899}
900
901impl<I: IpExt, Inner, M: IcmpMessage<I>> MaybeTransportPacketMut<I>
902    for Nested<Inner, IcmpPacketBuilder<I, M>>
903{
904    type TransportPacketMut<'a>
905        = &'a mut IcmpPacketBuilder<I, M>
906    where
907        M: 'a,
908        Inner: 'a;
909
910    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
911        Some(self.outer_mut())
912    }
913}
914
915impl<I: IpExt, M: IcmpMessage<I>> TransportPacketMut<I> for IcmpPacketBuilder<I, M> {
916    fn set_src_port(&mut self, id: NonZeroU16) {
917        let _: u16 = self.message_mut().update_icmp_id(id.get());
918    }
919
920    fn set_dst_port(&mut self, id: NonZeroU16) {
921        let _: u16 = self.message_mut().update_icmp_id(id.get());
922    }
923
924    fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
925        self.set_src_ip(new);
926    }
927
928    fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
929        self.set_dst_ip(new);
930    }
931}
932
933/// An ICMP message type that may allow for transport-layer packet inspection.
934pub trait IcmpMessage<I: IpExt>: icmp::IcmpMessage<I> + MaybeTransportPacket {
935    /// Sets the ICMP ID for the message, returning the previous value.
936    ///
937    /// The ICMP ID is both the *src* AND *dst* ports for conntrack entries.
938    fn update_icmp_id(&mut self, id: u16) -> u16;
939}
940
941// TODO(https://fxbug.dev/341128580): connection tracking will probably want to
942// special case ICMP echo packets to ensure that a new connection is only ever
943// created from an echo request, and not an echo response. We need to provide a
944// way for conntrack to differentiate between the two.
945impl MaybeTransportPacket for IcmpEchoReply {
946    fn transport_packet_data(&self) -> Option<TransportPacketData> {
947        Some(TransportPacketData::Generic { src_port: self.id(), dst_port: self.id() })
948    }
949}
950
951impl<I: IpExt> IcmpMessage<I> for IcmpEchoReply {
952    fn update_icmp_id(&mut self, id: u16) -> u16 {
953        let old = self.id();
954        self.set_id(id);
955        old
956    }
957}
958
959// TODO(https://fxbug.dev/341128580): connection tracking will probably want to
960// special case ICMP echo packets to ensure that a new connection is only ever
961// created from an echo request, and not an echo response. We need to provide a
962// way for conntrack to differentiate between the two.
963impl MaybeTransportPacket for IcmpEchoRequest {
964    fn transport_packet_data(&self) -> Option<TransportPacketData> {
965        Some(TransportPacketData::Generic { src_port: self.id(), dst_port: self.id() })
966    }
967}
968
969impl<I: IpExt> IcmpMessage<I> for IcmpEchoRequest {
970    fn update_icmp_id(&mut self, id: u16) -> u16 {
971        let old = self.id();
972        self.set_id(id);
973        old
974    }
975}
976
977macro_rules! unsupported_icmp_message_type {
978    ($message:ty, $($ips:ty),+) => {
979        impl MaybeTransportPacket for $message {
980            fn transport_packet_data(&self) -> Option<TransportPacketData> {
981                None
982            }
983        }
984
985        $(
986            impl IcmpMessage<$ips> for $message {
987                fn update_icmp_id(&mut self, _: u16) -> u16 {
988                    unreachable!("non-echo ICMP packets should never be rewritten")
989                }
990            }
991        )+
992    };
993}
994
995unsupported_icmp_message_type!(Icmpv4TimestampRequest, Ipv4);
996unsupported_icmp_message_type!(Icmpv4TimestampReply, Ipv4);
997unsupported_icmp_message_type!(Icmpv4Redirect, Ipv4);
998unsupported_icmp_message_type!(NeighborSolicitation, Ipv6);
999unsupported_icmp_message_type!(NeighborAdvertisement, Ipv6);
1000unsupported_icmp_message_type!(RouterSolicitation, Ipv6);
1001unsupported_icmp_message_type!(MulticastListenerDone, Ipv6);
1002unsupported_icmp_message_type!(MulticastListenerReport, Ipv6);
1003unsupported_icmp_message_type!(MulticastListenerReportV2, Ipv6);
1004unsupported_icmp_message_type!(MulticastListenerQuery, Ipv6);
1005unsupported_icmp_message_type!(MulticastListenerQueryV2, Ipv6);
1006unsupported_icmp_message_type!(RouterAdvertisement, Ipv6);
1007unsupported_icmp_message_type!(Redirect, Ipv6);
1008
1009// Transport layer packet inspection is not currently supported for any ICMP
1010// error message types.
1011//
1012// TODO(https://fxbug.dev/328057704): parse the IP packet contained in the ICMP
1013// error message payload so NAT can be applied to it.
1014macro_rules! icmp_error_message {
1015    ($message:ty, $($ips:ty),+) => {
1016        unsupported_icmp_message_type!($message, $( $ips ),+);
1017    };
1018}
1019
1020icmp_error_message!(IcmpDestUnreachable, Ipv4, Ipv6);
1021icmp_error_message!(IcmpTimeExceeded, Ipv4, Ipv6);
1022icmp_error_message!(Icmpv4ParameterProblem, Ipv4);
1023icmp_error_message!(Icmpv6ParameterProblem, Ipv6);
1024icmp_error_message!(Icmpv6PacketTooBig, Ipv6);
1025
1026impl<M: igmp::MessageType<EmptyBuf>> MaybeTransportPacket
1027    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
1028{
1029    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1030        None
1031    }
1032}
1033
1034impl<M: igmp::MessageType<EmptyBuf>> MaybeTransportPacketMut<Ipv4>
1035    for InnerSerializer<IgmpPacketBuilder<EmptyBuf, M>, EmptyBuf>
1036{
1037    type TransportPacketMut<'a>
1038        = Never
1039    where
1040        M: 'a;
1041
1042    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1043        None
1044    }
1045}
1046
1047impl<I> MaybeTransportPacket for InnerSerializer<IgmpMembershipReportV3Builder<I>, EmptyBuf> {
1048    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1049        None
1050    }
1051}
1052
1053impl<I> MaybeTransportPacketMut<Ipv4>
1054    for InnerSerializer<IgmpMembershipReportV3Builder<I>, EmptyBuf>
1055{
1056    type TransportPacketMut<'a>
1057        = Never
1058    where
1059        I: 'a;
1060
1061    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1062        None
1063    }
1064}
1065
1066impl<I> MaybeTransportPacket
1067    for EitherSerializer<
1068        EmptyBuf,
1069        InnerSerializer<packet::records::RecordSequenceBuilder<NdpOptionBuilder<'_>, I>, EmptyBuf>,
1070    >
1071{
1072    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1073        None
1074    }
1075}
1076
1077/// An unsanitized IP packet body.
1078///
1079/// Allows packets from raw IP sockets (with a user provided IP body), to be
1080/// tracked from the filtering module.
1081#[derive(GenericOverIp)]
1082#[generic_over_ip(I, Ip)]
1083pub struct RawIpBody<I: IpExt, B: ParseBuffer> {
1084    /// The IANA protocol of the inner message. This may be, but is not required
1085    /// to be, a transport protocol.
1086    protocol: I::Proto,
1087    /// The source IP addr of the packet. Required by
1088    /// [`ParsedTransportHeaderMut`] to recompute checksums.
1089    src_addr: I::Addr,
1090    /// The destination IP addr of the packet. Required by
1091    /// [`ParsedTransportHeaderMut`] to recompute checksums.
1092    dst_addr: I::Addr,
1093    /// The body of the IP packet. The body is expected to be a message of type
1094    /// `protocol`, but is not guaranteed to be valid.
1095    body: B,
1096    /// The parsed transport data contained within `body`. Only `Some` if body
1097    /// is a valid transport header.
1098    transport_packet_data: Option<TransportPacketData>,
1099}
1100
1101impl<I: IpExt, B: ParseBuffer> RawIpBody<I, B> {
1102    /// Construct a new [`RawIpBody`] from it's parts.
1103    pub fn new(
1104        protocol: I::Proto,
1105        src_addr: I::Addr,
1106        dst_addr: I::Addr,
1107        body: B,
1108    ) -> RawIpBody<I, B> {
1109        let transport_packet_data = TransportPacketData::parse_in_ip_packet::<I, _>(
1110            src_addr,
1111            dst_addr,
1112            protocol,
1113            Buf::new(&body, ..),
1114        );
1115        RawIpBody { protocol, src_addr, dst_addr, body, transport_packet_data }
1116    }
1117}
1118
1119impl<I: IpExt, B: ParseBuffer> MaybeTransportPacket for RawIpBody<I, B> {
1120    fn transport_packet_data(&self) -> Option<TransportPacketData> {
1121        self.transport_packet_data.clone()
1122    }
1123}
1124
1125impl<I: IpExt, B: BufferMut> MaybeTransportPacketMut<I> for RawIpBody<I, B> {
1126    type TransportPacketMut<'a>
1127        = ParsedTransportHeaderMut<'a, I>
1128    where
1129        Self: 'a;
1130
1131    fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1132        let RawIpBody { protocol, src_addr, dst_addr, body, transport_packet_data: _ } = self;
1133        ParsedTransportHeaderMut::<I>::parse_in_ip_packet(
1134            *src_addr,
1135            *dst_addr,
1136            *protocol,
1137            SliceBufViewMut::new(body.as_mut()),
1138        )
1139    }
1140}
1141
1142impl<I: IpExt, B: BufferMut> Serializer for RawIpBody<I, B> {
1143    type Buffer = <B as Serializer>::Buffer;
1144
1145    fn serialize<G: GrowBufferMut, P: BufferProvider<Self::Buffer, G>>(
1146        self,
1147        outer: PacketConstraints,
1148        provider: P,
1149    ) -> Result<G, (SerializeError<P::Error>, Self)> {
1150        let Self { protocol, src_addr, dst_addr, body, transport_packet_data } = self;
1151        body.serialize(outer, provider).map_err(|(err, body)| {
1152            (err, Self { protocol, src_addr, dst_addr, body, transport_packet_data })
1153        })
1154    }
1155
1156    fn serialize_new_buf<BB: ReusableBuffer, A: BufferAlloc<BB>>(
1157        &self,
1158        outer: PacketConstraints,
1159        alloc: A,
1160    ) -> Result<BB, SerializeError<A::Error>> {
1161        self.body.serialize_new_buf(outer, alloc)
1162    }
1163}
1164
1165fn parse_transport_header_in_ipv4_packet<B: ParseBuffer>(
1166    src_ip: Ipv4Addr,
1167    dst_ip: Ipv4Addr,
1168    proto: Ipv4Proto,
1169    body: B,
1170) -> Option<TransportPacketData> {
1171    match proto {
1172        Ipv4Proto::Proto(IpProto::Udp) => parse_udp_header::<_, Ipv4>(body),
1173        Ipv4Proto::Proto(IpProto::Tcp) => parse_tcp_header::<_, Ipv4>(body, src_ip, dst_ip),
1174        Ipv4Proto::Icmp => parse_icmpv4_header(body),
1175        Ipv4Proto::Proto(IpProto::Reserved) | Ipv4Proto::Igmp | Ipv4Proto::Other(_) => None,
1176    }
1177}
1178
1179fn parse_transport_header_in_ipv6_packet<B: ParseBuffer>(
1180    src_ip: Ipv6Addr,
1181    dst_ip: Ipv6Addr,
1182    proto: Ipv6Proto,
1183    body: B,
1184) -> Option<TransportPacketData> {
1185    match proto {
1186        Ipv6Proto::Proto(IpProto::Udp) => parse_udp_header::<_, Ipv6>(body),
1187        Ipv6Proto::Proto(IpProto::Tcp) => parse_tcp_header::<_, Ipv6>(body, src_ip, dst_ip),
1188        Ipv6Proto::Icmpv6 => parse_icmpv6_header(body),
1189        Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::NoNextHeader | Ipv6Proto::Other(_) => None,
1190    }
1191}
1192
1193fn parse_udp_header<B: ParseBuffer, I: Ip>(mut body: B) -> Option<TransportPacketData> {
1194    let packet = body.parse_with::<_, UdpPacketRaw<_>>(I::VERSION_MARKER).ok()?;
1195    Some(TransportPacketData::Generic {
1196        src_port: packet.src_port().map(NonZeroU16::get).unwrap_or(0),
1197        // NB: UDP packets must have a specified (nonzero) destination port, so
1198        // if this packet has a destination port of 0, it is malformed.
1199        dst_port: packet.dst_port()?.get(),
1200    })
1201}
1202
1203fn parse_tcp_header<B: ParseBuffer, I: IpExt>(
1204    mut body: B,
1205    src_ip: I::Addr,
1206    dst_ip: I::Addr,
1207) -> Option<TransportPacketData> {
1208    // NOTE: By using TcpSegmentRaw here, we're opting into getting invalid data
1209    // (for example, if the checksum isn't valid). As a team, we've decided
1210    // that's okay for now, since the worst that happens is we filter or
1211    // conntrack a packet incorrectly and the end host rejects it.
1212    //
1213    // This will be fixed at some point as part of a larger effort to ensure
1214    // that checksums are validated exactly once (and hopefully via checksum
1215    // offloading).
1216    let packet = body.parse::<TcpSegmentRaw<_>>().ok()?;
1217
1218    let (builder, options, body) = packet.into_builder_options(src_ip, dst_ip)?;
1219    let options = Options::from_iter(builder.syn_set(), options.iter());
1220
1221    let segment = SegmentHeader::from_builder_options(&builder, options).ok()?;
1222
1223    Some(TransportPacketData::Tcp {
1224        src_port: builder.src_port().map(NonZeroU16::get).unwrap_or(0),
1225        dst_port: builder.dst_port().map(NonZeroU16::get).unwrap_or(0),
1226        segment,
1227        payload_len: body.len(),
1228    })
1229}
1230
1231fn parse_icmpv4_header<B: ParseBuffer>(mut body: B) -> Option<TransportPacketData> {
1232    match icmp::peek_message_type(body.as_ref()).ok()? {
1233        Icmpv4MessageType::EchoRequest => {
1234            let packet = body.parse::<IcmpPacketRaw<Ipv4, _, IcmpEchoRequest>>().ok()?;
1235            packet.message().transport_packet_data()
1236        }
1237        Icmpv4MessageType::EchoReply => {
1238            let packet = body.parse::<IcmpPacketRaw<Ipv4, _, IcmpEchoReply>>().ok()?;
1239            packet.message().transport_packet_data()
1240        }
1241        // TODO(https://fxbug.dev/328057704): parse packet contained in ICMP error
1242        // message payload so NAT can be applied to it.
1243        Icmpv4MessageType::DestUnreachable
1244        | Icmpv4MessageType::Redirect
1245        | Icmpv4MessageType::TimeExceeded
1246        | Icmpv4MessageType::ParameterProblem
1247        // NOTE: If these are parsed, then without further work, conntrack won't
1248        // be able to differentiate between these and ECHO message with the same
1249        // ID.
1250        | Icmpv4MessageType::TimestampRequest
1251        | Icmpv4MessageType::TimestampReply => None,
1252    }
1253}
1254
1255fn parse_icmpv6_header<B: ParseBuffer>(mut body: B) -> Option<TransportPacketData> {
1256    match icmp::peek_message_type(body.as_ref()).ok()? {
1257        Icmpv6MessageType::EchoRequest => {
1258            let packet = body.parse::<IcmpPacketRaw<Ipv6, _, IcmpEchoRequest>>().ok()?;
1259            packet.message().transport_packet_data()
1260        }
1261        Icmpv6MessageType::EchoReply => {
1262            let packet = body.parse::<IcmpPacketRaw<Ipv6, _, IcmpEchoReply>>().ok()?;
1263            packet.message().transport_packet_data()
1264        }
1265        // TODO(https://fxbug.dev/328057704): parse packet contained in ICMP error
1266        // message payload so NAT can be applied to it.
1267        Icmpv6MessageType::DestUnreachable
1268        | Icmpv6MessageType::PacketTooBig
1269        | Icmpv6MessageType::TimeExceeded
1270        | Icmpv6MessageType::ParameterProblem
1271        | Icmpv6MessageType::RouterSolicitation
1272        | Icmpv6MessageType::RouterAdvertisement
1273        | Icmpv6MessageType::NeighborSolicitation
1274        | Icmpv6MessageType::NeighborAdvertisement
1275        | Icmpv6MessageType::Redirect
1276        | Icmpv6MessageType::MulticastListenerQuery
1277        | Icmpv6MessageType::MulticastListenerReport
1278        | Icmpv6MessageType::MulticastListenerDone
1279        | Icmpv6MessageType::MulticastListenerReportV2 => None,
1280    }
1281}
1282
1283/// A transport header that has been parsed from a byte buffer and provides
1284/// mutable access to its contents.
1285#[derive(GenericOverIp)]
1286#[generic_over_ip(I, Ip)]
1287pub enum ParsedTransportHeaderMut<'a, I: IpExt> {
1288    Tcp(TcpSegment<&'a mut [u8]>),
1289    Udp(UdpPacket<&'a mut [u8]>),
1290    Icmp(I::IcmpPacketTypeRaw<&'a mut [u8]>),
1291}
1292
1293impl<'a> ParsedTransportHeaderMut<'a, Ipv4> {
1294    fn parse_in_ipv4_packet<BV: BufferViewMut<&'a mut [u8]>>(
1295        src_ip: Ipv4Addr,
1296        dst_ip: Ipv4Addr,
1297        proto: Ipv4Proto,
1298        body: BV,
1299    ) -> Option<Self> {
1300        match proto {
1301            Ipv4Proto::Proto(IpProto::Udp) => {
1302                Some(Self::Udp(UdpPacket::parse_mut(body, UdpParseArgs::new(src_ip, dst_ip)).ok()?))
1303            }
1304            Ipv4Proto::Proto(IpProto::Tcp) => Some(Self::Tcp(
1305                TcpSegment::parse_mut(body, TcpParseArgs::new(src_ip, dst_ip)).ok()?,
1306            )),
1307            Ipv4Proto::Icmp => Some(Self::Icmp(Icmpv4PacketRaw::parse_mut(body, ()).ok()?)),
1308            Ipv4Proto::Proto(IpProto::Reserved) | Ipv4Proto::Igmp | Ipv4Proto::Other(_) => None,
1309        }
1310    }
1311}
1312
1313impl<'a> ParsedTransportHeaderMut<'a, Ipv6> {
1314    fn parse_in_ipv6_packet<BV: BufferViewMut<&'a mut [u8]>>(
1315        src_ip: Ipv6Addr,
1316        dst_ip: Ipv6Addr,
1317        proto: Ipv6Proto,
1318        body: BV,
1319    ) -> Option<Self> {
1320        match proto {
1321            Ipv6Proto::Proto(IpProto::Udp) => {
1322                Some(Self::Udp(UdpPacket::parse_mut(body, UdpParseArgs::new(src_ip, dst_ip)).ok()?))
1323            }
1324            Ipv6Proto::Proto(IpProto::Tcp) => Some(Self::Tcp(
1325                TcpSegment::parse_mut(body, TcpParseArgs::new(src_ip, dst_ip)).ok()?,
1326            )),
1327            Ipv6Proto::Icmpv6 => Some(Self::Icmp(Icmpv6PacketRaw::parse_mut(body, ()).ok()?)),
1328            Ipv6Proto::Proto(IpProto::Reserved) | Ipv6Proto::NoNextHeader | Ipv6Proto::Other(_) => {
1329                None
1330            }
1331        }
1332    }
1333}
1334
1335impl<'a, I: IpExt> ParsedTransportHeaderMut<'a, I> {
1336    fn parse_in_ip_packet<BV: BufferViewMut<&'a mut [u8]>>(
1337        src_ip: I::Addr,
1338        dst_ip: I::Addr,
1339        proto: I::Proto,
1340        body: BV,
1341    ) -> Option<Self> {
1342        I::map_ip(
1343            (src_ip, dst_ip, proto, IpInvariant(body)),
1344            |(src_ip, dst_ip, proto, IpInvariant(body))| {
1345                ParsedTransportHeaderMut::<'a, Ipv4>::parse_in_ipv4_packet(
1346                    src_ip, dst_ip, proto, body,
1347                )
1348            },
1349            |(src_ip, dst_ip, proto, IpInvariant(body))| {
1350                ParsedTransportHeaderMut::<'a, Ipv6>::parse_in_ipv6_packet(
1351                    src_ip, dst_ip, proto, body,
1352                )
1353            },
1354        )
1355    }
1356
1357    fn update_pseudo_header_address(&mut self, old: I::Addr, new: I::Addr) {
1358        match self {
1359            Self::Tcp(segment) => segment.update_checksum_pseudo_header_address(old, new),
1360            Self::Udp(packet) => {
1361                packet.update_checksum_pseudo_header_address(old, new);
1362            }
1363            Self::Icmp(packet) => {
1364                packet.update_checksum_pseudo_header_address(old, new);
1365            }
1366        }
1367    }
1368}
1369
1370/// A helper trait to extract [`IcmpMessage`] impls from parsed ICMP messages.
1371trait IcmpMessageImplHelper<I: IpExt> {
1372    fn message_impl_mut(&mut self) -> &mut impl IcmpMessage<I>;
1373}
1374
1375impl<I: IpExt, B: SplitByteSliceMut, M: IcmpMessage<I>> IcmpMessageImplHelper<I>
1376    for IcmpPacketRaw<I, B, M>
1377{
1378    fn message_impl_mut(&mut self) -> &mut impl IcmpMessage<I> {
1379        self.message_mut()
1380    }
1381}
1382
1383impl<'a, I: IpExt> TransportPacketMut<I> for ParsedTransportHeaderMut<'a, I> {
1384    fn set_src_port(&mut self, port: NonZeroU16) {
1385        match self {
1386            ParsedTransportHeaderMut::Tcp(segment) => segment.set_src_port(port),
1387            ParsedTransportHeaderMut::Udp(packet) => packet.set_src_port(port.get()),
1388            ParsedTransportHeaderMut::Icmp(packet) => {
1389                I::map_ip::<_, ()>(
1390                    packet,
1391                    |packet| {
1392                        packet_formats::icmpv4_dispatch!(
1393                            packet: raw,
1394                            p => {
1395                                let old = p.message_impl_mut().update_icmp_id(port.get());
1396                                p.update_checksum_header_field_u16(old, port.get())
1397                            }
1398                        );
1399                    },
1400                    |packet| {
1401                        packet_formats::icmpv6_dispatch!(
1402                            packet: raw,
1403                            p => {
1404                                let old = p.message_impl_mut().update_icmp_id(port.get());
1405                                p.update_checksum_header_field_u16(old, port.get())
1406                            }
1407                        );
1408                    },
1409                );
1410            }
1411        }
1412    }
1413
1414    fn set_dst_port(&mut self, port: NonZeroU16) {
1415        match self {
1416            ParsedTransportHeaderMut::Tcp(ref mut segment) => segment.set_dst_port(port),
1417            ParsedTransportHeaderMut::Udp(ref mut packet) => packet.set_dst_port(port),
1418            ParsedTransportHeaderMut::Icmp(packet) => {
1419                I::map_ip::<_, ()>(
1420                    packet,
1421                    |packet| {
1422                        packet_formats::icmpv4_dispatch!(
1423                            packet:raw,
1424                            p => {
1425                                let old = p.message_impl_mut().update_icmp_id(port.get());
1426                                p.update_checksum_header_field_u16(old, port.get())
1427                            }
1428                        );
1429                    },
1430                    |packet| {
1431                        packet_formats::icmpv6_dispatch!(
1432                            packet:raw,
1433                            p => {
1434                                let old = p.message_impl_mut().update_icmp_id(port.get());
1435                                p.update_checksum_header_field_u16(old, port.get())
1436                            }
1437                        );
1438                    },
1439                );
1440            }
1441        }
1442    }
1443
1444    fn update_pseudo_header_src_addr(&mut self, old: I::Addr, new: I::Addr) {
1445        self.update_pseudo_header_address(old, new);
1446    }
1447
1448    fn update_pseudo_header_dst_addr(&mut self, old: I::Addr, new: I::Addr) {
1449        self.update_pseudo_header_address(old, new);
1450    }
1451}
1452
1453#[cfg(any(test, feature = "testutils"))]
1454pub mod testutil {
1455    use super::*;
1456
1457    // Note that we could choose to implement `MaybeTransportPacket` for these
1458    // opaque byte buffer types by parsing them as we do incoming buffers, but since
1459    // these implementations are only for use in netstack3_core unit tests, there is
1460    // no expectation that filtering or connection tracking actually be performed.
1461    // If that changes at some point, we could replace these with "real"
1462    // implementations.
1463
1464    impl<B: BufferMut> MaybeTransportPacket for Nested<B, ()> {
1465        fn transport_packet_data(&self) -> Option<TransportPacketData> {
1466            unimplemented!()
1467        }
1468    }
1469
1470    impl<I: IpExt, B: BufferMut> MaybeTransportPacketMut<I> for Nested<B, ()> {
1471        type TransportPacketMut<'a>
1472            = Never
1473        where
1474            B: 'a;
1475
1476        fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1477            unimplemented!()
1478        }
1479    }
1480
1481    impl MaybeTransportPacket for InnerSerializer<&[u8], EmptyBuf> {
1482        fn transport_packet_data(&self) -> Option<TransportPacketData> {
1483            None
1484        }
1485    }
1486
1487    impl<I: IpExt> MaybeTransportPacketMut<I> for InnerSerializer<&[u8], EmptyBuf> {
1488        type TransportPacketMut<'a>
1489            = Never
1490        where
1491            Self: 'a;
1492
1493        fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1494            None
1495        }
1496    }
1497
1498    #[cfg(test)]
1499    pub(crate) mod internal {
1500        use net_declare::{net_ip_v4, net_ip_v6, net_subnet_v4, net_subnet_v6};
1501        use net_types::ip::Subnet;
1502        use netstack3_base::{SeqNum, UnscaledWindowSize};
1503
1504        use super::*;
1505
1506        pub trait TestIpExt: IpExt {
1507            const SRC_IP: Self::Addr;
1508            const SRC_PORT: u16 = 1234;
1509            const DST_IP: Self::Addr;
1510            const DST_PORT: u16 = 9876;
1511            const SRC_IP_2: Self::Addr;
1512            const DST_IP_2: Self::Addr;
1513            const IP_OUTSIDE_SUBNET: Self::Addr;
1514            const SUBNET: Subnet<Self::Addr>;
1515        }
1516
1517        impl TestIpExt for Ipv4 {
1518            const SRC_IP: Self::Addr = net_ip_v4!("192.0.2.1");
1519            const DST_IP: Self::Addr = net_ip_v4!("192.0.2.2");
1520            const SRC_IP_2: Self::Addr = net_ip_v4!("192.0.2.3");
1521            const DST_IP_2: Self::Addr = net_ip_v4!("192.0.2.4");
1522            const IP_OUTSIDE_SUBNET: Self::Addr = net_ip_v4!("192.0.3.1");
1523            const SUBNET: Subnet<Self::Addr> = net_subnet_v4!("192.0.2.0/24");
1524        }
1525
1526        impl TestIpExt for Ipv6 {
1527            const SRC_IP: Self::Addr = net_ip_v6!("2001:db8::1");
1528            const DST_IP: Self::Addr = net_ip_v6!("2001:db8::2");
1529            const SRC_IP_2: Self::Addr = net_ip_v6!("2001:db8::3");
1530            const DST_IP_2: Self::Addr = net_ip_v6!("2001:db8::4");
1531            const IP_OUTSIDE_SUBNET: Self::Addr = net_ip_v6!("2001:db8:ffff::1");
1532            const SUBNET: Subnet<Self::Addr> = net_subnet_v6!("2001:db8::/64");
1533        }
1534
1535        #[derive(Clone, Debug, PartialEq)]
1536        pub struct FakeIpPacket<I: IpExt, T>
1537        where
1538            for<'a> &'a T: TransportPacketExt<I>,
1539        {
1540            pub src_ip: I::Addr,
1541            pub dst_ip: I::Addr,
1542            pub body: T,
1543        }
1544
1545        impl<I: IpExt> FakeIpPacket<I, FakeUdpPacket> {
1546            pub(crate) fn reply(&self) -> Self {
1547                Self { src_ip: self.dst_ip, dst_ip: self.src_ip, body: self.body.reply() }
1548            }
1549        }
1550
1551        pub trait TransportPacketExt<I: IpExt>: MaybeTransportPacket {
1552            fn proto() -> I::Proto;
1553        }
1554
1555        impl<I: IpExt, T> IpPacket<I> for FakeIpPacket<I, T>
1556        where
1557            for<'a> &'a T: TransportPacketExt<I>,
1558            for<'a> &'a mut T: MaybeTransportPacketMut<I>,
1559        {
1560            type TransportPacket<'a>
1561                = &'a T
1562            where
1563                T: 'a;
1564            type TransportPacketMut<'a>
1565                = &'a mut T
1566            where
1567                T: 'a;
1568
1569            fn src_addr(&self) -> I::Addr {
1570                self.src_ip
1571            }
1572
1573            fn set_src_addr(&mut self, addr: I::Addr) {
1574                self.src_ip = addr;
1575            }
1576
1577            fn dst_addr(&self) -> I::Addr {
1578                self.dst_ip
1579            }
1580
1581            fn set_dst_addr(&mut self, addr: I::Addr) {
1582                self.dst_ip = addr;
1583            }
1584
1585            fn protocol(&self) -> I::Proto {
1586                <&T>::proto()
1587            }
1588
1589            fn maybe_transport_packet(&self) -> Self::TransportPacket<'_> {
1590                &self.body
1591            }
1592
1593            fn transport_packet_mut(&mut self) -> Self::TransportPacketMut<'_> {
1594                &mut self.body
1595            }
1596        }
1597
1598        #[derive(Clone, Debug, PartialEq)]
1599        pub struct FakeTcpSegment {
1600            pub src_port: u16,
1601            pub dst_port: u16,
1602            pub segment: SegmentHeader,
1603            pub payload_len: usize,
1604        }
1605
1606        impl<I: IpExt> TransportPacketExt<I> for &FakeTcpSegment {
1607            fn proto() -> I::Proto {
1608                I::map_ip_out(
1609                    (),
1610                    |()| Ipv4Proto::Proto(IpProto::Tcp),
1611                    |()| Ipv6Proto::Proto(IpProto::Tcp),
1612                )
1613            }
1614        }
1615
1616        impl MaybeTransportPacket for &FakeTcpSegment {
1617            fn transport_packet_data(&self) -> Option<TransportPacketData> {
1618                Some(TransportPacketData::Tcp {
1619                    src_port: self.src_port,
1620                    dst_port: self.dst_port,
1621                    segment: self.segment.clone(),
1622                    payload_len: self.payload_len,
1623                })
1624            }
1625        }
1626
1627        impl<I: IpExt> MaybeTransportPacketMut<I> for FakeTcpSegment {
1628            type TransportPacketMut<'a> = &'a mut Self;
1629
1630            fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1631                Some(self)
1632            }
1633        }
1634
1635        impl<I: IpExt> TransportPacketMut<I> for FakeTcpSegment {
1636            fn set_src_port(&mut self, port: NonZeroU16) {
1637                self.src_port = port.get();
1638            }
1639
1640            fn set_dst_port(&mut self, port: NonZeroU16) {
1641                self.dst_port = port.get();
1642            }
1643
1644            fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {}
1645
1646            fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {}
1647        }
1648
1649        #[derive(Clone, Debug, PartialEq)]
1650        pub struct FakeUdpPacket {
1651            pub src_port: u16,
1652            pub dst_port: u16,
1653        }
1654
1655        impl FakeUdpPacket {
1656            fn reply(&self) -> Self {
1657                Self { src_port: self.dst_port, dst_port: self.src_port }
1658            }
1659        }
1660
1661        impl<I: IpExt> TransportPacketExt<I> for &FakeUdpPacket {
1662            fn proto() -> I::Proto {
1663                I::map_ip_out(
1664                    (),
1665                    |()| Ipv4Proto::Proto(IpProto::Udp),
1666                    |()| Ipv6Proto::Proto(IpProto::Udp),
1667                )
1668            }
1669        }
1670
1671        impl MaybeTransportPacket for &FakeUdpPacket {
1672            fn transport_packet_data(&self) -> Option<TransportPacketData> {
1673                Some(TransportPacketData::Generic {
1674                    src_port: self.src_port,
1675                    dst_port: self.dst_port,
1676                })
1677            }
1678        }
1679
1680        impl<I: IpExt> MaybeTransportPacketMut<I> for FakeUdpPacket {
1681            type TransportPacketMut<'a> = &'a mut Self;
1682
1683            fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1684                Some(self)
1685            }
1686        }
1687
1688        impl<I: IpExt> TransportPacketMut<I> for FakeUdpPacket {
1689            fn set_src_port(&mut self, port: NonZeroU16) {
1690                self.src_port = port.get();
1691            }
1692
1693            fn set_dst_port(&mut self, port: NonZeroU16) {
1694                self.dst_port = port.get();
1695            }
1696
1697            fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {}
1698
1699            fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {}
1700        }
1701
1702        pub struct FakeIcmpEchoRequest {
1703            pub id: u16,
1704        }
1705
1706        impl<I: IpExt> TransportPacketExt<I> for &FakeIcmpEchoRequest {
1707            fn proto() -> I::Proto {
1708                I::map_ip_out((), |()| Ipv4Proto::Icmp, |()| Ipv6Proto::Icmpv6)
1709            }
1710        }
1711
1712        impl MaybeTransportPacket for &FakeIcmpEchoRequest {
1713            fn transport_packet_data(&self) -> Option<TransportPacketData> {
1714                Some(TransportPacketData::Generic { src_port: self.id, dst_port: 0 })
1715            }
1716        }
1717
1718        impl<I: IpExt> MaybeTransportPacketMut<I> for FakeIcmpEchoRequest {
1719            type TransportPacketMut<'a> = &'a mut Self;
1720
1721            fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1722                Some(self)
1723            }
1724        }
1725
1726        impl<I: IpExt> TransportPacketMut<I> for FakeIcmpEchoRequest {
1727            fn set_src_port(&mut self, port: NonZeroU16) {
1728                self.id = port.get();
1729            }
1730
1731            fn set_dst_port(&mut self, _: NonZeroU16) {
1732                panic!("cannot set destination port for ICMP echo request")
1733            }
1734
1735            fn update_pseudo_header_src_addr(&mut self, _: I::Addr, _: I::Addr) {}
1736
1737            fn update_pseudo_header_dst_addr(&mut self, _: I::Addr, _: I::Addr) {}
1738        }
1739
1740        pub trait ArbitraryValue {
1741            fn arbitrary_value() -> Self;
1742        }
1743
1744        impl<I, T> ArbitraryValue for FakeIpPacket<I, T>
1745        where
1746            I: TestIpExt,
1747            T: ArbitraryValue,
1748            for<'a> &'a T: TransportPacketExt<I>,
1749        {
1750            fn arbitrary_value() -> Self {
1751                FakeIpPacket { src_ip: I::SRC_IP, dst_ip: I::DST_IP, body: T::arbitrary_value() }
1752            }
1753        }
1754
1755        impl ArbitraryValue for FakeTcpSegment {
1756            fn arbitrary_value() -> Self {
1757                FakeTcpSegment {
1758                    src_port: 33333,
1759                    dst_port: 44444,
1760                    segment: SegmentHeader::arbitrary_value(),
1761                    payload_len: 8888,
1762                }
1763            }
1764        }
1765
1766        impl ArbitraryValue for FakeUdpPacket {
1767            fn arbitrary_value() -> Self {
1768                FakeUdpPacket { src_port: 33333, dst_port: 44444 }
1769            }
1770        }
1771
1772        impl ArbitraryValue for FakeIcmpEchoRequest {
1773            fn arbitrary_value() -> Self {
1774                FakeIcmpEchoRequest { id: 1 }
1775            }
1776        }
1777
1778        impl ArbitraryValue for SegmentHeader {
1779            fn arbitrary_value() -> Self {
1780                SegmentHeader {
1781                    seq: SeqNum::new(55555),
1782                    ack: None,
1783                    control: None,
1784                    wnd: UnscaledWindowSize::from(1234),
1785                    options: Options::default(),
1786                }
1787            }
1788        }
1789    }
1790}
1791
1792#[cfg(test)]
1793mod tests {
1794    use alloc::vec::Vec;
1795    use core::fmt::Debug;
1796    use netstack3_base::{SeqNum, UnscaledWindowSize};
1797
1798    use ip_test_macro::ip_test;
1799    use packet::InnerPacketBuilder as _;
1800    use packet_formats::icmp::IcmpZeroCode;
1801    use packet_formats::tcp::TcpSegmentBuilder;
1802    use test_case::test_case;
1803
1804    use super::testutil::internal::TestIpExt;
1805    use super::*;
1806
1807    const SRC_PORT: NonZeroU16 = NonZeroU16::new(11111).unwrap();
1808    const DST_PORT: NonZeroU16 = NonZeroU16::new(22222).unwrap();
1809    const SRC_PORT_2: NonZeroU16 = NonZeroU16::new(44444).unwrap();
1810    const DST_PORT_2: NonZeroU16 = NonZeroU16::new(55555).unwrap();
1811
1812    const SEQ_NUM: u32 = 1;
1813    const ACK_NUM: Option<u32> = Some(2);
1814    const WINDOW_SIZE: u16 = 3u16;
1815
1816    trait Protocol {
1817        type Serializer<'a, I: IpExt>: TransportPacketSerializer<I, Buffer: packet::ReusableBuffer>
1818            + MaybeTransportPacketMut<I>
1819            + Debug
1820            + PartialEq;
1821
1822        fn proto<I: IpExt>() -> I::Proto;
1823
1824        fn make_serializer_with_ports<'a, I: IpExt>(
1825            src_ip: I::Addr,
1826            dst_ip: I::Addr,
1827            src_port: NonZeroU16,
1828            dst_port: NonZeroU16,
1829        ) -> Self::Serializer<'a, I>;
1830
1831        fn make_serializer<'a, I: IpExt>(
1832            src_ip: I::Addr,
1833            dst_ip: I::Addr,
1834        ) -> Self::Serializer<'a, I> {
1835            Self::make_serializer_with_ports(src_ip, dst_ip, SRC_PORT, DST_PORT)
1836        }
1837
1838        fn make_packet<I: IpExt>(src_ip: I::Addr, dst_ip: I::Addr) -> Vec<u8> {
1839            Self::make_packet_with_ports::<I>(src_ip, dst_ip, SRC_PORT, DST_PORT)
1840        }
1841
1842        fn make_packet_with_ports<I: IpExt>(
1843            src_ip: I::Addr,
1844            dst_ip: I::Addr,
1845            src_port: NonZeroU16,
1846            dst_port: NonZeroU16,
1847        ) -> Vec<u8> {
1848            Self::make_serializer_with_ports::<I>(src_ip, dst_ip, src_port, dst_port)
1849                .serialize_vec_outer()
1850                .expect("serialize packet")
1851                .unwrap_b()
1852                .into_inner()
1853        }
1854    }
1855
1856    struct Udp;
1857
1858    impl Protocol for Udp {
1859        type Serializer<'a, I: IpExt> =
1860            Nested<InnerSerializer<&'a [u8], EmptyBuf>, UdpPacketBuilder<I::Addr>>;
1861
1862        fn proto<I: IpExt>() -> I::Proto {
1863            IpProto::Udp.into()
1864        }
1865
1866        fn make_serializer_with_ports<'a, I: IpExt>(
1867            src_ip: I::Addr,
1868            dst_ip: I::Addr,
1869            src_port: NonZeroU16,
1870            dst_port: NonZeroU16,
1871        ) -> Self::Serializer<'a, I> {
1872            [].into_serializer().encapsulate(UdpPacketBuilder::new(
1873                src_ip,
1874                dst_ip,
1875                Some(src_port),
1876                dst_port,
1877            ))
1878        }
1879    }
1880
1881    // The `TcpSegmentBuilder` impls are test-only on purpose, and removing this
1882    // restriction should be thought through.
1883    //
1884    // TCP state tracking depends on being able to read TCP options, but
1885    // TcpSegmentBuilder does not have this information. If a TcpSegmentBuilder
1886    // passes through filtering with options tracked separately, then these will
1887    // not be seen by conntrack and could lead to state desynchronization.
1888    impl<A: IpAddress, Inner: PayloadLen> MaybeTransportPacket for Nested<Inner, TcpSegmentBuilder<A>> {
1889        fn transport_packet_data(&self) -> Option<TransportPacketData> {
1890            Some(TransportPacketData::Tcp {
1891                src_port: TcpSegmentBuilder::src_port(self.outer()).map_or(0, NonZeroU16::get),
1892                dst_port: TcpSegmentBuilder::dst_port(self.outer()).map_or(0, NonZeroU16::get),
1893                segment: self.outer().try_into().ok()?,
1894                payload_len: self.inner().len(),
1895            })
1896        }
1897    }
1898
1899    impl<I: IpExt, Inner> MaybeTransportPacketMut<I> for Nested<Inner, TcpSegmentBuilder<I::Addr>> {
1900        type TransportPacketMut<'a>
1901            = &'a mut Self
1902        where
1903            Self: 'a;
1904
1905        fn transport_packet_mut(&mut self) -> Option<Self::TransportPacketMut<'_>> {
1906            Some(self)
1907        }
1908    }
1909
1910    impl<I: IpExt, Inner> TransportPacketMut<I> for Nested<Inner, TcpSegmentBuilder<I::Addr>> {
1911        fn set_src_port(&mut self, port: NonZeroU16) {
1912            self.outer_mut().set_src_port(port);
1913        }
1914
1915        fn set_dst_port(&mut self, port: NonZeroU16) {
1916            self.outer_mut().set_dst_port(port);
1917        }
1918
1919        fn update_pseudo_header_src_addr(&mut self, _old: I::Addr, new: I::Addr) {
1920            self.outer_mut().set_src_ip(new);
1921        }
1922
1923        fn update_pseudo_header_dst_addr(&mut self, _old: I::Addr, new: I::Addr) {
1924            self.outer_mut().set_dst_ip(new);
1925        }
1926    }
1927
1928    struct Tcp;
1929
1930    impl Protocol for Tcp {
1931        type Serializer<'a, I: IpExt> =
1932            Nested<InnerSerializer<&'a [u8], EmptyBuf>, TcpSegmentBuilder<I::Addr>>;
1933
1934        fn proto<I: IpExt>() -> I::Proto {
1935            IpProto::Tcp.into()
1936        }
1937
1938        fn make_serializer_with_ports<'a, I: IpExt>(
1939            src_ip: I::Addr,
1940            dst_ip: I::Addr,
1941            src_port: NonZeroU16,
1942            dst_port: NonZeroU16,
1943        ) -> Self::Serializer<'a, I> {
1944            [1, 2, 3].into_serializer().encapsulate(TcpSegmentBuilder::new(
1945                src_ip,
1946                dst_ip,
1947                src_port,
1948                dst_port,
1949                SEQ_NUM,
1950                ACK_NUM,
1951                WINDOW_SIZE,
1952            ))
1953        }
1954    }
1955
1956    struct IcmpEchoRequest;
1957
1958    impl Protocol for IcmpEchoRequest {
1959        type Serializer<'a, I: IpExt> = Nested<
1960            InnerSerializer<&'a [u8], EmptyBuf>,
1961            IcmpPacketBuilder<I, icmp::IcmpEchoRequest>,
1962        >;
1963
1964        fn proto<I: IpExt>() -> I::Proto {
1965            I::map_ip((), |()| Ipv4Proto::Icmp, |()| Ipv6Proto::Icmpv6)
1966        }
1967
1968        fn make_serializer_with_ports<'a, I: IpExt>(
1969            src_ip: I::Addr,
1970            dst_ip: I::Addr,
1971            src_port: NonZeroU16,
1972            _dst_port: NonZeroU16,
1973        ) -> Self::Serializer<'a, I> {
1974            [].into_serializer().encapsulate(IcmpPacketBuilder::<I, _>::new(
1975                src_ip,
1976                dst_ip,
1977                IcmpZeroCode,
1978                icmp::IcmpEchoRequest::new(/* id */ src_port.get(), /* seq */ 0),
1979            ))
1980        }
1981    }
1982
1983    struct IcmpEchoReply;
1984
1985    impl Protocol for IcmpEchoReply {
1986        type Serializer<'a, I: IpExt> =
1987            Nested<InnerSerializer<&'a [u8], EmptyBuf>, IcmpPacketBuilder<I, icmp::IcmpEchoReply>>;
1988
1989        fn proto<I: IpExt>() -> I::Proto {
1990            I::map_ip((), |()| Ipv4Proto::Icmp, |()| Ipv6Proto::Icmpv6)
1991        }
1992
1993        fn make_serializer_with_ports<'a, I: IpExt>(
1994            src_ip: I::Addr,
1995            dst_ip: I::Addr,
1996            _src_port: NonZeroU16,
1997            dst_port: NonZeroU16,
1998        ) -> Self::Serializer<'a, I> {
1999            [].into_serializer().encapsulate(IcmpPacketBuilder::<I, _>::new(
2000                src_ip,
2001                dst_ip,
2002                IcmpZeroCode,
2003                icmp::IcmpEchoReply::new(/* id */ dst_port.get(), /* seq */ 0),
2004            ))
2005        }
2006    }
2007
2008    enum TransportPacketDataProtocol {
2009        Tcp,
2010        Udp,
2011        IcmpEchoRequest,
2012    }
2013
2014    impl TransportPacketDataProtocol {
2015        fn make_packet<I: TestIpExt>(&self, src_ip: I::Addr, dst_ip: I::Addr) -> Vec<u8> {
2016            match self {
2017                TransportPacketDataProtocol::Tcp => Tcp::make_packet::<I>(src_ip, dst_ip),
2018                TransportPacketDataProtocol::Udp => Udp::make_packet::<I>(src_ip, dst_ip),
2019                TransportPacketDataProtocol::IcmpEchoRequest => {
2020                    IcmpEchoRequest::make_packet::<I>(src_ip, dst_ip)
2021                }
2022            }
2023        }
2024
2025        fn proto<I: TestIpExt>(&self) -> I::Proto {
2026            match self {
2027                TransportPacketDataProtocol::Tcp => Tcp::proto::<I>(),
2028                TransportPacketDataProtocol::Udp => Udp::proto::<I>(),
2029                TransportPacketDataProtocol::IcmpEchoRequest => IcmpEchoRequest::proto::<I>(),
2030            }
2031        }
2032    }
2033
2034    #[ip_test(I)]
2035    #[test_case(TransportPacketDataProtocol::Udp)]
2036    #[test_case(TransportPacketDataProtocol::Tcp)]
2037    #[test_case(TransportPacketDataProtocol::IcmpEchoRequest)]
2038    fn transport_packet_data_from_serialized<I: TestIpExt>(proto: TransportPacketDataProtocol) {
2039        let expected_data = match proto {
2040            TransportPacketDataProtocol::Tcp => TransportPacketData::Tcp {
2041                src_port: SRC_PORT.get(),
2042                dst_port: DST_PORT.get(),
2043                segment: SegmentHeader {
2044                    seq: SeqNum::new(SEQ_NUM),
2045                    ack: ACK_NUM.map(SeqNum::new),
2046                    control: None,
2047                    wnd: UnscaledWindowSize::from(WINDOW_SIZE),
2048                    options: Options::default(),
2049                },
2050                payload_len: 3,
2051            },
2052            TransportPacketDataProtocol::Udp => {
2053                TransportPacketData::Generic { src_port: SRC_PORT.get(), dst_port: DST_PORT.get() }
2054            }
2055            TransportPacketDataProtocol::IcmpEchoRequest => {
2056                TransportPacketData::Generic { src_port: SRC_PORT.get(), dst_port: SRC_PORT.get() }
2057            }
2058        };
2059
2060        let buf = proto.make_packet::<I>(I::SRC_IP, I::DST_IP);
2061        let parsed_data = TransportPacketData::parse_in_ip_packet::<I, _>(
2062            I::SRC_IP,
2063            I::DST_IP,
2064            proto.proto::<I>(),
2065            buf.as_slice(),
2066        )
2067        .expect("failed to parse transport packet data");
2068
2069        assert_eq!(parsed_data, expected_data);
2070    }
2071
2072    #[ip_test(I)]
2073    #[test_case(Udp)]
2074    #[test_case(Tcp)]
2075    #[test_case(IcmpEchoRequest)]
2076    fn update_pseudo_header_address_updates_checksum<I: TestIpExt, P: Protocol>(_proto: P) {
2077        let mut buf = P::make_packet::<I>(I::SRC_IP, I::DST_IP);
2078        let view = SliceBufViewMut::new(&mut buf);
2079
2080        let mut packet = ParsedTransportHeaderMut::<I>::parse_in_ip_packet(
2081            I::SRC_IP,
2082            I::DST_IP,
2083            P::proto::<I>(),
2084            view,
2085        )
2086        .expect("parse transport header");
2087        packet.update_pseudo_header_src_addr(I::SRC_IP, I::SRC_IP_2);
2088        packet.update_pseudo_header_dst_addr(I::DST_IP, I::DST_IP_2);
2089        // Drop the packet because it's holding a mutable borrow of `buf` which
2090        // we need to assert equality later.
2091        drop(packet);
2092
2093        let equivalent = P::make_packet::<I>(I::SRC_IP_2, I::DST_IP_2);
2094
2095        assert_eq!(equivalent, buf);
2096    }
2097
2098    #[ip_test(I)]
2099    #[test_case(Udp, true, true)]
2100    #[test_case(Tcp, true, true)]
2101    #[test_case(IcmpEchoRequest, true, false)]
2102    #[test_case(IcmpEchoReply, false, true)]
2103    fn parsed_packet_update_src_dst_port_updates_checksum<I: TestIpExt, P: Protocol>(
2104        _proto: P,
2105        update_src_port: bool,
2106        update_dst_port: bool,
2107    ) {
2108        let mut buf = P::make_packet_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT);
2109        let view = SliceBufViewMut::new(&mut buf);
2110
2111        let mut packet = ParsedTransportHeaderMut::<I>::parse_in_ip_packet(
2112            I::SRC_IP,
2113            I::DST_IP,
2114            P::proto::<I>(),
2115            view,
2116        )
2117        .expect("parse transport header");
2118        let expected_src_port = if update_src_port {
2119            packet.set_src_port(SRC_PORT_2);
2120            SRC_PORT_2
2121        } else {
2122            SRC_PORT
2123        };
2124        let expected_dst_port = if update_dst_port {
2125            packet.set_dst_port(DST_PORT_2);
2126            DST_PORT_2
2127        } else {
2128            DST_PORT
2129        };
2130        drop(packet);
2131
2132        let equivalent = P::make_packet_with_ports::<I>(
2133            I::SRC_IP,
2134            I::DST_IP,
2135            expected_src_port,
2136            expected_dst_port,
2137        );
2138
2139        assert_eq!(equivalent, buf);
2140    }
2141
2142    #[ip_test(I)]
2143    #[test_case(Udp)]
2144    #[test_case(Tcp)]
2145    fn serializer_update_src_dst_port_updates_checksum<I: TestIpExt, P: Protocol>(_proto: P) {
2146        let mut serializer =
2147            P::make_serializer_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT, DST_PORT);
2148        let mut packet =
2149            serializer.transport_packet_mut().expect("packet should support rewriting");
2150        packet.set_src_port(SRC_PORT_2);
2151        packet.set_dst_port(DST_PORT_2);
2152        drop(packet);
2153
2154        let equivalent =
2155            P::make_serializer_with_ports::<I>(I::SRC_IP, I::DST_IP, SRC_PORT_2, DST_PORT_2);
2156
2157        assert_eq!(equivalent, serializer);
2158    }
2159
2160    #[ip_test(I)]
2161    fn icmp_echo_request_update_id_port_updates_checksum<I: TestIpExt>() {
2162        let mut serializer = [].into_serializer().encapsulate(IcmpPacketBuilder::<I, _>::new(
2163            I::SRC_IP,
2164            I::DST_IP,
2165            IcmpZeroCode,
2166            icmp::IcmpEchoRequest::new(SRC_PORT.get(), /* seq */ 0),
2167        ));
2168        serializer
2169            .transport_packet_mut()
2170            .expect("packet should support rewriting")
2171            .set_src_port(SRC_PORT_2);
2172
2173        let equivalent = [].into_serializer().encapsulate(IcmpPacketBuilder::<I, _>::new(
2174            I::SRC_IP,
2175            I::DST_IP,
2176            IcmpZeroCode,
2177            icmp::IcmpEchoRequest::new(SRC_PORT_2.get(), /* seq */ 0),
2178        ));
2179
2180        assert_eq!(equivalent, serializer);
2181    }
2182
2183    #[ip_test(I)]
2184    fn icmp_echo_reply_update_id_port_updates_checksum<I: TestIpExt>() {
2185        let mut serializer = [].into_serializer().encapsulate(IcmpPacketBuilder::<I, _>::new(
2186            I::SRC_IP,
2187            I::DST_IP,
2188            IcmpZeroCode,
2189            icmp::IcmpEchoReply::new(SRC_PORT.get(), /* seq */ 0),
2190        ));
2191        serializer
2192            .transport_packet_mut()
2193            .expect("packet should support rewriting")
2194            .set_dst_port(SRC_PORT_2);
2195
2196        let equivalent = [].into_serializer().encapsulate(IcmpPacketBuilder::<I, _>::new(
2197            I::SRC_IP,
2198            I::DST_IP,
2199            IcmpZeroCode,
2200            icmp::IcmpEchoReply::new(SRC_PORT_2.get(), /* seq */ 0),
2201        ));
2202
2203        assert_eq!(equivalent, serializer);
2204    }
2205
2206    #[test]
2207    #[should_panic]
2208    fn icmp_serializer_set_port_panics_on_unsupported_type() {
2209        let mut serializer = [].into_serializer().encapsulate(IcmpPacketBuilder::new(
2210            Ipv4::SRC_IP,
2211            Ipv4::DST_IP,
2212            IcmpZeroCode,
2213            icmp::Icmpv4TimestampRequest::new(
2214                /* origin_timestamp */ 0,
2215                /* id */ SRC_PORT.get(),
2216                /* seq */ 0,
2217            )
2218            .reply(/* recv_timestamp */ 0, /* tx_timestamp */ 0),
2219        ));
2220        let Some(packet) = serializer.transport_packet_mut() else {
2221            // We expect this method to always return Some, and this test is expected to
2222            // panic, so *do not* panic in order to fail the test if this method returns
2223            // None.
2224            return;
2225        };
2226        packet.set_src_port(SRC_PORT_2);
2227    }
2228
2229    fn ip_packet<I: IpExt, P: Protocol>(src: I::Addr, dst: I::Addr) -> Buf<Vec<u8>> {
2230        Buf::new(P::make_packet::<I>(src, dst), ..)
2231            .encapsulate(I::PacketBuilder::new(src, dst, /* ttl */ u8::MAX, P::proto::<I>()))
2232            .serialize_vec_outer()
2233            .expect("serialize IP packet")
2234            .unwrap_b()
2235    }
2236
2237    #[ip_test(I)]
2238    #[test_case(Udp)]
2239    #[test_case(Tcp)]
2240    #[test_case(IcmpEchoRequest)]
2241    fn ip_packet_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(_proto: P)
2242    where
2243        for<'a> I::Packet<&'a mut [u8]>: IpPacket<I>,
2244    {
2245        let mut buf = ip_packet::<I, P>(I::SRC_IP, I::DST_IP).into_inner();
2246
2247        let mut packet =
2248            I::Packet::parse_mut(SliceBufViewMut::new(&mut buf), ()).expect("parse IP packet");
2249        packet.set_src_addr(I::SRC_IP_2);
2250        packet.set_dst_addr(I::DST_IP_2);
2251        drop(packet);
2252
2253        let equivalent = ip_packet::<I, P>(I::SRC_IP_2, I::DST_IP_2).into_inner();
2254
2255        assert_eq!(equivalent, buf);
2256    }
2257
2258    #[ip_test(I)]
2259    #[test_case(Udp)]
2260    #[test_case(Tcp)]
2261    #[test_case(IcmpEchoRequest)]
2262    fn forwarded_packet_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(_proto: P) {
2263        let mut buffer = ip_packet::<I, P>(I::SRC_IP, I::DST_IP);
2264        let meta = buffer.parse::<I::Packet<_>>().expect("parse IP packet").parse_metadata();
2265        let mut packet =
2266            ForwardedPacket::<I, _>::new(I::SRC_IP, I::DST_IP, P::proto::<I>(), meta, buffer);
2267        packet.set_src_addr(I::SRC_IP_2);
2268        packet.set_dst_addr(I::DST_IP_2);
2269
2270        let mut buffer = ip_packet::<I, P>(I::SRC_IP_2, I::DST_IP_2);
2271        let meta = buffer.parse::<I::Packet<_>>().expect("parse IP packet").parse_metadata();
2272        let equivalent =
2273            ForwardedPacket::<I, _>::new(I::SRC_IP_2, I::DST_IP_2, P::proto::<I>(), meta, buffer);
2274
2275        assert_eq!(equivalent, packet);
2276    }
2277
2278    #[ip_test(I)]
2279    #[test_case(Udp)]
2280    #[test_case(Tcp)]
2281    #[test_case(IcmpEchoRequest)]
2282    fn tx_packet_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(_proto: P) {
2283        let mut body = P::make_serializer::<I>(I::SRC_IP, I::DST_IP);
2284        let mut packet = TxPacket::<I, _>::new(I::SRC_IP, I::DST_IP, P::proto::<I>(), &mut body);
2285        packet.set_src_addr(I::SRC_IP_2);
2286        packet.set_dst_addr(I::DST_IP_2);
2287
2288        let mut equivalent_body = P::make_serializer::<I>(I::SRC_IP_2, I::DST_IP_2);
2289        let equivalent =
2290            TxPacket::new(I::SRC_IP_2, I::DST_IP_2, P::proto::<I>(), &mut equivalent_body);
2291
2292        assert_eq!(equivalent, packet);
2293    }
2294
2295    #[ip_test(I)]
2296    #[test_case(Udp)]
2297    #[test_case(Tcp)]
2298    #[test_case(IcmpEchoRequest)]
2299    fn nested_serializer_set_src_dst_addr_updates_checksums<I: TestIpExt, P: Protocol>(_proto: P) {
2300        let mut packet = P::make_serializer::<I>(I::SRC_IP, I::DST_IP).encapsulate(
2301            I::PacketBuilder::new(I::SRC_IP, I::DST_IP, /* ttl */ u8::MAX, P::proto::<I>()),
2302        );
2303        packet.set_src_addr(I::SRC_IP_2);
2304        packet.set_dst_addr(I::DST_IP_2);
2305
2306        let equivalent =
2307            P::make_serializer::<I>(I::SRC_IP_2, I::DST_IP_2).encapsulate(I::PacketBuilder::new(
2308                I::SRC_IP_2,
2309                I::DST_IP_2,
2310                /* ttl */ u8::MAX,
2311                P::proto::<I>(),
2312            ));
2313
2314        assert_eq!(equivalent, packet);
2315    }
2316}