use super::{AgentKind, EgressTier, ProviderId};
pub fn egress_for_provider(provider: &ProviderId) -> EgressTier {
if provider.is_unknown() {
EgressTier::Unknown
} else {
EgressTier::ThirdParty
}
}
pub fn egress_for_cli(cli: AgentKind) -> EgressTier {
let (provider, _) = super::provider_for_cli(cli);
egress_for_provider(&provider)
}
pub fn egress_for_base_url(base_url: &str) -> EgressTier {
let trimmed = base_url.trim();
if trimmed.is_empty() {
return EgressTier::Unknown;
}
host_from_base_url(trimmed)
.map(egress_for_host)
.unwrap_or(EgressTier::Unknown)
}
fn egress_for_host(host: &str) -> EgressTier {
let host = host.trim_matches(|c| c == '[' || c == ']');
let lower = host.to_ascii_lowercase();
if lower == "localhost" {
return EgressTier::Local;
}
if let Ok(ip) = lower.parse::<std::net::IpAddr>() {
return egress_for_ip(ip);
}
if has_private_dns_suffix(&lower) {
return EgressTier::PrivateNetwork;
}
EgressTier::ThirdParty
}
fn egress_for_ip(ip: std::net::IpAddr) -> EgressTier {
match ip {
std::net::IpAddr::V4(v4) => {
if v4.is_loopback() {
return EgressTier::Local;
}
if is_private_ipv4(v4) {
return EgressTier::PrivateNetwork;
}
EgressTier::ThirdParty
}
std::net::IpAddr::V6(v6) => {
if v6.is_loopback() {
return EgressTier::Local;
}
if v6.is_unicast_link_local() || is_ipv6_ula(v6) {
return EgressTier::PrivateNetwork;
}
EgressTier::ThirdParty
}
}
}
fn is_private_ipv4(ip: std::net::Ipv4Addr) -> bool {
let o = ip.octets();
o[0] == 10
|| (o[0] == 172 && (16..=31).contains(&o[1]))
|| (o[0] == 192 && o[1] == 168)
|| (o[0] == 169 && o[1] == 254)
}
fn is_ipv6_ula(ip: std::net::Ipv6Addr) -> bool {
(ip.segments()[0] & 0xfe00) == 0xfc00
}
fn has_private_dns_suffix(host: &str) -> bool {
host.ends_with(".local") || host.ends_with(".home.arpa")
}
fn host_from_base_url(base_url: &str) -> Option<&str> {
let rest = base_url
.split_once("://")
.map(|(_, after)| after)
.unwrap_or(base_url);
let authority = rest.split('/').next().unwrap_or(rest);
if authority.is_empty() {
return None;
}
let hostport = authority.rsplit('@').next().unwrap_or(authority);
if hostport.starts_with('[') {
return hostport.split(']').next().map(|h| h.trim_start_matches('['));
}
Some(hostport.split(':').next().unwrap_or(hostport)).filter(|h| !h.is_empty())
}