Skip to content

Commit

Permalink
Rollup merge of rust-lang#99957 - chotchki:ip-globally-reachable_reba…
Browse files Browse the repository at this point in the history
…se, r=Mark-Simulacrum

Rework Ipv6Addr::is_global to check for global reachability rather than global scope - rebase

Rebasing of pull request rust-lang#86634 off of master to try and get the feature "ip" stabilized.

I also found a test failure in the rebase that is_global was considering the benchmark space to be globally reachable.

This is related to my other rebasing pull request rust-lang#99947
  • Loading branch information
Dylan-DPC committed Aug 22, 2022
2 parents e77c208 + f659088 commit c1a5ec7
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 85 deletions.
204 changes: 133 additions & 71 deletions library/std/src/net/ip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -620,25 +620,31 @@ impl Ipv4Addr {
matches!(self.octets(), [169, 254, ..])
}

/// Returns [`true`] if the address appears to be globally routable.
/// See [iana-ipv4-special-registry][ipv4-sr].
/// Returns [`true`] if the address appears to be globally reachable
/// as specified by the [IANA IPv4 Special-Purpose Address Registry].
/// Whether or not an address is practically reachable will depend on your network configuration.
///
/// Most IPv4 addresses are globally reachable;
/// unless they are specifically defined as *not* globally reachable.
///
/// The following return [`false`]:
/// Non-exhaustive list of notable addresses that are not globally reachable:
///
/// - private addresses (see [`Ipv4Addr::is_private()`])
/// - the loopback address (see [`Ipv4Addr::is_loopback()`])
/// - the link-local address (see [`Ipv4Addr::is_link_local()`])
/// - the broadcast address (see [`Ipv4Addr::is_broadcast()`])
/// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`])
/// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole
/// `0.0.0.0/8` block
/// - addresses reserved for future protocols, except
/// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable
/// - addresses reserved for future use (see [`Ipv4Addr::is_reserved()`]
/// - addresses reserved for networking devices benchmarking (see
/// [`Ipv4Addr::is_benchmarking()`])
/// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified))
/// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private))
/// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared))
/// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback))
/// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local))
/// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation))
/// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking))
/// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved))
/// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast))
///
/// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
/// For the complete overview of which addresses are globally reachable, see the table at 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
/// [unspecified address]: Ipv4Addr::UNSPECIFIED
/// [broadcast address]: Ipv4Addr::BROADCAST

