Skip to content

Commit 90f8e7a

Browse files
committed
Fix Ipv6Addr::is_global to check for global reachability rather than global scope
1 parent d2b04f0 commit 90f8e7a

File tree

2 files changed

+168
-27
lines changed

2 files changed

+168
-27
lines changed

library/std/src/net/ip.rs

+80-15
Original file line numberDiff line numberDiff line change
@@ -1214,13 +1214,33 @@ impl Ipv6Addr {
12141214
u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
12151215
}
12161216

1217-
/// Returns [`true`] if the address appears to be globally routable.
1218-
///
1219-
/// The following return [`false`]:
1220-
///
1221-
/// - the loopback address
1222-
/// - link-local and unique local unicast addresses
1223-
/// - interface-, link-, realm-, admin- and site-local multicast addresses
1217+
/// Returns [`true`] if the address appears to be globally reachable
1218+
/// as specified by the [IANA IPv6 Special-Purpose Address Registry].
1219+
/// Whether or not an address is practically reachable will depend on your network configuration.
1220+
///
1221+
/// Most IPv6 addresses are globally reachable;
1222+
/// unless they are specifically defined as *not* globally reachable.
1223+
///
1224+
/// Non-exhaustive list of notable addresses that are not globally reachable:
1225+
/// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified))
1226+
/// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback))
1227+
/// - IPv4-mapped addresses
1228+
/// - Addresses reserved for benchmarking
1229+
/// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation))
1230+
/// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local))
1231+
/// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local))
1232+
///
1233+
/// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry].
1234+
///
1235+
/// Note that an address having global scope is not the same as being globally reachable,
1236+
/// and there is no direct relation between the two concepts: There exist addresses with global scope
1237+
/// that are not globally reachable (for example unique local addresses),
1238+
/// and addresses that are globally reachable without having global scope
1239+
/// (multicast addresses with non-global scope).
1240+
///
1241+
/// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
1242+
/// [unspecified address]: Ipv6Addr::UNSPECIFIED
1243+
/// [loopback address]: Ipv6Addr::LOCALHOST
12241244
///
12251245
/// # Examples
12261246
///
@@ -1229,19 +1249,64 @@ impl Ipv6Addr {
12291249
///
12301250
/// use std::net::Ipv6Addr;
12311251
///
1232-
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true);
1233-
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false);
1234-
/// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
1252+
/// // Most IPv6 addresses are globally reachable:
1253+
/// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true);
1254+
///
1255+
/// // However some addresses have been assigned a special meaning
1256+
/// // that makes them not globally reachable. Some examples are:
1257+
///
1258+
/// // The unspecified address (`::`)
1259+
/// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false);
1260+
///
1261+
/// // The loopback address (`::1`)
1262+
/// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false);
1263+
///
1264+
/// // IPv4-mapped addresses (`::ffff:0:0/96`)
1265+
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false);
1266+
///
1267+
/// // Addresses reserved for benchmarking (`2001:2::/48`)
1268+
/// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false);
1269+
///
1270+
/// // Addresses reserved for documentation (`2001:db8::/32`)
1271+
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false);
1272+
///
1273+
/// // Unique local addresses (`fc00::/7`)
1274+
/// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
1275+
///
1276+
/// // Unicast addresses with link-local scope (`fe80::/10`)
1277+
/// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
1278+
///
1279+
/// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry.
12351280
/// ```
12361281
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
12371282
#[unstable(feature = "ip", issue = "27709")]
12381283
#[inline]
12391284
pub const fn is_global(&self) -> bool {
1240-
match self.multicast_scope() {
1241-
Some(Ipv6MulticastScope::Global) => true,
1242-
None => self.is_unicast_global(),
1243-
_ => false,
1244-
}
1285+
!(self.is_unspecified()
1286+
|| self.is_loopback()
1287+
// IPv4-mapped Address (`::ffff:0:0/96`)
1288+
|| matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
1289+
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
1290+
|| matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
1291+
// Discard-Only Address Block (`100::/64`)
1292+
|| matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
1293+
// IETF Protocol Assignments (`2001::/23`)
1294+
|| (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
1295+
&& !(
1296+
// Port Control Protocol Anycast (`2001:1::1`)
1297+
u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
1298+
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
1299+
|| u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
1300+
// AMT (`2001:3::/32`)
1301+
|| matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
1302+
// AS112-v6 (`2001:4:112::/48`)
1303+
|| matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
1304+
// ORCHIDv2 (`2001:20::/28`)
1305+
|| matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
1306+
))
1307+
|| self.is_documentation()
1308+
|| self.is_unique_local()
1309+
|| self.is_unicast_link_local())
12451310
}
12461311

