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 c7da02b3cc1917cafa7e18c5adc669e119a84549 Author: Quan Tran <[email protected]> AuthorDate: Thu Nov 5 10:13:22 2026 +0700 [FIX] DNSTestingServer: no extended rcode in the OPT record of an answer DNSTestingServer, derived from dnsjava's jnamed, gave the rcode of an answer to the OPT record it adds for a query with EDNS, as its extended rcode: the upper 8 bits of a 12-bit rcode (RFC 6891 6.1.3). Its answers of no data and NXDOMAIN, whose rcode is 3 for both inside the server, then read as rcode 48 and 51, errors. dnsjava's Lookup reads only the 4 bits of the header, so the YAML suites run over this server never noticed. Leave the extended bits 0: the rcode, NOERROR or NXDOMAIN, is in the header. A package-private constructor builds the server without its network listeners, for its test. --- .../james/jspf/tester/DNSTestingServerTest.java | 66 ++++++++++++++++++++++ .../apache/james/jspf/tester/DNSTestingServer.java | 10 +++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/resolver/src/test/java/org/apache/james/jspf/tester/DNSTestingServerTest.java b/resolver/src/test/java/org/apache/james/jspf/tester/DNSTestingServerTest.java new file mode 100644 index 0000000..36b51b3 --- /dev/null +++ b/resolver/src/test/java/org/apache/james/jspf/tester/DNSTestingServerTest.java @@ -0,0 +1,66 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.jspf.tester; + +import org.junit.Test; +import org.xbill.DNS.DClass; +import org.xbill.DNS.Message; +import org.xbill.DNS.Name; +import org.xbill.DNS.OPTRecord; +import org.xbill.DNS.Rcode; +import org.xbill.DNS.Record; +import org.xbill.DNS.Section; +import org.xbill.DNS.Type; + +import java.io.IOException; +import java.util.Collections; + +import static org.junit.Assert.assertEquals; + +public class DNSTestingServerTest { + /** + * @return the answer of a server holding a TXT record of example.com to an EDNS query + */ + private static Message answerOf(String name, int type) throws IOException { + DNSTestingServer server = new DNSTestingServer(); + server.setData(Collections.singletonMap("example.com", + Collections.singletonList(Collections.singletonMap("TXT", "v=spf1 -all")))); + Message query = Message.newQuery(Record.newRecord(Name.fromString(name), type, DClass.IN)); + query.addRecord(new OPTRecord(1232, 0, 0), Section.ADDITIONAL); + byte[] wire = query.toWire(); + + return new Message(server.generateReply(wire, wire.length)); + } + + @Test(timeout = 10000) + public void shouldAnswerNxdomainToAnEdnsQueryOfANameThatDoesNotExist() throws Exception { + Message answer = answerOf("other.example.com.", Type.TXT); + + // the rcode is in the header, the OPT record holds no extended bits (RFC 6891 6.1.3) + assertEquals(Rcode.NXDOMAIN, answer.getRcode()); + } + + @Test(timeout = 10000) + public void shouldAnswerNoErrorToAnEdnsQueryOfATypeTheNameHasNot() throws Exception { + Message answer = answerOf("example.com.", Type.A); + + assertEquals(Rcode.NOERROR, answer.getRcode()); + } +} diff --git a/tester/src/main/java/org/apache/james/jspf/tester/DNSTestingServer.java b/tester/src/main/java/org/apache/james/jspf/tester/DNSTestingServer.java index 60a1125..c1ebb85 100644 --- a/tester/src/main/java/org/apache/james/jspf/tester/DNSTestingServer.java +++ b/tester/src/main/java/org/apache/james/jspf/tester/DNSTestingServer.java @@ -128,6 +128,13 @@ public class DNSTestingServer implements ResponseGenerator { zone = null; } + /** + * A server that only generates replies, without listening on the network: for tests + */ + DNSTestingServer() { + zone = null; + } + @SuppressWarnings("unchecked") public synchronized void setData(Map<String, List<?>> map) { try { @@ -462,7 +469,8 @@ public class DNSTestingServer implements ResponseGenerator { if (queryOPT != null) { int optflags = (flags == FLAG_DNSSECOK) ? ExtendedFlags.DO : 0; - OPTRecord opt = new OPTRecord((short) 4096, rcode, (byte) 0, + // the rcode, NOERROR or NXDOMAIN, is in the header: no extended bits (RFC 6891 6.1.3) + OPTRecord opt = new OPTRecord((short) 4096, 0, (byte) 0, optflags); response.addRecord(opt, Section.ADDITIONAL); } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
