mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 18:19:42 +00:00
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]
This commit is contained in:
parent
9616761417
commit
f20179857a
7
CHANGES
7
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
|
4423. [maint] Added missing IPv6 address 2001:500:84::b for
|
||||||
B.ROOT-SERVERS.NET. [RT #42898]
|
B.ROOT-SERVERS.NET. [RT #42898]
|
||||||
|
|
||||||
|
@ -109,6 +109,7 @@ options {\n\
|
|||||||
transfers-in 10;\n\
|
transfers-in 10;\n\
|
||||||
transfers-out 10;\n\
|
transfers-out 10;\n\
|
||||||
# treat-cr-as-space <obsolete>;\n\
|
# treat-cr-as-space <obsolete>;\n\
|
||||||
|
trust-anchor-telemetry yes;\n\
|
||||||
# use-id-pool <obsolete>;\n\
|
# use-id-pool <obsolete>;\n\
|
||||||
# use-ixfr <obsolete>;\n\
|
# use-ixfr <obsolete>;\n\
|
||||||
edns-udp-size 4096;\n\
|
edns-udp-size 4096;\n\
|
||||||
|
@ -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_notcp INIT(ISC_FALSE);
|
||||||
EXTERN isc_boolean_t ns_g_disable6 INIT(ISC_FALSE);
|
EXTERN isc_boolean_t ns_g_disable6 INIT(ISC_FALSE);
|
||||||
EXTERN isc_boolean_t ns_g_disable4 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
|
#ifdef HAVE_GEOIP
|
||||||
EXTERN dns_geoip_databases_t *ns_g_geoip INIT(NULL);
|
EXTERN dns_geoip_databases_t *ns_g_geoip INIT(NULL);
|
||||||
|
@ -76,6 +76,7 @@ struct ns_server {
|
|||||||
isc_timer_t * interface_timer;
|
isc_timer_t * interface_timer;
|
||||||
isc_timer_t * heartbeat_timer;
|
isc_timer_t * heartbeat_timer;
|
||||||
isc_timer_t * pps_timer;
|
isc_timer_t * pps_timer;
|
||||||
|
isc_timer_t * tat_timer;
|
||||||
|
|
||||||
isc_uint32_t interface_interval;
|
isc_uint32_t interface_interval;
|
||||||
isc_uint32_t heartbeat_interval;
|
isc_uint32_t heartbeat_interval;
|
||||||
|
@ -640,6 +640,9 @@ parse_command_line(int argc, char *argv[]) {
|
|||||||
ns_main_earlyfatal("bad mkeytimer");
|
ns_main_earlyfatal("bad mkeytimer");
|
||||||
} else if (!strcmp(isc_commandline_argument, "notcp"))
|
} else if (!strcmp(isc_commandline_argument, "notcp"))
|
||||||
ns_g_notcp = ISC_TRUE;
|
ns_g_notcp = ISC_TRUE;
|
||||||
|
else if (!strncmp(isc_commandline_argument, "tat=", 4))
|
||||||
|
ns_g_tat_interval =
|
||||||
|
atoi(isc_commandline_argument + 4);
|
||||||
else
|
else
|
||||||
fprintf(stderr, "unknown -T flag '%s\n",
|
fprintf(stderr, "unknown -T flag '%s\n",
|
||||||
isc_commandline_argument);
|
isc_commandline_argument);
|
||||||
|
@ -4103,6 +4103,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
|
|||||||
else
|
else
|
||||||
INSIST(0);
|
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
|
* Set sources where additional data and CNAME/DNAME
|
||||||
* targets for authoritative answers may be found.
|
* 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
|
static void
|
||||||
pps_timer_tick(isc_task_t *task, isc_event_t *event) {
|
pps_timer_tick(isc_task_t *task, isc_event_t *event) {
|
||||||
static unsigned int oldrequests = 0;
|
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,
|
CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
|
||||||
&interval, ISC_FALSE));
|
&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.
|
* Write the PID file.
|
||||||
*/
|
*/
|
||||||
@ -7970,6 +8159,11 @@ run_server(isc_task_t *task, isc_event_t *event) {
|
|||||||
server, &server->heartbeat_timer),
|
server, &server->heartbeat_timer),
|
||||||
"creating 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,
|
CHECKFATAL(isc_timer_create(ns_g_timermgr, isc_timertype_inactive,
|
||||||
NULL, NULL, server->task, pps_timer_tick,
|
NULL, NULL, server->task, pps_timer_tick,
|
||||||
server, &server->pps_timer),
|
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->interface_timer);
|
||||||
isc_timer_detach(&server->heartbeat_timer);
|
isc_timer_detach(&server->heartbeat_timer);
|
||||||
isc_timer_detach(&server->pps_timer);
|
isc_timer_detach(&server->pps_timer);
|
||||||
|
isc_timer_detach(&server->tat_timer);
|
||||||
|
|
||||||
ns_interfacemgr_shutdown(server->interfacemgr);
|
ns_interfacemgr_shutdown(server->interfacemgr);
|
||||||
ns_interfacemgr_detach(&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->interface_timer = NULL;
|
||||||
server->heartbeat_timer = NULL;
|
server->heartbeat_timer = NULL;
|
||||||
server->pps_timer = NULL;
|
server->pps_timer = NULL;
|
||||||
|
server->tat_timer = NULL;
|
||||||
|
|
||||||
server->interface_interval = 0;
|
server->interface_interval = 0;
|
||||||
server->heartbeat_interval = 0;
|
server->heartbeat_interval = 0;
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
* file, You can obtain one at http://mozilla.org/MPL/2.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
|
// NS1
|
||||||
|
|
||||||
controls { /* empty */ };
|
controls { /* empty */ };
|
||||||
@ -24,6 +22,8 @@ options {
|
|||||||
notify yes;
|
notify yes;
|
||||||
dnssec-enable yes;
|
dnssec-enable yes;
|
||||||
dnssec-validation yes;
|
dnssec-validation yes;
|
||||||
|
/* test that we can turn off trust-anchor-telemetry */
|
||||||
|
trust-anchor-telemetry no;
|
||||||
};
|
};
|
||||||
|
|
||||||
zone "." {
|
zone "." {
|
||||||
|
@ -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
|
||||||
|
@ -3286,5 +3286,26 @@ n=`expr $n + 1`
|
|||||||
if [ $ret != 0 ]; then echo "I:failed"; fi
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
status=`expr $status + $ret`
|
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"
|
echo "I:exit status: $status"
|
||||||
[ $status -eq 0 ] || exit 1
|
[ $status -eq 0 ] || exit 1
|
||||||
|
@ -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
|
||||||
|
@ -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
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
status=`expr $status + $ret`
|
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"
|
echo "I:exit status: $status"
|
||||||
[ $status -eq 0 ] || exit 1
|
[ $status -eq 0 ] || exit 1
|
||||||
|
@ -6435,6 +6435,37 @@ options {
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
<varlistentry>
|
||||||
<term><command>use-id-pool</command></term>
|
<term><command>use-id-pool</command></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -609,6 +609,19 @@
|
|||||||
Thanks to Tony Finch for the contribution. [RT #41615]
|
Thanks to Tony Finch for the contribution. [RT #41615]
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</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>
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -44,33 +44,6 @@
|
|||||||
|
|
||||||
ISC_LANG_BEGINDECLS
|
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
|
isc_result_t
|
||||||
dns_keytable_create(isc_mem_t *mctx, dns_keytable_t **keytablep);
|
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.
|
* 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
|
ISC_LANG_ENDDECLS
|
||||||
|
|
||||||
#endif /* DNS_KEYTABLE_H */
|
#endif /* DNS_KEYTABLE_H */
|
||||||
|
@ -122,6 +122,7 @@ struct dns_view {
|
|||||||
isc_boolean_t enablevalidation;
|
isc_boolean_t enablevalidation;
|
||||||
isc_boolean_t acceptexpired;
|
isc_boolean_t acceptexpired;
|
||||||
isc_boolean_t requireservercookie;
|
isc_boolean_t requireservercookie;
|
||||||
|
isc_boolean_t trust_anchor_telemetry;
|
||||||
dns_transfer_format_t transfer_format;
|
dns_transfer_format_t transfer_format;
|
||||||
dns_acl_t * cacheacl;
|
dns_acl_t * cacheacl;
|
||||||
dns_acl_t * cacheonacl;
|
dns_acl_t * cacheonacl;
|
||||||
|
@ -23,6 +23,33 @@
|
|||||||
#include <dns/rbt.h>
|
#include <dns/rbt.h>
|
||||||
#include <dns/result.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
|
static void
|
||||||
free_keynode(void *node, void *arg) {
|
free_keynode(void *node, void *arg) {
|
||||||
dns_keynode_t *keynode = node;
|
dns_keynode_t *keynode = node;
|
||||||
@ -637,6 +664,43 @@ dns_keytable_totext(dns_keytable_t *keytable, isc_buffer_t **text) {
|
|||||||
return (result);
|
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 *
|
dst_key_t *
|
||||||
dns_keynode_key(dns_keynode_t *keynode) {
|
dns_keynode_key(dns_keynode_t *keynode) {
|
||||||
|
|
||||||
|
@ -43,13 +43,13 @@
|
|||||||
#include <dns/nta.h>
|
#include <dns/nta.h>
|
||||||
#include <dns/order.h>
|
#include <dns/order.h>
|
||||||
#include <dns/peer.h>
|
#include <dns/peer.h>
|
||||||
#include <dns/rrl.h>
|
|
||||||
#include <dns/rbt.h>
|
#include <dns/rbt.h>
|
||||||
#include <dns/rdataset.h>
|
#include <dns/rdataset.h>
|
||||||
#include <dns/request.h>
|
#include <dns/request.h>
|
||||||
#include <dns/resolver.h>
|
#include <dns/resolver.h>
|
||||||
#include <dns/result.h>
|
#include <dns/result.h>
|
||||||
#include <dns/rpz.h>
|
#include <dns/rpz.h>
|
||||||
|
#include <dns/rrl.h>
|
||||||
#include <dns/stats.h>
|
#include <dns/stats.h>
|
||||||
#include <dns/time.h>
|
#include <dns/time.h>
|
||||||
#include <dns/tsig.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->requestnsid = ISC_FALSE;
|
||||||
view->sendcookie = ISC_TRUE;
|
view->sendcookie = ISC_TRUE;
|
||||||
view->requireservercookie = ISC_FALSE;
|
view->requireservercookie = ISC_FALSE;
|
||||||
|
view->trust_anchor_telemetry = ISC_TRUE;
|
||||||
view->new_zone_file = NULL;
|
view->new_zone_file = NULL;
|
||||||
view->new_zone_db = NULL;
|
view->new_zone_db = NULL;
|
||||||
view->new_zone_dbenv = NULL;
|
view->new_zone_dbenv = NULL;
|
||||||
|
110
lib/dns/zone.c
110
lib/dns/zone.c
@ -4010,6 +4010,54 @@ failure:
|
|||||||
return (result);
|
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 {}
|
* Synchronize the set of initializing keys found in managed-keys {}
|
||||||
* statements with the set of trust anchors found in the managed-keys.bind
|
* 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_result_t result = ISC_R_SUCCESS;
|
||||||
isc_boolean_t changed = ISC_FALSE;
|
isc_boolean_t changed = ISC_FALSE;
|
||||||
isc_boolean_t commit = 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_keynode_t *keynode = NULL;
|
||||||
dns_view_t *view = zone->view;
|
dns_view_t *view = zone->view;
|
||||||
dns_keytable_t *sr = NULL;
|
dns_keytable_t *sr = NULL;
|
||||||
dns_dbversion_t *ver = NULL;
|
dns_dbversion_t *ver = NULL;
|
||||||
dns_diff_t diff;
|
dns_diff_t diff;
|
||||||
dns_rriterator_t rrit;
|
dns_rriterator_t rrit;
|
||||||
|
struct addifmissing_arg arg;
|
||||||
|
|
||||||
dns_zone_log(zone, ISC_LOG_DEBUG(1), "synchronizing trusted keys");
|
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);
|
dns_diff_init(zone->mctx, &diff);
|
||||||
|
|
||||||
CHECK(dns_view_getsecroots(view, &sr));
|
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
|
* Now walk secroots to find any managed keys that aren't
|
||||||
* in the zone. If we find any, we add them to the zone.
|
* in the zone. If we find any, we add them to the zone.
|
||||||
*/
|
*/
|
||||||
RWLOCK(&sr->rwlock, isc_rwlocktype_write);
|
arg.db = db;
|
||||||
dns_rbtnodechain_init(&chain, zone->mctx);
|
arg.ver = ver;
|
||||||
result = dns_rbtnodechain_first(&chain, sr->table, &foundname, origin);
|
arg.result = ISC_R_SUCCESS;
|
||||||
if (result == ISC_R_NOTFOUND)
|
arg.diff = &diff;
|
||||||
result = ISC_R_NOMORE;
|
arg.zone = zone;
|
||||||
while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
|
arg.changed = &changed;
|
||||||
dns_rbtnode_t *rbtnode = NULL;
|
dns_keytable_forall(sr, addifmissing, &arg);
|
||||||
|
result = arg.result;
|
||||||
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;
|
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
/* Write changes to journal file. */
|
/* Write changes to journal file. */
|
||||||
CHECK(update_soa_serial(db, ver, &diff, zone->mctx,
|
CHECK(update_soa_serial(db, ver, &diff, zone->mctx,
|
||||||
|
@ -1749,6 +1749,7 @@ view_clauses[] = {
|
|||||||
{ "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
|
{ "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
|
||||||
{ "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
|
{ "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
|
||||||
{ "transfer-format", &cfg_type_transferformat, 0 },
|
{ "transfer-format", &cfg_type_transferformat, 0 },
|
||||||
|
{ "trust-anchor-telemetry", &cfg_type_boolean, 0 },
|
||||||
{ "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
|
{ "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
|
||||||
{ "v6-bias", &cfg_type_uint32, 0 },
|
{ "v6-bias", &cfg_type_uint32, 0 },
|
||||||
{ "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
|
{ "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user