Skip to content
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

Fix Ipv6Addr::is_unicast_global to check for unicast global scope #85696

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 72 additions & 41 deletions library/std/src/net/ip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1239,7 +1239,10 @@ impl Ipv6Addr {
pub const fn is_global(&self) -> bool {
match self.multicast_scope() {
Some(Ipv6MulticastScope::Global) => true,
None => self.is_unicast_global(),
None => {
self.has_unicast_global_scope()
&& !(self.is_unique_local() || self.is_documentation())
}
Comment on lines -1242 to +1245
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation of is_global is changed completely in #86634

_ => false,
}
}
Expand Down Expand Up @@ -1329,29 +1332,55 @@ impl Ipv6Addr {
/// use std::net::Ipv6Addr;
///
/// // The loopback address (`::1`) does not actually have link-local scope.
/// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
/// assert_eq!(Ipv6Addr::LOCALHOST.has_unicast_link_local_scope(), false);
///
/// // Only addresses in `fe80::/10` have link-local scope.
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
/// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).has_unicast_link_local_scope(), false);
/// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).has_unicast_link_local_scope(), true);
///
/// // Addresses outside the stricter `fe80::/64` also have link-local scope.
/// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
/// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
/// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).has_unicast_link_local_scope(), true);
/// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).has_unicast_link_local_scope(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_unicast_link_local(&self) -> bool {
pub const fn has_unicast_link_local_scope(&self) -> bool {
(self.segments()[0] & 0xffc0) == 0xfe80
}

/// Returns [`true`] if this is an address reserved for documentation
/// (`2001:db8::/32`).
/// Returns `true` if the address is a unicast address with global scope,
/// as defined in [RFC 4291].
///
/// This property is defined in [IETF RFC 3849].
/// Any unicast address has global scope if it is not:
/// - the [unspecified address] (`::`)
/// - the [loopback address] (`::1`)
/// - a [link-local address] (`fe80::/10`)
///
/// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
/// Note that an address that has global scope may still not be globally reachable.
/// If you want to check if an address appears to be globally reachable, use [`is_global`](Ipv6Addr::is_global).
///
/// # Deprecation of Site-Local Addresses
///
/// Site-local addresses have been officially deprecated, see [RFC 4291 section 2.5.7].
/// It is stated that the special behaviour of site-local unicast addresses must no longer be
/// supported, and that implementations must treat these addresses as having global scope.
///
/// This method therefore returns [`true`] for any address that had the deprecated site-local scope (`fec0::/10`).
///
/// # Stability Guarantees
///
/// Note that this method's behavior may be subject to changes in the future,
/// as new IETF RFCs are published. Specifically [RFC 4291 section 2.4] mentions:
///
/// > "Future specifications may redefine one or more sub-ranges of the Global Unicast space for other purposes"
///
/// [RFC 4291]: https://tools.ietf.org/html/rfc4291
/// [RFC 4291 section 2.4]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.4
/// [RFC 4291 section 2.5.7]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.7
/// [unspecified address]: Ipv6Addr::is_unspecified
/// [loopback address]: Ipv6Addr::is_loopback
/// [link-local address]: Ipv6Addr::has_unicast_link_local_scope
///
/// # Examples
///
Expand All @@ -1360,35 +1389,42 @@ impl Ipv6Addr {
///
/// use std::net::Ipv6Addr;
///
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false);
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
/// // The unspecified address (`::`) does not have unicast global scope
/// assert_eq!(Ipv6Addr::UNSPECIFIED.has_unicast_global_scope(), false);
///
/// // The loopback address (`::1`) does not have unicast global scope.
/// assert_eq!(Ipv6Addr::LOCALHOST.has_unicast_global_scope(), false);
///
/// // A unicast address with link-local scope (`fe80::/10`) does not have global scope.
/// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).has_unicast_global_scope(), false);
///
/// // A unicast address that had the deprecated site-local scope (`fec0::/10`) now has global scope.
/// assert_eq!(Ipv6Addr::new(0xfec2, 0, 0, 0, 0, 0, 0, 0).has_unicast_global_scope(), true);
///
/// // Any multicast address (`ff00::/8`) does not have unicast global scope;
/// // there is a difference between unicast global scope and multicast global scope.
/// assert_eq!(Ipv6Addr::new(0xff03, 0, 0, 0, 0, 0, 0, 0).has_unicast_global_scope(), false);
/// assert_eq!(Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).has_unicast_global_scope(), false);
///
/// // Any other address is defined as having unicast global scope.
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).has_unicast_global_scope(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_documentation(&self) -> bool {
(self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
pub const fn has_unicast_global_scope(&self) -> bool {
self.is_unicast()
&& !self.is_unspecified()
&& !self.is_loopback()
&& !self.has_unicast_link_local_scope()
}

/// 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]
/// Returns [`true`] if this is an address reserved for documentation
/// (`2001:db8::/32`).
///
/// ```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).
/// ```
/// This property is defined in [IETF RFC 3849].
///
/// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
/// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
///
/// # Examples
///
Expand All @@ -1397,19 +1433,14 @@ impl Ipv6Addr {
///
/// use std::net::Ipv6Addr;
///
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false);
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false);
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[unstable(feature = "ip", issue = "27709")]
#[inline]
pub const fn is_unicast_global(&self) -> bool {
self.is_unicast()
&& !self.is_loopback()
&& !self.is_unicast_link_local()
&& !self.is_unique_local()
&& !self.is_unspecified()
&& !self.is_documentation()
pub const fn is_documentation(&self) -> bool {
(self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
}

/// Returns the address's multicast scope if the address is multicast.
Expand Down
26 changes: 15 additions & 11 deletions library/std/src/net/ip/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,14 +518,14 @@ fn ipv6_properties() {
assert!(!ip!($s).is_global());
}
if ($mask & unicast_link_local) == unicast_link_local {
assert!(ip!($s).is_unicast_link_local());
assert!(ip!($s).has_unicast_link_local_scope());
} else {
assert!(!ip!($s).is_unicast_link_local());
assert!(!ip!($s).has_unicast_link_local_scope());
}
if ($mask & unicast_global) == unicast_global {
assert!(ip!($s).is_unicast_global());
assert!(ip!($s).has_unicast_global_scope());
} else {
assert!(!ip!($s).is_unicast_global());
assert!(!ip!($s).has_unicast_global_scope());
}
if ($mask & documentation) == documentation {
assert!(ip!($s).is_documentation());
Expand Down Expand Up @@ -593,12 +593,16 @@ fn ipv6_properties() {

check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);

check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
check!(
"fc00::",
&[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unique_local | unicast_global
);

check!(
"fdff:ffff::",
&[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
unique_local
unique_local | unicast_global
);

check!(
Expand Down Expand Up @@ -676,7 +680,7 @@ fn ipv6_properties() {
check!(
"2001:db8:85a3::8a2e:370:7334",
&[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
documentation
documentation | unicast_global
);

check!(
Expand Down Expand Up @@ -879,14 +883,14 @@ fn ipv6_const() {
const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
assert!(!IS_UNIQUE_LOCAL);

const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
assert!(!IS_UNICAST_LINK_LOCAL);
const HAS_UNICAST_LINK_LOCAL_SCOPE: bool = IP_ADDRESS.has_unicast_link_local_scope();
assert!(!HAS_UNICAST_LINK_LOCAL_SCOPE);

const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
assert!(!IS_DOCUMENTATION);

const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global();
assert!(!IS_UNICAST_GLOBAL);
const HAS_UNICAST_GLOBAL_SCOPE: bool = IP_ADDRESS.has_unicast_global_scope();
assert!(!HAS_UNICAST_GLOBAL_SCOPE);

const MULTICAST_SCOPE: Option<Ipv6MulticastScope> = IP_ADDRESS.multicast_scope();
assert_eq!(MULTICAST_SCOPE, None);
Expand Down