Skip to content

Commit

Permalink
Do not DNSBL check invalid domains (#1107)
Browse files Browse the repository at this point in the history
  • Loading branch information
mdecimus committed Jan 19, 2025
1 parent a6f1169 commit 5e5771e
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 30 deletions.
12 changes: 12 additions & 0 deletions crates/common/src/config/spamfilter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,18 @@ impl Element {
Element::Any => map,
}
}

pub fn as_str(&self) -> &'static str {
match self {
Element::Url => "url",
Element::Domain => "domain",
Element::Email => "email",
Element::Ip => "ip",
Element::Header => "header",
Element::Body => "body",
Element::Any => "any",
}
}
}

pub struct IpResolver {
Expand Down
36 changes: 18 additions & 18 deletions crates/spam-filter/src/analysis/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,12 @@ impl SpamFilterAnalyzeDomain for Server {
attributes.iter().find_map(|(attr, value)| {
if *attr == HREF {
let value = value.as_deref()?.strip_prefix("mailto:")?;
if value.contains('@') {
let email =
Email::new(value.split_once('?').map_or(value, |(e, _)| e));

if email.is_valid() {
return Some(ElementLocation::new(
Recipient {
email: Email::new(
value.split_once('?').map_or(value, |(e, _)| e),
),
name: None,
},
Recipient { email, name: None },
if is_body {
Location::BodyHtml
} else {
Expand Down Expand Up @@ -203,17 +201,19 @@ impl SpamFilterAnalyzeDomain for Server {
}
}

emails.insert(ElementLocation::new(
Recipient {
email: email.clone(),
name: None,
},
if is_body {
Location::BodyText
} else {
Location::Attachment
},
));
if email.is_valid() {
emails.insert(ElementLocation::new(
Recipient {
email: email.clone(),
name: None,
},
if is_body {
Location::BodyText
} else {
Location::Attachment
},
));
}
}
}
}
Expand Down
18 changes: 10 additions & 8 deletions crates/spam-filter/src/analysis/url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,14 +250,16 @@ impl SpamFilterAnalyzeUrl for Server {
}

// Check Domain DNSBL
check_dnsbl(
self,
ctx,
&StringResolver(host.sld_or_default()),
Element::Domain,
el.location,
)
.await;
if let Some(sld) = &host.sld {
check_dnsbl(
self,
ctx,
&StringResolver(sld),
Element::Domain,
el.location,
)
.await;
}
} else {
// URL is an ip address
ctx.result.add_tag("SUSPICIOUS_URL");
Expand Down
5 changes: 5 additions & 0 deletions crates/spam-filter/src/modules/dnsbl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub(crate) async fn check_dnsbl(
server,
dnsbl,
SpamFilterResolver::new(ctx, resolver, location),
scope,
&mut checks,
)
.await
Expand All @@ -77,6 +78,7 @@ async fn is_dnsbl(
server: &Server,
config: &DnsBlServer,
resolver: SpamFilterResolver<'_, impl ResolveVariable>,
element: Element,
checks: &mut usize,
) -> Option<String> {
let time = Instant::now();
Expand Down Expand Up @@ -133,6 +135,7 @@ async fn is_dnsbl(
.iter()
.map(|ip| trc::Value::from(ip.to_string()))
.collect::<Vec<_>>(),
Details = element.as_str(),
Elapsed = time.elapsed()
);

Expand All @@ -159,6 +162,7 @@ async fn is_dnsbl(
Spam(SpamEvent::Dnsbl),
Hostname = zone.clone(),
Result = trc::Value::None,
Details = element.as_str(),
Elapsed = time.elapsed()
);

Expand All @@ -175,6 +179,7 @@ async fn is_dnsbl(
Spam(SpamEvent::DnsblError),
Hostname = zone,
Elapsed = time.elapsed(),
Details = element.as_str(),
CausedBy = err.to_string()
);

Expand Down
14 changes: 11 additions & 3 deletions crates/spam-filter/src/modules/sanitize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{Email, Hostname};

impl Hostname {
pub fn new(host: &str) -> Self {
let mut fqdn = host.to_lowercase();
let mut fqdn = host.trim_end_matches('.').to_lowercase();

// Decode punycode
if fqdn.contains("xn--") {
Expand Down Expand Up @@ -42,12 +42,20 @@ impl Hostname {
.ok();

Hostname {
ip,
sld: if ip.is_none() {
psl::domain_str(&fqdn).map(str::to_string)
psl::domain(fqdn.as_bytes()).and_then(|domain| {
if domain.suffix().typ().is_some() {
std::str::from_utf8(domain.as_bytes())
.ok()
.map(str::to_string)
} else {
None
}
})
} else {
None
},
ip,
fqdn,
}
}
Expand Down
5 changes: 4 additions & 1 deletion crates/utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,10 @@ pub fn sanitize_email(email: &str) -> Option<String> {
}
}

if found_domain && last_ch != '.' && psl::domain(result.as_bytes()).is_some() {
if found_domain
&& last_ch != '.'
&& psl::domain(result.as_bytes()).is_some_and(|d| d.suffix().typ().is_some())
{
Some(result)
} else {
None
Expand Down
48 changes: 48 additions & 0 deletions tests/src/smtp/inbound/antispam.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,54 @@ path = "{PATH}/test_antispam.db"
#type = "redis"
#url = "redis://127.0.0.1"
[http-lookup.STWT_OPENPHISH]
enable = true
url = "https://openphish.com/feed.txt"
format = "list"
retry = "1h"
refresh = "12h"
timeout = "30s"
limits.size = 104857600
limits.entries = 900000
limits.entry-size = 512
[http-lookup.STWT_PHISHTANK]
enable = true
url = "http://data.phishtank.com/data/online-valid.csv.gz"
format = "csv"
separator = ","
index.key = 1
skip-first = true
gzipped = true
retry = "1h"
refresh = "6h"
timeout = "30s"
limits.size = 104857600
limits.entries = 900000
limits.entry-size = 512
[http-lookup.STWT_DISPOSABLE_DOMAINS]
enable = true
url = "https://disposable.github.io/disposable-email-domains/domains_mx.txt"
format = "list"
retry = "1h"
refresh = "24h"
timeout = "30s"
limits.size = 104857600
limits.entries = 900000
limits.entry-size = 512
[http-lookup.STWT_FREE_DOMAINS]
enable = true
url = "https://gist.githubusercontent.com/okutbay/5b4974b70673dfdcc21c517632c1f984/raw/993a35930a8d24a1faab1b988d19d38d92afbba4/free_email_provider_domains.txt"
format = "list"
retry = "1h"
refresh = "720h"
timeout = "30s"
limits.size = 104857600
limits.entries = 900000
limits.entry-size = 512
[enterprise.ai.dummy]
url = "https://127.0.0.1:9090/v1/chat/completions"
type = "chat"
Expand Down

0 comments on commit 5e5771e

Please sign in to comment.