]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
detect and processes root-key-sentinel labels.
authorMark Andrews <marka@isc.org>
Tue, 13 Mar 2018 01:11:48 +0000 (12:11 +1100)
committerOndřej Surý <ondrej@sury.org>
Wed, 18 Apr 2018 15:49:55 +0000 (08:49 -0700)
lib/ns/include/ns/query.h
lib/ns/query.c

index 87c0a638edbd0db9925884df1089e735dd616eb3..365cb8c7549a7a5e11761e20970e471a25a3e2e7 100644 (file)
@@ -75,6 +75,10 @@ struct ns_query {
                isc_boolean_t           authoritative;
                isc_boolean_t           is_zone;
        } redirect;
+
+       dns_keytag_t root_key_sentinel_keyid;
+       isc_boolean_t root_key_sentinel_is_ta;
+       isc_boolean_t root_key_sentinel_not_ta;
 };
 
 #define NS_QUERYATTR_RECURSIONOK       0x0001
index b352cdbf552d2b9409c66eb4f1172c4e9dd13429..275b2304321a12817e17042c27e047450a62f5a1 100644 (file)
@@ -36,6 +36,7 @@
 #include <dns/dnsrps.h>
 #include <dns/dnssec.h>
 #include <dns/events.h>
+#include <dns/keytable.h>
 #include <dns/message.h>
 #include <dns/ncache.h>
 #include <dns/nsec.h>
@@ -700,6 +701,9 @@ query_reset(ns_client_t *client, isc_boolean_t everything) {
        client->query.isreferral = ISC_FALSE;
        client->query.dns64_options = 0;
        client->query.dns64_ttl = ISC_UINT32_MAX;
+       client->query.root_key_sentinel_keyid = 0;
+       client->query.root_key_sentinel_is_ta = ISC_FALSE;
+       client->query.root_key_sentinel_not_ta = ISC_FALSE;
 }
 
 static void
@@ -5118,6 +5122,68 @@ query_setup(ns_client_t *client, dns_rdatatype_t qtype) {
        return (ns__query_start(&qctx));
 }
 
+static isc_boolean_t
+get_root_key_sentinel_id(query_ctx_t *qctx, const char *ndata) {
+       unsigned int v = 0;
+       int i;
+
+       for (i = 0; i < 5; i++) {
+               if (ndata[i] < '0' || ndata[i] > '9') {
+                       return (ISC_FALSE);
+               }
+               v *= 10;
+               v += ndata[i] - '0';
+       }
+       if (v > 65535U) {
+               return (ISC_FALSE);
+       }
+       qctx->client->query.root_key_sentinel_keyid = v;
+       return (ISC_TRUE);
+}
+
+/*%
+ * Find out if the query is for a root key sentinel and if so, record the type
+ * of root key sentinel query and the key id that is being checked for.
+ *
+ * The code is assuming a zero padded decimal field of width 5.
+ */
+static void
+root_key_sentinel_detect(query_ctx_t *qctx) {
+       const char *ndata = (const char *)qctx->client->query.qname->ndata;
+
+       if (qctx->client->query.qname->length > 30 && ndata[0] == 29 &&
+           strncasecmp(ndata + 1, "root-key-sentinel-is-ta-", 24) == 0)
+       {
+               if (!get_root_key_sentinel_id(qctx, ndata + 25)) {
+                       return;
+               }
+               qctx->client->query.root_key_sentinel_is_ta = ISC_TRUE;
+               /*
+                * Simplify processing by disabling agressive
+                * negative caching.
+                */
+               qctx->findcoveringnsec = ISC_FALSE;
+               ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
+                             NS_LOGMODULE_QUERY, ISC_LOG_INFO,
+                             "root-key-sentinel-is-ta query label found");
+       } else if (qctx->client->query.qname->length > 31 && ndata[0] == 30 &&
+                  strncasecmp(ndata + 1, "root-key-sentinel-not-ta-", 25) == 0)
+       {
+               if (!get_root_key_sentinel_id(qctx, ndata + 26)) {
+                       return;
+               }
+               qctx->client->query.root_key_sentinel_not_ta = ISC_TRUE;
+               /*
+                * Simplify processing by disabling agressive
+                * negative caching.
+                */
+               qctx->findcoveringnsec = ISC_FALSE;
+               ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
+                             NS_LOGMODULE_QUERY, ISC_LOG_INFO,
+                             "root-key-sentinel-not-ta query label found");
+       }
+}
+
 /*%
  * Starting point for a client query or a chaining query.
  *
@@ -5158,6 +5224,17 @@ ns__query_start(query_ctx_t *qctx) {
                return (query_done(qctx));
        }
 
+       /*
+        * Setup for root key sentinel processing.
+        */
+       if (qctx->client->query.restarts == 0 &&
+           (qctx->qtype == dns_rdatatype_a ||
+            qctx->qtype == dns_rdatatype_aaaa) &&
+           (qctx->client->message->flags & DNS_MESSAGEFLAG_CD) == 0)
+       {
+                root_key_sentinel_detect(qctx);
+       }
+
        /*
         * First we must find the right database.
         */
