You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
581 lines
23 KiB
Rust
581 lines
23 KiB
Rust
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
|
/// This code is the unstable ip code from the rust std
|
|
/// Since I would like to build on the stable rust, I just copied it yolo
|
|
|
|
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
|
|
pub enum Ipv6MulticastScope {
|
|
InterfaceLocal,
|
|
LinkLocal,
|
|
RealmLocal,
|
|
AdminLocal,
|
|
SiteLocal,
|
|
OrganizationLocal,
|
|
Global,
|
|
}
|
|
|
|
pub trait IpAddrExt {
|
|
fn ext_is_global(&self) -> bool;
|
|
fn ext_is_documentation(&self) -> bool;
|
|
}
|
|
|
|
impl IpAddrExt for IpAddr {
|
|
/// Returns [`true`] if the address appears to be globally routable.
|
|
///
|
|
/// See the documentation for [`Ipv4Addr::is_global`][IPv4] and
|
|
/// [`Ipv6Addr::is_global`][IPv6] for more details.
|
|
///
|
|
/// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_global
|
|
/// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_global
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
|
/// use torment_core::ip::IpAddrExt;
|
|
///
|
|
/// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).ext_is_global(), true);
|
|
/// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).ext_is_global(), true);
|
|
/// ```
|
|
fn ext_is_global(&self) -> bool {
|
|
match self {
|
|
IpAddr::V4(ip) => ip.ext_is_global(),
|
|
IpAddr::V6(ip) => ip.ext_is_global(),
|
|
}
|
|
}
|
|
|
|
/// Returns [`true`] if this address is in a range designated for documentation.
|
|
///
|
|
/// See the documentation for [`Ipv4Addr::is_documentation`][IPv4] and
|
|
/// [`Ipv6Addr::is_documentation`][IPv6] for more details.
|
|
///
|
|
/// [IPv4]: ../../std/net/struct.Ipv4Addr.html#method.is_documentation
|
|
/// [IPv6]: ../../std/net/struct.Ipv6Addr.html#method.is_documentation
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
|
/// use torment_core::ip::IpAddrExt;
|
|
///
|
|
/// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).ext_is_documentation(), true);
|
|
/// assert_eq!(
|
|
/// IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).ext_is_documentation(),
|
|
/// true
|
|
/// );
|
|
/// ```
|
|
fn ext_is_documentation(&self) -> bool {
|
|
match self {
|
|
IpAddr::V4(ip) => ip.is_documentation(),
|
|
IpAddr::V6(ip) => ip.ext_is_documentation(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait Ipv4AddrExt {
|
|
fn ext_is_global(&self) -> bool;
|
|
fn ext_is_shared(&self) -> bool;
|
|
fn ext_is_ietf_protocol_assignment(&self) -> bool;
|
|
fn ext_is_benchmarking(&self) -> bool;
|
|
fn ext_is_reserved(&self) -> bool;
|
|
}
|
|
|
|
impl Ipv4AddrExt for Ipv4Addr {
|
|
/// Returns [`true`] if the address appears to be globally routable.
|
|
/// See [iana-ipv4-special-registry][ipv4-sr].
|
|
///
|
|
/// The following return false:
|
|
///
|
|
/// - private addresses (see [`is_private()`](#method.is_private))
|
|
/// - the loopback address (see [`is_loopback()`](#method.is_loopback))
|
|
/// - the link-local address (see [`is_link_local()`](#method.is_link_local))
|
|
/// - the broadcast address (see [`is_broadcast()`](#method.is_broadcast))
|
|
/// - addresses used for documentation (see [`is_documentation()`](#method.is_documentation))
|
|
/// - the unspecified address (see [`is_unspecified()`](#method.is_unspecified)), and the whole
|
|
/// 0.0.0.0/8 block
|
|
/// - addresses reserved for future protocols (see
|
|
/// [`is_ietf_protocol_assignment()`](#method.is_ietf_protocol_assignment), except
|
|
/// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable
|
|
/// - addresses reserved for future use (see [`is_reserved()`](#method.is_reserved)
|
|
/// - addresses reserved for networking devices benchmarking (see
|
|
/// [`is_benchmarking`](#method.is_benchmarking))
|
|
///
|
|
/// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv4Addr;
|
|
/// use torment_core::ip::Ipv4AddrExt;
|
|
///
|
|
/// // private addresses are not global
|
|
/// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).ext_is_global(), false);
|
|
/// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).ext_is_global(), false);
|
|
/// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).ext_is_global(), false);
|
|
///
|
|
/// // the 0.0.0.0/8 block is not global
|
|
/// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).ext_is_global(), false);
|
|
/// // in particular, the unspecified address is not global
|
|
/// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).ext_is_global(), false);
|
|
///
|
|
/// // the loopback address is not global
|
|
/// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).ext_is_global(), false);
|
|
///
|
|
/// // link local addresses are not global
|
|
/// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).ext_is_global(), false);
|
|
///
|
|
/// // the broadcast address is not global
|
|
/// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).ext_is_global(), false);
|
|
///
|
|
/// // the address space designated for documentation is not global
|
|
/// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).ext_is_global(), false);
|
|
/// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).ext_is_global(), false);
|
|
/// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).ext_is_global(), false);
|
|
///
|
|
/// // shared addresses are not global
|
|
/// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).ext_is_global(), false);
|
|
///
|
|
/// // addresses reserved for protocol assignment are not global
|
|
/// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).ext_is_global(), false);
|
|
/// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).ext_is_global(), false);
|
|
///
|
|
/// // addresses reserved for future use are not global
|
|
/// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).ext_is_global(), false);
|
|
///
|
|
/// // addresses reserved for network devices benchmarking are not global
|
|
/// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).ext_is_global(), false);
|
|
///
|
|
/// // All the other addresses are global
|
|
/// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).ext_is_global(), true);
|
|
/// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).ext_is_global(), true);
|
|
/// ```
|
|
fn ext_is_global(&self) -> bool {
|
|
// check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
|
|
// globally routable addresses in the 192.0.0.0/24 range.
|
|
if u32::from(*self) == 0xc0000009 || u32::from(*self) == 0xc000000a {
|
|
return true;
|
|
}
|
|
!self.is_private()
|
|
&& !self.is_loopback()
|
|
&& !self.is_link_local()
|
|
&& !self.is_broadcast()
|
|
&& !self.is_documentation()
|
|
&& !self.ext_is_shared()
|
|
&& !self.ext_is_ietf_protocol_assignment()
|
|
&& !self.ext_is_reserved()
|
|
&& !self.ext_is_benchmarking()
|
|
// Make sure the address is not in 0.0.0.0/8
|
|
&& self.octets()[0] != 0
|
|
}
|
|
|
|
/// Returns [`true`] if this address is part of the Shared Address Space defined in
|
|
/// [IETF RFC 6598] (`100.64.0.0/10`).
|
|
///
|
|
/// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv4Addr;
|
|
/// use torment_core::ip::Ipv4AddrExt;
|
|
///
|
|
/// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).ext_is_shared(), true);
|
|
/// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).ext_is_shared(), true);
|
|
/// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).ext_is_shared(), false);
|
|
/// ```
|
|
fn ext_is_shared(&self) -> bool {
|
|
self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
|
|
}
|
|
|
|
/// Returns [`true`] if this address is part of `192.0.0.0/24`, which is reserved to
|
|
/// IANA for IETF protocol assignments, as documented in [IETF RFC 6890].
|
|
///
|
|
/// Note that parts of this block are in use:
|
|
///
|
|
/// - `192.0.0.8/32` is the "IPv4 dummy address" (see [IETF RFC 7600])
|
|
/// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723])
|
|
/// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155])
|
|
///
|
|
/// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890
|
|
/// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600
|
|
/// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723
|
|
/// [IETF RFC 8155]: https://tools.ietf.org/html/rfc8155
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv4Addr;
|
|
/// use torment_core::ip::Ipv4AddrExt;
|
|
///
|
|
/// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).ext_is_ietf_protocol_assignment(), true);
|
|
/// assert_eq!(Ipv4Addr::new(192, 0, 0, 8).ext_is_ietf_protocol_assignment(), true);
|
|
/// assert_eq!(Ipv4Addr::new(192, 0, 0, 9).ext_is_ietf_protocol_assignment(), true);
|
|
/// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).ext_is_ietf_protocol_assignment(), true);
|
|
/// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).ext_is_ietf_protocol_assignment(), false);
|
|
/// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).ext_is_ietf_protocol_assignment(), false);
|
|
/// ```
|
|
fn ext_is_ietf_protocol_assignment(&self) -> bool {
|
|
self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
|
|
}
|
|
|
|
/// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for
|
|
/// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0`
|
|
/// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`.
|
|
///
|
|
/// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544
|
|
/// [errata 423]: https://www.rfc-editor.org/errata/eid423
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv4Addr;
|
|
/// use torment_core::ip::Ipv4AddrExt;
|
|
///
|
|
/// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).ext_is_benchmarking(), false);
|
|
/// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).ext_is_benchmarking(), true);
|
|
/// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).ext_is_benchmarking(), true);
|
|
/// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).ext_is_benchmarking(), false);
|
|
/// ```
|
|
fn ext_is_benchmarking(&self) -> bool {
|
|
self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
|
|
}
|
|
|
|
/// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112]
|
|
/// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the
|
|
/// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since
|
|
/// it is obviously not reserved for future use.
|
|
///
|
|
/// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
///
|
|
/// # Warning
|
|
///
|
|
/// As IANA assigns new addresses, this method will be
|
|
/// updated. This may result in non-reserved addresses being
|
|
/// treated as reserved in code that relies on an outdated version
|
|
/// of this method.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv4Addr;
|
|
/// use torment_core::ip::Ipv4AddrExt;
|
|
///
|
|
/// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).ext_is_reserved(), true);
|
|
/// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).ext_is_reserved(), true);
|
|
///
|
|
/// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).ext_is_reserved(), false);
|
|
/// // The broadcast address is not considered as reserved for future use by this implementation
|
|
/// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).ext_is_reserved(), false);
|
|
/// ```
|
|
fn ext_is_reserved(&self) -> bool {
|
|
self.octets()[0] & 240 == 240 && !self.is_broadcast()
|
|
}
|
|
}
|
|
|
|
pub trait Ipv6AddrExt {
|
|
fn ext_is_global(&self) -> bool;
|
|
fn ext_is_unique_local(&self) -> bool;
|
|
fn ext_is_unicast_link_local_strict(&self) -> bool;
|
|
fn ext_is_unicast_link_local(&self) -> bool;
|
|
fn ext_is_unicast_site_local(&self) -> bool;
|
|
fn ext_is_unicast_global(&self) -> bool;
|
|
fn ext_is_documentation(&self) -> bool;
|
|
fn ext_multicast_scope(&self) -> Option<Ipv6MulticastScope>;
|
|
}
|
|
|
|
impl Ipv6AddrExt for Ipv6Addr {
|
|
/// Returns [`true`] if the address appears to be globally routable.
|
|
///
|
|
/// The following return [`false`]:
|
|
///
|
|
/// - the loopback address
|
|
/// - link-local and unique local unicast addresses
|
|
/// - interface-, link-, realm-, admin- and site-local multicast addresses
|
|
///
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
/// [`false`]: ../../std/primitive.bool.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv6Addr;
|
|
/// use torment_core::ip::Ipv6AddrExt;
|
|
///
|
|
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).ext_is_global(), true);
|
|
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).ext_is_global(), false);
|
|
/// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).ext_is_global(), true);
|
|
/// ```
|
|
fn ext_is_global(&self) -> bool {
|
|
match Ipv6AddrExt::ext_multicast_scope(self) {
|
|
Some(Ipv6MulticastScope::Global) => true,
|
|
None => self.ext_is_unicast_global(),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
/// Returns [`true`] if this is a unique local address (`fc00::/7`).
|
|
///
|
|
/// This property is defined in [IETF RFC 4193].
|
|
///
|
|
/// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv6Addr;
|
|
/// use torment_core::ip::Ipv6AddrExt;
|
|
///
|
|
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).ext_is_unique_local(), false);
|
|
/// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).ext_is_unique_local(), true);
|
|
/// ```
|
|
fn ext_is_unique_local(&self) -> bool {
|
|
(self.segments()[0] & 0xfe00) == 0xfc00
|
|
}
|
|
|
|
/// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`).
|
|
///
|
|
/// A common mis-conception is to think that "unicast link-local addresses start with
|
|
/// `fe80::`", but the [IETF RFC 4291] actually defines a stricter format for these addresses:
|
|
///
|
|
/// ```no_rust
|
|
/// | 10 |
|
|
/// | bits | 54 bits | 64 bits |
|
|
/// +----------+-------------------------+----------------------------+
|
|
/// |1111111010| 0 | interface ID |
|
|
/// +----------+-------------------------+----------------------------+
|
|
/// ```
|
|
///
|
|
/// This method validates the format defined in the RFC and won't recognize the following
|
|
/// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example.
|
|
/// If you need a less strict validation use [`is_unicast_link_local()`] instead.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv6Addr;
|
|
/// use torment_core::ip::Ipv6AddrExt;
|
|
///
|
|
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
|
|
/// assert!(ip.ext_is_unicast_link_local_strict());
|
|
///
|
|
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
|
|
/// assert!(ip.ext_is_unicast_link_local_strict());
|
|
///
|
|
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
|
|
/// assert!(!ip.ext_is_unicast_link_local_strict());
|
|
/// assert!(ip.ext_is_unicast_link_local());
|
|
///
|
|
/// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
|
|
/// assert!(!ip.ext_is_unicast_link_local_strict());
|
|
/// assert!(ip.ext_is_unicast_link_local());
|
|
/// ```
|
|
///
|
|
/// # See also
|
|
///
|
|
/// - [IETF RFC 4291 section 2.5.6]
|
|
/// - [RFC 4291 errata 4406]
|
|
/// - [`is_unicast_link_local()`]
|
|
///
|
|
/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
|
|
/// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
/// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
|
|
/// [`is_unicast_link_local()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local
|
|
///
|
|
fn ext_is_unicast_link_local_strict(&self) -> bool {
|
|
(self.segments()[0] & 0xffff) == 0xfe80
|
|
&& (self.segments()[1] & 0xffff) == 0
|
|
&& (self.segments()[2] & 0xffff) == 0
|
|
&& (self.segments()[3] & 0xffff) == 0
|
|
}
|
|
|
|
/// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`).
|
|
///
|
|
/// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4],
|
|
/// i.e. addresses with the following format:
|
|
///
|
|
/// ```no_rust
|
|
/// | 10 |
|
|
/// | bits | 54 bits | 64 bits |
|
|
/// +----------+-------------------------+----------------------------+
|
|
/// |1111111010| arbitratry value | interface ID |
|
|
/// +----------+-------------------------+----------------------------+
|
|
/// ```
|
|
///
|
|
/// As a result, this method consider addresses such as `fe80:0:0:1::` or `fe81::` to be
|
|
/// unicast link-local addresses, whereas [`is_unicast_link_local_strict()`] does not. If you
|
|
/// need a strict validation fully compliant with the RFC, use
|
|
/// [`is_unicast_link_local_strict()`].
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv6Addr;
|
|
/// use torment_core::ip::Ipv6AddrExt;
|
|
///
|
|
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
|
|
/// assert!(ip.ext_is_unicast_link_local());
|
|
///
|
|
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
|
|
/// assert!(ip.ext_is_unicast_link_local());
|
|
///
|
|
/// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
|
|
/// assert!(ip.ext_is_unicast_link_local());
|
|
/// assert!(!ip.ext_is_unicast_link_local_strict());
|
|
///
|
|
/// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
|
|
/// assert!(ip.ext_is_unicast_link_local());
|
|
/// assert!(!ip.ext_is_unicast_link_local_strict());
|
|
/// ```
|
|
///
|
|
/// # See also
|
|
///
|
|
/// - [IETF RFC 4291 section 2.4]
|
|
/// - [RFC 4291 errata 4406]
|
|
///
|
|
/// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
/// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
|
|
/// [`is_unicast_link_local_strict()`]: ../../std/net/struct.Ipv6Addr.html#method.is_unicast_link_local_strict
|
|
///
|
|
fn ext_is_unicast_link_local(&self) -> bool {
|
|
(self.segments()[0] & 0xffc0) == 0xfe80
|
|
}
|
|
|
|
/// Returns [`true`] if this is a deprecated unicast site-local address (fec0::/10). The
|
|
/// unicast site-local address format is defined in [RFC 4291 section 2.5.7] as:
|
|
///
|
|
/// ```no_rust
|
|
/// | 10 |
|
|
/// | bits | 54 bits | 64 bits |
|
|
/// +----------+-------------------------+----------------------------+
|
|
/// |1111111011| subnet ID | interface ID |
|
|
/// +----------+-------------------------+----------------------------+
|
|
/// ```
|
|
///
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
/// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv6Addr;
|
|
/// use torment_core::ip::Ipv6AddrExt;
|
|
///
|
|
/// assert_eq!(
|
|
/// Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).ext_is_unicast_site_local(),
|
|
/// false
|
|
/// );
|
|
/// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).ext_is_unicast_site_local(), true);
|
|
/// ```
|
|
///
|
|
/// # Warning
|
|
///
|
|
/// As per [RFC 3879], the whole `FEC0::/10` prefix is
|
|
/// deprecated. New software must not support site-local
|
|
/// addresses.
|
|
///
|
|
/// [RFC 3879]: https://tools.ietf.org/html/rfc3879
|
|
fn ext_is_unicast_site_local(&self) -> bool {
|
|
(self.segments()[0] & 0xffc0) == 0xfec0
|
|
}
|
|
|
|
/// Returns [`true`] if the address is a globally routable unicast address.
|
|
///
|
|
/// The following return false:
|
|
///
|
|
/// - the loopback address
|
|
/// - the link-local addresses
|
|
/// - unique local addresses
|
|
/// - the unspecified address
|
|
/// - the address range reserved for documentation
|
|
///
|
|
/// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7]
|
|
///
|
|
/// ```no_rust
|
|
/// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer
|
|
/// be supported in new implementations (i.e., new implementations must treat this prefix as
|
|
/// Global Unicast).
|
|
/// ```
|
|
///
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
/// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv6Addr;
|
|
/// use torment_core::ip::Ipv6AddrExt;
|
|
///
|
|
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).ext_is_unicast_global(), false);
|
|
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).ext_is_unicast_global(), true);
|
|
/// ```
|
|
fn ext_is_unicast_global(&self) -> bool {
|
|
!self.is_multicast()
|
|
&& !self.is_loopback()
|
|
&& !self.ext_is_unicast_link_local()
|
|
&& !self.ext_is_unique_local()
|
|
&& !self.is_unspecified()
|
|
&& !self.ext_is_documentation()
|
|
}
|
|
|
|
/// Returns [`true`] if this is an address reserved for documentation
|
|
/// (2001:db8::/32).
|
|
///
|
|
/// This property is defined in [IETF RFC 3849].
|
|
///
|
|
/// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
|
|
/// [`true`]: ../../std/primitive.bool.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::Ipv6Addr;
|
|
/// use torment_core::ip::Ipv6AddrExt;
|
|
///
|
|
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).ext_is_documentation(), false);
|
|
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).ext_is_documentation(), true);
|
|
/// ```
|
|
fn ext_is_documentation(&self) -> bool {
|
|
(self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
|
|
}
|
|
|
|
/// Returns the address's multicast scope if the address is multicast.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use std::net::{Ipv6Addr};
|
|
/// use torment_core::ip::{Ipv6AddrExt, Ipv6MulticastScope};
|
|
///
|
|
/// assert_eq!(
|
|
/// Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).ext_multicast_scope(),
|
|
/// Some(Ipv6MulticastScope::Global)
|
|
/// );
|
|
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).ext_multicast_scope(), None);
|
|
/// ```
|
|
fn ext_multicast_scope(&self) -> Option<Ipv6MulticastScope> {
|
|
if self.is_multicast() {
|
|
match self.segments()[0] & 0x000f {
|
|
1 => Some(Ipv6MulticastScope::InterfaceLocal),
|
|
2 => Some(Ipv6MulticastScope::LinkLocal),
|
|
3 => Some(Ipv6MulticastScope::RealmLocal),
|
|
4 => Some(Ipv6MulticastScope::AdminLocal),
|
|
5 => Some(Ipv6MulticastScope::SiteLocal),
|
|
8 => Some(Ipv6MulticastScope::OrganizationLocal),
|
|
14 => Some(Ipv6MulticastScope::Global),
|
|
_ => None,
|
|
}
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|