diff --git a/src/config.rs b/src/config.rs index bf48e76..f968535 100644 --- a/src/config.rs +++ b/src/config.rs @@ -32,7 +32,7 @@ use reqwest_middleware::ClientWithMiddleware; use rsa::{pkcs8::DecodePrivateKey, RsaPrivateKey}; use serde::de::DeserializeOwned; use std::{ - net::IpAddr, + net::{IpAddr, Ipv4Addr, Ipv6Addr}, ops::Deref, sync::{ atomic::{AtomicU32, Ordering}, @@ -189,19 +189,9 @@ impl FederationConfig { let mut ips = lookup_host((domain.to_owned(), 80)).await?; let allow_local = std::env::var("DANGER_FEDERATION_ALLOW_LOCAL_IP").is_ok(); let invalid_ip = !allow_local - && ips.any(|addr| match addr.ip() { - IpAddr::V4(addr) => { - addr.is_private() - || addr.is_link_local() - || addr.is_loopback() - || addr.is_multicast() - } - IpAddr::V6(addr) => { - addr.is_loopback() - || addr.is_multicast() - || ((addr.segments()[0] & 0xfe00) == 0xfc00) // is_unique_local - || ((addr.segments()[0] & 0xffc0) == 0xfe80) // is_unicast_link_local - } + && ips.any(|addr| match addr.ip().to_canonical() { + IpAddr::V4(addr) => v4_is_invalid(addr), + IpAddr::V6(addr) => v6_is_invalid(addr), }); if invalid_ip { let ip_addrs = ips.join(", "); @@ -245,6 +235,30 @@ impl FederationConfig { } } +fn v4_is_invalid(v4: Ipv4Addr) -> bool { + v4.is_private() + || v4.is_loopback() + || v4.is_link_local() + || v4.is_multicast() + || v4.is_documentation() + || v4.is_unspecified() + || v4.is_broadcast() +} + +fn v6_is_invalid(v6: Ipv6Addr) -> bool { + let is_documentation = matches!( + v6.segments(), + [0x2001, 0xdb8, ..] | [0x3fff, 0..=0x0fff, ..] + ); + is_documentation + || v6.is_loopback() + || v6.is_multicast() + || v6.is_unique_local() + || v6.is_unicast_link_local() + || v6.is_unspecified() + || v6.to_ipv4_mapped().is_some_and(v4_is_invalid) +} + impl FederationConfigBuilder { /// Sets an actor to use to sign all federated fetch requests pub fn signed_fetch_actor(&mut self, actor: &A) -> &mut Self {