[0.5] Add IP checks (#163)

* [0.5] Add IP checks

* add lockfile

* replace

* fix deps

* ci
This commit is contained in:
Nutomic 2026-03-17 11:15:37 +01:00 committed by GitHub
parent eca8f0fc6f
commit cb05faefdc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 2998 additions and 15 deletions

1
.gitignore vendored
View file

@ -1,6 +1,5 @@
/target /target
/.idea /.idea
/Cargo.lock
perf.data* perf.data*
flamegraph.svg flamegraph.svg

2970
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -32,7 +32,7 @@ use reqwest_middleware::ClientWithMiddleware;
use rsa::{pkcs8::DecodePrivateKey, RsaPrivateKey}; use rsa::{pkcs8::DecodePrivateKey, RsaPrivateKey};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::{ use std::{
net::IpAddr, net::{IpAddr, Ipv4Addr, Ipv6Addr},
ops::Deref, ops::Deref,
sync::{ sync::{
atomic::{AtomicU32, Ordering}, atomic::{AtomicU32, Ordering},
@ -189,19 +189,9 @@ impl<T: Clone> FederationConfig<T> {
let mut ips = lookup_host((domain.to_owned(), 80)).await?; let mut ips = lookup_host((domain.to_owned(), 80)).await?;
let allow_local = std::env::var("DANGER_FEDERATION_ALLOW_LOCAL_IP").is_ok(); let allow_local = std::env::var("DANGER_FEDERATION_ALLOW_LOCAL_IP").is_ok();
let invalid_ip = !allow_local let invalid_ip = !allow_local
&& ips.any(|addr| match addr.ip() { && ips.any(|addr| match addr.ip().to_canonical() {
IpAddr::V4(addr) => { IpAddr::V4(addr) => v4_is_invalid(addr),
addr.is_private() IpAddr::V6(addr) => v6_is_invalid(addr),
|| 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
}
}); });
if invalid_ip { if invalid_ip {
let ip_addrs = ips.join(", "); 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.segments()[0] & 0xfe00) == 0xfc00 // is_unique_local
|| (v6.segments()[0] & 0xffc0) == 0xfe80 // is_unicast_link_local
|| v6.is_unspecified()
|| v6.to_ipv4_mapped().is_some_and(v4_is_invalid)
}
impl<T: Clone> FederationConfigBuilder<T> { impl<T: Clone> FederationConfigBuilder<T> {
/// Sets an actor to use to sign all federated fetch requests /// Sets an actor to use to sign all federated fetch requests
pub fn signed_fetch_actor<A: Actor>(&mut self, actor: &A) -> &mut Self { pub fn signed_fetch_actor<A: Actor>(&mut self, actor: &A) -> &mut Self {