@@ -6339,6 +6416,91 @@ query_rpzcname(query_ctx_t *qctx, dns_name_t *cname) {
        return (ISC_R_SUCCESS);
 }
 
+/*%
+ * Check the configured trust anchors for a root zone trust anchor
+ * with a key id that matches qctx->client->query.root_key_sentinel_keyid.
+ *
+ * Return ISC_TRUE when found, otherwise return ISC_FALSE.
+ */
+static isc_boolean_t
+has_ta(query_ctx_t *qctx) {
+       dns_keytable_t *keytable = NULL;
+       dns_keynode_t *keynode = NULL;
+       isc_result_t result;
+
+       result = dns_view_getsecroots(qctx->client->view, &keytable);
+       if (result != ISC_R_SUCCESS) {
+               return (ISC_FALSE);
+       }
+
+       result = dns_keytable_find(keytable, dns_rootname, &keynode);
+       while (result == ISC_R_SUCCESS) {
+               dns_keynode_t *nextnode = NULL;
+               dns_keytag_t keyid = dst_key_id(dns_keynode_key(keynode));
+               if (keyid == qctx->client->query.root_key_sentinel_keyid) {
+                       dns_keytable_detachkeynode(keytable, &keynode);
+                       dns_keytable_detach(&keytable);
+                       return (ISC_TRUE);
+               }
+               result = dns_keytable_nextkeynode(keytable, keynode, &nextnode);
+               dns_keytable_detachkeynode(keytable, &keynode);
+               keynode = nextnode;
+       }
+       dns_keytable_detach(&keytable);
+
+       return (ISC_FALSE);
+}
+
+/*%
+ * Check if a root key sentinel SERVFAIL should be returned.
+ */
+static isc_boolean_t
+root_key_sentinel_return_servfail(query_ctx_t *qctx, isc_result_t result) {
+       /*
+        * Are we looking at a "root-key-sentinel" query?
+        */
+       if (!qctx->client->query.root_key_sentinel_is_ta &&
+           !qctx->client->query.root_key_sentinel_not_ta)
+       {
+               return (ISC_FALSE);
+       }
+
+       /*
+        * We only care about the query if 'result' indicates we have a cached
+        * answer.
+        */
+       switch (result) {
+       case ISC_R_SUCCESS:
+       case DNS_R_CNAME:
+       case DNS_R_DNAME:
+       case DNS_R_NCACHENXDOMAIN:
+       case DNS_R_NCACHENXRRSET:
+               break;
+       default:
+               return (ISC_FALSE);
+       }
+
+       /*
+        * Do we meet the specified conditions to return SERVFAIL?
+        */
+       if (!qctx->is_zone &&
+           qctx->rdataset->trust == dns_trust_secure &&
+           ((qctx->client->query.root_key_sentinel_is_ta && !has_ta(qctx)) ||
+            (qctx->client->query.root_key_sentinel_not_ta && has_ta(qctx))))
+       {
+               return (ISC_TRUE);
+       }
+
+       /*
+        * As special processing may only be triggered by the original QNAME,
+        * disable it after following a CNAME/DNAME.
+        */
+       qctx->client->query.root_key_sentinel_is_ta = ISC_FALSE;
+       qctx->client->query.root_key_sentinel_not_ta = ISC_FALSE;
+
+       return (ISC_FALSE);
+}
+
 /*%
  * Continue after doing a database lookup or returning from
  * recursion, and call out to the next function depending on the
@@ -6362,6 +6524,19 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) {
                        return (query_done(qctx));
        }
 
+       /*
+        * If required, handle special "root-key-sentinel-is-ta-<keyid>" and
+        * "root-key-sentinel-not-ta-<keyid>" labels by returning SERVFAIL.
+        */
+       if (root_key_sentinel_return_servfail(qctx, result)) {
+               /*
+                * Don't record this response in the SERVFAIL cache.
+                */
+               qctx->client->attributes |= NS_CLIENTATTR_NOSETFC;
+               QUERY_ERROR(qctx, DNS_R_SERVFAIL);
+               return (query_done(qctx));
+       }
+
        switch (result) {
        case ISC_R_SUCCESS:
                return (query_prepresponse(qctx));
@@ -10855,7 +11030,7 @@ ns_query_start(ns_client_t *client) {
                client->query.attributes &= ~NS_QUERYATTR_SECURE;
 
        /*
-        * Set NS_CLIENTATTR_WANTDNSSEC if the client has set AD in the query.
+        * Set NS_CLIENTATTR_WANTAD if the client has set AD in the query.
         * This allows AD to be returned on queries without DO set.
         */
        if ((message->flags & DNS_MESSAGEFLAG_AD) != 0)