Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 482997498f9f95c2819169698d08f0c7 > files > 34

bind-9.3.6-25.P1.el5_11.8.src.rpm

diff -up bind-9.3.6-P1/bin/named/config.c.CVE-2014-8500 bind-9.3.6-P1/bin/named/config.c
--- bind-9.3.6-P1/bin/named/config.c.CVE-2014-8500	2014-12-10 13:32:18.753869797 +0100
+++ bind-9.3.6-P1/bin/named/config.c	2014-12-10 13:32:18.956870266 +0100
@@ -76,6 +76,8 @@ options {\n\
 #endif
 "\
 	recursive-clients 1000;\n\
+	max-recursion-depth 7;\n\
+	max-recursion-queries 50;\n\
 	rrset-order {order cyclic;};\n\
 	serial-queries 20;\n\
 	serial-query-rate 20;\n\
diff -up bind-9.3.6-P1/bin/named/query.c.CVE-2014-8500 bind-9.3.6-P1/bin/named/query.c
--- bind-9.3.6-P1/bin/named/query.c.CVE-2014-8500	2014-12-10 13:32:18.803869913 +0100
+++ bind-9.3.6-P1/bin/named/query.c	2014-12-10 13:32:18.957870269 +0100
@@ -2159,10 +2159,11 @@ query_recurse(ns_client_t *client, dns_r
 
 	if (client->query.timerset == ISC_FALSE)
 		ns_client_settimeout(client, 60);
-	result = dns_resolver_createfetch(client->view->resolver,
+	result = dns_resolver_createfetch3(client->view->resolver,
 					  client->query.qname,
 					  qtype, qdomain, nameservers,
 					  NULL, client->query.fetchoptions,
+					  0, NULL,
 					  client->task,
 					  query_resume, client,
 					  rdataset, sigrdataset,
diff -up bind-9.3.6-P1/bin/named/server.c.CVE-2014-8500 bind-9.3.6-P1/bin/named/server.c
--- bind-9.3.6-P1/bin/named/server.c.CVE-2014-8500	2014-12-10 13:32:18.832869980 +0100
+++ bind-9.3.6-P1/bin/named/server.c	2014-12-10 13:32:18.958870271 +0100
@@ -1324,6 +1324,16 @@ configure_view(dns_view_t *view, const c
 		view->enableedns = cfg_obj_asboolean(obj);
 
 	obj = NULL;
+	result = ns_config_get(maps, "max-recursion-depth", &obj);
+	INSIST(result == ISC_R_SUCCESS);
+	dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
+
+	obj = NULL;
+	result = ns_config_get(maps, "max-recursion-queries", &obj);
+	INSIST(result == ISC_R_SUCCESS);
+	dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
+
+	obj = NULL;
 	result = ns_config_get(maps, "dnssec-enable", &obj);
 	INSIST(result == ISC_R_SUCCESS);
 	view->enablednssec = cfg_obj_asboolean(obj);
diff -up bind-9.3.6-P1/doc/arm/Bv9ARM-book.xml.CVE-2014-8500 bind-9.3.6-P1/doc/arm/Bv9ARM-book.xml
--- bind-9.3.6-P1/doc/arm/Bv9ARM-book.xml.CVE-2014-8500	2008-09-28 01:50:37.000000000 +0200
+++ bind-9.3.6-P1/doc/arm/Bv9ARM-book.xml	2014-12-10 13:32:18.959870273 +0100
@@ -2957,6 +2957,8 @@ statement in the <filename>named.conf</f
     <optional> additional-from-cache <replaceable>yes_or_no</replaceable> ; </optional>
     <optional> random-device <replaceable>path_name</replaceable> ; </optional>
     <optional> max-cache-size <replaceable>size_spec</replaceable> ; </optional>
+    <optional> max-recursion-depth <replaceable>number</replaceable> ; </optional>
+    <optional> max-recursion-queries <replaceable>number</replaceable> ; </optional>
     <optional> match-mapped-addresses <replaceable>yes_or_no</replaceable>; </optional>
     <optional> preferred-glue ( <replaceable>A</replaceable> | <replaceable>AAAA</replaceable> | <replaceable>NONE</replaceable> ); </optional>
     <optional> edns-udp-size <replaceable>number</replaceable>; </optional>
@@ -4250,6 +4252,35 @@ The default is 0.
 </para>
 </listitem></varlistentry>
 
+	  <varlistentry id="max-recursion-depth">
+	    <term><command>max-recursion-depth</command></term>
+	    <listitem>
+	      <para>
+		Sets the maximum number of levels of recursion
+		that are permitted at any one time while servicing
+		a recursive query. Resolving a name may require
+		looking up a name server address, which in turn
+		requires resolving another name, etc; if the number
+		of indirections exceeds this value, the recursive
+		query is terminated and returns SERVFAIL.  The
+		default is 7.
+	      </para>
+	    </listitem>
+	  </varlistentry>
+
+	  <varlistentry id="max-recursion-queries">
+	    <term><command>max-recursion-queries</command></term>
+	    <listitem>
+	      <para>
+		Sets the maximum number of iterative queries that
+		may be sent while servicing a recursive query.
+		If more queries are sent, the recursive query
+		is terminated and returns SERVFAIL. The default
+		is 50.
+	      </para>
+	    </listitem>
+	  </varlistentry>
+
 <varlistentry><term><command>tcp-listen-queue</command></term>
 <listitem><para>The listen queue depth.  The default and minimum is 3.
 If the kernel supports the accept filter "dataready" this also controls how
diff -up bind-9.3.6-P1/lib/dns/adb.c.CVE-2014-8500 bind-9.3.6-P1/lib/dns/adb.c
--- bind-9.3.6-P1/lib/dns/adb.c.CVE-2014-8500	2008-10-17 05:34:53.000000000 +0200
+++ bind-9.3.6-P1/lib/dns/adb.c	2014-12-10 13:44:58.750626863 +0100
@@ -198,6 +198,7 @@ struct dns_adbfetch {
 	dns_adbentry_t		       *entry;
 	dns_fetch_t		       *fetch;
 	dns_rdataset_t			rdataset;
+	unsigned int			depth;
 };
 
 /*
@@ -305,6 +306,7 @@ static void cancel_fetches_at_name(dns_a
 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
 				dns_rdatatype_t);
 static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
+			       unsigned int, isc_counter_t *qc,
 			       dns_rdatatype_t);
 static inline void check_exit(dns_adb_t *);
 static void timer_cleanup(isc_task_t *, isc_event_t *);
@@ -2282,6 +2284,19 @@ dns_adb_createfind(dns_adb_t *adb, isc_t
 		   unsigned int options, isc_stdtime_t now, dns_name_t *target,
 		   in_port_t port, dns_adbfind_t **findp)
 {
+	return (dns_adb_createfind2(adb, task, action, arg, name,
+				    zone, options, now,
+				    target, port, 0, NULL, findp));
+}
+
+isc_result_t
+dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
+		    void *arg, dns_name_t *name, dns_name_t *zone,
+		    unsigned int options,
+		    isc_stdtime_t now, dns_name_t *target,
+		    in_port_t port, unsigned int depth, isc_counter_t *qc,
+		    dns_adbfind_t **findp)
+{
 	dns_adbfind_t *find;
 	dns_adbname_t *adbname;
 	int bucket;
@@ -2500,7 +2515,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_t
 		 * Start V4.
 		 */
 		if (WANT_INET(wanted_fetches) &&
-		    fetch_name(adbname, start_at_zone,
+		    fetch_name(adbname, start_at_zone, depth, qc,
 			       dns_rdatatype_a) == ISC_R_SUCCESS) {
 			DP(DEF_LEVEL,
 			   "dns_adb_createfind: started A fetch for name %p",
@@ -2511,7 +2526,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_t
 		 * Start V6.
 		 */
 		if (WANT_INET6(wanted_fetches) &&
-		    fetch_name(adbname, start_at_zone,
+		    fetch_name(adbname, start_at_zone, depth, qc,
 			       dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
 			DP(DEF_LEVEL,
 			   "dns_adb_createfind: "
@@ -3236,6 +3251,12 @@ fetch_callback(isc_task_t *task, isc_eve
 		DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
 		   buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
 		   dns_result_totext(dev->result));
+		/*
+		 * Don't record a failure unless this is the initial
+		 * fetch of a chain.
+		 */
+		if (fetch->depth > 1)
+			goto out;
 		/* XXXMLG Don't pound on bad servers. */
 		if (address_type == DNS_ADBFIND_INET) {
 			name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
@@ -3271,9 +3292,8 @@ fetch_callback(isc_task_t *task, isc_eve
 }
 
 static isc_result_t
-fetch_name(dns_adbname_t *adbname,
-	   isc_boolean_t start_at_zone,
-	   dns_rdatatype_t type)
+fetch_name(dns_adbname_t *adbname, isc_boolean_t start_at_zone,
+	   unsigned int depth, isc_counter_t *qc, dns_rdatatype_t type)
 {
 	isc_result_t result;
 	dns_adbfetch_t *fetch = NULL;
@@ -3318,12 +3338,14 @@ fetch_name(dns_adbname_t *adbname,
 		result = ISC_R_NOMEMORY;
 		goto cleanup;
 	}
+	fetch->depth = depth;
 
-	result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
-					  type, name, nameservers, NULL,
-					  options, adb->task, fetch_callback,
-					  adbname, &fetch->rdataset, NULL,
-					  &fetch->fetch);
+	result = dns_resolver_createfetch3(adb->view->resolver, &adbname->name,
+					   type, name, nameservers, NULL,
+					   options, depth, qc,
+					   adb->task, fetch_callback, adbname,
+					   &fetch->rdataset, NULL,
+					   &fetch->fetch);
 	if (result != ISC_R_SUCCESS)
 		goto cleanup;
 
diff -up bind-9.3.6-P1/lib/dns/include/dns/adb.h.CVE-2014-8500 bind-9.3.6-P1/lib/dns/include/dns/adb.h
--- bind-9.3.6-P1/lib/dns/include/dns/adb.h.CVE-2014-8500	2004-03-06 09:13:50.000000000 +0100
+++ bind-9.3.6-P1/lib/dns/include/dns/adb.h	2014-12-10 13:32:18.960870276 +0100
@@ -301,6 +301,13 @@ dns_adb_createfind(dns_adb_t *adb, isc_t
 		   void *arg, dns_name_t *name, dns_name_t *zone,
 		   unsigned int options, isc_stdtime_t now, dns_name_t *target,
 		   in_port_t port, dns_adbfind_t **find);
+isc_result_t
+dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
+		    void *arg, dns_name_t *name, dns_name_t *zone,
+		    unsigned int options,
+		    isc_stdtime_t now, dns_name_t *target, in_port_t port,
+		    unsigned int depth, isc_counter_t *qc,
+		    dns_adbfind_t **find);
 /*
  * Main interface for clients. The adb will look up the name given in
  * "name" and will build up a list of found addresses, and perhaps start
diff -up bind-9.3.6-P1/lib/dns/include/dns/resolver.h.CVE-2014-8500 bind-9.3.6-P1/lib/dns/include/dns/resolver.h
--- bind-9.3.6-P1/lib/dns/include/dns/resolver.h.CVE-2014-8500	2014-12-10 13:32:18.791869885 +0100
+++ bind-9.3.6-P1/lib/dns/include/dns/resolver.h	2014-12-10 13:32:18.960870276 +0100
@@ -236,6 +236,17 @@ dns_resolver_createfetch(dns_resolver_t
 			 dns_rdataset_t *rdataset,
 			 dns_rdataset_t *sigrdataset,
 			 dns_fetch_t **fetchp);
+isc_result_t
+dns_resolver_createfetch3(dns_resolver_t *res, dns_name_t *name,
+			  dns_rdatatype_t type,
+			  dns_name_t *domain, dns_rdataset_t *nameservers,
+			  dns_forwarders_t *forwarders,
+			  unsigned int options, unsigned int depth,
+			  isc_counter_t *qc, isc_task_t *task,
+			  isc_taskaction_t action, void *arg,
+			  dns_rdataset_t *rdataset,
+			  dns_rdataset_t *sigrdataset,
+			  dns_fetch_t **fetchp);
 /*
  * Recurse to answer a question.
  *
@@ -466,6 +477,30 @@ dns_resolver_printbadcache(dns_resolver_
  *
  * Requires:
  *  resolver to be valid.
+ */
+
+void
+dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth);
+unsigned int
+dns_resolver_getmaxdepth(dns_resolver_t *resolver);
+/*%
+ * Get and set how many NS indirections will be followed when looking for
+ * nameserver addresses.
+ *
+ * Requires:
+ *  resolver to be valid.
+ */
+
+void
+dns_resolver_setmaxqueries(dns_resolver_t *resolver, unsigned int queries);
+unsigned int
+dns_resolver_getmaxqueries(dns_resolver_t *resolver);
+/*%
+ * Get and set how many iterative queries will be allowed before
+ * terminating a recursive query.
+ *
+ * Requires:
+ *  resolver to be valid.
  */
 
 ISC_LANG_ENDDECLS
diff -up bind-9.3.6-P1/lib/dns/resolver.c.CVE-2014-8500 bind-9.3.6-P1/lib/dns/resolver.c
--- bind-9.3.6-P1/lib/dns/resolver.c.CVE-2014-8500	2014-12-10 13:32:18.947870246 +0100
+++ bind-9.3.6-P1/lib/dns/resolver.c	2014-12-10 13:32:18.962870280 +0100
@@ -19,6 +19,7 @@
 
 #include <config.h>
 
+#include <isc/counter.h>
 #include <isc/print.h>
 #include <isc/string.h>
 #include <isc/task.h>
@@ -99,6 +100,16 @@
 #define QTRACE(m)
 #endif
 
+/* The default maximum number of recursions to follow before giving up. */
+#ifndef DEFAULT_RECURSION_DEPTH
+#define DEFAULT_RECURSION_DEPTH 7
+#endif
+
+/* The default maximum number of iterative queries to allow before giving up. */
+#ifndef DEFAULT_MAX_QUERIES
+#define DEFAULT_MAX_QUERIES 50
+#endif
+
 /*
  * Maximum EDNS0 input packet size.
  */
@@ -194,6 +205,7 @@ struct fetchctx {
 	dns_adb_t *			adb;
 	isc_boolean_t			ns_ttl_ok;
 	isc_uint32_t			ns_ttl;
+	isc_counter_t *			qc;
 
 	/*
 	 * The number of events we're waiting for.
@@ -227,6 +239,7 @@ struct fetchctx {
 	 * Number of queries that reference this context.
 	 */
 	unsigned int			nqueries;
+	unsigned int			depth;
 };
 
 #define FCTX_MAGIC			ISC_MAGIC('F', '!', '!', '!')
@@ -332,6 +345,8 @@ struct dns_resolver {
 	isc_rwlock_t			mbslock;
 #endif
 	dns_rbt_t *			mustbesecure;
+	unsigned int			maxdepth;
+	unsigned int			maxqueries;
 	/* Locked by lock. */
 	unsigned int			references;
 	isc_boolean_t			exiting;
@@ -1927,11 +1942,11 @@ findname(fetchctx_t *fctx, dns_name_t *n
 	 * See what we know about this address.
 	 */
 	find = NULL;
-	result = dns_adb_createfind(fctx->adb,
+	result = dns_adb_createfind2(fctx->adb,
 				    res->buckets[fctx->bucketnum].task,
 				    fctx_finddone, fctx, name,
 				    &fctx->domain, options, now, NULL,
-				    res->view->dstport, &find);
+				    res->view->dstport, fctx->depth + 1, fctx->qc, &find);
 	if (result != ISC_R_SUCCESS) {
 		if (result == DNS_R_ALIAS) {
 			/*
@@ -2038,6 +2053,14 @@ fctx_getaddresses(fetchctx_t *fctx, isc_
 	pruned = ISC_FALSE;
 	stdoptions = 0;		/* Keep compiler happy. */
 
+	if (fctx->depth > res->maxdepth) {
+		isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+			      DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
+			      "too much NS indirection resolving '%s'",
+			      fctx->info);
+		return (DNS_R_SERVFAIL);
+	}
+
 	/*
 	 * Forwarders.
 	 */
@@ -2511,6 +2534,16 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t
 		}
 	}
 
+	result = isc_counter_increment(fctx->qc);
+	if (result != ISC_R_SUCCESS) {
+		isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
+			      DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
+			      "exceeded max queries resolving '%s'",
+			      fctx->info);
+		fctx_done(fctx, DNS_R_SERVFAIL);
+		return;
+	}
+
 	result = fctx_query(fctx, addrinfo, fctx->options);
 	if (result != ISC_R_SUCCESS)
 		fctx_done(fctx, result);
@@ -2555,6 +2588,7 @@ fctx_destroy(fetchctx_t *fctx) {
 		isc_mem_put(res->mctx, sa, sizeof(*sa));
 	}
 
+	isc_counter_detach(&fctx->qc);
 	isc_timer_detach(&fctx->timer);
 	dns_message_destroy(&fctx->rmessage);
 	dns_message_destroy(&fctx->qmessage);
@@ -2873,7 +2907,8 @@ log_ns_ttl(fetchctx_t *fctx, const char
 static isc_result_t
 fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
 	    dns_name_t *domain, dns_rdataset_t *nameservers,
-	    unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp)
+	    unsigned int options, unsigned int bucketnum, unsigned int depth,
+	    isc_counter_t *qc, fetchctx_t **fctxp)
 {
 	fetchctx_t *fctx;
 	isc_result_t result;
@@ -2893,6 +2928,17 @@ fctx_create(dns_resolver_t *res, dns_nam
 	fctx = isc_mem_get(res->mctx, sizeof(*fctx));
 	if (fctx == NULL)
 		return (ISC_R_NOMEMORY);
+
+	fctx->qc = NULL;
+	if (qc != NULL) {
+		isc_counter_attach(qc, &fctx->qc);
+	} else {
+		result = isc_counter_create(res->mctx,
+					    res->maxqueries, &fctx->qc);
+		if (result != ISC_R_SUCCESS)
+			goto cleanup_fetch;
+	}
+
 	dns_name_format(name, buf, sizeof(buf));
 	dns_rdatatype_format(type, typebuf, sizeof(typebuf));
 	strcat(buf, "/");	/* checked */
@@ -2900,7 +2946,7 @@ fctx_create(dns_resolver_t *res, dns_nam
 	fctx->info = isc_mem_strdup(res->mctx, buf);
 	if (fctx->info == NULL) {
 		result = ISC_R_NOMEMORY;
-		goto cleanup_fetch;
+		goto cleanup_counter;
 	}
 	FCTXTRACE("create");
 	dns_name_init(&fctx->name, NULL);
@@ -2923,6 +2969,7 @@ fctx_create(dns_resolver_t *res, dns_nam
 	fctx->state = fetchstate_init;
 	fctx->want_shutdown = ISC_FALSE;
 	fctx->cloned = ISC_FALSE;
+	fctx->depth = depth;
 	ISC_LIST_INIT(fctx->queries);
 	ISC_LIST_INIT(fctx->finds);
 	ISC_LIST_INIT(fctx->altfinds);
@@ -3102,6 +3149,9 @@ fctx_create(dns_resolver_t *res, dns_nam
  cleanup_info:
 	isc_mem_free(res->mctx, fctx->info);
 
+ cleanup_counter:
+	isc_counter_detach(&fctx->qc);
+
  cleanup_fetch:
 	isc_mem_put(res->mctx, fctx, sizeof(*fctx));
 
@@ -6236,6 +6286,8 @@ dns_resolver_create(dns_view_t *view,
 	res->badsweep = 0;
 	res->mustbesecure = NULL;
 
+	res->maxdepth = DEFAULT_RECURSION_DEPTH;
+	res->maxqueries = DEFAULT_MAX_QUERIES;
 	res->nbuckets = ntasks;
 	res->activebuckets = ntasks;
 	res->buckets = isc_mem_get(view->mctx,
@@ -6622,6 +6674,24 @@ dns_resolver_createfetch(dns_resolver_t
 			 dns_rdataset_t *sigrdataset,
 			 dns_fetch_t **fetchp)
 {
+	return (dns_resolver_createfetch3(res, name, type, domain,
+					  nameservers, forwarders,
+					  options, 0, NULL, task, action, arg,
+					  rdataset, sigrdataset, fetchp));
+}
+
+isc_result_t
+dns_resolver_createfetch3(dns_resolver_t *res, dns_name_t *name,
+			  dns_rdatatype_t type,
+			  dns_name_t *domain, dns_rdataset_t *nameservers,
+			  dns_forwarders_t *forwarders,
+			  unsigned int options, unsigned int depth,
+			  isc_counter_t *qc, isc_task_t *task,
+			  isc_taskaction_t action, void *arg,
+			  dns_rdataset_t *rdataset,
+			  dns_rdataset_t *sigrdataset,
+			  dns_fetch_t **fetchp)
+{
 	dns_fetch_t *fetch;
 	fetchctx_t *fctx = NULL;
 	isc_result_t result;
@@ -6684,11 +6754,12 @@ dns_resolver_createfetch(dns_resolver_t
 	    ISC_LIST_EMPTY(fctx->events)) {
 		fctx = NULL;
 		result = fctx_create(res, name, type, domain, nameservers,
-				     options, bucketnum, &fctx);
+				     options, bucketnum, depth, qc, &fctx);
 		if (result != ISC_R_SUCCESS)
 			goto unlock;
 		new_fctx = ISC_TRUE;
-	}
+	} else if (fctx->depth > depth)
+		fctx->depth = depth;
 
 	result = fctx_join(fctx, task, action, arg,
 			   rdataset, sigrdataset, fetch);
@@ -7341,3 +7412,27 @@ dns_resolver_getmustbesecure(dns_resolve
 #endif
 	return (value);
 }
+
+void
+dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth) {
+	REQUIRE(VALID_RESOLVER(resolver));
+	resolver->maxdepth = maxdepth;
+}
+
+unsigned int
+dns_resolver_getmaxdepth(dns_resolver_t *resolver) {
+	REQUIRE(VALID_RESOLVER(resolver));
+	return (resolver->maxdepth);
+}
+
+void
+dns_resolver_setmaxqueries(dns_resolver_t *resolver, unsigned int queries) {
+	REQUIRE(VALID_RESOLVER(resolver));
+	resolver->maxqueries = queries;
+}
+
+unsigned int
+dns_resolver_getmaxqueries(dns_resolver_t *resolver) {
+	REQUIRE(VALID_RESOLVER(resolver));
+	return (resolver->maxqueries);
+}
diff -up bind-9.3.6-P1/lib/isccfg/namedconf.c.CVE-2014-8500 bind-9.3.6-P1/lib/isccfg/namedconf.c
--- bind-9.3.6-P1/lib/isccfg/namedconf.c.CVE-2014-8500	2014-12-10 13:32:18.760869813 +0100
+++ bind-9.3.6-P1/lib/isccfg/namedconf.c	2014-12-10 13:32:18.962870280 +0100
@@ -772,6 +772,8 @@ view_clauses[] = {
 	{ "lame-ttl", &cfg_type_uint32, 0 },
 	{ "max-ncache-ttl", &cfg_type_uint32, 0 },
 	{ "max-cache-ttl", &cfg_type_uint32, 0 },
+	{ "max-recursion-depth", &cfg_type_uint32, 0 },
+	{ "max-recursion-queries", &cfg_type_uint32, 0 },
 	{ "transfer-format", &cfg_type_transferformat, 0 },
 	{ "max-cache-size", &cfg_type_sizenodefault, 0 },
 	{ "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
diff -up bind-9.3.6-P1/lib/isc/counter.c.CVE-2014-8500 bind-9.3.6-P1/lib/isc/counter.c
--- bind-9.3.6-P1/lib/isc/counter.c.CVE-2014-8500	2014-12-10 13:32:18.963870283 +0100
+++ bind-9.3.6-P1/lib/isc/counter.c	2014-12-10 13:32:18.963870283 +0100
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <stddef.h>
+
+#include <isc/counter.h>
+#include <isc/magic.h>
+#include <isc/mem.h>
+#include <isc/util.h>
+
+#define COUNTER_MAGIC			ISC_MAGIC('C', 'n', 't', 'r')
+#define VALID_COUNTER(r)		ISC_MAGIC_VALID(r, COUNTER_MAGIC)
+
+struct isc_counter {
+	unsigned int	magic;
+	isc_mem_t	*mctx;
+	isc_mutex_t	lock;
+	unsigned int	references;
+	unsigned int	limit;
+	unsigned int	used;
+};
+
+isc_result_t
+isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp) {
+	isc_result_t result;
+	isc_counter_t *counter;
+
+	REQUIRE(counterp != NULL && *counterp == NULL);
+
+	counter = isc_mem_get(mctx, sizeof(*counter));
+	if (counter == NULL)
+		return (ISC_R_NOMEMORY);
+
+	result = isc_mutex_init(&counter->lock);
+	if (result != ISC_R_SUCCESS) {
+		isc_mem_put(mctx, counter, sizeof(*counter));
+		return (result);
+	}
+
+	counter->mctx = NULL;
+	isc_mem_attach(mctx, &counter->mctx);
+
+	counter->references = 1;
+	counter->limit = limit;
+	counter->used = 0;
+
+	counter->magic = COUNTER_MAGIC;
+	*counterp = counter;
+	return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+isc_counter_increment(isc_counter_t *counter) {
+	isc_result_t result = ISC_R_SUCCESS;
+
+	LOCK(&counter->lock);
+	counter->used++;
+	if (counter->limit != 0 && counter->used >= counter->limit)
+		result = ISC_R_QUOTA;
+	UNLOCK(&counter->lock);
+
+	return (result);
+}
+
+unsigned int
+isc_counter_used(isc_counter_t *counter) {
+	REQUIRE(VALID_COUNTER(counter));
+
+	return (counter->used);
+}
+
+void
+isc_counter_setlimit(isc_counter_t *counter, int limit) {
+	REQUIRE(VALID_COUNTER(counter));
+
+	LOCK(&counter->lock);
+	counter->limit = limit;
+	UNLOCK(&counter->lock);
+}
+
+void
+isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp) {
+	REQUIRE(VALID_COUNTER(source));
+	REQUIRE(targetp != NULL && *targetp == NULL);
+
+	LOCK(&source->lock);
+	source->references++;
+	INSIST(source->references > 0);
+	UNLOCK(&source->lock);
+
+	*targetp = source;
+}
+
+static void
+destroy(isc_counter_t *counter) {
+	counter->magic = 0;
+	isc_mutex_destroy(&counter->lock);
+	isc_mem_putanddetach(&counter->mctx, counter, sizeof(*counter));
+}
+
+void
+isc_counter_detach(isc_counter_t **counterp) {
+	isc_counter_t *counter;
+	isc_boolean_t want_destroy = ISC_FALSE;
+
+	REQUIRE(counterp != NULL && *counterp != NULL);
+	counter = *counterp;
+	REQUIRE(VALID_COUNTER(counter));
+
+	*counterp = NULL;
+
+	LOCK(&counter->lock);
+	INSIST(counter->references > 0);
+	counter->references--;
+	if (counter->references == 0)
+		want_destroy = ISC_TRUE;
+	UNLOCK(&counter->lock);
+
+	if (want_destroy)
+		destroy(counter);
+}
diff -up bind-9.3.6-P1/lib/isc/include/isc/counter.h.CVE-2014-8500 bind-9.3.6-P1/lib/isc/include/isc/counter.h
--- bind-9.3.6-P1/lib/isc/include/isc/counter.h.CVE-2014-8500	2014-12-10 13:32:18.963870283 +0100
+++ bind-9.3.6-P1/lib/isc/include/isc/counter.h	2014-12-10 13:32:18.963870283 +0100
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ISC_COUNTER_H
+#define ISC_COUNTER_H 1
+
+/*****
+ ***** Module Info
+ *****/
+
+/*! \file isc/counter.h
+ *
+ * \brief The isc_counter_t object is a simplified version of the
+ * isc_quota_t object; it tracks the consumption of limited
+ * resources, returning an error condition when the quota is
+ * exceeded.  However, unlike isc_quota_t, attaching and detaching
+ * from a counter object does not increment or decrement the counter.
+ */
+
+/***
+ *** Imports.
+ ***/
+
+#include <isc/lang.h>
+#include <isc/mutex.h>
+#include <isc/types.h>
+
+/*****
+ ***** Types.
+ *****/
+
+ISC_LANG_BEGINDECLS
+
+isc_result_t
+isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp);
+/*%<
+ * Allocate and initialize a counter object.
+ */
+
+isc_result_t
+isc_counter_increment(isc_counter_t *counter);
+/*%<
+ * Increment the counter.
+ *
+ * If the counter limit is nonzero and has been reached, then
+ * return ISC_R_QUOTA, otherwise ISC_R_SUCCESS. (The counter is
+ * incremented regardless of return value.)
+ */
+
+unsigned int
+isc_counter_used(isc_counter_t *counter);
+/*%<
+ * Return the current counter value.
+ */
+
+void
+isc_counter_setlimit(isc_counter_t *counter, int limit);
+/*%<
+ * Set the counter limit.
+ */
+
+void
+isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp);
+/*%<
+ * Attach to a counter object, increasing its reference counter.
+ */
+
+void
+isc_counter_detach(isc_counter_t **counterp);
+/*%<
+ * Detach (and destroy if reference counter has dropped to zero)
+ * a counter object.
+ */
+
+ISC_LANG_ENDDECLS
+
+#endif /* ISC_COUNTER_H */
diff -up bind-9.3.6-P1/lib/isc/include/isc/Makefile.in.CVE-2014-8500 bind-9.3.6-P1/lib/isc/include/isc/Makefile.in
--- bind-9.3.6-P1/lib/isc/include/isc/Makefile.in.CVE-2014-8500	2005-03-22 03:32:07.000000000 +0100
+++ bind-9.3.6-P1/lib/isc/include/isc/Makefile.in	2014-12-10 13:32:18.963870283 +0100
@@ -27,7 +27,7 @@ top_srcdir =	@top_srcdir@
 # install target below.
 #
 HEADERS =	app.h assertions.h base64.h bitstring.h boolean.h buffer.h \
-		bufferlist.h commandline.h entropy.h error.h event.h \
+		bufferlist.h commandline.h counter.h entropy.h error.h event.h \
 		eventclass.h file.h formatcheck.h fsaccess.h \
 		hash.h heap.h hex.h hmacmd5.h \
 		interfaceiter.h @ISC_IPV6_H@ lang.h lex.h \
diff -up bind-9.3.6-P1/lib/isc/include/isc/types.h.CVE-2014-8500 bind-9.3.6-P1/lib/isc/include/isc/types.h
--- bind-9.3.6-P1/lib/isc/include/isc/types.h.CVE-2014-8500	2008-06-26 01:45:37.000000000 +0200
+++ bind-9.3.6-P1/lib/isc/include/isc/types.h	2014-12-10 13:32:18.963870283 +0100
@@ -46,6 +46,7 @@ typedef struct isc_buffer		isc_buffer_t;
 typedef ISC_LIST(isc_buffer_t)		isc_bufferlist_t;
 typedef struct isc_constregion		isc_constregion_t;
 typedef struct isc_consttextregion	isc_consttextregion_t;
+typedef struct isc_counter		isc_counter_t;		/*%< Counter */
 typedef struct isc_entropy		isc_entropy_t;
 typedef struct isc_entropysource	isc_entropysource_t;
 typedef struct isc_event		isc_event_t;
diff -up bind-9.3.6-P1/lib/isc/Makefile.in.CVE-2014-8500 bind-9.3.6-P1/lib/isc/Makefile.in
--- bind-9.3.6-P1/lib/isc/Makefile.in.CVE-2014-8500	2014-12-10 13:32:18.725869733 +0100
+++ bind-9.3.6-P1/lib/isc/Makefile.in	2014-12-10 13:32:18.964870285 +0100
@@ -51,7 +51,7 @@ WIN32OBJS = 	win32/condition.@O@ win32/d
 # Alphabetically
 OBJS =		@ISC_EXTRA_OBJS@ \
 		assertions.@O@ base64.@O@ bitstring.@O@ buffer.@O@ \
-		bufferlist.@O@ commandline.@O@ error.@O@ event.@O@ \
+		bufferlist.@O@ commandline.@O@ counter.@O@ error.@O@ event.@O@ \
 		hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ \
 		lex.@O@ lfsr.@O@ lib.@O@ log.@O@ md5.@O@ \
 		mem.@O@ mutexblock.@O@ netaddr.@O@ netscope.@O@ ondestroy.@O@ \
@@ -64,7 +64,7 @@ OBJS =		@ISC_EXTRA_OBJS@ \
 # Alphabetically
 SRCS =		@ISC_EXTRA_SRCS@ \
 		assertions.c base64.c bitstring.c buffer.c \
-		bufferlist.c commandline.c error.c event.c \
+		bufferlist.c commandline.c counter.c error.c event.c \
 		heap.c hex.c hmacmd5.c \
 		lex.c lfsr.c lib.c log.c \
 		md5.c mem.c mutexblock.c netaddr.c netscope.c ondestroy.c \
diff -up bind-9.3.6-P1/lib/isc/tests/counter_test.c.CVE-2014-8500 bind-9.3.6-P1/lib/isc/tests/counter_test.c
--- bind-9.3.6-P1/lib/isc/tests/counter_test.c.CVE-2014-8500	2014-12-10 13:32:18.964870285 +0100
+++ bind-9.3.6-P1/lib/isc/tests/counter_test.c	2014-12-10 13:32:18.964870285 +0100
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+#include <isc/counter.h>
+#include <isc/result.h>
+
+#include "isctest.h"
+
+ATF_TC(isc_counter);
+ATF_TC_HEAD(isc_counter, tc) {
+	atf_tc_set_md_var(tc, "descr", "isc counter object");
+}
+ATF_TC_BODY(isc_counter, tc) {
+	isc_result_t result;
+	isc_counter_t *counter = NULL;
+	int i;
+
+	result = isc_test_begin(NULL, ISC_TRUE);
+	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+	result = isc_counter_create(mctx, 0, &counter);
+	ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+	for (i = 0; i < 10; i++) {
+		result = isc_counter_increment(counter);
+		ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+	}
+
+	ATF_CHECK_EQ(isc_counter_used(counter), 10);
+
+	isc_counter_setlimit(counter, 15);
+	for (i = 0; i < 10; i++) {
+		result = isc_counter_increment(counter);
+		if (result != ISC_R_SUCCESS)
+			break;
+	}
+
+	ATF_CHECK_EQ(isc_counter_used(counter), 15);
+
+	isc_counter_detach(&counter);
+	isc_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+	ATF_TP_ADD_TC(tp, isc_counter);
+	return (atf_no_error());
+}
+