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 9576ba6674c104b060e4d3a549614db129d5c03f
Author: Quan Tran <[email protected]>
AuthorDate: Wed Nov 4 22:28:21 2026 +0700

    [FIX] ptr mechanism: no match on a DNS error of its lookups
    
    A DNS error of a lookup of the ptr mechanism, as SERVFAIL for the PTR
    records of the client address, made the whole check a temperror. RFC
    7208 5.5 says otherwise: "If a DNS error occurs while doing the PTR RR
    lookup, then this mechanism fails to match", and "If a DNS error occurs
    while doing an A RR lookup, then that domain name is skipped and the
    search continues". Reverse zones answering SERVFAIL are common, so
    "v=spf1 ptr ip4:192.0.2.10 -all" gave temperror for 192.0.2.10 instead
    of pass.
    
    On a DNS error of the PTR lookup the mechanism does not match; on one
    of an address lookup, the next name is checked.
---
 .../org/apache/james/jspf/terms/PTRMechanism.java  |  7 ++++-
 .../org/apache/james/jspf/SPFExecutorBaseTest.java | 35 ++++++++++++++++++++++
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git 
a/resolver/src/main/java/org/apache/james/jspf/terms/PTRMechanism.java 
b/resolver/src/main/java/org/apache/james/jspf/terms/PTRMechanism.java
index 5ac51d3..0a0dfb2 100644
--- a/resolver/src/main/java/org/apache/james/jspf/terms/PTRMechanism.java
+++ b/resolver/src/main/java/org/apache/james/jspf/terms/PTRMechanism.java
@@ -187,7 +187,12 @@ public class PTRMechanism extends GenericMechanism 
implements DNSServiceEnabled,
             
             }
         } catch (TimeoutException e) {
-            throw new TempErrorException("Timeout querying the dns server");
+            // RFC 7208 5.5: "If a DNS error occurs while doing the PTR RR 
lookup, then this mechanism
+            // fails to match", and of an address lookup, "that domain name is 
skipped"
+            if (domainList == null) {
+                spfSession.setAttribute(Directive.ATTRIBUTE_MECHANISM_RESULT, 
Boolean.FALSE);
+                return null;
+            }
         }
         
 
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 bdec8fb..bcc20c4 100644
--- a/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java
+++ b/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java
@@ -808,6 +808,41 @@ public abstract class SPFExecutorBaseTest {
         assertEquals(SPFErrorConstants.PASS_CONV, result.getResult());
     }
 
+    @Test(timeout = 10000)
+    public void ptrShouldNotMatchWhenThePtrLookupFails() throws IOException {
+        String hostname = "ptrservfail.spfexecutor.fake";
+        // the names of no record of fakeResolver, as the reverse name of the 
client, answer SERVFAIL
+        FakeResolver fakeResolver = new 
FakeResolver(AnsweringResolver.withRcode(Rcode.SERVFAIL));
+        fakeResolver.addRecord(new TXTRecord(Name.fromString(hostname + "."), 
DClass.IN, 30L,
+            "v=spf1 ptr ip4:192.0.2.10 -all"));
+        SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver));
+
+        SPFResult result = spf.checkSPF("192.0.2.10", "a_user@" + hostname, 
hostname);
+
+        // RFC 7208 5.5: "If a DNS error occurs while doing the PTR RR lookup, 
then this mechanism fails to match"
+        assertEquals(SPFErrorConstants.PASS_CONV, result.getResult());
+    }
+
+    @Test(timeout = 10000)
+    public void ptrShouldSkipANameWhoseAddressLookupFails() throws IOException 
{
+        String hostname = "ptrskip.spfexecutor.fake";
+        FakeResolver fakeResolver = new 
FakeResolver(AnsweringResolver.withRcode(Rcode.SERVFAIL));
+        fakeResolver.addRecord(new TXTRecord(Name.fromString(hostname + "."), 
DClass.IN, 30L, "v=spf1 ptr -all"));
+        // the client is named by broken.servfail.fake, of no record here, 
then by mail.<hostname>
+        fakeResolver.addRecord(new 
PTRRecord(Name.fromString("10.2.0.192.in-addr.arpa."), DClass.IN, 30L,
+            Name.fromString("broken.servfail.fake.")));
+        fakeResolver.addRecord(new 
PTRRecord(Name.fromString("10.2.0.192.in-addr.arpa."), DClass.IN, 30L,
+            Name.fromString("mail." + hostname + ".")));
+        fakeResolver.addRecord(new ARecord(Name.fromString("mail." + hostname 
+ "."), DClass.IN, 30L,
+            InetAddress.getByName("192.0.2.10")));
+        SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver));
+
+        SPFResult result = spf.checkSPF("192.0.2.10", "a_user@" + hostname, 
hostname);
+
+        // RFC 7208 5.5: "If a DNS error occurs while doing an A RR lookup, 
then that domain name is skipped"
+        assertEquals(SPFErrorConstants.PASS_CONV, result.getResult());
+    }
+
     @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