blob: 89fb88b4a0855f6f5170c4d88165d7f8189e8d99 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! IP protocol types.
// TODO(https://fxbug.dev/326330182): this import seems actually necessary. Is this a bug on the
// lint?
#[allow(unused_imports)]
use alloc::vec::Vec;
use core::cmp::PartialEq;
use core::convert::Infallible as Never;
use core::fmt::{Debug, Display};
use core::hash::Hash;
use net_types::ip::{GenericOverIp, Ip, IpAddr, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
use packet::{BufferViewMut, PacketBuilder, ParsablePacket, ParseMetadata};
use zerocopy::{ByteSlice, ByteSliceMut};
use crate::error::{IpParseError, IpParseResult};
use crate::ethernet::EthernetIpExt;
use crate::icmp::IcmpIpExt;
use crate::ipv4::{Ipv4Header, Ipv4OnlyMeta, Ipv4Packet, Ipv4PacketBuilder};
use crate::ipv6::{Ipv6Header, Ipv6Packet, Ipv6PacketBuilder};
use crate::private::Sealed;
/// An [`Ip`] extension trait adding an associated type for the IP protocol
/// number.
pub trait IpProtoExt: Ip {
/// The type representing an IPv4 or IPv6 protocol number.
///
/// For IPv4, this is [`Ipv4Proto`], and for IPv6, this is [`Ipv6Proto`].
type Proto: IpProtocol
+ GenericOverIp<Self, Type = Self::Proto>
+ GenericOverIp<Ipv4, Type = Ipv4Proto>
+ GenericOverIp<Ipv6, Type = Ipv6Proto>
+ Copy
+ Clone
+ Hash
+ Debug
+ Display
+ PartialEq
+ Eq;
}
impl IpProtoExt for Ipv4 {
type Proto = Ipv4Proto;
}
impl IpProtoExt for Ipv6 {
type Proto = Ipv6Proto;
}
/// An extension trait to the `Ip` trait adding associated types relevant for
/// packet parsing and serialization.
pub trait IpExt: EthernetIpExt + IcmpIpExt {
/// An IP packet type for this IP version.
type Packet<B: ByteSlice>: IpPacket<B, Self, Builder = Self::PacketBuilder>;
/// An IP packet builder type for the IP version.
type PacketBuilder: IpPacketBuilder<Self> + Eq;
}
impl IpExt for Ipv4 {
type Packet<B: ByteSlice> = Ipv4Packet<B>;
type PacketBuilder = Ipv4PacketBuilder;
}
impl IpExt for Ipv6 {
type Packet<B: ByteSlice> = Ipv6Packet<B>;
type PacketBuilder = Ipv6PacketBuilder;
}
/// An error encountered during NAT64 translation.
#[derive(Debug)]
pub enum Nat64Error {
/// Support not yet implemented in the library.
NotImplemented,
}
/// The result of NAT64 translation.
#[derive(Debug)]
pub enum Nat64TranslationResult<S, E> {
/// Forward the packet encoded in `S`.
Forward(S),
/// Silently drop the packet.
Drop,
/// An error was encountered.
Err(E),
}
/// An IPv4 or IPv6 packet.
///
/// `IpPacket` is implemented by `Ipv4Packet` and `Ipv6Packet`.
pub trait IpPacket<B: ByteSlice, I: IpExt>:
Sized + Debug + ParsablePacket<B, (), Error = IpParseError<I>>
{
/// A builder for this packet type.
type Builder: IpPacketBuilder<I>;
/// Metadata which is only present in the packet format of a specific version
/// of the IP protocol.
type VersionSpecificMeta;
/// The source IP address.
fn src_ip(&self) -> I::Addr;
/// The destination IP address.
fn dst_ip(&self) -> I::Addr;
/// The protocol number.
fn proto(&self) -> I::Proto;
/// The Time to Live (TTL) (IPv4) or Hop Limit (IPv6) field.
fn ttl(&self) -> u8;
/// Set the Time to Live (TTL) (IPv4) or Hop Limit (IPv6) field.
///
/// `set_ttl` updates the packet's TTL/Hop Limit in place.
fn set_ttl(&mut self, ttl: u8)
where
B: ByteSliceMut;
/// Get the body.
fn body(&self) -> &[u8];
/// Gets packet metadata relevant only for this version of the IP protocol.
fn version_specific_meta(&self) -> Self::VersionSpecificMeta;
/// Consume the packet and return some metadata.
///
/// Consume the packet and return the source address, destination address,
/// protocol, and `ParseMetadata`.
fn into_metadata(self) -> (I::Addr, I::Addr, I::Proto, ParseMetadata) {
let src_ip = self.src_ip();
let dst_ip = self.dst_ip();
let proto = self.proto();
let meta = self.parse_metadata();
(src_ip, dst_ip, proto, meta)
}
/// Converts a packet reference into a dynamically-typed reference.
fn as_ip_addr_ref(&self) -> IpAddr<&'_ Ipv4Packet<B>, &'_ Ipv6Packet<B>>;
/// Reassembles a fragmented packet into a parsed IP packet.
fn reassemble_fragmented_packet<BV: BufferViewMut<B>, IT: Iterator<Item = Vec<u8>>>(
buffer: BV,
header: Vec<u8>,
body_fragments: IT,
) -> IpParseResult<I, Self>
where
B: ByteSliceMut;
}
impl<B: ByteSlice> IpPacket<B, Ipv4> for Ipv4Packet<B> {
type Builder = Ipv4PacketBuilder;
type VersionSpecificMeta = Ipv4OnlyMeta;
fn src_ip(&self) -> Ipv4Addr {
Ipv4Header::src_ip(self)
}
fn dst_ip(&self) -> Ipv4Addr {
Ipv4Header::dst_ip(self)
}
fn proto(&self) -> Ipv4Proto {
Ipv4Header::proto(self)
}
fn ttl(&self) -> u8 {
Ipv4Header::ttl(self)
}
fn set_ttl(&mut self, ttl: u8)
where
B: ByteSliceMut,
{
Ipv4Packet::set_ttl(self, ttl)
}
fn body(&self) -> &[u8] {
Ipv4Packet::body(self)
}
fn version_specific_meta(&self) -> Ipv4OnlyMeta {
Ipv4OnlyMeta { id: Ipv4Header::id(self) }
}
fn as_ip_addr_ref(&self) -> IpAddr<&'_ Self, &'_ Ipv6Packet<B>> {
IpAddr::V4(self)
}
fn reassemble_fragmented_packet<BV: BufferViewMut<B>, IT: Iterator<Item = Vec<u8>>>(
buffer: BV,
header: Vec<u8>,
body_fragments: IT,
) -> IpParseResult<Ipv4, Ipv4Packet<B>>
where
B: ByteSliceMut,
{
crate::ipv4::reassemble_fragmented_packet(buffer, header, body_fragments)
}
}
impl<B: ByteSlice> IpPacket<B, Ipv6> for Ipv6Packet<B> {
type Builder = Ipv6PacketBuilder;
type VersionSpecificMeta = ();
fn src_ip(&self) -> Ipv6Addr {
Ipv6Header::src_ip(self)
}
fn dst_ip(&self) -> Ipv6Addr {
Ipv6Header::dst_ip(self)
}
fn proto(&self) -> Ipv6Proto {
Ipv6Packet::proto(self)
}
fn ttl(&self) -> u8 {
Ipv6Header::hop_limit(self)
}
fn set_ttl(&mut self, ttl: u8)
where
B: ByteSliceMut,
{
Ipv6Packet::set_hop_limit(self, ttl)
}
fn body(&self) -> &[u8] {
Ipv6Packet::body(self)
}
fn version_specific_meta(&self) -> () {
()
}
fn as_ip_addr_ref(&self) -> IpAddr<&'_ Ipv4Packet<B>, &'_ Self> {
IpAddr::V6(self)
}
fn reassemble_fragmented_packet<BV: BufferViewMut<B>, IT: Iterator<Item = Vec<u8>>>(
buffer: BV,
header: Vec<u8>,
body_fragments: IT,
) -> IpParseResult<Ipv6, Ipv6Packet<B>>
where
B: ByteSliceMut,
{
crate::ipv6::reassemble_fragmented_packet(buffer, header, body_fragments)
}
}
/// A builder for IP packets.
pub trait IpPacketBuilder<I: IpExt>: PacketBuilder + Clone + Debug {
/// Returns a new packet builder for an associated IP version with the given
/// given source and destination IP addresses, TTL (IPv4)/Hop Limit (IPv4)
/// and Protocol Number.
fn new(src_ip: I::Addr, dst_ip: I::Addr, ttl: u8, proto: I::Proto) -> Self;
/// Returns the source IP address for the builder.
fn src_ip(&self) -> I::Addr;
/// Returns the destination IP address for the builder.
fn dst_ip(&self) -> I::Addr;
/// Returns the IP protocol number for the builder.
fn proto(&self) -> I::Proto;
}
/// An IPv4 or IPv6 protocol number.
pub trait IpProtocol: From<IpProto> + Sealed + Send + Sync + 'static {}
impl Sealed for Never {}
create_protocol_enum!(
/// An IPv4 or IPv6 protocol number.
///
/// `IpProto` encodes the protocol numbers whose values are the same for
/// both IPv4 and IPv6.
///
/// The protocol numbers are maintained [by IANA][protocol-numbers].
///
/// [protocol-numbers]: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
#[allow(missing_docs)]
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub enum IpProto: u8 {
Tcp, 6, "TCP";
Udp, 17, "UDP";
}
);
create_protocol_enum!(
/// An IPv4 protocol number.
///
/// The protocol numbers are maintained [by IANA][protocol-numbers].
///
/// [protocol-numbers]: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
#[allow(missing_docs)]
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub enum Ipv4Proto: u8 {
Icmp, 1, "ICMP";
Igmp, 2, "IGMP";
+ Proto(IpProto);
_, "IPv4 protocol {}";
}
);
impl IpProtocol for Ipv4Proto {}
impl<I: Ip + IpProtoExt> GenericOverIp<I> for Ipv4Proto {
type Type = I::Proto;
}
impl Sealed for Ipv4Proto {}
create_protocol_enum!(
/// An IPv6 protocol number.
///
/// The protocol numbers are maintained [by IANA][protocol-numbers].
///
/// [protocol-numbers]: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
#[allow(missing_docs)]
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub enum Ipv6Proto: u8 {
Icmpv6, 58, "ICMPv6";
NoNextHeader, 59, "NO NEXT HEADER";
+ Proto(IpProto);
_, "IPv6 protocol {}";
}
);
impl IpProtocol for Ipv6Proto {}
impl<I: Ip + IpProtoExt> GenericOverIp<I> for Ipv6Proto {
type Type = I::Proto;
}
impl Sealed for Ipv6Proto {}
create_protocol_enum!(
/// An IPv6 extension header.
///
/// These are next header values that encode for extension header types.
/// This enum does not include upper layer protocol numbers even though they
/// may be valid next header values.
#[allow(missing_docs)]
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
pub enum Ipv6ExtHdrType: u8 {
HopByHopOptions, 0, "IPv6 HOP-BY-HOP OPTIONS HEADER";
Routing, 43, "IPv6 ROUTING HEADER";
Fragment, 44, "IPv6 FRAGMENT HEADER";
EncapsulatingSecurityPayload, 50, "ENCAPSULATING SECURITY PAYLOAD";
Authentication, 51, "AUTHENTICATION HEADER";
DestinationOptions, 60, "IPv6 DESTINATION OPTIONS HEADER";
_, "IPv6 EXTENSION HEADER {}";
}
);