]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
4424. [experimental] Named now sends _ta-XXXX.<trust-anchor>/NULL queries
authorMark Andrews <marka@isc.org>
Fri, 22 Jul 2016 10:02:17 +0000 (20:02 +1000)
committerMark Andrews <marka@isc.org>
Fri, 22 Jul 2016 10:02:17 +0000 (20:02 +1000)
                        to provide feedback to the trust-anchor administrators
                        about how key rollovers are progressing as per
                        draft-ietf-dnsop-edns-key-tag-02.  This can be
                        disabled using 'trust-anchor-telemetry no;'.
                        [RT #40583]

19 files changed:
CHANGES
bin/named/config.c
bin/named/include/named/globals.h
bin/named/include/named/server.h
bin/named/main.c
bin/named/server.c
bin/tests/system/dnssec/ns1/named.conf
bin/tests/system/dnssec/ns6/named.args
bin/tests/system/dnssec/tests.sh
bin/tests/system/mkeys/ns3/named.args
bin/tests/system/mkeys/tests.sh
doc/arm/Bv9ARM-book.xml
doc/arm/notes.xml
lib/dns/include/dns/keytable.h
lib/dns/include/dns/view.h
lib/dns/keytable.c
lib/dns/view.c
lib/dns/zone.c
lib/isccfg/namedconf.c

diff --git a/CHANGES b/CHANGES
index c926ce6e6bb183404ce8d44e077146966f458862..46dffcc25e5f90603e35637dada5d80c535b38e5 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,10 @@
+4424.  [experimental]  Named now sends _ta-XXXX.<trust-anchor>/NULL queries
+                       to provide feedback to the trust-anchor administrators
+                       about how key rollovers are progressing as per
+                       draft-ietf-dnsop-edns-key-tag-02.  This can be
+                       disabled using 'trust-anchor-telemetry no;'.
+                       [RT #40583]
+
 4423.  [maint]         Added missing IPv6 address 2001:500:84::b for
                        B.ROOT-SERVERS.NET. [RT #42898]
 
index 5e22269f2980cd87abb4d8979d88035e0f78943a..638a2b3f9b1027287f2f04b6b3e7d29275805aa7 100644 (file)
@@ -109,6 +109,7 @@ options {\n\
        transfers-in 10;\n\
        transfers-out 10;\n\
 #      treat-cr-as-space <obsolete>;\n\
+       trust-anchor-telemetry yes;\n\
 #      use-id-pool <obsolete>;\n\
 #      use-ixfr <obsolete>;\n\
        edns-udp-size 4096;\n\
index b0223242a64fc65cf8ba356b00bdec3b07f949da..c95350ce55b6873f0a0d435d47f700388675c077 100644 (file)
@@ -176,6 +176,7 @@ EXTERN isc_boolean_t                ns_g_nonearest          INIT(ISC_FALSE);
 EXTERN isc_boolean_t           ns_g_notcp              INIT(ISC_FALSE);
 EXTERN isc_boolean_t           ns_g_disable6           INIT(ISC_FALSE);
 EXTERN isc_boolean_t           ns_g_disable4           INIT(ISC_FALSE);
+EXTERN unsigned int            ns_g_tat_interval       INIT(24*3600);
 
 #ifdef HAVE_GEOIP
 EXTERN dns_geoip_databases_t   *ns_g_geoip             INIT(NULL);
index 2ecd888578e2aafe00642f00e0cdec4a1c792d2a..8fd3899a7d940d91da10ca5f66a3c7aef6696967 100644 (file)
@@ -76,6 +76,7 @@ struct ns_server {
        isc_timer_t *           interface_timer;
        isc_timer_t *           heartbeat_timer;
        isc_timer_t *           pps_timer;
+       isc_timer_t *           tat_timer;
 
        isc_uint32_t            interface_interval;
        isc_uint32_t            heartbeat_interval;
index 7f427ffe3a6d785c7dc627e84402006745e7c789..8c01d75ba493ae1bb72308a9c038042d590d039a 100644 (file)
@@ -640,6 +640,9 @@ parse_command_line(int argc, char *argv[]) {
                                        ns_main_earlyfatal("bad mkeytimer");
                        } else if (!strcmp(isc_commandline_argument, "notcp"))
                                ns_g_notcp = ISC_TRUE;
+                       else if (!strncmp(isc_commandline_argument, "tat=", 4))
+                               ns_g_tat_interval =
+                                          atoi(isc_commandline_argument + 4);
                        else
                                fprintf(stderr, "unknown -T flag '%s\n",
                                        isc_commandline_argument);
index 3363db2af5cea8633e028b390e198e54582af1c9..bb5453f7208b49144526b745f751b051253839be 100644 (file)
@@ -4103,6 +4103,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
        else
                INSIST(0);
 
+       obj = NULL;
+       result = ns_config_get(maps, "trust-anchor-telemetry", &obj);
+       INSIST(result == ISC_R_SUCCESS);
+       view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
+
        /*
         * Set sources where additional data and CNAME/DNAME
         * targets for authoritative answers may be found.
@@ -5834,6 +5839,186 @@ heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
        }
 }
 
+typedef struct {
+       isc_mem_t       *mctx;
+       isc_task_t      *task;
+       dns_rdataset_t  rdataset;
+       dns_rdataset_t  sigrdataset;
+       dns_fetch_t     *fetch;
+} ns_tat_t;
+
+static int
+cid(const void *a, const void *b) {
+       const isc_uint16_t ida = *(const isc_uint16_t *)a;
+       const isc_uint16_t idb = *(const isc_uint16_t *)b;
+       if (ida < idb)
+               return (-1);
+       else if (ida > idb)
+               return (1);
+       else
+               return (0);
+}
+
+static void
+tat_done(isc_task_t *task, isc_event_t *event) {
+       dns_fetchevent_t *devent;
+       ns_tat_t *tat;
+
+       UNUSED(task);
+       INSIST(event != NULL && event->ev_type == DNS_EVENT_FETCHDONE);
+       INSIST(event->ev_arg != NULL);
+
+       tat = event->ev_arg;
+       devent = (dns_fetchevent_t *) event;
+
+       /* Free resources which are not of interest */
+       if (devent->node != NULL)
+               dns_db_detachnode(devent->db, &devent->node);
+       if (devent->db != NULL)
+               dns_db_detach(&devent->db);
+       isc_event_free(&event);
+       dns_resolver_destroyfetch(&tat->fetch);
+       if (dns_rdataset_isassociated(&tat->rdataset))
+               dns_rdataset_disassociate(&tat->rdataset);
+       if (dns_rdataset_isassociated(&tat->sigrdataset))
+               dns_rdataset_disassociate(&tat->sigrdataset);
+       isc_task_detach(&tat->task);
+       isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
+}
+
+struct dotat_arg {
+       dns_view_t *view;
+       isc_task_t *task;
+};
+
+static void
+dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, void *arg) {
+       isc_result_t result;
+       dns_keynode_t *firstnode = keynode;
+       dns_keynode_t *nextnode;
+       unsigned int i, n = 0;
+       char label[64], namebuf[DNS_NAME_FORMATSIZE];
+       dns_fixedname_t fixed;
+       dns_name_t *tatname;
+       isc_uint16_t ids[12]; /* Only 12 id's will fit in a label. */
+       int m;
+       ns_tat_t *tat;
+       dns_name_t *name = NULL;
+       struct dotat_arg *dotat_arg = arg;
+       dns_view_t *view;
+       isc_task_t *task;
+       isc_textregion_t r;
+
+       REQUIRE(keytable != NULL);
+       REQUIRE(keynode != NULL);
+       REQUIRE(arg != NULL);
+
+       view = dotat_arg->view;
+       task = dotat_arg->task;
+
+       do {
+               dst_key_t *key = dns_keynode_key(keynode);
+               if (key != NULL) {
+                       name = dst_key_name(key);
+                       if (n < (sizeof(ids)/sizeof(ids[0]))) {
+                               ids[n] = dst_key_id(key);
+                               n++;
+                       }
+               }
+               nextnode = NULL;
+               (void)dns_keytable_nextkeynode(keytable, keynode, &nextnode);
+               if (keynode != firstnode)
+                       dns_keytable_detachkeynode(keytable, &keynode);
+               keynode = nextnode;
+       } while (keynode != NULL);
+
+       if (n == 0)
+               return;
+
+       if (n > 1)
+               qsort(ids, n, sizeof(ids[0]), cid);
+
+       /*
+        * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of
+        * of the keyid.
+        */
+       label[0] = 0;
+       r.base = label;
+       r.length = sizeof(label);;
+       m = snprintf(r.base, r.length, "_ta");
+       if (m < 0 || (unsigned)m > r.length)
+               return;
+       isc_textregion_consume(&r, m);
+       for (i = 0; i < n; i++) {
+               m = snprintf(r.base, r.length, "-%04x", ids[i]);
+               if (m < 0 || (unsigned)m > r.length)
+                       return;
+               isc_textregion_consume(&r, m);
+       }
+       dns_fixedname_init(&fixed);
+       tatname = dns_fixedname_name(&fixed);
+       result = dns_name_fromstring2(tatname, label, name, 0, NULL);
+       if (result != ISC_R_SUCCESS)
+               return;
+
+       dns_name_format(tatname, namebuf, sizeof(namebuf));
+       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
+                     ISC_LOG_INFO,
+                    "%s: sending trust-anchor-telemetry query '%s/NULL'",
+                    view->name, namebuf);
+
+       tat = isc_mem_get(dotat_arg->view->mctx, sizeof(*tat));
+       if (tat == NULL)
+               return;
+
+       tat->mctx = NULL;
+       tat->task = NULL;
+       tat->fetch = NULL;
+       dns_rdataset_init(&tat->rdataset);
+       dns_rdataset_init(&tat->sigrdataset);
+       isc_mem_attach(dotat_arg->view->mctx, &tat->mctx);
+       isc_task_attach(task, &tat->task);
+
+       result = dns_resolver_createfetch(view->resolver, tatname,
+                                         dns_rdatatype_null, NULL, NULL,
+                                         NULL, 0, tat->task, tat_done, tat,
+                                         &tat->rdataset, &tat->sigrdataset,
+                                         &tat->fetch);
+
+       if (result != ISC_R_SUCCESS) {
+               isc_task_detach(&tat->task);
+               isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
+       }
+}
+
+static void
+tat_timer_tick(isc_task_t *task, isc_event_t *event) {
+       isc_result_t result;
+       ns_server_t *server = (ns_server_t *) event->ev_arg;
+       struct dotat_arg arg;
+       dns_view_t *view;
+       dns_keytable_t *secroots = NULL;
+
+       isc_event_free(&event);
+
+       for (view = ISC_LIST_HEAD(server->viewlist);
+            view != NULL;
+            view = ISC_LIST_NEXT(view, link))
+       {
+               if (!view->trust_anchor_telemetry)
+                       continue;
+
+               result = dns_view_getsecroots(view, &secroots);
+               if (result != ISC_R_SUCCESS)
+                       continue;
+
+               arg.view = view;
+               arg.task = task;
+               (void)dns_keytable_forall(secroots, dotat, &arg);
+               dns_keytable_detach(&secroots);
+       }
+}
+
 static void
 pps_timer_tick(isc_task_t *task, isc_event_t *event) {
        static unsigned int oldrequests = 0;
@@ -7257,6 +7442,10 @@ load_configuration(const char *filename, ns_server_t *server,
        CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
                              &interval, ISC_FALSE));
 
+       isc_interval_set(&interval, ns_g_tat_interval, 0);
+       CHECK(isc_timer_reset(server->tat_timer, isc_timertype_ticker, NULL,
+                             &interval, ISC_FALSE));
+
        /*
         * Write the PID file.
         */
@@ -7970,6 +8159,11 @@ run_server(isc_task_t *task, isc_event_t *event) {
                                    server, &server->heartbeat_timer),
                   "creating heartbeat timer");
 
+       CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
+                                   NULL, NULL, server->task, tat_timer_tick,
+                                   server, &server->tat_timer),
+                  "creating trust anchor telemetry timer");
+
        CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
                                    NULL, NULL, server->task, pps_timer_tick,
                                    server, &server->pps_timer),
