]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix a 'deny-answer-aliases' bug when using a cached DNAME 12044/head
authorAram Sargsyan <aram@isc.org>
Mon, 18 May 2026 09:17:51 +0000 (09:17 +0000)
committerArаm Sаrgsyаn <aram@isc.org>
Mon, 15 Jun 2026 09:37:07 +0000 (09:37 +0000)
When using a cached DNAME to resolve a name, make sure to consult
the denied answers lists, otherwise it is possible to consutruct
a restricted alias by caching a DNAME that is a parent of the
denied alias. See the comments in the tests case from the previous
commit an example.

lib/ns/query.c

index ca76df4f3d542b56c8389743afb41d676745d2fa..4fd70e6fbcdbeea5763e74a26033221e7e1dde9e 100644 (file)
@@ -47,6 +47,7 @@
 #include <dns/ede.h>
 #include <dns/keytable.h>
 #include <dns/message.h>
+#include <dns/nametree.h>
 #include <dns/ncache.h>
 #include <dns/nsec.h>
 #include <dns/nsec3.h>
@@ -10137,6 +10138,7 @@ query_cname(query_ctx_t *qctx) {
        dns_name_copy(&cname.cname, tname);
 
        dns_rdata_freestruct(&cname);
+
        ns_client_qnamereplace(qctx->client, tname);
        qctx->want_restart = true;
        if (!WANTRECURSION(qctx->client)) {
@@ -10260,6 +10262,37 @@ query_dname(query_ctx_t *qctx) {
                goto cleanup;
        }
 
+       /*
+        * If the target is a denied alias, and both the `except-from` list
+        * and the subdomain rule of the `deny-answer-aliases`
+        * configuration option (see ARM) don't give an exception, then
+        * answer with a SERVFAIL.
+        */
+       dns_fixedname_t fdeniedname;
+       dns_name_t *deniedname = dns_fixedname_initname(&fdeniedname);
+       if (qctx->view->denyanswernames != NULL &&
+           dns_nametree_covered(qctx->view->denyanswernames, qctx->fname,
+                                deniedname, 0) &&
+           !dns_nametree_covered(qctx->view->answernames_exclude,
+                                 qctx->client->query.qname, NULL, 0) &&
+           !dns_name_issubdomain(qctx->client->query.qname, deniedname))
+       {
+               char qnamebuf[DNS_NAME_FORMATSIZE];
+               char tnamebuf[DNS_NAME_FORMATSIZE];
+
+               dns_name_format(qctx->client->query.qname, qnamebuf,
+                               sizeof(qnamebuf));
+               dns_name_format(qctx->fname, tnamebuf, sizeof(tnamebuf));
+               ns_client_log(qctx->client, NS_LOGCATEGORY_QUERIES,
+                             NS_LOGMODULE_QUERY, ISC_LOG_NOTICE,
+                             "DNAME target %s denied for %s (cache)", tnamebuf,
+                             qnamebuf);
+               QUERY_ERROR(qctx, DNS_R_SERVFAIL);
+               ns_client_releasename(qctx->client, &qctx->fname);
+               (void)ns_query_done(qctx);
+               goto cleanup;
+       }
+
        ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
 
        /*