Skip to main content

packet_formats/
ip.rs

1// Copyright 2020 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
5//! IP protocol types.
6
7// TODO(https://fxbug.dev/326330182): this import seems actually necessary. Is this a bug on the
8// lint?
9#[allow(unused_imports)]
10use alloc::vec::Vec;
11use core::cmp::PartialEq;
12use core::convert::Infallible as Never;
13use core::fmt::{Debug, Display};
14use core::hash::Hash;
15use core::marker::PhantomData;
16
17use net_types::ip::{GenericOverIp, Ip, IpAddr, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
18use packet::{
19    BufferViewMut, NoOpSerializationContext, PacketBuilder, ParsablePacket, ParseMetadata,
20    PartialPacketBuilder, SerializationContext,
21};
22use zerocopy::{
23    FromBytes, Immutable, IntoBytes, KnownLayout, SplitByteSlice, SplitByteSliceMut, Unaligned,
24};
25
26use crate::error::{IpParseResult, Ipv6ParseError, ParseError};
27use crate::ethernet::EthernetIpExt;
28use crate::icmp::IcmpIpExt;
29use crate::ipv4::{IPV4_MIN_HDR_LEN, Ipv4Header, Ipv4Packet, Ipv4PacketBuilder, Ipv4PacketRaw};
30use crate::ipv6::{IPV6_FIXED_HDR_LEN, Ipv6Header, Ipv6Packet, Ipv6PacketBuilder, Ipv6PacketRaw};
31use crate::private::Sealed;
32
33/// An [`Ip`] extension trait adding an associated type for the IP protocol
34/// number.
35pub trait IpProtoExt: Ip {
36    /// The type representing an IPv4 or IPv6 protocol number.
37    ///
38    /// For IPv4, this is [`Ipv4Proto`], and for IPv6, this is [`Ipv6Proto`].
39    type Proto: IpProtocol
40        + GenericOverIp<Self, Type = Self::Proto>
41        + GenericOverIp<Ipv4, Type = Ipv4Proto>
42        + GenericOverIp<Ipv6, Type = Ipv6Proto>
43        + Copy
44        + Clone
45        + Hash
46        + Debug
47        + Display
48        + PartialEq
49        + Eq
50        + PartialOrd
51        + Ord;
52}
53
54impl IpProtoExt for Ipv4 {
55    type Proto = Ipv4Proto;
56}
57
58impl IpProtoExt for Ipv6 {
59    type Proto = Ipv6Proto;
60}
61
62/// IP packet context relevant to serialization.
63pub struct IpEnvelope<I: IpExt> {
64    _marker: PhantomData<I>,
65}
66
67impl<I: IpExt> IpEnvelope<I> {
68    /// Creates a new `IpEnvelope`.
69    pub fn new() -> Self {
70        Self { _marker: PhantomData }
71    }
72}
73
74/// A trait for IP serialization contexts.
75pub trait IpSerializationContext<I: IpExt>: SerializationContext {
76    /// Converts an `IpEnvelope` into the serialization context's state.
77    fn envelope_to_state(envelope: IpEnvelope<I>) -> Self::ContextState;
78}
79
80impl<I: IpExt> IpSerializationContext<I> for NoOpSerializationContext {
81    fn envelope_to_state(_envelope: IpEnvelope<I>) -> Self::ContextState {
82        ()
83    }
84}
85
86/// An extension trait to the `Ip` trait adding associated types relevant for
87/// packet parsing and serialization.
88pub trait IpExt: EthernetIpExt + IcmpIpExt {
89    /// The error type returned when parsing a packet of this IP version fails.
90    type PacketParseError: From<ParseError> + Debug + PartialEq + Send + Sync;
91
92    /// An IP packet type for this IP version.
93    type Packet<B: SplitByteSlice>: IpPacket<B, Self>
94        + GenericOverIp<Self, Type = Self::Packet<B>>
95        + GenericOverIp<Ipv4, Type = Ipv4Packet<B>>
96        + GenericOverIp<Ipv6, Type = Ipv6Packet<B>>;
97    /// A raw IP packet type for this IP version.
98    type PacketRaw<B: SplitByteSlice>: IpPacketRaw<B, Self>
99        + GenericOverIp<Self, Type = Self::PacketRaw<B>>
100        + GenericOverIp<Ipv4, Type = Ipv4PacketRaw<B>>
101        + GenericOverIp<Ipv6, Type = Ipv6PacketRaw<B>>;
102    /// An IP packet builder type for the IP version.
103    type PacketBuilder<C: IpSerializationContext<Self>>: IpPacketBuilder<C, Self> + Eq;
104    /// Minimal IP header size.
105    const MIN_HEADER_LENGTH: usize;
106}
107
108impl IpExt for Ipv4 {
109    type PacketParseError = ParseError;
110    type Packet<B: SplitByteSlice> = Ipv4Packet<B>;
111    type PacketRaw<B: SplitByteSlice> = Ipv4PacketRaw<B>;
112    type PacketBuilder<C: IpSerializationContext<Self>> = Ipv4PacketBuilder;
113
114    const MIN_HEADER_LENGTH: usize = IPV4_MIN_HDR_LEN;
115}
116
117impl IpExt for Ipv6 {
118    type PacketParseError = Ipv6ParseError;
119    type Packet<B: SplitByteSlice> = Ipv6Packet<B>;
120    type PacketRaw<B: SplitByteSlice> = Ipv6PacketRaw<B>;
121    type PacketBuilder<C: IpSerializationContext<Self>> = Ipv6PacketBuilder;
122
123    const MIN_HEADER_LENGTH: usize = IPV6_FIXED_HDR_LEN;
124}
125
126/// An error encountered during NAT64 translation.
127#[derive(Debug)]
128pub enum Nat64Error {
129    /// Support not yet implemented in the library.
130    NotImplemented,
131}
132
133/// The result of NAT64 translation.
134#[derive(Debug)]
135pub enum Nat64TranslationResult<S, E> {
136    /// Forward the packet encoded in `S`.
137    Forward(S),
138    /// Silently drop the packet.
139    Drop,
140    /// An error was encountered.
141    Err(E),
142}
143
144/// Combines Differentiated Services Code Point (DSCP) and Explicit Congestion
145/// Notification (ECN) values into one. Internally the 2 fields are stored
146/// using the same layout as the Traffic Class field in IPv6 and the Type Of
147/// Service field in IPv4: 6 higher bits for DSCP and 2 lower bits for ECN.
148#[derive(
149    Default,
150    Debug,
151    Clone,
152    Copy,
153    PartialEq,
154    Eq,
155    KnownLayout,
156    FromBytes,
157    IntoBytes,
158    Immutable,
159    Unaligned,
160)]
161#[repr(C)]
162pub struct DscpAndEcn(u8);
163
164const DSCP_OFFSET: u8 = 2;
165const DSCP_MAX: u8 = (1 << (8 - DSCP_OFFSET)) - 1;
166const ECN_MAX: u8 = (1 << DSCP_OFFSET) - 1;
167
168impl DscpAndEcn {
169    /// Returns the default value. Implemented separately from the `Default`
170    /// trait to make it `const`.
171    pub const fn default() -> Self {
172        Self(0)
173    }
174
175    /// Creates a new `DscpAndEcn` instance with the specified DSCP and ECN
176    /// values.
177    pub const fn new(dscp: u8, ecn: u8) -> Self {
178        debug_assert!(dscp <= DSCP_MAX);
179        debug_assert!(ecn <= ECN_MAX);
180        Self((dscp << DSCP_OFFSET) + ecn)
181    }
182
183    /// Constructs a new `DspAndEcn` from a raw value, i.e., both fields packet
184    /// into one byte.
185    pub const fn new_with_raw(value: u8) -> Self {
186        Self(value)
187    }
188
189    /// Returns the Differentiated Services Code Point value.
190    pub fn dscp(self) -> u8 {
191        let Self(v) = self;
192        v >> 2
193    }
194
195    /// Returns the Explicit Congestion Notification value.
196    pub fn ecn(self) -> u8 {
197        let Self(v) = self;
198        v & 0x3
199    }
200
201    /// Returns the raw value, i.e. both fields packed into one byte.
202    pub fn raw(self) -> u8 {
203        let Self(value) = self;
204        value
205    }
206}
207
208impl From<u8> for DscpAndEcn {
209    fn from(value: u8) -> Self {
210        Self::new_with_raw(value)
211    }
212}
213
214/// An IPv4 or IPv6 packet.
215///
216/// `IpPacket` is implemented by `Ipv4Packet` and `Ipv6Packet`.
217pub trait IpPacket<B: SplitByteSlice, I: IpExt>:
218    Sized + Debug + ParsablePacket<B, (), Error = I::PacketParseError>
219{
220    /// A builder for this packet type.
221    type Builder<C: IpSerializationContext<I>>: IpPacketBuilder<C, I>;
222
223    /// The source IP address.
224    fn src_ip(&self) -> I::Addr;
225
226    /// The destination IP address.
227    fn dst_ip(&self) -> I::Addr;
228
229    /// The protocol number.
230    fn proto(&self) -> I::Proto;
231
232    /// The Time to Live (TTL) (IPv4) or Hop Limit (IPv6) field.
233    fn ttl(&self) -> u8;
234
235    /// The Differentiated Services Code Point (DSCP) and the Explicit
236    /// Congestion Notification (ECN).
237    fn dscp_and_ecn(&self) -> DscpAndEcn;
238
239    /// Set the Time to Live (TTL) (IPv4) or Hop Limit (IPv6) field.
240    ///
241    /// `set_ttl` updates the packet's TTL/Hop Limit in place.
242    fn set_ttl(&mut self, ttl: u8)
243    where
244        B: SplitByteSliceMut;
245
246    /// Get the body.
247    fn body(&self) -> &[u8];
248
249    /// Consume the packet and return some metadata.
250    ///
251    /// Consume the packet and return the source address, destination address,
252    /// protocol, and `ParseMetadata`.
253    fn into_metadata(self) -> (I::Addr, I::Addr, I::Proto, ParseMetadata) {
254        let src_ip = self.src_ip();
255        let dst_ip = self.dst_ip();
256        let proto = self.proto();
257        let meta = self.parse_metadata();
258        (src_ip, dst_ip, proto, meta)
259    }
260
261    /// Converts a packet reference into a dynamically-typed reference.
262    fn as_ip_addr_ref(&self) -> IpAddr<&'_ Ipv4Packet<B>, &'_ Ipv6Packet<B>>;
263
264    /// Reassembles a fragmented packet into a parsed IP packet.
265    ///
266    /// # Panics
267    ///
268    /// Panics if the provided header is too small to hold a valid header.
269    fn reassemble_fragmented_packet<BV: BufferViewMut<B>, IT: Iterator<Item = Vec<u8>>>(
270        buffer: BV,
271        header: Vec<u8>,
272        body_fragments: IT,
273    ) -> IpParseResult<I, ()>
274    where
275        B: SplitByteSliceMut;
276
277    /// Copies the full packet into a `Vec`.
278    fn to_vec(&self) -> Vec<u8>;
279
280    /// Constructs a builder with the same contents as this packet's header.
281    fn builder<C: IpSerializationContext<I>>(&self) -> Self::Builder<C>;
282}
283
284impl<B: SplitByteSlice> IpPacket<B, Ipv4> for Ipv4Packet<B> {
285    type Builder<C: IpSerializationContext<Ipv4>> = Ipv4PacketBuilder;
286
287    fn src_ip(&self) -> Ipv4Addr {
288        Ipv4Header::src_ip(self)
289    }
290    fn dst_ip(&self) -> Ipv4Addr {
291        Ipv4Header::dst_ip(self)
292    }
293    fn proto(&self) -> Ipv4Proto {
294        Ipv4Header::proto(self)
295    }
296    fn dscp_and_ecn(&self) -> DscpAndEcn {
297        Ipv4Header::dscp_and_ecn(self)
298    }
299    fn ttl(&self) -> u8 {
300        Ipv4Header::ttl(self)
301    }
302    fn set_ttl(&mut self, ttl: u8)
303    where
304        B: SplitByteSliceMut,
305    {
306        Ipv4Packet::set_ttl(self, ttl)
307    }
308    fn body(&self) -> &[u8] {
309        Ipv4Packet::body(self)
310    }
311
312    fn as_ip_addr_ref(&self) -> IpAddr<&'_ Self, &'_ Ipv6Packet<B>> {
313        IpAddr::V4(self)
314    }
315
316    fn reassemble_fragmented_packet<BV: BufferViewMut<B>, IT: Iterator<Item = Vec<u8>>>(
317        buffer: BV,
318        header: Vec<u8>,
319        body_fragments: IT,
320    ) -> IpParseResult<Ipv4, ()>
321    where
322        B: SplitByteSliceMut,
323    {
324        crate::ipv4::reassemble_fragmented_packet(buffer, header, body_fragments)
325    }
326
327    fn to_vec(&self) -> Vec<u8> {
328        self.to_vec()
329    }
330
331    fn builder<C: IpSerializationContext<Ipv4>>(&self) -> Self::Builder<C> {
332        Ipv4Header::builder(self)
333    }
334}
335
336impl<B: SplitByteSlice> IpPacket<B, Ipv6> for Ipv6Packet<B> {
337    type Builder<C: IpSerializationContext<Ipv6>> = Ipv6PacketBuilder;
338
339    fn src_ip(&self) -> Ipv6Addr {
340        Ipv6Header::src_ip(self)
341    }
342    fn dst_ip(&self) -> Ipv6Addr {
343        Ipv6Header::dst_ip(self)
344    }
345    fn proto(&self) -> Ipv6Proto {
346        Ipv6Packet::proto(self)
347    }
348    fn dscp_and_ecn(&self) -> DscpAndEcn {
349        Ipv6Header::dscp_and_ecn(self)
350    }
351    fn ttl(&self) -> u8 {
352        Ipv6Header::hop_limit(self)
353    }
354    fn set_ttl(&mut self, ttl: u8)
355    where
356        B: SplitByteSliceMut,
357    {
358        Ipv6Packet::set_hop_limit(self, ttl)
359    }
360    fn body(&self) -> &[u8] {
361        Ipv6Packet::body(self)
362    }
363
364    fn as_ip_addr_ref(&self) -> IpAddr<&'_ Ipv4Packet<B>, &'_ Self> {
365        IpAddr::V6(self)
366    }
367    fn reassemble_fragmented_packet<BV: BufferViewMut<B>, IT: Iterator<Item = Vec<u8>>>(
368        buffer: BV,
369        header: Vec<u8>,
370        body_fragments: IT,
371    ) -> IpParseResult<Ipv6, ()>
372    where
373        B: SplitByteSliceMut,
374    {
375        crate::ipv6::reassemble_fragmented_packet(buffer, header, body_fragments)
376    }
377
378    fn to_vec(&self) -> Vec<u8> {
379        self.to_vec()
380    }
381
382    fn builder<C: IpSerializationContext<Ipv6>>(&self) -> Self::Builder<C> {
383        self.builder()
384    }
385}
386
387/// A raw IPv4 or IPv6 packet.
388///
389/// `IpPacketRaw` is implemented by `Ipv4PacketRaw` and `Ipv6PacketRaw`.
390pub trait IpPacketRaw<B: SplitByteSlice, I: IpExt>:
391    Sized + ParsablePacket<B, (), Error = I::PacketParseError>
392{
393}
394
395impl<B: SplitByteSlice> IpPacketRaw<B, Ipv4> for Ipv4PacketRaw<B> {}
396impl<B: SplitByteSlice, I: IpExt> GenericOverIp<I> for Ipv4PacketRaw<B> {
397    type Type = <I as IpExt>::PacketRaw<B>;
398}
399
400impl<B: SplitByteSlice> IpPacketRaw<B, Ipv6> for Ipv6PacketRaw<B> {}
401impl<B: SplitByteSlice, I: IpExt> GenericOverIp<I> for Ipv6PacketRaw<B> {
402    type Type = <I as IpExt>::PacketRaw<B>;
403}
404
405/// A builder for IP packets.
406pub trait IpPacketBuilder<C: SerializationContext, I: IpExt>:
407    PacketBuilder<C> + PartialPacketBuilder<C> + Clone + Debug
408{
409    /// Returns a new packet builder for an associated IP version with the given
410    /// given source and destination IP addresses, TTL (IPv4)/Hop Limit (IPv4)
411    /// and Protocol Number.
412    fn new(src_ip: I::Addr, dst_ip: I::Addr, ttl: u8, proto: I::Proto) -> Self;
413
414    /// Returns the source IP address for the builder.
415    fn src_ip(&self) -> I::Addr;
416
417    /// Sets the source IP address for the builder.
418    fn set_src_ip(&mut self, addr: I::Addr);
419
420    /// Returns the destination IP address for the builder.
421    fn dst_ip(&self) -> I::Addr;
422
423    /// Sets the destination IP address for the builder.
424    fn set_dst_ip(&mut self, addr: I::Addr);
425
426    /// Returns the IP protocol number for the builder.
427    fn proto(&self) -> I::Proto;
428
429    /// Set DSCP & ECN fields.
430    fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn);
431}
432
433/// An IPv4 or IPv6 protocol number.
434pub trait IpProtocol: From<IpProto> + From<u8> + Sealed + Send + Sync + 'static {}
435
436impl Sealed for Never {}
437
438create_protocol_enum!(
439    /// An IPv4 or IPv6 protocol number.
440    ///
441    /// `IpProto` encodes the protocol numbers whose values are the same for
442    /// both IPv4 and IPv6.
443    ///
444    /// The protocol numbers are maintained [by IANA][protocol-numbers].
445    ///
446    /// [protocol-numbers]: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
447    #[allow(missing_docs)]
448    #[derive(Copy, Clone, Hash, Eq, Ord, PartialEq, PartialOrd)]
449    pub enum IpProto: u8 {
450        Tcp, 6, "TCP";
451        Udp, 17, "UDP";
452        Reserved, 255, "IANA-RESERVED";
453    }
454);
455
456create_protocol_enum!(
457    /// An IPv4 protocol number.
458    ///
459    /// The protocol numbers are maintained [by IANA][protocol-numbers].
460    ///
461    /// [protocol-numbers]: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
462    #[allow(missing_docs)]
463    #[derive(Copy, Clone, Hash, Eq, Ord, PartialEq, PartialOrd)]
464    pub enum Ipv4Proto: u8 {
465        Icmp, 1, "ICMP";
466        Igmp, 2, "IGMP";
467        + Proto(IpProto);
468        _, "IPv4 protocol {}";
469    }
470);
471
472impl IpProtocol for Ipv4Proto {}
473impl<I: Ip + IpProtoExt> GenericOverIp<I> for Ipv4Proto {
474    type Type = I::Proto;
475}
476impl Sealed for Ipv4Proto {}
477
478create_protocol_enum!(
479    /// An IPv6 protocol number.
480    ///
481    /// The protocol numbers are maintained [by IANA][protocol-numbers].
482    ///
483    /// [protocol-numbers]: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
484    #[allow(missing_docs)]
485    #[derive(Copy, Clone, Hash, Eq, Ord, PartialEq, PartialOrd)]
486    pub enum Ipv6Proto: u8 {
487        Icmpv6, 58, "ICMPv6";
488        NoNextHeader, 59, "NO NEXT HEADER";
489        + Proto(IpProto);
490        _, "IPv6 protocol {}";
491    }
492);
493
494impl IpProtocol for Ipv6Proto {}
495impl<I: Ip + IpProtoExt> GenericOverIp<I> for Ipv6Proto {
496    type Type = I::Proto;
497}
498impl Sealed for Ipv6Proto {}
499
500create_protocol_enum!(
501    /// An IPv6 extension header.
502    ///
503    /// These are next header values that encode for extension header types.
504    /// This enum does not include upper layer protocol numbers even though they
505    /// may be valid next header values.
506    #[allow(missing_docs)]
507    #[derive(Copy, Clone, Hash, Eq, PartialEq)]
508    pub enum Ipv6ExtHdrType: u8 {
509        HopByHopOptions, 0, "IPv6 HOP-BY-HOP OPTIONS HEADER";
510        Routing, 43, "IPv6 ROUTING HEADER";
511        Fragment, 44, "IPv6 FRAGMENT HEADER";
512        EncapsulatingSecurityPayload, 50, "ENCAPSULATING SECURITY PAYLOAD";
513        Authentication, 51, "AUTHENTICATION HEADER";
514        DestinationOptions, 60, "IPv6 DESTINATION OPTIONS HEADER";
515        _,  "IPv6 EXTENSION HEADER {}";
516    }
517);
518
519/// An IP fragment offset.
520///
521/// Represents a fragment offset found in an IP header. The offset is expressed
522/// in units of 8 octets and must be smaller than `1 << 13`.
523///
524/// This is valid for both IPv4 ([RFC 791 Section 3.1]) and IPv6 ([RFC 8200
525/// Section 4.5]) headers.
526///
527/// [RFC 791 Section 3.1]: https://datatracker.ietf.org/doc/html/rfc791#section-3.1
528/// [RFC 8200 Section 4.5]: https://datatracker.ietf.org/doc/html/rfc8200#section-4.5
529#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)]
530pub struct FragmentOffset(u16);
531
532impl FragmentOffset {
533    /// The zero fragment offset.
534    pub const ZERO: FragmentOffset = FragmentOffset(0);
535
536    /// Creates a new offset from a raw u16 value.
537    ///
538    /// Returns `None` if `offset` is not smaller than `1 << 13`.
539    pub const fn new(offset: u16) -> Option<Self> {
540        if offset < 1 << 13 { Some(Self(offset)) } else { None }
541    }
542
543    /// Creates a new offset from a raw u16 value masking to only the lowest 13
544    /// bits.
545    pub(crate) fn new_with_lsb(offset: u16) -> Self {
546        Self(offset & 0x1FFF)
547    }
548
549    /// Creates a new offset from a raw u16 value masking to only the highest 13
550    /// bits.
551    pub(crate) fn new_with_msb(offset: u16) -> Self {
552        Self(offset >> 3)
553    }
554
555    /// Creates a new offset from a raw bytes value.
556    ///
557    /// Returns `None` if `offset_bytes` is not a multiple of `8`.
558    pub const fn new_with_bytes(offset_bytes: u16) -> Option<Self> {
559        if offset_bytes & 0x7 == 0 {
560            // NOTE: check for length above ensures this fits in a u16.
561            Some(Self(offset_bytes >> 3))
562        } else {
563            None
564        }
565    }
566
567    /// Consumes `self` returning the raw offset value in 8-octets multiples.
568    pub const fn into_raw(self) -> u16 {
569        self.0
570    }
571
572    /// Consumes `self` returning the total number of bytes represented by this
573    /// offset.
574    ///
575    /// Equal to 8 times the raw offset value.
576    pub fn into_bytes(self) -> u16 {
577        // NB: Shift can't overflow because `FragmentOffset` is guaranteed to
578        // fit in 13 bits.
579        self.0 << 3
580    }
581}
582
583#[cfg(test)]
584mod tests {
585    use super::*;
586
587    #[test]
588    fn fragment_offset_raw() {
589        assert_eq!(FragmentOffset::new(1), Some(FragmentOffset(1)));
590        assert_eq!(FragmentOffset::new(1 << 13), None);
591    }
592
593    #[test]
594    fn fragment_offset_bytes() {
595        assert_eq!(FragmentOffset::new_with_bytes(0), Some(FragmentOffset(0)));
596        for i in 1..=7 {
597            assert_eq!(FragmentOffset::new_with_bytes(i), None);
598        }
599        assert_eq!(FragmentOffset::new_with_bytes(8), Some(FragmentOffset(1)));
600        assert_eq!(FragmentOffset::new_with_bytes(core::u16::MAX), None);
601        assert_eq!(
602            FragmentOffset::new_with_bytes(core::u16::MAX & !0x7),
603            Some(FragmentOffset((1 << 13) - 1)),
604        );
605    }
606}