Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c1a5ec7

Browse files
authoredAug 22, 2022
Rollup merge of #99957 - chotchki:ip-globally-reachable_rebase, r=Mark-Simulacrum
Rework Ipv6Addr::is_global to check for global reachability rather than global scope - rebase Rebasing of pull request #86634 off of master to try and get the feature "ip" stabilized. I also found a test failure in the rebase that is_global was considering the benchmark space to be globally reachable. This is related to my other rebasing pull request #99947
2 parents e77c208 + f659088 commit c1a5ec7

File tree

2 files changed

+217
-85
lines changed

2 files changed

+217
-85
lines changed
 

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

Lines changed: 133 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -620,25 +620,31 @@ impl Ipv4Addr {
620620
matches!(self.octets(), [169, 254, ..])
621621
}
622622

623-
/// Returns [`true`] if the address appears to be globally routable.
624-
/// See [iana-ipv4-special-registry][ipv4-sr].
623+
/// Returns [`true`] if the address appears to be globally reachable
624+
/// as specified by the [IANA IPv4 Special-Purpose Address Registry].
625+
/// Whether or not an address is practically reachable will depend on your network configuration.
626+
///
627+
/// Most IPv4 addresses are globally reachable;
628+
/// unless they are specifically defined as *not* globally reachable.
625629
///
626-
/// The following return [`false`]:
630+
/// Non-exhaustive list of notable addresses that are not globally reachable:
627631
///
628-
/// - private addresses (see [`Ipv4Addr::is_private()`])
629-
/// - the loopback address (see [`Ipv4Addr::is_loopback()`])
630-
/// - the link-local address (see [`Ipv4Addr::is_link_local()`])
631-
/// - the broadcast address (see [`Ipv4Addr::is_broadcast()`])
632-
/// - addresses used for documentation (see [`Ipv4Addr::is_documentation()`])
633-
/// - the unspecified address (see [`Ipv4Addr::is_unspecified()`]), and the whole
634-
/// `0.0.0.0/8` block
635-
/// - addresses reserved for future protocols, except
636-
/// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable
637-
/// - addresses reserved for future use (see [`Ipv4Addr::is_reserved()`]
638-
/// - addresses reserved for networking devices benchmarking (see
639-
/// [`Ipv4Addr::is_benchmarking()`])
632+
/// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified))
633+
/// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private))
634+
/// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared))
635+
/// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback))
636+
/// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local))
637+
/// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation))
638+
/// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking))
639+
/// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved))
640+
/// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast))
640641
///
641-
/// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
642+
/// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry].
643+
///
644+
/// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
645+
/// [unspecified address]: Ipv4Addr::UNSPECIFIED
646+
/// [broadcast address]: Ipv4Addr::BROADCAST
647+
642648
///
643649
/// # Examples
644650
///
@@ -647,71 +653,61 @@ impl Ipv4Addr {
647653
///
648654
/// use std::net::Ipv4Addr;
649655
///
650-
/// // private addresses are not global
656+
/// // Most IPv4 addresses are globally reachable:
657+
/// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
658+
///
659+
/// // However some addresses have been assigned a special meaning
660+
/// // that makes them not globally reachable. Some examples are:
661+
///
662+
/// // The unspecified address (`0.0.0.0`)
663+
/// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false);
664+
///
665+
/// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16)
651666
/// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
652667
/// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
653668
/// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
654669
///
655-
/// // the 0.0.0.0/8 block is not global
656-
/// assert_eq!(Ipv4Addr::new(0, 1, 2, 3).is_global(), false);
657-
/// // in particular, the unspecified address is not global
658-
/// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_global(), false);
670+
/// // Addresses in the shared address space (`100.64.0.0/10`)
671+
/// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
659672
///
660-
/// // the loopback address is not global
661-
/// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_global(), false);
673+
/// // The loopback addresses (`127.0.0.0/8`)
674+
/// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false);
662675
///
663-
/// // link local addresses are not global
676+
/// // Link-local addresses (`169.254.0.0/16`)
664677
/// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false);
665678
///
666-
/// // the broadcast address is not global
667-
/// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_global(), false);
668-
///
669-
/// // the address space designated for documentation is not global
679+
/// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`)
670680
/// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false);
671681
/// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false);
672682
/// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false);
673683
///
674-
/// // shared addresses are not global
675-
/// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
676-
///
677-
/// // addresses reserved for protocol assignment are not global
678-
/// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_global(), false);
679-
/// assert_eq!(Ipv4Addr::new(192, 0, 0, 255).is_global(), false);
684+
/// // Addresses reserved for benchmarking (`198.18.0.0/15`)
685+
/// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
680686
///
681-
/// // addresses reserved for future use are not global
687+
/// // Reserved addresses (`240.0.0.0/4`)
682688
/// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
683689
///
684-
/// // addresses reserved for network devices benchmarking are not global
685-
/// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
690+
/// // The broadcast address (`255.255.255.255`)
691+
/// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false);
686692
///
687-
/// // All the other addresses are global
688-
/// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true);
689-
/// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
693+
/// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry.
690694
/// ```
691695
#[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
692696
#[unstable(feature = "ip", issue = "27709")]
693697
#[must_use]
694698
#[inline]
695699
pub const fn is_global(&self) -> bool {
696-
// check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
697-
// globally routable addresses in the 192.0.0.0/24 range.
698-
if u32::from_be_bytes(self.octets()) == 0xc0000009
699-
|| u32::from_be_bytes(self.octets()) == 0xc000000a
700-
{
701-
return true;
702-
}
703-
!self.is_private()
704-
&& !self.is_loopback()
705-
&& !self.is_link_local()
706-
&& !self.is_broadcast()
707-
&& !self.is_documentation()
708-
&& !self.is_shared()
700+
!(self.octets()[0] == 0 // "This network"
701+
|| self.is_private()
702+
|| self.is_shared()
703+
|| self.is_loopback()
704+
|| self.is_link_local()
709705
// addresses reserved for future protocols (`192.0.0.0/24`)
710-
&& !(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
711-
&& !self.is_reserved()
712-
&& !self.is_benchmarking()
713-
// Make sure the address is not in 0.0.0.0/8
714-
&& self.octets()[0] != 0
706+
||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
707+
|| self.is_documentation()
708+
|| self.is_benchmarking()
709+
|| self.is_reserved()
710+
|| self.is_broadcast())
715711
}
716712

717713
/// Returns [`true`] if this address is part of the Shared Address Space defined in
@@ -1300,13 +1296,33 @@ impl Ipv6Addr {
13001296
u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
13011297
}
13021298

1303-
/// Returns [`true`] if the address appears to be globally routable.
1299+
/// Returns [`true`] if the address appears to be globally reachable
1300+
/// as specified by the [IANA IPv6 Special-Purpose Address Registry].
1301+
/// Whether or not an address is practically reachable will depend on your network configuration.
13041302
///
1305-
/// The following return [`false`]:
1303+
/// Most IPv6 addresses are globally reachable;
1304+
/// unless they are specifically defined as *not* globally reachable.
13061305
///
1307-
/// - the loopback address
1308-
/// - link-local and unique local unicast addresses
1309-
/// - interface-, link-, realm-, admin- and site-local multicast addresses
1306+
/// Non-exhaustive list of notable addresses that are not globally reachable:
1307+
/// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified))
1308+
/// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback))
1309+
/// - IPv4-mapped addresses
1310+
/// - Addresses reserved for benchmarking
1311+
/// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation))
1312+
/// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local))
1313+
/// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local))
1314+
///
1315+
/// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry].
1316+
///
1317+
/// Note that an address having global scope is not the same as being globally reachable,
1318+
/// and there is no direct relation between the two concepts: There exist addresses with global scope
1319+
/// that are not globally reachable (for example unique local addresses),
1320+
/// and addresses that are globally reachable without having global scope
1321+
/// (multicast addresses with non-global scope).
1322+
///
1323+
/// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
1324+
/// [unspecified address]: Ipv6Addr::UNSPECIFIED
1325+
/// [loopback address]: Ipv6Addr::LOCALHOST
13101326
///
13111327
/// # Examples
13121328
///
@@ -1315,20 +1331,65 @@ impl Ipv6Addr {
13151331
///
13161332
/// use std::net::Ipv6Addr;
13171333
///
1318-
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), true);
1319-
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false);
1320-
/// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
1334+
/// // Most IPv6 addresses are globally reachable:
1335+
/// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true);
1336+
///
1337+
/// // However some addresses have been assigned a special meaning
1338+
/// // that makes them not globally reachable. Some examples are:
1339+
///
1340+
/// // The unspecified address (`::`)
1341+
/// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false);
1342+
///
1343+
/// // The loopback address (`::1`)
1344+
/// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false);
1345+
///
1346+
/// // IPv4-mapped addresses (`::ffff:0:0/96`)
1347+
/// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false);
1348+
///
1349+
/// // Addresses reserved for benchmarking (`2001:2::/48`)
1350+
/// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false);
1351+
///
1352+
/// // Addresses reserved for documentation (`2001:db8::/32`)
1353+
/// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false);
1354+
///
1355+
/// // Unique local addresses (`fc00::/7`)
1356+
/// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
1357+
///
1358+
/// // Unicast addresses with link-local scope (`fe80::/10`)
1359+
/// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
1360+
///
1361+
/// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry.
13211362
/// ```
13221363
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
13231364
#[unstable(feature = "ip", issue = "27709")]
13241365
#[must_use]
13251366
#[inline]
13261367
pub const fn is_global(&self) -> bool {
1327-
match self.multicast_scope() {
1328-
Some(Ipv6MulticastScope::Global) => true,
1329-
None => self.is_unicast_global(),
1330-
_ => false,
1331-
}
1368+
!(self.is_unspecified()
1369+
|| self.is_loopback()
1370+
// IPv4-mapped Address (`::ffff:0:0/96`)
1371+
|| matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
1372+
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
1373+
|| matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
1374+
// Discard-Only Address Block (`100::/64`)
1375+
|| matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
1376+
// IETF Protocol Assignments (`2001::/23`)
1377+
|| (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
1378+
&& !(
1379+
// Port Control Protocol Anycast (`2001:1::1`)
1380+
u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
1381+
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
1382+
|| u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
1383+
// AMT (`2001:3::/32`)
1384+
|| matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
1385+
// AS112-v6 (`2001:4:112::/48`)
1386+
|| matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
1387+
// ORCHIDv2 (`2001:20::/28`)
1388+
|| matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
1389+
))
1390+
|| self.is_documentation()
1391+
|| self.is_unique_local()
1392+
|| self.is_unicast_link_local())
13321393
}
13331394

13341395
/// Returns [`true`] if this is a unique local address (`fc00::/7`).
@@ -1525,6 +1586,7 @@ impl Ipv6Addr {
15251586
&& !self.is_unique_local()
15261587
&& !self.is_unspecified()
15271588
&& !self.is_documentation()
1589+
&& !self.is_benchmarking()
15281590
}
15291591

15301592
/// Returns the address's multicast scope if the address is multicast.

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

Lines changed: 84 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -321,15 +321,15 @@ 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);
332-
check!("2001:2::ac32:23ff:21", global | benchmarking);
332+
check!("2001:2::ac32:23ff:21", benchmarking);
333333
check!("102:304:506:708:90a:b0c:d0e:f10", global);
334334
}
335335

@@ -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!(
@@ -698,7 +768,7 @@ fn ipv6_properties() {
698768
check!(
699769
"2001:2::ac32:23ff:21",
700770
&[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21],
701-
global | unicast_global | benchmarking
771+
benchmarking
702772
);
703773

704774
check!(

0 commit comments

Comments
 (0)
Please sign in to comment.