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-project.git


The following commit(s) were added to refs/heads/master by this push:
     new 9eb0bd40d7 [FIX] DNSJavaService: Avoid mutating unmodifiable 
collection and skipping fallback on resolution failure (#3211)
9eb0bd40d7 is described below

commit 9eb0bd40d7731a9d0ea8cc98c7888ca1318d7385
Author: ilya terskov <[email protected]>
AuthorDate: Thu Oct 1 16:25:38 2026 +0700

    [FIX] DNSJavaService: Avoid mutating unmodifiable collection and skipping 
fallback on resolution failure (#3211)
    
    Fixes issues in DNSJavaService.findMXRecords:
    - Avoid modifying unmodifiable collection or throwing 
UnsupportedOperationException when raw MX records list is empty.
    - Do not execute A fallback when TemporaryResolutionException is thrown by 
raw MX lookup.
    - Include unit and non-regression tests in DNSJavaServiceTest.
---
 .../james/dnsservice/dnsjava/DNSJavaService.java   | 31 ++++++++--------
 .../dnsservice/dnsjava/DNSJavaServiceTest.java     | 42 ++++++++++++++++++++++
 2 files changed, 58 insertions(+), 15 deletions(-)

diff --git 
a/server/dns-service/dnsservice-dnsjava/src/main/java/org/apache/james/dnsservice/dnsjava/DNSJavaService.java
 
b/server/dns-service/dnsservice-dnsjava/src/main/java/org/apache/james/dnsservice/dnsjava/DNSJavaService.java
index c366934c0c..e82f2ab6a8 100644
--- 
a/server/dns-service/dnsservice-dnsjava/src/main/java/org/apache/james/dnsservice/dnsjava/DNSJavaService.java
+++ 
b/server/dns-service/dnsservice-dnsjava/src/main/java/org/apache/james/dnsservice/dnsjava/DNSJavaService.java
@@ -315,25 +315,26 @@ public class DNSJavaService implements DNSService, 
DNSServiceMBean, Configurable
     @Override
     public Collection<String> findMXRecords(String hostname) throws 
TemporaryResolutionException {
         TimeMetric timeMetric = metricFactory.timer("findMXRecords");
-        List<String> servers = new ArrayList<>();
         try {
-            servers = findMXRecordsRaw(hostname);
-            return Collections.unmodifiableCollection(servers);
-        } finally {
+            List<String> servers = findMXRecordsRaw(hostname);
+            if (!servers.isEmpty()) {
+                return Collections.unmodifiableCollection(servers);
+            }
+
             // If we found no results, we'll add the original domain name if
             // it's a valid DNS entry
-            if (servers.isEmpty()) {
-                LOGGER.info("Couldn't resolve MX records for domain {}.", 
hostname);
-                try {
-                    getByName(hostname);
-                    servers.add(hostname);
-                } catch (UnknownHostException uhe) {
-                    // The original domain name is not a valid host,
-                    // so we can't add it to the server list. In this
-                    // case we return an empty list of servers
-                    LOGGER.error("Couldn't resolve IP address for host {}.", 
hostname, uhe);
-                }
+            LOGGER.info("Couldn't resolve MX records for domain {}. Falling 
back to A/AAAA resolution instead", hostname);
+            try {
+                getByName(hostname);
+                return ImmutableList.of(hostname);
+            } catch (UnknownHostException uhe) {
+                // The original domain name is not a valid host,
+                // so we can't add it to the server list. In this
+                // case we return an empty list of servers
+                LOGGER.info("Couldn't resolve IP address for host {}.", 
hostname, uhe);
+                return ImmutableList.of();
             }
+        } finally {
             timeMetric.stopAndPublish();
         }
     }
diff --git 
a/server/dns-service/dnsservice-dnsjava/src/test/java/org/apache/james/dnsservice/dnsjava/DNSJavaServiceTest.java
 
b/server/dns-service/dnsservice-dnsjava/src/test/java/org/apache/james/dnsservice/dnsjava/DNSJavaServiceTest.java
index fe3f041a48..b9024c4026 100644
--- 
a/server/dns-service/dnsservice-dnsjava/src/test/java/org/apache/james/dnsservice/dnsjava/DNSJavaServiceTest.java
+++ 
b/server/dns-service/dnsservice-dnsjava/src/test/java/org/apache/james/dnsservice/dnsjava/DNSJavaServiceTest.java
@@ -210,6 +210,48 @@ class DNSJavaServiceTest {
         assertThat(records.size()).isEqualTo(1);
         assertThat(records.contains("mx1.one-mx.bar.")).isTrue();
     }
+
+    @Test
+    void testFindMXRecordsShouldReturnFallbackAddressWhenNoMX() throws 
Exception {
+        doAnswer(new ZoneCacheLookupRecordsAnswer(loadZone("dnstest.com.")))
+                .when(mockedCache).lookupRecords(any(Name.class), anyInt(), 
anyInt());
+        dnsServer.setCache(mockedCache);
+
+        Collection<String> records = 
dnsServer.findMXRecords("nomx.dnstest.com.");
+        assertThat(records).containsExactly("nomx.dnstest.com.");
+    }
+
+    @Test
+    void testFindMXRecordsShouldReturnEmptyCollectionWhenNoMXAndUnknownHost() 
throws Exception {
+        doAnswer(new ZoneCacheLookupRecordsAnswer(loadZone("dnstest.com.")))
+                .when(mockedCache).lookupRecords(any(Name.class), anyInt(), 
anyInt());
+        dnsServer.setCache(mockedCache);
+
+        Collection<String> records = 
dnsServer.findMXRecords("nonexistent.dnstest.com.");
+        assertThat(records).isEmpty();
+    }
+
+    @Test
+    void 
testFindMXRecordsShouldNotExecuteFallbackWhenTemporaryResolutionExceptionThrown()
 {
+        dnsServer.setCache(mockedCache);
+        when(mockedCache.lookupRecords(any(Name.class), anyInt(), anyInt()))
+                .thenThrow(new IllegalStateException("Simulated DNS failure"));
+
+        org.assertj.core.api.Assertions.assertThatThrownBy(() -> 
dnsServer.findMXRecords("dnstest.com."))
+                
.isInstanceOf(org.apache.james.dnsservice.api.TemporaryResolutionException.class);
+    }
+
+    @Test
+    void testFindMXRecordsShouldReturnUnmodifiableCollection() throws 
Exception {
+        doAnswer(new ZoneCacheLookupRecordsAnswer(loadZone("dnstest.com.")))
+                .when(mockedCache).lookupRecords(any(Name.class), anyInt(), 
anyInt());
+        dnsServer.setCache(mockedCache);
+
+        Collection<String> records = dnsServer.findMXRecords("dnstest.com.");
+        org.assertj.core.api.Assertions.assertThatThrownBy(() -> 
records.add("evil.host.com."))
+                .isInstanceOf(UnsupportedOperationException.class);
+    }
+
     /*
      * public void testCNAMEasMXrecords() throws Exception { // Zone z =
      * loadZone("brandilyncollins.com."); dnsServer.setResolver(null);


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

Reply via email to