Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 6e3f21ce1d62a9e7001f9d653bfca859 > files > 55

bind-9.3.6-20.P1.el5_8.5.src.rpm

diff -up bind-9.3.6-P1/bin/named/server.c.rh572848 bind-9.3.6-P1/bin/named/server.c
--- bind-9.3.6-P1/bin/named/server.c.rh572848	2010-08-10 12:17:31.699313304 +0200
+++ bind-9.3.6-P1/bin/named/server.c	2010-08-10 12:17:31.699313304 +0200
@@ -4045,6 +4045,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) {
diff -up bind-9.3.6-P1/lib/dns/include/dns/resolver.h.rh572848 bind-9.3.6-P1/lib/dns/include/dns/resolver.h
--- bind-9.3.6-P1/lib/dns/include/dns/resolver.h.rh572848	2006-02-02 00:48:51.000000000 +0100
+++ bind-9.3.6-P1/lib/dns/include/dns/resolver.h	2010-08-10 12:17:31.699313304 +0200
@@ -426,6 +426,48 @@ dns_resolver_setmustbesecure(dns_resolve
 isc_boolean_t
 dns_resolver_getmustbesecure(dns_resolver_t *resolver, dns_name_t *name);
 
+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:
+ *  resolver to be valid.
+ *  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:
+ *  resolver to be valid.
+ *  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:
+ *  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:
+ *  resolver to be valid.
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_RESOLVER_H */
diff -up bind-9.3.6-P1/lib/dns/include/dns/result.h.rh572848 bind-9.3.6-P1/lib/dns/include/dns/result.h
--- bind-9.3.6-P1/lib/dns/include/dns/result.h.rh572848	2004-05-14 07:06:41.000000000 +0200
+++ bind-9.3.6-P1/lib/dns/include/dns/result.h	2010-08-10 12:17:31.699313304 +0200
@@ -143,8 +143,9 @@
 #define DNS_R_UNKNOWNCOMMAND		(ISC_RESULTCLASS_DNS + 99)
 #define DNS_R_MUSTBESECURE		(ISC_RESULTCLASS_DNS + 100)
 #define DNS_R_COVERINGNSEC		(ISC_RESULTCLASS_DNS + 101)
+#define DNS_R_BROKENCHAIN		(ISC_RESULTCLASS_DNS + 102)
 
-#define DNS_R_NRESULTS			102	/* Number of results */
+#define DNS_R_NRESULTS			103	/* Number of results */
 
 /*
  * DNS wire format rcodes.
diff -up bind-9.3.6-P1/lib/dns/include/dns/validator.h.rh572848 bind-9.3.6-P1/lib/dns/include/dns/validator.h
--- bind-9.3.6-P1/lib/dns/include/dns/validator.h.rh572848	2007-09-19 05:41:33.000000000 +0200
+++ bind-9.3.6-P1/lib/dns/include/dns/validator.h	2010-08-10 12:17:31.699313304 +0200
@@ -151,6 +151,8 @@ struct dns_validator {
 	isc_boolean_t			mustbesecure;
 	unsigned int			dlvlabels;
 	unsigned int			depth;
+	unsigned int			authcount;
+	unsigned int			authfail;
 };
 
 /*%
diff -up bind-9.3.6-P1/lib/dns/resolver.c.rh572848 bind-9.3.6-P1/lib/dns/resolver.c
--- bind-9.3.6-P1/lib/dns/resolver.c.rh572848	2010-08-10 12:17:31.679309993 +0200
+++ bind-9.3.6-P1/lib/dns/resolver.c	2010-08-10 12:17:31.709314955 +0200
@@ -286,6 +286,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;
@@ -324,6 +336,13 @@ struct dns_resolver {
 	isc_eventlist_t			whenshutdown;
 	unsigned int			activebuckets;
 	isc_boolean_t			priming;
+
+	/* 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. */
@@ -353,7 +372,7 @@ static void empty_bucket(dns_resolver_t 
 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);
+static void fctx_try(fetchctx_t *fctx, 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,
@@ -898,7 +917,7 @@ process_sendevent(resquery_t *query, isc
 		if (result != ISC_R_SUCCESS)
 			fctx_done(fctx, result);
 		else
-			fctx_try(fctx);
+			fctx_try(fctx, ISC_FALSE);
 	}
 }
 
@@ -1591,7 +1610,7 @@ resquery_connected(isc_task_t *task, isc
 		if (result != ISC_R_SUCCESS)
 			fctx_done(fctx, result);
 		else
-			fctx_try(fctx);
+			fctx_try(fctx, ISC_FALSE);
 	}
 }
 
@@ -1650,7 +1669,7 @@ fctx_finddone(isc_task_t *task, isc_even
 	dns_adb_destroyfind(&find);
 
 	if (want_try)
-		fctx_try(fctx);
+		fctx_try(fctx, ISC_FALSE);
 	else if (want_done)
 		fctx_done(fctx, ISC_R_FAILURE);
 	else if (bucket_empty)
@@ -1990,7 +2009,7 @@ findname(fetchctx_t *fctx, dns_name_t *n
 }
 
 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;
@@ -2206,12 +2225,24 @@ fctx_getaddresses(fetchctx_t *fctx) {
 			fctx_cleanupfinds(fctx);
 			goto restart;
 		} 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 {
@@ -2433,7 +2464,7 @@ fctx_nextaddress(fetchctx_t *fctx) {
 }
 
 static void
-fctx_try(fetchctx_t *fctx) {
+fctx_try(fetchctx_t *fctx, isc_boolean_t badcache) {
 	isc_result_t result;
 	dns_adbaddrinfo_t *addrinfo;
 
@@ -2451,7 +2482,7 @@ fctx_try(fetchctx_t *fctx) {
 		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.
@@ -2594,7 +2625,7 @@ fctx_timeout(isc_task_t *task, isc_event
 			/*
 			 * Keep trying.
 			 */
-			fctx_try(fctx);
+			fctx_try(fctx, ISC_FALSE);
 	}
 
 	isc_event_free(&event);
@@ -2764,7 +2795,7 @@ fctx_start(isc_task_t *task, isc_event_t
 		if (result != ISC_R_SUCCESS)
 			fctx_done(fctx, result);
 		else
-			fctx_try(fctx);
+			fctx_try(fctx, ISC_FALSE);
 	} else if (bucket_empty)
 		empty_bucket(res);
 }
@@ -3310,6 +3341,8 @@ validated(isc_task_t *task, isc_event_t 
 
 	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.
@@ -3352,37 +3385,83 @@ validated(isc_task_t *task, isc_event_t 
 	}
 
 	if (vevent->result != ISC_R_SUCCESS) {
+		isc_result_t vresult;
 		FCTXTRACE("validation failed");
-		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;
+		vresult = vevent->result;
+		if (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 (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 = vresult;
 		add_bad(fctx, addrinfo, result);
 		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);	/* Locks bucket. */
-		else
-			fctx_try(fctx);			/* 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);	/* Locks bucket. */
+		} else
+			fctx_try(fctx, ISC_TRUE);	/* Locks bucket. */
 		return;
 	}
 
-	isc_stdtime_get(&now);
-
 	if (negative) {
 		dns_rdatatype_t covers;
 		FCTXTRACE("nonexistence validation OK");
@@ -5146,7 +5225,7 @@ resume_dslookup(isc_task_t *task, isc_ev
 		/*
 		 * Try again.
 		 */
-		fctx_try(fctx);
+		fctx_try(fctx, ISC_FALSE);
 	} else {
 		unsigned int n;
 		dns_rdataset_t *nsrdataset = NULL;
@@ -5847,7 +5926,7 @@ resquery_response(isc_task_t *task, isc_
 		/*
 		 * Try again.
 		 */
-		fctx_try(fctx);
+		fctx_try(fctx, ISC_FALSE);
 	} else if (resend) {
 		/*
 		 * Resend (probably with changed options).
@@ -5908,6 +5987,28 @@ resquery_response(isc_task_t *task, isc_
 /***
  *** 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) {
@@ -5944,6 +6045,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);
@@ -6032,6 +6134,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->nbuckets = ntasks;
@@ -6730,6 +6836,255 @@ dns_resolver_getudpsize(dns_resolver_t *
 	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;
diff -up bind-9.3.6-P1/lib/dns/result.c.rh572848 bind-9.3.6-P1/lib/dns/result.c
--- bind-9.3.6-P1/lib/dns/result.c.rh572848	2004-05-14 07:06:39.000000000 +0200
+++ bind-9.3.6-P1/lib/dns/result.c	2010-08-10 12:17:50.772459957 +0200
@@ -151,7 +151,8 @@ static const char *text[DNS_R_NRESULTS] 
 	"unknown command",		       /* 99 DNS_R_UNKNOWNCOMMAND    */
 
 	"must-be-secure",		       /* 100 DNS_R_MUSTBESECURE     */
-	"covering NSEC record returned"	       /* 101 DNS_R_COVERINGNSEC     */
+	"covering NSEC record returned",       /* 101 DNS_R_COVERINGNSEC     */
+	"broken trust chain",                  /* 102 DNS_R_BROKENCHAIN      */
 };
 
 static const char *rcode_text[DNS_R_NRCODERESULTS] = {
diff -up bind-9.3.6-P1/lib/dns/validator.c.rh572848 bind-9.3.6-P1/lib/dns/validator.c
--- bind-9.3.6-P1/lib/dns/validator.c.rh572848	2010-08-10 12:17:31.689311653 +0200
+++ bind-9.3.6-P1/lib/dns/validator.c	2010-08-10 12:17:31.709314955 +0200
@@ -339,7 +339,7 @@ fetch_callback_validator(isc_task_t *tas
 		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);
@@ -409,7 +409,7 @@ dsfetched(isc_task_t *task, isc_event_t 
 		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);
@@ -552,7 +552,7 @@ keyvalidated(isc_task_t *task, isc_event
 		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);
@@ -602,7 +602,7 @@ dsvalidated(isc_task_t *task, isc_event_
 		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);
@@ -804,6 +804,8 @@ authvalidated(isc_task_t *task, isc_even
 		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 {
@@ -869,6 +871,7 @@ authvalidated(isc_task_t *task, isc_even
  * \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) {
@@ -878,9 +881,12 @@ view_find(dns_validator_t *val, dns_name
 	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);
@@ -890,6 +896,16 @@ view_find(dns_validator_t *val, dns_name
 	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;
@@ -1246,7 +1262,8 @@ get_key(dns_validator_t *val, dns_rdata_
 		 * 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)
@@ -1754,11 +1771,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);
 		}
 
@@ -1819,7 +1839,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);
 	}
 
 	/*
@@ -2143,6 +2164,7 @@ nsecvalidate(dns_validator_t *val, isc_b
 						  "nsecvalidate");
 			if (result != ISC_R_SUCCESS)
 				return (result);
+			val->authcount++;
 			return (DNS_R_WAIT);
 
 		}
@@ -2196,6 +2218,8 @@ nsecvalidate(dns_validator_t *val, isc_b
 		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_AUTHNONPENDING;
@@ -2227,6 +2251,52 @@ check_ds(dns_validator_t *val, dns_name_
 	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 {
+		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.
  *
@@ -2422,6 +2492,24 @@ finddlvsep(dns_validator_t *val, isc_boo
 			      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");
@@ -2475,6 +2563,7 @@ finddlvsep(dns_validator_t *val, isc_boo
  * \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)
@@ -2701,7 +2790,8 @@ proveunsecure(dns_validator_t *val, isc_
 			if (result != ISC_R_SUCCESS)
 				goto out;
 			return (DNS_R_WAIT);
-		}
+		} else if (result == DNS_R_BROKENCHAIN)
+			return (result);
 	}
 	validator_log(val, ISC_LOG_DEBUG(3), "insecurity proof failed");
 	return (DNS_R_NOTINSECURE); /* Couldn't complete insecurity proof */
@@ -2907,6 +2997,8 @@ dns_validator_create(dns_view_t *view, d
 	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);
diff -up bind-9.3.6-P1/lib/dns/view.c.rh572848 bind-9.3.6-P1/lib/dns/view.c
--- bind-9.3.6-P1/lib/dns/view.c.rh572848	2010-08-10 12:17:31.659306690 +0200
+++ bind-9.3.6-P1/lib/dns/view.c	2010-08-10 12:17:31.709314955 +0200
@@ -1175,6 +1175,7 @@ dns_view_dumpdbtostream(dns_view_t *view
 	if (result != ISC_R_SUCCESS)
 		return (result);
 	dns_adb_dump(view->adb, fp);
+	dns_resolver_printbadcache(view->resolver, fp);
 	return (ISC_R_SUCCESS);
 }
 
@@ -1191,6 +1192,8 @@ dns_view_flushcache(dns_view_t *view) {
 		return (result);
 	dns_db_detach(&view->cachedb);
 	dns_cache_attachdb(view->cache, &view->cachedb);
+	if (view->resolver != NULL)
+		dns_resolver_flushbadcache(view->resolver, NULL);
 
 	dns_adb_flush(view->adb);
 	return (ISC_R_SUCCESS);
@@ -1205,6 +1208,8 @@ dns_view_flushname(dns_view_t *view, dns
 		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));
 }