Relaxed alignment with differing subdomains not passing
Closed this issue · 3 comments
If a sender passes SPF or DKIM and their domain is z.example.org
and the domain of the sender in the From header is a.b.c.example.org
under relaxed alignent DMARC should pass because the Organizational Domain example.org
aligns.
This test case can be added to the tests in dmarc/verify.rs
to illustrate the scenario.
// Relaxed - Pass with tree walk and different subdomains
(
"_dmarc.c.example.org.",
concat!(
"v=DMARC1; p=reject; sp=quarantine; np=None; aspf=r; adkim=r; fo=1;",
"rua=mailto:dmarc-feedback@example.org"
),
"From: hello@a.b.c.example.org\r\n\r\n",
"z.example.org",
"z.example.org",
DkimResult::Pass,
SpfResult::Pass,
DmarcResult::Pass,
DmarcResult::Pass,
Policy::Quarantine,
),
Currently, the test for relaxed alignment checks if either domain ends with the other. If this condition is met, the domains are considered aligned.
https://github.com/stalwartlabs/mail-auth/blob/main/src/dmarc/verify.rs#L74-L76
However, this test fails if the domains are 2 separate subdomains entirely. Looking at RFC sections 3.1.1 and 3.1.2, it looks like the correct test should be to test if the SPF/DKIM authenticated domain matches the Organizational Domain of the From header domain.
RFC povides guidance on how to extract the Organizational Domain in section 3.2. It looks like there are a couple of crates that provide this functionality:
The simplest approach is to use the psl
crate but that comes with the shortcoming of needing to re-compile if the public suffix list changes in the future. The publicsuffix
crate would require reading a file from the filesystem but it's unclear to me how you'd want to handle that configuration in this library.
Fixed, the dmarc_verify
function now expects a function to extract the domain as a parameter. You can call the psl
crate from there:
let dmarc_result = resolver
.verify_dmarc(
&authenticated_message,
&dkim_result,
"example.org",
&spf_result,
|domain| psl::domain_str(domain).unwrap_or(domain),
)
.await;
If it works well please let me know and I'll publish v0.5.0.
Looks great. Thanks!