From 5da355e91c9452077d460b2788f87884c14c3d3b Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Mon, 25 Jun 2018 18:21:27 -0700 Subject: [PATCH 1/6] fix Ipv6Addr::is_unicast_link_local() --- src/libstd/net/ip.rs | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index fcec8d06853f6..31787126a4fb0 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -1027,11 +1027,23 @@ impl Ipv6Addr { (self.segments()[0] & 0xfe00) == 0xfc00 } - /// Returns [`true`] if the address is unicast and link-local (fe80::/10). + /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). /// - /// This property is defined in [IETF RFC 4291]. + /// A common mis-conception is to think that unicast link-local addresses start with + /// `fe80::`, but the [IETF RFC 4291] actually defines a stricter format for these addresses: /// - /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// ```no_rust + /// | 10 | + /// | bits | 54 bits | 64 bits | + /// +----------+-------------------------+----------------------------+ + /// |1111111010| 0 | interface ID | + /// +----------+-------------------------+----------------------------+ + /// ``` + /// + /// This method validates the format defined in the RFC and won't recognize the following + /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example. + /// + /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291#section-2.5.6 /// [`true`]: ../../std/primitive.bool.html /// /// # Examples @@ -1042,13 +1054,19 @@ impl Ipv6Addr { /// use std::net::Ipv6Addr; /// /// fn main() { - /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_link_local(), - /// false); - /// assert_eq!(Ipv6Addr::new(0xfe8a, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); + /// assert!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local()); + /// assert!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff).is_unicast_link_local()); + /// // fe80::0:0:1:: is not a valid unicast link-local address + /// assert!(!Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local()); + /// // neither is fe81:: + /// assert!(!Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local()); /// } /// ``` pub fn is_unicast_link_local(&self) -> bool { - (self.segments()[0] & 0xffc0) == 0xfe80 + (self.segments()[0] & 0xffff) == 0xfe80 + && (self.segments()[1] & 0xffff) == 0 + && (self.segments()[2] & 0xffff) == 0 + && (self.segments()[3] & 0xffff) == 0 } /// Returns [`true`] if this is a deprecated unicast site-local address From 12d456c03a593c5885da74be532d6a4317bf56f0 Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Tue, 26 Jun 2018 16:07:45 -0700 Subject: [PATCH 2/6] std::net: add Ipv4Addr::is_shared() --- src/libstd/net/ip.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 31787126a4fb0..babdd5ef55b86 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -534,6 +534,28 @@ impl Ipv4Addr { !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() } + /// Returns [`true`] if this address is part of the Shared Address Space defined in + /// [IETF RFC 6598] (`100.64.0.0/10`). + /// + /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// fn main() { + /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); + /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); + /// } + /// ``` + pub fn is_shared(&self) -> bool { + self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) + } + + /// Returns [`true`] if this is a multicast address (224.0.0.0/4). /// /// Multicast addresses have a most significant octet between 224 and 239, From accb394e2ddebd06a86741d9ef1bbf3dc87de314 Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Tue, 26 Jun 2018 16:10:21 -0700 Subject: [PATCH 3/6] std::net: add Ipv4Addr::is_ietf_protocol_assignment() --- src/libstd/net/ip.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index babdd5ef55b86..1c2a6049812ac 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -555,6 +555,35 @@ impl Ipv4Addr { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) } + /// Returns [`true`] if this address is part of `192.0.0.0/24`, which is reserved to + /// IANA for IETF protocol assignments, as documented in [IETF RFC 6890]. + /// + /// Note that parts of this block are in use: + /// + /// - `192.0.0.8/32` is the "IPv4 dummy address" (see [IETF RFC 7600]) + /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723]) + /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155]) + /// + /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890 + /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600 + /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723 + /// [IETF RFC 8155]: https://tools.ietf.org/html/rfc8155 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// fn main() { + /// assert_eq!(Ipv4Addr::new(192, 0, 0, 0).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(192, 255, 255, 255).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(193, 0, 0, 0).is_ietf_protocol_assignment(), false); + /// } + /// ``` + pub fn is_ietf_protocol_assignment(&self) -> bool { + self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 + } /// Returns [`true`] if this is a multicast address (224.0.0.0/4). /// From 65d71e2f3afb7dcd34df3f72c302a174599b8bc0 Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Tue, 26 Jun 2018 16:10:57 -0700 Subject: [PATCH 4/6] std::net: add Ipv4Addr::is_benchmarking() --- src/libstd/net/ip.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 1c2a6049812ac..eda588e36c1ef 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -585,6 +585,30 @@ impl Ipv4Addr { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 } + /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for + /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` + /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. + /// + /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 + /// [errate 423]: https://www.rfc-editor.org/errata/eid423 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// fn main() { + /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false); + /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); + /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); + /// } + /// ``` + pub fn is_benchmarking(&self) -> bool { + self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 + } + /// Returns [`true`] if this is a multicast address (224.0.0.0/4). /// /// Multicast addresses have a most significant octet between 224 and 239, From e0e9e3fcc18f861cd6d4a45cdb873e6a660ec220 Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Tue, 26 Jun 2018 16:11:35 -0700 Subject: [PATCH 5/6] std::net: add Ipv4Addr::is_reserved() --- src/libstd/net/ip.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index eda588e36c1ef..cd336991efcec 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -609,6 +609,30 @@ impl Ipv4Addr { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 } + /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112] + /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the + /// broadcast address `255.255.255.255`, but this implementation explicitely excludes it, since + /// it is obviously not reserved for future use. + /// + /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 + /// [`true`]: ../../std/primitive.bool.html + /// + /// # Examples + /// + /// ``` + /// use std::net::Ipv4Addr; + /// + /// fn main() { + /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_ietf_protocol_assignment(), true); + /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_ietf_protocol_assignment(), false); + /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_ietf_protocol_assignment(), false); + /// } + /// ``` + pub fn is_reserved(&self) -> bool { + self.octets()[0] & 240 == 240 && !self.is_broadcast() + } + /// Returns [`true`] if this is a multicast address (224.0.0.0/4). /// /// Multicast addresses have a most significant octet between 224 and 239, From 7254fb323633c2399ad757e04970a04e810c2ec7 Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Tue, 26 Jun 2018 16:12:09 -0700 Subject: [PATCH 6/6] std::net: fix Ipv4Addr::is_global() --- src/libstd/net/ip.rs | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index cd336991efcec..64cd8f12fe4d1 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -504,12 +504,18 @@ impl Ipv4Addr { /// /// The following return false: /// - /// - private address (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16) - /// - the loopback address (127.0.0.0/8) - /// - the link-local address (169.254.0.0/16) - /// - the broadcast address (255.255.255.255/32) - /// - test addresses used for documentation (192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24) - /// - the unspecified address (0.0.0.0) + /// - private addresses (see [`is_private()`](#method.is_private)) + /// - the loopback address (see [`is_loopback()`](#method.is_loopback)) + /// - the link-local address (see [`is_link_local()`](#method.is_link_local)) + /// - the broadcast address (see [`is_broadcast()`](#method.is_broadcast)) + /// - addresses used for documentation (see [`is_documentation()`](#method.is_documentation)) + /// - the unspecified address (see [`is_unspecified()`](#method.is_unspecified)), and the whole 0.0.0.0/8 block + /// - addresses reserved for future protocols (see + /// [`is_ietf_protocol_assignment()`](#method.is_ietf_protocol_assignment), except + /// `192.0.0.9/32` and `192.0.0.10/32` which are globally routable + /// - addresses reserved for future use (see [`is_reserved()`](#method.is_reserved()) + /// - addresses reserved for networking devices benchmarking (see + /// [`is_benchmarking`](#method.is_benchmarking)) /// /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml /// [`true`]: ../../std/primitive.bool.html @@ -530,8 +536,22 @@ impl Ipv4Addr { /// } /// ``` pub fn is_global(&self) -> bool { - !self.is_private() && !self.is_loopback() && !self.is_link_local() && - !self.is_broadcast() && !self.is_documentation() && !self.is_unspecified() + // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two + // globally routable addresses in the 192.0.0.0/24 range. + if u32::from(*self) == 0xc0000009 || u32::from(*self) == 0xc000000a { + return true; + } + !self.is_private() + && !self.is_loopback() + && !self.is_link_local() + && !self.is_broadcast() + && !self.is_documentation() + && !self.is_shared() + && !self.is_ietf_protocol_assignment() + && !self.is_reserved() + && !self.is_benchmarking() + // Make sure the address is not in 0.0.0.0/8 + && self.octets()[0] != 0 } /// Returns [`true`] if this address is part of the Shared Address Space defined in