tox_core 0.1.1

The core of tox
Documentation
/*!
Module for utils of IP and Port.
*/

use std::net::IpAddr;

/// TODO: replace with https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html#method.is_global when it is stabilized
pub trait IsGlobal {
    /// checkif IP is not a LAN ip
    fn is_global(&self) -> bool;
}

impl IsGlobal for IpAddr {
    /// TODO: replace with https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html#method.is_global when it is stabilized
    fn is_global(&self) -> bool {
        if self.is_loopback() {
            return false;
        }

        match *self {
            IpAddr::V4(ipv4) => {
                let addrs = ipv4.octets();

                /* 10.0.0.0 to 10.255.255.255 range. */
                if addrs[0] == 10 {
                    return false;
                }

                /* 172.16.0.0 to 172.31.255.255 range. */
                if addrs[0] == 172 && addrs[1] >= 16 && addrs[1] <= 31 {
                    return false;
                }

                /* 192.168.0.0 to 192.168.255.255 range. */
                if addrs[0] == 192 && addrs[1] == 168 {
                    return false;
                }

                /* 169.254.1.0 to 169.254.254.255 range. */
                if addrs[0] == 169 && addrs[1] == 254 && addrs[2] != 0 && addrs[2] != 255 {
                    return false;
                }

                /* RFC 6598: 100.64.0.0 to 100.127.255.255 (100.64.0.0/10)
                 * (shared address space to stack another layer of NAT) */
                if addrs[0] == 100 && (addrs[1] & 0xC0) == 0x40 {
                    return false;
                }
            },
            IpAddr::V6(ipv6) => {
                let addrs = ipv6.octets();

                /* autogenerated for each interface: FE80::* (up to FEBF::*)
                   FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */
                if (addrs[0] == 0xFF && addrs[1] < 3 && addrs[15] == 1) ||
                    (addrs[0] == 0xFE && (addrs[1] & 0xC0) == 0x80) {
                    return false;
                }

                /* embedded IPv4-in-IPv6 */
                if let Some(ipv4) = ipv6.to_ipv4() {
                    return IsGlobal::is_global(&IpAddr::V4(ipv4));
                } else {}
            },
        };

        true
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::net::Ipv4Addr;
    use std::str::FromStr;

    #[test]
    fn is_global_test() {
        let ipv4 = "127.0.0.1".parse().unwrap();
        assert!(!IsGlobal::is_global(&IpAddr::V4(ipv4)));

        let ipv6 = Ipv4Addr::from_str("127.0.0.1").unwrap().to_ipv6_mapped();
        assert!(!IsGlobal::is_global(&IpAddr::V6(ipv6)));

        let ipv6 = "::1".parse().unwrap();
        assert!(!IsGlobal::is_global(&IpAddr::V6(ipv6)));

        let ipv4 = "10.0.0.1".parse().unwrap();
        assert!(!IsGlobal::is_global(&IpAddr::V4(ipv4)));

        let ipv4 = "192.168.0.1".parse().unwrap();
        assert!(!IsGlobal::is_global(&IpAddr::V4(ipv4)));

        let ipv4 = "169.254.1.1".parse().unwrap();
        assert!(!IsGlobal::is_global(&IpAddr::V4(ipv4)));

        let ipv4 = "100.64.0.1".parse().unwrap();
        assert!(!IsGlobal::is_global(&IpAddr::V4(ipv4)));

        let ipv6 = "FF02::1".parse().unwrap();
        assert!(!IsGlobal::is_global(&IpAddr::V6(ipv6)));

        let ipv6 = Ipv4Addr::from_str("192.168.0.1").unwrap().to_ipv6_mapped();
        assert!(!IsGlobal::is_global(&IpAddr::V6(ipv6)));

        // global ip
        let ipv4 = "128.0.0.1".parse().unwrap();
        assert!(IsGlobal::is_global(&IpAddr::V4(ipv4)));
    }
}