File bind-9.11-CVE-2025-40778.patch of Package bind.41417

commit 2951ecac67415efbd3d238e1887f077cfb6ef6c8
Author: Michał Kępień <michal@isc.org>
Date:   Wed Oct 22 18:48:06 2025 +0200

    [9.11] [CVE-2025-40778] sec: usr: Address various spoofing attacks
    
    Previously, several issues could be exploited to poison a DNS cache with
    spoofed records for zones which were not DNSSEC-signed or if the
    resolver was configured to not do DNSSEC validation. These issues were
    assigned CVE-2025-40778 and have now been fixed.
    
    As an additional layer of protection, :iscman:`named` no longer accepts
    DNAME records or extraneous NS records in the AUTHORITY section unless
    these are received via spoofing-resistant transport (TCP, UDP with DNS
    cookies, TSIG, or SIG(0)).
    
    ISC would like to thank Yuxiao Wu, Yunyi Zhang, Baojun Liu, and Haixin
    Duan from Tsinghua University for bringing this vulnerability to our
    attention.
    
    Backport of !838
    
    Closes isc-projects/bind9#5414
    
    Merge branch '5414-security-check-name-vs-qname-again-9.11' into 'bind-9.11-release'
    
    See merge request isc-private/bind9!862

diff --git a/bin/tests/system/chain/ans3/ans.pl b/bin/tests/system/chain/ans3/ans.pl
deleted file mode 100644
index cdbfc84c13..0000000000
--- a/bin/tests/system/chain/ans3/ans.pl
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/usr/bin/env perl
-#
-# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-# See the COPYRIGHT file distributed with this work for additional
-# information regarding copyright ownership.
-
-use strict;
-use warnings;
-
-use IO::File;
-use Getopt::Long;
-use Net::DNS::Nameserver;
-
-my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!";
-print $pidf "$$\n" or die "cannot write pid file: $!";
-$pidf->close or die "cannot close pid file: $!";
-sub rmpid { unlink "ans.pid"; exit 1; };
-
-$SIG{INT} = \&rmpid;
-$SIG{TERM} = \&rmpid;
-
-my $localaddr = "10.53.0.3";
-
-my $localport = int($ENV{'PORT'});
-if (!$localport) { $localport = 5300; }
-
-my $verbose = 0;
-my $ttl = 60;
-my $zone = "example.broken";
-my $nsname = "ns3.$zone";
-my $synth = "synth-then-dname.$zone";
-my $synth2 = "synth2-then-dname.$zone";
-
-sub reply_handler {
-    my ($qname, $qclass, $qtype, $peerhost, $query, $conn) = @_;
-    my ($rcode, @ans, @auth, @add);
-
-    print ("request: $qname/$qtype\n");
-    STDOUT->flush();
-
-    if ($qname eq "example.broken") {
-        if ($qtype eq "SOA") {
-	    my $rr = new Net::DNS::RR("$qname $ttl $qclass SOA . . 0 0 0 0 0");
-	    push @ans, $rr;
-        } elsif ($qtype eq "NS") {
-	    my $rr = new Net::DNS::RR("$qname $ttl $qclass NS $nsname");
-	    push @ans, $rr;
-	    $rr = new Net::DNS::RR("$nsname $ttl $qclass A $localaddr");
-	    push @add, $rr;
-        }
-        $rcode = "NOERROR";
-    } elsif ($qname eq "cname-to-$synth2") {
-        my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name.$synth2");
-	push @ans, $rr;
-        $rr = new Net::DNS::RR("name.$synth2 $ttl $qclass CNAME name");
-	push @ans, $rr;
-        $rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME .");
-	push @ans, $rr;
-	$rcode = "NOERROR";
-    } elsif ($qname eq "$synth" || $qname eq "$synth2") {
-	if ($qtype eq "DNAME") {
-	    my $rr = new Net::DNS::RR("$qname $ttl $qclass DNAME .");
-	    push @ans, $rr;
-	}
-	$rcode = "NOERROR";
-    } elsif ($qname eq "name.$synth") {
-	my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name.");
-	push @ans, $rr;
-	$rr = new Net::DNS::RR("$synth $ttl $qclass DNAME .");
-	push @ans, $rr;
-	$rcode = "NOERROR";
-    } elsif ($qname eq "name.$synth2") {
-	my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name.");
-	push @ans, $rr;
-	$rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME .");
-	push @ans, $rr;
-	$rcode = "NOERROR";
-    } else {
-	$rcode = "REFUSED";
-    }
-    return ($rcode, \@ans, \@auth, \@add, { aa => 1 });
-}
-
-GetOptions(
-    'port=i' => \$localport,
-    'verbose!' => \$verbose,
-);
-
-my $ns = Net::DNS::Nameserver->new(
-    LocalAddr => $localaddr,
-    LocalPort => $localport,
-    ReplyHandler => \&reply_handler,
-    Verbose => $verbose,
-);
-
-$ns->main_loop;
diff --git a/bin/tests/system/chain/ans3/ans.py b/bin/tests/system/chain/ans3/ans.py
new file mode 100644
index 0000000000..d6d4eea6d9
--- /dev/null
+++ b/bin/tests/system/chain/ans3/ans.py
@@ -0,0 +1,216 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0.  If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+############################################################################
+# ans.py: See README.anspy for details.
+############################################################################
+
+from __future__ import print_function
+import os
+import sys
+import signal
+import socket
+import select
+from datetime import datetime, timedelta
+import functools
+
+import dns, dns.message, dns.query
+from dns.rdatatype import *
+from dns.rdataclass import *
+from dns.rcode import *
+from dns.name import *
+
+############################################################################
+# Respond to a DNS query.
+############################################################################
+def create_response(msg):
+    ttl = 60
+    zone = "example.broken."
+    nsname = "ns3." + zone
+    synth = "synth-then-dname." + zone
+    synth2 = "synth2-then-dname." + zone
+
+    m = dns.message.from_wire(msg)
+    qname = m.question[0].name.to_text()
+
+    # prepare the response and convert to wire format
+    r = dns.message.make_response(m)
+
+    # get qtype
+    rrtype = m.question[0].rdtype
+    qtype = dns.rdatatype.to_text(rrtype)
+    print("request: " + qname + "/" + qtype)
+
+    rcode = "NOERROR"
+    if qname == zone:
+        if qtype == "SOA":
+            r.answer.append(dns.rrset.from_text(qname, ttl, IN, SOA, ". . 0 0 0 0 0"))
+        elif qtype == "NS":
+            r.answer.append(dns.rrset.from_text(qname, ttl, IN, NS, nsname))
+            r.additional.append(dns.rrset.from_text(nsname, ttl, IN, A, ip4))
+    elif qname == "cname-to-" + synth2:
+        r.answer.append(dns.rrset.from_text(qname, ttl, IN, CNAME, "name." + synth2))
+        r.answer.append(dns.rrset.from_text("name." + synth2, ttl, IN, CNAME, "name."))
+        r.answer.append(dns.rrset.from_text(synth2, ttl, IN, DNAME, "."))
+    elif qname == synth or qname == synth2:
+        if qtype == "DNAME":
+            r.answer.append(dns.rrset.from_text(qname, ttl, IN, DNAME, "."))
+    elif qname == "name." + synth:
+        r.answer.append(dns.rrset.from_text(qname, ttl, IN, CNAME, "name."))
+        r.answer.append(dns.rrset.from_text(synth, ttl, IN, DNAME, "."))
+    elif qname == "name." + synth2:
+        r.answer.append(dns.rrset.from_text(qname, ttl, IN, CNAME, "name."))
+        r.answer.append(dns.rrset.from_text(synth2, ttl, IN, DNAME, "."))
+    elif qname == "ns3.example.dname.":
+        # This and the next two code branches referring to the "example.dname"
+        # zone are necessary for the resolver variant of the CVE-2021-25215
+        # regression test to work.  A named instance cannot be used for
+        # serving the DNAME records below as a version of BIND vulnerable to
+        # CVE-2021-25215 would crash while answering the queries asked by
+        # the tested resolver.
+        if qtype == "A":
+            r.answer.append(dns.rrset.from_text(qname, ttl, IN, A, ip4))
+        elif qtype == "AAAA":
+            r.authority.append(
+                dns.rrset.from_text("example.dname.", ttl, IN, SOA, ". . 0 0 0 0 0")
+            )
+    elif qname == "self.example.self..example.dname.":
+        r.answer.append(
+            dns.rrset.from_text("self.example.dname.", ttl, IN, DNAME, "dname.")
+        )
+        r.answer.append(
+            dns.rrset.from_text(qname, ttl, IN, CNAME, "self.example.dname.")
+        )
+    elif qname == "self.example.dname.":
+        if qtype == "DNAME":
+            r.answer.append(dns.rrset.from_text(qname, ttl, IN, DNAME, "dname."))
+    else:
+        rcode = "REFUSED"
+
+    r.flags |= dns.flags.AA
+    r.use_edns()
+    return r.to_wire()
+
+
+def sigterm(signum, frame):
+    print("Shutting down now...")
+    os.remove("ans.pid")
+    running = False
+    sys.exit(0)
+
+
+############################################################################
+# Main
+#
+# Set up responder and control channel, open the pid file, and start
+# the main loop, listening for queries on the query channel or commands
+# on the control channel and acting on them.
+############################################################################
+ip4 = "10.53.0.3"
+ip6 = "fd92:7065:b8e:ffff::3"
+
+try:
+    port = int(os.environ["PORT"])
+except:
+    port = 5300
+
+query4_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+query4_udp.bind((ip4, port))
+
+query4_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+query4_tcp.bind((ip4, port))
+query4_tcp.listen(1)
+query4_tcp.settimeout(1)
+
+havev6 = True
+try:
+    query6_udp = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
+    try:
+        query6_udp.bind((ip6, port))
+    except:
+        query6_udp.close()
+        havev6 = False
+
+    query6_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    try:
+        query6_tcp.bind((ip4, port))
+        query6_tcp.listen(1)
+        query6_tcp.settimeout(1)
+    except:
+        query6_tcp.close()
+        havev6 = False
+except:
+    havev6 = False
+
+signal.signal(signal.SIGTERM, sigterm)
+
+f = open("ans.pid", "w")
+pid = os.getpid()
+print(pid, file=f)
+f.close()
+
+running = True
+
+print("Listening on %s port %d" % (ip4, port))
+if havev6:
+    print("Listening on %s port %d" % (ip6, port))
+print("Ctrl-c to quit")
+
+if havev6:
+    input = [query4_udp, query4_tcp, query6_udp, query6_tcp]
+else:
+    input = [query4_udp, query4_tcp]
+
+while running:
+    try:
+        inputready, outputready, exceptready = select.select(input, [], [])
+    except select.error as e:
+        break
+    except socket.error as e:
+        break
+    except KeyboardInterrupt:
+        break
+
+    for s in inputready:
+        if s == query4_udp or s == query6_udp:
+            print("Query received on %s" % (ip4 if s == query4_udp else ip6))
+            # Handle incoming queries
+            msg = s.recvfrom(65535)
+            rsp = create_response(msg[0])
+            if rsp:
+                s.sendto(rsp, msg[1])
+        elif s == query4_tcp or s == query6_tcp:
+            try:
+                conn, _ = s.accept()
+                if s == query4_tcp or s == query6_tcp:
+                    print(
+                        "TCP Query received on %s" % (ip4 if s == query4_tcp else ip6),
+                        end=" ",
+                    )
+                # get TCP message length
+                msg = conn.recv(2)
+                if len(msg) != 2:
+                    print("couldn't read TCP message length")
+                    continue
+                length = struct.unpack(">H", msg[:2])[0]
+                msg = conn.recv(length)
+                if len(msg) != length:
+                    print("couldn't read TCP message")
+                    continue
+                rsp = create_response(msg)
+                if rsp:
+                    conn.send(struct.pack(">H", len(rsp)))
+                    conn.send(rsp)
+                conn.close()
+            except socket.error as e:
+                print("error: %s" % str(e))
+    if not running:
+        break
diff --git a/bin/tests/system/chain/ans4/ans.py b/bin/tests/system/chain/ans4/ans.py
index 88a06cae99..85901295df 100755
--- a/bin/tests/system/chain/ans4/ans.py
+++ b/bin/tests/system/chain/ans4/ans.py
@@ -276,16 +276,30 @@ except: port=5300
 try: ctrlport=int(os.environ['EXTRAPORT1'])
 except: ctrlport=5300
 
