use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
pub trait IpAddrExt {
fn is_global(&self) -> bool;
}
impl IpAddrExt for IpAddr {
fn is_global(&self) -> bool {
match self {
IpAddr::V4(ip) => IpAddrExt::is_global(ip),
IpAddr::V6(ip) => IpAddrExt::is_global(ip),
}
}
}
impl IpAddrExt for Ipv4Addr {
fn is_global(&self) -> bool {
!(self.octets()[0] == 0 || self.is_private()
|| self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
|| self.is_loopback()
|| self.is_link_local()
|| (
self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
&& self.octets()[3] != 9 && self.octets()[3] != 10
)
|| self.is_documentation()
|| self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
|| self.octets()[0] & 240 == 240 && !self.is_broadcast()
|| self.is_broadcast())
}
}
impl IpAddrExt for Ipv6Addr {
fn is_global(&self) -> bool {
!(self.is_unspecified()
|| self.is_loopback()
|| matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
|| matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
|| matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
|| (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
&& !(
u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
|| u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
|| matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
|| matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
|| matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x3F)
))
|| matches!(self.segments(), [0x2002, _, _, _, _, _, _, _])
|| matches!(self.segments(), [0x2001, 0xdb8, ..] | [0x3fff, 0..=0x0fff, ..])
|| matches!(self.segments(), [0x5f00, ..])
|| self.is_unique_local()
|| self.is_unicast_link_local())
}
}