]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
detect and process root-key-sentinel labels.
authorMark Andrews <marka@isc.org>
Tue, 13 Mar 2018 01:11:48 +0000 (12:11 +1100)
committerEvan Hunt <each@isc.org>
Tue, 5 Jun 2018 03:06:20 +0000 (20:06 -0700)
(cherry picked from commit 8fc9f64df9fec3a4c872d7b873f1dd5907487b7e)
(cherry picked from commit 7111eff80c12419ff93bd5fcb3daa5f20c55269d)
(cherry picked from commit afa97c65524607e54646f60b637bc6dbcd6c5e03)
(cherry picked from commit a624e884d49681bc6271b3128b2f2f349a3479b2)

bin/named/include/named/query.h
bin/named/query.c

index 6e64ceab8dbd05dd0977a585ca53a9d322584638..d87074c343a3495d4caf96f3a53f44e0319a07de 100644 (file)
@@ -65,6 +65,9 @@ struct ns_query {
        unsigned int                    dns64_aaaaoklen;
        unsigned int                    dns64_options;
        unsigned int                    dns64_ttl;
+       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 c606a7650c4b79807a21027ea22feb9553b54621..364b5a50a052b99b513f8ff91e0a9d2bcb390c3c 100644 (file)
@@ -35,6 +35,7 @@
 #include <dns/dns64.h>
 #include <dns/dnssec.h>
 #include <dns/events.h>
+#include <dns/keytable.h>
 #include <dns/message.h>
 #include <dns/ncache.h>
 #include <dns/nsec3.h>
@@ -443,6 +444,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
@@ -2885,7 +2889,6 @@ query_addns(ns_client_t *client, dns_db_t *db, dns_dbversion_t *version) {
        CTRACE(ISC_LOG_DEBUG(3), "query_addns: done");
        return (eresult);
 }
-
 static isc_result_t
 query_add_cname(ns_client_t *client, dns_name_t *qname, dns_name_t *tname,
                dns_trust_t trust, dns_ttl_t ttl)
@@ -2962,6 +2965,58 @@ query_add_cname(ns_client_t *client, dns_name_t *qname, dns_name_t *tname,
        return (ISC_R_SUCCESS);
 }
 
+static isc_boolean_t
+get_root_key_sentinel_id(ns_client_t *client, 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);
+       }
+       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(ns_client_t *client) {
+       const char *ndata = (const char *)client->query.qname->ndata;
+
+       if (client->query.qname->length > 30 && ndata[0] == 29 &&
+           strncasecmp(ndata + 1, "root-key-sentinel-is-ta-", 24) == 0)
+       {
+               if (!get_root_key_sentinel_id(client, ndata + 25)) {
+                       return;
+               }
+               client->query.root_key_sentinel_is_ta = ISC_TRUE;
+               ns_client_log(client, NS_LOGCATEGORY_TAT,
+                             NS_LOGMODULE_QUERY, ISC_LOG_INFO,
+                             "root-key-sentinel-is-ta query label found");
+       } else if (client->query.qname->length > 31 && ndata[0] == 30 &&
+                  strncasecmp(ndata + 1, "root-key-sentinel-not-ta-", 25) == 0)
+       {
+               if (!get_root_key_sentinel_id(client, ndata + 26)) {
+                       return;
+               }
+               client->query.root_key_sentinel_not_ta = ISC_TRUE;
+               ns_client_log(client, NS_LOGCATEGORY_TAT,
+                             NS_LOGMODULE_QUERY, ISC_LOG_INFO,
+                             "root-key-sentinel-not-ta query label found");
+       }
+}
+
 /*
  * Mark the RRsets as secure.  Update the cache (db) to reflect the
  * change in trust level.
@@ -3813,6 +3868,92 @@ free_devent(ns_client_t *client, isc_event_t **eventp,
        isc_event_free(eventp);
 }
 
+/*%
+ * Check the configured trust anchors for a root zone trust anchor
+ * with a key id that matches client->query.root_key_sentinel_keyid.
+ *
+ * Return ISC_TRUE when found, otherwise return ISC_FALSE.
+ */
+static isc_boolean_t
+has_ta(ns_client_t *client) {
+       dns_keytable_t *keytable = NULL;
+       dns_keynode_t *keynode = NULL;
+       isc_result_t result;
+
+       result = dns_view_getsecroots(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 == 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(ns_client_t *client, isc_boolean_t is_zone,
+                                 dns_rdataset_t *rdataset, isc_result_t result)
+{
+       /*
+        * Are we looking at a "root-key-sentinel" query?
+        */
+       if (!client->query.root_key_sentinel_is_ta &&
+           !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 (!is_zone && rdataset->trust == dns_trust_secure &&
+           ((client->query.root_key_sentinel_is_ta && !has_ta(client)) ||
+            (client->query.root_key_sentinel_not_ta && has_ta(client))))
+       {
+               return (ISC_TRUE);
+       }
+
+       /*
+        * As special processing may only be triggered by the original QNAME,
+        * disable it after following a CNAME/DNAME.
+        */
+       client->query.root_key_sentinel_is_ta = ISC_FALSE;
+       client->query.root_key_sentinel_not_ta = ISC_FALSE;
+
+       return (ISC_FALSE);
+}
+
 static void
 query_resume(isc_task_t *task, isc_event_t *event) {
        dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
@@ -5961,6 +6102,17 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                goto cleanup;
        }
 
+       /*
+        * Setup for root key sentinel processing.
+        */
+       if (client->query.restarts == 0 &&
+           (qtype == dns_rdatatype_a ||
+            qtype == dns_rdatatype_aaaa) &&
+           (client->message->flags & DNS_MESSAGEFLAG_CD) == 0)
+       {
+                root_key_sentinel_detect(client);
+       }
+
        /*
         * First we must find the right database.
         */
@@ -6365,6 +6517,17 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                }
        }
 
+       /*
+        * 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(client, is_zone,
+                                             rdataset, result))
+       {
+               QUERY_ERROR(DNS_R_SERVFAIL);
+               goto cleanup;
+       }
+
        switch (result) {
        case ISC_R_SUCCESS:
                /*
@@ -8125,7 +8288,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)