This is an automated email from the ASF dual-hosted git repository.

chibenwa pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-jspf.git

commit 6266c12f6bfff635f41be7a9af1bc3245f0a8d7d
Author: Quan Tran <[email protected]>
AuthorDate: Wed Nov 4 22:37:59 2026 +0700

    [FIX] DNSServiceXBillImpl: look up the names as fully qualified
    
    getRecords gave dnsjava's Lookup the name as relative, so after an
    NXDOMAIN Lookup looked it up again under each domain of the search path
    of the host: a sender domain x.example.com that does not exist was
    checked with the record of x.example.com.corp.local, when the host
    searches corp.local. The domains of SPF are fully qualified (RFC 7208
    4.3, and 4.8: "a fully qualified DNS name"), and the asynchronous
    lookup, of a session without search path, did not do it.
    
    Look up the names as fully qualified, in both getRecords and
    getRecordsAsync.
---
 .../apache/james/jspf/impl/DNSServiceXBillImpl.java  |  5 +++--
 .../org/apache/james/jspf/SPFExecutorBaseTest.java   | 20 ++++++++++++++++++++
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git 
a/resolver/src/main/java/org/apache/james/jspf/impl/DNSServiceXBillImpl.java 
b/resolver/src/main/java/org/apache/james/jspf/impl/DNSServiceXBillImpl.java
index da95454..a0614cd 100644
--- a/resolver/src/main/java/org/apache/james/jspf/impl/DNSServiceXBillImpl.java
+++ b/resolver/src/main/java/org/apache/james/jspf/impl/DNSServiceXBillImpl.java
@@ -305,7 +305,8 @@ public class DNSServiceXBillImpl implements DNSService {
 
             LOGGER.debug("Start {}-Record lookup for : {}", 
recordTypeDescription, request.getHostname());
 
-            Lookup query = new Lookup(request.getHostname(), dnsJavaType);
+            // RFC 7208 4.3: a fully qualified name, not looked up under the 
search path of the host
+            Lookup query = new Lookup(Name.fromString(request.getHostname(), 
Name.root), dnsJavaType);
             query.setResolver(resolver);
 
             Record[] rr = query.run();
@@ -345,7 +346,7 @@ public class DNSServiceXBillImpl implements DNSService {
         final LookupSession lookupSession = 
LookupSession.defaultBuilder().resolver(new 
BoundedResolver(this.resolver)).build();
 
         try {
-            return 
lookupSession.lookupAsync(Name.fromString(request.getHostname()), dnsJavaType)
+            return 
lookupSession.lookupAsync(Name.fromString(request.getHostname(), Name.root), 
dnsJavaType)
                 .thenApply(result -> 
convertRecordsToList(ofType(result.getRecords().toArray(new Record[0]), 
dnsJavaType)));
         } catch (TextParseException e) {
             // no record, as getRecords answers
diff --git 
a/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java 
b/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java
index b7736cd..45626d4 100644
--- a/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java
+++ b/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java
@@ -960,6 +960,26 @@ public abstract class SPFExecutorBaseTest {
             result.getHeader());
     }
 
+    @Test(timeout = 10000)
+    public void shouldNotLookUpTheDomainUnderTheSearchPath() throws 
IOException {
+        String hostname = "searchPath.spfexecutor.fake";
+        FakeResolver fakeResolver = new 
FakeResolver(AnsweringResolver.withRcode(Rcode.NXDOMAIN));
+        // the domain under a search path of the host, of a record that would 
pass
+        fakeResolver.addRecord(new TXTRecord(Name.fromString(hostname + 
".search.fake."), DClass.IN, 30L, "v=spf1 +all"));
+        List<Name> searchPath = Lookup.getDefaultSearchPath();
+        Lookup.setDefaultSearchPath(Name.fromString("search.fake."));
+        try {
+            SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver));
+
+            SPFResult result = spf.checkSPF("192.0.2.10", "a_user@" + 
hostname, hostname);
+
+            // RFC 7208 4.3: the domain is fully qualified, and does not exist
+            assertEquals(SPFErrorConstants.NONE_CONV, result.getResult());
+        } finally {
+            Lookup.setDefaultSearchPath(searchPath);
+        }
+    }
+
     @Test(timeout = 10000)
     public void shouldReturnPermErrorOnAIp4CidrOverflowingAnInt() throws 
IOException {
         SPFResult result = checkRecord("aIp4CidrOverflow.spfexecutor.fake", 
"v=spf1 a/4294967296 -all", "1.2.3.4");


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to