-query4_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-query4_socket.bind((ip4, port))
+query4_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+query4_udp.bind((ip4, port))
+
+query4_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+query4_tcp.bind((ip4, port))
+query4_tcp.listen(1)
+query4_tcp.settimeout(1)
 
 havev6 = True
 try:
-    query6_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
+    query6_udp = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
+    try:
+        query6_udp.bind((ip6, port))
+    except:
+        query6_udp.close()
+        havev6 = False
+
+    query6_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     try:
-        query6_socket.bind((ip6, port))
+        query6_tcp.bind((ip4, port))
+        query6_tcp.listen(1)
+        query6_tcp.settimeout(1)
     except:
-        query6_socket.close()
+        query6_tcp.close()
         havev6 = False
 except:
     havev6 = False
@@ -310,9 +324,9 @@ print ("Control channel on %s port %d" % (ip4, ctrlport))
 print ("Ctrl-c to quit")
 
 if havev6:
-    input = [query4_socket, query6_socket, ctrl_socket]
+    input = [query4_udp, query4_tcp, query6_udp, query6_tcp, ctrl_socket]
 else:
-    input = [query4_socket, ctrl_socket]
+    input = [query4_udp, query4_tcp, ctrl_socket]
 
 while running:
     try:
@@ -335,13 +349,37 @@ while running:
                     break
                 ctl_channel(msg)
             conn.close()