12471312
/// Returns [`true`] if this is a unique local address (`fc00::/7`).

library/std/src/net/ip/tests.rs

+88-12
Original file line numberDiff line numberDiff line change
@@ -305,12 +305,12 @@ fn ip_properties() {
305305
check!("fe80:ffff::");
306306
check!("febf:ffff::");
307307
check!("fec0::", global);
308-
check!("ff01::", multicast);
309-
check!("ff02::", multicast);
310-
check!("ff03::", multicast);
311-
check!("ff04::", multicast);
312-
check!("ff05::", multicast);
313-
check!("ff08::", multicast);
308+
check!("ff01::", global | multicast);
309+
check!("ff02::", global | multicast);
310+
check!("ff03::", global | multicast);
311+
check!("ff04::", global | multicast);
312+
check!("ff05::", global | multicast);
313+
check!("ff08::", global | multicast);
314314
check!("ff0e::", global | multicast);
315315
check!("2001:db8:85a3::8a2e:370:7334", doc);
316316
check!("102:304:506:708:90a:b0c:d0e:f10", global);
@@ -593,6 +593,60 @@ fn ipv6_properties() {
593593

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

596+
check!(
597+
"::ffff:127.0.0.1",
598+
&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1],
599+
unicast_global
600+
);
601+
602+
check!(
603+
"64:ff9b:1::",
604+
&[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
605+
unicast_global
606+
);
607+
608+
check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
609+
610+
check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
611+
612+
check!(
613+
"2001:1::1",
614+
&[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
615+
global | unicast_global
616+
);
617+
618+
check!(
619+
"2001:1::2",
620+
&[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
621+
global | unicast_global
622+
);
623+
624+
check!(
625+
"2001:3::",
626+
&[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
627+
global | unicast_global
628+
);
629+
630+
check!(
631+
"2001:4:112::",
632+
&[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
633+
global | unicast_global
634+
);
635+
636+
check!(
637+
"2001:20::",
638+
&[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
639+
global | unicast_global
640+
);
641+
642+
check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
643+
644+
check!(
645+
"2001:200::",
646+
&[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
647+
global | unicast_global
648+
);
649+
596650
check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
597651

598652
check!(
@@ -650,21 +704,37 @@ fn ipv6_properties() {
650704
check!(
651705
"ff01::",
652706
&[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
653-
multicast_interface_local
707+
multicast_interface_local | global
654708
);
655709

656-
check!("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_link_local);
710+
check!(
711+
"ff02::",
712+
&[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
713+
multicast_link_local | global
714+
);
657715

658-
check!("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_realm_local);
716+
check!(
717+
"ff03::",
718+
&[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
719+
multicast_realm_local | global
720+
);
659721

660-
check!("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_admin_local);
722+
check!(
723+
"ff04::",
724+
&[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
725+
multicast_admin_local | global
726+
);
661727

662-
check!("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_site_local);
728+
check!(
729+
"ff05::",
730+
&[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
731+
multicast_site_local | global
732+
);
663733

664734
check!(
665735
"ff08::",
666736
&[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
667-
multicast_organization_local
737+
multicast_organization_local | global
668738
);
669739

670740
check!(
@@ -673,6 +743,12 @@ fn ipv6_properties() {
673743
multicast_global | global
674744
);
675745

746+
check!(
747+
"2001:2::ac32:23ff:21",
748+
&[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21],
749+
unicast_global
750+
);
751+
676752
check!(
677753
"2001:db8:85a3::8a2e:370:7334",
678754
&[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],

0 commit comments

Comments
 (0)