///
/// # Examples
///
Expand All @@ -647,71 +653,61 @@ impl Ipv4Addr {
///
/// use std::net::Ipv4Addr;
///
/// // private addresses are not global
/// // Most IPv4 addresses are globally reachable:
/// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
///
/// // However some addresses have been assigned a special meaning
/// // that makes them not globally reachable. Some examples are:
///
/// // The unspecified address (`0.0.0.0`)
/// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false);
///
/// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16)
/// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
/// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
/// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
///
/// // the 0.0.0.0/8 block is not global
/// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false);
/// // in particular, the unspecified address is not global
/// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false);
/// // Addresses in the shared address space (`100.64.0.0/10`)
/// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
///
/// // the loopback address is not global
/// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false);
/// // The loopback addresses (`127.0.0.0/8`)
/// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false);
///
/// // link local addresses are not global
/// // Link-local addresses (`169.254.0.0/16`)
/// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false);
///
/// // the broadcast address is not global
/// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false);
///
/// // the address space designated for documentation is not global
/// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`)
/// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false);
/// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false);
/// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false);
///
/// // shared addresses are not global
/// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
///
/// // addresses reserved for protocol assignment are not global
/// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false);
/// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false);
/// // Addresses reserved for benchmarking (`198.18.0.0/15`)
/// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
///
/// // addresses reserved for future use are not global
/// // Reserved addresses (`240.0.0.0/4`)
/// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
///
/// // addresses reserved for network devices benchmarking are not global
/// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
/// // The broadcast address (`255.255.255.255`)
/// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false);
///
/// // All the other addresses are global
/// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true);
/// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
/// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry.
/// ```
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
#[unstable(feature = "ip", issue = "27709")]
#[must_use]
#[inline]
pub const fn 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_be_bytes(self.octets()) == 0xc0000009
|| u32::from_be_bytes(self.octets()) == 0xc000000a
{
return true;
}
!self.is_private()
&& !self.is_loopback()
&& !self.is_link_local()
&& !self.is_broadcast()
&& !self.is_documentation()
&& !self.is_shared()
!(self.octets()[0] == 0 // "This network"
|| self.is_private()
|| self.is_shared()
|| self.is_loopback()
|| self.is_link_local()
// addresses reserved for future protocols (`192.0.0.0/24`)
&& !(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
&& !self.is_reserved()
&& !self.is_benchmarking()
// Make sure the address is not in 0.0.0.0/8
&& self.octets()[0] != 0
||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
|| self.is_documentation()
|| self.is_benchmarking()
|| self.is_reserved()
|| self.is_broadcast())
}

/// Returns [`true`] if this address is part of the Shared Address Space defined in
Expand Down Expand Up @@ -1300,13 +1296,33 @@ impl Ipv6Addr {
u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
}

/// Returns [`true`] if the address appears to be globally routable.
/// Returns [`true`] if the address appears to be globally reachable
/// as specified by the [IANA IPv6 Special-Purpose Address Registry].
/// Whether or not an address is practically reachable will depend on your network configuration.
///
/// The following return [`false`]:
/// Most IPv6 addresses are globally reachable;
/// unless they are specifically defined as *not* globally reachable.
///
/// - the loopback address
/// - link-local and unique local unicast addresses
/// - interface-, link-, realm-, admin- and site-local multicast addresses
/// Non-exhaustive list of notable addresses that are not globally reachable:
/// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified))
/// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback))
/// - IPv4-mapped addresses
/// - Addresses reserved for benchmarking
/// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation))
/// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local))
/// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local))
///
/// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry].
///
/// Note that an address having global scope is not the same as being globally reachable,
/// and there is no direct relation between the two concepts: There exist addresses with global scope
/// that are not globally reachable (for example unique local addresses),
/// and addresses that are globally reachable without having global scope
/// (multicast addresses with non-global scope).
///
/// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
/// [unspecified address]: Ipv6Addr::UNSPECIFIED
/// [loopback address]: Ipv6Addr::LOCALHOST
///
/// # Examples
///
Expand All @@ -1315,20 +1331,65 @@ impl Ipv6Addr {
///
/// use std::net::Ipv6Addr;
///
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true);
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false);
/// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
/// // Most IPv6 addresses are globally reachable:
/// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true);
///
/// // However some addresses have been assigned a special meaning
/// // that makes them not globally reachable. Some examples are:
///
/// // The unspecified address (`::`)
/// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false);
///
/// // The loopback address (`::1`)
/// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false);
///
/// // IPv4-mapped addresses (`::ffff:0:0/96`)
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false);
///
/// // Addresses reserved for benchmarking (`2001:2::/48`)
/// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false);
///
/// // Addresses reserved for documentation (`2001:db8::/32`)
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false);
///
/// // Unique local addresses (`fc00::/7`)
/// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
///
/// // Unicast addresses with link-local scope (`fe80::/10`)
/// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
///
/// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry.
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[unstable(feature = "ip", issue = "27709")]
#[must_use]
#[inline]
pub const fn is_global(&self) -> bool {
match self.multicast_scope() {
Some(Ipv6MulticastScope::Global) => true,
None => self.is_unicast_global(),
_ => false,
}
!(self.is_unspecified()
|| self.is_loopback()
// IPv4-mapped Address (`::ffff:0:0/96`)
|| matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
|| matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
// Discard-Only Address Block (`100::/64`)
|| matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
// IETF Protocol Assignments (`2001::/23`)
|| (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
&& !(
// Port Control Protocol Anycast (`2001:1::1`)
u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
|| u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
// AMT (`2001:3::/32`)
|| matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
// AS112-v6 (`2001:4:112::/48`)
|| matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
// ORCHIDv2 (`2001:20::/28`)
|| matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
))
|| self.is_documentation()
|| self.is_unique_local()
|| self.is_unicast_link_local())
}

/// Returns [`true`] if this is a unique local address (`fc00::/7`).
Expand Down Expand Up @@ -1525,6 +1586,7 @@ impl Ipv6Addr {
&& !self.is_unique_local()
&& !self.is_unspecified()
&& !self.is_documentation()
&& !self.is_benchmarking()
}

/// Returns the address's multicast scope if the address is multicast.
Expand Down
Loading

0 comments on commit c1a5ec7

Please sign in to comment.