]> 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 04:39:13 +0000 (04:39 +0000)
committerMark Andrews <marka@isc.org>
Thu, 25 Feb 2010 04:39:13 +0000 (04:39 +0000)
19 files changed:
CHANGES
bin/named/server.c
doc/arm/Bv9ARM-book.xml
lib/dns/ecdb.c
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 27ad013a13ff2e15f4a0bdee5b5328fc2504ac90..d9009196e18badfd5d0359bd48f3e13757bf183e 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 0b849ad6a59ac4dd8786931f2402b7bb9f5883fc..913ebe2dcb4a0b6f1b96986f86db9d2d9af5bbe9 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: server.c,v 1.562 2010/01/13 23:48:59 tbox Exp $ */
+/* $Id: server.c,v 1.563 2010/02/25 04:39:12 marka Exp $ */
 
 /*! \file */
 
@@ -5528,6 +5528,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 5dae00b0e0b14226d7e27db5241cc7eceb447fac..b135cd7a668a0a91d5495cd12908f4554697f8f7 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- File: $Id: Bv9ARM-book.xml,v 1.455 2010/02/03 01:31:48 each Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.456 2010/02/25 04:39:12 marka Exp $ -->
 <book xmlns:xi="http://www.w3.org/2001/XInclude">
   <title>BIND 9 Administrator Reference Manual</title>
 
@@ -8176,6 +8176,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 450b9d872bd32005fd24c7c3bfad69e63be49ae6..705930767481b561839954048183cf133b5eb257 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: ecdb.c,v 1.4 2009/11/06 04:19:28 marka Exp $ */
+/* $Id: ecdb.c,v 1.5 2010/02/25 04:39:13 marka Exp $ */
 
 #include "config.h"
 
@@ -99,6 +99,7 @@ static isc_result_t rdataset_next(dns_rdataset_t *rdataset);
 static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
 static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
 static unsigned int rdataset_count(dns_rdataset_t *rdataset);
