mirror of
https://github.com/mailscope/kumomta.git
synced 2026-09-21 09:05:32 +00:00
spf: implement h and r macros
refs: https://github.com/KumoCorp/kumomta/issues/423
This commit is contained in:
@@ -115,6 +115,13 @@ pub struct CheckHostParams {
|
||||
|
||||
/// IP address of the SMTP client that is emitting the mail (v4 or v6).
|
||||
pub client_ip: IpAddr,
|
||||
|
||||
/// Explicitly the domain name passed to HELO/EHLO,
|
||||
/// regardless of the `domain` value.
|
||||
pub ehlo_domain: Option<String>,
|
||||
|
||||
/// The host name of this host, the one doing the check
|
||||
pub relaying_host_name: Option<String>,
|
||||
}
|
||||
|
||||
impl CheckHostParams {
|
||||
@@ -123,6 +130,8 @@ impl CheckHostParams {
|
||||
domain,
|
||||
sender,
|
||||
client_ip,
|
||||
ehlo_domain,
|
||||
relaying_host_name,
|
||||
} = self;
|
||||
|
||||
let sender = match sender {
|
||||
@@ -131,7 +140,12 @@ impl CheckHostParams {
|
||||
};
|
||||
|
||||
match SpfContext::new(&sender, &domain, client_ip) {
|
||||
Ok(cx) => cx.check(resolver, true).await,
|
||||
Ok(cx) => {
|
||||
cx.with_ehlo_domain(ehlo_domain.as_deref())
|
||||
.with_relaying_host_name(relaying_host_name.as_deref())
|
||||
.check(resolver, true)
|
||||
.await
|
||||
}
|
||||
Err(result) => result,
|
||||
}
|
||||
}
|
||||
@@ -144,6 +158,8 @@ struct SpfContext<'a> {
|
||||
pub(crate) domain: &'a str,
|
||||
pub(crate) client_ip: IpAddr,
|
||||
pub(crate) now: SystemTime,
|
||||
pub(crate) ehlo_domain: Option<&'a str>,
|
||||
pub(crate) relaying_host_name: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> SpfContext<'a> {
|
||||
@@ -169,9 +185,25 @@ impl<'a> SpfContext<'a> {
|
||||
domain,
|
||||
client_ip,
|
||||
now: SystemTime::now(),
|
||||
ehlo_domain: None,
|
||||
relaying_host_name: "localhost",
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_ehlo_domain(&self, ehlo_domain: Option<&'a str>) -> Self {
|
||||
Self {
|
||||
ehlo_domain,
|
||||
..*self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_relaying_host_name(&self, relaying_host_name: Option<&'a str>) -> Self {
|
||||
Self {
|
||||
relaying_host_name: relaying_host_name.unwrap_or(self.relaying_host_name),
|
||||
..*self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_domain(&self, domain: &'a str) -> Self {
|
||||
Self { domain, ..*self }
|
||||
}
|
||||
|
||||
@@ -155,9 +155,13 @@ impl MacroSpec {
|
||||
.unwrap_or(0)
|
||||
))
|
||||
.unwrap(),
|
||||
MacroName::RelayingHostName
|
||||
| MacroName::HeloDomain
|
||||
| MacroName::ValidatedDomainName => {
|
||||
MacroName::HeloDomain => {
|
||||
buf.push_str(cx.ehlo_domain.unwrap_or(""));
|
||||
}
|
||||
MacroName::RelayingHostName => {
|
||||
buf.push_str(cx.relaying_host_name);
|
||||
}
|
||||
MacroName::ValidatedDomainName => {
|
||||
return Err(format!("{:?} has not been implemented", m.name))
|
||||
}
|
||||
};
|
||||
@@ -345,7 +349,9 @@ mod test {
|
||||
"email.example.com",
|
||||
IpAddr::from([192, 0, 2, 3]),
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap()
|
||||
.with_ehlo_domain(Some("mx1.example.com"))
|
||||
.with_relaying_host_name(Some("mx.mbp.com"));
|
||||
|
||||
for (input, expect) in &[
|
||||
("%{s}", "strong-bad@email.example.com"),
|
||||
@@ -362,6 +368,10 @@ mod test {
|
||||
("%{lr}", "strong-bad"),
|
||||
("%{lr-}", "bad.strong"),
|
||||
("%{l1r-}", "strong"),
|
||||
("%{h}", "mx1.example.com"),
|
||||
("%{h2}", "example.com"),
|
||||
("%{r}", "mx.mbp.com"),
|
||||
("%{rr}", "com.mbp.mx"),
|
||||
] {
|
||||
let spec = MacroSpec::parse(input).unwrap();
|
||||
let output = spec.expand(&ctx).unwrap();
|
||||
|
||||
@@ -26,11 +26,16 @@ pub fn register<'lua>(lua: &'lua Lua) -> anyhow::Result<()> {
|
||||
.and_then(|v| SocketAddr::from_str(v.as_str()?).ok())
|
||||
.expect("`received_from` is always set, and always to a value representing a `SocketAddr`");
|
||||
|
||||
let ehlo_domain = meta.get_meta("ehlo_domain").map(|s| s.to_string());
|
||||
let relaying_host_name = meta.get_meta("hostname").map(|s| s.to_string());
|
||||
|
||||
let resolver = dns_resolver::get_resolver();
|
||||
let result = CheckHostParams {
|
||||
domain,
|
||||
sender,
|
||||
client_ip: addr.ip(),
|
||||
ehlo_domain,
|
||||
relaying_host_name,
|
||||
}
|
||||
.check(&**resolver)
|
||||
.await;
|
||||
|
||||
Reference in New Issue
Block a user