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 64df226ed59f3c8116c802d362259ce41ddaad9b Author: Quan Tran <[email protected]> AuthorDate: Thu Nov 5 11:26:37 2026 +0700 [FIX] ptr mechanism: check the first 10 names, not 9 Of more than 10 PTR names of the client address, the ptr mechanism kept the first getRecordLimit() - 1, so 9 with the default limit of 10, and none with a limit of 1: when the 10th name was the one validating the client, the mechanism did not match where it matches. RFC 7208 4.6.4: "all records other than the first 10 MUST be ignored". Keep the first getRecordLimit() names. --- .../org/apache/james/jspf/terms/PTRMechanism.java | 6 ++-- .../org/apache/james/jspf/SPFExecutorBaseTest.java | 35 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) 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 0a0dfb2..374d799 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 @@ -156,9 +156,9 @@ public class PTRMechanism extends GenericMechanism implements DNSServiceEnabled, // check if the maximum lookup count is reached if (dnsService.getRecordLimit() > 0 && domainList.size() > dnsService.getRecordLimit()) { - // Truncate the PTR list to getRecordLimit. - // See #ptr-limit rfc4408 test - domainList = domainList.subList(0, dnsService.getRecordLimit()-1); + // Truncate the PTR list to getRecordLimit: RFC 7208 4.6.4, "all records other than the + // first 10 MUST be ignored". See #ptr-limit rfc4408 test + domainList = domainList.subList(0, dnsService.getRecordLimit()); // throw new PermErrorException("Maximum PTR lookup count reached"); } 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 b5d6f3c..f678e92 100644 --- a/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java +++ b/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java @@ -83,6 +83,20 @@ public abstract class SPFExecutorBaseTest { return fakeResolver; } + // hostname has "v=spf1 ptr -all", and 1.2.3.4 the 11 PTR names name<i>.<hostname>, of which only name<validated> has + // the address 1.2.3.4 + private static FakeResolver elevenPtrNamesOfTheClient(String hostname, int validated) throws IOException { + FakeResolver fakeResolver = new FakeResolver(); + fakeResolver.addRecord(new TXTRecord(Name.fromString(hostname + "."), DClass.IN, 30L, "v=spf1 ptr -all")); + for (int i = 1; i <= 11; i++) { + fakeResolver.addRecord(new PTRRecord(Name.fromString("4.3.2.1.in-addr.arpa."), DClass.IN, 30L, + Name.fromString("name" + i + "." + hostname + "."))); + } + fakeResolver.addRecord(new ARecord(Name.fromString("name" + validated + "." + hostname + "."), DClass.IN, 30L, + InetAddress.getByName("1.2.3.4"))); + return fakeResolver; + } + // a server publishing the record, failing the lookups of the given DNSRequest type private static DNSService dnsFailing(int failedType, Record record) throws IOException { FakeResolver fakeResolver = new FakeResolver(); @@ -716,6 +730,27 @@ public abstract class SPFExecutorBaseTest { assertEquals(SPFErrorConstants.PASS_CONV, result.getResult()); } + @Test(timeout = 10000) + public void ptrShouldCheckTheTenthOfMoreThanTenNames() throws IOException { + String hostname = "ptrlimit.spfexecutor.fake"; + SPF spf = createCustomSPF(new DNSServiceXBillImpl(elevenPtrNamesOfTheClient(hostname, 10))); + + SPFResult result = spf.checkSPF("1.2.3.4", "a_user@" + hostname, hostname); + + // RFC 7208 4.6.4: "all records other than the first 10 MUST be ignored" + assertEquals(SPFErrorConstants.PASS_CONV, result.getResult()); + } + + @Test(timeout = 10000) + public void ptrShouldIgnoreTheEleventhOfMoreThanTenNames() throws IOException { + String hostname = "ptrlimit11.spfexecutor.fake"; + SPF spf = createCustomSPF(new DNSServiceXBillImpl(elevenPtrNamesOfTheClient(hostname, 11))); + + SPFResult result = spf.checkSPF("1.2.3.4", "a_user@" + hostname, hostname); + + assertEquals(SPFErrorConstants.FAIL_CONV, result.getResult()); + } + @Test(timeout = 10000) public void ptrShouldNotMatchALabelHoldingADotAsASubdomain() throws IOException { String hostname = "ptrlabel.spfexecutor.fake"; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
