95 lines
2.3 KiB
Rust
95 lines
2.3 KiB
Rust
//! `is_public`: the egress proxy connects only to public addresses. Everything in the M3b spec,
|
|
//! section 5, "Refused ranges" tables is not public; everything else is.
|
|
|
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
|
|
|
/// True if `ip` is a public unicast address.
|
|
pub fn is_public(ip: IpAddr) -> bool {
|
|
match ip {
|
|
IpAddr::V4(v4) => is_public_v4(v4),
|
|
IpAddr::V6(v6) => is_public_v6(v6),
|
|
}
|
|
}
|
|
|
|
fn is_public_v4(ip: Ipv4Addr) -> bool {
|
|
let [a, b, c, _] = ip.octets();
|
|
if a == 0 {
|
|
return false;
|
|
}
|
|
if a == 10 {
|
|
return false;
|
|
}
|
|
if a == 100 && (64..=127).contains(&b) {
|
|
return false;
|
|
}
|
|
if a == 127 {
|
|
return false;
|
|
}
|
|
if a == 169 && b == 254 {
|
|
return false;
|
|
}
|
|
if a == 172 && (16..=31).contains(&b) {
|
|
return false;
|
|
}
|
|
if a == 192 && b == 0 && c == 0 {
|
|
return false;
|
|
}
|
|
if a == 192 && b == 0 && c == 2 {
|
|
return false;
|
|
}
|
|
if a == 192 && b == 168 {
|
|
return false;
|
|
}
|
|
if a == 198 && (b == 18 || b == 19) {
|
|
return false;
|
|
}
|
|
if a == 198 && b == 51 && c == 100 {
|
|
return false;
|
|
}
|
|
if a == 203 && b == 0 && c == 113 {
|
|
return false;
|
|
}
|
|
if a >= 224 {
|
|
return false;
|
|
}
|
|
true
|
|
}
|
|
|
|
fn is_public_v6(ip: Ipv6Addr) -> bool {
|
|
let s = ip.segments();
|
|
if is_ipv4_mapped(s) {
|
|
let last32 = (u32::from(s[6]) << 16) | u32::from(s[7]);
|
|
return is_public_v4(Ipv4Addr::from(last32));
|
|
}
|
|
if is_nat64(s) {
|
|
let last32 = (u32::from(s[6]) << 16) | u32::from(s[7]);
|
|
return is_public_v4(Ipv4Addr::from(last32));
|
|
}
|
|
if s[0..6].iter().all(|&x| x == 0) {
|
|
return false;
|
|
}
|
|
if s[0] & 0xfe00 == 0xfc00 {
|
|
return false;
|
|
}
|
|
if s[0] & 0xffc0 == 0xfe80 {
|
|
return false;
|
|
}
|
|
if s[0] & 0xff00 == 0xff00 {
|
|
return false;
|
|
}
|
|
if s[0] == 0x2001 && s[1] == 0x0db8 {
|
|
return false;
|
|
}
|
|
true
|
|
}
|
|
|
|
/// `::ffff:0:0/96`: the high 80 bits are zero, then the `ffff` marker.
|
|
fn is_ipv4_mapped(s: [u16; 8]) -> bool {
|
|
s[0..5].iter().all(|&x| x == 0) && s[5] == 0xffff
|
|
}
|
|
|
|
/// `64:ff9b::/96`: the NAT64 prefix, then 32 zero bits, then the embedded IPv4 address.
|
|
fn is_nat64(s: [u16; 8]) -> bool {
|
|
s[0] == 0x64 && s[1] == 0xff9b && s[2] == 0 && s[3] == 0 && s[4] == 0 && s[5] == 0
|
|
}
|