diff --git a/crates/kumo-spf/src/lib.rs b/crates/kumo-spf/src/lib.rs index 0e2ec4d6..333c93d6 100644 --- a/crates/kumo-spf/src/lib.rs +++ b/crates/kumo-spf/src/lib.rs @@ -177,7 +177,7 @@ impl<'a> SpfContext<'a> { } pub async fn check(&self, resolver: &dyn Resolver, initial: bool) -> SpfResult { - let name = match Name::from_utf8(self.domain) { + let name = match Name::from_str_relaxed(self.domain) { Ok(name) => name, Err(_) => { // Per , invalid diff --git a/crates/kumo-spf/src/record.rs b/crates/kumo-spf/src/record.rs index 6fcaf6e6..cf58addc 100644 --- a/crates/kumo-spf/src/record.rs +++ b/crates/kumo-spf/src/record.rs @@ -4,7 +4,6 @@ use dns_resolver::Resolver; use hickory_resolver::Name; use std::fmt; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use std::str::FromStr; #[derive(Debug, Default)] pub(crate) struct Record { @@ -229,7 +228,7 @@ impl Directive { } .matches(cx.client_ip, IpAddr::V6(*ip6_network)), Mechanism::Ptr { domain } => { - let domain = match Name::from_str(&cx.domain(domain.as_ref())?) { + let domain = match Name::from_str_relaxed(&cx.domain(domain.as_ref())?) { Ok(domain) => domain, Err(err) => { return Err(SpfResult { diff --git a/crates/kumo-spf/src/tests.rs b/crates/kumo-spf/src/tests.rs index 9018c476..1d57c7ba 100644 --- a/crates/kumo-spf/src/tests.rs +++ b/crates/kumo-spf/src/tests.rs @@ -124,6 +124,30 @@ async fn mx() { ); } +#[tokio::test] +async fn underscores() { + let resolver = TestResolver::default() + .with_zone(EXAMPLE_COM) + .with_txt( + "under_score.com", + "v=spf1 ip4:192.0.2.128/28 -all".to_string(), + ) + .with_txt( + "example.com", + "v=spf1 include:under_score.com -all".to_string(), + ); + + let result = evaluate_ip(Ipv4Addr::from([192, 0, 2, 65]), &resolver).await; + k9::assert_equal!( + &result, + &SpfResult { + disposition: SpfDisposition::Fail, + context: "matched '-all' directive".to_owned(), + }, + "{result:?}" + ); +} + /// https://www.rfc-editor.org/rfc/rfc7208#appendix-A.1 #[tokio::test] async fn ip4() {