parent
5e8e918003
commit
fcb69ebffe
2 changed files with 41 additions and 9 deletions
|
|
@ -20,7 +20,7 @@ use crate::{
|
||||||
http_signatures::sign_request,
|
http_signatures::sign_request,
|
||||||
protocol::verification::verify_domains_match,
|
protocol::verification::verify_domains_match,
|
||||||
traits::{Activity, Actor},
|
traits::{Activity, Actor},
|
||||||
utils::is_invalid_ip,
|
utils::validate_ip,
|
||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
@ -183,7 +183,7 @@ impl<T: Clone> FederationConfig<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
if !allow_local && is_invalid_ip(domain).await? {
|
if !allow_local && validate_ip(&url).await.is_err() {
|
||||||
return Err(Error::DomainResolveError(domain.to_string()));
|
return Err(Error::DomainResolveError(domain.to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -378,6 +378,15 @@ impl<T: Clone> Data<T> {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolve domain of the url and throw error if it points to local/private IP.
|
||||||
|
pub async fn is_valid_ip(&self, url: &Url) -> Result<(), Error> {
|
||||||
|
if self.config.debug {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_ip(url).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone> Deref for Data<T> {
|
impl<T: Clone> Deref for Data<T> {
|
||||||
|
|
|
||||||
37
src/utils.rs
37
src/utils.rs
|
|
@ -2,16 +2,33 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use tokio::net::lookup_host;
|
use tokio::net::lookup_host;
|
||||||
|
use url::{Host, Url};
|
||||||
|
|
||||||
// Resolve domain and see if it points to private IP
|
|
||||||
// TODO: Use is_global() once stabilized
|
// TODO: Use is_global() once stabilized
|
||||||
// https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_global
|
// https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_global
|
||||||
pub(crate) async fn is_invalid_ip(domain: &str) -> Result<bool, Error> {
|
pub(crate) async fn validate_ip(url: &Url) -> Result<(), Error> {
|
||||||
let mut ips = lookup_host((domain, 80)).await?;
|
let mut ip = vec![];
|
||||||
Ok(ips.any(|addr| match addr.ip() {
|
let host = url
|
||||||
|
.host()
|
||||||
|
.ok_or(Error::UrlVerificationError("Url must have a domain"))?;
|
||||||
|
match host {
|
||||||
|
Host::Domain(domain) => ip.extend(
|
||||||
|
lookup_host((domain.to_owned(), 80))
|
||||||
|
.await?
|
||||||
|
.map(|s| s.ip().to_canonical()),
|
||||||
|
),
|
||||||
|
Host::Ipv4(ipv4) => ip.push(ipv4.into()),
|
||||||
|
Host::Ipv6(ipv6) => ip.push(ipv6.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let invalid_ip = ip.into_iter().any(|addr| match addr {
|
||||||
IpAddr::V4(addr) => v4_is_invalid(addr),
|
IpAddr::V4(addr) => v4_is_invalid(addr),
|
||||||
IpAddr::V6(addr) => v6_is_invalid(addr),
|
IpAddr::V6(addr) => v6_is_invalid(addr),
|
||||||
}))
|
});
|
||||||
|
if invalid_ip {
|
||||||
|
return Err(Error::DomainResolveError(host.to_string()));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn v4_is_invalid(v4: Ipv4Addr) -> bool {
|
fn v4_is_invalid(v4: Ipv4Addr) -> bool {
|
||||||
|
|
@ -48,8 +65,14 @@ mod test {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_is_valid_ip() -> Result<(), Error> {
|
async fn test_is_valid_ip() -> Result<(), Error> {
|
||||||
assert!(!is_invalid_ip("example.com").await?);
|
assert!(validate_ip(&Url::parse("http://example.com")?)
|
||||||
assert!(is_invalid_ip("localhost").await?);
|
.await
|
||||||
|
.is_ok());
|
||||||
|
assert!(validate_ip(&Url::parse("http://172.66.147.243")?)
|
||||||
|
.await
|
||||||
|
.is_ok());
|
||||||
|
assert!(validate_ip(&Url::parse("http://localhost")?).await.is_err());
|
||||||
|
assert!(validate_ip(&Url::parse("http://127.0.0.1")?).await.is_err());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue