|
| 1 | +/// IpAddr `is_global` implementation (for use with stable rust compiler) |
| 2 | +/// The code is copied from STD |
| 3 | +
|
| 4 | +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; |
| 5 | + |
| 6 | +pub trait IpAddrExt { |
| 7 | + fn is_global(&self) -> bool; |
| 8 | +} |
| 9 | + |
| 10 | +impl IpAddrExt for IpAddr { |
| 11 | + fn is_global(&self) -> bool { |
| 12 | + match self { |
| 13 | + IpAddr::V4(ip) => IpAddrExt::is_global(ip), |
| 14 | + IpAddr::V6(ip) => IpAddrExt::is_global(ip), |
| 15 | + } |
| 16 | + } |
| 17 | +} |
| 18 | + |
| 19 | +impl IpAddrExt for Ipv4Addr { |
| 20 | + fn is_global(&self) -> bool { |
| 21 | + !(self.octets()[0] == 0 // "This network" |
| 22 | + || self.is_private() |
| 23 | + // NOTE, this line replaces `self.is_shared()` |
| 24 | + || self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) |
| 25 | + || self.is_loopback() |
| 26 | + || self.is_link_local() |
| 27 | + // addresses reserved for future protocols (`192.0.0.0/24`) |
| 28 | + // .9 and .10 are documented as globally reachable so they're excluded |
| 29 | + || ( |
| 30 | + self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 |
| 31 | + && self.octets()[3] != 9 && self.octets()[3] != 10 |
| 32 | + ) |
| 33 | + || self.is_documentation() |
| 34 | + // NOTE, this line replaces `self.is_benchmarking()` |
| 35 | + || self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 |
| 36 | + // NOTE, this line replaces `self.is_reserved()` |
| 37 | + || self.octets()[0] & 240 == 240 && !self.is_broadcast() |
| 38 | + || self.is_broadcast()) |
| 39 | + } |
| 40 | +} |
| 41 | +impl IpAddrExt for Ipv6Addr { |
| 42 | + fn is_global(&self) -> bool { |
| 43 | + !(self.is_unspecified() |
| 44 | + || self.is_loopback() |
| 45 | + // IPv4-mapped Address (`::ffff:0:0/96`) |
| 46 | + || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _]) |
| 47 | + // IPv4-IPv6 Translat. (`64:ff9b:1::/48`) |
| 48 | + || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _]) |
| 49 | + // Discard-Only Address Block (`100::/64`) |
| 50 | + || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _]) |
| 51 | + // IETF Protocol Assignments (`2001::/23`) |
| 52 | + || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200) |
| 53 | + && !( |
| 54 | + // Port Control Protocol Anycast (`2001:1::1`) |
| 55 | + u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001 |
| 56 | + // Traversal Using Relays around NAT Anycast (`2001:1::2`) |
| 57 | + || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002 |
| 58 | + // AMT (`2001:3::/32`) |
| 59 | + || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _]) |
| 60 | + // AS112-v6 (`2001:4:112::/48`) |
| 61 | + || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _]) |
| 62 | + // ORCHIDv2 (`2001:20::/28`) |
| 63 | + // Drone Remote ID Protocol Entity Tags (DETs) Prefix (`2001:30::/28`)` |
| 64 | + || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x3F) |
| 65 | + )) |
| 66 | + // 6to4 (`2002::/16`) – it's not explicitly documented as globally reachable, |
| 67 | + // IANA says N/A. |
| 68 | + || matches!(self.segments(), [0x2002, _, _, _, _, _, _, _]) |
| 69 | + // NOTE, this line replaces `self.is_documentation()` |
| 70 | + || matches!(self.segments(), [0x2001, 0xdb8, ..] | [0x3fff, 0..=0x0fff, ..]) |
| 71 | + // Segment Routing (SRv6) SIDs (`5f00::/16`) |
| 72 | + || matches!(self.segments(), [0x5f00, ..]) |
| 73 | + || self.is_unique_local() |
| 74 | + || self.is_unicast_link_local()) |
| 75 | + } |
| 76 | +} |
0 commit comments