blob: d3fc3d86699dcb7a428546795b3e34a4e62517b4 [file] [log] [blame] [edit]
// Copyright 2019 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.
// TODO: Edit this doc comment (it's copy+pasted from the Netstack3 core)
//! Internet Protocol (IP) types.
//!
//! This module provides support for various types and traits relating to IPv4
//! and IPv6, including a number of mechanisms for abstracting over details
//! which are shared between IPv4 and IPv6.
//!
//! # `Ip` and `IpAddress`
//!
//! The most important traits are [`Ip`] and [`IpAddress`].
//!
//! `Ip` represents a version of the IP protocol - either IPv4 or IPv6 - and is
//! implemented by [`Ipv4`] and [`Ipv6`]. These types exist only at the type
//! level - they cannot be constructed at runtime. They provide a place to put
//! constants and functionality which are not associated with a particular type,
//! and they allow code to be written which is generic over the version of the
//! IP protocol. For example:
//!
//! ```rust
//! # use net_types::ip::{Ip, IpAddress, Subnet};
//! struct Entry<A: IpAddress> {
//! subnet: Subnet<A>,
//! dest: Destination<A>,
//! }
//!
//! enum Destination<A: IpAddress> {
//! Local { device_id: usize },
//! Remote { dst: A },
//! }
//!
//! struct ForwardingTable<I: Ip> {
//! entries: Vec<Entry<I::Addr>>,
//! }
//! ```
//!
//! See also [`IpVersionMarker`].
//!
//! The `IpAddress` trait is implemented by the concrete [`Ipv4Addr`] and
//! [`Ipv6Addr`] types.
//!
//! # Runtime types
//!
//! Sometimes, it is not known at compile time which version of a given type -
//! IPv4 or IPv6 - is present. For these cases, enums are provided with variants
//! for both IPv4 and IPv6. These are [`IpAddr`], [`SubnetEither`], and
//! [`AddrSubnetEither`].
//!
//! # Composite types
//!
//! This modules also provides composite types such as [`Subnet`] and
//! [`AddrSubnet`].
use core::fmt::{self, Debug, Display, Formatter};
use core::hash::Hash;
use core::mem;
use core::ops::{Deref, DerefMut};
#[cfg(feature = "std")]
use std::net;
pub use net_types_macros::GenericOverIp;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
use crate::{
sealed, LinkLocalAddr, LinkLocalAddress, MappedAddress, MulticastAddr, MulticastAddress,
NonMappedAddr, Scope, ScopeableAddress, SpecifiedAddr, SpecifiedAddress, UnicastAddr,
UnicastAddress, Witness,
};
// NOTE on passing by reference vs by value: Clippy advises us to pass IPv4
// addresses by value, and IPv6 addresses by reference. For concrete types, we
// do the right thing. For the IpAddress trait, we use references in order to
// optimize (albeit very slightly) for IPv6 performance.
/// An IP protocol version.
#[allow(missing_docs)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)]
pub enum IpVersion {
V4,
V6,
}
/// Evaluates `expression` for any given `ip_version`.
///
/// `type_param` will be defined to be [`crate::ip::Ipv4`] for
/// [`crate::ip::IpVersion::V4`], and [`crate::ip::Ipv6`] for
/// [`crate::ip::IpVersion::V6`].
///
/// Example usage:
///
/// ```
/// let ip_version: IpVersion = foo();
/// for_any_ip_version!(ip_version, I, some_ip_generic_fn::<I>());
/// ```
#[macro_export]
macro_rules! for_any_ip_version {
($ip_version:expr, $type_param:ident, $expression:expr) => {
match $ip_version {
$crate::ip::IpVersion::V4 => {
type $type_param = $crate::ip::Ipv4;
$expression
}
$crate::ip::IpVersion::V6 => {
type $type_param = $crate::ip::Ipv6;
$expression
}
}
};
}
/// A zero-sized type that carries IP version information.
///
/// `IpVersionMarker` is typically used by types that are generic over IP
/// version, but without any other associated data. In this sense,
/// `IpVersionMarker` behaves similarly to [`PhantomData`].
///
/// [`PhantomData`]: core::marker::PhantomData
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, GenericOverIp)]
#[generic_over_ip(I, Ip)]
pub struct IpVersionMarker<I: Ip> {
_marker: core::marker::PhantomData<I>,
}
impl<I: Ip> IpVersionMarker<I> {
/// Creates a new `IpVersionMarker`.
// TODO(https://github.com/rust-lang/rust/issues/67792): Remove once
// `const_trait_impl` is stabilized.
pub const fn new() -> Self {
Self { _marker: core::marker::PhantomData }
}
}
impl<I: Ip> Default for IpVersionMarker<I> {
fn default() -> Self {
Self { _marker: core::marker::PhantomData }
}
}
impl<I: Ip> Debug for IpVersionMarker<I> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "IpVersionMarker<{}>", I::NAME)
}
}
/// An IP address.
///
/// By default, the contained address types are [`Ipv4Addr`] and [`Ipv6Addr`].
/// However, any types can be provided. This is intended to support types like
/// `IpAddr<SpecifiedAddr<Ipv4Addr>, SpecifiedAddr<Ipv6Addr>>`. `From` is
/// implemented to support conversions in both directions between
/// `IpAddr<SpecifiedAddr<Ipv4Addr>, SpecifiedAddr<Ipv6Addr>>` and
/// `SpecifiedAddr<IpAddr>`, and similarly for other witness types.
#[allow(missing_docs)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)]
pub enum IpAddr<V4 = Ipv4Addr, V6 = Ipv6Addr> {
V4(V4),
V6(V6),
}
impl<V4: Display, V6: Display> Display for IpAddr<V4, V6> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::V4(v4) => v4.fmt(f),
Self::V6(v6) => v6.fmt(f),
}
}
}
impl<V4, V6> IpAddr<V4, V6> {
/// Transposes an `IpAddr` of a witness type to a witness type of an
/// `IpAddr`.
///
/// For example, `transpose` can be used to convert an
/// `IpAddr<SpecifiedAddr<Ipv4Addr>, SpecifiedAddr<Ipv6Addr>>` into a
/// `SpecifiedAddr<IpAddr<Ipv4Addr, Ipv6Addr>>`.
pub fn transpose<W: IpAddrWitness<V4 = V4, V6 = V6>>(self) -> W {
match self {
IpAddr::V4(addr) => W::from_v4(addr),
IpAddr::V6(addr) => W::from_v6(addr),
}
}
}
impl<A: IpAddress> From<A> for IpAddr {
#[inline]
fn from(addr: A) -> IpAddr {
addr.to_ip_addr()
}
}
impl<A: IpAddress, const N: usize> From<[A; N]> for IpAddr<[Ipv4Addr; N], [Ipv6Addr; N]> {
#[inline]
fn from(addrs: [A; N]) -> Self {
A::array_into_ip_addr(addrs)
}
}
#[cfg(feature = "std")]
impl From<net::IpAddr> for IpAddr {
#[inline]
fn from(addr: net::IpAddr) -> IpAddr {
match addr {
net::IpAddr::V4(addr) => IpAddr::V4(addr.into()),
net::IpAddr::V6(addr) => IpAddr::V6(addr.into()),
}
}
}
#[cfg(feature = "std")]
impl From<IpAddr> for net::IpAddr {
fn from(addr: IpAddr) -> net::IpAddr {
match addr {
IpAddr::V4(addr) => net::IpAddr::V4(addr.into()),
IpAddr::V6(addr) => net::IpAddr::V6(addr.into()),
}
}
}
impl IpVersion {
/// The number for this IP protocol version.
///
/// 4 for `V4` and 6 for `V6`.
#[inline]
pub fn version_number(self) -> u8 {
match self {
IpVersion::V4 => 4,
IpVersion::V6 => 6,
}
}
/// Is this IPv4?
#[inline]
pub fn is_v4(self) -> bool {
self == IpVersion::V4
}
/// Is this IPv6?
#[inline]
pub fn is_v6(self) -> bool {
self == IpVersion::V6
}
}
/// The maximum transmit unit, i.e., the maximum size of an entire IP packet
/// one link can transmit.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Mtu(u32);
impl Mtu {
/// Creates MTU from the maximum size of an entire IP packet in bytes.
pub const fn new(mtu: u32) -> Self {
Self(mtu)
}
/// Gets the numeric value of the MTU.
pub const fn get(&self) -> u32 {
let Self(mtu) = self;
*mtu
}
/// Creates a new `Mtu` with the maximum possible representation.
pub const fn max() -> Self {
Self(u32::MAX)
}
/// Equivalent to [`Mtu::max`], but with a name more telling for usage in
/// contexts where many `Mtu` instances are composed to enforce a minimum
/// `Mtu` value.
pub const fn no_limit() -> Self {
Self::max()
}
}
impl From<Mtu> for u32 {
fn from(Mtu(mtu): Mtu) -> Self {
mtu
}
}
impl From<Mtu> for usize {
fn from(Mtu(mtu): Mtu) -> Self {
mtu.try_into().expect("mtu must fit usize")
}
}
/// A trait for IP protocol versions.
///
/// `Ip` encapsulates the details of a version of the IP protocol. It includes a
/// runtime representation of the protocol version ([`VERSION`]), the type of
/// addresses for this version ([`Addr`]), and a number of constants which exist
/// in both protocol versions. This trait is sealed, and there are guaranteed to
/// be no other implementors besides these. Code - including unsafe code - may
/// rely on this assumption for its correctness and soundness.
///
/// Note that the implementors of this trait cannot be instantiated; they only
/// exist at the type level.
///
/// [`VERSION`]: Ip::VERSION
/// [`Addr`]: Ip::Addr
pub trait Ip:
Sized
+ Clone
+ Copy
+ Debug
+ Default
+ Eq
+ Hash
+ Ord
+ PartialEq
+ PartialOrd
+ Send
+ Sync
+ sealed::Sealed
+ 'static
{
/// The IP version.
///
/// `V4` for IPv4 and `V6` for IPv6.
const VERSION: IpVersion;
/// The zero-sized-type IP version marker.
const VERSION_MARKER: IpVersionMarker<Self>;
/// The unspecified address.
///
/// This is 0.0.0.0 for IPv4 and :: for IPv6.
const UNSPECIFIED_ADDRESS: Self::Addr;
/// The default loopback address.
///
/// When sending packets to a loopback interface, this address is used as
/// the source address. It is an address in the [`LOOPBACK_SUBNET`].
///
/// [`LOOPBACK_SUBNET`]: Ip::LOOPBACK_SUBNET
const LOOPBACK_ADDRESS: SpecifiedAddr<Self::Addr>;
/// The subnet of loopback addresses.
///
/// Addresses in this subnet must not appear outside a host, and may only be
/// used for loopback interfaces.
const LOOPBACK_SUBNET: Subnet<Self::Addr>;
/// The subnet of multicast addresses.
const MULTICAST_SUBNET: Subnet<Self::Addr>;
/// The subnet of link-local unicast addresses.
///
/// Note that some multicast addresses are also link-local. In IPv4, these
/// are contained in the [link-local multicast subnet]. In IPv6, the
/// link-local multicast addresses are not organized into a single subnet;
/// instead, whether a multicast IPv6 address is link-local is a function of
/// its scope.
///
/// [link-local multicast subnet]: Ipv4::LINK_LOCAL_MULTICAST_SUBNET
const LINK_LOCAL_UNICAST_SUBNET: Subnet<Self::Addr>;
/// "IPv4" or "IPv6".
const NAME: &'static str;
/// The minimum link MTU for this version.
///
/// Every internet link supporting this IP version must have a maximum
/// transmission unit (MTU) of at least this many bytes. This MTU applies to
/// the size of an IP packet, and does not include any extra bytes used by
/// encapsulating packets (Ethernet frames, GRE packets, etc).
const MINIMUM_LINK_MTU: Mtu;
/// The address type for this IP version.
///
/// [`Ipv4Addr`] for IPv4 and [`Ipv6Addr`] for IPv6.
type Addr: IpAddress<Version = Self>
+ GenericOverIp<Self, Type = Self::Addr>
+ GenericOverIp<Ipv4, Type = Ipv4Addr>
+ GenericOverIp<Ipv6, Type = Ipv6Addr>;
/// Apply one of the given functions to the input and return the result.
///
/// This makes it possible to implement specialized behavior for IPv4 and
/// IPv6 versions that is more versatile than matching on [`Ip::VERSION`].
/// With a `match` expression, all branches must produce a value of the
/// same type. `map_ip` relaxes that restriction by instead requiring that
/// inputs and outputs are [`GenericOverIp`].
///
/// Using `map_ip`, you can write generic code with specialized
/// implementations for different IP versions where some or all of the input
/// and output arguments have a type parameter `I: Ip`. As an example,
/// consider the following:
///
/// ```
/// // Swaps the order of the addresses only if `I=Ipv4`.
/// fn swap_only_if_ipv4<I: Ip>(addrs: (I::Addr, I::Addr)) -> (I::Addr, I::Addr) {
/// I::map_ip::<(I::Addr, I::Addr), (I::Addr, I::Addr)>(
/// addrs,
/// |(a, b): (Ipv4Addr, Ipv4Addr)| (b, a),
/// |ab: (Ipv6Addr, Ipv6Addr)| ab
/// )
/// }
/// ```
///
/// Note that the input and output arguments both depend on the type
/// parameter `I`, but the closures take an [`Ipv4Addr`] or [`Ipv6Addr`].
///
/// Types that don't implement `GenericOverIp` can be wrapped in
/// [`IpInvariant`], which implements `GenericOverIp` assuming the type
/// inside doesn't have any IP-related components.
fn map_ip<
In: GenericOverIp<Self, Type = In> + GenericOverIp<Ipv4> + GenericOverIp<Ipv6>,
Out: GenericOverIp<Self, Type = Out> + GenericOverIp<Ipv4> + GenericOverIp<Ipv6>,
>(
input: In,
v4: impl FnOnce(<In as GenericOverIp<Ipv4>>::Type) -> <Out as GenericOverIp<Ipv4>>::Type,
v6: impl FnOnce(<In as GenericOverIp<Ipv6>>::Type) -> <Out as GenericOverIp<Ipv6>>::Type,
) -> Out;
/// Apply one of the given functions to the input and return the result.
///
/// This is similar to `map_ip`, except only the input type is required to
/// be [`GenericOverIp`], while the output type is invariant. This allows
/// callers to more conveniently write this use case without having to wrap
/// the result in a type like [`IpInvariant`].
fn map_ip_in<
In: GenericOverIp<Self, Type = In> + GenericOverIp<Ipv4> + GenericOverIp<Ipv6>,
Out,
>(
input: In,
v4: impl FnOnce(<In as GenericOverIp<Ipv4>>::Type) -> Out,
v6: impl FnOnce(<In as GenericOverIp<Ipv6>>::Type) -> Out,
) -> Out {
Self::map_ip::<_, IpInvariant<_>>(
input,
|input| IpInvariant(v4(input)),
|input| IpInvariant(v6(input)),
)
.into_inner()
}
/// Apply one of the given functions to the input and return the result.
///
/// This is similar to `map_ip`, except only the output type is required to
/// be [`GenericOverIp`], while the input type is invariant. This allows
/// callers to more conveniently write this use case without having to wrap
/// the input in a type like [`IpInvariant`].
fn map_ip_out<
In,
Out: GenericOverIp<Self, Type = Out> + GenericOverIp<Ipv4> + GenericOverIp<Ipv6>,
>(
input: In,
v4: impl FnOnce(In) -> <Out as GenericOverIp<Ipv4>>::Type,
v6: impl FnOnce(In) -> <Out as GenericOverIp<Ipv6>>::Type,
) -> Out {
Self::map_ip(
IpInvariant(input),
|IpInvariant(input)| v4(input),
|IpInvariant(input)| v6(input),
)
}
}
/// Invokes `I::map_ip`, passing the same function body as both arguments.
///
/// The first argument is always the `I` on which to invoke `I::map_ip`.
/// Optionally, this can include an alias (`I as IpAlias`) that should be bound
/// to `Ipv4` and `Ipv6` for each instantiation of the function body. (If the
/// `Ip` argument passed is a simple identifier, then it is automatically
/// aliased in this way.)
/// The next argument is the input to thread through `map_ip` to the function,
/// and the final argument is the function to be duplicated to serve as the
/// closures passed to `map_ip`.
///
/// This macro helps avoid code duplication when working with types that are
/// _not_ GenericOverIp, but have identical shapes such that the actual text of
/// the code you are writing is identical. This should be very rare, and is
/// generally limited to cases where we are interfacing with code that we don't
/// have the ability to make generic-over-IP -- when possible, it's better to
/// push `I: Ip` generics further through the types you are working with instead
/// so that you can avoid using `map_ip` entirely.
///
/// Example:
///
/// ```
/// // Imagine that `IpExt` is implemented for concrete `Ipv4` and `Ipv6` but
/// // not for blanket `I: Ip`.
/// struct Foo<I: IpExt>;
///
/// struct FooFactory;
/// impl FooFactory {
/// fn get<I: IpExt>(&self) -> Foo<I> {
/// unimplemented!()
/// }
/// }
///
/// struct FooSink<I: IpExt>;
/// impl<I: IpExt> FooSink<I> {
/// fn use_foo(&self, foo: Foo<I>) {
/// unimplemented!()
/// }
/// }
///
/// fn do_something<I: Ip>(factory: FooFactory) -> Foo<I> {
/// map_ip_twice!(
/// I,
/// (),
/// |()| {
/// // This works because even though the `I` from the function decl
/// // doesn't have an `IpExt` bound, it's aliased to either `Ipv4`
/// // or `Ipv6` here.
/// factory.get::<I>()
/// },
/// )
/// }
///
/// fn do_something_else<I: IpExt>(factory: FooFactory, foo_sink: FooSink<I>) {
/// map_ip_twice!(
/// // Introduce different alias to avoid shadowing `I`.
/// I as IpAlias,
/// (),
/// |()| {
/// let foo_with_orig_ip = factory.get::<I>();
/// // The fact that `I` was not shadowed allows us to make use of
/// // `foo_sink` by capture rather than needing to thread it
/// // through the generic-over-IP input.
/// foo_sink.use_foo(foo_with_orig_ip)
/// },
/// )
/// }
/// ```
#[macro_export]
macro_rules! map_ip_twice {
// This case triggers if we're passed an `Ip` implementor that is a simple
// identifier in-scope (e.g. `I`), which allows us to automatically alias it
// to `Ipv4` and `Ipv6` in each `$fn` instantiation.
($ip:ident, $input:expr, $fn:expr $(,)?) => {
$crate::map_ip_twice!($ip as $ip, $input, $fn)
};
// This case triggers if we're passed an `Ip` implementor that is _not_ an
// identifier, and thus we can't use it as the left-hand-side of a type
// alias binding (e.g. `<A as IpAddress>::Version`).
($ip:ty, $input:expr, $fn:expr $(,)?) => {
<$ip as $crate::ip::Ip>::map_ip($input, { $fn }, { $fn })
};
($ip:ty as $iptypealias:ident, $input:expr, $fn:expr $(,)?) => {
<$ip as $crate::ip::Ip>::map_ip(
$input,
{
#[allow(dead_code)]
type $iptypealias = $crate::ip::Ipv4;
$fn
},
{
#[allow(dead_code)]
type $iptypealias = $crate::ip::Ipv6;
$fn
},
)
};
}
/// IPv4.
///
/// `Ipv4` implements [`Ip`] for IPv4.
///
/// Note that this type has no value constructor. It is used purely at the type
/// level. Attempting to construct it by calling `Default::default` will panic.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Ipv4 {}
impl Default for Ipv4 {
fn default() -> Ipv4 {
panic!("Ipv4 default")
}
}
impl sealed::Sealed for Ipv4 {}
impl Ip for Ipv4 {
const VERSION: IpVersion = IpVersion::V4;
const VERSION_MARKER: IpVersionMarker<Self> = IpVersionMarker::new();
// TODO(https://fxbug.dev/42163997): Document the standard in which this
// constant is defined.
const UNSPECIFIED_ADDRESS: Ipv4Addr = Ipv4Addr::new([0, 0, 0, 0]);
/// The default IPv4 address used for loopback, defined in [RFC 5735 Section
/// 3].
///
/// Note that while this address is the most commonly used address for
/// loopback traffic, any address in the [`LOOPBACK_SUBNET`] may be used.
///
/// [RFC 5735 Section 3]: https://datatracker.ietf.org/doc/html/rfc5735#section-3
/// [`LOOPBACK_SUBNET`]: Ipv4::LOOPBACK_SUBNET
const LOOPBACK_ADDRESS: SpecifiedAddr<Ipv4Addr> =
unsafe { SpecifiedAddr::new_unchecked(Ipv4Addr::new([127, 0, 0, 1])) };
/// The IPv4 loopback subnet, defined in [RFC 1122 Section 3.2.1.3].
///
/// [RFC 1122 Section 3.2.1.3]: https://www.rfc-editor.org/rfc/rfc1122.html#section-3.2.1.3
const LOOPBACK_SUBNET: Subnet<Ipv4Addr> =
Subnet { network: Ipv4Addr::new([127, 0, 0, 0]), prefix: 8 };
/// The IPv4 Multicast subnet, defined in [RFC 1112 Section 4].
///
/// [RFC 1112 Section 4]: https://www.rfc-editor.org/rfc/rfc1112.html#section-4
const MULTICAST_SUBNET: Subnet<Ipv4Addr> = Self::CLASS_D_SUBNET;
/// The subnet of link-local unicast IPv4 addresses, outlined in [RFC 3927
/// Section 2.1].
///
/// [RFC 3927 Section 2.1]: https://tools.ietf.org/html/rfc3927#section-2.1
const LINK_LOCAL_UNICAST_SUBNET: Subnet<Ipv4Addr> =
Subnet { network: Ipv4Addr::new([169, 254, 0, 0]), prefix: 16 };
const NAME: &'static str = "IPv4";
/// The IPv4 minimum link MTU.
///
/// Per [RFC 791 Section 3.2], "[\e\]very internet module must be able to
/// forward a datagram of 68 octets without further fragmentation."
///
/// [RFC 791 Section 3.2]: https://tools.ietf.org/html/rfc791#section-3.2
const MINIMUM_LINK_MTU: Mtu = Mtu(68);
type Addr = Ipv4Addr;
fn map_ip<
In: GenericOverIp<Self, Type = In> + GenericOverIp<Ipv4> + GenericOverIp<Ipv6>,
Out: GenericOverIp<Self, Type = Out> + GenericOverIp<Ipv4> + GenericOverIp<Ipv6>,
>(
input: In,
v4: impl FnOnce(<In as GenericOverIp<Ipv4>>::Type) -> <Out as GenericOverIp<Ipv4>>::Type,
_v6: impl FnOnce(<In as GenericOverIp<Ipv6>>::Type) -> <Out as GenericOverIp<Ipv6>>::Type,
) -> Out {
v4(input)
}
}
impl Ipv4 {
/// The limited broadcast address.
///
/// The limited broadcast address is considered to be a broadcast address on
/// all networks regardless of subnet address. This is distinct from the
/// subnet-specific broadcast address (e.g., 192.168.255.255 on the subnet
/// 192.168.0.0/16). It is defined in the [IANA IPv4 Special-Purpose Address
/// Registry].
///
/// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
pub const LIMITED_BROADCAST_ADDRESS: SpecifiedAddr<Ipv4Addr> =
unsafe { SpecifiedAddr::new_unchecked(Ipv4Addr::new([255, 255, 255, 255])) };
/// The Class A subnet.
///
/// The Class A subnet is defined in [RFC 1812 section 2.2.5.1].
///
/// [RFC 1812 section 2.2.5.1]: https://datatracker.ietf.org/doc/html/rfc1812#section-2.2.5.1
pub const CLASS_A_SUBNET: Subnet<Ipv4Addr> =
Subnet { network: Ipv4Addr::new([0, 0, 0, 0]), prefix: 1 };
/// The Class B subnet.
///
/// The Class B subnet is defined in [RFC 1812 section 2.2.5.1].
///
/// [RFC 1812 section 2.2.5.1]: https://datatracker.ietf.org/doc/html/rfc1812#section-2.2.5.1
pub const CLASS_B_SUBNET: Subnet<Ipv4Addr> =
Subnet { network: Ipv4Addr::new([128, 0, 0, 0]), prefix: 2 };
/// The Class C subnet.
///
/// The Class C subnet is defined in [RFC 1812 section 2.2.5.1].
///
/// [RFC 1812 section 2.2.5.1]: https://datatracker.ietf.org/doc/html/rfc1812#section-2.2.5.1
pub const CLASS_C_SUBNET: Subnet<Ipv4Addr> =
Subnet { network: Ipv4Addr::new([192, 0, 0, 0]), prefix: 3 };
/// The Class D subnet.
///
/// This subnet is also known as the multicast subnet.
///
/// The Class D subnet is defined in [RFC 1812 section 2.2.5.1].
///
/// [RFC 1812 section 2.2.5.1]: https://datatracker.ietf.org/doc/html/rfc1812#section-2.2.5.1
pub const CLASS_D_SUBNET: Subnet<Ipv4Addr> =
Subnet { network: Ipv4Addr::new([224, 0, 0, 0]), prefix: 4 };
/// The Class E subnet.
///
/// The Class E subnet is meant for experimental purposes, and should not be
/// used on the general internet. [RFC 1812 Section 5.3.7] suggests that
/// routers SHOULD discard packets with a source address in the Class E
/// subnet. The Class E subnet is defined in [RFC 1112 Section 4].
///
/// [RFC 1812 Section 5.3.7]: https://tools.ietf.org/html/rfc1812#section-5.3.7
/// [RFC 1112 Section 4]: https://datatracker.ietf.org/doc/html/rfc1112#section-4
pub const CLASS_E_SUBNET: Subnet<Ipv4Addr> =
Subnet { network: Ipv4Addr::new([240, 0, 0, 0]), prefix: 4 };
/// The subnet of link-local multicast addresses, outlined in [RFC 5771
/// Section 4].
///
/// [RFC 5771 Section 4]: https://tools.ietf.org/html/rfc5771#section-4
pub const LINK_LOCAL_MULTICAST_SUBNET: Subnet<Ipv4Addr> =
Subnet { network: Ipv4Addr::new([224, 0, 0, 0]), prefix: 24 };
/// The multicast address subscribed to by all systems on the local network,
/// defined in the [IPv4 Multicast Address Space Registry].
///
/// [IPv4 Multicast Address Space Registry]: https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml
pub const ALL_SYSTEMS_MULTICAST_ADDRESS: MulticastAddr<Ipv4Addr> =
unsafe { MulticastAddr::new_unchecked(Ipv4Addr::new([224, 0, 0, 1])) };
/// The multicast address subscribed to by all routers on the local network,
/// defined in the [IPv4 Multicast Address Space Registry].
///
/// [IPv4 Multicast Address Space Registry]: https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml
pub const ALL_ROUTERS_MULTICAST_ADDRESS: MulticastAddr<Ipv4Addr> =
unsafe { MulticastAddr::new_unchecked(Ipv4Addr::new([224, 0, 0, 2])) };
}
/// IPv6.
///
/// `Ipv6` implements [`Ip`] for IPv6.
///
/// Note that this type has no value constructor. It is used purely at the type
/// level. Attempting to construct it by calling `Default::default` will panic.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Ipv6 {}
impl Default for Ipv6 {
fn default() -> Ipv6 {
panic!("Ipv6 default")
}
}
impl sealed::Sealed for Ipv6 {}
impl Ip for Ipv6 {
const VERSION: IpVersion = IpVersion::V6;
const VERSION_MARKER: IpVersionMarker<Self> = IpVersionMarker::new();
/// The unspecified IPv6 address, defined in [RFC 4291 Section 2.5.2].
///
/// Per RFC 4291:
///
/// > The address 0:0:0:0:0:0:0:0 is called the unspecified address. It
/// > must never be assigned to any node. It indicates the absence of an
/// > address. One example of its use is in the Source Address field of any
/// > IPv6 packets sent by an initializing host before it has learned its
/// > own address.
/// >
/// > The unspecified address must not be used as the destination address of
/// > IPv6 packets or in IPv6 Routing headers. An IPv6 packet with a source
/// > address of unspecified must never be forwarded by an IPv6 router.
///
/// [RFC 4291 Section 2.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2
const UNSPECIFIED_ADDRESS: Ipv6Addr = Ipv6Addr::new([0; 8]);
/// The loopback IPv6 address, defined in [RFC 4291 Section 2.5.3].
///
/// Per RFC 4291:
///
/// > The unicast address 0:0:0:0:0:0:0:1 is called the loopback address.
/// > It may be used by a node to send an IPv6 packet to itself. It must
/// > not be assigned to any physical interface. It is treated as having
/// > Link-Local scope, and may be thought of as the Link-Local unicast
/// > address of a virtual interface (typically called the "loopback
/// > interface") to an imaginary link that goes nowhere.
/// >
/// > The loopback address must not be used as the source address in IPv6
/// > packets that are sent outside of a single node. An IPv6 packet with
/// > a destination address of loopback must never be sent outside of a
/// > single node and must never be forwarded by an IPv6 router. A packet
/// > received on an interface with a destination address of loopback must
/// > be dropped.
///
/// [RFC 4291 Section 2.5.3]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3
const LOOPBACK_ADDRESS: SpecifiedAddr<Ipv6Addr> =
unsafe { SpecifiedAddr::new_unchecked(Ipv6Addr::new([0, 0, 0, 0, 0, 0, 0, 1])) };
/// The subnet of loopback IPv6 addresses, defined in [RFC 4291 Section 2.4].
///
/// Note that the IPv6 loopback subnet is a /128, meaning that it contains
/// only one address - the [`LOOPBACK_ADDRESS`].
///
/// [RFC 4291 Section 2.4]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.4
/// [`LOOPBACK_ADDRESS`]: Ipv6::LOOPBACK_ADDRESS
const LOOPBACK_SUBNET: Subnet<Ipv6Addr> =
Subnet { network: Ipv6Addr::new([0, 0, 0, 0, 0, 0, 0, 1]), prefix: 128 };
/// The subnet of multicast IPv6 addresses, defined in [RFC 4291 Section
/// 2.7].
///
/// [RFC 4291 Section 2.7]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.7
const MULTICAST_SUBNET: Subnet<Ipv6Addr> =
Subnet { network: Ipv6Addr::new([0xff00, 0, 0, 0, 0, 0, 0, 0]), prefix: 8 };
/// The subnet of link-local unicast addresses, defined in [RFC 4291 Section
/// 2.4].
///
/// Note that multicast addresses can also be link-local. However, there is
/// no single subnet of link-local multicast addresses. For more details on
/// link-local multicast addresses, see [RFC 4291 Section 2.7].
///
/// [RFC 4291 Section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
/// [RFC 4291 Section 2.7]: https://tools.ietf.org/html/rfc4291#section-2.7
const LINK_LOCAL_UNICAST_SUBNET: Subnet<Ipv6Addr> =
Subnet { network: Ipv6Addr::new([0xfe80, 0, 0, 0, 0, 0, 0, 0]), prefix: 10 };
const NAME: &'static str = "IPv6";
/// The IPv6 minimum link MTU, defined in [RFC 8200 Section 5].
///
/// Per RFC 8200:
///
/// > IPv6 requires that every link in the Internet have an MTU of 1280
/// > octets or greater. This is known as the IPv6 minimum link MTU. On any
/// > link that cannot convey a 1280-octet packet in one piece, link-
/// > specific fragmentation and reassembly must be provided at a layer
/// > below IPv6.
///
/// [RFC 8200 Section 5]: https://tools.ietf.org/html/rfc8200#section-5
const MINIMUM_LINK_MTU: Mtu = Mtu(1280);
type Addr = Ipv6Addr;
fn map_ip<
In: GenericOverIp<Self, Type = In> + GenericOverIp<Ipv4> + GenericOverIp<Ipv6>,
Out: GenericOverIp<Self, Type = Out> + GenericOverIp<Ipv4> + GenericOverIp<Ipv6>,
>(
input: In,
_v4: impl FnOnce(<In as GenericOverIp<Ipv4>>::Type) -> <Out as GenericOverIp<Ipv4>>::Type,
v6: impl FnOnce(<In as GenericOverIp<Ipv6>>::Type) -> <Out as GenericOverIp<Ipv6>>::Type,
) -> Out {
v6(input)
}
}
impl Ipv6 {
/// The loopback address represented as a [`UnicastAddr`].
///
/// This is equivalent to [`LOOPBACK_ADDRESS`], except that it is a
/// [`UnicastAddr`] witness type.
///
/// [`LOOPBACK_ADDRESS`]: Ipv6::LOOPBACK_ADDRESS
pub const LOOPBACK_IPV6_ADDRESS: UnicastAddr<Ipv6Addr> =
unsafe { UnicastAddr::new_unchecked(Ipv6::LOOPBACK_ADDRESS.0) };
/// The IPv6 All Nodes multicast address in link-local scope, defined in
/// [RFC 4291 Section 2.7.1].
///
/// [RFC 4291 Section 2.7.1]: https://tools.ietf.org/html/rfc4291#section-2.7.1
pub const ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS: MulticastAddr<Ipv6Addr> =
unsafe { MulticastAddr::new_unchecked(Ipv6Addr::new([0xff02, 0, 0, 0, 0, 0, 0, 1])) };
/// The IPv6 All Routers multicast address in link-local scope, defined in
/// [RFC 4291 Section 2.7.1].
///
/// [RFC 4291 Section 2.7.1]: https://tools.ietf.org/html/rfc4291#section-2.7.1
pub const ALL_ROUTERS_LINK_LOCAL_MULTICAST_ADDRESS: MulticastAddr<Ipv6Addr> =
unsafe { MulticastAddr::new_unchecked(Ipv6Addr::new([0xff02, 0, 0, 0, 0, 0, 0, 2])) };
/// The (deprecated) subnet of site-local unicast addresses, defined in [RFC
/// 3513 Section 2.5.6].
///
/// The site-local unicast subnet was deprecated in [RFC 3879]:
///
/// > The special behavior of this prefix MUST no longer be supported in new
/// > implementations. The prefix MUST NOT be reassigned for other use
/// > except by a future IETF standards action... However, router
/// > implementations SHOULD be configured to prevent routing of this prefix
/// > by default.
///
/// [RFC 3513 Section 2.5.6]: https://tools.ietf.org/html/rfc3513#section-2.5.6
/// [RFC 3879]: https://tools.ietf.org/html/rfc3879
pub const SITE_LOCAL_UNICAST_SUBNET: Subnet<Ipv6Addr> =
Subnet { network: Ipv6Addr::new([0xfec0, 0, 0, 0, 0, 0, 0, 0]), prefix: 10 };
/// The length, in bits, of the interface identifier portion of unicast IPv6
/// addresses *except* for addresses which start with the binary value 000.
///
/// According to [RFC 4291 Section 2.5.1], "\[f\]or all unicast addresses,
/// except those that start with the binary value 000, Interface IDs are
/// required to be 64 bits."
///
/// Note that, per [RFC 4862 Section 5.5.3]:
///
/// > a future revision of the address architecture \[RFC4291\] and a future
/// > link-type-specific document, which will still be consistent with each
/// > other, could potentially allow for an interface identifier of length
/// > other than the value defined in the current documents. Thus, an
/// > implementation should not assume a particular constant. Rather, it
/// > should expect any lengths of interface identifiers.
///
/// In other words, this constant may be used to generate addresses or
/// subnet prefix lengths, but should *not* be used to validate addresses or
/// subnet prefix lengths generated by other software or other machines, as
/// it might be valid for other software or other machines to use an
/// interface identifier length different from this one.
///
/// [RFC 4291 Section 2.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.1
/// [RFC 4862 Section 5.5.3]: https://tools.ietf.org/html/rfc4862#section-5.5.3
pub const UNICAST_INTERFACE_IDENTIFIER_BITS: u8 = 64;
/// The length, in bits, of an IPv6 flow label, defined in [RFC 6437 Section 2].
///
/// [RFC 6437 Section 2]: https://tools.ietf.org/html/rfc6437#section-2
pub const FLOW_LABEL_BITS: u8 = 20;
}
/// An IPv4 or IPv6 address.
///
/// `IpAddress` is implemented by [`Ipv4Addr`] and [`Ipv6Addr`]. It is sealed,
/// and there are guaranteed to be no other implementors besides these. Code -
/// including unsafe code - may rely on this assumption for its correctness and
/// soundness.
pub trait IpAddress:
Sized
+ Eq
+ PartialEq
+ PartialOrd
+ Ord
+ Hash
+ Copy
+ Display
+ Debug
+ Default
+ Sync
+ Send
+ LinkLocalAddress
+ ScopeableAddress
+ GenericOverIp<Self::Version, Type = Self>
+ GenericOverIp<Ipv4, Type = Ipv4Addr>
+ GenericOverIp<Ipv6, Type = Ipv6Addr>
+ sealed::Sealed
+ 'static
{
/// The number of bytes in an address of this type.
///
/// 4 for IPv4 and 16 for IPv6.
const BYTES: u8;
/// The IP version type of this address.
///
/// [`Ipv4`] for [`Ipv4Addr`] and [`Ipv6`] for [`Ipv6Addr`].
type Version: Ip<Addr = Self>;
/// Gets the underlying bytes of the address.
fn bytes(&self) -> &[u8];
/// Masks off the top bits of the address.
///
/// Returns a copy of `self` where all but the top `bits` bits are set to
/// 0.
///
/// # Panics
///
/// `mask` panics if `bits` is out of range - if it is greater than 32 for
/// IPv4 or greater than 128 for IPv6.
fn mask(&self, bits: u8) -> Self;
/// Converts a statically-typed IP address into a dynamically-typed one.
fn to_ip_addr(&self) -> IpAddr;
/// Is this a loopback address?
///
/// `is_loopback` returns `true` if this address is a member of the
/// [`LOOPBACK_SUBNET`].
///
/// [`LOOPBACK_SUBNET`]: Ip::LOOPBACK_SUBNET
#[inline]
fn is_loopback(&self) -> bool {
Self::Version::LOOPBACK_SUBNET.contains(self)
}
/// Calculates the common prefix length between this address and `other`.
fn common_prefix_len(&self, other: &Self) -> u8;
/// Is this a unicast address contained in the given subnet?
///
/// `is_unicast_in_subnet` returns `true` if the given subnet contains this
/// address and the address is none of:
/// - a multicast address
/// - the IPv4 limited broadcast address
/// - the IPv4 subnet-specific broadcast address for the given subnet
/// - an IPv4 address whose host bits (those bits following the network
/// prefix) are all 0
/// - the unspecified address
/// - an IPv4 Class E address
///
/// Note two exceptions to these rules: If `subnet` is an IPv4 /32, then the
/// single unicast address in the subnet is also technically the subnet
/// broadcast address. If `subnet` is an IPv4 /31, then both addresses in
/// that subnet are broadcast addresses. In either case, the "no
/// subnet-specific broadcast" and "no address with a host part of all
/// zeroes" rules don't apply. Note further that this exception *doesn't*
/// apply to the unspecified address, which is never considered a unicast
/// address regardless of what subnet it's in.
///
/// # RFC Deep Dive
///
/// ## IPv4 addresses ending in zeroes
///
/// In this section, we justify the rule that IPv4 addresses whose host bits
/// are all 0 are not considered unicast addresses.
///
/// In earlier standards, an IPv4 address whose bits were all 0 after the
/// network prefix (e.g., 192.168.0.0 in the subnet 192.168.0.0/16) were a
/// form of "network-prefix-directed" broadcast addresses. Similarly,
/// 0.0.0.0 was considered a form of "limited broadcast address" (equivalent
/// to 255.255.255.255). These have since been deprecated (in the case of
/// 0.0.0.0, it is now considered the "unspecified" address).
///
/// As evidence that this deprecation is official, consider [RFC 1812
/// Section 5.3.5]. In reference to these types of addresses, it states that
/// "packets addressed to any of these addresses SHOULD be silently
/// discarded \[by routers\]". This not only deprecates them as broadcast
/// addresses, but also as unicast addresses (after all, unicast addresses
/// are not particularly useful if packets destined to them are discarded by
/// routers).
///
/// ## IPv4 /31 and /32 exceptions
///
/// In this section, we justify the exceptions that all addresses in IPv4
/// /31 and /32 subnets are considered unicast.
///
/// For /31 subnets, the case is easy. [RFC 3021 Section 2.1] states that
/// both addresses in a /31 subnet "MUST be interpreted as host addresses."
///
/// For /32, the case is a bit more vague. RFC 3021 makes no mention of /32
/// subnets. However, the same reasoning applies - if an exception is not
/// made, then there do not exist any host addresses in a /32 subnet. [RFC
/// 4632 Section 3.1] also vaguely implies this interpretation by referring
/// to addresses in /32 subnets as "host routes."
///
/// [RFC 1812 Section 5.3.5]: https://tools.ietf.org/html/rfc1812#page-92
/// [RFC 4632 Section 3.1]: https://tools.ietf.org/html/rfc4632#section-3.1
fn is_unicast_in_subnet(&self, subnet: &Subnet<Self>) -> bool;
// Functions used to implement internal types. These functions aren't
// particularly useful to users, but allow us to implement certain
// specialization-like behavior without actually relying on the unstable
// `specialization` feature.
#[doc(hidden)]
fn subnet_into_either(subnet: Subnet<Self>) -> SubnetEither;
#[doc(hidden)]
fn array_into_ip_addr<const N: usize>(addrs: [Self; N])
-> IpAddr<[Ipv4Addr; N], [Ipv6Addr; N]>;
}
impl<A: IpAddress> SpecifiedAddress for A {
/// Is this an address other than the unspecified address?
///
/// `is_specified` returns true if `self` is not equal to
/// [`A::Version::UNSPECIFIED_ADDRESS`].
///
/// [`A::Version::UNSPECIFIED_ADDRESS`]: Ip::UNSPECIFIED_ADDRESS
#[inline]
fn is_specified(&self) -> bool {
self != &A::Version::UNSPECIFIED_ADDRESS
}
}
/// Maps a method over an `IpAddr`, calling it after matching on the type of IP
/// address.
macro_rules! map_ip_addr {
($val:expr, $method:ident) => {
match $val {
IpAddr::V4(a) => a.$method(),
IpAddr::V6(a) => a.$method(),
}
};
}
impl SpecifiedAddress for IpAddr {
/// Is this an address other than the unspecified address?
///
/// `is_specified` returns true if `self` is not equal to
/// [`Ip::UNSPECIFIED_ADDRESS`] for the IP version of this address.
#[inline]
fn is_specified(&self) -> bool {
map_ip_addr!(self, is_specified)
}
}
impl<A: IpAddress> MulticastAddress for A {
/// Is this address in the multicast subnet?
///
/// `is_multicast` returns true if `self` is in
/// [`A::Version::MULTICAST_SUBNET`].
///
/// [`A::Version::MULTICAST_SUBNET`]: Ip::MULTICAST_SUBNET
#[inline]
fn is_multicast(&self) -> bool {
<A as IpAddress>::Version::MULTICAST_SUBNET.contains(self)
}
}
impl MulticastAddress for IpAddr {
/// Is this an address in the multicast subnet?
///
/// `is_multicast` returns true if `self` is in [`Ip::MULTICAST_SUBNET`] for
/// the IP version of this address.
#[inline]
fn is_multicast(&self) -> bool {
map_ip_addr!(self, is_multicast)
}
}
impl LinkLocalAddress for Ipv4Addr {
/// Is this address in the link-local subnet?
///
/// `is_link_local` returns true if `self` is in
/// [`Ipv4::LINK_LOCAL_UNICAST_SUBNET`] or
/// [`Ipv4::LINK_LOCAL_MULTICAST_SUBNET`].
#[inline]
fn is_link_local(&self) -> bool {
Ipv4::LINK_LOCAL_UNICAST_SUBNET.contains(self)
|| Ipv4::LINK_LOCAL_MULTICAST_SUBNET.contains(self)
}
}
impl LinkLocalAddress for Ipv6Addr {
/// Is this address in the link-local subnet?
///
/// `is_link_local` returns true if `self` is in
/// [`Ipv6::LINK_LOCAL_UNICAST_SUBNET`], is a multicast address whose scope
/// is link-local, or is the address [`Ipv6::LOOPBACK_ADDRESS`] (per [RFC
/// 4291 Section 2.5.3], the loopback address is considered to have
/// link-local scope).
///
/// [RFC 4291 Section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
#[inline]
fn is_link_local(&self) -> bool {
Ipv6::LINK_LOCAL_UNICAST_SUBNET.contains(self)
|| (self.is_multicast() && self.scope() == Ipv6Scope::LinkLocal)
|| self == Ipv6::LOOPBACK_ADDRESS.deref()
}
}
impl LinkLocalAddress for IpAddr {
/// Is this address link-local?
#[inline]
fn is_link_local(&self) -> bool {
map_ip_addr!(self, is_link_local)
}
}
impl<A: IpAddress> MappedAddress for A {
/// Is this address non-mapped?
///
/// For IPv4 addresses, this always returns true because they do not have a
/// mapped address space.
///
/// For Ipv6 addresses, this returns true if `self` is outside of the IPv4
/// mapped Ipv6 address subnet, as defined in [RFC 4291 Section 2.5.5.2]
/// (e.g. `::FFFF:0:0/96`).
///
/// [RFC 4291 Section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
#[inline]
fn is_non_mapped(&self) -> bool {
A::Version::map_ip(self, |_addr_v4| true, |addr_v6| addr_v6.to_ipv4_mapped().is_none())
}
}
impl MappedAddress for IpAddr {
/// Is this address non-mapped?
#[inline]
fn is_non_mapped(&self) -> bool {
map_ip_addr!(self, is_non_mapped)
}
}
impl<I: Ip> GenericOverIp<I> for Ipv4Addr {
type Type = I::Addr;
}
impl<I: Ip> GenericOverIp<I> for Ipv6Addr {
type Type = I::Addr;
}
impl ScopeableAddress for Ipv4Addr {
type Scope = ();
/// The scope of this address.
///
/// Although IPv4 defines a link local subnet, IPv4 addresses are always
/// considered to be in the global scope.
fn scope(&self) {}
}
/// The list of IPv6 scopes.
///
/// These scopes are defined by [RFC 4291 Section 2.7].
///
/// [RFC 4291 Section 2.7]: https://tools.ietf.org/html/rfc4291#section-2.7
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Ipv6Scope {
/// The interface-local scope.
InterfaceLocal,
/// The link-local scope.
LinkLocal,
/// The admin-local scope.
AdminLocal,
/// The (deprecated) site-local scope.
///
/// The site-local scope was deprecated in [RFC 3879]. While this scope
/// is returned for both site-local unicast and site-local multicast
/// addresses, RFC 3879 says the following about site-local unicast addresses
/// in particular ("this prefix" refers to the [site-local unicast subnet]):
///
/// > The special behavior of this prefix MUST no longer be supported in new
/// > implementations. The prefix MUST NOT be reassigned for other use
/// > except by a future IETF standards action... However, router
/// > implementations SHOULD be configured to prevent routing of this prefix
/// > by default.
///
/// [RFC 3879]: https://tools.ietf.org/html/rfc3879
/// [site-local unicast subnet]: Ipv6::SITE_LOCAL_UNICAST_SUBNET
SiteLocal,
/// The organization-local scope.
OrganizationLocal,
/// The global scope.
Global,
/// Scopes which are reserved for future use by [RFC 4291 Section 2.7].
///
/// [RFC 4291 Section 2.7]: https://tools.ietf.org/html/rfc4291#section-2.7
Reserved(Ipv6ReservedScope),
/// Scopes which are available for local definition by administrators.
Unassigned(Ipv6UnassignedScope),
}
/// The list of IPv6 scopes which are reserved for future use by [RFC 4291
/// Section 2.7].
///
/// [RFC 4291 Section 2.7]: https://tools.ietf.org/html/rfc4291#section-2.7
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Ipv6ReservedScope {
/// The scope with numerical value 0.
Scope0 = 0,
/// The scope with numerical value 3.
Scope3 = 3,
/// The scope with numerical value 0xF.
ScopeF = 0xF,
}
/// The list of IPv6 scopes which are available for local definition by
/// administrators.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Ipv6UnassignedScope {
/// The scope with numerical value 6.
Scope6 = 6,
/// The scope with numerical value 7.
Scope7 = 7,
/// The scope with numerical value 9.
Scope9 = 9,
/// The scope with numerical value 0xA.
ScopeA = 0xA,
/// The scope with numerical value 0xB.
ScopeB = 0xB,
/// The scope with numerical value 0xC.
ScopeC = 0xC,
/// The scope with numerical value 0xD.
ScopeD = 0xD,
}
impl Scope for Ipv6Scope {
#[inline]
fn can_have_zone(&self) -> bool {
// Per RFC 6874 Section 4:
//
// > [I]mplementations MUST NOT allow use of this format except for
// > well-defined usages, such as sending to link-local addresses under
// > prefix fe80::/10. At the time of writing, this is the only
// > well-defined usage known.
//
// While this directive applies particularly to the human-readable
// string representation of IPv6 addresses and zone identifiers, it
// seems reasonable to limit the in-memory representation in the same
// way.
//
// Note that, if interpreted literally, this quote would bar the use of
// zone identifiers on link-local multicast addresses (they are not
// under the prefix fe80::/10). However, it seems clear that this is not
// the interpretation that was intended. Link-local multicast addresses
// have the same need for a zone identifier as link-local unicast
// addresses, and indeed, real systems like Linux allow link-local
// multicast addresses to be accompanied by zone identifiers.
matches!(self, Ipv6Scope::LinkLocal)
}
}
impl Ipv6Scope {
/// The multicast scope ID of an interface-local address, defined in [RFC
/// 4291 Section 2.7].
///
/// [RFC 4291 Section 2.7]: https://tools.ietf.org/html/rfc4291#section-2.7
pub const MULTICAST_SCOPE_ID_INTERFACE_LOCAL: u8 = 1;
/// The multicast scope ID of a link-local address, defined in [RFC 4291
/// Section 2.7].
///
/// [RFC 4291 Section 2.7]: https://tools.ietf.org/html/rfc4291#section-2.7
pub const MULTICAST_SCOPE_ID_LINK_LOCAL: u8 = 2;
/// The multicast scope ID of an admin-local address, defined in [RFC 4291
/// Section 2.7].
///
/// [RFC 4291 Section 2.7]: https://tools.ietf.org/html/rfc4291#section-2.7
pub const MULTICAST_SCOPE_ID_ADMIN_LOCAL: u8 = 4;
/// The multicast scope ID of a (deprecated) site-local address, defined in
/// [RFC 4291 Section 2.7].
///
/// Note that site-local addresses are deprecated.
///
/// [RFC 4291 Section 2.7]: https://tools.ietf.org/html/rfc4291#section-2.7
pub const MULTICAST_SCOPE_ID_SITE_LOCAL: u8 = 5;
/// The multicast scope ID of an organization-local address, defined in [RFC
/// 4291 Section 2.7].
///
/// [RFC 4291 Section 2.7]: https://tools.ietf.org/html/rfc4291#section-2.7
pub const MULTICAST_SCOPE_ID_ORG_LOCAL: u8 = 8;
/// The multicast scope ID of global address, defined in [RFC 4291 Section
/// 2.7].
///
/// [RFC 4291 Section 2.7]: https://tools.ietf.org/html/rfc4291#section-2.7
pub const MULTICAST_SCOPE_ID_GLOBAL: u8 = 0xE;
/// The ID used to indicate this scope in a multicast IPv6 address.
///
/// Per [RFC 4291 Section 2.7], the bits of a multicast IPv6 address are
/// laid out as follows:
///
/// ```text
/// | 8 | 4 | 4 | 112 bits |
/// +------ -+----+----+---------------------------------------------+
/// |11111111|flgs|scop| group ID |
/// +--------+----+----+---------------------------------------------+
/// ```
///
/// The 4-bit scop field encodes the scope of the address.
/// `multicast_scope_id` returns the numerical value used to encode this
/// scope in the scop field of a multicast address.
///
/// [RFC 4291 Section 2.7]: https://tools.ietf.org/html/rfc4291#section-2.7
pub fn multicast_scope_id(&self) -> u8 {
match self {
Ipv6Scope::Reserved(Ipv6ReservedScope::Scope0) => 0,
Ipv6Scope::InterfaceLocal => Self::MULTICAST_SCOPE_ID_INTERFACE_LOCAL,
Ipv6Scope::LinkLocal => Self::MULTICAST_SCOPE_ID_LINK_LOCAL,
Ipv6Scope::Reserved(Ipv6ReservedScope::Scope3) => 3,
Ipv6Scope::AdminLocal => Self::MULTICAST_SCOPE_ID_ADMIN_LOCAL,
Ipv6Scope::SiteLocal => Self::MULTICAST_SCOPE_ID_SITE_LOCAL,
Ipv6Scope::Unassigned(Ipv6UnassignedScope::Scope6) => 6,
Ipv6Scope::Unassigned(Ipv6UnassignedScope::Scope7) => 7,
Ipv6Scope::OrganizationLocal => Self::MULTICAST_SCOPE_ID_ORG_LOCAL,
Ipv6Scope::Unassigned(Ipv6UnassignedScope::Scope9) => 9,
Ipv6Scope::Unassigned(Ipv6UnassignedScope::ScopeA) => 0xA,
Ipv6Scope::Unassigned(Ipv6UnassignedScope::ScopeB) => 0xB,
Ipv6Scope::Unassigned(Ipv6UnassignedScope::ScopeC) => 0xC,
Ipv6Scope::Unassigned(Ipv6UnassignedScope::ScopeD) => 0xD,
Ipv6Scope::Global => Self::MULTICAST_SCOPE_ID_GLOBAL,
Ipv6Scope::Reserved(Ipv6ReservedScope::ScopeF) => 0xF,
}
}
}
impl ScopeableAddress for Ipv6Addr {
type Scope = Ipv6Scope;
/// The scope of this address.
#[inline]
fn scope(&self) -> Ipv6Scope {
if self.is_multicast() {
use Ipv6ReservedScope::*;
use Ipv6Scope::*;
use Ipv6UnassignedScope::*;
// The "scop" field of a multicast address is the last 4 bits of the
// second byte of the address (see
// https://tools.ietf.org/html/rfc4291#section-2.7).
match self.0[1] & 0xF {
0 => Reserved(Scope0),
Ipv6Scope::MULTICAST_SCOPE_ID_INTERFACE_LOCAL => InterfaceLocal,
Ipv6Scope::MULTICAST_SCOPE_ID_LINK_LOCAL => LinkLocal,
3 => Reserved(Scope3),
Ipv6Scope::MULTICAST_SCOPE_ID_ADMIN_LOCAL => AdminLocal,
Ipv6Scope::MULTICAST_SCOPE_ID_SITE_LOCAL => SiteLocal,
6 => Unassigned(Scope6),
7 => Unassigned(Scope7),
Ipv6Scope::MULTICAST_SCOPE_ID_ORG_LOCAL => OrganizationLocal,
9 => Unassigned(Scope9),
0xA => Unassigned(ScopeA),
0xB => Unassigned(ScopeB),
0xC => Unassigned(ScopeC),
0xD => Unassigned(ScopeD),
Ipv6Scope::MULTICAST_SCOPE_ID_GLOBAL => Global,
0xF => Reserved(ScopeF),
_ => unreachable!(),
}
} else if self.is_link_local() {
Ipv6Scope::LinkLocal
} else if self.is_site_local() {
Ipv6Scope::SiteLocal
} else {
Ipv6Scope::Global
}
}
}
impl Scope for IpAddr<(), Ipv6Scope> {
#[inline]
fn can_have_zone(&self) -> bool {
match self {
IpAddr::V4(scope) => scope.can_have_zone(),
IpAddr::V6(scope) => scope.can_have_zone(),
}
}
}
impl ScopeableAddress for IpAddr {
type Scope = IpAddr<(), Ipv6Scope>;
#[inline]
fn scope(&self) -> IpAddr<(), Ipv6Scope> {
match self {
IpAddr::V4(_) => IpAddr::V4(()),
IpAddr::V6(addr) => IpAddr::V6(addr.scope()),
}
}
}
// The definition of each trait for `IpAddr` is equal to the definition of that
// trait for whichever of `Ipv4Addr` and `Ipv6Addr` is actually present in the
// enum. Thus, we can convert between `$witness<IpvXAddr>`, `$witness<IpAddr>`,
// and `IpAddr<$witness<Ipv4Addr>, $witness<Ipv6Addr>>` arbitrarily.
/// Provides various useful `From` impls for an IP address witness type.
///
/// `impl_from_witness!($witness)` implements:
/// - `From<IpAddr<$witness<Ipv4Addr>, $witness<Ipv6Addr>>> for
/// $witness<IpAddr>`
/// - `From<$witness<IpAddr>> for IpAddr<$witness<Ipv4Addr>,
/// $witness<Ipv6Addr>>`
/// - `From<$witness<A>> for $witness<A>`
/// - `From<$witness<Ipv4Addr>> for IpAddr`
/// - `From<$witness<Ipv6Addr>> for IpAddr`
/// - `TryFrom<Ipv4Addr> for $witness<Ipv4Addr>`
/// - `TryFrom<Ipv6Addr> for $witness<Ipv6Addr>`
///
/// `impl_from_witness!($witness, $ipaddr, $new_unchecked)` implements:
/// - `From<$witness<$ipaddr>> for $witness<IpAddr>`
/// - `From<$witness<$ipaddr>> for $ipaddr`
/// - `TryFrom<$ipaddr> for $witness<$ipaddr>`
macro_rules! impl_from_witness {
($witness:ident, $witness_trait:ident) => {
impl From<IpAddr<$witness<Ipv4Addr>, $witness<Ipv6Addr>>> for $witness<IpAddr> {
fn from(addr: IpAddr<$witness<Ipv4Addr>, $witness<Ipv6Addr>>) -> $witness<IpAddr> {
unsafe {
Witness::new_unchecked(match addr {
IpAddr::V4(addr) => IpAddr::V4(addr.get()),
IpAddr::V6(addr) => IpAddr::V6(addr.get()),
})
}
}
}
impl From<$witness<IpAddr>> for IpAddr<$witness<Ipv4Addr>, $witness<Ipv6Addr>> {
fn from(addr: $witness<IpAddr>) -> IpAddr<$witness<Ipv4Addr>, $witness<Ipv6Addr>> {
unsafe {
match addr.get() {
IpAddr::V4(addr) => IpAddr::V4(Witness::new_unchecked(addr)),
IpAddr::V6(addr) => IpAddr::V6(Witness::new_unchecked(addr)),
}
}
}
}
impl<A: IpAddress> From<$witness<A>> for $witness<IpAddr> {
fn from(addr: $witness<A>) -> $witness<IpAddr> {
unsafe { Witness::new_unchecked(addr.to_ip_addr()) }
}
}
impl<A: IpAddress> From<$witness<A>> for IpAddr<$witness<Ipv4Addr>, $witness<Ipv6Addr>> {
fn from(addr: $witness<A>) -> IpAddr<$witness<Ipv4Addr>, $witness<Ipv6Addr>> {
let addr: $witness<IpAddr> = addr.into();
addr.into()
}
}
// NOTE: Orphan rules prevent implementing `From` for `A: IpAddress`.
impl<A: Into<Ipv4Addr> + $witness_trait + Copy> From<$witness<A>> for Ipv4Addr {
fn from(addr: $witness<A>) -> Ipv4Addr {
let addr: A = addr.get();
addr.into()
}
}
impl<A: Into<Ipv6Addr> + $witness_trait + Copy> From<$witness<A>> for Ipv6Addr {
fn from(addr: $witness<A>) -> Ipv6Addr {
let addr: A = addr.get();
addr.into()
}
}
// NOTE: Orphan rules prevent implementing `TryFrom` for `A: IpAddress`.
impl TryFrom<Ipv4Addr> for $witness<Ipv4Addr> {
type Error = ();
fn try_from(addr: Ipv4Addr) -> Result<$witness<Ipv4Addr>, ()> {
Witness::new(addr).ok_or(())
}
}
impl TryFrom<Ipv6Addr> for $witness<Ipv6Addr> {
type Error = ();
fn try_from(addr: Ipv6Addr) -> Result<$witness<Ipv6Addr>, ()> {
Witness::new(addr).ok_or(())
}
}
};
($witness:ident, $witness_trait:ident, $ipaddr:ident, $new_unchecked:expr) => {
impl From<$witness<$ipaddr>> for $witness<IpAddr> {
fn from(addr: $witness<$ipaddr>) -> $witness<IpAddr> {
let addr: $ipaddr = addr.get();
let addr: IpAddr = addr.into();
#[allow(unused_unsafe)] // For when a closure is passed
unsafe {
$new_unchecked(addr)
}
}
}
impl<A: Into<$ipaddr> + $witness_trait + Copy> From<$witness<A>> for $ipaddr {
fn from(addr: $witness<A>) -> $ipaddr {
let addr: A = addr.get();
addr.into()
}
}
impl TryFrom<$ipaddr> for $witness<$ipaddr> {
type Error = ();
fn try_from(addr: $ipaddr) -> Result<$witness<$ipaddr>, ()> {
Witness::new(addr).ok_or(())
}
}
};
}
impl_from_witness!(SpecifiedAddr, SpecifiedAddress);
impl_from_witness!(MulticastAddr, MulticastAddress);
impl_from_witness!(LinkLocalAddr, LinkLocalAddress);
impl_from_witness!(NonMappedAddr, MappedAddress);
// Only add `From` conversions for `Ipv6Addr`, because `Ipv4Addr` does not
// implement `UnicastAddress`.
impl_from_witness!(UnicastAddr, UnicastAddress, Ipv6Addr, UnicastAddr::new_unchecked);
/// The class of an IPv4 address.
///
/// The classful addressing scheme is obsoloted in favour of [CIDR] but is still
/// used on some systems. For more information, see [RFC 791 section 2.3] and
/// [RFC 1812 section 2.2.5.1].
///
/// [CIDR]: https://datatracker.ietf.org/doc/html/rfc1518
/// [RFC 791 section 2.3]: https://datatracker.ietf.org/doc/html/rfc791#section-2.3
/// [RFC 1812 section 2.2.5.1]: https://datatracker.ietf.org/doc/html/rfc1812#section-2.2.5.1
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Ipv4AddressClass {
/// A Class A IPv4 address.
A,
/// A Class B IPv4 address.
B,
/// A Class C IPv4 address.
C,
/// A Class D IPv4 address.
///
/// Class D addresses are also known as multicast.
D,
/// A Class E IPv4 address.
///
/// Class E addresses are also known as experimental.
E,
}
impl Ipv4AddressClass {
/// Returns the default prefix length for an IPv4 address class if the
/// prefix is well-defined.
pub const fn default_prefix_len(self) -> Option<u8> {
// Per RFC 943 https://datatracker.ietf.org/doc/html/rfc943
//
// The first type of address, or class A, has a 7-bit network number
// and a 24-bit local address. The highest-order bit is set to 0.
// This allows 128 class A networks.
//
// 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |0| NETWORK | Local Address |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Class A Address
//
// The second type of address, class B, has a 14-bit network number
// and a 16-bit local address. The two highest-order bits are set to
// 1-0. This allows 16,384 class B networks.
//
// 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |1 0| NETWORK | Local Address |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Class B Address
//
// The third type of address, class C, has a 21-bit network number
// and a 8-bit local address. The three highest-order bits are set
// to 1-1-0. This allows 2,097,152 class C networks.
//
// 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |1 1 0| NETWORK | Local Address |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Class C Address
match self {
Ipv4AddressClass::A => Some(8),
Ipv4AddressClass::B => Some(16),
Ipv4AddressClass::C => Some(24),
Ipv4AddressClass::D => None,
Ipv4AddressClass::E => None,
}
}
}
/// An IPv4 address.
///
/// # Layout
///
/// `Ipv4Addr` has the same layout as `[u8; 4]`, which is the layout that most
/// protocols use to represent an IPv4 address in their packet formats. This can
/// be useful when parsing an IPv4 address from a packet. For example:
///
/// ```rust
/// # use net_types::ip::Ipv4Addr;
/// /// An ICMPv4 Redirect Message header.
/// ///
/// /// `Icmpv4RedirectHeader` has the same layout as the header of an ICMPv4
/// /// Redirect Message.
/// #[repr(C)]
/// struct Icmpv4RedirectHeader {
/// typ: u8,
/// code: u8,
/// checksum: [u8; 2],
/// gateway: Ipv4Addr,
/// }
/// ```
#[derive(
Copy,
Clone,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
KnownLayout,
FromBytes,
IntoBytes,
Immutable,
Unaligned,
)]
#[repr(transparent)]
pub struct Ipv4Addr([u8; 4]);
impl Ipv4Addr {
/// Creates a new IPv4 address.
#[inline]
pub const fn new(bytes: [u8; 4]) -> Self {
Ipv4Addr(bytes)
}
/// Gets the bytes of the IPv4 address.
#[inline]
pub const fn ipv4_bytes(self) -> [u8; 4] {
self.0
}
/// Is this the limited broadcast address?
///
/// `is_limited_broadcast` is a shorthand for comparing against
/// [`Ipv4::LIMITED_BROADCAST_ADDRESS`].
#[inline]
pub fn is_limited_broadcast(self) -> bool {
self == Ipv4::LIMITED_BROADCAST_ADDRESS.get()
}
/// Is this a Class E address?
///
/// `is_class_e` is a shorthand for checking membership in
/// [`Ipv4::CLASS_E_SUBNET`].
#[inline]
pub fn is_class_e(self) -> bool {
Ipv4::CLASS_E_SUBNET.contains(&self)
}
/// Converts the address to an IPv4-compatible IPv6 address according to
/// [RFC 4291 Section 2.5.5.1].
///
/// IPv4-compatible IPv6 addresses were defined to assist in the IPv6
/// transition, and are now specified in [RFC 4291 Section 2.5.5.1]. The
/// lowest-order 32 bits carry an IPv4 address, while the highest-order 96
/// bits are all set to 0 as in this diagram from the RFC:
///
/// ```text
/// | 80 bits | 16 | 32 bits |
/// +--------------------------------------+--------------------------+
/// |0000..............................0000|0000| IPv4 address |
/// +--------------------------------------+----+---------------------+
/// ```
///
/// Per RFC 4291:
///
/// > The 'IPv4-Compatible IPv6 address' is now deprecated because the
/// > current IPv6 transition mechanisms no longer use these addresses. New
/// > or updated implementations are not required to support this address
/// > type.
///
/// The more modern embedding format is IPv4-mapped IPv6 addressing - see
/// [`to_ipv6_mapped`].
///
/// [RFC 4291 Section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1
/// [`to_ipv6_mapped`]: Ipv4Addr::to_ipv6_mapped
#[inline]
pub fn to_ipv6_compatible(self) -> Ipv6Addr {
let Self([a, b, c, d]) = self;
Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d])
}
/// Converts the address to an IPv4-mapped IPv6 address according to [RFC
/// 4291 Section 2.5.5.2].
///
/// IPv4-mapped IPv6 addresses are used to represent the addresses of IPv4
/// nodes as IPv6 addresses, and are defined in [RFC 4291 Section 2.5.5.2].
/// The lowest-order 32 bits carry an IPv4 address, the middle order 16 bits
/// carry the literal 0xFFFF, and the highest order 80 bits are set to 0 as
/// in this diagram from the RFC:
///
/// ```text
/// | 80 bits | 16 | 32 bits |
/// +--------------------------------------+--------------------------+
/// |0000..............................0000|FFFF| IPv4 address |
/// +--------------------------------------+----+---------------------+
/// ```
///
/// [RFC 4291 Section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
#[inline]
pub fn to_ipv6_mapped(self) -> SpecifiedAddr<Ipv6Addr> {
let Self([a, b, c, d]) = self;
SpecifiedAddr::new(Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d]))
.unwrap()
}
/// Returns the address's class according to the obsoleted classful
/// addressing architecture.
pub fn class(&self) -> Ipv4AddressClass {
for (subnet, class) in [
(Ipv4::CLASS_A_SUBNET, Ipv4AddressClass::A),
(Ipv4::CLASS_B_SUBNET, Ipv4AddressClass::B),
(Ipv4::CLASS_C_SUBNET, Ipv4AddressClass::C),
(Ipv4::CLASS_D_SUBNET, Ipv4AddressClass::D),
(Ipv4::CLASS_E_SUBNET, Ipv4AddressClass::E),
] {
if subnet.contains(self) {
return class;
}
}
unreachable!("{} should fit into a class", self)
}
}
impl sealed::Sealed for Ipv4Addr {}
impl IpAddress for Ipv4Addr {
const BYTES: u8 = 4;
type Version = Ipv4;
#[inline]
fn mask(&self, bits: u8) -> Self {
assert!(bits <= 32);
// Need to perform a checked shift left in case `bits == 32`, in which
// case an unchecked shift left (`u32::MAX << bits`) would overflow,
// causing a panic in debug mode.
let mask = u32::MAX.checked_shl((32 - bits).into()).unwrap_or(0);
Ipv4Addr((u32::from_be_bytes(self.0) & mask).to_be_bytes())
}
#[inline]
fn bytes(&self) -> &[u8] {
&self.0
}
#[inline]
fn to_ip_addr(&self) -> IpAddr {
IpAddr::V4(*self)
}
#[inline]
fn common_prefix_len(&self, other: &Ipv4Addr) -> u8 {
let me = u32::from_be_bytes(self.0);
let other = u32::from_be_bytes(other.0);
// `same_bits` has a 0 wherever `me` and `other` have the same bit in a
// given position, and a 1 wherever they have opposite bits.
let same_bits = me ^ other;
same_bits.leading_zeros() as u8
}
#[inline]
fn is_unicast_in_subnet(&self, subnet: &Subnet<Self>) -> bool {
!self.is_multicast()
&& !self.is_limited_broadcast()
// This clause implements the rules that (the subnet broadcast is
// not unicast AND the address with an all-zeroes host part is not
// unicast) UNLESS the prefix length is 31 or 32.
&& (subnet.prefix() == 32
|| subnet.prefix() == 31
|| (*self != subnet.broadcast() && *self != subnet.network()))
&& self.is_specified()
&& !self.is_class_e()
&& subnet.contains(self)
}
fn subnet_into_either(subnet: Subnet<Ipv4Addr>) -> SubnetEither {
SubnetEither::V4(subnet)
}
#[inline]
fn array_into_ip_addr<const N: usize>(
addrs: [Self; N],
) -> IpAddr<[Ipv4Addr; N], [Ipv6Addr; N]> {
IpAddr::V4(addrs)
}
}
impl From<[u8; 4]> for Ipv4Addr {
#[inline]
fn from(bytes: [u8; 4]) -> Ipv4Addr {
Ipv4Addr(bytes)
}
}
#[cfg(feature = "std")]
impl From<net::Ipv4Addr> for Ipv4Addr {
#[inline]
fn from(ip: net::Ipv4Addr) -> Ipv4Addr {
Ipv4Addr::new(ip.octets())
}
}
#[cfg(feature = "std")]
impl From<Ipv4Addr> for net::Ipv4Addr {
#[inline]
fn from(ip: Ipv4Addr) -> net::Ipv4Addr {
net::Ipv4Addr::from(ip.0)
}
}
impl Display for Ipv4Addr {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}.{}.{}.{}", self.0[0], self.0[1], self.0[2], self.0[3])
}
}
impl Debug for Ipv4Addr {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
Display::fmt(self, f)
}
}
/// An IPv6 address.
///
/// # Layout
///
/// `Ipv6Addr` has the same layout as `[u8; 16]`, which is the layout that most
/// protocols use to represent an IPv6 address in their packet formats. This can
/// be useful when parsing an IPv6 address from a packet. For example:
///
/// ```rust
/// # use net_types::ip::Ipv6Addr;
/// /// The fixed part of an IPv6 packet header.
/// ///
/// /// `FixedHeader` has the same layout as the fixed part of an IPv6 packet
/// /// header.
/// #[repr(C)]
/// pub struct FixedHeader {
/// version_tc_flowlabel: [u8; 4],
/// payload_len: [u8; 2],
/// next_hdr: u8,
/// hop_limit: u8,
/// src_ip: Ipv6Addr,
/// dst_ip: Ipv6Addr,
/// }
/// ```
///
/// # `Display`
///
/// The [`Display`] impl for `Ipv6Addr` formats according to [RFC 5952].
///
/// Where RFC 5952 leaves decisions up to the implementation, `Ipv6Addr` matches
/// the behavior of [`std::net::Ipv6Addr`] - all IPv6 addresses are formatted
/// the same by `Ipv6Addr` as by `<std::net::Ipv6Addr as Display>::fmt`.
///
/// [RFC 5952]: https://datatracker.ietf.org/doc/html/rfc5952
#[derive(
Copy,
Clone,
Default,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
KnownLayout,
FromBytes,
IntoBytes,
Immutable,
Unaligned,
)]
#[repr(transparent)]
pub struct Ipv6Addr([u8; 16]);
impl Ipv6Addr {
/// Creates a new IPv6 address from 16-bit segments.
#[inline]
pub const fn new(segments: [u16; 8]) -> Ipv6Addr {
#![allow(clippy::many_single_char_names)]
let [a, b, c, d, e, f, g, h] = segments;
let [aa, ab] = a.to_be_bytes();
let [ba, bb] = b.to_be_bytes();
let [ca, cb] = c.to_be_bytes();
let [da, db] = d.to_be_bytes();
let [ea, eb] = e.to_be_bytes();
let [fa, fb] = f.to_be_bytes();
let [ga, gb] = g.to_be_bytes();
let [ha, hb] = h.to_be_bytes();
Ipv6Addr([aa, ab, ba, bb, ca, cb, da, db, ea, eb, fa, fb, ga, gb, ha, hb])
}
/// Creates a new IPv6 address from bytes.
#[inline]
pub const fn from_bytes(bytes: [u8; 16]) -> Ipv6Addr {
Ipv6Addr(bytes)
}
/// Gets the bytes of the IPv6 address.
#[inline]
pub const fn ipv6_bytes(&self) -> [u8; 16] {
self.0
}
/// Gets the 16-bit segments of the IPv6 address.
#[inline]
pub fn segments(&self) -> [u16; 8] {
#![allow(clippy::many_single_char_names)]
let [a, b, c, d, e, f, g, h]: [zerocopy::network_endian::U16; 8] =
zerocopy::transmute!(self.ipv6_bytes());
[a.into(), b.into(), c.into(), d.into(), e.into(), f.into(), g.into(), h.into()]
}
/// Converts this `Ipv6Addr` to the IPv6 Solicited-Node Address, used in
/// Neighbor Discovery, defined in [RFC 4291 Section 2.7.1].
///
/// [RFC 4291 Section 2.7.1]: https://tools.ietf.org/html/rfc4291#section-2.7.1
#[inline]
pub const fn to_solicited_node_address(&self) -> MulticastAddr<Ipv6Addr> {
// TODO(brunodalbo) benchmark this generation and evaluate if using
// bit operations with u128 could be faster. This is very likely
// going to be on a hot path.
// We know we are not breaking the guarantee that `MulticastAddr` provides
// when calling `new_unchecked` because the address we provide it is
// a multicast address as defined by RFC 4291 section 2.7.1.
unsafe {
MulticastAddr::new_unchecked(Ipv6Addr::from_bytes([
0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0xff, self.0[13], self.0[14],
self.0[15],
]))
}
}
/// Is this a valid unicast address?
///
/// A valid unicast address is any unicast address that can be bound to an
/// interface (not the unspecified or loopback addresses).
/// `addr.is_valid_unicast()` is equivalent to `!(addr.is_loopback() ||
/// !addr.is_specified() || addr.is_multicast())`.
#[inline]
pub fn is_valid_unicast(&self) -> bool {
!(self.is_loopback() || !self.is_specified() || self.is_multicast())
}
/// Is this address in the (deprecated) site-local unicast subnet?
///
/// `is_site_local` returns true if `self` is in the (deprecated)
/// [`Ipv6::SITE_LOCAL_UNICAST_SUBNET`]. See that constant's documentation
/// for more details on deprecation and how the subnet should be used in
/// light of deprecation.
#[inline]
pub fn is_site_local(&self) -> bool {
Ipv6::SITE_LOCAL_UNICAST_SUBNET.contains(self)
}
/// Is this a unicast link-local address?
///
/// `addr.is_unicast_link_local()` is equivalent to
/// `addr.is_unicast_in_subnet(&Ipv6::LINK_LOCAL_UNICAST_SUBNET)`.
#[inline]
pub fn is_unicast_link_local(&self) -> bool {
self.is_unicast_in_subnet(&Ipv6::LINK_LOCAL_UNICAST_SUBNET)
}
/// Tries to extract the IPv4 address from an IPv4-compatible IPv6 address.
///
/// IPv4-compatible IPv6 addresses were defined to assist in the IPv6
/// transition, and are now specified in [RFC 4291 Section 2.5.5.1]. The
/// lowest-order 32 bits carry an IPv4 address, while the highest-order 96
/// bits are all set to 0 as in this diagram from the RFC:
///
/// ```text
/// | 80 bits | 16 | 32 bits |
/// +--------------------------------------+--------------------------+
/// |0000..............................0000|0000| IPv4 address |
/// +--------------------------------------+----+---------------------+
/// ```
///
/// `to_ipv4_compatible` checks to see if `self` is an IPv4-compatible
/// IPv6 address. If it is, the IPv4 address is extracted and returned.
///
/// Per RFC 4291:
///
/// > The 'IPv4-Compatible IPv6 address' is now deprecated because the
/// > current IPv6 transition mechanisms no longer use these addresses. New
/// > or updated implementations are not required to support this address
/// > type.
///
/// The more modern embedding format is IPv4-mapped IPv6 addressing - see
/// [`to_ipv4_mapped`].
///
/// [RFC 4291 Section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1
/// [`to_ipv4_mapped`]: Ipv6Addr::to_ipv4_mapped
pub fn to_ipv4_compatible(&self) -> Option<Ipv4Addr> {
if let [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] = self.0 {
Some(Ipv4Addr::new([a, b, c, d]))
} else {
None
}
}
/// Tries to extract the IPv4 address from an IPv4-mapped IPv6 address.
///
/// IPv4-mapped IPv6 addresses are used to represent the addresses of IPv4
/// nodes as IPv6 addresses, and are defined in [RFC 4291 Section 2.5.5.2].
/// The lowest-order 32 bits carry an IPv4 address, the middle order 16 bits
/// carry the literal 0xFFFF, and the highest order 80 bits are set to 0 as
/// in this diagram from the RFC:
///
/// ```text
/// | 80 bits | 16 | 32 bits |
/// +--------------------------------------+--------------------------+
/// |0000..............................0000|FFFF| IPv4 address |
/// +--------------------------------------+----+---------------------+
/// ```
///
/// `to_ipv4_mapped` checks to see if `self` is an IPv4-mapped
/// IPv6 address. If it is, the IPv4 address is extracted and returned.
///
/// [RFC 4291 Section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
pub fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
if let [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] = self.0 {
Some(Ipv4Addr::new([a, b, c, d]))
} else {
None
}
}
}
impl sealed::Sealed for Ipv6Addr {}
/// [`Ipv4Addr`] is convertible into [`Ipv6Addr`] through
/// [`Ipv4Addr::to_ipv6_mapped`].
impl From<Ipv4Addr> for Ipv6Addr {
fn from(addr: Ipv4Addr) -> Ipv6Addr {
*addr.to_ipv6_mapped()
}
}
impl IpAddress for Ipv6Addr {
const BYTES: u8 = 16;
type Version = Ipv6;
#[inline]
fn mask(&self, bits: u8) -> Ipv6Addr {
assert!(bits <= 128);
// Need to perform a checked shift left in case `bits == 128`, in which
// case an unchecked shift left (`u128::MAX << bits`) would overflow,
// causing a panic in debug mode.
let mask = u128::MAX.checked_shl((128 - bits).into()).unwrap_or(0);
Ipv6Addr((u128::from_be_bytes(self.0) & mask).to_be_bytes())
}
#[inline]
fn bytes(&self) -> &[u8] {
&self.0
}
#[inline]
fn to_ip_addr(&self) -> IpAddr {
IpAddr::V6(*self)
}
#[inline]
fn common_prefix_len(&self, other: &Ipv6Addr) -> u8 {
let me = u128::from_be_bytes(self.0);
let other = u128::from_be_bytes(other.0);
// `same_bits` has a 0 wherever `me` and `other` have the same bit in a
// given position, and a 1 wherever they have opposite bits.
let same_bits = me ^ other;
same_bits.leading_zeros() as u8
}
#[inline]
fn is_unicast_in_subnet(&self, subnet: &Subnet<Self>) -> bool {
!self.is_multicast() && self.is_specified() && subnet.contains(self)
}
fn subnet_into_either(subnet: Subnet<Ipv6Addr>) -> SubnetEither {
SubnetEither::V6(subnet)
}
#[inline]
fn array_into_ip_addr<const N: usize>(
addrs: [Self; N],
) -> IpAddr<[Ipv4Addr; N], [Ipv6Addr; N]> {
IpAddr::V6(addrs)
}
}
impl UnicastAddress for Ipv6Addr {
/// Is this a unicast address?
///
/// `addr.is_unicast()` is equivalent to `!addr.is_multicast() &&
/// addr.is_specified()`.
#[inline]
fn is_unicast(&self) -> bool {
!self.is_multicast() && self.is_specified()
}
}
impl From<[u8; 16]> for Ipv6Addr {
#[inline]
fn from(bytes: [u8; 16]) -> Ipv6Addr {
Ipv6Addr::from_bytes(bytes)
}
}
#[cfg(feature = "std")]
impl From<net::Ipv6Addr> for Ipv6Addr {
#[inline]
fn from(addr: net::Ipv6Addr) -> Ipv6Addr {
Ipv6Addr::from_bytes(addr.octets())
}
}
#[cfg(feature = "std")]
impl From<Ipv6Addr> for net::Ipv6Addr {
#[inline]
fn from(addr: Ipv6Addr) -> net::Ipv6Addr {
net::Ipv6Addr::from(addr.ipv6_bytes())
}
}
impl Display for Ipv6Addr {
/// Formats an IPv6 address according to [RFC 5952].
///
/// Where RFC 5952 leaves decisions up to the implementation, this function
/// matches the behavior of [`std::net::Ipv6Addr`] - all IPv6 addresses are
/// formatted the same by this function as by `<std::net::Ipv6Addr as
/// Display>::fmt`.
///
/// [RFC 5952]: https://datatracker.ietf.org/doc/html/rfc5952
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
// `fmt_inner` implements the core of the formatting algorithm, but does
// not handle precision or width requirements. Those are handled below
// by creating a scratch buffer, calling `fmt_inner` on that scratch
// buffer, and then satisfying those requirements.
fn fmt_inner<W: fmt::Write>(addr: &Ipv6Addr, w: &mut W) -> Result<(), fmt::Error> {
// We special-case the unspecified address, localhost address, and
// IPv4-mapped addresses, but not IPv4-compatible addresses. We
// follow Rust's behavior here: https://github.com/rust-lang/rust/pull/112606
if !addr.is_specified() {
write!(w, "::")
} else if addr.is_loopback() {
write!(w, "::1")
} else if let Some(v4) = addr.to_ipv4_mapped() {
write!(w, "::ffff:{}", v4)
} else {
let segments = addr.segments();
let longest_zero_span = {
let mut longest_zero_span = 0..0;
let mut current_zero_span = 0..0;
for (i, seg) in segments.iter().enumerate() {
if *seg == 0 {
current_zero_span.end = i + 1;
if current_zero_span.len() > longest_zero_span.len() {
longest_zero_span = current_zero_span.clone();
}
} else {
let next_idx = i + 1;
current_zero_span = next_idx..next_idx;
}
}
longest_zero_span
};
let write_slice = |w: &mut W, slice: &[u16]| {
if let [head, tail @ ..] = slice {
write!(w, "{:x}", head)?;
for seg in tail {
write!(w, ":{:x}", seg)?;
}
}
Ok(())
};
// Note that RFC 5952 gives us a choice of when to compress a
// run of zeroes:
//
// It is possible to select whether or not to omit just one
// 16-bit 0 field.
//
// Given this choice, we opt to match the stdlib's behavior.
// This makes it easier to write tests (we can simply check to
// see whether our behavior matches `std`'s behavior on a range
// of inputs), and makes it so that our `Ipv6Addr` type is,
// behaviorally, more of a drop-in for `std::net::Ipv6Addr` than
// it would be if we were to diverge on formatting. This makes
// replacing `std::net::Ipv6Addr` with our `Ipv6Addr` easier for
// clients, and also makes it an easier choice since they don't
// have to weigh whether the difference in behavior is
// acceptable for them.
if longest_zero_span.len() > 1 {
write_slice(w, &segments[..longest_zero_span.start])?;
w.write_str("::")?;
write_slice(w, &segments[longest_zero_span.end..])
} else {
write_slice(w, &segments)
}
}
}
if f.precision().is_none() && f.width().is_none() {
// Fast path: No precision or width requirements, so write directly
// to `f`.
fmt_inner(self, f)
} else {
// Slow path: Precision or width requirement(s), so construct a
// scratch buffer, use the `fmt_inner` to fill it, then use `f.pad`
// to satisfy precision/width requirement(s).
// `[u8]` does not implement `core::fmt::Write`, so we provide our
// own wrapper which does.
struct ByteSlice<'a>(&'a mut [u8]);
impl<'a> fmt::Write for ByteSlice<'a> {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
let from = s.as_bytes();
if from.len() > self.0.len() {
return Err(fmt::Error);
}
// Temporarily replace `self.0` with an empty slice and move
// the old value of `self.0` into our scope so that we can
// operate on it by value. This allows us to split it in two
// (`to` and `remaining`) and then overwrite `self.0` with
// `remaining`.
let to = mem::replace(&mut self.0, &mut [][..]);
let (to, remaining) = to.split_at_mut(from.len());
to.copy_from_slice(from);
self.0 = remaining;
Ok(())
}
}
// The maximum length for an IPv6 address displays all 8 pairs of
// bytes in hexadecimal representation (4 characters per two bytes
// of IPv6 address), each separated with colons (7 colons total).
const MAX_DISPLAY_LEN: usize = (4 * 8) + 7;
let mut scratch = [0u8; MAX_DISPLAY_LEN];
let mut scratch_slice = ByteSlice(&mut scratch[..]);
// `fmt_inner` only returns an error if a method on `w` returns an
// error. Since, in this call to `fmt_inner`, `w` is
// `scratch_slice`, the only error that could happen would be if we
// run out of space, but we know we won't because `scratch_slice`
// has `MAX_DISPLAY_LEN` bytes, which is enough to hold any
// formatted IPv6 address.
fmt_inner(self, &mut scratch_slice)
.expect("<Ipv6Addr as Display>::fmt: fmt_inner should have succeeded because the scratch buffer was long enough");
let unwritten = scratch_slice.0.len();
let len = MAX_DISPLAY_LEN - unwritten;
// `fmt_inner` only writes valid UTF-8.
let str = core::str::from_utf8(&scratch[..len])
.expect("<Ipv6Addr as Display>::fmt: scratch buffer should contain valid UTF-8");
f.pad(str)
}
}
}
impl Debug for Ipv6Addr {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
Display::fmt(self, f)
}
}
/// The source address from an IPv6 packet.
///
/// An `Ipv6SourceAddr` represents the source address from an IPv6 packet, which
/// may only be either:
/// * unicast and non-mapped (e.g. not an ipv4-mapped-ipv6 address), or
/// * unspecified.
#[allow(missing_docs)]
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Ipv6SourceAddr {
Unicast(NonMappedAddr<UnicastAddr<Ipv6Addr>>),
Unspecified,
}
impl crate::sealed::Sealed for Ipv6SourceAddr {}
impl Ipv6SourceAddr {
/// Constructs a new `Ipv6SourceAddr`.
///
/// Returns `None` if `addr` does not satisfy the properties required of an
/// `Ipv6SourceAddr`.
#[inline]
pub fn new(addr: Ipv6Addr) -> Option<Ipv6SourceAddr> {
if let Some(addr) = UnicastAddr::new(addr) {
NonMappedAddr::new(addr).map(Ipv6SourceAddr::Unicast)
} else if !addr.is_specified() {
Some(Ipv6SourceAddr::Unspecified)
} else {
None
}
}
}
impl Witness<Ipv6Addr> for Ipv6SourceAddr {
#[inline]
fn new(addr: Ipv6Addr) -> Option<Ipv6SourceAddr> {
Ipv6SourceAddr::new(addr)
}
#[inline]
unsafe fn new_unchecked(addr: Ipv6Addr) -> Ipv6SourceAddr {
Ipv6SourceAddr::new(addr).unwrap()
}
#[inline]
fn into_addr(self) -> Ipv6Addr {
match self {
Ipv6SourceAddr::Unicast(addr) => **addr,
Ipv6SourceAddr::Unspecified => Ipv6::UNSPECIFIED_ADDRESS,
}
}
}
impl SpecifiedAddress for Ipv6SourceAddr {
fn is_specified(&self) -> bool {
self != &Ipv6SourceAddr::Unspecified
}
}
impl UnicastAddress for Ipv6SourceAddr {
fn is_unicast(&self) -> bool {
matches!(self, Ipv6SourceAddr::Unicast(_))
}
}
impl LinkLocalAddress for Ipv6SourceAddr {
fn is_link_local(&self) -> bool {
let addr: Ipv6Addr = self.into();
addr.is_link_local()
}
}
impl MappedAddress for Ipv6SourceAddr {
fn is_non_mapped(&self) -> bool {
let addr: Ipv6Addr = self.into();
addr.is_non_mapped()
}
}
impl From<Ipv6SourceAddr> for Ipv6Addr {
fn from(addr: Ipv6SourceAddr) -> Ipv6Addr {
addr.get()
}
}
impl From<&'_ Ipv6SourceAddr> for Ipv6Addr {
fn from(addr: &Ipv6SourceAddr) -> Ipv6Addr {
match addr {
Ipv6SourceAddr::Unicast(addr) => addr.get(),
Ipv6SourceAddr::Unspecified => Ipv6::UNSPECIFIED_ADDRESS,
}
}
}
impl TryFrom<Ipv6Addr> for Ipv6SourceAddr {
type Error = ();
fn try_from(addr: Ipv6Addr) -> Result<Ipv6SourceAddr, ()> {
Ipv6SourceAddr::new(addr).ok_or(())
}
}
impl AsRef<Ipv6Addr> for Ipv6SourceAddr {
fn as_ref(&self) -> &Ipv6Addr {
match self {
Ipv6SourceAddr::Unicast(addr) => addr,
Ipv6SourceAddr::Unspecified => &Ipv6::UNSPECIFIED_ADDRESS,
}
}
}
impl Deref for Ipv6SourceAddr {
type Target = Ipv6Addr;
fn deref(&self) -> &Ipv6Addr {
self.as_ref()
}
}
impl Display for Ipv6SourceAddr {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
match self {
Ipv6SourceAddr::Unicast(addr) => write!(f, "{}", addr),
Ipv6SourceAddr::Unspecified => write!(f, "::"),
}
}
}
impl Debug for Ipv6SourceAddr {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
Display::fmt(self, f)
}
}
/// An IPv6 address stored as a unicast or multicast witness type.
///
/// `UnicastOrMulticastIpv6Addr` is either a [`UnicastAddr`] or a
/// [`MulticastAddr`]. It allows the user to match on the unicast-ness or
/// multicast-ness of an IPv6 address and obtain a statically-typed witness in
/// each case. This is useful if the user needs to call different functions
/// which each take a witness type.
#[allow(missing_docs)]
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum UnicastOrMulticastIpv6Addr {
Unicast(UnicastAddr<Ipv6Addr>),
Multicast(MulticastAddr<Ipv6Addr>),
}
impl UnicastOrMulticastIpv6Addr {
/// Constructs a new `UnicastOrMulticastIpv6Addr`.
///
/// Returns `None` if `addr` is the unspecified address.
pub fn new(addr: Ipv6Addr) -> Option<UnicastOrMulticastIpv6Addr> {
SpecifiedAddr::new(addr).map(UnicastOrMulticastIpv6Addr::from_specified)
}
/// Constructs a new `UnicastOrMulticastIpv6Addr` from a specified address.
pub fn from_specified(addr: SpecifiedAddr<Ipv6Addr>) -> UnicastOrMulticastIpv6Addr {
if addr.is_unicast() {
UnicastOrMulticastIpv6Addr::Unicast(UnicastAddr(addr.get()))
} else {
UnicastOrMulticastIpv6Addr::Multicast(MulticastAddr(addr.get()))
}
}
}
impl crate::sealed::Sealed for UnicastOrMulticastIpv6Addr {}
impl Witness<Ipv6Addr> for UnicastOrMulticastIpv6Addr {
#[inline]
fn new(addr: Ipv6Addr) -> Option<UnicastOrMulticastIpv6Addr> {
UnicastOrMulticastIpv6Addr::new(addr)
}
#[inline]
unsafe fn new_unchecked(addr: Ipv6Addr) -> UnicastOrMulticastIpv6Addr {
UnicastOrMulticastIpv6Addr::new(addr).unwrap()
}
#[inline]
fn into_addr(self) -> Ipv6Addr {
match self {
UnicastOrMulticastIpv6Addr::Unicast(addr) => addr.get(),
UnicastOrMulticastIpv6Addr::Multicast(addr) => addr.get(),
}
}
}
impl UnicastAddress for UnicastOrMulticastIpv6Addr {
fn is_unicast(&self) -> bool {
matches!(self, UnicastOrMulticastIpv6Addr::Unicast(_))
}
}
impl MulticastAddress for UnicastOrMulticastIpv6Addr {
fn is_multicast(&self) -> bool {
matches!(self, UnicastOrMulticastIpv6Addr::Multicast(_))
}
}
impl LinkLocalAddress for UnicastOrMulticastIpv6Addr {
fn is_link_local(&self) -> bool {
match self {
UnicastOrMulticastIpv6Addr::Unicast(addr) => addr.is_link_local(),
UnicastOrMulticastIpv6Addr::Multicast(addr) => addr.is_link_local(),
}
}
}
impl MappedAddress for UnicastOrMulticastIpv6Addr {
fn is_non_mapped(&self) -> bool {
match self {
UnicastOrMulticastIpv6Addr::Unicast(addr) => addr.is_non_mapped(),
UnicastOrMulticastIpv6Addr::Multicast(addr) => addr.is_non_mapped(),
}
}
}
impl From<UnicastOrMulticastIpv6Addr> for Ipv6Addr {
fn from(addr: UnicastOrMulticastIpv6Addr) -> Ipv6Addr {
addr.get()
}
}
impl From<&'_ UnicastOrMulticastIpv6Addr> for Ipv6Addr {
fn from(addr: &UnicastOrMulticastIpv6Addr) -> Ipv6Addr {
addr.get()
}
}
impl From<UnicastAddr<Ipv6Addr>> for UnicastOrMulticastIpv6Addr {
fn from(addr: UnicastAddr<Ipv6Addr>) -> UnicastOrMulticastIpv6Addr {
UnicastOrMulticastIpv6Addr::Unicast(addr)
}
}
impl From<MulticastAddr<Ipv6Addr>> for UnicastOrMulticastIpv6Addr {
fn from(addr: MulticastAddr<Ipv6Addr>) -> UnicastOrMulticastIpv6Addr {
UnicastOrMulticastIpv6Addr::Multicast(addr)
}
}
impl TryFrom<Ipv6Addr> for UnicastOrMulticastIpv6Addr {
type Error = ();
fn try_from(addr: Ipv6Addr) -> Result<UnicastOrMulticastIpv6Addr, ()> {
UnicastOrMulticastIpv6Addr::new(addr).ok_or(())
}
}
impl AsRef<Ipv6Addr> for UnicastOrMulticastIpv6Addr {
fn as_ref(&self) -> &Ipv6Addr {
match self {
UnicastOrMulticastIpv6Addr::Unicast(addr) => addr,
UnicastOrMulticastIpv6Addr::Multicast(addr) => addr,
}
}
}
impl Deref for UnicastOrMulticastIpv6Addr {
type Target = Ipv6Addr;
fn deref(&self) -> &Ipv6Addr {
self.as_ref()
}
}
impl Display for UnicastOrMulticastIpv6Addr {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
match self {
UnicastOrMulticastIpv6Addr::Unicast(addr) => write!(f, "{}", addr),
UnicastOrMulticastIpv6Addr::Multicast(addr) => write!(f, "{}", addr),
}
}
}
impl Debug for UnicastOrMulticastIpv6Addr {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
Display::fmt(self, f)
}
}
/// The error returned from [`Subnet::new`] and [`SubnetEither::new`].
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SubnetError {
/// The network prefix is longer than the number of bits in the address (32
/// for IPv4/128 for IPv6).
PrefixTooLong,
/// The network address has some bits in the host part (past the network
/// prefix) set to one.
HostBitsSet,
}
/// A prefix was provided which is longer than the number of bits in the address
/// (32 for IPv4/128 for IPv6).
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct PrefixTooLongError;
/// An IP subnet.
///
/// `Subnet` is a combination of an IP network address and a prefix length.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Subnet<A> {
// invariant: only contains prefix bits
network: A,
prefix: u8,
}
impl<A: core::cmp::Ord> core::cmp::PartialOrd for Subnet<A> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
/// Subnet ordering always orders from least-specific to most-specific subnet.
impl<A: core::cmp::Ord> core::cmp::Ord for Subnet<A> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
let Self { network, prefix } = self;
let Self { network: other_network, prefix: other_prefix } = other;
match prefix.cmp(other_prefix) {
core::cmp::Ordering::Equal => network.cmp(other_network),
ord => ord,
}
}
}
impl<A> Subnet<A> {
/// Creates a new subnet without enforcing correctness.
///
/// # Safety
///
/// Unlike `new`, `new_unchecked` does not validate that `prefix` is in the
/// proper range, and does not check that `network` has only the top
/// `prefix` bits set. It is up to the caller to guarantee that `prefix` is
/// in the proper range, and that none of the bits of `network` beyond the
/// prefix are set.
#[inline]
pub const unsafe fn new_unchecked(network: A, prefix: u8) -> Subnet<A> {
Subnet { network, prefix }
}
}
impl<A: IpAddress> Subnet<A> {
/// Creates a new subnet.
///
/// `new` creates a new subnet with the given network address and prefix
/// length. It returns `Err` if `prefix` is longer than the number of bits
/// in this type of IP address (32 for IPv4 and 128 for IPv6) or if any of
/// the host bits (beyond the first `prefix` bits) are set in `network`.
#[inline]
pub fn new(network: A, prefix: u8) -> Result<Subnet<A>, SubnetError> {
if prefix > A::BYTES * 8 {
return Err(SubnetError::PrefixTooLong);
}
// TODO(joshlf): Is there a more efficient way we can perform this
// check?
if network != network.mask(prefix) {
return Err(SubnetError::HostBitsSet);
}
Ok(Subnet { network, prefix })
}
/// Creates a new subnet from the address of a host in that subnet.
///
/// Unlike [`new`], the `host` address may have host bits set.
///
/// [`new`]: Subnet::new
#[inline]
pub fn from_host(host: A, prefix: u8) -> Result<Subnet<A>, PrefixTooLongError> {
if prefix > A::BYTES * 8 {
return Err(PrefixTooLongError);
}
let network = host.mask(prefix);
Ok(Subnet { network, prefix })
}
/// Gets the network address component of this subnet.
///
/// Any bits beyond the prefix will be zero.
#[inline]
pub fn network(&self) -> A {
self.network
}
/// Gets the prefix length component of this subnet.
#[inline]
pub fn prefix(&self) -> u8 {
self.prefix
}
/// Tests whether an address is in this subnet.
///
/// Tests whether `addr` is in this subnet by testing whether the prefix
/// bits match the prefix bits of the subnet's network address. This is
/// equivalent to `sub.network() == addr.mask(sub.prefix())`.
#[inline]
pub fn contains(&self, addr: &A) -> bool {
self.network == addr.mask(self.prefix)
}
}
impl Subnet<Ipv4Addr> {
// TODO(joshlf): If we introduce a separate type for an address in a subnet
// (with fewer requirements than `AddrSubnet` has now so that a broadcast
// address is representable), then that type could implement
// `BroadcastAddress`, and `broadcast` could return
// `BroadcastAddr<Foo<Ipv4Addr>>`.
/// Gets the broadcast address in this IPv4 subnet.
#[inline]
pub fn broadcast(self) -> Ipv4Addr {
if self.prefix == 32 {
// shifting right by the size of the value is undefined
self.network
} else {
let mask = <u32>::max_value() >> self.prefix;
Ipv4Addr::new((u32::from_be_bytes(self.network.0) | mask).to_be_bytes())
}
}
}
impl<A: IpAddress> Display for Subnet<A> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}/{}", self.network, self.prefix)
}
}
impl<A: IpAddress> Debug for Subnet<A> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "{}/{}", self.network, self.prefix)
}
}
impl<A, I: Ip> GenericOverIp<I> for Subnet<A> {
type Type = Subnet<I::Addr>;
}
/// An IPv4 subnet or an IPv6 subnet.
///
/// `SubnetEither` is an enum of [`Subnet<Ipv4Addr>`] and `Subnet<Ipv6Addr>`.
///
/// [`Subnet<Ipv4Addr>`]: Subnet
#[allow(missing_docs)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
pub enum SubnetEither {
V4(Subnet<Ipv4Addr>),
V6(Subnet<Ipv6Addr>),
}
impl SubnetEither {
/// Creates a new subnet.
///
/// `new` creates a new subnet with the given network address and prefix
/// length. It returns `Err` if `prefix` is longer than the number of bits
/// in this type of IP address (32 for IPv4 and 128 for IPv6) or if any of
/// the host bits (beyond the first `prefix` bits) are set in `network`.
#[inline]
pub fn new(network: IpAddr, prefix: u8) -> Result<SubnetEither, SubnetError> {
Ok(match network {
IpAddr::V4(network) => SubnetEither::V4(Subnet::new(network, prefix)?),
IpAddr::V6(network) => SubnetEither::V6(Subnet::new(network, prefix)?),
})
}
/// Creates a new subnet from the address of a host in that subnet.
///
/// Unlike [`new`], the `host` address may have host bits set.
///
/// [`new`]: SubnetEither::new
#[inline]
pub fn from_host(host: IpAddr, prefix: u8) -> Result<SubnetEither, PrefixTooLongError> {
Ok(match host {
IpAddr::V4(host) => SubnetEither::V4(Subnet::from_host(host, prefix)?),
IpAddr::V6(host) => SubnetEither::V6(Subnet::from_host(host, prefix)?),
})
}
/// Gets the network and prefix.
#[inline]
pub fn net_prefix(&self) -> (IpAddr, u8) {
match self {
SubnetEither::V4(v4) => (v4.network.into(), v4.prefix),
SubnetEither::V6(v6) => (v6.network.into(), v6.prefix),
}
}
}
impl<A: IpAddress> From<Subnet<A>> for SubnetEither {
fn from(subnet: Subnet<A>) -> SubnetEither {
A::subnet_into_either(subnet)
}
}
/// The error returned from [`AddrSubnet::new`] and [`AddrSubnetEither::new`].
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AddrSubnetError {
/// The network prefix is longer than the number of bits in the address (32
/// for IPv4/128 for IPv6).
PrefixTooLong,
/// The address is not a unicast address in the given subnet (see
/// [`IpAddress::is_unicast_in_subnet`]).
NotUnicastInSubnet,
/// The address does not satisfy the requirements of the witness type.
InvalidWitness,
}
// TODO(joshlf): Is the unicast restriction always necessary, or will some users
// want the AddrSubnet functionality without that restriction?
/// An address and that address's subnet.
///
/// An `AddrSubnet` is a pair of an address and a subnet which maintains the
/// invariant that the address is guaranteed to be a unicast address in the
/// subnet. `S` is the type of address ([`Ipv4Addr`] or [`Ipv6Addr`]), and `A`
/// is the type of the address in the subnet, which is always a witness wrapper
/// around `S`. By default, it is `SpecifiedAddr<S>`.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
pub struct AddrSubnet<S: IpAddress, A: Witness<S> + Copy = SpecifiedAddr<S>> {
// TODO(joshlf): Would it be more performant to store these as just an
// address and subnet mask? It would make the object smaller and so cheaper
// to pass around, but it would make certain operations more expensive.
addr: A,
subnet: Subnet<S>,
}
impl<S: IpAddress, A: Witness<S> + Copy> AddrSubnet<S, A> {
/// Creates a new `AddrSubnet`.
///
/// `new` is like [`from_witness`], except that it also converts `addr` into
/// the appropriate witness type, returning
/// [`AddrSubnetError::InvalidWitness`] if the conversion fails.
///
/// [`from_witness`]: Witness::from_witness
#[inline]
pub fn new(addr: S, prefix: u8) -> Result<AddrSubnet<S, A>, AddrSubnetError> {
AddrSubnet::from_witness(A::new(addr).ok_or(AddrSubnetError::InvalidWitness)?, prefix)
}
/// Creates a new `AddrSubnet` without checking for validity.
///
/// # Safety
///
/// Unlike [`new`], `new_unchecked` does not validate that `prefix` is in the
/// proper range, and does not check that `addr` is a valid value for the
/// witness type `A`. It is up to the caller to guarantee that `prefix` is
/// in the proper range, and `A::new(addr)` is not `None`.
///
/// [`new`]: AddrSubnet::new
#[inline]
pub unsafe fn new_unchecked(addr: S, prefix: u8) -> Self {
let (subnet, addr) =
unsafe { (Subnet::new_unchecked(addr.mask(prefix), prefix), A::new_unchecked(addr)) };
AddrSubnet { addr, subnet }
}
/// Creates a new `AddrSubnet` from an existing witness.
///
/// `from_witness` creates a new `AddrSubnet` with the given address and
/// prefix length. The network address of the subnet is taken to be the
/// first `prefix` bits of the address. It returns `Err` if `prefix` is
/// longer than the number of bits in this type of IP address (32 for IPv4
/// and 128 for IPv6) or if `addr` is not a unicast address in the resulting
/// subnet (see [`IpAddress::is_unicast_in_subnet`]).
pub fn from_witness(addr: A, prefix: u8) -> Result<AddrSubnet<S, A>, AddrSubnetError> {
if prefix > S::BYTES * 8 {
return Err(AddrSubnetError::PrefixTooLong);
}
let subnet = Subnet { network: addr.as_ref().mask(prefix), prefix };
if !addr.as_ref().is_unicast_in_subnet(&subnet) {
return Err(AddrSubnetError::NotUnicastInSubnet);
}
Ok(AddrSubnet { addr, subnet })
}
/// Gets the subnet.
#[inline]
pub fn subnet(&self) -> Subnet<S> {
self.subnet
}
/// Gets the address.
#[inline]
pub fn addr(&self) -> A {
self.addr
}
/// Gets the address and subnet.
#[inline]
pub fn addr_subnet(self) -> (A, Subnet<S>) {
(self.addr, self.subnet)
}
/// Constructs a new `AddrSubnet` of a different witness type.
#[inline]
pub fn to_witness<B: Witness<S> + Copy>(&self) -> AddrSubnet<S, B>
where
A: Into<B>,
{
AddrSubnet { addr: self.addr.into(), subnet: self.subnet }
}
/// Wraps an additional witness onto this [`AddrSubnet`].
#[inline]
pub fn add_witness<B: Witness<A> + Witness<S> + Copy>(&self) -> Option<AddrSubnet<S, B>> {
let addr = B::new(self.addr)?;
Some(AddrSubnet { addr, subnet: self.subnet })
}
/// Replaces the [`AddrSubnet`] witness.
#[inline]
pub fn replace_witness<B: Witness<S> + Copy>(&self) -> Option<AddrSubnet<S, B>> {
let addr = B::new(self.addr.get())?;
Some(AddrSubnet { addr, subnet: self.subnet })
}
}
impl<S: IpAddress, A: Witness<S> + Copy + Display> Display for AddrSubnet<S, A> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {