Skip to content

Commit f7d8805

Browse files
CDirkxchotchki
authored andcommitted
Fix Ipv6Addr::is_global to check for global reachability rather than global scope
1 parent 110777b commit f7d8805

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
@@ -1349,13 +1349,33 @@ impl Ipv6Addr {
13491349
u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
13501350
}
13511351

1352-
/// Returns [`true`] if the address appears to be globally routable.
1353-
///
1354-
/// The following return [`false`]:
1355-
///
1356-
/// - the loopback address
1357-
/// - link-local and unique local unicast addresses
1358-
/// - interface-, link-, realm-, admin- and site-local multicast addresses
1352+
/// Returns [`true`] if the address appears to be globally reachable
1353+
/// as specified by the [IANA IPv6 Special-Purpose Address Registry].
1354+
/// Whether or not an address is practically reachable will depend on your network configuration.
1355+
///
1356+
/// Most IPv6 addresses are globally reachable;
1357+
/// unless they are specifically defined as *not* globally reachable.
1358+
///
1359+
/// Non-exhaustive list of notable addresses that are not globally reachable:
1360+
/// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified))
1361+
/// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback))
1362+
/// - IPv4-mapped addresses
1363+
/// - Addresses reserved for benchmarking
1364+
/// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation))
1365+
/// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local))
1366+
/// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local))
1367+
///
1368+
/// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry].
1369+
///
1370+
/// Note that an address having global scope is not the same as being globally reachable,
1371+
/// and there is no direct relation between the two concepts: There exist addresses with global scope
1372+
/// that are not globally reachable (for example unique local addresses),
1373+
/// and addresses that are globally reachable without having global scope
1374+
/// (multicast addresses with non-global scope).
1375+
///
1376+
/// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
1377+
/// [unspecified address]: Ipv6Addr::UNSPECIFIED
1378+
/// [loopback address]: Ipv6Addr::LOCALHOST
13591379
///
13601380
/// # Examples
13611381
///
@@ -1364,20 +1384,65 @@ impl Ipv6Addr {
13641384
///
13651385
/// use std::net::Ipv6Addr;
13661386
///
1367-
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true);
1368-
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false);
1369-
/// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
1387+
/// // Most IPv6 addresses are globally reachable:
1388+
/// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true);
1389+
///
1390+
/// // However some addresses have been assigned a special meaning
1391+
/// // that makes them not globally reachable. Some examples are:
1392+
///
1393+
/// // The unspecified address (`::`)
1394+
/// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false);
1395+
///
1396+
/// // The loopback address (`::1`)
1397+
/// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false);
1398+
///
1399+
/// // IPv4-mapped addresses (`::ffff:0:0/96`)
1400+
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false);
1401+
///
1402+
/// // Addresses reserved for benchmarking (`2001:2::/48`)
1403+
/// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false);
1404+
///
1405+
/// // Addresses reserved for documentation (`2001:db8::/32`)
1406+
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false);
1407+
///
1408+
/// // Unique local addresses (`fc00::/7`)
1409+
/// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
1410+
///
1411+
/// // Unicast addresses with link-local scope (`fe80::/10`)
1412+
/// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
1413+
///
1414+
/// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry.
13701415
/// ```
13711416
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
13721417
#[unstable(feature = "ip", issue = "27709")]
13731418
#[must_use]
13741419
#[inline]
13751420
pub const fn is_global(&self) -> bool {
1376-
match self.multicast_scope() {
1377-
Some(Ipv6MulticastScope::Global) => true,
1378-
None => self.is_unicast_global(),
1379-
_ => false,
1380-
}
1421+
!(self.is_unspecified()
1422+
|| self.is_loopback()
1423+
// IPv4-mapped Address (`::ffff:0:0/96`)
1424+
|| matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
1425+
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
1426+
|| matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
1427+
// Discard-Only Address Block (`100::/64`)
1428+
|| matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
1429+
// IETF Protocol Assignments (`2001::/23`)
1430+
|| (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
1431+
&& !(
1432+
// Port Control Protocol Anycast (`2001:1::1`)
1433+
u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
1434+
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
1435+
|| u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
1436+
// AMT (`2001:3::/32`)
1437+
|| matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
1438+
// AS112-v6 (`2001:4:112::/48`)
1439+
|| matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
1440+
// ORCHIDv2 (`2001:20::/28`)
1441+
|| matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
1442+
))
1443+
|| self.is_documentation()
1444+
|| self.is_unique_local()
1445+
|| self.is_unicast_link_local())
13811446
}
13821447

13831448
/// 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
@@ -321,12 +321,12 @@ fn ip_properties() {
321321
check!("fe80:ffff::");
322322
check!("febf:ffff::");
323323
check!("fec0::", global);
324-
check!("ff01::", multicast);
325-
check!("ff02::", multicast);
326-
check!("ff03::", multicast);
327-
check!("ff04::", multicast);
328-
check!("ff05::", multicast);
329-
check!("ff08::", multicast);
324+
check!("ff01::", global | multicast);
325+
check!("ff02::", global | multicast);
326+
check!("ff03::", global | multicast);
327+
check!("ff04::", global | multicast);
328+
check!("ff05::", global | multicast);
329+
check!("ff08::", global | multicast);
330330
check!("ff0e::", global | multicast);
331331
check!("2001:db8:85a3::8a2e:370:7334", doc);
332332
check!("2001:2::ac32:23ff:21", global | benchmarking);
@@ -609,6 +609,60 @@ fn ipv6_properties() {
609609

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

612+
check!(
613+
"::ffff:127.0.0.1",
614+
&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1],
615+
unicast_global
616+
);
617+
618+
check!(
619+
"64:ff9b:1::",
620+
&[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
621+
unicast_global
622+
);
623+
624+
check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
625+
626+
check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
627+
628+
check!(
629+
"2001:1::1",
630+
&[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
631+
global | unicast_global
632+
);
633+
634+
check!(
635+
"2001:1::2",
636+
&[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
637+
global | unicast_global
638+
);
639+
640+
check!(
641+
"2001:3::",
642+
&[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
643+
global | unicast_global
644+
);
645+
646+
check!(
647+
"2001:4:112::",
648+
&[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
649+
global | unicast_global
650+
);
651+
652+
check!(
653+
"2001:20::",
654+
&[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
655+
global | unicast_global
656+
);
657+
658+
check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
659+
660+
check!(
661+
"2001:200::",
662+
&[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
663+
global | unicast_global
664+
);
665+
612666
check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
613667

614668
check!(
@@ -666,21 +720,37 @@ fn ipv6_properties() {
666720
check!(
667721
"ff01::",
668722
&[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
669-
multicast_interface_local
723+
multicast_interface_local | global
670724
);
671725

672-
check!("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_link_local);
726+
check!(
727+
"ff02::",
728+
&[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
729+
multicast_link_local | global
730+
);
673731

674-
check!("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_realm_local);
732+
check!(
733+
"ff03::",
734+
&[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
735+
multicast_realm_local | global
736+
);
675737

676-
check!("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_admin_local);
738+
check!(
739+
"ff04::",
740+
&[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
741+
multicast_admin_local | global
742+
);
677743

678-
check!("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_site_local);
744+
check!(
745+
"ff05::",
746+
&[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
747+
multicast_site_local | global
748+
);
679749

680750
check!(
681751
"ff08::",
682752
&[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
683-
multicast_organization_local
753+
multicast_organization_local | global
684754
);
685755

686756
check!(
@@ -689,6 +759,12 @@ fn ipv6_properties() {
689759
multicast_global | global
690760
);
691761

762+
check!(
763+
"2001:2::ac32:23ff:21",
764+
&[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21],
765+
unicast_global
766+
);
767+
692768
check!(
693769
"2001:db8:85a3::8a2e:370:7334",
694770
&[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],

0 commit comments

Comments
 (0)