2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-22 10:10:06 +00:00

[master] complete NTA work

3882.	[func]		By default, negative trust anchors will be tested
			periodically to see whether data below them can be
			validated, and if so, they will be allowed to
			expire early. The "rndc nta -force" option
			overrides this behvaior.  The default NTA lifetime
			and the recheck frequency can be configured by the
			"nta-lifetime" and "nta-recheck" options. [RT #36146]
This commit is contained in:
Evan Hunt 2014-06-18 16:47:22 -07:00
parent 8eb2d262dc
commit b8a9632333
29 changed files with 802 additions and 169 deletions

View File

@ -1,3 +1,11 @@
3882. [func] By default, negative trust anchors will be tested
periodically to see whether data below them can be
validated, and if so, they will be allowed to
expire early. The "rndc nta -force" option
overrides this behvaior. The default NTA lifetime
and the recheck frequency can be configured by the
"nta-lifetime" and "nta-recheck" options. [RT #36146]
3881. [bug] Address memory leak with UPDATE error handling. 3881. [bug] Address memory leak with UPDATE error handling.
[RT #36303] [RT #36303]

View File

@ -53,6 +53,7 @@
static char defaultconf[] = "\ static char defaultconf[] = "\
options {\n\ options {\n\
automatic-interface-scan yes;\n\ automatic-interface-scan yes;\n\
bindkeys-file \"" NS_SYSCONFDIR "/bind.keys\";\n\
# blackhole {none;};\n" # blackhole {none;};\n"
#ifndef WIN32 #ifndef WIN32
" coresize default;\n\ " coresize default;\n\
@ -78,8 +79,9 @@ options {\n\
memstatistics-file \"named.memstats\";\n\ memstatistics-file \"named.memstats\";\n\
multiple-cnames no;\n\ multiple-cnames no;\n\
# named-xfer <obsolete>;\n\ # named-xfer <obsolete>;\n\
nta-lifetime 3600;\n\
nta-recheck 300;\n\
# pid-file \"" NS_LOCALSTATEDIR "/run/named/named.pid\"; /* or /lwresd.pid */\n\ # pid-file \"" NS_LOCALSTATEDIR "/run/named/named.pid\"; /* or /lwresd.pid */\n\
bindkeys-file \"" NS_SYSCONFDIR "/bind.keys\";\n\
port 53;\n\ port 53;\n\
prefetch 2 9;\n\ prefetch 2 9;\n\
recursing-file \"named.recursing\";\n\ recursing-file \"named.recursing\";\n\

View File

@ -15,8 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
/* $Id$ */
/*! \file */ /*! \file */
#include <config.h> #include <config.h>

View File

@ -826,7 +826,7 @@ configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
return (ISC_R_UNEXPECTED); return (ISC_R_UNEXPECTED);
} }
result = dns_view_initntatable(view, mctx); result = dns_view_initntatable(view, ns_g_taskmgr, ns_g_timermgr);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
NS_LOGMODULE_SERVER, ISC_LOG_ERROR, NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
@ -3566,6 +3566,16 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
if (result == ISC_R_SUCCESS) if (result == ISC_R_SUCCESS)
CHECK(mustbesecure(obj, view->resolver)); CHECK(mustbesecure(obj, view->resolver));
obj = NULL;
result = ns_config_get(maps, "nta-recheck", &obj);
INSIST(result == ISC_R_SUCCESS);
view->nta_recheck = cfg_obj_asuint32(obj);
obj = NULL;
result = ns_config_get(maps, "nta-lifetime", &obj);
INSIST(result == ISC_R_SUCCESS);
view->nta_lifetime = cfg_obj_asuint32(obj);
obj = NULL; obj = NULL;
result = ns_config_get(maps, "preferred-glue", &obj); result = ns_config_get(maps, "preferred-glue", &obj);
if (result == ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) {
@ -3626,6 +3636,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
} else { } else {
empty_zones_enable = ISC_FALSE; empty_zones_enable = ISC_FALSE;
} }
if (empty_zones_enable && !lwresd_g_useresolvconf) { if (empty_zones_enable && !lwresd_g_useresolvconf) {
const char *empty; const char *empty;
int empty_zone = 0; int empty_zone = 0;
@ -7768,6 +7779,7 @@ isc_result_t
ns_server_dumpsecroots(ns_server_t *server, char *args) { ns_server_dumpsecroots(ns_server_t *server, char *args) {
dns_view_t *view; dns_view_t *view;
dns_keytable_t *secroots = NULL; dns_keytable_t *secroots = NULL;
dns_ntatable_t *ntatable = NULL;
isc_result_t result; isc_result_t result;
char *ptr; char *ptr;
FILE *fp = NULL; FILE *fp = NULL;
@ -7801,11 +7813,25 @@ ns_server_dumpsecroots(ns_server_t *server, char *args) {
result = ISC_R_SUCCESS; result = ISC_R_SUCCESS;
continue; continue;
} }
fprintf(fp, "\n Start view %s\n\n", view->name); fprintf(fp, "\n Start view %s\n", view->name);
fprintf(fp, " Secure roots:\n\n");
result = dns_keytable_dump(secroots, fp); result = dns_keytable_dump(secroots, fp);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
fprintf(fp, " dumpsecroots failed: %s\n", fprintf(fp, " dumpsecroots failed: %s\n",
isc_result_totext(result)); isc_result_totext(result));
if (ntatable != NULL)
dns_ntatable_detach(&ntatable);
result = dns_view_getntatable(view, &ntatable);
if (result == ISC_R_NOTFOUND) {
result = ISC_R_SUCCESS;
continue;
}
fprintf(fp, "\n Negative trust anchors:\n\n");
result = dns_ntatable_dump(ntatable, fp);
if (result != ISC_R_SUCCESS)
fprintf(fp, " dumpntatable failed: %s\n",
isc_result_totext(result));
} }
if (ptr != NULL) if (ptr != NULL)
ptr = next_token(&args, " \t"); ptr = next_token(&args, " \t");
@ -7814,6 +7840,8 @@ ns_server_dumpsecroots(ns_server_t *server, char *args) {
cleanup: cleanup:
if (secroots != NULL) if (secroots != NULL)
dns_keytable_detach(&secroots); dns_keytable_detach(&secroots);
if (ntatable != NULL)
dns_ntatable_detach(&ntatable);
if (fp != NULL) if (fp != NULL)
(void)isc_stdio_close(fp); (void)isc_stdio_close(fp);
if (result == ISC_R_SUCCESS) if (result == ISC_R_SUCCESS)
@ -9772,15 +9800,18 @@ ns_server_nta(ns_server_t *server, char *args, isc_buffer_t *text) {
dns_view_t *view; dns_view_t *view;
dns_ntatable_t *ntatable = NULL; dns_ntatable_t *ntatable = NULL;
isc_result_t result; isc_result_t result;
char *ptr, *nametext, *viewname; char *ptr, *nametext = NULL, *viewname;
isc_stdtime_t now, when; isc_stdtime_t now, when;
isc_time_t t; isc_time_t t;
char tbuf[64]; char tbuf[64];
const char *msg = NULL; const char *msg = NULL;
isc_boolean_t dump = ISC_FALSE, force = ISC_FALSE;
dns_fixedname_t fn; dns_fixedname_t fn;
dns_name_t *ntaname; dns_name_t *ntaname;
dns_ttl_t ntattl; dns_ttl_t ntattl;
isc_textregion_t tr; isc_boolean_t ttlset = ISC_FALSE;
UNUSED(force);
dns_fixedname_init(&fn); dns_fixedname_init(&fn);
ntaname = dns_fixedname_name(&fn); ntaname = dns_fixedname_name(&fn);
@ -9790,8 +9821,78 @@ ns_server_nta(ns_server_t *server, char *args, isc_buffer_t *text) {
if (ptr == NULL) if (ptr == NULL)
return (ISC_R_UNEXPECTEDEND); return (ISC_R_UNEXPECTEDEND);
for (;;) {
size_t len;
/* Check for options */
ptr = next_token(&args, " \t");
if (ptr == NULL)
return (ISC_R_UNEXPECTEDEND);
len = strlen(ptr);
if (strncasecmp(ptr, "-dump", len) == 0)
dump = ISC_TRUE;
else if (strncasecmp(ptr, "-remove", len) == 0) {
ntattl = 0;
ttlset = ISC_TRUE;
} else if (strncasecmp(ptr, "-force", len) == 0) {
force = ISC_TRUE;
continue;
} else if (strncasecmp(ptr, "-lifetime", len) == 0) {
isc_textregion_t tr;
ptr = next_token(&args, " \t");
if (ptr == NULL) {
msg = "No lifetime specified";
CHECK(ISC_R_UNEXPECTEDEND);
}
tr.base = ptr;
tr.length = strlen(ptr);
result = dns_ttl_fromtext(&tr, &ntattl);
if (result != ISC_R_SUCCESS) {
msg = "could not parse NTA lifetime";
CHECK(result);
}
if (ntattl > 86400) {
msg = "NTA lifetime cannot exceed one day";
CHECK(ISC_R_RANGE);
}
ttlset = ISC_TRUE;
continue;
} else
nametext = ptr;
break;
}
/*
* If -dump was specified, list NTA's and return
*/
if (dump) {
for (view = ISC_LIST_HEAD(server->viewlist);
view != NULL;
view = ISC_LIST_NEXT(view, link))
{
if (ntatable != NULL)
dns_ntatable_detach(&ntatable);
result = dns_view_getntatable(view, &ntatable);
if (result == ISC_R_NOTFOUND) {
result = ISC_R_SUCCESS;
continue;
}
CHECK(dns_ntatable_totext(ntatable, text));
}
goto cleanup;
}
/* Get the NTA name. */ /* Get the NTA name. */
nametext = next_token(&args, " \t"); if (nametext == NULL)
nametext = next_token(&args, " \t");
if (nametext == NULL) if (nametext == NULL)
return (ISC_R_UNEXPECTEDEND); return (ISC_R_UNEXPECTEDEND);
@ -9804,26 +9905,10 @@ ns_server_nta(ns_server_t *server, char *args, isc_buffer_t *text) {
CHECK(dns_name_fromtext(ntaname, &b, dns_rootname, 0, NULL)); CHECK(dns_name_fromtext(ntaname, &b, dns_rootname, 0, NULL));
} }
/* Get the NTA duration. */
ptr = next_token(&args, " \t");
if (ptr == NULL)
return (ISC_R_UNEXPECTEDEND);
tr.base = ptr;
tr.length = strlen(ptr);
CHECK(dns_ttl_fromtext(&tr, &ntattl));
if (ntattl > 86400) {
msg = "NTA cannot exceed one day";
CHECK(ISC_R_RANGE);
}
/* Look for the view name. */ /* Look for the view name. */
viewname = next_token(&args, " \t"); viewname = next_token(&args, " \t");
/* Set up the NTA */
isc_stdtime_get(&now); isc_stdtime_get(&now);
when = now + ntattl;
result = isc_task_beginexclusive(server->task); result = isc_task_beginexclusive(server->task);
RUNTIME_CHECK(result == ISC_R_SUCCESS); RUNTIME_CHECK(result == ISC_R_SUCCESS);
@ -9835,6 +9920,12 @@ ns_server_nta(ns_server_t *server, char *args, isc_buffer_t *text) {
strcmp(view->name, viewname) != 0) strcmp(view->name, viewname) != 0)
continue; continue;
if (view->nta_lifetime == 0 || view->nta_recheck == 0)
continue;
if (!ttlset)
ntattl = view->nta_lifetime;
if (ntatable != NULL) if (ntatable != NULL)
dns_ntatable_detach(&ntatable); dns_ntatable_detach(&ntatable);
@ -9851,11 +9942,13 @@ ns_server_nta(ns_server_t *server, char *args, isc_buffer_t *text) {
nametext, view->name, nametext, view->name,
isc_result_totext(result)); isc_result_totext(result));
isc_time_set(&t, when, 0); if (ntattl != 0) {
isc_time_formattimestamp(&t, tbuf, sizeof(tbuf)); CHECK(dns_ntatable_add(ntatable, ntaname,
force, now, ntattl));
if (ntattl > 0) { when = now + ntattl;
CHECK(dns_ntatable_add(ntatable, ntaname, when)); isc_time_set(&t, when, 0);
isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
CHECK(putstr(text, "Negative trust anchor added: ")); CHECK(putstr(text, "Negative trust anchor added: "));
CHECK(putstr(text, nametext)); CHECK(putstr(text, nametext));

View File

@ -463,10 +463,9 @@
<term><userinput>secroots <optional><replaceable>view ...</replaceable></optional></userinput></term> <term><userinput>secroots <optional><replaceable>view ...</replaceable></optional></userinput></term>
<listitem> <listitem>
<para> <para>
Dump the server's security roots to the secroots Dump the server's security roots and negative trust anchors
file for the specified views. If no view is to the secroots file for the specified views. If no view is
specified, security roots for all specified, all views are dumped.
views are dumped.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -597,12 +596,19 @@
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><userinput>nta <replaceable>domain</replaceable> <replaceable>duration</replaceable> </userinput></term> <term><userinput>nta
<optional>( -d | -f | -r | -l <replaceable>duration</replaceable>)</optional>
<replaceable>domain</replaceable>
<optional><replaceable>view</replaceable></optional>
</userinput></term>
<listitem> <listitem>
<para> <para>
Sets a DNSSEC negative trust anchor (NTA) Sets a DNSSEC negative trust anchor (NTA)
for <option>domain</option>, with a lifetime of for <option>domain</option>, with a lifetime of
<option>duration</option> (up to a limit of one day). <option>lifetime</option>. The default lifetime is
configured in <file>named.conf</file> via the
<option>nta-lifetime</option>, and defaults to
one hour. The lifetime cannot exceed one day.
</para> </para>
<para> <para>
A negative trust anchor selectively disables A negative trust anchor selectively disables
@ -617,13 +623,40 @@
restarted (NTA's do not persist across restarts). restarted (NTA's do not persist across restarts).
</para> </para>
<para> <para>
TTL-style suffixes can be used to specify An existing NTA can be removed by using the
<option>duration</option> in seconds, minutes, or hours. <option>-remove</option> option.
</para> </para>
<para> <para>
If the specified domain already has an NTA, its duration An NTA's lifetime can be specified with the
will be updated to the new value. Setting <option>-lifetime</option> option. TTL-style
<option>duration</option> to zero will delete the NTA. suffixes can be used to specify the lifetime in
seconds, minutes, or hours. If the specified NTA
already exists, its lifetime will be updated to the
new value. Setting <option>lifetime</option> to zero
is equivalent to <option>-remove</option>.
</para>
<para>
If <option>-dump</option> is used, any other arguments
are ignored, and a list of existing NTAs is printed
(note that this may include NTAs that are expired but
have not yet been cleaned up).
</para>
<para>
Normally, <command>named</command> will periodically
test to see whether data below an NTA can now be
validated (see the <option>nta-recheck</option> option
in the Administrator Reference Manual for details).
If data can be validated, then the NTA is regarded as
no longer necessary, and will be allowed to expire
early. The <option>-force</option> overrides this
behavior and forces an NTA to persist for its entire
lifetime, regardless of whether data could be
validated if the NTA were not present.
</para>
<para>
All of these options can be shortened, i.e., to
<option>-l</option>, <option>-r</option>, <option>-d</option>,
and <option>-f</option>.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -51,7 +51,7 @@ linecount=`grep "\./RSAMD5/.* ; managed" ns2/named.secroots | wc -l`
linecount=`grep "dlv.isc.org/RSAMD5/.* ; managed" ns2/named.secroots | wc -l` linecount=`grep "dlv.isc.org/RSAMD5/.* ; managed" ns2/named.secroots | wc -l`
[ "$linecount" -eq 2 ] || ret=1 [ "$linecount" -eq 2 ] || ret=1
linecount=`cat ns2/named.secroots | wc -l` linecount=`cat ns2/named.secroots | wc -l`
[ "$linecount" -eq 13 ] || ret=1 [ "$linecount" -eq 28 ] || ret=1
n=`expr $n + 1` 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`

View File

@ -65,6 +65,10 @@ ns.insecure A 10.53.0.3
bogus NS ns.bogus bogus NS ns.bogus
ns.bogus A 10.53.0.3 ns.bogus A 10.53.0.3
; A subdomain with a corrupt DS
badds NS ns.badds
ns.badds A 10.53.0.3
; A dynamic secure subdomain ; A dynamic secure subdomain
dynamic NS dynamic dynamic NS dynamic
dynamic A 10.53.0.3 dynamic A 10.53.0.3

View File

@ -26,11 +26,10 @@ zonefile=example.db
( cd ../ns3 && $SHELL sign.sh ) ( cd ../ns3 && $SHELL sign.sh )
for subdomain in secure bogus dynamic keyless nsec3 optout nsec3-unknown \ for subdomain in secure badds bogus dynamic keyless nsec3 optout \
optout-unknown multiple rsasha256 rsasha512 kskonly update-nsec3 \ nsec3-unknown optout-unknown multiple rsasha256 rsasha512 \
auto-nsec auto-nsec3 secure.below-cname ttlpatch split-dnssec \ kskonly update-nsec3 auto-nsec auto-nsec3 secure.below-cname \
split-smart expired expiring upper lower ttlpatch split-dnssec split-smart expired expiring upper lower
do do
cp ../ns3/dsset-$subdomain.example. . cp ../ns3/dsset-$subdomain.example. .
done done

View File

@ -28,5 +28,6 @@ ns A 10.53.0.3
a A 10.0.0.1 a A 10.0.0.1
b A 10.0.0.2 b A 10.0.0.2
c A 10.0.0.3
d A 10.0.0.4 d A 10.0.0.4
z A 10.0.0.26 z A 10.0.0.26

View File

@ -68,6 +68,12 @@ zone "bogus.example" {
allow-update { any; }; allow-update { any; };
}; };
zone "badds.example" {
type master;
file "badds.example.db.signed";
allow-update { any; };
};
zone "dynamic.example" { zone "dynamic.example" {
type master; type master;
file "dynamic.example.db.signed"; file "dynamic.example.db.signed";

View File

@ -26,7 +26,11 @@ ns3 A 10.53.0.3
a A 10.0.0.1 a A 10.0.0.1
b A 10.0.0.2 b A 10.0.0.2
c A 10.0.0.3
d A 10.0.0.4 d A 10.0.0.4
e A 10.0.0.5
f A 10.0.0.6
g A 10.0.0.7
z A 10.0.0.26 z A 10.0.0.26
a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27 a.a.a.a.a.a.a.a.a.a.e A 10.0.0.27
x CNAME a x CNAME a

View File

@ -459,3 +459,18 @@ zonefile=siginterval.example.db
kskname=`$KEYGEN -q -3 -r $RANDFILE -fk $zone` kskname=`$KEYGEN -q -3 -r $RANDFILE -fk $zone`
zskname=`$KEYGEN -q -3 -r $RANDFILE $zone` zskname=`$KEYGEN -q -3 -r $RANDFILE $zone`
cp $infile $zonefile cp $infile $zonefile
#
# A zone with a bad DS in the parent
# (sourced from bogus.example.db.in)
#
zone=badds.example.
infile=bogus.example.db.in
zonefile=badds.example.db
keyname=`$KEYGEN -q -r $RANDFILE -a RSAMD5 -b 768 -n zone $zone`
cat $infile $keyname.key >$zonefile
$SIGNER -P -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
sed -e 's/bogus/badds/g' < dsset-bogus.example. > dsset-badds.example.

View File

@ -34,6 +34,9 @@ options {
dnssec-validation yes; dnssec-validation yes;
dnssec-must-be-secure mustbesecure.example yes; dnssec-must-be-secure mustbesecure.example yes;
nta-lifetime 10s;
nta-recheck 7s;
# Note: We only reference the bind.keys file here to confirm that it # Note: We only reference the bind.keys file here to confirm that it
# is *not* being used. It contains the real root key, and we're # is *not* being used. It contains the real root key, and we're
# using a local toy root zone for the tests, so it wouldn't work. # using a local toy root zone for the tests, so it wouldn't work.

View File

@ -26,6 +26,7 @@ cd ns1 && $SHELL sign.sh
echo "a.bogus.example. A 10.0.0.22" >>../ns3/bogus.example.db.signed echo "a.bogus.example. A 10.0.0.22" >>../ns3/bogus.example.db.signed
echo "b.bogus.example. A 10.0.0.23" >>../ns3/bogus.example.db.signed echo "b.bogus.example. A 10.0.0.23" >>../ns3/bogus.example.db.signed
echo "c.bogus.example. A 10.0.0.23" >>../ns3/bogus.example.db.signed
cd ../ns3 && cp -f siginterval1.conf siginterval.conf cd ../ns3 && cp -f siginterval1.conf siginterval.conf
cd ../ns4 && cp -f named1.conf named.conf cd ../ns4 && cp -f named1.conf named.conf

View File

@ -1568,7 +1568,7 @@ keyid=`cat ns1/managed.key.id`
linecount=`grep "./RSAMD5/$keyid ; trusted" ns4/named.secroots | wc -l` linecount=`grep "./RSAMD5/$keyid ; trusted" ns4/named.secroots | wc -l`
[ "$linecount" -eq 1 ] || ret=1 [ "$linecount" -eq 1 ] || ret=1
linecount=`cat ns4/named.secroots | wc -l` linecount=`cat ns4/named.secroots | wc -l`
[ "$linecount" -eq 5 ] || ret=1 [ "$linecount" -eq 10 ] || ret=1
n=`expr $n + 1` 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`
@ -1654,26 +1654,88 @@ status=`expr $status + $ret`
echo "I:checking positive and negative validation with negative trust anchors ($n)" echo "I:checking positive and negative validation with negative trust anchors ($n)"
ret=0 ret=0
#
# check correct initial behavior # check correct initial behavior
#
$DIG $DIGOPTS a.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.1 || ret=1 $DIG $DIGOPTS a.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.1 || ret=1
grep "status: SERVFAIL" dig.out.ns4.test$n.1 > /dev/null || ret=1 grep "status: SERVFAIL" dig.out.ns4.test$n.1 > /dev/null || ret=1
$DIG $DIGOPTS a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.2 || ret=1 $DIG $DIGOPTS badds.example. soa @10.53.0.4 > dig.out.ns4.test$n.2 || ret=1
grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.2 > /dev/null || ret=1 grep "status: SERVFAIL" dig.out.ns4.test$n.2 > /dev/null || ret=1
$DIG $DIGOPTS a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.3 || ret=1
grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.3 > /dev/null || ret=1
#
# add negative trust anchors # add negative trust anchors
$RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 nta bogus.example 15s 2>&1 | sed 's/^/I:ns4 /' #
$RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 nta secure.example 15s 2>&1 | sed 's/^/I:ns4 /' $RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 nta -f -l 15s bogus.example 2>&1 | sed 's/^/I:ns4 /'
$RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 nta badds.example 2>&1 | sed 's/^/I:ns4 /'
lines=`$RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 nta -d | wc -l`
[ "$lines" -eq 2 ] || ret=1
$RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 nta secure.example 2>&1 | sed 's/^/I:ns4 /'
$RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 nta fakenode.secure.example 2>&1 | sed 's/^/I:ns4 /'
lines=`$RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 nta -d | wc -l`
[ "$lines" -eq 4 ] || ret=1
#
# check behavior with NTA's in place # check behavior with NTA's in place
$DIG $DIGOPTS a.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.3 || ret=1 #
grep "status: SERVFAIL" dig.out.ns4.test$n.3 > /dev/null && ret=1 $DIG $DIGOPTS a.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.4 || ret=1
$DIG $DIGOPTS a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.4 || ret=1 grep "status: SERVFAIL" dig.out.ns4.test$n.4 > /dev/null && ret=1
grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.4 > /dev/null && ret=1 $DIG $DIGOPTS badds.example. soa @10.53.0.4 > dig.out.ns4.test$n.5 || ret=1
echo "I: waiting for NTA expiration" grep "status: SERVFAIL" dig.out.ns4.test$n.5 > /dev/null && ret=1
sleep 15 $DIG $DIGOPTS a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.6 || ret=1
# check correct behavior after expiry grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.6 > /dev/null && ret=1
$DIG $DIGOPTS b.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.5 || ret=1 $DIG $DIGOPTS a.fakenode.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.7 || ret=1
grep "status: SERVFAIL" dig.out.ns4.test$n.5 > /dev/null || ret=1 grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.7 > /dev/null && ret=1
$DIG $DIGOPTS b.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.6 || ret=1 echo "I: dumping secroots"
grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.6 > /dev/null || ret=1 $RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 secroots | sed 's/^/I:ns4 /'
grep "bogus.example: expiry" ns4/named.secroots > /dev/null || ret=1
grep "badds.example: expiry" ns4/named.secroots > /dev/null || ret=1
grep "secure.example: expiry" ns4/named.secroots > /dev/null || ret=1
grep "fakenode.secure.example: expiry" ns4/named.secroots > /dev/null || ret=1
echo "I: waiting for NTA rechecks/expirations"
#
# secure.example and badds.example used default nta-duration
# (configured as 10s in ns4/named1.conf), but nta recheck interval
# is configured to 7s, so at t=8 the NTAs for secure.example and
# fakenode.secure.example should both be lifted, but badds.example
# should still be going.
#
sleep 8
$DIG $DIGOPTS b.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.8 || ret=1
grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.8 > /dev/null || ret=1
$DIG $DIGOPTS b.fakenode.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.9 || ret=1
grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.9 > /dev/null || ret=1
grep "status: NXDOMAIN" dig.out.ns4.test$n.9 > /dev/null || ret=1
$DIG $DIGOPTS badds.example. soa @10.53.0.4 > dig.out.ns4.test$n.10 || ret=1
grep "status: SERVFAIL" dig.out.ns4.test$n.10 > /dev/null && ret=1
#
# bogus.example was set to expire in 15s, so at t=11
# it should still be NTA'd, but badds.example used the default
# lifetime of 10s, so it should revert to SERVFAIL now.
#
sleep 3
$DIG $DIGOPTS b.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.11 || ret=1
grep "status: SERVFAIL" dig.out.ns4.test$n.11 > /dev/null && ret=1
$DIG $DIGOPTS a.badds.example. a @10.53.0.4 > dig.out.ns4.test$n.12 || ret=1
grep "status: SERVFAIL" dig.out.ns4.test$n.12 > /dev/null || ret=1
$DIG $DIGOPTS c.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.13 || ret=1
grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.13 > /dev/null || ret=1
#
# at t=16, all the NTAs should have expired.
#
sleep 5
# check correct behavior after bogus.example expiry
$DIG $DIGOPTS d.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.14 || ret=1
grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.14 > /dev/null || ret=1
$DIG $DIGOPTS c.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.15 || ret=1
grep "status: SERVFAIL" dig.out.ns4.test$n.15 > /dev/null || ret=1
# check nta table has been cleaned up now
lines=`$RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 nta -d | wc -l`
[ "$lines" -eq 0 ] || ret=1
n=`expr $n + 1` 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`

View File

@ -4939,6 +4939,8 @@ badresp:1,adberr:0,findfail:0,valfail:0]
<optional> max-refresh-time <replaceable>number</replaceable> ; </optional> <optional> max-refresh-time <replaceable>number</replaceable> ; </optional>
<optional> min-retry-time <replaceable>number</replaceable> ; </optional> <optional> min-retry-time <replaceable>number</replaceable> ; </optional>
<optional> max-retry-time <replaceable>number</replaceable> ; </optional> <optional> max-retry-time <replaceable>number</replaceable> ; </optional>
<optional> nta-lifetime <replaceable>duration</replaceable> ; </optional>
<optional> nta-recheck <replaceable>duration</replaceable> ; </optional>
<optional> port <replaceable>ip_port</replaceable>; </optional> <optional> port <replaceable>ip_port</replaceable>; </optional>
<optional> dscp <replaceable>ip_dscp</replaceable></optional> ; <optional> dscp <replaceable>ip_dscp</replaceable></optional> ;
<optional> additional-from-auth <replaceable>yes_or_no</replaceable> ; </optional> <optional> additional-from-auth <replaceable>yes_or_no</replaceable> ; </optional>
@ -5746,6 +5748,69 @@ options {
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><command>nta-lifetime</command></term>
<listitem>
<para>
Species the default lifetime, in seconds,
that will be used for negative trust anchors added
via <command>rndc nta</command>.
</para>
<para>
A negative trust anchor selectively disables
DNSSEC validation for zones that known to be
failing because of misconfiguration rather than
an attack. When data to be validated is
at or below an active NTA (and above any other
configured trust anchors), <command>named</command> will
abort the DNSSEC validation process and treat the data as
insecure rather than bogus. This continues until the
NTA's lifetime is elapsed, or until the server is
restarted (NTA's do not persist across restarts).
</para>
<para>
For convienience, TTL-style time unit suffixes can be
used to specify the NTA lifetime in seconds, minutes
or hours. <option>nta-lifetime</option> defaults to
one hour. It cannot exceed one day.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>nta-recheck</command></term>
<listitem>
<para>
Species how often to check whether negative
trust anchors added via <command>rndc nta</command>
are still necessary.
</para>
<para>
A negative trust anchor is normally used when a
domain has stopped validating due to operator error;
it temporarily disables DNSSEC validation for that
domain. In the interest of ensuring that DNSSEC
validation is turned back on as soon as possible,
<command>named</command> will periodically send a
query to the domain, ignoring negative trust anchors,
to find out whether it can now be validated. If so,
the negative trust anchor is allowed to expire early.
</para>
<para>
Validity checks can be disabled for an indivdiual
NTA by using <command>rndc nta -f</command>, or
for all NTA's by setting <option>nta-recheck</option>
to zero.
</para>
<para>
For convienience, TTL-style time unit suffixes can be
used to specify the NTA recheck interval in seconds,
minutes or hours. The default is five minutes.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><command>max-zone-ttl</command></term> <term><command>max-zone-ttl</command></term>
<listitem> <listitem>

View File

@ -783,6 +783,7 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
const char *str; const char *str;
dns_name_t *name; dns_name_t *name;
isc_buffer_t b; isc_buffer_t b;
isc_uint32_t lifetime;
static intervaltable intervals[] = { static intervaltable intervals[] = {
{ "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */ { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
@ -1153,6 +1154,38 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
if (tresult != ISC_R_SUCCESS) if (tresult != ISC_R_SUCCESS)
result = tresult; result = tresult;
obj = NULL;
(void)cfg_map_get(options, "nta-lifetime", &obj);
if (obj != NULL) {
lifetime = cfg_obj_asuint32(obj);
if (lifetime > 86400) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"'nta-lifetime' cannot exceed one day");
result = ISC_R_RANGE;
} else if (lifetime == 0) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"'nta-lifetime' may not be zero");
result = ISC_R_RANGE;
}
}
obj = NULL;
(void)cfg_map_get(options, "nta-recheck", &obj);
if (obj != NULL) {
isc_uint32_t recheck = cfg_obj_asuint32(obj);
if (recheck > 86400) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
"'nta-recheck' cannot exceed one day");
result = ISC_R_RANGE;
}
if (recheck > lifetime)
cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
"'nta-recheck' (%d seconds) is "
"greater than 'nta-lifetime' "
"(%d seconds)", recheck, lifetime);
}
return (result); return (result);
} }

View File

@ -300,6 +300,8 @@ dns_cache_create3(isc_mem_t *cmctx, isc_mem_t *hmctx, isc_taskmgr_t *taskmgr,
result = isc_task_create(taskmgr, 1, &dbtask); result = isc_task_create(taskmgr, 1, &dbtask);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup_db; goto cleanup_db;
isc_task_setname(dbtask, "cache_dbtask", NULL);
dns_db_settask(cache->db, dbtask); dns_db_settask(cache->db, dbtask);
isc_task_detach(&dbtask); isc_task_detach(&dbtask);
} }

View File

@ -28,21 +28,31 @@
* DNSSEC validation. * DNSSEC validation.
*/ */
#include <isc/buffer.h>
#include <isc/lang.h> #include <isc/lang.h>
#include <isc/magic.h> #include <isc/magic.h>
#include <isc/refcount.h> #include <isc/refcount.h>
#include <isc/rwlock.h> #include <isc/rwlock.h>
#include <isc/stdtime.h> #include <isc/stdtime.h>
#include <isc/task.h>
#include <isc/timer.h>
#include <dns/types.h> #include <dns/types.h>
#include <dns/rdataset.h>
#include <dns/resolver.h>
#include <dns/view.h>
ISC_LANG_BEGINDECLS ISC_LANG_BEGINDECLS
struct dns_ntatable { struct dns_ntatable {
/* Unlocked. */ /* Unlocked. */
unsigned int magic; unsigned int magic;
isc_mem_t *mctx; dns_view_t *view;
isc_rwlock_t rwlock; isc_rwlock_t rwlock;
isc_uint32_t recheck;
isc_taskmgr_t *taskmgr;
isc_timermgr_t *timermgr;
isc_task_t *task;
/* Locked by rwlock. */ /* Locked by rwlock. */
isc_uint32_t references; isc_uint32_t references;
dns_rbt_t *table; dns_rbt_t *table;
@ -51,23 +61,18 @@ struct dns_ntatable {
#define NTATABLE_MAGIC ISC_MAGIC('N', 'T', 'A', 't') #define NTATABLE_MAGIC ISC_MAGIC('N', 'T', 'A', 't')
#define VALID_NTATABLE(nt) ISC_MAGIC_VALID(nt, NTATABLE_MAGIC) #define VALID_NTATABLE(nt) ISC_MAGIC_VALID(nt, NTATABLE_MAGIC)
struct dns_nta {
unsigned int magic;
isc_refcount_t refcount;
isc_stdtime_t expiry;
};
#define NTA_MAGIC ISC_MAGIC('N', 'T', 'A', 'n')
#define VALID_NTA(nn) ISC_MAGIC_VALID(nn, NTA_MAGIC)
isc_result_t isc_result_t
dns_ntatable_create(isc_mem_t *mctx, dns_ntatable_t **ntatablep); dns_ntatable_create(dns_view_t *view,
isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr,
dns_ntatable_t **ntatablep);
/*%< /*%<
* Create an NTA table. * Create an NTA table in view 'view'.
* *
* Requires: * Requires:
* *
*\li 'mctx' is a valid memory context. *\li 'view' is a valid view.
*
*\li 'tmgr' is a valid timer manager.
* *
*\li ntatablep != NULL && *ntatablep == NULL *\li ntatablep != NULL && *ntatablep == NULL
* *
@ -116,10 +121,13 @@ dns_ntatable_detach(dns_ntatable_t **ntatablep);
isc_result_t isc_result_t
dns_ntatable_add(dns_ntatable_t *ntatable, dns_name_t *name, dns_ntatable_add(dns_ntatable_t *ntatable, dns_name_t *name,
isc_uint32_t expiry); isc_boolean_t force, isc_stdtime_t now,
isc_uint32_t lifetime);
/*%< /*%<
* Add a negative trust anchor to 'ntatable' for name 'name', * Add a negative trust anchor to 'ntatable' for name 'name',
* which will expire at time 'expiry'. * which will expire at time 'now' + 'lifetime'. If 'force' is ISC_FALSE,
* then the name will be checked periodically to see if it's bogus;
* if not, then the NTA will be allowed to expire early.
* *
* Notes: * Notes:
* *
@ -191,15 +199,15 @@ dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
*/ */
isc_result_t isc_result_t
dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp); dns_ntatable_totext(dns_ntatable_t *ntatable, isc_buffer_t *buf);
/*%< /*%<
* Dump the NTA table on fp. * Dump the NTA table to buffer 'buf'
*/ */
isc_result_t isc_result_t
dns_nta_create(isc_mem_t *mctx, dns_nta_t **target); dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp);
/*%< /*%<
* Allocate space for an NTA * Dump the NTA table to the file opened as 'fp'.
*/ */
ISC_LANG_ENDDECLS ISC_LANG_ENDDECLS

View File

@ -98,6 +98,7 @@ typedef struct dns_fetchevent {
#define DNS_FETCHOPT_WANTNSID 0x080 /*%< Request NSID */ #define DNS_FETCHOPT_WANTNSID 0x080 /*%< Request NSID */
#define DNS_FETCHOPT_PREFETCH 0x100 /*%< Do prefetch */ #define DNS_FETCHOPT_PREFETCH 0x100 /*%< Do prefetch */
#define DNS_FETCHOPT_NOCDFLAG 0x200 /*%< Don't set CD flag. */ #define DNS_FETCHOPT_NOCDFLAG 0x200 /*%< Don't set CD flag. */
#define DNS_FETCHOPT_NONTA 0x400 /*%< Ignore NTA table. */
/* Reserved in use by adb.c 0x00400000 */ /* Reserved in use by adb.c 0x00400000 */
#define DNS_FETCHOPT_EDNSVERSIONSET 0x00800000 #define DNS_FETCHOPT_EDNSVERSIONSET 0x00800000

View File

@ -174,6 +174,7 @@ struct dns_validator {
#define DNS_VALIDATOR_DLV 0x0001U #define DNS_VALIDATOR_DLV 0x0001U
#define DNS_VALIDATOR_DEFER 0x0002U #define DNS_VALIDATOR_DEFER 0x0002U
#define DNS_VALIDATOR_NOCDFLAG 0x0004U #define DNS_VALIDATOR_NOCDFLAG 0x0004U
#define DNS_VALIDATOR_NONTA 0x0008U /*% Ignore NTA table */
ISC_LANG_BEGINDECLS ISC_LANG_BEGINDECLS

View File

@ -152,6 +152,8 @@ struct dns_view {
isc_boolean_t requestsit; isc_boolean_t requestsit;
dns_ttl_t maxcachettl; dns_ttl_t maxcachettl;
dns_ttl_t maxncachettl; dns_ttl_t maxncachettl;
isc_uint32_t nta_lifetime;
isc_uint32_t nta_recheck;
dns_ttl_t prefetch_trigger; dns_ttl_t prefetch_trigger;
dns_ttl_t prefetch_eligible; dns_ttl_t prefetch_eligible;
in_port_t dstport; in_port_t dstport;
@ -1076,7 +1078,8 @@ dns_view_iscacheshared(dns_view_t *view);
*/ */
isc_result_t isc_result_t
dns_view_initntatable(dns_view_t *view, isc_mem_t *mctx); dns_view_initntatable(dns_view_t *view,
isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr);
/*%< /*%<
* Initialize the negative trust anchor table for the view. * Initialize the negative trust anchor table for the view.
* *
@ -1144,11 +1147,15 @@ dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp);
isc_result_t isc_result_t
dns_view_issecuredomain(dns_view_t *view, dns_name_t *name, dns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
isc_stdtime_t now, isc_boolean_t *secure_domain); isc_stdtime_t now, isc_boolean_t checknta,
isc_boolean_t *secure_domain);
/*%< /*%<
* Is 'name' at or beneath a trusted key, and not covered by a valid * Is 'name' at or beneath a trusted key, and not covered by a valid
* negative trust anchor? Put answer in '*secure_domain'. * negative trust anchor? Put answer in '*secure_domain'.
* *
* If 'checknta' is ISC_FALSE, ignore the NTA table in determining
* whether this is a secure domain.
*
* Requires: * Requires:
* \li 'view' is valid. * \li 'view' is valid.
* *

View File

@ -18,20 +18,42 @@
#include <config.h> #include <config.h>
#include <isc/buffer.h>
#include <isc/log.h> #include <isc/log.h>
#include <isc/mem.h> #include <isc/mem.h>
#include <isc/rwlock.h> #include <isc/rwlock.h>
#include <isc/string.h> #include <isc/string.h>
#include <isc/task.h>
#include <isc/time.h> #include <isc/time.h>
#include <isc/timer.h>
#include <isc/util.h> #include <isc/util.h>
#include <dns/db.h>
#include <dns/log.h> #include <dns/log.h>
#include <dns/nta.h> #include <dns/nta.h>
#include <dns/fixedname.h> #include <dns/fixedname.h>
#include <dns/name.h> #include <dns/name.h>
#include <dns/rbt.h> #include <dns/rbt.h>
#include <dns/rdataset.h>
#include <dns/resolver.h>
#include <dns/result.h> #include <dns/result.h>
struct dns_nta {
unsigned int magic;
isc_refcount_t refcount;
dns_ntatable_t *ntatable;
isc_timer_t *timer;
dns_fetch_t *fetch;
dns_rdataset_t rdataset;
dns_rdataset_t sigrdataset;
dns_fixedname_t fn;
dns_name_t *name;
isc_stdtime_t expiry;
};
#define NTA_MAGIC ISC_MAGIC('N', 'T', 'A', 'n')
#define VALID_NTA(nn) ISC_MAGIC_VALID(nn, NTA_MAGIC)
static void static void
nta_detach(isc_mem_t *mctx, dns_nta_t **ntap) { nta_detach(isc_mem_t *mctx, dns_nta_t **ntap) {
unsigned int refs; unsigned int refs;
@ -42,7 +64,22 @@ nta_detach(isc_mem_t *mctx, dns_nta_t **ntap) {
*ntap = NULL; *ntap = NULL;
isc_refcount_decrement(&nta->refcount, &refs); isc_refcount_decrement(&nta->refcount, &refs);
if (refs == 0) { if (refs == 0) {
nta->magic = 0;
if (nta->timer != NULL) {
(void) isc_timer_reset(nta->timer,
isc_timertype_inactive,
NULL, NULL, ISC_TRUE);
isc_timer_detach(&nta->timer);
}
isc_refcount_destroy(&nta->refcount); isc_refcount_destroy(&nta->refcount);
if (dns_rdataset_isassociated(&nta->rdataset))
dns_rdataset_disassociate(&nta->rdataset);
if (dns_rdataset_isassociated(&nta->sigrdataset))
dns_rdataset_disassociate(&nta->sigrdataset);
if (nta->fetch != NULL) {
dns_resolver_cancelfetch(nta->fetch);
dns_resolver_destroyfetch(&nta->fetch);
}
isc_mem_put(mctx, nta, sizeof(dns_nta_t)); isc_mem_put(mctx, nta, sizeof(dns_nta_t));
} }
} }
@ -56,32 +93,41 @@ free_nta(void *data, void *arg) {
} }
isc_result_t isc_result_t
dns_ntatable_create(isc_mem_t *mctx, dns_ntatable_t **ntatablep) { dns_ntatable_create(dns_view_t *view,
isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr,
dns_ntatable_t **ntatablep)
{
dns_ntatable_t *ntatable; dns_ntatable_t *ntatable;
isc_result_t result; isc_result_t result;
/*
* Create an NTA table.
*/
REQUIRE(ntatablep != NULL && *ntatablep == NULL); REQUIRE(ntatablep != NULL && *ntatablep == NULL);
ntatable = isc_mem_get(mctx, sizeof(*ntatable)); ntatable = isc_mem_get(view->mctx, sizeof(*ntatable));
if (ntatable == NULL) if (ntatable == NULL)
return (ISC_R_NOMEMORY); return (ISC_R_NOMEMORY);
ntatable->table = NULL; ntatable->task = NULL;
result = dns_rbt_create(mctx, free_nta, mctx, &ntatable->table); result = isc_task_create(taskmgr, 0, &ntatable->task);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup_ntatable; goto cleanup_ntatable;
isc_task_setname(ntatable->task, "ntatable", ntatable);
ntatable->table = NULL;
result = dns_rbt_create(view->mctx, free_nta, view->mctx,
&ntatable->table);
if (result != ISC_R_SUCCESS)
goto cleanup_task;
result = isc_rwlock_init(&ntatable->rwlock, 0, 0); result = isc_rwlock_init(&ntatable->rwlock, 0, 0);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup_rbt; goto cleanup_rbt;
ntatable->mctx = NULL; ntatable->timermgr = timermgr;
isc_mem_attach(mctx, &ntatable->mctx); ntatable->taskmgr = taskmgr;
ntatable->view = view;
ntatable->references = 1; ntatable->references = 1;
ntatable->magic = NTATABLE_MAGIC; ntatable->magic = NTATABLE_MAGIC;
*ntatablep = ntatable; *ntatablep = ntatable;
@ -90,8 +136,11 @@ dns_ntatable_create(isc_mem_t *mctx, dns_ntatable_t **ntatablep) {
cleanup_rbt: cleanup_rbt:
dns_rbt_destroy(&ntatable->table); dns_rbt_destroy(&ntatable->table);
cleanup_task:
isc_task_detach(&ntatable->task);
cleanup_ntatable: cleanup_ntatable:
isc_mem_put(mctx, ntatable, sizeof(*ntatable)); isc_mem_put(ntatable->view->mctx, ntatable, sizeof(*ntatable));
return (result); return (result);
} }
@ -132,43 +181,187 @@ dns_ntatable_detach(dns_ntatable_t **ntatablep) {
if (destroy) { if (destroy) {
dns_rbt_destroy(&ntatable->table); dns_rbt_destroy(&ntatable->table);
isc_rwlock_destroy(&ntatable->rwlock); isc_rwlock_destroy(&ntatable->rwlock);
if (ntatable->task != NULL)
isc_task_detach(&ntatable->task);
ntatable->timermgr = NULL;
ntatable->taskmgr = NULL;
ntatable->magic = 0; ntatable->magic = 0;
isc_mem_putanddetach(&ntatable->mctx, isc_mem_put(ntatable->view->mctx, ntatable, sizeof(*ntatable));
ntatable, sizeof(*ntatable));
} }
} }
static void
fetch_done(isc_task_t *task, isc_event_t *event) {
dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
dns_nta_t *nta = devent->ev_arg;
isc_result_t eresult = devent->result;
dns_ntatable_t *ntatable = nta->ntatable;
isc_stdtime_t now;
UNUSED(task);
if (dns_rdataset_isassociated(&nta->rdataset))
dns_rdataset_disassociate(&nta->rdataset);
if (dns_rdataset_isassociated(&nta->sigrdataset))
dns_rdataset_disassociate(&nta->sigrdataset);
dns_resolver_destroyfetch(&nta->fetch);
if (devent->node != NULL)
dns_db_detachnode(devent->db, &devent->node);
if (devent->db != NULL)
dns_db_detach(&devent->db);
isc_event_free(&event);
switch (eresult) {
case ISC_R_SUCCESS:
case DNS_R_NCACHENXDOMAIN:
case DNS_R_NXDOMAIN:
case DNS_R_NCACHENXRRSET:
case DNS_R_NXRRSET:
isc_stdtime_get(&now);
nta->expiry = now;
break;
default:
break;
}
/*
* If we're expiring before the next recheck, we might
* as well stop the timer now.
*/
if (nta->timer != NULL && nta->expiry - now < ntatable->recheck)
(void) isc_timer_reset(nta->timer, isc_timertype_inactive,
NULL, NULL, ISC_TRUE);
}
static void
checkbogus(isc_task_t *task, isc_event_t *event) {
dns_nta_t *nta = event->ev_arg;
dns_ntatable_t *ntatable = nta->ntatable;
dns_view_t *view = ntatable->view;
if (nta->fetch != NULL) {
dns_resolver_cancelfetch(nta->fetch);
dns_resolver_destroyfetch(&nta->fetch);
}
if (dns_rdataset_isassociated(&nta->rdataset))
dns_rdataset_disassociate(&nta->rdataset);
if (dns_rdataset_isassociated(&nta->sigrdataset))
dns_rdataset_disassociate(&nta->sigrdataset);
isc_event_free(&event);
(void)dns_resolver_createfetch(view->resolver, nta->name,
dns_rdatatype_nsec,
NULL, NULL, NULL,
DNS_FETCHOPT_NONTA,
task, fetch_done, nta,
&nta->rdataset,
&nta->sigrdataset,
&nta->fetch);
}
static isc_result_t
settimer(dns_ntatable_t *ntatable, dns_nta_t *nta, isc_uint32_t lifetime) {
isc_result_t result;
isc_interval_t interval;
dns_view_t *view;
REQUIRE(VALID_NTATABLE(ntatable));
REQUIRE(VALID_NTA(nta));
if (ntatable->timermgr == NULL)
return (ISC_R_SUCCESS);
view = ntatable->view;
if (view->nta_recheck == 0 || lifetime <= view->nta_recheck)
return (ISC_R_SUCCESS);
isc_interval_set(&interval, view->nta_recheck, 0);
result = isc_timer_create(ntatable->timermgr, isc_timertype_ticker,
NULL, &interval, ntatable->task,
checkbogus, nta, &nta->timer);
return (result);
}
static isc_result_t
nta_create(dns_ntatable_t *ntatable, dns_name_t *name, dns_nta_t **target) {
isc_result_t result;
dns_nta_t *nta = NULL;
dns_view_t *view;
REQUIRE(VALID_NTATABLE(ntatable));
REQUIRE(target != NULL && *target == NULL);
view = ntatable->view;
nta = isc_mem_get(view->mctx, sizeof(dns_nta_t));
if (nta == NULL)
return (ISC_R_NOMEMORY);
nta->ntatable = ntatable;
nta->expiry = 0;
nta->timer = NULL;
nta->fetch = NULL;
dns_rdataset_init(&nta->rdataset);
dns_rdataset_init(&nta->sigrdataset);
result = isc_refcount_init(&nta->refcount, 1);
if (result != ISC_R_SUCCESS) {
isc_mem_put(view->mctx, nta, sizeof(dns_nta_t));
return (result);
}
dns_fixedname_init(&nta->fn);
nta->name = dns_fixedname_name(&nta->fn);
dns_name_copy(name, nta->name, NULL);
nta->magic = NTA_MAGIC;
*target = nta;
return (ISC_R_SUCCESS);
}
isc_result_t isc_result_t
dns_ntatable_add(dns_ntatable_t *ntatable, dns_name_t *name, dns_ntatable_add(dns_ntatable_t *ntatable, dns_name_t *name,
isc_uint32_t expiry) isc_boolean_t force, isc_stdtime_t now,
isc_uint32_t lifetime)
{ {
isc_result_t result; isc_result_t result;
dns_nta_t *nta = NULL; dns_nta_t *nta = NULL;
dns_rbtnode_t *node; dns_rbtnode_t *node;
dns_view_t *view;
REQUIRE(VALID_NTATABLE(ntatable)); REQUIRE(VALID_NTATABLE(ntatable));
result = dns_nta_create(ntatable->mctx, &nta); view = ntatable->view;
result = nta_create(ntatable, name, &nta);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
return (result); return (result);
nta->expiry = expiry; nta->expiry = now + lifetime;
RWLOCK(&ntatable->rwlock, isc_rwlocktype_write); RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
node = NULL; node = NULL;
result = dns_rbt_addnode(ntatable->table, name, &node); result = dns_rbt_addnode(ntatable->table, name, &node);
if (result == ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) {
if (!force)
(void)settimer(ntatable, nta, lifetime);
node->data = nta; node->data = nta;
nta = NULL; nta = NULL;
} else if (result == ISC_R_EXISTS) { } else if (result == ISC_R_EXISTS) {
dns_nta_t *n = node->data; dns_nta_t *n = node->data;
if (n == NULL) { if (n == NULL) {
if (!force)
(void)settimer(ntatable, nta, lifetime);
node->data = nta; node->data = nta;
nta = NULL; nta = NULL;
} else { } else {
n->expiry = nta->expiry; n->expiry = nta->expiry;
nta_detach(ntatable->mctx, &nta); nta_detach(view->mctx, &nta);
} }
result = ISC_R_SUCCESS; result = ISC_R_SUCCESS;
} }
@ -176,7 +369,7 @@ dns_ntatable_add(dns_ntatable_t *ntatable, dns_name_t *name,
RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write); RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_write);
if (nta != NULL) if (nta != NULL)
nta_detach(ntatable->mctx, &nta); nta_detach(view->mctx, &nta);
return (result); return (result);
} }
@ -268,6 +461,13 @@ dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
DNS_LOGMODULE_NTA, ISC_LOG_INFO, DNS_LOGMODULE_NTA, ISC_LOG_INFO,
"deleting expired NTA at %s", nb); "deleting expired NTA at %s", nb);
if (nta->timer != NULL) {
(void) isc_timer_reset(nta->timer,
isc_timertype_inactive,
NULL, NULL, ISC_TRUE);
isc_timer_detach(&nta->timer);
}
result = delete(ntatable, foundname); result = delete(ntatable, foundname);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
@ -283,15 +483,19 @@ dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
} }
isc_result_t isc_result_t
dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) { dns_ntatable_totext(dns_ntatable_t *ntatable, isc_buffer_t *buf) {
isc_result_t result; isc_result_t result;
dns_rbtnode_t *node; dns_rbtnode_t *node;
dns_rbtnodechain_t chain; dns_rbtnodechain_t chain;
isc_boolean_t first = ISC_TRUE;
isc_stdtime_t now;
REQUIRE(VALID_NTATABLE(ntatable)); REQUIRE(VALID_NTATABLE(ntatable));
isc_stdtime_get(&now);
RWLOCK(&ntatable->rwlock, isc_rwlocktype_read); RWLOCK(&ntatable->rwlock, isc_rwlocktype_read);
dns_rbtnodechain_init(&chain, ntatable->mctx); dns_rbtnodechain_init(&chain, ntatable->view->mctx);
result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL); result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL);
if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
goto cleanup; goto cleanup;
@ -300,15 +504,80 @@ dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) {
if (node->data != NULL) { if (node->data != NULL) {
dns_nta_t *n = (dns_nta_t *) node->data; dns_nta_t *n = (dns_nta_t *) node->data;
char nbuf[DNS_NAME_FORMATSIZE], tbuf[80]; char nbuf[DNS_NAME_FORMATSIZE], tbuf[80];
dns_name_t name; char obuf[DNS_NAME_FORMATSIZE + 200];
dns_fixedname_t fn;
dns_name_t *name;
isc_time_t t; isc_time_t t;
dns_name_init(&name, NULL); dns_fixedname_init(&fn);
dns_rbt_namefromnode(node, &name); name = dns_fixedname_name(&fn);
dns_name_format(&name, nbuf, sizeof(nbuf)); dns_rbt_fullnamefromnode(node, name);
dns_name_format(name, nbuf, sizeof(nbuf));
isc_time_set(&t, n->expiry, 0); isc_time_set(&t, n->expiry, 0);
isc_time_formattimestamp(&t, tbuf, sizeof(tbuf)); isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
fprintf(fp, "%s : expiry %s\n", nbuf, tbuf);
snprintf(obuf, sizeof(obuf), "%s%s: %s %s",
first ? "" : "\n", nbuf,
n->expiry < now ? "expired" : "expiry",
tbuf);
first = ISC_FALSE;
if (strlen(obuf) >= isc_buffer_availablelength(buf)) {
result = ISC_R_NOSPACE;
goto cleanup;
} else
isc_buffer_putstr(buf, obuf);
}
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;
}
}
if (isc_buffer_availablelength(buf) != 0)
isc_buffer_putuint8(buf, 0);
cleanup:
dns_rbtnodechain_invalidate(&chain);
RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read);
return (result);
}
isc_result_t
dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) {
isc_result_t result;
dns_rbtnode_t *node;
dns_rbtnodechain_t chain;
isc_stdtime_t now;
REQUIRE(VALID_NTATABLE(ntatable));
isc_stdtime_get(&now);
RWLOCK(&ntatable->rwlock, isc_rwlocktype_read);
dns_rbtnodechain_init(&chain, ntatable->view->mctx);
result = dns_rbtnodechain_first(&chain, ntatable->table, NULL, NULL);
if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
goto cleanup;
for (;;) {
dns_rbtnodechain_current(&chain, NULL, NULL, &node);
if (node->data != NULL) {
dns_nta_t *n = (dns_nta_t *) node->data;
char nbuf[DNS_NAME_FORMATSIZE], tbuf[80];
dns_fixedname_t fn;
dns_name_t *name;
isc_time_t t;
dns_fixedname_init(&fn);
name = dns_fixedname_name(&fn);
dns_rbt_fullnamefromnode(node, name);
dns_name_format(name, nbuf, sizeof(nbuf));
isc_time_set(&t, n->expiry, 0);
isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
fprintf(fp, "%s: %s %s\n", nbuf,
n->expiry < now ? "expired" : "expiry",
tbuf);
} }
result = dns_rbtnodechain_next(&chain, NULL, NULL); result = dns_rbtnodechain_next(&chain, NULL, NULL);
if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) { if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
@ -323,28 +592,3 @@ dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) {
RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read); RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read);
return (result); return (result);
} }
isc_result_t
dns_nta_create(isc_mem_t *mctx, dns_nta_t **target) {
isc_result_t result;
dns_nta_t *nta = NULL;
REQUIRE(target != NULL && *target == NULL);
nta = isc_mem_get(mctx, sizeof(dns_nta_t));
if (nta == NULL)
return (ISC_R_NOMEMORY);
nta->expiry = 0;
result = isc_refcount_init(&nta->refcount, 1);
if (result != ISC_R_SUCCESS) {
isc_mem_put(mctx, nta, sizeof(dns_nta_t));
return (result);
}
nta->magic = NTA_MAGIC;
*target = nta;
return (ISC_R_SUCCESS);
}

View File

@ -1823,7 +1823,8 @@ compute_cc(resquery_t *query, unsigned char *sit, size_t len) {
static isc_result_t static isc_result_t
issecuredomain(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, issecuredomain(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
isc_stdtime_t now, isc_boolean_t *issecure) isc_stdtime_t now, isc_boolean_t checknta,
isc_boolean_t *issecure)
{ {
dns_name_t suffix; dns_name_t suffix;
unsigned int labels; unsigned int labels;
@ -1841,7 +1842,7 @@ issecuredomain(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
name = &suffix; name = &suffix;
} }
return (dns_view_issecuredomain(view, name, now, issecure)); return (dns_view_issecuredomain(view, name, now, checknta, issecure));
} }
static isc_result_t static isc_result_t
@ -1944,10 +1945,13 @@ resquery_send(resquery_t *query) {
else if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0) else if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0)
fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD; fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
else if (res->view->enablevalidation && else if (res->view->enablevalidation &&
((fctx->qmessage->flags & DNS_MESSAGEFLAG_RD) != 0)) { ((fctx->qmessage->flags & DNS_MESSAGEFLAG_RD) != 0))
{
isc_boolean_t checknta =
ISC_TF((query->options & DNS_FETCHOPT_NONTA) == 0);
result = issecuredomain(res->view, &fctx->name, result = issecuredomain(res->view, &fctx->name,
fctx->type, query->start.seconds, fctx->type, query->start.seconds,
&secure_domain); checknta, &secure_domain);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
secure_domain = ISC_FALSE; secure_domain = ISC_FALSE;
if (res->view->dlv != NULL) if (res->view->dlv != NULL)
@ -4833,6 +4837,7 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
isc_task_t *task; isc_task_t *task;
isc_boolean_t fail; isc_boolean_t fail;
unsigned int valoptions = 0; unsigned int valoptions = 0;
isc_boolean_t checknta = ISC_TRUE;
/* /*
* The appropriate bucket lock must be held. * The appropriate bucket lock must be held.
@ -4849,14 +4854,19 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo,
/* /*
* Is DNSSEC validation required for this name? * Is DNSSEC validation required for this name?
*/ */
if ((fctx->options & DNS_FETCHOPT_NONTA) != 0) {
valoptions |= DNS_VALIDATOR_NONTA;
checknta = ISC_FALSE;
}
if (res->view->enablevalidation) { if (res->view->enablevalidation) {
result = issecuredomain(res->view, name, fctx->type, result = issecuredomain(res->view, name, fctx->type,
now, &secure_domain); now, checknta, &secure_domain);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
return (result); return (result);
if (!secure_domain && res->view->dlv != NULL) { if (!secure_domain && res->view->dlv != NULL) {
valoptions = DNS_VALIDATOR_DLV; valoptions |= DNS_VALIDATOR_DLV;
secure_domain = ISC_TRUE; secure_domain = ISC_TRUE;
} }
} }
@ -5362,6 +5372,7 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
dns_fetchevent_t *event; dns_fetchevent_t *event;
isc_uint32_t ttl; isc_uint32_t ttl;
unsigned int valoptions = 0; unsigned int valoptions = 0;
isc_boolean_t checknta = ISC_TRUE;
FCTXTRACE("ncache_message"); FCTXTRACE("ncache_message");
@ -5384,14 +5395,19 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
/* /*
* Is DNSSEC validation required for this name? * Is DNSSEC validation required for this name?
*/ */
if ((fctx->options & DNS_FETCHOPT_NONTA) != 0) {
valoptions |= DNS_VALIDATOR_NONTA;
checknta = ISC_FALSE;
}
if (fctx->res->view->enablevalidation) { if (fctx->res->view->enablevalidation) {
result = issecuredomain(res->view, name, fctx->type, result = issecuredomain(res->view, name, fctx->type,
now, &secure_domain); now, checknta, &secure_domain);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
return (result); return (result);
if (!secure_domain && res->view->dlv != NULL) { if (!secure_domain && res->view->dlv != NULL) {
valoptions = DNS_VALIDATOR_DLV; valoptions |= DNS_VALIDATOR_DLV;
secure_domain = ISC_TRUE; secure_domain = ISC_TRUE;
} }
} }
@ -8275,6 +8291,7 @@ dns_resolver_create(dns_view_t *view,
result = isc_task_create(taskmgr, 0, &task); result = isc_task_create(taskmgr, 0, &task);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup_primelock; goto cleanup_primelock;
isc_task_setname(task, "resolver_task", NULL);
result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL, result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
task, spillattimer_countdown, res, task, spillattimer_countdown, res,

View File

@ -50,6 +50,8 @@ static const dns_keytag_t keytag1 = 30591;
static const char *keystr2 = "BQEAAAABwuHz9Cem0BJ0JQTO7C/a3McR6hMaufljs1dfG/inaJpYv7vH XTrAOm/MeKp+/x6eT4QLru0KoZkvZJnqTI8JyaFTw2OM/ItBfh/hL2lm Cft2O7n3MfeqYtvjPnY7dWghYW4sVfH7VVEGm958o9nfi79532Qeklxh x8pXWdeAaRU="; static const char *keystr2 = "BQEAAAABwuHz9Cem0BJ0JQTO7C/a3McR6hMaufljs1dfG/inaJpYv7vH XTrAOm/MeKp+/x6eT4QLru0KoZkvZJnqTI8JyaFTw2OM/ItBfh/hL2lm Cft2O7n3MfeqYtvjPnY7dWghYW4sVfH7VVEGm958o9nfi79532Qeklxh x8pXWdeAaRU=";
static dns_view_t *view = NULL;
/* /*
* Test utilities. In general, these assume input parameters are valid * Test utilities. In general, these assume input parameters are valid
* (checking with ATF_REQUIRE_EQ, thus aborting if not) and unlikely run time * (checking with ATF_REQUIRE_EQ, thus aborting if not) and unlikely run time
@ -119,11 +121,16 @@ create_key(isc_uint16_t flags, isc_uint8_t proto, isc_uint8_t alg,
/* Common setup: create a keytable and ntatable to test with a few keys */ /* Common setup: create a keytable and ntatable to test with a few keys */
static void static void
create_tables() { create_tables() {
isc_result_t result;
dst_key_t *key = NULL; dst_key_t *key = NULL;
isc_stdtime_t now; isc_stdtime_t now;
result = dns_test_makeview("view", &view);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
ATF_REQUIRE_EQ(dns_keytable_create(mctx, &keytable), ISC_R_SUCCESS); ATF_REQUIRE_EQ(dns_keytable_create(mctx, &keytable), ISC_R_SUCCESS);
ATF_REQUIRE_EQ(dns_ntatable_create(mctx, &ntatable), ISC_R_SUCCESS); ATF_REQUIRE_EQ(dns_ntatable_create(view, taskmgr, timermgr,
&ntatable), ISC_R_SUCCESS);
/* Add a normal key */ /* Add a normal key */
create_key(257, 3, 5, "example.com", keystr1, &key); create_key(257, 3, 5, "example.com", keystr1, &key);
@ -139,7 +146,7 @@ create_tables() {
isc_stdtime_get(&now); isc_stdtime_get(&now);
ATF_REQUIRE_EQ(dns_ntatable_add(ntatable, ATF_REQUIRE_EQ(dns_ntatable_add(ntatable,
str2name("insecure.example"), str2name("insecure.example"),
now + 3600), ISC_FALSE, now, 3600),
ISC_R_SUCCESS); ISC_R_SUCCESS);
} }
@ -149,6 +156,8 @@ destroy_tables() {
dns_ntatable_detach(&ntatable); dns_ntatable_detach(&ntatable);
if (keytable != NULL) if (keytable != NULL)
dns_keytable_detach(&keytable); dns_keytable_detach(&keytable);
dns_view_detach(&view);
} }
/* /*
@ -167,7 +176,7 @@ ATF_TC_BODY(add, tc) {
UNUSED(tc); UNUSED(tc);
ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS); ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_TRUE), ISC_R_SUCCESS);
create_tables(); create_tables();
/* /*
@ -246,7 +255,7 @@ ATF_TC_HEAD(delete, tc) {
ATF_TC_BODY(delete, tc) { ATF_TC_BODY(delete, tc) {
UNUSED(tc); UNUSED(tc);
ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS); ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_TRUE), ISC_R_SUCCESS);
create_tables(); create_tables();
/* dns_keytable_delete requires exact match */ /* dns_keytable_delete requires exact match */
@ -279,7 +288,7 @@ ATF_TC_BODY(deletekeynode, tc) {
UNUSED(tc); UNUSED(tc);
ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS); ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_TRUE), ISC_R_SUCCESS);
create_tables(); create_tables();
/* key name doesn't match */ /* key name doesn't match */
@ -340,7 +349,7 @@ ATF_TC_BODY(find, tc) {
UNUSED(tc); UNUSED(tc);
ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS); ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_TRUE), ISC_R_SUCCESS);
create_tables(); create_tables();
/* /*
@ -432,7 +441,7 @@ ATF_TC_BODY(issecuredomain, tc) {
"null.example", "sub.null.example", NULL}; "null.example", "sub.null.example", NULL};
UNUSED(tc); UNUSED(tc);
ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS); ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_TRUE), ISC_R_SUCCESS);
create_tables(); create_tables();
/* /*
@ -476,7 +485,7 @@ ATF_TC_HEAD(dump, tc) {
ATF_TC_BODY(dump, tc) { ATF_TC_BODY(dump, tc) {
UNUSED(tc); UNUSED(tc);
ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_FALSE), ISC_R_SUCCESS); ATF_REQUIRE_EQ(dns_test_begin(NULL, ISC_TRUE), ISC_R_SUCCESS);
create_tables(); create_tables();
/* /*
@ -508,12 +517,15 @@ ATF_TC_BODY(nta, tc) {
result = dns_test_makeview("view", &view); result = dns_test_makeview("view", &view);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = isc_task_create(taskmgr, 0, &view->task);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = dns_view_initsecroots(view, mctx); result = dns_view_initsecroots(view, mctx);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = dns_view_getsecroots(view, &keytable); result = dns_view_getsecroots(view, &keytable);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = dns_view_initntatable(view, mctx); result = dns_view_initntatable(view, taskmgr, timermgr);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = dns_view_getntatable(view, &ntatable); result = dns_view_getntatable(view, &ntatable);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
@ -524,20 +536,21 @@ ATF_TC_BODY(nta, tc) {
isc_stdtime_get(&now); isc_stdtime_get(&now);
result = dns_ntatable_add(ntatable, result = dns_ntatable_add(ntatable,
str2name("insecure.example"), now + 1); str2name("insecure.example"),
ISC_FALSE, now, 1);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
/* Should be secure */ /* Should be secure */
result = dns_view_issecuredomain(view, result = dns_view_issecuredomain(view,
str2name("test.secure.example"), str2name("test.secure.example"),
now, &issecure); now, ISC_TRUE, &issecure);
ATF_CHECK_EQ(result, ISC_R_SUCCESS); ATF_CHECK_EQ(result, ISC_R_SUCCESS);
ATF_CHECK(issecure); ATF_CHECK(issecure);
/* Should not be secure */ /* Should not be secure */
result = dns_view_issecuredomain(view, result = dns_view_issecuredomain(view,
str2name("test.insecure.example"), str2name("test.insecure.example"),
now, &issecure); now, ISC_TRUE, &issecure);
ATF_CHECK_EQ(result, ISC_R_SUCCESS); ATF_CHECK_EQ(result, ISC_R_SUCCESS);
ATF_CHECK(!issecure); ATF_CHECK(!issecure);
@ -554,17 +567,17 @@ ATF_TC_BODY(nta, tc) {
/* As of now + 2, the NTA should be clear */ /* As of now + 2, the NTA should be clear */
result = dns_view_issecuredomain(view, result = dns_view_issecuredomain(view,
str2name("test.insecure.example"), str2name("test.insecure.example"),
now + 2, &issecure); now + 2, ISC_TRUE, &issecure);
ATF_CHECK_EQ(result, ISC_R_SUCCESS); ATF_CHECK_EQ(result, ISC_R_SUCCESS);
ATF_CHECK(issecure); ATF_CHECK(issecure);
/* Now check deletion */ /* Now check deletion */
result = dns_ntatable_add(ntatable, result = dns_ntatable_add(ntatable, str2name("new.example"),
str2name("new.example"), now + 3600); ISC_FALSE, now, 3600);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = dns_view_issecuredomain(view, str2name("test.new.example"), result = dns_view_issecuredomain(view, str2name("test.new.example"),
now, &issecure); now, ISC_TRUE, &issecure);
ATF_CHECK_EQ(result, ISC_R_SUCCESS); ATF_CHECK_EQ(result, ISC_R_SUCCESS);
ATF_CHECK(!issecure); ATF_CHECK(!issecure);
@ -572,7 +585,7 @@ ATF_TC_BODY(nta, tc) {
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
result = dns_view_issecuredomain(view, str2name("test.new.example"), result = dns_view_issecuredomain(view, str2name("test.new.example"),
now, &issecure); now, ISC_TRUE, &issecure);
ATF_CHECK_EQ(result, ISC_R_SUCCESS); ATF_CHECK_EQ(result, ISC_R_SUCCESS);
ATF_CHECK(issecure); ATF_CHECK(issecure);

View File

@ -1139,6 +1139,9 @@ create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
if ((val->options & DNS_VALIDATOR_NOCDFLAG) != 0) if ((val->options & DNS_VALIDATOR_NOCDFLAG) != 0)
fopts |= DNS_FETCHOPT_NOCDFLAG; fopts |= DNS_FETCHOPT_NOCDFLAG;
if ((val->options & DNS_VALIDATOR_NONTA) != 0)
fopts |= DNS_FETCHOPT_NONTA;
validator_logcreate(val, name, type, caller, "fetch"); validator_logcreate(val, name, type, caller, "fetch");
return (dns_resolver_createfetch(val->view->resolver, name, type, return (dns_resolver_createfetch(val->view->resolver, name, type,
NULL, NULL, NULL, fopts, NULL, NULL, NULL, fopts,
@ -3164,7 +3167,8 @@ finddlvsep(dns_validator_t *val, isc_boolean_t resume) {
return (DNS_R_NOVALIDSIG); return (DNS_R_NOVALIDSIG);
} }
if (dns_view_ntacovers(val->view, val->start, dlvname, val->view->dlv)) if (((val->options & DNS_VALIDATOR_NONTA) == 0) &&
dns_view_ntacovers(val->view, val->start, dlvname, val->view->dlv))
return (DNS_R_NTACOVERED); return (DNS_R_NTACOVERED);
while (dns_name_countlabels(dlvname) >= while (dns_name_countlabels(dlvname) >=

View File

@ -192,6 +192,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->provideixfr = ISC_TRUE; view->provideixfr = ISC_TRUE;
view->maxcachettl = 7 * 24 * 3600; view->maxcachettl = 7 * 24 * 3600;
view->maxncachettl = 3 * 3600; view->maxncachettl = 3 * 3600;
view->nta_lifetime = 0;
view->nta_recheck = 0;
view->prefetch_eligible = 0; view->prefetch_eligible = 0;
view->prefetch_trigger = 0; view->prefetch_trigger = 0;
view->dstport = 53; view->dstport = 53;
@ -1776,11 +1778,14 @@ dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) {
} }
isc_result_t isc_result_t
dns_view_initntatable(dns_view_t *view, isc_mem_t *mctx) { dns_view_initntatable(dns_view_t *view,
isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr)
{
REQUIRE(DNS_VIEW_VALID(view)); REQUIRE(DNS_VIEW_VALID(view));
if (view->ntatable_priv != NULL) if (view->ntatable_priv != NULL)
dns_ntatable_detach(&view->ntatable_priv); dns_ntatable_detach(&view->ntatable_priv);
return (dns_ntatable_create(mctx, &view->ntatable_priv)); return (dns_ntatable_create(view, taskmgr, timermgr,
&view->ntatable_priv));
} }
isc_result_t isc_result_t
@ -1825,7 +1830,8 @@ dns_view_ntacovers(dns_view_t *view, isc_stdtime_t now,
isc_result_t isc_result_t
dns_view_issecuredomain(dns_view_t *view, dns_name_t *name, dns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
isc_stdtime_t now, isc_boolean_t *secure_domain) isc_stdtime_t now, isc_boolean_t checknta,
isc_boolean_t *secure_domain)
{ {
isc_result_t result; isc_result_t result;
isc_boolean_t secure = ISC_FALSE; isc_boolean_t secure = ISC_FALSE;
@ -1845,7 +1851,7 @@ dns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
return (result); return (result);
if (secure && view->ntatable_priv != NULL && if (checknta && secure && view->ntatable_priv != NULL &&
dns_ntatable_covered(view->ntatable_priv, now, name, anchor)) dns_ntatable_covered(view->ntatable_priv, now, name, anchor))
secure = ISC_FALSE; secure = ISC_FALSE;

View File

@ -483,7 +483,6 @@ dns_nsec_isset
dns_nsec_nseconly dns_nsec_nseconly
dns_nsec_setbit dns_nsec_setbit
dns_nsec_typepresent dns_nsec_typepresent
dns_nta_create
dns_ntatable_add dns_ntatable_add
dns_ntatable_attach dns_ntatable_attach
dns_ntatable_covered dns_ntatable_covered

View File

@ -136,6 +136,7 @@ static cfg_type_t cfg_type_sizenodefault;
static cfg_type_t cfg_type_sockaddr4wild; static cfg_type_t cfg_type_sockaddr4wild;
static cfg_type_t cfg_type_sockaddr6wild; static cfg_type_t cfg_type_sockaddr6wild;
static cfg_type_t cfg_type_statschannels; static cfg_type_t cfg_type_statschannels;
static cfg_type_t cfg_type_ttlval;
static cfg_type_t cfg_type_view; static cfg_type_t cfg_type_view;
static cfg_type_t cfg_type_viewopts; static cfg_type_t cfg_type_viewopts;
static cfg_type_t cfg_type_zone; static cfg_type_t cfg_type_zone;
@ -1544,6 +1545,8 @@ view_clauses[] = {
{ "max-udp-size", &cfg_type_uint32, 0 }, { "max-udp-size", &cfg_type_uint32, 0 },
{ "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
{ "minimal-responses", &cfg_type_boolean, 0 }, { "minimal-responses", &cfg_type_boolean, 0 },
{ "nta-recheck", &cfg_type_ttlval, 0 },
{ "nta-lifetime", &cfg_type_ttlval, 0 },
{ "prefetch", &cfg_type_prefetch, 0 }, { "prefetch", &cfg_type_prefetch, 0 },
{ "preferred-glue", &cfg_type_astring, 0 }, { "preferred-glue", &cfg_type_astring, 0 },
{ "no-case-compress", &cfg_type_bracketed_aml, 0 }, { "no-case-compress", &cfg_type_bracketed_aml, 0 },
@ -3182,7 +3185,7 @@ static cfg_type_t cfg_type_masterselement = {
}; };
static isc_result_t static isc_result_t
parse_maxttlval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { parse_ttlval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
isc_result_t result; isc_result_t result;
cfg_obj_t *obj = NULL; cfg_obj_t *obj = NULL;
isc_uint32_t ttl; isc_uint32_t ttl;
@ -3213,15 +3216,16 @@ parse_maxttlval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
} }
/*% /*%
* A size value (number + optional unit). * A TTL value (number + optional unit).
*/ */
static cfg_type_t cfg_type_maxttlval = { static cfg_type_t cfg_type_ttlval = {
"maxttlval", parse_maxttlval, cfg_print_uint64, cfg_doc_terminal, "ttlval", parse_ttlval, cfg_print_uint64, cfg_doc_terminal,
&cfg_rep_uint64, NULL }; &cfg_rep_uint64, NULL
};
static isc_result_t static isc_result_t
parse_maxttl(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { parse_maxttl(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
return (parse_enum_or_other(pctx, type, &cfg_type_maxttlval, ret)); return (parse_enum_or_other(pctx, type, &cfg_type_ttlval, ret));
} }
/*% /*%