+static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
 
 static dns_rdatasetmethods_t rdataset_methods = {
        rdataset_disassociate,
@@ -113,7 +114,9 @@ static dns_rdatasetmethods_t rdataset_methods = {
        NULL,                   /* getclosest */
        NULL,                   /* getadditional */
        NULL,                   /* setadditional */
-       NULL                    /* putadditional */
+       NULL,                   /* putadditional */
+       rdataset_settrust,      /* settrust */
+       NULL                    /* expire */
 };
 
 typedef struct ecdb_rdatasetiter {
@@ -736,6 +739,14 @@ rdataset_count(dns_rdataset_t *rdataset) {
        return (count);
 }
 
+static void
+rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
+       rdatasetheader_t *header = rdataset->private3;
+
+       header--;
+       header->trust = rdataset->trust = trust;
+}
+
 /*
  * Rdataset Iterator Methods
  */
index 3d416a5bcaf07e13af8e64f8a40c5b4e2c42965f..6a64ee7d264bbbf561fc6930be841e3d242f6879 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdataset.h,v 1.67 2009/01/17 23:47:43 tbox Exp $ */
+/* $Id: rdataset.h,v 1.68 2010/02/25 04:39:13 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 bdf4c64333492ac6076caf4502ede53c9314212a..cb416655e51d41504b710f941611f0c1a67c23c3 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: resolver.h,v 1.64 2009/09/01 00:22:26 jinmei Exp $ */
+/* $Id: resolver.h,v 1.65 2010/02/25 04:39:13 marka Exp $ */
 
 #ifndef DNS_RESOLVER_H
 #define DNS_RESOLVER_H 1
@@ -509,6 +509,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 0d172f687cce6082e8008d31ba8353a1994003b1..4882d3d23ac6628ac4721f0df9376a2ece4e1651 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.h,v 1.118 2009/10/12 23:48:02 tbox Exp $ */
+/* $Id: result.h,v 1.119 2010/02/25 04:39:13 marka Exp $ */
 
 #ifndef DNS_RESULT_H
 #define DNS_RESULT_H 1
 #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                 106     /*%< Number of results */
+#define DNS_R_NRESULTS                 107     /*%< Number of results */
 
 /*
  * DNS wire format rcodes.
index 7f57877eb2a14687c58fb642c03e308912eb3a76..e6b6632a5a04c18affe7f1acefd1629f97717e04 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: validator.h,v 1.44 2009/01/17 13:20:45 fdupont Exp $ */
+/* $Id: validator.h,v 1.45 2010/02/25 04:39:13 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..6c81dd149ec7c9d005fcf98a607e16cbd8284b62 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.44 2010/02/25 04:39:13 marka Exp $ */
 
 /*! \file */
 
@@ -519,6 +519,8 @@ static dns_rdatasetmethods_t rdataset_methods = {
        NULL,
        NULL,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index cf491d31832fb23f8c2d0f993da69e9ea9aa9f1d..3f8c1e377b8bd48cd51799f408a49985d2480085 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.298 2010/01/04 23:48:51 tbox Exp $ */
+/* $Id: rbtdb.c,v 1.299 2010/02/25 04:39:13 marka Exp $ */
 
 /*! \file */
 
@@ -522,6 +522,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,
@@ -536,7 +538,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);
@@ -7662,6 +7666,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..73a9e2d08056b0fb3e29af4af4612591ad457463 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.37 2010/02/25 04:39:13 marka Exp $ */
 
 /*! \file */
 
@@ -46,6 +46,8 @@ static dns_rdatasetmethods_t methods = {
        isc__rdatalist_getclosest,
        NULL,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index 1e59a053827821efb8c539ecc53bc6c254ba9d94..9c503c43262c67c48f99c2dbf6dfe8d94bf3e6fc 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdataset.c,v 1.84 2009/01/17 23:47:43 tbox Exp $ */
+/* $Id: rdataset.c,v 1.85 2010/02/25 04:39:13 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 04d8504b63321cb23611d431be7c644246f19c97..8b17c79cd06df481764cba96bcbe378ce8d6fc6f 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rdataslab.c,v 1.50 2009/01/17 23:47:43 tbox Exp $ */
+/* $Id: rdataslab.c,v 1.51 2010/02/25 04:39:13 marka Exp $ */
 
 /*! \file */
 
@@ -436,6 +436,8 @@ static dns_rdatasetmethods_t rdataset_methods = {
        NULL,
        NULL,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index 92107de69e8769321ae22d0b49d4bb244e03fe1e..26e52173ae1266007a20bd8cf4e939d8de8203d8 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: resolver.c,v 1.415 2010/01/07 23:48:54 tbox Exp $ */
+/* $Id: resolver.c,v 1.416 2010/02/25 04:39:13 marka Exp $ */
 
 /*! \file */
 
@@ -336,6 +336,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;
@@ -382,6 +394,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. */
@@ -412,7 +431,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,
@@ -1172,7 +1192,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);
        }
 }
 
@@ -2073,7 +2093,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);
        }
 }
 
@@ -2135,7 +2155,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)
@@ -2543,7 +2563,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;
@@ -2762,12 +2782,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 {
@@ -2990,7 +3022,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;
 
@@ -3008,7 +3040,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.
@@ -3173,7 +3205,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);
@@ -3343,7 +3375,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);
 }
@@ -3965,6 +3997,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.
@@ -4011,35 +4045,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;
@@ -6102,7 +6181,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;
@@ -6981,7 +7060,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).
@@ -7043,6 +7122,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) {
@@ -7080,6 +7180,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);
@@ -7203,6 +7304,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;
@@ -8046,6 +8151,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 0e857ac7d716a8ec09839822d837a8346c8ba29d..0a954e139e3c16e7021492992b7da0159dd854cd 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.c,v 1.128 2009/10/12 20:48:12 each Exp $ */
+/* $Id: result.c,v 1.129 2010/02/25 04:39:13 marka Exp $ */
 
 /*! \file */
 
@@ -157,7 +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 52c51d9c638084681f8f6cd8ba5e1b405ef10c31..29eb825e6e885e3990d4afb1ebdeb5c757bad87f 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: sdb.c,v 1.71 2009/10/08 23:13:07 marka Exp $ */
+/* $Id: sdb.c,v 1.72 2010/02/25 04:39:13 marka Exp $ */
 
 /*! \file */
 
