-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rework Ipv6Addr::is_global
to check for global reachability rather than global scope
#86634
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -474,26 +474,30 @@ impl Ipv4Addr { | |
matches!(self.octets(), [169, 254, ..]) | ||
} | ||
|
||
/// Returns [`true`] if the address appears to be globally routable. | ||
/// See [iana-ipv4-special-registry][ipv4-sr]. | ||
/// | ||
/// The following return [`false`]: | ||
/// | ||
/// - 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 (see | ||
/// [`Ipv4Addr::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 [`Ipv4Addr::is_reserved()`] | ||
/// - addresses reserved for networking devices benchmarking (see | ||
/// [`Ipv4Addr::is_benchmarking()`]) | ||
/// | ||
/// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml | ||
/// 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. | ||
/// | ||
/// Non-exhaustive list of notable addresses that are not globally reachable: | ||
/// | ||
/// - 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)) | ||
/// | ||
/// 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 | ||
/// | ||
|
@@ -502,69 +506,65 @@ 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")] | ||
#[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.is_ietf_protocol_assignment() | ||
&& !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] == 0 // "This network" | ||
|| self.is_private() | ||
|| self.is_shared() | ||
|| self.is_loopback() | ||
|| self.is_link_local() | ||
|| (self.is_ietf_protocol_assignment() | ||
&& !( | ||
// Port Control Protocol Anycast (`192.0.0.9`) | ||
u32::from_be_bytes(self.octets()) == 0xc0000009 | ||
// Traversal Using Relays around NAT Anycast (`192.0.0.10`) | ||
|| u32::from_be_bytes(self.octets()) == 0xc000000a | ||
)) | ||
|| self.is_documentation() | ||
|| self.is_benchmarking() | ||
|| self.is_reserved() | ||
|| self.is_broadcast()) | ||
Comment on lines
-550
to
+567
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reordered the checks to match the order in the Special Address Registry. |
||
} | ||
|
||
/// Returns [`true`] if this address is part of the Shared Address Space defined in | ||
|
@@ -1214,13 +1214,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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "globally reachable" instead of "globally routable", as that is the terminology used in the Special Address Registry. |
||
/// as specified by the [IANA IPv6 Special-Purpose Address Registry]. | ||
/// Whether or not an address is practically reachable will depend on your network configuration. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you're not connected to the internet, you still can't reach a "globally reachable" address. I hope this also makes it clear that this method doesn't actually do any network traffic. |
||
/// | ||
/// 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). | ||
Comment on lines
+1235
to
+1239
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trying to avoid the confusion between "globally reachable" and "global scope", the rename in #85696 from |
||
/// | ||
/// [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 | ||
/// | ||
|
@@ -1229,19 +1249,64 @@ 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")] | ||
#[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, _, _]) | ||
Mark-Simulacrum marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// 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`). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reworded to a (in my opinion) less cluttered non-exhaustive list. Instead of trying to list every type of address and exceptions, we list the most notable ones (mostly the ones Rust has methods for) and refer to the Special Address Registry for the complete overview. A similar thing is done in the description of
Ipv6Addr::is_global
.