From f20179857a8512441c3be7ad33f1c84e367de041 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 22 Jul 2016 20:02:17 +1000 Subject: [PATCH] 4424. [experimental] Named now sends _ta-XXXX./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] --- CHANGES | 7 + bin/named/config.c | 1 + bin/named/include/named/globals.h | 1 + bin/named/include/named/server.h | 1 + bin/named/main.c | 3 + bin/named/server.c | 196 +++++++++++++++++++++++++ bin/tests/system/dnssec/ns1/named.conf | 4 +- bin/tests/system/dnssec/ns6/named.args | 2 +- bin/tests/system/dnssec/tests.sh | 21 +++ bin/tests/system/mkeys/ns3/named.args | 2 +- bin/tests/system/mkeys/tests.sh | 14 ++ doc/arm/Bv9ARM-book.xml | 31 ++++ doc/arm/notes.xml | 13 ++ lib/dns/include/dns/keytable.h | 32 +--- lib/dns/include/dns/view.h | 1 + lib/dns/keytable.c | 64 ++++++++ lib/dns/view.c | 3 +- lib/dns/zone.c | 110 +++++++------- lib/isccfg/namedconf.c | 1 + 19 files changed, 422 insertions(+), 85 deletions(-) diff --git a/CHANGES b/CHANGES index c926ce6e6b..46dffcc25e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +4424. [experimental] Named now sends _ta-XXXX./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] diff --git a/bin/named/config.c b/bin/named/config.c index 5e22269f29..638a2b3f9b 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -109,6 +109,7 @@ options {\n\ transfers-in 10;\n\ transfers-out 10;\n\ # treat-cr-as-space ;\n\ + trust-anchor-telemetry yes;\n\ # use-id-pool ;\n\ # use-ixfr ;\n\ edns-udp-size 4096;\n\ diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h index b0223242a6..c95350ce55 100644 --- a/bin/named/include/named/globals.h +++ b/bin/named/include/named/globals.h @@ -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); diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index 2ecd888578..8fd3899a7d 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -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; diff --git a/bin/named/main.c b/bin/named/main.c index 7f427ffe3a..8c01d75ba4 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -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); diff --git a/bin/named/server.c b/bin/named/server.c index 3363db2af5..bb5453f720 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -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; diff --git a/bin/tests/system/dnssec/ns1/named.conf b/bin/tests/system/dnssec/ns1/named.conf index 80e5faf5cd..d2d754b4eb 100644 --- a/bin/tests/system/dnssec/ns1/named.conf +++ b/bin/tests/system/dnssec/ns1/named.conf @@ -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 "." { diff --git a/bin/tests/system/dnssec/ns6/named.args b/bin/tests/system/dnssec/ns6/named.args index 34442d8543..04cf949bf6 100644 --- a/bin/tests/system/dnssec/ns6/named.args +++ b/bin/tests/system/dnssec/ns6/named.args @@ -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 diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index 6cc9c60333..437246a0fc 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -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 diff --git a/bin/tests/system/mkeys/ns3/named.args b/bin/tests/system/mkeys/ns3/named.args index 25c42898ca..038b980eca 100644 --- a/bin/tests/system/mkeys/ns3/named.args +++ b/bin/tests/system/mkeys/ns3/named.args @@ -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 diff --git a/bin/tests/system/mkeys/tests.sh b/bin/tests/system/mkeys/tests.sh index fe9978d183..f0c85670b8 100644 --- a/bin/tests/system/mkeys/tests.sh +++ b/bin/tests/system/mkeys/tests.sh @@ -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 diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 2119d564e7..dd679090a4 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -6435,6 +6435,37 @@ options { + + trust-anchor-telemetry + + + Causes named to send specially-formed + queries once per day to domains for which trust anchors + have been configured via trusted-keys, + managed-keys, + dnssec-validation auto, or + dnssec-lookaside auto. + + + The query name used for these queries has the + form "_ta-xxxx(-xxxx)(...)".<domain>, 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. + + + 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. + + + The default is yes. + + + + use-id-pool diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index 760581593a..393bd98a4e 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -609,6 +609,19 @@ Thanks to Tony Finch for the contribution. [RT #41615] + + + named now provides feedback to the + owners of zones which have trust anchors configured + (trusted-keys, + managed-keys, dnssec-validation + auto; and dnssec-lookaside auto;) + by sending a daily query which encodes the keyids of the + configured trust anchors for the zone. This is controlled + by trust-anchor-telemetry and defaults + to yes. + + diff --git a/lib/dns/include/dns/keytable.h b/lib/dns/include/dns/keytable.h index fde630cff5..ebb85565ec 100644 --- a/lib/dns/include/dns/keytable.h +++ b/lib/dns/include/dns/keytable.h @@ -44,33 +44,6 @@ 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 */ diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 7653b6f886..bead8fbfa6 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -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; diff --git a/lib/dns/keytable.c b/lib/dns/keytable.c index ef96cc1c3f..1817b27787 100644 --- a/lib/dns/keytable.c +++ b/lib/dns/keytable.c @@ -23,6 +23,33 @@ #include #include +#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) { diff --git a/lib/dns/view.c b/lib/dns/view.c index 7d51d38713..67b90afcbf 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -43,13 +43,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -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; diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 40f2e8fce7..38f5dd9b48 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -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, diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 610db0e527..142ef0188b 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -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 },