[0.5] Add IP checks

This commit is contained in:
Felix Ableitner 2026-03-16 15:49:14 +01:00
parent eca8f0fc6f
commit 7c20b6e567

View file

@ -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<T: Clone> FederationConfig<T> {
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<T: Clone> FederationConfig<T> {
}
}
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<T: Clone> FederationConfigBuilder<T> {
/// Sets an actor to use to sign all federated fetch requests
pub fn signed_fetch_actor<A: Actor>(&mut self, actor: &A) -> &mut Self {