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 18885745350e2146d0b73ab04ac3c7c4c65bb462
Author: Quan Tran <[email protected]>
AuthorDate: Thu Nov 5 13:12:29 2026 +0700

    [FIX] a/mx mechanisms: a CIDR length with a leading zero is a permerror
    
    The a and mx mechanisms read a CIDR length with a leading zero, as
    "a/024" or "mx//064", as the number, where the ip4 mechanism already
    gives permerror: RFC 7208 5.6 allows "0" or a number without a leading
    zero, ip4-cidr-length = "/" ("0" / %x31-39 0*1DIGIT) and
    ip6-cidr-length = "/" ("0" / %x31-39 0*2DIGIT), and a record that does
    not match the grammar is a permerror (4.6).
    
    Reject such a length in AMechanism, which MXMechanism extends. "/0"
    stays valid.
---
 .../org/apache/james/jspf/terms/AMechanism.java    |  7 ++---
 .../org/apache/james/jspf/SPFExecutorBaseTest.java | 30 ++++++++++++++++++++++
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/resolver/src/main/java/org/apache/james/jspf/terms/AMechanism.java 
b/resolver/src/main/java/org/apache/james/jspf/terms/AMechanism.java
index c7f4098..f5b4ba8 100644
--- a/resolver/src/main/java/org/apache/james/jspf/terms/AMechanism.java
+++ b/resolver/src/main/java/org/apache/james/jspf/terms/AMechanism.java
@@ -112,9 +112,10 @@ public class AMechanism extends GenericMechanism 
implements SPFCheckerDNSRespons
      */
     public synchronized void config(Configuration params) throws 
PermErrorException {
         super.config(params);
-        // the regex accepts any number of digits: more than 3 are invalid, 
and could overflow an int
+        // the regex accepts any number of digits: more than 3, which could 
overflow an int, or a leading zero, as
+        // in "a/024", are invalid (RFC 7208 5.6: "0" / %x31-39 0*1DIGIT, or 
0*2DIGIT for ip6-cidr-length)
         if (params.groupCount() >= 2 && params.group(2) != null) {
-            if (params.group(2).length() > 3) {
+            if (params.group(2).length() > 3 || (params.group(2).length() > 1 
&& params.group(2).startsWith("0"))) {
                 throw new PermErrorException("Ivalid IP4 CIDR length");
             }
             ip4cidr = Integer.parseInt(params.group(2));
@@ -125,7 +126,7 @@ public class AMechanism extends GenericMechanism implements 
SPFCheckerDNSRespons
             ip4cidr = 32;
         }
         if (params.groupCount() >= 3 && params.group(3) != null) {
-            if (params.group(3).length() > 3) {
+            if (params.group(3).length() > 3 || (params.group(3).length() > 1 
&& params.group(3).startsWith("0"))) {
                 throw new PermErrorException("Ivalid IP6 CIDR length");
             }
             ip6cidr = Integer.parseInt(params.group(3).toString());
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 def8399..4710ee5 100644
--- a/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java
+++ b/resolver/src/test/java/org/apache/james/jspf/SPFExecutorBaseTest.java
@@ -1326,6 +1326,36 @@ public abstract class SPFExecutorBaseTest {
         assertEquals(SPFErrorConstants.PERM_ERROR_CONV, result.getResult());
     }
 
+    @Test(timeout = 10000)
+    public void shouldReturnPermErrorOnAIp4CidrWithALeadingZero() throws 
IOException {
+        SPFResult result = checkRecord("aIp4CidrZero.spfexecutor.fake", 
"v=spf1 a/024 -all", "1.2.3.4");
+
+        // RFC 7208 5.6: ip4-cidr-length = "/" ("0" / %x31-39 0*1DIGIT)
+        assertEquals(SPFErrorConstants.PERM_ERROR_CONV, result.getResult());
+    }
+
+    @Test(timeout = 10000)
+    public void shouldReturnPermErrorOnMxIp6CidrWithALeadingZero() throws 
IOException {
+        SPFResult result = checkRecord("mxIp6CidrZero.spfexecutor.fake", 
"v=spf1 mx//064 -all", "1.2.3.4");
+
+        // RFC 7208 5.6: ip6-cidr-length = "/" ("0" / %x31-39 0*2DIGIT)
+        assertEquals(SPFErrorConstants.PERM_ERROR_CONV, result.getResult());
+    }
+
+    @Test(timeout = 10000)
+    public void shouldAcceptACidrLengthOfZero() throws IOException {
+        String hostname = "aCidrZero.spfexecutor.fake";
+        FakeResolver fakeResolver = new FakeResolver();
+        fakeResolver.addRecord(new TXTRecord(Name.fromString(hostname + "."), 
DClass.IN, 30L, "v=spf1 a/0//0 -all"));
+        fakeResolver.addRecord(new ARecord(Name.fromString(hostname + "."), 
DClass.IN, 30L, InetAddress.getByName("192.0.2.1")));
+        SPF spf = createCustomSPF(new DNSServiceXBillImpl(fakeResolver));
+
+        SPFResult result = spf.checkSPF("1.2.3.4", "a_user@" + hostname, 
hostname);
+
+        // "0" alone is a CIDR length: a/0 matches every IPv4 client of a 
domain having an IPv4 address
+        assertEquals(SPFErrorConstants.PASS_CONV, result.getResult());
+    }
+
     @Test(timeout = 10000)
     public void shouldReturnPermErrorOnMxIp6CidrOverflowingAnInt() throws 
IOException {
         SPFResult result = checkRecord("mxIp6CidrOverflow.spfexecutor.fake", 
"v=spf1 mx//99999999999 -all", "1.2.3.4");


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

Reply via email to