1
0
Fork 0
mirror of https://gitlab.com/famedly/conduit.git synced 2025-06-27 16:35:59 +00:00

Do spamhaus check

This commit is contained in:
Steven Vergenz 2024-10-31 11:21:16 -07:00
parent b76357c80e
commit 7dd9bda17b
2 changed files with 26 additions and 4 deletions

View file

@ -7,6 +7,7 @@ use crate::{
service::media::{FileMeta, UrlPreviewData}, service::media::{FileMeta, UrlPreviewData},
config::UrlPreviewPermission, config::UrlPreviewPermission,
services, utils, Error, Result, Ruma}; services, utils, Error, Result, Ruma};
use hickory_resolver::error::ResolveErrorKind;
use http::header::{CONTENT_DISPOSITION, CONTENT_TYPE}; use http::header::{CONTENT_DISPOSITION, CONTENT_TYPE};
use ruma::{ use ruma::{
api::{ api::{
@ -126,7 +127,7 @@ async fn download_html(
Ok(data) Ok(data)
} }
fn url_request_allowed(addr: &IpAddr) -> bool { fn is_ip_external(addr: &IpAddr) -> bool {
// could be implemented with reqwest when it supports IP filtering: // could be implemented with reqwest when it supports IP filtering:
// https://github.com/seanmonstar/reqwest/issues/1515 // https://github.com/seanmonstar/reqwest/issues/1515
@ -179,18 +180,38 @@ fn url_request_allowed(addr: &IpAddr) -> bool {
/// Generate URL preview data from the given URL /// Generate URL preview data from the given URL
async fn request_url_preview(url: &Url) -> Result<UrlPreviewData> { async fn request_url_preview(url: &Url) -> Result<UrlPreviewData> {
// resolve host to IP to ensure it's not a local IP (host guaranteed to not be None) // host guaranteed to not be None by get_media_preview_route
let host = url.host_str().unwrap();
// resolve host to IP to ensure it's not an internal IP
let dns_resolver = services().globals.dns_resolver(); let dns_resolver = services().globals.dns_resolver();
match dns_resolver.lookup_ip(url.host_str().unwrap()).await { match dns_resolver.lookup_ip(host).await {
Err(_) => { Err(_) => {
return Err(Error::BadServerResponse("Failed to resolve media preview host")); return Err(Error::BadServerResponse("Failed to resolve media preview host"));
}, },
Ok(lookup) if lookup.iter().any(|ip| !url_request_allowed(&ip)) => { Ok(lookup) if lookup.iter().any(|ip| !is_ip_external(&ip)) => {
return Err(Error::BadRequest(ErrorKind::Unknown, "Requesting from this address forbidden")); return Err(Error::BadRequest(ErrorKind::Unknown, "Requesting from this address forbidden"));
}, },
Ok(_) => { }, Ok(_) => { },
} }
// Spamhaus API is over DNS. Query the API domain, no result = no block
// https://docs.spamhaus.com/datasets/docs/source/70-access-methods/data-query-service/040-dqs-queries.html
if services().globals.url_previews().use_spamhaus_denylist {
let resolver = services().globals.dns_resolver();
match resolver.lookup_ip(format!("{host}.dbl.spamhaus.org")).await {
Err(e) => {
if let ResolveErrorKind::NoRecordsFound { .. } = e.kind() { }
else {
tracing::log::warn!("Failed to check Spamhaus denylist: {}", e);
}
},
Ok(_) => {
return Err(Error::BadRequest(ErrorKind::Unknown, "Domain fails reputation check"));
},
}
}
let client = services().globals.default_client(); let client = services().globals.default_client();
let response = client.head(url.as_str()).send().await?; let response = client.head(url.as_str()).send().await?;

View file

@ -110,6 +110,7 @@ pub struct WellKnownConfig {
pub struct UrlPreviewConfig { pub struct UrlPreviewConfig {
pub default: UrlPreviewPermission, pub default: UrlPreviewPermission,
pub exceptions: Vec<WildCardedDomain>, pub exceptions: Vec<WildCardedDomain>,
pub use_spamhaus_denylist: bool,
} }
#[derive(Clone, Debug, Deserialize, Default)] #[derive(Clone, Debug, Deserialize, Default)]