]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2852. [bug] Handle broken DNSSEC trust chains better. [RT #15619]
authorMark Andrews <marka@isc.org>
Thu, 25 Feb 2010 05:35:11 +0000 (05:35 +0000)
committerMark Andrews <marka@isc.org>
Thu, 25 Feb 2010 05:35:11 +0000 (05:35 +0000)
18 files changed:
CHANGES
bin/named/server.c
doc/arm/Bv9ARM-book.xml
lib/dns/include/dns/rdataset.h
lib/dns/include/dns/resolver.h
lib/dns/include/dns/result.h
lib/dns/include/dns/validator.h
lib/dns/ncache.c
lib/dns/rbtdb.c
lib/dns/rdatalist.c
lib/dns/rdataset.c
lib/dns/rdataslab.c
lib/dns/resolver.c
lib/dns/result.c
lib/dns/sdb.c
lib/dns/sdlz.c
lib/dns/validator.c
lib/dns/view.c

diff --git a/CHANGES b/CHANGES
index 95d61e36f38e726549f394e927e8a34f9d4a7e5a..83015f4b23daed3c79ab3bc0192a8ce973c570d6 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+2852.  [bug]           Handle broken DNSSEC trust chains better. [RT #15619]
+
 2851.  [doc]           nslookup.1, removed <informalexample> from the docbook
                        source as it produced bad nroff.  [RT #21007]
 
index b9259c71a7c13c981658b91c7cbbef953f174e38..96e6bd1115311fc988969c265d93e7f0db84441e 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: server.c,v 1.520.12.11 2009/12/24 00:17:47 each Exp $ */
+/* $Id: server.c,v 1.520.12.12 2010/02/25 05:35:09 marka Exp $ */
 
 /*! \file */
 
@@ -4726,6 +4726,8 @@ dumpdone(void *arg, isc_result_t result) {
        }
        if (dctx->cache != NULL) {
                dns_adb_dump(dctx->view->view->adb, dctx->fp);
+               dns_resolver_printbadcache(dctx->view->view->resolver,
+                                          dctx->fp);
                dns_db_detach(&dctx->cache);
        }
        if (dctx->dumpzones) {
index 44e30b16da9652d9b7cc57a4652d2eea30930148..2ea60fee76011916d98dc32d1070596f55d647da 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- File: $Id: Bv9ARM-book.xml,v 1.380.14.24 2010/01/23 23:47:52 tbox Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.380.14.25 2010/02/25 05:35:09 marka Exp $ -->
 <book xmlns:xi="http://www.w3.org/2001/XInclude">
   <title>BIND 9 Administrator Reference Manual</title>
 
@@ -7705,6 +7705,13 @@ avoid-v6-udp-ports { 40000; range 50000 60000; };
                   <literal>1800</literal> (30 minutes).
                 </para>
 
+               <para>
+                 Lame-ttl also controls the amount of time DNSSEC
+                 validation failures are cached.  There is a minimum
+                 of 30 seconds applied to bad cache entries if the
+                 lame-ttl is set to less than 30 seconds.
+               </para>
+
               </listitem>
             </varlistentry>
 
index baff146fcade60a118a2e6747ddb57274c6b6aab..21d6e77c73177b4a8d8174e45d97ddee8b553738 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdataset.h,v 1.65.50.2 2009/01/18 23:47:41 tbox Exp $ */
+/* $Id: rdataset.h,v 1.65.50.3 2010/02/25 05:35:11 marka Exp $ */
 
 #ifndef DNS_RDATASET_H
 #define DNS_RDATASET_H 1
@@ -110,6 +110,9 @@ typedef struct dns_rdatasetmethods {
                                                 dns_rdataset_t *rdataset,
                                                 dns_rdatasetadditional_t type,
                                                 dns_rdatatype_t qtype);
+       void                    (*settrust)(dns_rdataset_t *rdataset,
+                                           dns_trust_t trust);
+       void                    (*expire)(dns_rdataset_t *rdataset);
 } dns_rdatasetmethods_t;
 
 #define DNS_RDATASET_MAGIC            ISC_MAGIC('D','N','S','R')
@@ -634,6 +637,19 @@ dns_rdataset_putadditional(dns_acache_t *acache,
  *                       information for 'rdataset.'
  */
 
+void
+dns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
+/*%<
+ * Set the trust of the 'rdataset' to trust in any in the backing database.
+ * The local trust level of 'rdataset' is also set.
+ */
+
+void
+dns_rdataset_expire(dns_rdataset_t *rdataset);
+/*%<
+ * Mark the rdataset to be expired in the backing database.
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_RDATASET_H */
index fa837c1de4d769cc2e7648d5e90423be31929713..9063029acadd92aa0443dccc95cb595d244fe326 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: resolver.h,v 1.60.56.3 2009/01/29 22:40:35 jinmei Exp $ */
+/* $Id: resolver.h,v 1.60.56.4 2010/02/25 05:35:11 marka Exp $ */
 
 #ifndef DNS_RESOLVER_H
 #define DNS_RESOLVER_H 1
@@ -508,6 +508,48 @@ dns_resolver_setzeronosoattl(dns_resolver_t *resolver, isc_boolean_t state);
 unsigned int
 dns_resolver_getoptions(dns_resolver_t *resolver);
 
+void
+dns_resolver_addbadcache(dns_resolver_t *resolver, dns_name_t *name,
+                         dns_rdatatype_t type, isc_time_t *expire);
+/*%<
+ * Add a entry to the bad cache for <name,type> that will expire at 'expire'.
+ *
+ * Requires:
+ * \li resolver to be valid.
+ * \li name to be valid.
+ */
+
+isc_boolean_t
+dns_resolver_getbadcache(dns_resolver_t *resolver, dns_name_t *name,
+                         dns_rdatatype_t type, isc_time_t *now);
+/*%<
+ * Check to see if there is a unexpired entry in the bad cache for
+ * <name,type>.
+ *
+ * Requires:
+ * \li resolver to be valid.
+ * \li name to be valid.
+ */
+
+void
+dns_resolver_flushbadcache(dns_resolver_t *resolver, dns_name_t *name);
+/*%<
+ * Flush the bad cache of all entries at 'name' if 'name' is non NULL.
+ * Flush the entire bad cache if 'name' is NULL.
+ *
+ * Requires:
+ * \li resolver to be valid.
+ */
+
+void
+dns_resolver_printbadcache(dns_resolver_t *resolver, FILE *fp);
+/*%
+ * Print out the contents of the bad cache to 'fp'.
+ *
+ * Requires:
+ * \li resolver to be valid.
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_RESOLVER_H */
index ed29bcd5d3f6000787502c72748b903a4f9052c3..351eceb38ab387ec35925d3d152c98222cbd6802 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.h,v 1.116 2008/09/25 04:02:39 tbox Exp $ */
+/* $Id: result.h,v 1.116.48.1 2010/02/25 05:35:11 marka Exp $ */
 
 #ifndef DNS_RESULT_H
 #define DNS_RESULT_H 1
 #define DNS_R_MXISADDRESS              (ISC_RESULTCLASS_DNS + 102)
 #define DNS_R_DUPLICATE                        (ISC_RESULTCLASS_DNS + 103)
 #define DNS_R_INVALIDNSEC3             (ISC_RESULTCLASS_DNS + 104)
+#define DNS_R_NOTMASTER                        (ISC_RESULTCLASS_DNS + 105)
+#define DNS_R_BROKENCHAIN              (ISC_RESULTCLASS_DNS + 106)
 
-#define DNS_R_NRESULTS                 105     /*%< Number of results */
+#define DNS_R_NRESULTS                 107     /*%< Number of results */
 
 /*
  * DNS wire format rcodes.
index 2555214b14cf2c43369c18b4372bdb1879e3d634..5560122e74060fb7689c500157f5cef9bb8df770 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: validator.h,v 1.41.48.3 2009/01/18 23:25:17 marka Exp $ */
+/* $Id: validator.h,v 1.41.48.4 2010/02/25 05:35:11 marka Exp $ */
 
 #ifndef DNS_VALIDATOR_H
 #define DNS_VALIDATOR_H 1
@@ -159,6 +159,8 @@ struct dns_validator {
        isc_boolean_t                   mustbesecure;
        unsigned int                    dlvlabels;
        unsigned int                    depth;
+       unsigned int                    authcount;
+       unsigned int                    authfail;
 };
 
 /*%
index af0450b525dc594fa353b46a2083be7a6e0997bb..d5d5702b2589096c120efe57039f5998dd08ea95 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: ncache.c,v 1.43 2008/09/25 04:02:38 tbox Exp $ */
+/* $Id: ncache.c,v 1.43.48.1 2010/02/25 05:35:09 marka Exp $ */
 
 /*! \file */
 
@@ -519,6 +519,8 @@ static dns_rdatasetmethods_t rdataset_methods = {
        NULL,
        NULL,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index f841ebea5e943d21ae033259175007587fee3429..deea9db50808866c8ead9176fbef29d93f2b9820 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.270.12.16 2009/12/30 08:34:30 jinmei Exp $ */
+/* $Id: rbtdb.c,v 1.270.12.17 2010/02/25 05:35:09 marka Exp $ */
 
 /*! \file */
 
@@ -521,6 +521,8 @@ static void overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start,
 static isc_result_t resign_insert(dns_rbtdb_t *rbtdb, int idx,
                                  rdatasetheader_t *newheader);
 static void prune_tree(isc_task_t *task, isc_event_t *event);
+static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
+static void rdataset_expire(dns_rdataset_t *rdataset);
 
 static dns_rdatasetmethods_t rdataset_methods = {
        rdataset_disassociate,
@@ -535,7 +537,9 @@ static dns_rdatasetmethods_t rdataset_methods = {
        rdataset_getclosest,
        rdataset_getadditional,
        rdataset_setadditional,
-       rdataset_putadditional
+       rdataset_putadditional,
+       rdataset_settrust,
+       rdataset_expire
 };
 
 static void rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
@@ -7407,6 +7411,28 @@ rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
        return (ISC_R_SUCCESS);
 }
 
+static void
+rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
+       rdatasetheader_t *header = rdataset->private3;
+
+       header--;
+       header->trust = rdataset->trust = trust;
+}
+
+static void
+rdataset_expire(dns_rdataset_t *rdataset) {
+       dns_rbtdb_t *rbtdb = rdataset->private1;
+       dns_rbtnode_t *rbtnode = rdataset->private2;
+       rdatasetheader_t *header = rdataset->private3;
+
+       header--;
+       NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                 isc_rwlocktype_write);
+       expire_header(rbtdb, header, ISC_FALSE);
+       NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
+                 isc_rwlocktype_write);
+}
+
 /*
  * Rdataset Iterator Methods
  */
index d6f11ae64d3007d85593e2d55dcb005446c19de3..109bc8a812c604b8624eee6e05b11f52487a3fc9 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdatalist.c,v 1.36 2008/09/24 02:46:22 marka Exp $ */
+/* $Id: rdatalist.c,v 1.36.50.1 2010/02/25 05:35:10 marka Exp $ */
 
 /*! \file */
 
@@ -46,6 +46,8 @@ static dns_rdatasetmethods_t methods = {
        isc__rdatalist_getclosest,
        NULL,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index 6088a068ad2f3252644f16754ec2db9a1ff39569..1e9aed0da5b752d237b40e10d5612dc3ef6cc9bf 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdataset.c,v 1.82.50.2 2009/01/18 23:47:40 tbox Exp $ */
+/* $Id: rdataset.c,v 1.82.50.3 2010/02/25 05:35:10 marka Exp $ */
 
 /*! \file */
 
@@ -182,6 +182,8 @@ static dns_rdatasetmethods_t question_methods = {
        NULL,
        NULL,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
@@ -732,3 +734,22 @@ dns_rdataset_putadditional(dns_acache_t *acache,
        return (ISC_R_FAILURE);
 }
 
+void
+dns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
+       REQUIRE(DNS_RDATASET_VALID(rdataset));
+       REQUIRE(rdataset->methods != NULL);
+
+       if (rdataset->methods->settrust != NULL)
+               (rdataset->methods->settrust)(rdataset, trust);
+       else
+               rdataset->trust = trust;
+}
+
+void
+dns_rdataset_expire(dns_rdataset_t *rdataset) {
+       REQUIRE(DNS_RDATASET_VALID(rdataset));
+       REQUIRE(rdataset->methods != NULL);
+
+       if (rdataset->methods->expire != NULL)
+               (rdataset->methods->expire)(rdataset);
+}
index b22868d6f212669f5b3fe53de4f1efa9436c3c51..18fbee9cc17414e615d452a5db21142c64058446 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdataslab.c,v 1.48.50.2 2009/01/18 23:47:40 tbox Exp $ */
+/* $Id: rdataslab.c,v 1.48.50.3 2010/02/25 05:35:10 marka Exp $ */
 
 /*! \file */
 
@@ -436,6 +436,8 @@ static dns_rdatasetmethods_t rdataset_methods = {
        NULL,
        NULL,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index 02e96cda70994f123f2a32bd1a31f051897a2ca3..ad4a7dd3729eca67c51e1a4920715e781ae07d9d 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: resolver.c,v 1.384.14.20 2010/01/07 23:47:36 tbox Exp $ */
+/* $Id: resolver.c,v 1.384.14.21 2010/02/25 05:35:10 marka Exp $ */
 
 /*! \file */
 
@@ -334,6 +334,18 @@ typedef struct alternate {
        ISC_LINK(struct alternate)      link;
 } alternate_t;
 
+typedef struct dns_badcache dns_badcache_t;
+struct dns_badcache {
+       dns_badcache_t *        next;
+       dns_rdatatype_t         type;
+       isc_time_t              expire;
+       unsigned int            hashval;
+       dns_name_t              name;
+};
+#define DNS_BADCACHE_SIZE 1021
+#define DNS_BADCACHE_TTL(fctx) \
+       (((fctx)->res->lame_ttl > 30 ) ? (fctx)->res->lame_ttl : 30)
+
 struct dns_resolver {
        /* Unlocked. */
        unsigned int                    magic;
@@ -380,6 +392,13 @@ struct dns_resolver {
        isc_boolean_t                   priming;
        unsigned int                    spillat;        /* clients-per-query */
        unsigned int                    nextdisp;
+
+       /* Bad cache. */
+       dns_badcache_t  **              badcache;
+       unsigned int                    badcount;
+       unsigned int                    badhash;
+       unsigned int                    badsweep;
+
        /* Locked by primelock. */
        dns_fetch_t *                   primefetch;
        /* Locked by nlock. */
@@ -410,7 +429,8 @@ static void empty_bucket(dns_resolver_t *res);
 static isc_result_t resquery_send(resquery_t *query);
 static void resquery_response(isc_task_t *task, isc_event_t *event);
 static void resquery_connected(isc_task_t *task, isc_event_t *event);
-static void fctx_try(fetchctx_t *fctx, isc_boolean_t retrying);
+static void fctx_try(fetchctx_t *fctx, isc_boolean_t retrying,
+                    isc_boolean_t badcache);
 static isc_boolean_t fctx_destroy(fetchctx_t *fctx);
 static isc_result_t ncache_adderesult(dns_message_t *message,
                                      dns_db_t *cache, dns_dbnode_t *node,
@@ -1169,7 +1189,7 @@ process_sendevent(resquery_t *query, isc_event_t *event) {
                if (result != ISC_R_SUCCESS)
                        fctx_done(fctx, result, __LINE__);
                else
-                       fctx_try(fctx, ISC_TRUE);
+                       fctx_try(fctx, ISC_TRUE, ISC_FALSE);
        }
 }
 
@@ -2071,7 +2091,7 @@ resquery_connected(isc_task_t *task, isc_event_t *event) {
                if (result != ISC_R_SUCCESS)
                        fctx_done(fctx, result, __LINE__);
                else
-                       fctx_try(fctx, ISC_TRUE);
+                       fctx_try(fctx, ISC_TRUE, ISC_FALSE);
        }
 }
 
@@ -2133,7 +2153,7 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
        dns_adb_destroyfind(&find);
 
        if (want_try)
-               fctx_try(fctx, ISC_TRUE);
+               fctx_try(fctx, ISC_TRUE, ISC_FALSE);
        else if (want_done)
                fctx_done(fctx, ISC_R_FAILURE, __LINE__);
        else if (bucket_empty)
@@ -2545,7 +2565,7 @@ isstrictsubdomain(dns_name_t *name1, dns_name_t *name2) {
 }
 
 static isc_result_t
-fctx_getaddresses(fetchctx_t *fctx) {
+fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) {
        dns_rdata_t rdata = DNS_RDATA_INIT;
        isc_result_t result;
        dns_resolver_t *res;
@@ -2764,12 +2784,24 @@ fctx_getaddresses(fetchctx_t *fctx) {
                         */
                        result = DNS_R_WAIT;
                } else {
+                       isc_time_t expire;
+                       isc_interval_t i;
                        /*
                         * We've lost completely.  We don't know any
                         * addresses, and the ADB has told us it can't get
                         * them.
                         */
                        FCTXTRACE("no addresses");
+                       isc_interval_set(&i, DNS_BADCACHE_TTL(fctx), 0);
+                       result = isc_time_nowplusinterval(&expire, &i);
+                       if (badcache &&
+                           (fctx->type == dns_rdatatype_dnskey ||
+                            fctx->type == dns_rdatatype_dlv ||
+                            fctx->type == dns_rdatatype_ds) &&
+                            result == ISC_R_SUCCESS)
+                               dns_resolver_addbadcache(fctx->res,
+                                                        &fctx->name,
+                                                        fctx->type, &expire);
                        result = ISC_R_FAILURE;
                }
        } else {
@@ -2992,7 +3024,7 @@ fctx_nextaddress(fetchctx_t *fctx) {
 }
 
 static void
-fctx_try(fetchctx_t *fctx, isc_boolean_t retrying) {
+fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache) {
        isc_result_t result;
        dns_adbaddrinfo_t *addrinfo;
 
@@ -3010,7 +3042,7 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t retrying) {
                fctx_cleanupaltfinds(fctx);
                fctx_cleanupforwaddrs(fctx);
                fctx_cleanupaltaddrs(fctx);
-               result = fctx_getaddresses(fctx);
+               result = fctx_getaddresses(fctx, badcache);
                if (result == DNS_R_WAIT) {
                        /*
                         * Sleep waiting for addresses.
@@ -3175,7 +3207,7 @@ fctx_timeout(isc_task_t *task, isc_event_t *event) {
                        /*
                         * Keep trying.
                         */
-                       fctx_try(fctx, ISC_TRUE);
+                       fctx_try(fctx, ISC_TRUE, ISC_FALSE);
        }
 
        isc_event_free(&event);
@@ -3345,7 +3377,7 @@ fctx_start(isc_task_t *task, isc_event_t *event) {
                if (result != ISC_R_SUCCESS)
                        fctx_done(fctx, result, __LINE__);
                else
-                       fctx_try(fctx, ISC_FALSE);
+                       fctx_try(fctx, ISC_FALSE, ISC_FALSE);
        } else if (bucket_empty)
                empty_bucket(res);
 }
@@ -3923,6 +3955,8 @@ validated(isc_task_t *task, isc_event_t *event) {
 
        LOCK(&fctx->res->buckets[fctx->bucketnum].lock);
 
+       isc_stdtime_get(&now);
+
        /*
         * If chaining, we need to make sure that the right result code is
         * returned, and that the rdatasets are bound.
@@ -3969,35 +4003,80 @@ validated(isc_task_t *task, isc_event_t *event) {
                inc_stats(fctx->res, dns_resstatscounter_valfail);
                fctx->valfail++;
                fctx->vresult = vevent->result;
-               result = ISC_R_NOTFOUND;
-               if (vevent->rdataset != NULL)
-                       result = dns_db_findnode(fctx->cache, vevent->name,
-                                                ISC_TRUE, &node);
-               if (result == ISC_R_SUCCESS)
-                       (void)dns_db_deleterdataset(fctx->cache, node, NULL,
-                                                   vevent->type, 0);
-               if (result == ISC_R_SUCCESS && vevent->sigrdataset != NULL)
-                       (void)dns_db_deleterdataset(fctx->cache, node, NULL,
-                                                   dns_rdatatype_rrsig,
-                                                   vevent->type);
-               if (result == ISC_R_SUCCESS)
-                       dns_db_detachnode(fctx->cache, &node);
-               result = vevent->result;
+               if (fctx->vresult != DNS_R_BROKENCHAIN) {
+                       result = ISC_R_NOTFOUND;
+                       if (vevent->rdataset != NULL)
+                               result = dns_db_findnode(fctx->cache,
+                                                        vevent->name,
+                                                        ISC_TRUE, &node);
+                       if (result == ISC_R_SUCCESS)
+                               (void)dns_db_deleterdataset(fctx->cache, node,
+                                                            NULL,
+                                                           vevent->type, 0);
+                       if (result == ISC_R_SUCCESS &&
+                            vevent->sigrdataset != NULL)
+                               (void)dns_db_deleterdataset(fctx->cache, node,
+                                                           NULL,
+                                                           dns_rdatatype_rrsig,
+                                                           vevent->type);
+                       if (result == ISC_R_SUCCESS)
+                               dns_db_detachnode(fctx->cache, &node);
+               }
+               if (fctx->vresult == DNS_R_BROKENCHAIN && !negative) {
+                       /*
+                        * Cache the data as pending for later validation.
+                        */
+                       result = ISC_R_NOTFOUND;
+                       if (vevent->rdataset != NULL)
+                               result = dns_db_findnode(fctx->cache,
+                                                        vevent->name,
+                                                        ISC_TRUE, &node);
+                       if (result == ISC_R_SUCCESS) {
+                               (void)dns_db_addrdataset(fctx->cache, node,
+                                                        NULL, now,
+                                                        vevent->rdataset, 0,
+                                                        NULL);
+                       }
+                       if (result == ISC_R_SUCCESS &&
+                           vevent->sigrdataset != NULL)
+                               (void)dns_db_addrdataset(fctx->cache, node,
+                                                        NULL, now,
+                                                        vevent->sigrdataset,
+                                                        0, NULL);
+                       if (result == ISC_R_SUCCESS)
+                               dns_db_detachnode(fctx->cache, &node);
+               }
+               result = fctx->vresult;
                add_bad(fctx, addrinfo, result, badns_validation);
                isc_event_free(&event);
                UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock);
                INSIST(fctx->validator == NULL);
                fctx->validator = ISC_LIST_HEAD(fctx->validators);
-               if (fctx->validator != NULL) {
+               if (fctx->validator != NULL)
                        dns_validator_send(fctx->validator);
-               else if (sentresponse)
+               else if (sentresponse)
                        fctx_done(fctx, result, __LINE__); /* Locks bucket. */
-               else
-                       fctx_try(fctx, ISC_TRUE);       /* Locks bucket. */
+               else if (result == DNS_R_BROKENCHAIN) {
+                       isc_result_t tresult;
+                       isc_time_t expire;
+                       isc_interval_t i;
+
+                       isc_interval_set(&i, DNS_BADCACHE_TTL(fctx), 0);
+                       tresult = isc_time_nowplusinterval(&expire, &i);
+                       if (negative &&
+                           (fctx->type == dns_rdatatype_dnskey ||
+                            fctx->type == dns_rdatatype_dlv ||
+                            fctx->type == dns_rdatatype_ds) &&
+                            tresult == ISC_R_SUCCESS)
+                               dns_resolver_addbadcache(fctx->res,
+                                                        &fctx->name,
+                                                        fctx->type, &expire);
+                       fctx_done(fctx, result, __LINE__); /* Locks bucket. */
+               } else
+                       fctx_try(fctx, ISC_TRUE, ISC_TRUE); /* Locks bucket. */
                return;
        }
 
-       isc_stdtime_get(&now);
 
        if (negative) {
                dns_rdatatype_t covers;
@@ -5790,7 +5869,7 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) {
                /*
                 * Try again.
                 */
-               fctx_try(fctx, ISC_TRUE);
+               fctx_try(fctx, ISC_TRUE, ISC_FALSE);
        } else {
                unsigned int n;
                dns_rdataset_t *nsrdataset = NULL;
@@ -6629,7 +6708,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
                /*
                 * Try again.
                 */
-               fctx_try(fctx, !get_nameservers);
+               fctx_try(fctx, !get_nameservers, ISC_FALSE);
        } else if (resend) {
                /*
                 * Resend (probably with changed options).
@@ -6691,6 +6770,27 @@ resquery_response(isc_task_t *task, isc_event_t *event) {
 /***
  *** Resolver Methods
  ***/
+static void
+destroy_badcache(dns_resolver_t *res) {
+       dns_badcache_t *bad, *next;
+       unsigned int i;
+
+       if (res->badcache != NULL) {
+               for (i = 0; i < res->badhash; i++)
+                       for (bad = res->badcache[i]; bad != NULL;
+                            bad = next) {
+                               next = bad->next;
+                               isc_mem_put(res->mctx, bad, sizeof(*bad) +
+                                           bad->name.length);
+                               res->badcount--;
+                       }
+               isc_mem_put(res->mctx, res->badcache,
+                           sizeof(*res->badcache) * res->badhash);
+               res->badcache = NULL;
+               res->badhash = 0;
+               INSIST(res->badcount == 0);
+       }
+}
 
 static void
 destroy(dns_resolver_t *res) {
@@ -6728,6 +6828,7 @@ destroy(dns_resolver_t *res) {
                isc_mem_put(res->mctx, a, sizeof(*a));
        }
        dns_resolver_reset_algorithms(res);
+       destroy_badcache(res);
        dns_resolver_resetmustbesecure(res);
 #if USE_ALGLOCK
        isc_rwlock_destroy(&res->alglock);
@@ -6851,6 +6952,10 @@ dns_resolver_create(dns_view_t *view,
        ISC_LIST_INIT(res->alternates);
        res->udpsize = RECV_BUFFER_SIZE;
        res->algorithms = NULL;
+       res->badcache = NULL;
+       res->badcount = 0;
+       res->badhash = 0;
+       res->badsweep = 0;
        res->mustbesecure = NULL;
        res->spillatmin = res->spillat = 10;
        res->spillatmax = 100;
@@ -7692,6 +7797,256 @@ dns_resolver_getudpsize(dns_resolver_t *resolver) {
        return (resolver->udpsize);
 }
 
+void
+dns_resolver_flushbadcache(dns_resolver_t *resolver, dns_name_t *name) {
+       unsigned int i;
+       dns_badcache_t *bad, *prev, *next;
+
+       REQUIRE(VALID_RESOLVER(resolver));
+
+       LOCK(&resolver->lock);
+       if (resolver->badcache == NULL)
+               goto unlock;
+
+       if (name != NULL) {
+               isc_time_t now;
+               isc_result_t result;
+               result = isc_time_now(&now);
+               if (result != ISC_R_SUCCESS)
+                       isc_time_settoepoch(&now);
+               i = dns_name_hash(name, ISC_FALSE) % resolver->badhash;
+               prev = NULL;
+               for (bad = resolver->badcache[i]; bad != NULL; bad = next) {
+                       int n;
+                       next = bad->next;
+                       n = isc_time_compare(&bad->expire, &now);
+                       if (n < 0 || dns_name_equal(name, &bad->name)) {
+                               if (prev == NULL)
+                                       resolver->badcache[i] = bad->next;
+                               else
+                                       prev->next = bad->next;
+                               isc_mem_put(resolver->mctx, bad, sizeof(*bad) +
+                                           bad->name.length);
+                               resolver->badcount--;
+                       } else
+                               prev = bad;
+               }
+       } else 
+               destroy_badcache(resolver);
+
+ unlock:
+       UNLOCK(&resolver->lock);
+
+}
+
+static void
+resizehash(dns_resolver_t *resolver, isc_time_t *now, isc_boolean_t grow) {
+       unsigned int newsize;
+       dns_badcache_t **new, *bad, *next;
+       unsigned int i;
+
+       if (grow)
+               newsize = resolver->badhash * 2 + 1;
+       else
+               newsize = (resolver->badhash - 1) / 2;
+
+       new = isc_mem_get(resolver->mctx,
+                         sizeof(*resolver->badcache) * newsize);
+       if (new == NULL)
+               return;
+       memset(new, 0, sizeof(*resolver->badcache) * newsize);
+       for (i = 0; i < resolver->badhash; i++) {
+               for (bad = resolver->badcache[i]; bad != NULL; bad = next) {
+                       next = bad->next;
+                       if (isc_time_compare(&bad->expire, now) < 0) {
+                               isc_mem_put(resolver->mctx, bad, sizeof(*bad) +
+                                           bad->name.length);
+                               resolver->badcount--;
+                       } else {
+                               bad->next = new[bad->hashval % newsize];
+                               new[bad->hashval % newsize] = bad;
+                       }
+               }
+       }
+       isc_mem_put(resolver->mctx, resolver->badcache,
+                   sizeof(*resolver->badcache) * resolver->badhash);
+       resolver->badhash = newsize;
+       resolver->badcache = new;
+}
+
+void
+dns_resolver_addbadcache(dns_resolver_t *resolver, dns_name_t *name,
+                        dns_rdatatype_t type, isc_time_t *expire)
+{
+       isc_time_t now;
+       isc_result_t result = ISC_R_SUCCESS;
+       unsigned int i, hashval;
+       dns_badcache_t *bad, *prev, *next;
+
+       REQUIRE(VALID_RESOLVER(resolver));
+
+       LOCK(&resolver->lock);
+       if (resolver->badcache == NULL) {
+               resolver->badcache = isc_mem_get(resolver->mctx,
+                                                sizeof(*resolver->badcache) *
+                                                DNS_BADCACHE_SIZE);
+               if (resolver->badcache == NULL) {
+                       result = ISC_R_NOMEMORY;
+                       goto cleanup;
+               }
+               resolver->badhash = DNS_BADCACHE_SIZE;
+               memset(resolver->badcache, 0, sizeof(*resolver->badcache) *
+                      resolver->badhash);
+       }
+
+       result = isc_time_now(&now);
+       if (result != ISC_R_SUCCESS)
+               isc_time_settoepoch(&now);
+       hashval = dns_name_hash(name, ISC_FALSE);
+       i = hashval % resolver->badhash;
+       prev = NULL;
+       for (bad = resolver->badcache[i]; bad != NULL; bad = next) {
+               next = bad->next;
+               if (bad->type == type && dns_name_equal(name, &bad->name))
+                       break;
+               if (isc_time_compare(&bad->expire, &now) < 0) {
+                       if (prev == NULL)
+                               resolver->badcache[i] = bad->next;
+                       else
+                               prev->next = bad->next;
+                       isc_mem_put(resolver->mctx, bad, sizeof(*bad) +
+                                   bad->name.length);
+                       resolver->badcount--;
+               } else
+                       prev = bad;
+       }
+       if (bad == NULL) {
+               isc_buffer_t buffer;
+               bad = isc_mem_get(resolver->mctx, sizeof(*bad) + name->length);
+               if (bad == NULL) {
+                       result = ISC_R_NOMEMORY;
+                       goto cleanup;
+               }
+               bad->type = type;
+               bad->hashval = hashval;
+               isc_buffer_init(&buffer, bad + 1, name->length);
+               dns_name_init(&bad->name, NULL);
+               dns_name_copy(name, &bad->name, &buffer);
+               bad->next = resolver->badcache[i];
+               resolver->badcache[i] = bad;
+               resolver->badcount++;
+               if (resolver->badcount > resolver->badhash * 8)
+                       resizehash(resolver, &now, ISC_TRUE);
+               if (resolver->badcount < resolver->badhash * 2 &&
+                   resolver->badhash > DNS_BADCACHE_SIZE)
+                       resizehash(resolver, &now, ISC_FALSE);
+       }
+       bad->expire = *expire;
+ cleanup:
+       UNLOCK(&resolver->lock);
+}
+
+isc_boolean_t
+dns_resolver_getbadcache(dns_resolver_t *resolver, dns_name_t *name,
+                        dns_rdatatype_t type, isc_time_t *now)
+{
+       dns_badcache_t *bad, *prev, *next;
+       isc_boolean_t answer = ISC_FALSE;
+       unsigned int i;
+
+       REQUIRE(VALID_RESOLVER(resolver));
+
+       LOCK(&resolver->lock);
+       if (resolver->badcache == NULL)
+               goto unlock;
+
+       i = dns_name_hash(name, ISC_FALSE) % resolver->badhash;
+       prev = NULL;
+       for (bad = resolver->badcache[i]; bad != NULL; bad = next) {
+               next = bad->next;
+               /*
+                * Search the hash list. Clean out expired records as we go.
+                */
+               if (isc_time_compare(&bad->expire, now) < 0) {
+                       if (prev != NULL)
+                               prev->next = bad->next;
+                       else
+                               resolver->badcache[i] = bad->next;
+                       isc_mem_put(resolver->mctx, bad, sizeof(*bad) +
+                                   bad->name.length);
+                       resolver->badcount--;
+                       continue;
+               }
+               if (bad->type == type && dns_name_equal(name, &bad->name)) {
+                       answer = ISC_TRUE;
+                       break;
+               }
+               prev = bad;
+       }
+
+       /*
+        * Slow sweep to clean out stale records.
+        */
+       i = resolver->badsweep++ % resolver->badhash;
+       bad = resolver->badcache[i];
+       if (bad != NULL && isc_time_compare(&bad->expire, now) < 0) {
+               resolver->badcache[i] = bad->next;
+               isc_mem_put(resolver->mctx, bad, sizeof(*bad) +
+                           bad->name.length);
+               resolver->badcount--;
+       }
+
+ unlock:
+       UNLOCK(&resolver->lock);
+       return (answer);
+}
+
+void
+dns_resolver_printbadcache(dns_resolver_t *resolver, FILE *fp) {
+       char namebuf[DNS_NAME_FORMATSIZE];
+       char typebuf[DNS_RDATATYPE_FORMATSIZE];
+       dns_badcache_t *bad, *next, *prev;
+       isc_time_t now;
+       unsigned int i;
+       isc_uint64_t t;
+
+       LOCK(&resolver->lock);
+       fprintf(fp, ";\n; Bad cache\n;\n");
+
+       if (resolver->badcache == NULL)
+               goto unlock;
+
+       TIME_NOW(&now);
+       for (i = 0; i < resolver->badhash; i++) {
+               prev = NULL;
+               for (bad = resolver->badcache[i]; bad != NULL; bad = next) {
+                       next = bad->next;
+                       if (isc_time_compare(&bad->expire, &now) < 0) {
+                               if (prev != NULL)
+                                       prev->next = bad->next;
+                               else
+                                       resolver->badcache[i] = bad->next;
+                               isc_mem_put(resolver->mctx, bad, sizeof(*bad) +
+                                           bad->name.length);
+                               resolver->badcount--;
+                               continue;
+                       }
+                       prev = bad;
+                       dns_name_format(&bad->name, namebuf, sizeof(namebuf));
+                       dns_rdatatype_format(bad->type, typebuf,
+                                            sizeof(typebuf));
+                       t = isc_time_microdiff(&bad->expire, &now);
+                       t /= 1000;
+                       fprintf(fp, "; %s/%s [ttl "
+                               "%" ISC_PLATFORM_QUADFORMAT "u]\n",
+                               namebuf, typebuf, t);
+               }
+       }
+
+ unlock:
+       UNLOCK(&resolver->lock);
+}
+
 static void
 free_algorithm(void *node, void *arg) {
        unsigned char *algorithms = node;
index 54c70e0e9088f673d8e7582278b649988808682d..95b9a4c1ebdb2d8941b35c1210cef25a78bfc116 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.c,v 1.125 2008/09/25 04:02:38 tbox Exp $ */
+/* $Id: result.c,v 1.125.48.1 2010/02/25 05:35:11 marka Exp $ */
 
 /*! \file */
 
@@ -157,6 +157,9 @@ static const char *text[DNS_R_NRESULTS] = {
        "MX is an address",                    /*%< 102 DNS_R_MXISADDRESS */
        "duplicate query",                     /*%< 103 DNS_R_DUPLICATE */
        "invalid NSEC3 owner name (wildcard)", /*%< 104 DNS_R_INVALIDNSEC3 */
+
+       "not master",                          /*%< 105 DNS_R_NOTMASTER */
+       "broken trust chain",                  /*%< 106 DNS_R_BROKENCHAIN */
 };
 
 static const char *rcode_text[DNS_R_NRCODERESULTS] = {
index ab9ff1967f687d06394c51da8b20ce1aaeba1dc4..45fb56ac93f72b6a8d8b485704caf53555dfedde 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: sdb.c,v 1.66.48.3 2009/06/26 06:25:44 marka Exp $ */
+/* $Id: sdb.c,v 1.66.48.4 2010/02/25 05:35:11 marka Exp $ */
 
 /*! \file */
 
@@ -1387,6 +1387,8 @@ static dns_rdatasetmethods_t methods = {
        NULL,
        NULL,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index 5e5f7e3d7a25f2ceecfb8b15ff05d1091b060c60..de1c3d1feef6554035f1c4bacb99e8ca51b2e9c2 100644 (file)
@@ -50,7 +50,7 @@
  * USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: sdlz.c,v 1.18.50.3 2009/06/26 06:25:44 marka Exp $ */
+/* $Id: sdlz.c,v 1.18.50.4 2010/02/25 05:35:11 marka Exp $ */
 
 /*! \file */
 
@@ -1211,6 +1211,8 @@ static dns_rdatasetmethods_t rdataset_methods = {
        NULL,
        NULL,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index 1e55a34055b3394f378aacc0cee64df1c08d7219..323c676a6174a34d887e0c009e956123c2710e64 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: validator.c,v 1.164.12.11 2009/12/30 06:44:44 each Exp $ */
+/* $Id: validator.c,v 1.164.12.12 2010/02/25 05:35:11 marka Exp $ */
 
 #include <config.h>
 
@@ -177,9 +177,16 @@ static inline void
 markanswer(dns_validator_t *val) {
        validator_log(val, ISC_LOG_DEBUG(3), "marking as answer");
        if (val->event->rdataset != NULL)
-               val->event->rdataset->trust = dns_trust_answer;
+               dns_rdataset_settrust(val->event->rdataset, dns_trust_answer);
        if (val->event->sigrdataset != NULL)
-               val->event->sigrdataset->trust = dns_trust_answer;
+               dns_rdataset_settrust(val->event->sigrdataset,
+                                     dns_trust_answer);
+}
+
+static inline void
+marksecure(dns_validatorevent_t *event) {
+       dns_rdataset_settrust(event->rdataset, dns_trust_secure);
+       dns_rdataset_settrust(event->sigrdataset, dns_trust_secure);
 }
 
 static void
@@ -425,7 +432,7 @@ fetch_callback_validator(isc_task_t *task, isc_event_t *event) {
                if (eresult == ISC_R_CANCELED)
                        validator_done(val, eresult);
                else
-                       validator_done(val, DNS_R_NOVALIDKEY);
+                       validator_done(val, DNS_R_BROKENCHAIN);
        }
        want_destroy = exit_check(val);
        UNLOCK(&val->lock);
@@ -495,7 +502,7 @@ dsfetched(isc_task_t *task, isc_event_t *event) {
                if (eresult == ISC_R_CANCELED)
                        validator_done(val, eresult);
                else
-                       validator_done(val, DNS_R_NOVALIDDS);
+                       validator_done(val, DNS_R_BROKENCHAIN);
        }
        want_destroy = exit_check(val);
        UNLOCK(&val->lock);
@@ -635,10 +642,16 @@ keyvalidated(isc_task_t *task, isc_event_t *event) {
                if (result != DNS_R_WAIT)
                        validator_done(val, result);
        } else {
+               if (eresult != DNS_R_BROKENCHAIN) {
+                       if (dns_rdataset_isassociated(&val->frdataset))
+                               dns_rdataset_expire(&val->frdataset);
+                       if (dns_rdataset_isassociated(&val->fsigrdataset))
+                               dns_rdataset_expire(&val->fsigrdataset);
+               }
                validator_log(val, ISC_LOG_DEBUG(3),
                              "keyvalidated: got %s",
                              isc_result_totext(eresult));
-               validator_done(val, eresult);
+               validator_done(val, DNS_R_BROKENCHAIN);
        }
        want_destroy = exit_check(val);
        UNLOCK(&val->lock);
@@ -685,10 +698,16 @@ dsvalidated(isc_task_t *task, isc_event_t *event) {
                if (result != DNS_R_WAIT)
                        validator_done(val, result);
        } else {
+               if (eresult != DNS_R_BROKENCHAIN) {
+                       if (dns_rdataset_isassociated(&val->frdataset))
+                               dns_rdataset_expire(&val->frdataset);
+                       if (dns_rdataset_isassociated(&val->fsigrdataset))
+                               dns_rdataset_expire(&val->fsigrdataset);
+               }
                validator_log(val, ISC_LOG_DEBUG(3),
                              "dsvalidated: got %s",
                              isc_result_totext(eresult));
-               validator_done(val, eresult);
+               validator_done(val, DNS_R_BROKENCHAIN);
        }
        want_destroy = exit_check(val);
        UNLOCK(&val->lock);
@@ -1199,6 +1218,8 @@ authvalidated(isc_task_t *task, isc_event_t *event) {
                validator_log(val, ISC_LOG_DEBUG(3),
                              "authvalidated: got %s",
                              isc_result_totext(result));
+               if (result == DNS_R_BROKENCHAIN)
+                       val->authfail++;
                if (result == ISC_R_CANCELED)
                        validator_done(val, result);
                else {
@@ -1271,6 +1292,7 @@ authvalidated(isc_task_t *task, isc_event_t *event) {
  * \li DNS_R_NCACHENXRRSET
  * \li DNS_R_NXRRSET
  * \li DNS_R_NXDOMAIN
+ * \li DNS_R_BROKENCHAIN
  */
 static inline isc_result_t
 view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
@@ -1280,9 +1302,12 @@ view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
        dns_rdata_t rdata = DNS_RDATA_INIT;
        isc_result_t result;
        unsigned int options;
+       isc_time_t now;
        char buf1[DNS_NAME_FORMATSIZE];
        char buf2[DNS_NAME_FORMATSIZE];
        char buf3[DNS_NAME_FORMATSIZE];
+       char namebuf[DNS_NAME_FORMATSIZE];
+       char typebuf[DNS_RDATATYPE_FORMATSIZE];
 
        if (dns_rdataset_isassociated(&val->frdataset))
                dns_rdataset_disassociate(&val->frdataset);
@@ -1292,6 +1317,16 @@ view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
        if (val->view->zonetable == NULL)
                return (ISC_R_CANCELED);
 
+       if (isc_time_now(&now) == ISC_R_SUCCESS &&
+           dns_resolver_getbadcache(val->view->resolver, name, type, &now)) {
+
+               dns_name_format(name, namebuf, sizeof(namebuf));
+               dns_rdatatype_format(type, typebuf, sizeof(typebuf));
+               validator_log(val, ISC_LOG_INFO, "bad cache hit (%s/%s)",
+                             namebuf, typebuf);
+               return (DNS_R_BROKENCHAIN);
+       }
+
        options = DNS_DBFIND_PENDINGOK;
        if (type == dns_rdatatype_dlv)
                options |= DNS_DBFIND_COVERINGNSEC;
@@ -1300,6 +1335,7 @@ view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
        result = dns_view_find(val->view, name, type, 0, options,
                               ISC_FALSE, NULL, NULL, foundname,
                               &val->frdataset, &val->fsigrdataset);
+
        if (result == DNS_R_NXDOMAIN) {
                if (dns_rdataset_isassociated(&val->frdataset))
                        dns_rdataset_disassociate(&val->frdataset);
@@ -1656,7 +1692,8 @@ get_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo) {
                /*
                 * We don't know anything about this key.
                 */
-               result = create_fetch(val, &siginfo->signer, dns_rdatatype_dnskey,
+               result = create_fetch(val, &siginfo->signer,
+                                     dns_rdatatype_dnskey,
                                      fetch_callback_validator, "get_key");
                if (result != ISC_R_SUCCESS)
                        return (result);
@@ -1671,7 +1708,8 @@ get_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo) {
                 * This key doesn't exist.
                 */
                result = DNS_R_CONTINUE;
-       }
+       } else if (result == DNS_R_BROKENCHAIN)
+               return (result);
 
        if (dns_rdataset_isassociated(&val->frdataset) &&
            val->keyset != &val->frdataset)
@@ -1919,8 +1957,7 @@ validate(dns_validator_t *val, isc_boolean_t resume) {
                                      "looking for noqname proof");
                        return (nsecvalidate(val, ISC_FALSE));
                } else if (result == ISC_R_SUCCESS) {
-                       event->rdataset->trust = dns_trust_secure;
-                       event->sigrdataset->trust = dns_trust_secure;
+                       marksecure(event);
                        validator_log(val, ISC_LOG_DEBUG(3),
                                      "marking as secure");
                        return (result);
@@ -2096,8 +2133,7 @@ dlv_validatezonekey(dns_validator_t *val) {
                              "no RRSIG matching DLV key");
        }
        if (result == ISC_R_SUCCESS) {
-               val->event->rdataset->trust = dns_trust_secure;
-               val->event->sigrdataset->trust = dns_trust_secure;
+               marksecure(val->event);
                validator_log(val, ISC_LOG_DEBUG(3), "marking as secure");
                return (result);
        } else if (result == ISC_R_NOMORE && !supported_algorithm) {
@@ -2198,8 +2234,7 @@ validatezonekey(dns_validator_t *val) {
                                keynode = nextnode;
                        }
                        if (result == ISC_R_SUCCESS) {
-                               event->rdataset->trust = dns_trust_secure;
-                               event->sigrdataset->trust = dns_trust_secure;
+                               marksecure(event);
                                validator_log(val, ISC_LOG_DEBUG(3),
                                              "signed by trusted key; "
                                              "marking as secure");
@@ -2226,11 +2261,14 @@ validatezonekey(dns_validator_t *val) {
                         */
                        dns_name_format(val->event->name, namebuf,
                                        sizeof(namebuf));
-                       validator_log(val, ISC_LOG_DEBUG(2),
+                       validator_log(val, ISC_LOG_NOTICE,
                                      "unable to find a DNSKEY which verifies "
                                      "the DNSKEY RRset and also matches one "
                                      "of specified trusted-keys for '%s'",
                                      namebuf);
+                       validator_log(val, ISC_LOG_NOTICE,
+                                     "please check the 'trusted-keys' for "
+                                     "'%s' in named.conf.", namebuf);
                        return (DNS_R_NOVALIDKEY);
                }
 
@@ -2291,7 +2329,8 @@ validatezonekey(dns_validator_t *val) {
                                dns_rdataset_disassociate(&val->fsigrdataset);
                        validator_log(val, ISC_LOG_DEBUG(2), "no DS record");
                        return (DNS_R_NOVALIDSIG);
-               }
+               } else if (result == DNS_R_BROKENCHAIN)
+                       return (result);
        }
 
        /*
@@ -2440,8 +2479,7 @@ validatezonekey(dns_validator_t *val) {
                              "no RRSIG matching DS key");
        }
        if (result == ISC_R_SUCCESS) {
-               event->rdataset->trust = dns_trust_secure;
-               event->sigrdataset->trust = dns_trust_secure;
+               marksecure(event);
                validator_log(val, ISC_LOG_DEBUG(3), "marking as secure");
                return (result);
        } else if (result == ISC_R_NOMORE && !supported_algorithm) {
@@ -2844,6 +2882,7 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) {
                                                  "nsecvalidate");
                        if (result != ISC_R_SUCCESS)
                                return (result);
+                       val->authcount++;
                        return (DNS_R_WAIT);
 
                }
@@ -2868,8 +2907,7 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) {
                                      "noqname proof found");
                        validator_log(val, ISC_LOG_DEBUG(3),
                                      "marking as secure");
-                       val->event->rdataset->trust = dns_trust_secure;
-                       val->event->sigrdataset->trust = dns_trust_secure;
+                       marksecure(val->event);
                        return (ISC_R_SUCCESS);
                } else if ((val->attributes & VALATTR_FOUNDOPTOUT) != 0 &&
                           dns_name_countlabels(dns_fixedname_name(&val->wild))
@@ -2923,6 +2961,8 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) {
        }
                findnsec3proofs(val);
 
+       if (val->authcount == val->authfail)
+               return (DNS_R_BROKENCHAIN);
        validator_log(val, ISC_LOG_DEBUG(3),
                      "nonexistence proof(s) not found");
        val->attributes |= VALATTR_INSECURITY;
@@ -2954,6 +2994,58 @@ check_ds(dns_validator_t *val, dns_name_t *name, dns_rdataset_t *rdataset) {
        return (ISC_FALSE);
 }
 
+static void
+dlvvalidated(isc_task_t *task, isc_event_t *event) {
+       dns_validatorevent_t *devent;
+       dns_validator_t *val;
+       isc_result_t eresult;
+       isc_boolean_t want_destroy;
+
+       UNUSED(task);
+       INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE);
+
+       devent = (dns_validatorevent_t *)event;
+       val = devent->ev_arg;
+       eresult = devent->result;
+
+       isc_event_free(&event);
+       dns_validator_destroy(&val->subvalidator);
+
+       INSIST(val->event != NULL);
+
+       validator_log(val, ISC_LOG_DEBUG(3), "in dlvvalidated");
+       LOCK(&val->lock);
+       if (CANCELED(val)) {
+               validator_done(val, ISC_R_CANCELED);
+       } else if (eresult == ISC_R_SUCCESS) {
+               validator_log(val, ISC_LOG_DEBUG(3),
+                             "dlvset with trust %d", val->frdataset.trust);
+               dns_rdataset_clone(&val->frdataset, &val->dlv);
+               val->havedlvsep = ISC_TRUE;
+               if (dlv_algorithm_supported(val))
+                       dlv_validator_start(val);
+               else {
+                       markanswer(val);
+                       validator_done(val, ISC_R_SUCCESS);
+               }
+       } else {
+               if (eresult != DNS_R_BROKENCHAIN) {
+                       if (dns_rdataset_isassociated(&val->frdataset))
+                               dns_rdataset_expire(&val->frdataset);
+                       if (dns_rdataset_isassociated(&val->fsigrdataset))
+                               dns_rdataset_expire(&val->fsigrdataset);
+               }
+               validator_log(val, ISC_LOG_DEBUG(3),
+                             "dlvvalidated: got %s",
+                             isc_result_totext(eresult));
+               validator_done(val, DNS_R_BROKENCHAIN);
+       }
+       want_destroy = exit_check(val);
+       UNLOCK(&val->lock);
+       if (want_destroy)
+               destroy(val);
+}
+
 /*%
  * Callback from fetching a DLV record.
  *
@@ -3173,6 +3265,24 @@ finddlvsep(dns_validator_t *val, isc_boolean_t resume) {
                              namebuf);
                result = view_find(val, dlvname, dns_rdatatype_dlv);
                if (result == ISC_R_SUCCESS) {
+                        if (DNS_TRUST_PENDING(val->frdataset.trust) &&
+                            dns_rdataset_isassociated(&val->fsigrdataset))
+                        {
+                                dns_fixedname_init(&val->fname);
+                                dns_name_copy(dlvname,
+                                              dns_fixedname_name(&val->fname),
+                                              NULL);
+                                result = create_validator(val,
+                                                dns_fixedname_name(&val->fname),
+                                                          dns_rdatatype_dlv,
+                                                          &val->frdataset,
+                                                          &val->fsigrdataset,
+                                                          dlvvalidated,
+                                                          "finddlvsep");
+                                if (result != ISC_R_SUCCESS)
+                                        return (result);
+                                return (DNS_R_WAIT);
+                        }
                        if (val->frdataset.trust < dns_trust_secure)
                                return (DNS_R_NOVALIDSIG);
                        val->havedlvsep = ISC_TRUE;
@@ -3223,6 +3333,7 @@ finddlvsep(dns_validator_t *val, isc_boolean_t resume) {
  * \li DNS_R_NOVALIDSIG
  * \li DNS_R_NOVALIDNSEC
  * \li DNS_R_NOTINSECURE
+ * \li DNS_R_BROKENCHAIN
  */
 static isc_result_t
 proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume)
@@ -3465,7 +3576,8 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume)
                        if (result != ISC_R_SUCCESS)
                                goto out;
                        return (DNS_R_WAIT);
-               }
+               } else if (result == DNS_R_BROKENCHAIN)
+                       return (result);
        }
 
 /*
@@ -3682,6 +3794,8 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
        val->seensig = ISC_FALSE;
        val->havedlvsep = ISC_FALSE;
        val->depth = 0;
+       val->authcount = 0;
+       val->authfail = 0;
        val->mustbesecure = dns_resolver_getmustbesecure(view->resolver, name);
        dns_rdataset_init(&val->frdataset);
        dns_rdataset_init(&val->fsigrdataset);
index 961268e22c1cbf9eb91b429a0692f43ec22e5e51..c6069fc92e8bdf7dba8c344b043b1c0351da7e6d 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: view.c,v 1.150.84.3 2009/11/12 23:39:23 marka Exp $ */
+/* $Id: view.c,v 1.150.84.4 2010/02/25 05:35:11 marka Exp $ */
 
 /*! \file */
 
@@ -1271,10 +1271,11 @@ dns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
 
        (void)fprintf(fp, ";\n; Cache dump of view '%s'\n;\n", view->name);
        result = dns_master_dumptostream(view->mctx, view->cachedb, NULL,
-                                         &dns_master_style_cache, fp);
+                                        &dns_master_style_cache, fp);
        if (result != ISC_R_SUCCESS)
                return (result);
        dns_adb_dump(view->adb, fp);
+       dns_resolver_printbadcache(view->resolver, fp);
        return (ISC_R_SUCCESS);
 }
 
@@ -1295,6 +1296,8 @@ dns_view_flushcache(dns_view_t *view) {
        dns_cache_attachdb(view->cache, &view->cachedb);
        if (view->acache != NULL)
                dns_acache_setdb(view->acache, view->cachedb);
+       if (view->resolver != NULL)
+               dns_resolver_flushbadcache(view->resolver, NULL);
 
        dns_adb_flush(view->adb);
        return (ISC_R_SUCCESS);
@@ -1309,6 +1312,8 @@ dns_view_flushname(dns_view_t *view, dns_name_t *name) {
                dns_adb_flushname(view->adb, name);
        if (view->cache == NULL)
                return (ISC_R_SUCCESS);
+       if (view->resolver != NULL)
+               dns_resolver_flushbadcache(view->resolver, name);
        return (dns_cache_flushname(view->cache, name));
 }