@@ -1387,6 +1387,8 @@ static dns_rdatasetmethods_t methods = {
        NULL,
        NULL,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index 2138e38eb8f7c2370364008595f9c5ec346092cc..7c48d24145ac2b6d22dcb2cfb8fcf64d5789432c 100644 (file)
@@ -50,7 +50,7 @@
  * USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: sdlz.c,v 1.22 2009/09/01 00:22:26 jinmei Exp $ */
+/* $Id: sdlz.c,v 1.23 2010/02/25 04:39:13 marka Exp $ */
 
 /*! \file */
 
@@ -1211,6 +1211,8 @@ static dns_rdatasetmethods_t rdataset_methods = {
        NULL,
        NULL,
        NULL,
+       NULL,
+       NULL,
        NULL
 };
 
index 027e23605be34dc59972cb25fb82479d0aba3faa..fad6975722939e9d1046665e8214853bc56cdffc 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: validator.c,v 1.183 2009/12/30 06:46:58 each Exp $ */
+/* $Id: validator.c,v 1.184 2010/02/25 04:39:13 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);
@@ -636,10 +643,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);
@@ -686,10 +699,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);
@@ -1200,6 +1219,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 {
@@ -1272,6 +1293,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) {
@@ -1281,9 +1303,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);
@@ -1293,6 +1318,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;
@@ -1301,6 +1336,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);
@@ -1663,7 +1699,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);
@@ -1678,7 +1715,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)
@@ -1930,8 +1968,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, "
                                      "noqname proof not needed");
@@ -2108,8 +2145,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 (dlv)");
                return (result);
        } else if (result == ISC_R_NOMORE && !supported_algorithm) {
@@ -2219,8 +2255,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");
@@ -2252,11 +2287,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 a "
                                      "trusted key for '%s'",
                                      namebuf);
+                       validator_log(val, ISC_LOG_NOTICE,
+                                     "please check the 'trusted-keys' for "
+                                     "'%s' in named.conf.", namebuf);
                        return (DNS_R_NOVALIDKEY);
                }
 
@@ -2317,7 +2355,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);
        }
 
        /*
@@ -2467,8 +2506,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 (DS)");
                return (result);
        } else if (result == ISC_R_NOMORE && !supported_algorithm) {
@@ -2875,6 +2913,7 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) {
                                                  "nsecvalidate");
                        if (result != ISC_R_SUCCESS)
                                return (result);
+                       val->authcount++;
                        return (DNS_R_WAIT);
 
                }
@@ -2897,8 +2936,7 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) {
                    (val->attributes & VALATTR_FOUNDCLOSEST) != 0) {
                        validator_log(val, ISC_LOG_DEBUG(3),
                                      "marking as secure, noqname proof found");
-                       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))
@@ -2951,6 +2989,8 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) {
                return (ISC_R_SUCCESS);
        }
 
+       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;
@@ -2982,6 +3022,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.
  *
@@ -3204,6 +3296,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) {
                                validator_log(val, ISC_LOG_DEBUG(3),
                                              "DLV not validated");
@@ -3257,6 +3367,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)
@@ -3518,7 +3629,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);
        }
 
 /*
@@ -3744,6 +3856,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 6850f2f5020277ee825a4f7b3997985d6911726b..09ef1caf3c746d37c28c276f45f3ae4116e57e76 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: view.c,v 1.159 2009/11/28 15:57:37 vjs Exp $ */
+/* $Id: view.c,v 1.160 2010/02/25 04:39:13 marka Exp $ */
 
 /*! \file */
 
@@ -1325,10 +1325,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);
 }
 #endif
@@ -1360,6 +1361,8 @@ dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly) {
 #ifdef BIND9
        if (view->acache != NULL)
                dns_acache_setdb(view->acache, view->cachedb);
+       if (view->resolver != NULL)
+               dns_resolver_flushbadcache(view->resolver, NULL);
 #endif
 
        dns_adb_flush(view->adb);
@@ -1375,6 +1378,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));
 }