Make IP check public
This commit is contained in:
parent
5e8e918003
commit
a087c489a0
2 changed files with 41 additions and 9 deletions
|
|
@ -20,7 +20,7 @@ use crate::{
|
|||
http_signatures::sign_request,
|
||||
protocol::verification::verify_domains_match,
|
||||
traits::{Activity, Actor},
|
||||
utils::is_invalid_ip,
|
||||
utils::validate_ip,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
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();
|
||||
if !allow_local && is_invalid_ip(domain).await? {
|
||||
if !allow_local && self.is_valid_ip(&url).await.is_err() {
|
||||
return Err(Error::DomainResolveError(domain.to_string()));
|
||||
}
|
||||
}
|
||||
|
|
@ -222,6 +222,15 @@ impl<T: Clone> FederationConfig<T> {
|
|||
pub fn domain(&self) -> &str {
|
||||
&self.domain
|
||||
}
|
||||
|
||||
/// 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.debug {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
validate_ip(url).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> FederationConfigBuilder<T> {
|
||||
|
|
|
|||
37
src/utils.rs
37
src/utils.rs
|
|
@ -2,16 +2,33 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
|||
|
||||
use crate::error::Error;
|
||||
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
|
||||
// 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> {
|
||||
let mut ips = lookup_host((domain, 80)).await?;
|
||||
Ok(ips.any(|addr| match addr.ip() {
|
||||
pub(crate) async fn validate_ip(url: &Url) -> Result<(), Error> {
|
||||
let mut ip = vec![];
|
||||
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::V6(addr) => v6_is_invalid(addr),
|
||||
}))
|
||||
});
|
||||
if invalid_ip {
|
||||
return Err(Error::DomainResolveError(host.to_string()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn v4_is_invalid(v4: Ipv4Addr) -> bool {
|
||||
|
|
@ -48,8 +65,14 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn test_is_valid_ip() -> Result<(), Error> {
|
||||
assert!(!is_invalid_ip("example.com").await?);
|
||||
assert!(is_invalid_ip("localhost").await?);
|
||||
assert!(validate_ip(&Url::parse("http://example.com")?)
|
||||
.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(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue