diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index baf1c5aa2b941..d8e1b952fc346 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -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()) + } _ => false, } } @@ -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 /// @@ -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 /// @@ -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. diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index 2109980ad058d..645ea62f62453 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -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()); @@ -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!( @@ -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!( @@ -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 = IP_ADDRESS.multicast_scope(); assert_eq!(MULTICAST_SCOPE, None);