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