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 920ec4d676b061f55d39f4dd923fb0e07dfa978d
Author: Quan Tran <[email protected]>
AuthorDate: Fri Oct 30 16:55:04 2026 +0700

    [FIX] DNSServiceXBillImpl: convert the answer records of the type asked for
    
    convertRecordsToList cast each record on its getType() only. dnsjava
    parses a record without data as an EmptyRecord that keeps the type of
    the record it stands for, so such an answer (here a TXT of RDLENGTH 0
    in an UPDATE message) threw ClassCastException: the check ended as
    neutral. The answer could also hold records of another type, returned
    as answers (a TXT string for an AAAA query, through getRecordsAsync).
    
    Keep the records of the type asked for, and treat a record of none of
    the classes converted as a record of an unknown type: no data.
---
 .../apache/james/jspf/impl/DNSServiceXBillImpl.java | 21 +++++++++++++++++++--
 .../apache/james/jspf/DNSServiceXBillImplTest.java  | 14 ++++++++++++++
 2 files changed, 33 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 fbb8eb9..ed36c7f 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
@@ -22,6 +22,7 @@ package org.apache.james.jspf.impl;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
@@ -54,6 +55,16 @@ import org.xbill.DNS.lookup.LookupSession;
 public class DNSServiceXBillImpl implements DNSService {
     private static final Logger LOGGER = 
LoggerFactory.getLogger(DNSServiceXBillImpl.class);
 
+    /**
+     * @return the records of the given type: an answer can hold others
+     */
+    private static Record[] ofType(Record[] rr, int type) {
+        if (rr == null) {
+            return null;
+        }
+        return Arrays.stream(rr).filter(record -> record.getType() == 
type).toArray(Record[]::new);
+    }
+
     // The record limit for lookups
     protected int recordLimit;
 
@@ -161,7 +172,7 @@ public class DNSServiceXBillImpl implements DNSService {
                 throw new TimeoutException(query.getErrorString());
             }
             
-            List<String> records = convertRecordsToList(rr);
+            List<String> records = convertRecordsToList(ofType(rr, 
dnsJavaType));
             
             LOGGER.debug("Found {} {}-Records", (rr != null ? rr.length : 0), 
recordTypeDescription);
             return records;
@@ -191,7 +202,7 @@ public class DNSServiceXBillImpl implements DNSService {
 
         try {
             return 
lookupSession.lookupAsync(Name.fromString(request.getHostname()), dnsJavaType)
-                .thenApply(result -> 
convertRecordsToList(result.getRecords().toArray(new Record[0])));
+                .thenApply(result -> 
convertRecordsToList(ofType(result.getRecords().toArray(new Record[0]), 
dnsJavaType)));
         } catch (TextParseException e) {
             // no record, as getRecords answers
             LOGGER.debug("No {} Record found for host: {}", 
recordTypeDescription, request.getHostname());
@@ -211,6 +222,12 @@ public class DNSServiceXBillImpl implements DNSService {
         if (rr != null && rr.length > 0) {
             records = new ArrayList<String>();
             for (int i = 0; i < rr.length; i++) {
+                // a record without data (dnsjava's EmptyRecord) has the type 
of the record it stands for,
+                // not its class: as a record of another type, it makes no data
+                if (!(rr[i] instanceof ARecord || rr[i] instanceof AAAARecord 
|| rr[i] instanceof MXRecord
+                        || rr[i] instanceof PTRRecord || rr[i] instanceof 
TXTRecord || rr[i] instanceof SPFRecord)) {
+                    return null;
+                }
                 switch (rr[i].getType()) {
                     case Type.A:
                         ARecord a = (ARecord) rr[i];
diff --git 
a/resolver/src/test/java/org/apache/james/jspf/DNSServiceXBillImplTest.java 
b/resolver/src/test/java/org/apache/james/jspf/DNSServiceXBillImplTest.java
index e51969a..22c556a 100644
--- a/resolver/src/test/java/org/apache/james/jspf/DNSServiceXBillImplTest.java
+++ b/resolver/src/test/java/org/apache/james/jspf/DNSServiceXBillImplTest.java
@@ -23,18 +23,22 @@ package org.apache.james.jspf;
 import org.apache.james.jspf.impl.DNSServiceXBillImpl;
 import org.junit.Test;
 import org.xbill.DNS.DClass;
+import org.xbill.DNS.Message;
 import org.xbill.DNS.Name;
 import org.xbill.DNS.Record;
 import org.xbill.DNS.SPFRecord;
+import org.xbill.DNS.Section;
 import org.xbill.DNS.TXTRecord;
 import org.xbill.DNS.Type;
 
 import java.net.UnknownHostException;
+import java.util.Base64;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 
 public class DNSServiceXBillImplTest {
     @Test
@@ -73,4 +77,14 @@ public class DNSServiceXBillImplTest {
         assertEquals("quoted string", records.get(0));
     }
 
+    @Test
+    public void convertRecordsToListShouldIgnoreAnswersWithoutData() throws 
Exception {
+        // an UPDATE message holding a TXT answer of RDLENGTH 0: dnsjava 
parses it as an EmptyRecord of type TXT
+        byte[] message = 
Base64.getDecoder().decode("AAEpgAABAAEAAAAAB2V4YW1wbGUDY29tAIGDAAHADAAQAAEAAA4QAABs");
+        Record[] answer = new 
Message(message).getSection(Section.ANSWER).toArray(new Record[0]);
+
+        assertEquals(Type.TXT, answer[0].getType());
+        assertNull(DNSServiceXBillImpl.convertRecordsToList(answer));
+    }
+
 }


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

Reply via email to