+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]
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\
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);
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;
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);
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.
}
}
+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;
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.
*/
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),
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);
server->interface_timer = NULL;
server->heartbeat_timer = NULL;
server->pps_timer = NULL;
+ server->tat_timer = NULL;
server->interface_interval = 0;
server->heartbeat_interval = 0;
* 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 */ };
notify yes;
dnssec-enable yes;
dnssec-validation yes;
+ /* test that we can turn off trust-anchor-telemetry */
+ trust-anchor-telemetry no;
};
zone "." {
--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
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
--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
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
</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)(...)".<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.
+ </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>
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>
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);
/*%<
/*%<
* 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 */
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;
#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;
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) {
#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>
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;
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
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));
* 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,
{ "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 },