]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] complete NTA work
authorEvan Hunt <each@isc.org>
Wed, 18 Jun 2014 23:47:22 +0000 (16:47 -0700)
committerEvan Hunt <each@isc.org>
Wed, 18 Jun 2014 23:50:38 +0000 (16:50 -0700)
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]

29 files changed:
CHANGES
bin/named/config.c
bin/named/query.c
bin/named/server.c
bin/rndc/rndc.docbook
bin/tests/system/dlvauto/tests.sh
bin/tests/system/dnssec/ns2/example.db.in
bin/tests/system/dnssec/ns2/sign.sh
bin/tests/system/dnssec/ns3/bogus.example.db.in
bin/tests/system/dnssec/ns3/named.conf
bin/tests/system/dnssec/ns3/secure.example.db.in
bin/tests/system/dnssec/ns3/sign.sh
bin/tests/system/dnssec/ns4/named1.conf
bin/tests/system/dnssec/setup.sh
bin/tests/system/dnssec/tests.sh
doc/arm/Bv9ARM-book.xml
lib/bind9/check.c
lib/dns/cache.c
lib/dns/include/dns/nta.h
lib/dns/include/dns/resolver.h
lib/dns/include/dns/validator.h
lib/dns/include/dns/view.h
lib/dns/nta.c
lib/dns/resolver.c
lib/dns/tests/keytable_test.c
lib/dns/validator.c
lib/dns/view.c
lib/dns/win32/libdns.def.in
lib/isccfg/namedconf.c

diff --git a/CHANGES b/CHANGES
index a02ff61d34f8c5786447bcd063b8cf91d42c9915..ac7181cd4282d9bf8d14a67fbd8b00cef536f234 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -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.
                        [RT #36303]
 
index 55155726a37406cc9c61c4aac21a3bb56a1405db..c841e31e097b95845bef69b95d1d594f6b9b2b42 100644 (file)
@@ -53,6 +53,7 @@
 static char defaultconf[] = "\
 options {\n\
        automatic-interface-scan yes;\n\
+       bindkeys-file \"" NS_SYSCONFDIR "/bind.keys\";\n\
 #      blackhole {none;};\n"
 #ifndef WIN32
 "      coresize default;\n\
@@ -78,8 +79,9 @@ options {\n\
        memstatistics-file \"named.memstats\";\n\
        multiple-cnames no;\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\
-       bindkeys-file \"" NS_SYSCONFDIR "/bind.keys\";\n\
        port 53;\n\
        prefetch 2 9;\n\
        recursing-file \"named.recursing\";\n\
index 775e99dd25346e2d67cde9fe5f3f3b663e14c5b7..a0edf106a8f4021cbaa03ceb4785807ef25a248d 100644 (file)
@@ -15,8 +15,6 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id$ */
-
 /*! \file */
 
 #include <config.h>
index 679cf28fffc2fe377e61e84f8a99f646a4973327..a23db3391283af0d66c13f6105f078202236c88f 100644 (file)
@@ -826,7 +826,7 @@ configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
                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) {
                isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                              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)
                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;
        result = ns_config_get(maps, "preferred-glue", &obj);
        if (result == ISC_R_SUCCESS) {
@@ -3626,6 +3636,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
        } else {
                empty_zones_enable = ISC_FALSE;
        }
+
        if (empty_zones_enable && !lwresd_g_useresolvconf) {
                const char *empty;
                int empty_zone = 0;
@@ -7768,6 +7779,7 @@ isc_result_t
 ns_server_dumpsecroots(ns_server_t *server, char *args) {
        dns_view_t *view;
        dns_keytable_t *secroots = NULL;
+       dns_ntatable_t *ntatable = NULL;
        isc_result_t result;
        char *ptr;
        FILE *fp = NULL;
@@ -7801,11 +7813,25 @@ ns_server_dumpsecroots(ns_server_t *server, char *args) {
                                result = ISC_R_SUCCESS;
                                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);
                        if (result != ISC_R_SUCCESS)
                                fprintf(fp, " dumpsecroots failed: %s\n",
                                        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)
                        ptr = next_token(&args, " \t");
@@ -7814,6 +7840,8 @@ ns_server_dumpsecroots(ns_server_t *server, char *args) {
  cleanup:
        if (secroots != NULL)
                dns_keytable_detach(&secroots);
+       if (ntatable != NULL)
+               dns_ntatable_detach(&ntatable);
        if (fp != NULL)
                (void)isc_stdio_close(fp);
        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_ntatable_t *ntatable = NULL;
        isc_result_t result;
-       char *ptr, *nametext, *viewname;
+       char *ptr, *nametext = NULL, *viewname;
        isc_stdtime_t now, when;
        isc_time_t t;
        char tbuf[64];
        const char *msg = NULL;
+       isc_boolean_t dump = ISC_FALSE, force = ISC_FALSE;
        dns_fixedname_t fn;
        dns_name_t *ntaname;
        dns_ttl_t ntattl;
-       isc_textregion_t tr;
+       isc_boolean_t ttlset = ISC_FALSE;
+
+       UNUSED(force);
 
        dns_fixedname_init(&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)
                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. */
-       nametext = next_token(&args, " \t");
+       if (nametext == NULL)
+               nametext = next_token(&args, " \t");
        if (nametext == NULL)
                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));
        }
 
