| // 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> { |
|