-        if s == query4_socket or s == query6_socket:
-            print ("Query received on %s" %
-                    (ip4 if s == query4_socket else ip6))
+        elif s == query4_udp or s == query6_udp:
+            print("Query received on %s" % (ip4 if s == query4_udp else ip6))
             # Handle incoming queries
             msg = s.recvfrom(65535)
             rsp = create_response(msg[0])
             if rsp:
                 s.sendto(rsp, msg[1])
+        elif s == query4_tcp or s == query6_tcp:
+            try:
+                conn, _ = s.accept()
+                if s == query4_tcp or s == query6_tcp:
+                    print(
+                        "TCP Query received on %s" % (ip4 if s == query4_tcp else ip6),
+                        end=" ",
+                    )
+                # get TCP message length
+                msg = conn.recv(2)
+                if len(msg) != 2:
+                    print("couldn't read TCP message length")
+                    continue
+                length = struct.unpack(">H", msg[:2])[0]
+                msg = conn.recv(length)
+                if len(msg) != length:
+                    print("couldn't read TCP message")
+                    continue
+                rsp = create_response(msg)
+                if rsp:
+                    conn.send(struct.pack(">H", len(rsp)))
+                    conn.send(rsp)
+                conn.close()
+            except socket.error as e:
+                print("error: %s" % str(e))
     if not running:
         break
diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h
index 40490d794b..a70098619c 100644
--- a/lib/dns/include/dns/message.h
+++ b/lib/dns/include/dns/message.h
@@ -224,6 +224,7 @@ struct dns_message {
 	unsigned int			cc_bad : 1;
 	unsigned int			tkey : 1;
 	unsigned int			rdclass_set : 1;
+	unsigned int			has_dname : 1;
 
 	unsigned int			opt_reserved;
 	unsigned int			sig_reserved;
@@ -1397,6 +1398,13 @@ dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass);
  * \li   msg be a valid message with parsing intent.
  */
 
+bool
+dns_message_hasdname(dns_message_t *msg);
+/*%<
+ * Return whether a DNAME was detected in the ANSWER section of a QUERY
+ * message when it was parsed.
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_MESSAGE_H */
diff --git a/lib/dns/message.c b/lib/dns/message.c
index e6d090f94c..4e4427e1cb 100644
--- a/lib/dns/message.c
+++ b/lib/dns/message.c
@@ -458,6 +458,7 @@ msginit(dns_message_t *m) {
 	m->cc_bad = 0;
 	m->tkey = 0;
 	m->rdclass_set = 0;
+	m->has_dname = 0;
 	m->querytsig = NULL;
 }
 
@@ -1807,6 +1808,11 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
 			 */
 			msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
 			free_name = false;
+		} else if (rdtype == dns_rdatatype_dname &&
+			   sectionid == DNS_SECTION_ANSWER &&
+			   msg->opcode == dns_opcode_query)
+		{
+			msg->has_dname = 1;
 		}
 		rdataset = NULL;
 
@@ -4678,3 +4684,9 @@ dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) {
 	msg->rdclass = rdclass;
 	msg->rdclass_set = 1;
 }
+
+bool
+dns_message_hasdname(dns_message_t *msg) {
+	REQUIRE(DNS_MESSAGE_VALID(msg));
+	return msg->has_dname;
+}
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
index c7cb854eba..89f9aede91 100644
--- a/lib/dns/resolver.c
+++ b/lib/dns/resolver.c
@@ -278,6 +278,7 @@ struct fetchctx {
 	unsigned int			dbucketnum;
 	char *				info;
 	isc_mem_t *			mctx;
+	dns_name_t *			ns_name;
 
 	/*% Locked by appropriate bucket lock. */
 	fetchstate			state;
@@ -6218,7 +6219,9 @@ mark_related(dns_name_t *name, dns_rdataset_t *rdataset,
  * locally served zone.
  */
 static inline bool
-name_external(dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) {
+name_external(dns_name_t *name, dns_name_t *ns_name, dns_rdatatype_t type,
+	      fetchctx_t *fctx)
+{
 	isc_result_t result;
 	dns_forwarders_t *forwarders = NULL;
 	dns_fixedname_t fixed, zfixed;
@@ -6230,7 +6233,9 @@ name_external(dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) {
 	unsigned int labels;
 	dns_namereln_t rel;
 
-	apex = ISFORWARDER(fctx->addrinfo) ? fctx->fwdname : &fctx->domain;
+	apex = ISFORWARDER(fctx->addrinfo)
+		? fctx->fwdname
+		: (ns_name != NULL) ? ns_name : &fctx->domain;
 
 	/*
 	 * The name is outside the queried namespace.
@@ -6338,7 +6343,7 @@ check_section(void *arg, dns_name_t *addname, dns_rdatatype_t type,
 	result = dns_message_findname(fctx->rmessage, section, addname,
 				      dns_rdatatype_any, 0, &name, NULL);
 	if (result == ISC_R_SUCCESS) {
-		external = name_external(name, type, fctx);
+		external = name_external(name, fctx->ns_name, type, fctx);
 		if (type == dns_rdatatype_a) {
 			for (rdataset = ISC_LIST_HEAD(name->list);
 			     rdataset != NULL;
@@ -7049,6 +7054,8 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname,
 		 */
 		INSIST(ns_rdataset != NULL);
 		FCTX_ATTR_SET(fctx, FCTX_ATTR_GLUING);
+		fctx->ns_name = ns_name;
+
 		/*
 		 * Mark the glue records in the additional section to be cached.
 		 */
@@ -7141,8 +7148,9 @@ validinanswer(dns_rdataset_t *rdataset, fetchctx_t *fctx) {
 }
 
 static isc_result_t
-answer_response(fetchctx_t *fctx) {
+answer_response(resquery_t *query) {
 	isc_result_t result;
+	fetchctx_t *fctx = NULL;
 	dns_message_t *message = NULL;
 	dns_name_t *name = NULL, *qname = NULL, *ns_name = NULL;
 	dns_name_t *aname = NULL, *cname = NULL, *dname = NULL;
@@ -7156,6 +7164,8 @@ answer_response(fetchctx_t *fctx) {
 	dns_view_t *view = NULL;
 	dns_trust_t trust;
 
+	REQUIRE(VALID_QUERY(query));
+	fctx = query->fctx;
 	REQUIRE(VALID_FCTX(fctx));
 
 	FCTXTRACE("answer_response");
@@ -7221,7 +7231,9 @@ answer_response(fetchctx_t *fctx) {
 			/*
 			 * Don't accept DNAME from parent namespace.
 			 */
-			if (name_external(name, dns_rdatatype_dname, fctx)) {
+			if (name_external(name, NULL, dns_rdatatype_dname,
+					  fctx))
+			{
 				continue;
 			}
 
@@ -7303,6 +7315,7 @@ answer_response(fetchctx_t *fctx) {
 			rdataset->attributes |= DNS_RDATASETATTR_ANSWER;
 			rdataset->attributes |= DNS_RDATASETATTR_CACHE;
 			rdataset->trust = trust;
+			fctx->ns_name = ns_name;
 			(void)dns_rdataset_additionaldata(rdataset,
 							  check_related,
 							  fctx, 0);
@@ -7329,6 +7342,7 @@ answer_response(fetchctx_t *fctx) {
 		ardataset->attributes |= DNS_RDATASETATTR_ANSWER;
 		ardataset->attributes |= DNS_RDATASETATTR_CACHE;
 		ardataset->trust = trust;
+		fctx->ns_name = ns_name;
 		(void)dns_rdataset_additionaldata(ardataset, check_related,
 						  fctx, 0);
 		for (sigrdataset = ISC_LIST_HEAD(aname->list);
@@ -7450,12 +7464,23 @@ answer_response(fetchctx_t *fctx) {
 	 *
 	 * We expect there to be only one owner name for all the rdatasets
 	 * in this section, and we expect that it is not external.
+	 *
+	 * If the message was not sent over TCP or otherwise secured,
+	 * skip this.
 	 */
-	result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+	if (message->cc_ok || message->tsig != NULL || message->sig0 != NULL ||
+	    (query->options & DNS_FETCHOPT_TCP) != 0)
+	{
+		result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
+	} else {
+		done = true;
+	}
 	while (!done && result == ISC_R_SUCCESS) {
 		name = NULL;
 		dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
-		if (!name_external(name, dns_rdatatype_ns, fctx)) {
+		if (!name_external(name, ns_name, dns_rdatatype_ns, fctx) &&
+		    dns_name_issubdomain(&fctx->name, name))
+		{
 			/*
 			 * We expect to find NS or SIG NS rdatasets, and
 			 * nothing else.
@@ -7487,6 +7512,7 @@ answer_response(fetchctx_t *fctx) {
 					 * Mark any additional data related
 					 * to this rdataset.
 					 */
+					fctx->ns_name = ns_name;
 					(void)dns_rdataset_additionaldata(
 							rdataset,
 							check_related,
@@ -8601,7 +8627,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
 		if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 ||
 		    ISFORWARDER(query->addrinfo))
 		{
-			result = answer_response(fctx);
+			result = answer_response(query);
 			if (result != ISC_R_SUCCESS)
 				FCTXTRACE3("answer_response (AA/fwd)", result);
 		} else if (iscname(fctx) &&
@@ -8613,7 +8639,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
 			 * answer when a CNAME is followed.  We should treat
 			 * it as a valid answer.
 			 */
-			result = answer_response(fctx);
+			result = answer_response(query);
 			if (result != ISC_R_SUCCESS)
 				FCTXTRACE3("answer_response (!ANY/!CNAME)",
 					   result);
@@ -8622,7 +8648,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
 			/*
 			 * Lame response !!!.
 			 */
-			result = answer_response(fctx);
+			result = answer_response(query);
 			if (result != ISC_R_SUCCESS)
 				FCTXTRACE3("answer_response (!NS)", result);
 		} else {
openSUSE Build Service is sponsored by