-       /* 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. */
        viewname = next_token(&args, " \t");
 
-       /* Set up the NTA */
        isc_stdtime_get(&now);
-       when = now + ntattl;
 
        result = isc_task_beginexclusive(server->task);
        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)
                        continue;
 
+               if (view->nta_lifetime == 0 || view->nta_recheck == 0)
+                       continue;
+
+               if (!ttlset)
+                       ntattl = view->nta_lifetime;
+
                if (ntatable != NULL)
                        dns_ntatable_detach(&ntatable);
 
@@ -9851,11 +9942,13 @@ ns_server_nta(ns_server_t *server, char *args, isc_buffer_t *text) {
                              nametext, view->name,
                              isc_result_totext(result));
 
-               isc_time_set(&t, when, 0);
-               isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
+               if (ntattl != 0) {
+                       CHECK(dns_ntatable_add(ntatable, ntaname,
+                                              force, now, ntattl));
 
-               if (ntattl > 0) {
-                       CHECK(dns_ntatable_add(ntatable, ntaname, when));
+                       when = now + ntattl;
+                       isc_time_set(&t, when, 0);
+                       isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
 
                        CHECK(putstr(text, "Negative trust anchor added: "));
                        CHECK(putstr(text, nametext));
index 7c28ac480f5e268086c38cf743308f7087734c97..c3c6e78cfcc21dcca74071b5cd273455dfe53829 100644 (file)
         <term><userinput>secroots <optional><replaceable>view ...</replaceable></optional></userinput></term>
         <listitem>
           <para>
-            Dump the server's security roots to the secroots
-            file for the specified views.  If no view is
-            specified, security roots for all
-            views are dumped.
+            Dump the server's security roots and negative trust anchors
+            to the secroots file for the specified views.  If no view is
+            specified, all views are dumped.
           </para>
         </listitem>
       </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>
           <para>
             Sets a DNSSEC negative trust anchor (NTA)
             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>
             A negative trust anchor selectively disables
             restarted (NTA's do not persist across restarts).
           </para>
           <para>
-            TTL-style suffixes can be used to specify
-            <option>duration</option> in seconds, minutes, or hours.
+            An existing NTA can be removed by using the
+            <option>-remove</option> option.
+          </para>
+          <para>
+            An NTA's lifetime can be specified with the
+            <option>-lifetime</option> option.  TTL-style
+            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>
-            If the specified domain already has an NTA, its duration
-            will be updated to the new value.  Setting
-            <option>duration</option> to zero will delete the NTA.
+            All of these options can be shortened, i.e., to
+            <option>-l</option>, <option>-r</option>, <option>-d</option>,
+            and <option>-f</option>.
           </para>
         </listitem>
       </varlistentry>
index a6866980df6e68d232b54ee3283e745ca8758f77..e4de957192989c1dacd3fc9f696dc623c993b4bf 100644 (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" -eq 2 ] || ret=1
 linecount=`cat ns2/named.secroots | wc -l`
-[ "$linecount" -eq 13 ] || ret=1
+[ "$linecount" -eq 28 ] || ret=1
 n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
index db66cc66da6b1d38af9de57cfbb0b2dfd6b64165..7d86540b410bb5c98205c8c5a6d944738c62cd4d 100644 (file)
@@ -65,6 +65,10 @@ ns.insecure          A       10.53.0.3
 bogus                  NS      ns.bogus
 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
 dynamic                        NS      dynamic
 dynamic                        A       10.53.0.3
index a4dcad3788f462f84a3c7c67bb17e08b025a11e3..f302d79b00b4e6492cd876ffecc4610f48563cee 100644 (file)
@@ -26,11 +26,10 @@ zonefile=example.db
 
 ( cd ../ns3 && $SHELL sign.sh )
 
-for subdomain in secure bogus dynamic keyless nsec3 optout nsec3-unknown \
-    optout-unknown multiple rsasha256 rsasha512 kskonly update-nsec3 \
-    auto-nsec auto-nsec3 secure.below-cname ttlpatch split-dnssec \
-    split-smart expired expiring upper lower
-
+for subdomain in secure badds bogus dynamic keyless nsec3 optout \
+       nsec3-unknown optout-unknown multiple rsasha256 rsasha512 \
+       kskonly update-nsec3 auto-nsec auto-nsec3 secure.below-cname \
+       ttlpatch split-dnssec split-smart expired expiring upper lower
 do
        cp ../ns3/dsset-$subdomain.example. .
 done
index e83d07bea05f9d125957175e1bba333f7e49a3ff..80fb5e399244c94a4ef1ee9414b75e692400228e 100644 (file)
@@ -28,5 +28,6 @@ ns                    A       10.53.0.3
 
 a                      A       10.0.0.1
 b                      A       10.0.0.2
+c                      A       10.0.0.3
 d                      A       10.0.0.4
 z                      A       10.0.0.26
index 23b9d1d6a94cbff85effc9aa3316fbf196571776..c655c0d6b694c7f94c93a2b9c06b5470b2287260 100644 (file)
@@ -68,6 +68,12 @@ zone "bogus.example" {
        allow-update { any; };
 };
 
+zone "badds.example" {
+       type master;
+       file "badds.example.db.signed";
+       allow-update { any; };
+};
+
 zone "dynamic.example" {
        type master;
        file "dynamic.example.db.signed";
index 0d2fa4f46a8f80bde09c9eaf081c60c4b3cc64ca..d5081e7546ab32c31c1c8695ca4412df753ec6b6 100644 (file)
@@ -26,7 +26,11 @@ ns3                  A       10.53.0.3
 
 a                      A       10.0.0.1
 b                      A       10.0.0.2
+c                      A       10.0.0.3
 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
 a.a.a.a.a.a.a.a.a.a.e  A       10.0.0.27
 x                      CNAME   a
index fc6a5a24dd792155bfd0fdaa3d13261f6b6b43b4..bef02321bbfd27231900fd41368cacfff973764e 100644 (file)
@@ -459,3 +459,18 @@ zonefile=siginterval.example.db
 kskname=`$KEYGEN -q -3 -r $RANDFILE -fk $zone`
 zskname=`$KEYGEN -q -3 -r $RANDFILE $zone`
 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.
index 2cc3034992bf7ad1cfcaa079dd92ee2f0ef374b2..3873723d73467e342e0372c88dc89e94e00457b2 100644 (file)
@@ -34,6 +34,9 @@ options {
        dnssec-validation 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
        # 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.
index 23143836b2a86aa21933f711d04dbd62ff1e8579..f2e4980bb1e5511c2cc5d523acca0e728770d051 100644 (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 "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 ../ns4 && cp -f named1.conf named.conf
index 2961b7504816f4fee14bccaf4715f64a1e02d210..67460724e24a96abd045e95ed2b5a1a0f8105c11 100644 (file)
@@ -1568,7 +1568,7 @@ keyid=`cat ns1/managed.key.id`
 linecount=`grep "./RSAMD5/$keyid ; trusted" ns4/named.secroots | wc -l`
 [ "$linecount" -eq 1 ] || ret=1
 linecount=`cat ns4/named.secroots | wc -l`
-[ "$linecount" -eq 5 ] || ret=1
+[ "$linecount" -eq 10 ] || ret=1
 n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
@@ -1654,26 +1654,88 @@ status=`expr $status + $ret`
 
 echo "I:checking positive and negative validation with negative trust anchors ($n)"
 ret=0
+#
 # check correct initial behavior
+#
 $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
-$DIG $DIGOPTS a.secure.example. a @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
+$DIG $DIGOPTS badds.example. soa @10.53.0.4 > dig.out.ns4.test$n.2 || 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
-$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
-$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.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.4 || ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.4 > /dev/null && ret=1
-echo "I: waiting for NTA expiration"
-sleep 15
-# check correct behavior after expiry
-$DIG $DIGOPTS b.bogus.example. a @10.53.0.4 > dig.out.ns4.test$n.5 || ret=1
-grep "status: SERVFAIL" dig.out.ns4.test$n.5 > /dev/null || ret=1
-$DIG $DIGOPTS b.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.6 || ret=1
-grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.6 > /dev/null || ret=1
+#
+$DIG $DIGOPTS a.bogus.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
+$DIG $DIGOPTS badds.example. soa @10.53.0.4 > dig.out.ns4.test$n.5 || ret=1
+grep "status: SERVFAIL" dig.out.ns4.test$n.5 > /dev/null && ret=1
+$DIG $DIGOPTS a.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.6 || ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.6 > /dev/null && ret=1
+$DIG $DIGOPTS a.fakenode.secure.example. a @10.53.0.4 > dig.out.ns4.test$n.7 || ret=1
+grep "flags:[^;]* ad[^;]*;" dig.out.ns4.test$n.7 > /dev/null && ret=1
+echo "I: dumping secroots"
+$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`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
index 8616ba0a915bd303583d470ffb5f13b45068fed7..bf99f22cc5cc66cdca0db6a1b38fb340c251a7a5 100644 (file)
@@ -4939,6 +4939,8 @@ badresp:1,adberr:0,findfail:0,valfail:0]
     <optional> max-refresh-time <replaceable>number</replaceable> ; </optional>
     <optional> min-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> dscp <replaceable>ip_dscp</replaceable></optional> ;
     <optional> additional-from-auth <replaceable>yes_or_no</replaceable> ; </optional>
@@ -5746,6 +5748,69 @@ options {
            </listitem>
          </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>
            <term><command>max-zone-ttl</command></term>
            <listitem>
index faa467cba0ba29f1c1d960d5e283f2256631faf5..262c4f88b5f7bfec9cbd166e73ca7f0d1b09d1c7 100644 (file)
@@ -783,6 +783,7 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
        const char *str;
        dns_name_t *name;
        isc_buffer_t b;
+       isc_uint32_t lifetime;
 
        static intervaltable intervals[] = {
        { "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)
                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);
 }
 
index abe163b35da15027cbe51e408c17599a3dbdfb6a..07be9d4a31f04a30221c506e545e215bf2d25611 100644 (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);
                if (result != ISC_R_SUCCESS)
                        goto cleanup_db;
+
+               isc_task_setname(dbtask, "cache_dbtask", NULL);
                dns_db_settask(cache->db, dbtask);
                isc_task_detach(&dbtask);
        }
index 3231171da8dff6acb8e13ebe7ca36e1542a69c31..f6826485a96a20205fb9f8261303c932e672fb96 100644 (file)
  * DNSSEC validation.
  */
 
+#include <isc/buffer.h>
 #include <isc/lang.h>
 #include <isc/magic.h>
 #include <isc/refcount.h>
 #include <isc/rwlock.h>
 #include <isc/stdtime.h>
+#include <isc/task.h>
+#include <isc/timer.h>
 
 #include <dns/types.h>
+#include <dns/rdataset.h>
+#include <dns/resolver.h>
+#include <dns/view.h>
 
 ISC_LANG_BEGINDECLS
 
 struct dns_ntatable {
        /* Unlocked. */
        unsigned int            magic;
-       isc_mem_t               *mctx;
+       dns_view_t              *view;
        isc_rwlock_t            rwlock;
+       isc_uint32_t            recheck;
+       isc_taskmgr_t           *taskmgr;
+       isc_timermgr_t          *timermgr;
+       isc_task_t              *task;
        /* Locked by rwlock. */
        isc_uint32_t            references;
        dns_rbt_t               *table;
@@ -51,23 +61,18 @@ struct dns_ntatable {
 #define NTATABLE_MAGIC         ISC_MAGIC('N', 'T', 'A', 't')
 #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
-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:
  *
- *\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
  *
@@ -116,10 +121,13 @@ dns_ntatable_detach(dns_ntatable_t **ntatablep);
 
 isc_result_t
 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',
- * 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:
  *
@@ -191,15 +199,15 @@ dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
  */
 
 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
-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
 
index bea163686f45bdc4a2dc9fc1e90aebffeb6fc871..e9aabc2b8cb9eb57e552fcbe06c29c934af90406 100644 (file)
@@ -98,6 +98,7 @@ typedef struct dns_fetchevent {
 #define DNS_FETCHOPT_WANTNSID          0x080        /*%< Request NSID */
 #define DNS_FETCHOPT_PREFETCH          0x100        /*%< Do prefetch */
 #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 */
 #define        DNS_FETCHOPT_EDNSVERSIONSET     0x00800000
index 0abf1dce1f183d849975182b299796ccc9234353..505a25e5cdf34009f79df6c524d65eb3035283fc 100644 (file)
@@ -174,6 +174,7 @@ struct dns_validator {
 #define DNS_VALIDATOR_DLV              0x0001U
 #define DNS_VALIDATOR_DEFER            0x0002U
 #define DNS_VALIDATOR_NOCDFLAG         0x0004U
+#define DNS_VALIDATOR_NONTA            0x0008U  /*% Ignore NTA table */
 
 ISC_LANG_BEGINDECLS
 
index 3a0c3f8602e81bb1c0840dd0ec1970b13ca3c2d9..0e7808db604fa36b2f8a8afb5ef9f2ef1d403501 100644 (file)
@@ -152,6 +152,8 @@ struct dns_view {
        isc_boolean_t                   requestsit;
        dns_ttl_t                       maxcachettl;
        dns_ttl_t                       maxncachettl;
+       isc_uint32_t                    nta_lifetime;
+       isc_uint32_t                    nta_recheck;
        dns_ttl_t                       prefetch_trigger;
        dns_ttl_t                       prefetch_eligible;
        in_port_t                       dstport;
@@ -1076,7 +1078,8 @@ dns_view_iscacheshared(dns_view_t *view);
  */
 
 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.
  *
@@ -1144,11 +1147,15 @@ dns_view_getsecroots(dns_view_t *view, dns_keytable_t **ktp);
 
 isc_result_t
 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
  * 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:
  * \li 'view' is valid.
  *
index 879ab0ae8e498dabede79e6c16ee04488b72d4fe..f48b5424d47b5b8937cffb4455fb312730bd8620 100644 (file)
 
 #include <config.h>
 
+#include <isc/buffer.h>
 #include <isc/log.h>
 #include <isc/mem.h>
 #include <isc/rwlock.h>
 #include <isc/string.h>
+#include <isc/task.h>
 #include <isc/time.h>
+#include <isc/timer.h>
 #include <isc/util.h>
 
+#include <dns/db.h>
 #include <dns/log.h>
 #include <dns/nta.h>
 #include <dns/fixedname.h>
 #include <dns/name.h>
 #include <dns/rbt.h>
+#include <dns/rdataset.h>
+#include <dns/resolver.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
 nta_detach(isc_mem_t *mctx, dns_nta_t **ntap) {
        unsigned int refs;
@@ -42,7 +64,22 @@ nta_detach(isc_mem_t *mctx, dns_nta_t **ntap) {
        *ntap = NULL;
        isc_refcount_decrement(&nta->refcount, &refs);
        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);
+               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));
        }
 }
@@ -56,32 +93,41 @@ free_nta(void *data, void *arg) {
 }
 
 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;
        isc_result_t result;
 
-       /*
-        * Create an NTA table.
-        */
-
        REQUIRE(ntatablep != NULL && *ntatablep == NULL);
 
-       ntatable = isc_mem_get(mctx, sizeof(*ntatable));
+       ntatable = isc_mem_get(view->mctx, sizeof(*ntatable));
        if (ntatable == NULL)
                return (ISC_R_NOMEMORY);
 
-       ntatable->table = NULL;
-       result = dns_rbt_create(mctx, free_nta, mctx, &ntatable->table);
+       ntatable->task = NULL;
+       result = isc_task_create(taskmgr, 0, &ntatable->task);
        if (result != ISC_R_SUCCESS)
                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);
        if (result != ISC_R_SUCCESS)
                goto cleanup_rbt;
 
-       ntatable->mctx = NULL;
-       isc_mem_attach(mctx, &ntatable->mctx);
+       ntatable->timermgr = timermgr;
+       ntatable->taskmgr = taskmgr;
+
+       ntatable->view = view;
        ntatable->references = 1;
+
        ntatable->magic = NTATABLE_MAGIC;
        *ntatablep = ntatable;
 
@@ -90,8 +136,11 @@ dns_ntatable_create(isc_mem_t *mctx, dns_ntatable_t **ntatablep) {
    cleanup_rbt:
        dns_rbt_destroy(&ntatable->table);
 
+   cleanup_task:
+       isc_task_detach(&ntatable->task);
+
    cleanup_ntatable:
-       isc_mem_put(mctx, ntatable, sizeof(*ntatable));
+       isc_mem_put(ntatable->view->mctx, ntatable, sizeof(*ntatable));
 
        return (result);
 }
@@ -132,43 +181,187 @@ dns_ntatable_detach(dns_ntatable_t **ntatablep) {
        if (destroy) {
                dns_rbt_destroy(&ntatable->table);
                isc_rwlock_destroy(&ntatable->rwlock);
+               if (ntatable->task != NULL)
+                       isc_task_detach(&ntatable->task);
+               ntatable->timermgr = NULL;
+               ntatable->taskmgr = NULL;
                ntatable->magic = 0;
-               isc_mem_putanddetach(&ntatable->mctx,
-                                    ntatable, sizeof(*ntatable));
+               isc_mem_put(ntatable->view->mctx, 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
 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;
        dns_nta_t *nta = NULL;
        dns_rbtnode_t *node;
+       dns_view_t *view;
 
        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)
                return (result);
 
-       nta->expiry = expiry;
+       nta->expiry = now + lifetime;
 
        RWLOCK(&ntatable->rwlock, isc_rwlocktype_write);
 
        node = NULL;
        result = dns_rbt_addnode(ntatable->table, name, &node);
        if (result == ISC_R_SUCCESS) {
+               if (!force)
+                       (void)settimer(ntatable, nta, lifetime);
                node->data = nta;
                nta = NULL;
        } else if (result == ISC_R_EXISTS) {
                dns_nta_t *n = node->data;
                if (n == NULL) {
+                       if (!force)
+                               (void)settimer(ntatable, nta, lifetime);
                        node->data = nta;
                        nta = NULL;
                } else {
                        n->expiry = nta->expiry;
-                       nta_detach(ntatable->mctx, &nta);
+                       nta_detach(view->mctx, &nta);
                }
                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);
 
        if (nta != NULL)
-               nta_detach(ntatable->mctx, &nta);
+               nta_detach(view->mctx, &nta);
 
        return (result);
 }
@@ -268,6 +461,13 @@ dns_ntatable_covered(dns_ntatable_t *ntatable, isc_stdtime_t now,
                              DNS_LOGMODULE_NTA, ISC_LOG_INFO,
                              "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);
                if (result != ISC_R_SUCCESS) {
                        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
-dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) {
+dns_ntatable_totext(dns_ntatable_t *ntatable, isc_buffer_t *buf) {
        isc_result_t result;
        dns_rbtnode_t *node;
        dns_rbtnodechain_t chain;
+       isc_boolean_t first = ISC_TRUE;
+       isc_stdtime_t now;
 
        REQUIRE(VALID_NTATABLE(ntatable));
 
+       isc_stdtime_get(&now);
+
        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);
        if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
                goto cleanup;
@@ -300,15 +504,28 @@ dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) {
                if (node->data != NULL) {
                        dns_nta_t *n = (dns_nta_t *) node->data;
                        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;
 
-                       dns_name_init(&name, NULL);
-                       dns_rbt_namefromnode(node, &name);
-                       dns_name_format(&name, nbuf, sizeof(nbuf));
+                       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 : 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) {
@@ -318,6 +535,9 @@ dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) {
                }
        }
 
+       if (isc_buffer_availablelength(buf) != 0)
+               isc_buffer_putuint8(buf, 0);
+
    cleanup:
        dns_rbtnodechain_invalidate(&chain);
        RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read);
@@ -325,26 +545,50 @@ dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) {
 }
 
 isc_result_t
-dns_nta_create(isc_mem_t *mctx, dns_nta_t **target) {
+dns_ntatable_dump(dns_ntatable_t *ntatable, FILE *fp) {
        isc_result_t result;
-       dns_nta_t *nta = NULL;
+       dns_rbtnode_t *node;
+       dns_rbtnodechain_t chain;
+       isc_stdtime_t now;
 
-       REQUIRE(target != NULL && *target == NULL);
+       REQUIRE(VALID_NTATABLE(ntatable));
 
-       nta = isc_mem_get(mctx, sizeof(dns_nta_t));
-       if (nta == NULL)
-               return (ISC_R_NOMEMORY);
+       isc_stdtime_get(&now);
 
-       nta->expiry = 0;
+       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;
 
-       result = isc_refcount_init(&nta->refcount, 1);
-       if (result != ISC_R_SUCCESS) {
-               isc_mem_put(mctx, nta, sizeof(dns_nta_t));
-               return (result);
+                       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);
+               if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
+                       if (result == ISC_R_NOMORE)
+                               result = ISC_R_SUCCESS;
+                       break;
+               }
        }
 
-       nta->magic = NTA_MAGIC;
-
-       *target = nta;
-       return (ISC_R_SUCCESS);
+   cleanup:
+       dns_rbtnodechain_invalidate(&chain);
+       RWUNLOCK(&ntatable->rwlock, isc_rwlocktype_read);
+       return (result);
 }
index dc14a1d8b3c80a93b405ecfc7ef1daaae5315a5a..27b61ae5d5e901c3e814a3e7fd2ce78909a8ef9b 100644 (file)
@@ -1823,7 +1823,8 @@ compute_cc(resquery_t *query, unsigned char *sit, size_t len) {
 
 static isc_result_t
 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;
        unsigned int labels;
@@ -1841,7 +1842,7 @@ issecuredomain(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
                name = &suffix;
        }
 
-       return (dns_view_issecuredomain(view, name, now, issecure));
+       return (dns_view_issecuredomain(view, name, now, checknta, issecure));
 }
 
 static isc_result_t
@@ -1944,10 +1945,13 @@ resquery_send(resquery_t *query) {
        else if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0)
                fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
        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,
                                        fctx->type, query->start.seconds,
-                                       &secure_domain);
+                                       checknta, &secure_domain);
                if (result != ISC_R_SUCCESS)
                        secure_domain = ISC_FALSE;
                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_boolean_t fail;
        unsigned int valoptions = 0;
+       isc_boolean_t checknta = ISC_TRUE;
 
        /*
         * 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?
         */
+       if ((fctx->options & DNS_FETCHOPT_NONTA) != 0) {
+               valoptions |= DNS_VALIDATOR_NONTA;
+               checknta = ISC_FALSE;
+       }
+
        if (res->view->enablevalidation) {
                result = issecuredomain(res->view, name, fctx->type,
-                                       now, &secure_domain);
+                                       now, checknta, &secure_domain);
                if (result != ISC_R_SUCCESS)
                        return (result);
 
                if (!secure_domain && res->view->dlv != NULL) {
-                       valoptions = DNS_VALIDATOR_DLV;
+                       valoptions |= DNS_VALIDATOR_DLV;
                        secure_domain = ISC_TRUE;
                }
        }
@@ -5362,6 +5372,7 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
        dns_fetchevent_t *event;
        isc_uint32_t ttl;
        unsigned int valoptions = 0;
+       isc_boolean_t checknta = ISC_TRUE;
 
        FCTXTRACE("ncache_message");
 
@@ -5384,14 +5395,19 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
        /*
         * 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) {
                result = issecuredomain(res->view, name, fctx->type,
-                                       now, &secure_domain);
+                                       now, checknta, &secure_domain);
                if (result != ISC_R_SUCCESS)
                        return (result);
 
                if (!secure_domain && res->view->dlv != NULL) {
-                       valoptions = DNS_VALIDATOR_DLV;
+                       valoptions |= DNS_VALIDATOR_DLV;
                        secure_domain = ISC_TRUE;
                }
        }
@@ -8275,6 +8291,7 @@ dns_resolver_create(dns_view_t *view,
        result = isc_task_create(taskmgr, 0, &task);
        if (result != ISC_R_SUCCESS)
                goto cleanup_primelock;
+       isc_task_setname(task, "resolver_task", NULL);
 
        result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
                                  task, spillattimer_countdown, res,
index 620b76f9a87caa4b136eb443dba660c870f7db33..8fcb5589301bdebd7d9beb2b3f93ab9f56431603 100644 (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 dns_view_t *view = NULL;
+
 /*
  * Test utilities.  In general, these assume input parameters are valid
  * (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 */
 static void
 create_tables() {
+       isc_result_t result;
        dst_key_t *key = NULL;
        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_ntatable_create(mctx, &ntatable), ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_ntatable_create(view, taskmgr, timermgr,
+                                          &ntatable), ISC_R_SUCCESS);
 
        /* Add a normal key */
        create_key(257, 3, 5, "example.com", keystr1, &key);
@@ -139,7 +146,7 @@ create_tables() {
        isc_stdtime_get(&now);
        ATF_REQUIRE_EQ(dns_ntatable_add(ntatable,
                                        str2name("insecure.example"),
-                                       now + 3600),
+                                       ISC_FALSE, now, 3600),
                       ISC_R_SUCCESS);
 }
 
@@ -149,6 +156,8 @@ destroy_tables() {
                dns_ntatable_detach(&ntatable);
        if (keytable != NULL)
                dns_keytable_detach(&keytable);
+
+       dns_view_detach(&view);
 }
 
 /*
@@ -167,7 +176,7 @@ ATF_TC_BODY(add, 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();
 
        /*
@@ -246,7 +255,7 @@ ATF_TC_HEAD(delete, tc) {
 ATF_TC_BODY(delete, 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();
 
        /* dns_keytable_delete requires exact match */
@@ -279,7 +288,7 @@ ATF_TC_BODY(deletekeynode, 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();
 
        /* key name doesn't match */
@@ -340,7 +349,7 @@ ATF_TC_BODY(find, 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();
 
        /*
@@ -432,7 +441,7 @@ ATF_TC_BODY(issecuredomain, tc) {
                               "null.example", "sub.null.example", NULL};
 
        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();
 
        /*
@@ -476,7 +485,7 @@ ATF_TC_HEAD(dump, tc) {
 ATF_TC_BODY(dump, 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();
 
        /*
@@ -508,12 +517,15 @@ ATF_TC_BODY(nta, tc) {
        result = dns_test_makeview("view", &view);
        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);
        ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
        result = dns_view_getsecroots(view, &keytable);
        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);
        result = dns_view_getntatable(view, &ntatable);
        ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
@@ -524,20 +536,21 @@ ATF_TC_BODY(nta, tc) {
 
        isc_stdtime_get(&now);
        result = dns_ntatable_add(ntatable,
-                                 str2name("insecure.example"), now + 1);
+                                 str2name("insecure.example"),
+                                 ISC_FALSE, now, 1);
        ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
 
        /* Should be secure */
        result = dns_view_issecuredomain(view,
                                         str2name("test.secure.example"),
-                                        now, &issecure);
+                                        now, ISC_TRUE, &issecure);
        ATF_CHECK_EQ(result, ISC_R_SUCCESS);
        ATF_CHECK(issecure);
 
        /* Should not be secure */
        result = dns_view_issecuredomain(view,
                                         str2name("test.insecure.example"),
-                                        now, &issecure);
+                                        now, ISC_TRUE, &issecure);
        ATF_CHECK_EQ(result, ISC_R_SUCCESS);
        ATF_CHECK(!issecure);
 
@@ -554,17 +567,17 @@ ATF_TC_BODY(nta, tc) {
        /* As of now + 2, the NTA should be clear */
        result = dns_view_issecuredomain(view,
                                         str2name("test.insecure.example"),
-                                        now + 2, &issecure);
+                                        now + 2, ISC_TRUE, &issecure);
        ATF_CHECK_EQ(result, ISC_R_SUCCESS);
        ATF_CHECK(issecure);
 
        /* Now check deletion */
-       result = dns_ntatable_add(ntatable,
-                                 str2name("new.example"), now + 3600);
+       result = dns_ntatable_add(ntatable, str2name("new.example"),
+                                 ISC_FALSE, now, 3600);
        ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
 
        result = dns_view_issecuredomain(view, str2name("test.new.example"),
-                                        now, &issecure);
+                                        now, ISC_TRUE, &issecure);
        ATF_CHECK_EQ(result, ISC_R_SUCCESS);
        ATF_CHECK(!issecure);
 
@@ -572,7 +585,7 @@ ATF_TC_BODY(nta, tc) {
        ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
 
        result = dns_view_issecuredomain(view, str2name("test.new.example"),
-                                        now, &issecure);
+                                        now, ISC_TRUE, &issecure);
        ATF_CHECK_EQ(result, ISC_R_SUCCESS);
        ATF_CHECK(issecure);
 
index f7d7d70e2049a08fd2fc45703c86e68b565a0dec..36fe54330ba5448d5ca18871695adb8e7ed98176 100644 (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)
                fopts |= DNS_FETCHOPT_NOCDFLAG;
 
+       if ((val->options & DNS_VALIDATOR_NONTA) != 0)
+               fopts |= DNS_FETCHOPT_NONTA;
+
        validator_logcreate(val, name, type, caller, "fetch");
        return (dns_resolver_createfetch(val->view->resolver, name, type,
                                         NULL, NULL, NULL, fopts,
@@ -3164,7 +3167,8 @@ finddlvsep(dns_validator_t *val, isc_boolean_t resume) {
                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);
 
        while (dns_name_countlabels(dlvname) >=
index d3462ffe2f0ef5fe250f9fb33165a11534c87cf2..4a45f1912b70325e2d0094aa833eb0943acf990e 100644 (file)
@@ -192,6 +192,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
        view->provideixfr = ISC_TRUE;
        view->maxcachettl = 7 * 24 * 3600;
        view->maxncachettl = 3 * 3600;
+       view->nta_lifetime = 0;
+       view->nta_recheck = 0;
        view->prefetch_eligible = 0;
        view->prefetch_trigger = 0;
        view->dstport = 53;
@@ -1776,11 +1778,14 @@ dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp) {
 }
 
 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));
        if (view->ntatable_priv != NULL)
                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
@@ -1825,7 +1830,8 @@ dns_view_ntacovers(dns_view_t *view, isc_stdtime_t now,
 
 isc_result_t
 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_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)
                return (result);
 
-       if (secure && view->ntatable_priv != NULL &&
+       if (checknta && secure && view->ntatable_priv != NULL &&
            dns_ntatable_covered(view->ntatable_priv, now, name, anchor))
                secure = ISC_FALSE;
 
index 838b403e4f87457e21ea246f4fd5ea1bd910324d..740a35442489cfc253db401126d72083a51f1081 100644 (file)
@@ -483,7 +483,6 @@ dns_nsec_isset
 dns_nsec_nseconly
 dns_nsec_setbit
 dns_nsec_typepresent
-dns_nta_create
 dns_ntatable_add
 dns_ntatable_attach
 dns_ntatable_covered
index 96ce6c12df3a0c9e3c403deebff7d82eaf28036d..377546d9e17ec2bc7be11c49ea46dd4a5bcd546e 100644 (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_sockaddr6wild;
 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_viewopts;
 static cfg_type_t cfg_type_zone;
@@ -1544,6 +1545,8 @@ view_clauses[] = {
        { "max-udp-size", &cfg_type_uint32, 0 },
        { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
        { "minimal-responses", &cfg_type_boolean, 0 },
+       { "nta-recheck", &cfg_type_ttlval, 0 },
+       { "nta-lifetime", &cfg_type_ttlval, 0 },
        { "prefetch", &cfg_type_prefetch, 0 },
        { "preferred-glue", &cfg_type_astring, 0 },
        { "no-case-compress", &cfg_type_bracketed_aml, 0 },
@@ -3182,7 +3185,7 @@ static cfg_type_t cfg_type_masterselement = {
 };
 
 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;
        cfg_obj_t *obj = NULL;
        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 = {
-       "maxttlval", parse_maxttlval, cfg_print_uint64, cfg_doc_terminal,
-       &cfg_rep_uint64, NULL };
+static cfg_type_t cfg_type_ttlval = {
+       "ttlval", parse_ttlval, cfg_print_uint64, cfg_doc_terminal,
+       &cfg_rep_uint64, NULL
+};
 
 static isc_result_t
 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));
 }
 
 /*%