File bind-CVE-2021-25220.patch of Package bind.37294

Index: bind-9.9.9-P1/bin/named/include/named/query.h
===================================================================
--- bind-9.9.9-P1.orig/bin/named/include/named/query.h
+++ bind-9.9.9-P1/bin/named/include/named/query.h
@@ -66,6 +66,19 @@ struct ns_query {
 	unsigned int			dns64_aaaaoklen;
 	unsigned int			dns64_options;
 	unsigned int			dns64_ttl;
+	struct {
+		dns_db_t *              db;
+		dns_zone_t *            zone;
+		dns_dbnode_t *          node;
+		dns_rdatatype_t         qtype;
+		dns_name_t *            fname;
+		dns_fixedname_t         fixed;
+		isc_result_t            result;
+		dns_rdataset_t *        rdataset;
+		dns_rdataset_t *        sigrdataset;
+		isc_boolean_t           authoritative;
+		isc_boolean_t           is_zone;
+	} redirect;
 };
 
 #define NS_QUERYATTR_RECURSIONOK	0x0001
Index: bind-9.9.9-P1/bin/named/query.c
===================================================================
--- bind-9.9.9-P1.orig/bin/named/query.c
+++ bind-9.9.9-P1/bin/named/query.c
@@ -661,6 +661,17 @@ ns_query_init(ns_client_t *client) {
 	client->query.dns64_sigaaaa = NULL;
 	client->query.dns64_aaaaok = NULL;
 	client->query.dns64_aaaaoklen = 0;
+	client->query.redirect.db = NULL;
+	client->query.redirect.node = NULL;
+	client->query.redirect.zone = NULL;
+	client->query.redirect.qtype = dns_rdatatype_none;
+	client->query.redirect.result = ISC_R_SUCCESS;
+	client->query.redirect.rdataset = NULL;
+	client->query.redirect.sigrdataset = NULL;
+	client->query.redirect.authoritative = isc_boolean_false;
+	client->query.redirect.is_zone  = isc_boolean_false;
+	client->query.redirect.fname =
+		dns_fixedname_initname(&client->query.redirect.fixed);
 	query_reset(client, ISC_FALSE);
 	result = query_newdbversion(client, 3);
 	if (result != ISC_R_SUCCESS) {
@@ -2676,8 +2687,7 @@ query_addsoa(ns_client_t *client, dns_db
 		dns_fixedname_t foundname;
 		dns_name_t *fname;
 
-		dns_fixedname_init(&foundname);
-		fname = dns_fixedname_name(&foundname);
+		fname = dns_fixedname_initname(&foundname);
 
 		result = dns_db_findext(db, name, version, dns_rdatatype_soa,
 					client->query.dboptions, 0, &node,
@@ -2761,8 +2771,7 @@ query_addns(ns_client_t *client, dns_db_
 	name = NULL;
 	rdataset = NULL;
 	node = NULL;
-	dns_fixedname_init(&foundname);
-	fname = dns_fixedname_name(&foundname);
+	fname = dns_fixedname_initname(&foundname);
 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
 	dns_clientinfo_init(&ci, client);
 
@@ -3492,8 +3501,7 @@ query_addwildcardproof(ns_client_t *clie
 	 *	wild *.example
 	 */
 	options = client->query.dboptions | DNS_DBFIND_NOWILD;
-	dns_fixedname_init(&wfixed);
-	wname = dns_fixedname_name(&wfixed);
+	wname = dns_fixedname_initname(&wfixed);
  again:
 	have_wname = ISC_FALSE;
 	/*
@@ -3518,8 +3526,7 @@ query_addwildcardproof(ns_client_t *clie
 		/*
 		 * No NSEC proof available, return NSEC3 proofs instead.
 		 */
-		dns_fixedname_init(&cfixed);
-		cname = dns_fixedname_name(&cfixed);
+		cname = dns_fixedname_initname(&cfixed);
 		/*
 		 * Find the closest encloser.
 		 */
@@ -4097,8 +4104,7 @@ rpz_rrset_find(ns_client_t *client, dns_
 	}
 
 	node = NULL;
-	dns_fixedname_init(&fixed);
-	found = dns_fixedname_name(&fixed);
+	found = dns_fixedname_initname(&fixed);
 	result = dns_db_findext(*dbp, name, version, type, DNS_DBFIND_GLUEOK,
 				client->now, &node, found,
 				&cm, &ci, *rdatasetp, NULL);
@@ -4335,8 +4341,7 @@ rpz_find(ns_client_t *client, dns_rdatat
 		return (DNS_R_NXDOMAIN);
 	}
 
-	dns_fixedname_init(&fixed);
-	found = dns_fixedname_name(&fixed);
+	found = dns_fixedname_initname(&fixed);
 	result = dns_db_findext(*dbp, qnamef, *versionp, dns_rdatatype_any, 0,
 				client->now, nodep, found, &cm, &ci,
 				*rdatasetp, NULL);
@@ -4491,15 +4496,13 @@ rpz_rewrite_name(ns_client_t *client, dn
 		/*
 		 * Construct the policy's owner name.
 		 */
-		dns_fixedname_init(&prefixf);
-		prefix = dns_fixedname_name(&prefixf);
+		prefix = dns_fixedname_initname(&prefixf);
 		dns_name_split(qname, 1, prefix, NULL);
 		if (rpz_type == DNS_RPZ_TYPE_NSDNAME)
 			suffix = &rpz->nsdname;
 		else
 			suffix = &rpz->origin;
-		dns_fixedname_init(&rpz_qnamef);
-		rpz_qname = dns_fixedname_name(&rpz_qnamef);
+		rpz_qname = dns_fixedname_initname(&rpz_qnamef);
 		for (;;) {
 			result = dns_name_concatenate(prefix, suffix,
 						      rpz_qname, NULL);
@@ -4674,12 +4677,9 @@ rpz_rewrite(ns_client_t *client, dns_rda
 		st->m.ttl = ~0;
 		memset(&st->r, 0, sizeof(st->r));
 		memset(&st->q, 0, sizeof(st->q));
-		dns_fixedname_init(&st->_qnamef);
-		dns_fixedname_init(&st->_r_namef);
-		dns_fixedname_init(&st->_fnamef);
-		st->qname = dns_fixedname_name(&st->_qnamef);
-		st->r_name = dns_fixedname_name(&st->_r_namef);
-		st->fname = dns_fixedname_name(&st->_fnamef);
+		st->qname = dns_fixedname_initname(&st->_qnamef);
+		st->r_name = dns_fixedname_initname(&st->_r_namef);
+		st->fname = dns_fixedname_initname(&st->_fnamef);
 		client->query.rpz_st = st;
 	}
 
@@ -4957,8 +4957,7 @@ rpz_ck_dnssec(ns_client_t *client, isc_r
 	 */
 	if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) == 0)
 		return (ISC_TRUE);
-	dns_fixedname_init(&fixed);
-	found = dns_fixedname_name(&fixed);
+	found = dns_fixedname_initname(&fixed);
 	dns_rdataset_init(&trdataset);
 	for (result = dns_rdataset_first(rdataset);
 	     result == ISC_R_SUCCESS;
@@ -5544,8 +5543,7 @@ redirect(ns_client_t *client, dns_name_t
 	if (client->view->redirect == NULL)
 		return (ISC_R_NOTFOUND);
 
-	dns_fixedname_init(&fixed);
-	found = dns_fixedname_name(&fixed);
+	found = dns_fixedname_initname(&fixed);
 	dns_rdataset_init(&trdataset);
 
 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
@@ -6709,8 +6707,7 @@ query_find(ns_client_t *client, dns_fetc
 				dns_name_t *found;
 				dns_name_t *qname;
 
-				dns_fixedname_init(&fixed);
-				found = dns_fixedname_name(&fixed);
+				found = dns_fixedname_initname(&fixed);
 				qname = client->query.qname;
 
 				query_findclosestnsec3(qname, db, version,
@@ -7153,8 +7150,7 @@ query_find(ns_client_t *client, dns_fetc
 		 * Construct the new qname consisting of
 		 * <found name prefix>.<dname target>
 		 */
-		dns_fixedname_init(&fixed);
-		prefix = dns_fixedname_name(&fixed);
+		prefix = dns_fixedname_initname(&fixed);
 		dns_name_split(client->query.qname, nlabels, prefix, NULL);
 		INSIST(fname == NULL);
 		dbuf = query_getnamebuf(client);
Index: bind-9.9.9-P1/bin/named/tkeyconf.c
===================================================================
--- bind-9.9.9-P1.orig/bin/named/tkeyconf.c
+++ bind-9.9.9-P1/bin/named/tkeyconf.c
@@ -75,8 +75,7 @@ ns_tkeyctx_fromconfig(const cfg_obj_t *o
 		n = cfg_obj_asuint32(cfg_tuple_get(obj, "keyid"));
 		isc_buffer_constinit(&b, s, strlen(s));
 		isc_buffer_add(&b, strlen(s));
-		dns_fixedname_init(&fname);
-		name = dns_fixedname_name(&fname);
+		name = dns_fixedname_initname(&fname);
 		RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
 		type = DST_TYPE_PUBLIC|DST_TYPE_PRIVATE|DST_TYPE_KEY;
 		RETERR(dst_key_fromfile(name, (dns_keytag_t) n, DNS_KEYALG_DH,
@@ -89,8 +88,7 @@ ns_tkeyctx_fromconfig(const cfg_obj_t *o
 		s = cfg_obj_asstring(obj);
 		isc_buffer_constinit(&b, s, strlen(s));
 		isc_buffer_add(&b, strlen(s));
-		dns_fixedname_init(&fname);
-		name = dns_fixedname_name(&fname);
+		name = dns_fixedname_initname(&fname);
 		RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
 		tctx->domain = isc_mem_get(mctx, sizeof(dns_name_t));
 		if (tctx->domain == NULL) {
@@ -108,8 +106,7 @@ ns_tkeyctx_fromconfig(const cfg_obj_t *o
 
 		isc_buffer_constinit(&b, s, strlen(s));
 		isc_buffer_add(&b, strlen(s));
-		dns_fixedname_init(&fname);
-		name = dns_fixedname_name(&fname);
+		name = dns_fixedname_initname(&fname);
 		RETERR(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
 		RETERR(dst_gssapi_acquirecred(name, ISC_FALSE, &tctx->gsscred));
 	}
Index: bind-9.9.9-P1/lib/dns/forward.c
===================================================================
--- bind-9.9.9-P1.orig/lib/dns/forward.c
+++ bind-9.9.9-P1/lib/dns/forward.c
@@ -81,12 +81,62 @@ dns_fwdtable_create(isc_mem_t *mctx, dns
 }
 
 isc_result_t
+dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, dns_name_t *name,
+		     dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t fwdpolicy)
+{
+	isc_result_t result;
+	dns_forwarders_t *forwarders;
+	dns_forwarder_t *fwd, *nfwd;
+
+	REQUIRE(VALID_FWDTABLE(fwdtable));
+
+	forwarders = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarders_t));
+	if (forwarders == NULL)
+		return (ISC_R_NOMEMORY);
+
+	ISC_LIST_INIT(forwarders->fwdrs);
+	for (fwd = ISC_LIST_HEAD(*fwdrs);
+	     fwd != NULL;
+	     fwd = ISC_LIST_NEXT(fwd, link))
+	{
+		nfwd = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarder_t));
+		if (nfwd == NULL) {
+			result = ISC_R_NOMEMORY;
+			goto cleanup;
+		}
+		*nfwd = *fwd;
+		ISC_LINK_INIT(nfwd, link);
+		ISC_LIST_APPEND(forwarders->fwdrs, nfwd, link);
+	}
+	forwarders->fwdpolicy = fwdpolicy;
+
+	RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
+	result = dns_rbt_addname(fwdtable->table, name, forwarders);
+	RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
+
+	if (result != ISC_R_SUCCESS)
+		goto cleanup;
+
+	return (ISC_R_SUCCESS);
+
+  cleanup:
+	while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
+		fwd = ISC_LIST_HEAD(forwarders->fwdrs);
+		ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
+		isc_mem_put(fwdtable->mctx, fwd, sizeof(isc_sockaddr_t));
+	}
+	isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
+	return (result);
+}
+
+isc_result_t
 dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name,
 		 isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy)
 {
 	isc_result_t result;
 	dns_forwarders_t *forwarders;
-	isc_sockaddr_t *sa, *nsa;
+	dns_forwarder_t *fwd;
+	isc_sockaddr_t *sa;
 
 	REQUIRE(VALID_FWDTABLE(fwdtable));
 
@@ -94,19 +144,20 @@ dns_fwdtable_add(dns_fwdtable_t *fwdtabl
 	if (forwarders == NULL)
 		return (ISC_R_NOMEMORY);
 
-	ISC_LIST_INIT(forwarders->addrs);
+	ISC_LIST_INIT(forwarders->fwdrs);
 	for (sa = ISC_LIST_HEAD(*addrs);
 	     sa != NULL;
 	     sa = ISC_LIST_NEXT(sa, link))
 	{
-		nsa = isc_mem_get(fwdtable->mctx, sizeof(isc_sockaddr_t));
-		if (nsa == NULL) {
+		fwd = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarder_t));
+		if (fwd == NULL) {
 			result = ISC_R_NOMEMORY;
 			goto cleanup;
 		}
-		*nsa = *sa;
-		ISC_LINK_INIT(nsa, link);
-		ISC_LIST_APPEND(forwarders->addrs, nsa, link);
+		fwd->addr = *sa;
+		fwd->dscp = -1;
+		ISC_LINK_INIT(fwd, link);
+		ISC_LIST_APPEND(forwarders->fwdrs, fwd, link);
 	}
 	forwarders->fwdpolicy = fwdpolicy;
 
@@ -120,10 +171,10 @@ dns_fwdtable_add(dns_fwdtable_t *fwdtabl
 	return (ISC_R_SUCCESS);
 
  cleanup:
-	while (!ISC_LIST_EMPTY(forwarders->addrs)) {
-		sa = ISC_LIST_HEAD(forwarders->addrs);
-		ISC_LIST_UNLINK(forwarders->addrs, sa, link);
-		isc_mem_put(fwdtable->mctx, sa, sizeof(isc_sockaddr_t));
+	while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
+		fwd = ISC_LIST_HEAD(forwarders->fwdrs);
+		ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
+		isc_mem_put(fwdtable->mctx, fwd, sizeof(dns_forwarder_t));
 	}
 	isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
 	return (result);
@@ -199,14 +250,14 @@ static void
 auto_detach(void *data, void *arg) {
 	dns_forwarders_t *forwarders = data;
 	dns_fwdtable_t *fwdtable = arg;
-	isc_sockaddr_t *sa;
+	dns_forwarder_t *fwd;
 
 	UNUSED(arg);
 
-	while (!ISC_LIST_EMPTY(forwarders->addrs)) {
-		sa = ISC_LIST_HEAD(forwarders->addrs);
-		ISC_LIST_UNLINK(forwarders->addrs, sa, link);
-		isc_mem_put(fwdtable->mctx, sa, sizeof(isc_sockaddr_t));
+	while (!ISC_LIST_EMPTY(forwarders->fwdrs)) {
+		fwd = ISC_LIST_HEAD(forwarders->fwdrs);
+		ISC_LIST_UNLINK(forwarders->fwdrs, fwd, link);
+		isc_mem_put(fwdtable->mctx, fwd, sizeof(dns_forwarder_t));
 	}
 	isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
 }
Index: bind-9.9.9-P1/lib/dns/include/dns/fixedname.h
===================================================================
--- bind-9.9.9-P1.orig/lib/dns/include/dns/fixedname.h
+++ bind-9.9.9-P1/lib/dns/include/dns/fixedname.h
@@ -83,4 +83,10 @@ struct dns_fixedname {
 
 #define dns_fixedname_name(fn)		(&((fn)->name))
 
+static inline dns_name_t *
+dns_fixedname_initname(dns_fixedname_t *fixed) {
+	dns_fixedname_init(fixed);
+	return (dns_fixedname_name(fixed));
+}
+
 #endif /* DNS_FIXEDNAME_H */
Index: bind-9.9.9-P1/lib/dns/include/dns/forward.h
===================================================================
--- bind-9.9.9-P1.orig/lib/dns/include/dns/forward.h
+++ bind-9.9.9-P1/lib/dns/include/dns/forward.h
@@ -28,8 +28,16 @@
 
 ISC_LANG_BEGINDECLS
 
+struct dns_forwarder {
+	isc_sockaddr_t                  addr;
+	isc_dscp_t                      dscp;
+	ISC_LINK(dns_forwarder_t)       link;
+};
+
+typedef ISC_LIST(struct dns_forwarder)  dns_forwarderlist_t;
+
 struct dns_forwarders {
-	isc_sockaddrlist_t	addrs;
+	dns_forwarderlist_t	fwdrs;
 	dns_fwdpolicy_t		fwdpolicy;
 };
 
@@ -48,17 +56,23 @@ dns_fwdtable_create(isc_mem_t *mctx, dns
  */
 
 isc_result_t
+dns_fwdtable_addfwd(dns_fwdtable_t *fwdtable, dns_name_t *name,
+		    dns_forwarderlist_t *fwdrs, dns_fwdpolicy_t policy);
+
+isc_result_t
 dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name,
 		 isc_sockaddrlist_t *addrs, dns_fwdpolicy_t policy);
 /*%<
  * Adds an entry to the forwarding table.  The entry associates
  * a domain with a list of forwarders and a forwarding policy.  The
- * addrs list is copied if not empty, so the caller should free its copy.
+ * addrs/fwdrs list is copied if not empty, so the caller should free
+ * its copy.
  *
  * Requires:
  * \li	fwdtable is a valid forwarding table.
  * \li	name is a valid name
- * \li	addrs is a valid list of sockaddrs, which may be empty.
+ * \li	addrs/fwdrs is a valid list of isc_sockaddr/dns_forwarder
+ *	structures, which may be empty.
  *
  * Returns:
  * \li	#ISC_R_SUCCESS
Index: bind-9.9.9-P1/lib/dns/include/dns/types.h
===================================================================
--- bind-9.9.9-P1.orig/lib/dns/include/dns/types.h
+++ bind-9.9.9-P1/lib/dns/include/dns/types.h
@@ -77,6 +77,7 @@ typedef struct dns_ednsopt			dns_ednsopt
 typedef struct dns_fetch			dns_fetch_t;
 typedef struct dns_fixedname			dns_fixedname_t;
 typedef struct dns_forwarders			dns_forwarders_t;
+typedef struct dns_forwarder			dns_forwarder_t;
 typedef struct dns_fwdtable			dns_fwdtable_t;
 typedef struct dns_iptable			dns_iptable_t;
 typedef isc_uint32_t				dns_iterations_t;
Index: bind-9.9.9-P1/lib/dns/resolver.c
===================================================================
--- bind-9.9.9-P1.orig/lib/dns/resolver.c
+++ bind-9.9.9-P1/lib/dns/resolver.c
@@ -61,6 +61,7 @@
 #include <dns/stats.h>
 #include <dns/tsig.h>
 #include <dns/validator.h>
+#include <dns/zone.h>
 
 #ifdef WANT_QUERYTRACE
 #define RTRACE(m)       isc_log_write(dns_lctx, \
@@ -282,7 +283,7 @@ struct fetchctx {
 	dns_adbfind_t *			altfind;
 	dns_adbaddrinfolist_t		forwaddrs;
 	dns_adbaddrinfolist_t		altaddrs;
-	isc_sockaddrlist_t		forwarders;
+	dns_forwarderlist_t		forwarders;
 	dns_fwdpolicy_t			fwdpolicy;
 	isc_sockaddrlist_t		bad;
 	isc_sockaddrlist_t		edns;
@@ -295,6 +296,8 @@ struct fetchctx {
 	isc_boolean_t			ns_ttl_ok;
 	isc_uint32_t			ns_ttl;
 	isc_counter_t *			qc;
+	dns_fixedname_t			fwdfname;
+	dns_name_t			*fwdname;
 
 	/*%
 	 * The number of events we're waiting for.
@@ -2887,7 +2890,7 @@ fctx_getaddresses(fetchctx_t *fctx, isc_
 	dns_resolver_t *res;
 	isc_stdtime_t now;
 	unsigned int stdoptions = 0;
-	isc_sockaddr_t *sa;
+	dns_forwarder_t *fwd;
 	dns_adbaddrinfo_t *ai;
 	isc_boolean_t all_bad;
 	dns_rdata_ns_t ns;
@@ -2931,8 +2934,8 @@ fctx_getaddresses(fetchctx_t *fctx, isc_
 	 * selective forwarders specified in the view; otherwise use the
 	 * resolver's forwarders (if any).
 	 */
-	sa = ISC_LIST_HEAD(fctx->forwarders);
-	if (sa == NULL) {
+	fwd = ISC_LIST_HEAD(fctx->forwarders);
+	if (fwd == NULL) {
 		dns_forwarders_t *forwarders = NULL;
 		dns_name_t *name = &fctx->name;
 		dns_name_t suffix;
@@ -2952,13 +2955,13 @@ fctx_getaddresses(fetchctx_t *fctx, isc_
 			name = &suffix;
 		}
 
-		dns_fixedname_init(&fixed);
-		domain = dns_fixedname_name(&fixed);
+		domain = dns_fixedname_initname(&fixed);
 		result = dns_fwdtable_find2(res->view->fwdtable, name,
 					    domain, &forwarders);
 		if (result == ISC_R_SUCCESS) {
-			sa = ISC_LIST_HEAD(forwarders->addrs);
+			fwd = ISC_LIST_HEAD(forwarders->fwdrs);
 			fctx->fwdpolicy = forwarders->fwdpolicy;
+			dns_name_copy(domain, fctx->fwdname, NULL);
 			if (fctx->fwdpolicy == dns_fwdpolicy_only &&
 			    isstrictsubdomain(domain, &fctx->domain)) {
 #ifdef ENABLE_FETCHLIMIT
@@ -2981,17 +2984,16 @@ fctx_getaddresses(fetchctx_t *fctx, isc_
 		}
 	}
 
-	while (sa != NULL) {
-		if ((isc_sockaddr_pf(sa) == AF_INET &&
+	while (fwd != NULL) {
+		if ((isc_sockaddr_pf(&fwd->addr) == AF_INET &&
 			 fctx->res->dispatches4 == NULL) ||
-		    (isc_sockaddr_pf(sa) == AF_INET6 &&
+		    (isc_sockaddr_pf(&fwd->addr) == AF_INET6 &&
 			fctx->res->dispatches6 == NULL)) {
-				sa = ISC_LIST_NEXT(sa, link);
+				fwd = ISC_LIST_NEXT(fwd, link);
 				continue;
 		}
 		ai = NULL;
-		result = dns_adb_findaddrinfo(fctx->adb,
-					      sa, &ai, 0);  /* XXXMLG */
+		result = dns_adb_findaddrinfo(fctx->adb, &fwd->addr, &ai, 0);
 		if (result == ISC_R_SUCCESS) {
 			dns_adbaddrinfo_t *cur;
 			ai->flags |= FCTX_ADDRINFO_FORWARDER;
@@ -3004,7 +3006,7 @@ fctx_getaddresses(fetchctx_t *fctx, isc_
 			else
 				ISC_LIST_APPEND(fctx->forwaddrs, ai, publink);
 		}
-		sa = ISC_LIST_NEXT(sa, link);
+		fwd = ISC_LIST_NEXT(fwd, link);
 	}
 
 	/*
@@ -4012,6 +4014,9 @@ fctx_create(dns_resolver_t *res, dns_nam
 	fctx->restarts = 0;
 	fctx->querysent = 0;
 	fctx->referrals = 0;
+
+	fctx->fwdname = dns_fixedname_initname(&fctx->fwdfname);
+
 	TIME_NOW(&fctx->start);
 	fctx->timeouts = 0;
 	fctx->lamecount = 0;
@@ -5715,6 +5720,107 @@ mark_related(dns_name_t *name, dns_rdata
 		rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL;
 }
 
+/*
+ * Returns true if 'name' is external to the namespace for which
+ * the server being queried can answer, either because it's not a
+ * subdomain or because it's below a forward declaration or a
+ * locally served zone.
+ */
+static inline isc_boolean_t
+name_external(dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) {
+	isc_result_t result;
+	dns_forwarders_t *forwarders = NULL;
+	dns_fixedname_t fixed, zfixed;
+	dns_name_t *fname = dns_fixedname_initname(&fixed);
+	dns_name_t *zfname = dns_fixedname_initname(&zfixed);
+	dns_name_t *apex = NULL;
+	dns_name_t suffix;
+	dns_zone_t *zone = NULL;
+	unsigned int labels;
+	dns_namereln_t rel;
+
+	apex = ISFORWARDER(fctx->addrinfo) ? fctx->fwdname : &fctx->domain;
+
+	/*
+	 * The name is outside the queried namespace.
+	 */
+	rel = dns_name_fullcompare(name, apex, &(int){ 0 },
+				   &(unsigned int){ 0U });
+	if (rel != dns_namereln_subdomain && rel != dns_namereln_equal) {
+		return (ISC_TRUE);
+	}
+
+	/*
+	 * If the record lives in the parent zone, adjust the name so we
+	 * look for the correct zone or forward clause.
+	 */
+	labels = dns_name_countlabels(name);
+	if (dns_rdatatype_atparent(type) && labels > 1U) {
+		dns_name_init(&suffix, NULL);
+		dns_name_getlabelsequence(name, 1, labels - 1, &suffix);
+		name = &suffix;
+	} else if (rel == dns_namereln_equal) {
+		/* If 'name' is 'apex', no further checking is needed. */
+		return (ISC_FALSE);
+	}
+
+	/*
+	 * If there is a locally served zone between 'apex' and 'name'
+	 * then don't cache.
+	 */
+	LOCK(&fctx->res->view->lock);
+	if (fctx->res->view->zonetable != NULL) {
+		unsigned int options = DNS_ZTFIND_NOEXACT;
+		result = dns_zt_find(fctx->res->view->zonetable, name, options,
+				     zfname, &zone);
+		if (zone != NULL) {
+			dns_zone_detach(&zone);
+		}
+		if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+			if (dns_name_fullcompare(zfname, apex, &(int){ 0 },
+						 &(unsigned int){ 0U }) ==
+			    dns_namereln_subdomain)
+			{
+				UNLOCK(&fctx->res->view->lock);
+				return (ISC_TRUE);
+			}
+		}
+	}
+	UNLOCK(&fctx->res->view->lock);
+
+	/*
+	 * Look for a forward declaration below 'name'.
+	 */
+	result = dns_fwdtable_find2(fctx->res->view->fwdtable, name, fname,
+				    &forwarders);
+
+	if (ISFORWARDER(fctx->addrinfo)) {
+		/*
+		 * See if the forwarder declaration is better.
+		 */
+		if (result == ISC_R_SUCCESS) {
+			return (!dns_name_equal(fname, fctx->fwdname));
+		}
+
+		/*
+		 * If the lookup failed, the configuration must have
+		 * changed: play it safe and don't cache.
+		 */
+		return (ISC_TRUE);
+	} else if (result == ISC_R_SUCCESS &&
+		   forwarders->fwdpolicy == dns_fwdpolicy_only &&
+		   !ISC_LIST_EMPTY(forwarders->fwdrs))
+	{
+		/*
+		 * If 'name' is covered by a 'forward only' clause then we
+		 * can't cache this repsonse.
+		 */
+		return (ISC_TRUE);
+	}
+
+	return (ISC_FALSE);
+}
+
 static isc_result_t
 check_section(void *arg, dns_name_t *addname, dns_rdatatype_t type,
 	      dns_section_t section)
@@ -5743,7 +5849,7 @@ check_section(void *arg, dns_name_t *add
 	result = dns_message_findname(fctx->rmessage, section, addname,
 				      dns_rdatatype_any, 0, &name, NULL);
 	if (result == ISC_R_SUCCESS) {
-		external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
+		external = ISC_TF(name_external(name, type, fctx));
 		if (type == dns_rdatatype_a) {
 			for (rdataset = ISC_LIST_HEAD(name->list);
 			     rdataset != NULL;
@@ -6602,6 +6708,13 @@ answer_response(fetchctx_t *fctx) {
 
 		case dns_namereln_subdomain:
 			/*
+			 * Don't accept DNAME from parent namespace.
+			 */
+			if (name_external(name, dns_rdatatype_dname, fctx)) {
+				continue;
+			}
+
+			 /*
 			 * In-scope DNAME records must have at least
 			 * as many labels as the domain being queried.
 			 * They also must be less that qname's labels
@@ -6829,11 +6942,9 @@ answer_response(fetchctx_t *fctx) {
 	 */
 	result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
 	while (!done && result == ISC_R_SUCCESS) {
-		isc_boolean_t external;
 		name = NULL;
 		dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name);
-		external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain));
-		if (!external) {
+		if (ISC_TF(!name_external(name, dns_rdatatype_ns, fctx))) {
 			/*
 			 * We expect to find NS or SIG NS rdatasets, and
 			 * nothing else.
Index: bind-9.9.9-P1/lib/isc/include/isc/types.h
===================================================================
--- bind-9.9.9-P1.orig/lib/isc/include/isc/types.h
+++ bind-9.9.9-P1/lib/isc/include/isc/types.h
@@ -51,6 +51,7 @@ typedef ISC_LIST(isc_buffer_t)		isc_buff
 typedef struct isc_constregion		isc_constregion_t;	/*%< Const region */
 typedef struct isc_consttextregion	isc_consttextregion_t;	/*%< Const Text Region */
 typedef struct isc_counter		isc_counter_t;		/*%< Counter */
+typedef int16_t			isc_dscp_t;		/*%< Diffserv code point */
 typedef struct isc_entropy		isc_entropy_t;		/*%< Entropy */
 typedef struct isc_entropysource	isc_entropysource_t;	/*%< Entropy Source */
 typedef struct isc_event		isc_event_t;		/*%< Event */
openSUSE Build Service is sponsored by