@@ -8059,6 +8253,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
        isc_timer_detach(&server->interface_timer);
        isc_timer_detach(&server->heartbeat_timer);
        isc_timer_detach(&server->pps_timer);
+       isc_timer_detach(&server->tat_timer);
 
        ns_interfacemgr_shutdown(server->interfacemgr);
        ns_interfacemgr_detach(&server->interfacemgr);
@@ -8173,6 +8368,7 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
        server->interface_timer = NULL;
        server->heartbeat_timer = NULL;
        server->pps_timer = NULL;
+       server->tat_timer = NULL;
 
        server->interface_interval = 0;
        server->heartbeat_interval = 0;
index 80e5faf5cdec91f43eb372ffdc08c51ff656af5f..d2d754b4ebfbb405061bec68be33f8c438c8bf53 100644 (file)
@@ -6,8 +6,6 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-/* $Id: named.conf,v 1.24 2007/06/19 23:47:02 tbox Exp $ */
-
 // NS1
 
 controls { /* empty */ };
@@ -24,6 +22,8 @@ options {
        notify yes;
        dnssec-enable yes;
        dnssec-validation yes;
+       /* test that we can turn off trust-anchor-telemetry */
+       trust-anchor-telemetry no;
 };
 
 zone "." {
index 34442d85436feb57cb8f2ae9a1da8951ab036f97..04cf949bf66f0994b9a536523421f17d09a71538 100644 (file)
@@ -1 +1 @@
--m record,size,mctx -c named.conf -d 99 -X named.lock -g -T nonearest -T clienttest
+-m record,size,mctx -c named.conf -d 99 -X named.lock -g -T nonearest -T clienttest -T tat=1
index 6cc9c603332fe47a8b7be9881ded83b3e6f9c091..437246a0fc1e45d4eee5b5c9554c2e9b5d2d55af 100644 (file)
@@ -3286,5 +3286,26 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
+echo "I:check that trust-anchor-telemetry queries are logged ($n)"
+ret=0
+grep "sending trust-anchor-telemetry query '_ta-[0-9a-f]*/NULL" ns6/named.run > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:check that trust-anchor-telemetry queries are received ($n)"
+ret=0
+grep "query '_ta-[0-9a-f]*/NULL/IN' approved" ns1/named.run > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:check that trust-anchor-telemetry are not sent when disabled ($n)"
+ret=0
+grep "sending trust-anchor-telemetry query '_ta-[0-9a-f]*/NULL" ns1/named.run > /dev/null && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
 echo "I:exit status: $status"
 [ $status -eq 0 ] || exit 1
index 25c42898ca5404791480cd8e489532c2092109b4..038b980ecaa73ffacd8da5455f5ba4cf03d9cc72 100644 (file)
@@ -1 +1 @@
--m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g -T mkeytimers=2/10/20
+-m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g -T mkeytimers=2/10/20 -T tat=1
index fe9978d1831918a1d23947f1ccb960814c4e31fb..f0c85670b866f4b0e5066214f694bbd7da797229 100644 (file)
@@ -534,5 +534,19 @@ grep "example..*.RRSIG..*TXT" dig.out.ns2.test$n > /dev/null || ret=1
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
+n=`expr $n + 1`
+echo "I: check that trust-anchor-telemetry queries are logged ($n)"
+ret=0
+grep "sending trust-anchor-telemetry query '_ta-[0-9a-f]*/NULL" ns3/named.run > /dev/null || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo "I: check that trust-anchor-telemetry queries are received ($n)"
+ret=0
+grep "query '_ta-[0-9a-f]*/NULL/IN' approved" ns1/named.run > /dev/null || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
 echo "I:exit status: $status"
 [ $status -eq 0 ] || exit 1
index 2119d564e753adea9d9e6e3869cb0d0c815944c2..dd679090a4b3a7ce1e209fccf6589b6dc6a7d653 100644 (file)
@@ -6435,6 +6435,37 @@ options {
              </listitem>
            </varlistentry>
 
+           <varlistentry>
+             <term><command>trust-anchor-telemetry</command></term>
+             <listitem>
+               <para>
+                 Causes <command>named</command> to send specially-formed
+                 queries once per day to domains for which trust anchors
+                 have been configured via <command>trusted-keys</command>,
+                 <command>managed-keys</command>,
+                 <command>dnssec-validation auto</command>, or
+                 <command>dnssec-lookaside auto</command>.
+               </para>
+               <para>
+                 The query name used for these queries has the
+                 form "_ta-xxxx(-xxxx)(...)".&lt;domain&gt;, where
+                 each "xxxx" is a group of four hexadecimal digits
+                 representing the key ID of a trusted DNSSEC key.
+                 The key IDs for each domain are sorted smallest
+                 to largest prior to encoding. The query type is NULL.
+               </para>
+               <para>
+                 By monitoring these queries, zone operators will
+                 be able to see which resolvers have been updated to
+                 trust a new key; this may help them decide when it
+                 is safe to remove an old one.
+               </para>
+               <para>
+                 The default is <userinput>yes</userinput>.
+               </para>
+             </listitem>
+           </varlistentry>
+
            <varlistentry>
              <term><command>use-id-pool</command></term>
              <listitem>
index 760581593ae7e049878ed517685c7a6895aeee32..393bd98a4ef9ab342f2a80d96a1935045d64f82b 100644 (file)
          Thanks to Tony Finch for the contribution. [RT #41615]
        </para>
       </listitem>
+      <listitem>
+       <para>
+         <command>named</command> now provides feedback to the
+         owners of zones which have trust anchors configured
+         (<command>trusted-keys</command>,
+         <command>managed-keys</command>, <command>dnssec-validation
+         auto;</command> and <command>dnssec-lookaside auto;</command>)
+         by sending a daily query which encodes the keyids of the
+         configured trust anchors for the zone.  This is controlled
+         by <command>trust-anchor-telemetry</command> and defaults
+         to yes.
+       </para>
+      </listitem>
     </itemizedlist>
   </section>
 
index fde630cff54d8ada50d83780a294c2be6ca20d06..ebb85565ecff74e43a167cce75114beb11410c6f 100644 (file)
 
 ISC_LANG_BEGINDECLS
 
-struct dns_keytable {
-       /* Unlocked. */
-       unsigned int            magic;
-       isc_mem_t               *mctx;
-       isc_mutex_t             lock;
-       isc_rwlock_t            rwlock;
-       /* Locked by lock. */
-       isc_uint32_t            active_nodes;
-       /* Locked by rwlock. */
-       isc_uint32_t            references;
-       dns_rbt_t               *table;
-};
-
-#define KEYTABLE_MAGIC                 ISC_MAGIC('K', 'T', 'b', 'l')
-#define VALID_KEYTABLE(kt)             ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC)
-
-struct dns_keynode {
-       unsigned int            magic;
-       isc_refcount_t          refcount;
-       dst_key_t *             key;
-       isc_boolean_t           managed;
-       struct dns_keynode *    next;
-};
-
-#define KEYNODE_MAGIC                  ISC_MAGIC('K', 'N', 'o', 'd')
-#define VALID_KEYNODE(kn)              ISC_MAGIC_VALID(kn, KEYNODE_MAGIC)
-
 isc_result_t
 dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep);
 /*%<
@@ -453,6 +426,11 @@ dns_keynode_detachall(isc_mem_t *mctx, dns_keynode_t **target);
 /*%<
  * Detach a keynode and all its succesors.
  */
+
+isc_result_t
+dns_keytable_forall(dns_keytable_t *keytable,
+                    void (*func)(dns_keytable_t *, dns_keynode_t *, void *),
+                   void *arg);
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_KEYTABLE_H */
index 7653b6f886f52aa25d67c0b7192ca34161cd3162..bead8fbfa69864c11ced2f4084c63d9dc0ee0b37 100644 (file)
@@ -122,6 +122,7 @@ struct dns_view {
        isc_boolean_t                   enablevalidation;
        isc_boolean_t                   acceptexpired;
        isc_boolean_t                   requireservercookie;
+       isc_boolean_t                   trust_anchor_telemetry;
        dns_transfer_format_t           transfer_format;
        dns_acl_t *                     cacheacl;
        dns_acl_t *                     cacheonacl;
index ef96cc1c3f5126120ba19685419c44567aed03fb..1817b277870db99a7cf0bdaea804e088c9bf86c3 100644 (file)
 #include <dns/rbt.h>
 #include <dns/result.h>
 
+#define KEYTABLE_MAGIC                  ISC_MAGIC('K', 'T', 'b', 'l')
+#define VALID_KEYTABLE(kt)              ISC_MAGIC_VALID(kt, KEYTABLE_MAGIC)
+
+#define KEYNODE_MAGIC                   ISC_MAGIC('K', 'N', 'o', 'd')
+#define VALID_KEYNODE(kn)               ISC_MAGIC_VALID(kn, KEYNODE_MAGIC)
+
+struct dns_keytable {
+        /* Unlocked. */
+        unsigned int            magic;
+        isc_mem_t               *mctx;
+        isc_mutex_t             lock;
+        isc_rwlock_t            rwlock;
+        /* Locked by lock. */
+        isc_uint32_t            active_nodes;
+        /* Locked by rwlock. */
+        isc_uint32_t            references;
+        dns_rbt_t               *table;
+};
+
+struct dns_keynode {
+        unsigned int            magic;
+        isc_refcount_t          refcount;
+        dst_key_t *             key;
+        isc_boolean_t           managed;
+        struct dns_keynode *    next;
+};
+
 static void
 free_keynode(void *node, void *arg) {
        dns_keynode_t *keynode = node;
@@ -637,6 +664,43 @@ dns_keytable_totext(dns_keytable_t *keytable, isc_buffer_t **text) {
        return (result);
 }
 
+isc_result_t
+dns_keytable_forall(dns_keytable_t *keytable,
+                   void (*func)(dns_keytable_t *, dns_keynode_t *, void *),
+                   void *arg)
+{
+       isc_result_t result;
+       dns_rbtnode_t *node;
+       dns_rbtnodechain_t chain;
+
+       REQUIRE(VALID_KEYTABLE(keytable));
+
+       RWLOCK(&keytable->rwlock, isc_rwlocktype_read);
+       dns_rbtnodechain_init(&chain, keytable->mctx);
+       result = dns_rbtnodechain_first(&chain, keytable->table, NULL, NULL);
+       if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+               if (result == ISC_R_NOTFOUND)
+                       result = ISC_R_SUCCESS;
+               goto cleanup;
+       }
+       for (;;) {
+               dns_rbtnodechain_current(&chain, NULL, NULL, &node);
+               if (node->data != NULL)
+                       (*func)(keytable, node->data, arg);
+               result = dns_rbtnodechain_next(&chain, NULL, NULL);
+               if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+                       if (result == ISC_R_NOMORE)
+                               result = ISC_R_SUCCESS;
+                       break;
+               }
+       }
+
+   cleanup:
+       dns_rbtnodechain_invalidate(&chain);
+       RWUNLOCK(&keytable->rwlock, isc_rwlocktype_read);
+       return (result);
+}
+
 dst_key_t *
 dns_keynode_key(dns_keynode_t *keynode) {
 
index 7d51d3871397aab7dd8811e451e2a7c502f1d4fc..67b90afcbfd5ce1be1469e5ad4008053435aa35b 100644 (file)
 #include <dns/nta.h>
 #include <dns/order.h>
 #include <dns/peer.h>
-#include <dns/rrl.h>
 #include <dns/rbt.h>
 #include <dns/rdataset.h>
 #include <dns/request.h>
 #include <dns/resolver.h>
 #include <dns/result.h>
 #include <dns/rpz.h>
+#include <dns/rrl.h>
 #include <dns/stats.h>
 #include <dns/time.h>
 #include <dns/tsig.h>
@@ -233,6 +233,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
        view->requestnsid = ISC_FALSE;
        view->sendcookie = ISC_TRUE;
        view->requireservercookie = ISC_FALSE;
+       view->trust_anchor_telemetry = ISC_TRUE;
        view->new_zone_file = NULL;
        view->new_zone_db = NULL;
        view->new_zone_dbenv = NULL;
index 40f2e8fce7a836ea1fb76c75f6a8ebdf1d4f0642..38f5dd9b48b879a61d848cc4d454ee02001a7b51 100644 (file)
@@ -4010,6 +4010,54 @@ failure:
        return (result);
 }
 
+struct addifmissing_arg {
+       dns_db_t *db;
+       dns_dbversion_t *ver;
+       dns_diff_t *diff;
+       dns_zone_t *zone;
+       isc_boolean_t *changed;
+       isc_result_t result;
+};
+
+static void
+addifmissing(dns_keytable_t *keytable, dns_keynode_t *keynode, void *arg) {
+       dns_db_t *db = ((struct addifmissing_arg *)arg)->db;
+       dns_dbversion_t *ver = ((struct addifmissing_arg *)arg)->ver;
+       dns_diff_t *diff = ((struct addifmissing_arg *)arg)->diff;
+       dns_zone_t *zone = ((struct addifmissing_arg *)arg)->zone;
+       isc_boolean_t *changed = ((struct addifmissing_arg *)arg)->changed;
+       isc_result_t result;
+       dns_keynode_t *dummy = NULL;
+
+       if (((struct addifmissing_arg *)arg)->result != ISC_R_SUCCESS)
+               return;
+
+       if (dns_keynode_managed(keynode)) {
+               dns_fixedname_t fname;
+               dns_name_t *keyname;
+               dst_key_t *key;
+
+               key = dns_keynode_key(keynode);
+               if (key == NULL)
+                       return;
+               dns_fixedname_init(&fname);
+
+               keyname = dst_key_name(key);
+               result = dns_db_find(db, keyname, ver,
+                                    dns_rdatatype_keydata,
+                                    DNS_DBFIND_NOWILD, 0, NULL,
+                                    dns_fixedname_name(&fname),
+                                    NULL, NULL);
+               if (result == ISC_R_SUCCESS)
+                       return;
+               dns_keytable_attachkeynode(keytable, keynode, &dummy);
+               result = create_keydata(zone, db, ver, diff, keytable,
+                                       &dummy, changed);
+               if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
+                       ((struct addifmissing_arg *)arg)->result = result;
+       }
+};
+
 /*
  * Synchronize the set of initializing keys found in managed-keys {}
  * statements with the set of trust anchors found in the managed-keys.bind
@@ -4023,22 +4071,16 @@ sync_keyzone(dns_zone_t *zone, dns_db_t *db) {
        isc_result_t result = ISC_R_SUCCESS;
        isc_boolean_t changed = ISC_FALSE;
        isc_boolean_t commit = ISC_FALSE;
-       dns_rbtnodechain_t chain;
-       dns_fixedname_t fn;
-       dns_name_t foundname, *origin;
        dns_keynode_t *keynode = NULL;
        dns_view_t *view = zone->view;
        dns_keytable_t *sr = NULL;
        dns_dbversion_t *ver = NULL;
        dns_diff_t diff;
        dns_rriterator_t rrit;
+       struct addifmissing_arg arg;
 
        dns_zone_log(zone, ISC_LOG_DEBUG(1), "synchronizing trusted keys");
 
-       dns_name_init(&foundname, NULL);
-       dns_fixedname_init(&fn);
-       origin = dns_fixedname_name(&fn);
-
        dns_diff_init(zone->mctx, &diff);
 
        CHECK(dns_view_getsecroots(view, &sr));
@@ -4097,52 +4139,14 @@ sync_keyzone(dns_zone_t *zone, dns_db_t *db) {
         * Now walk secroots to find any managed keys that aren't
         * in the zone.  If we find any, we add them to the zone.
         */
-       RWLOCK(&sr->rwlock, isc_rwlocktype_write);
-       dns_rbtnodechain_init(&chain, zone->mctx);
-       result = dns_rbtnodechain_first(&chain, sr->table, &foundname, origin);
-       if (result == ISC_R_NOTFOUND)
-               result = ISC_R_NOMORE;
-       while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
-               dns_rbtnode_t *rbtnode = NULL;
-
-               dns_rbtnodechain_current(&chain, &foundname, origin, &rbtnode);
-               if (rbtnode->data == NULL)
-                       goto skip;
-
-               dns_keytable_attachkeynode(sr, rbtnode->data, &keynode);
-               if (dns_keynode_managed(keynode)) {
-                       dns_fixedname_t fname;
-                       dns_name_t *keyname;
-                       dst_key_t *key;
-
-                       key = dns_keynode_key(keynode);
-                       dns_fixedname_init(&fname);
-
-                       if (key == NULL)   /* fail_secure() was called. */
-                               goto skip;
-
-                       keyname = dst_key_name(key);
-                       result = dns_db_find(db, keyname, ver,
-                                            dns_rdatatype_keydata,
-                                            DNS_DBFIND_NOWILD, 0, NULL,
-                                            dns_fixedname_name(&fname),
-                                            NULL, NULL);
-                       if (result != ISC_R_SUCCESS)
-                               result = create_keydata(zone, db, ver, &diff,
-                                                       sr, &keynode, &changed);
-                       if (result != ISC_R_SUCCESS)
-                               break;
-               }
-  skip:
-               result = dns_rbtnodechain_next(&chain, &foundname, origin);
-               if (keynode != NULL)
-                       dns_keytable_detachkeynode(sr, &keynode);
-       }
-       RWUNLOCK(&sr->rwlock, isc_rwlocktype_write);
-
-       if (result == ISC_R_NOMORE)
-               result = ISC_R_SUCCESS;
-
+       arg.db = db;
+       arg.ver = ver;
+       arg.result = ISC_R_SUCCESS;
+       arg.diff = &diff;
+       arg.zone = zone;
+       arg.changed = &changed;
+       dns_keytable_forall(sr, addifmissing, &arg);
+       result = arg.result;
        if (changed) {
                /* Write changes to journal file. */
                CHECK(update_soa_serial(db, ver, &diff, zone->mctx,
index 610db0e527af20960d1a95eb870890722ad0e9e1..142ef0188be4cea386acd8c805fdfca3e517912d 100644 (file)
@@ -1749,6 +1749,7 @@ view_clauses[] = {
        { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
        { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
        { "transfer-format", &cfg_type_transferformat, 0 },
+       { "trust-anchor-telemetry", &cfg_type_boolean, 0 },
        { "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
        { "v6-bias", &cfg_type_uint32, 0 },
        { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },