Blame SOURCES/bind99-CVE-2014-8500.patch

5c48e4
diff -up bind-9.9.4/bin/named/config.c.CVE-2014-8500 bind-9.9.4/bin/named/config.c
5c48e4
--- bind-9.9.4/bin/named/config.c.CVE-2014-8500	2013-09-05 07:09:08.000000000 +0200
5c48e4
+++ bind-9.9.4/bin/named/config.c	2014-12-10 14:56:24.959552559 +0100
5c48e4
@@ -160,6 +160,8 @@ options {\n\
5c48e4
 	dnssec-accept-expired no;\n\
5c48e4
 	clients-per-query 10;\n\
5c48e4
 	max-clients-per-query 100;\n\
5c48e4
+	max-recursion-depth 7;\n\
5c48e4
+	max-recursion-queries 50;\n\
5c48e4
 	zero-no-soa-ttl-cache no;\n\
5c48e4
 	nsec3-test-zone no;\n\
5c48e4
 	allow-new-zones no;\n\
5c48e4
diff -up bind-9.9.4/bin/named/query.c.CVE-2014-8500 bind-9.9.4/bin/named/query.c
5c48e4
--- bind-9.9.4/bin/named/query.c.CVE-2014-8500	2014-12-10 14:56:24.945552543 +0100
5c48e4
+++ bind-9.9.4/bin/named/query.c	2014-12-10 14:56:24.960552560 +0100
5c48e4
@@ -3872,12 +3872,11 @@ query_recurse(ns_client_t *client, dns_r
5c48e4
 		peeraddr = &client->peeraddr;
5c48e4
 	else
5c48e4
 		peeraddr = NULL;
5c48e4
-	result = dns_resolver_createfetch2(client->view->resolver,
5c48e4
+	result = dns_resolver_createfetch3(client->view->resolver,
5c48e4
 					   qname, qtype, qdomain, nameservers,
5c48e4
 					   NULL, peeraddr, client->message->id,
5c48e4
-					   client->query.fetchoptions,
5c48e4
-					   client->task,
5c48e4
-					   query_resume, client,
5c48e4
+					   client->query.fetchoptions, 0, NULL,
5c48e4
+					   client->task, query_resume, client,
5c48e4
 					   rdataset, sigrdataset,
5c48e4
 					   &client->query.fetch);
5c48e4
 
5c48e4
diff -up bind-9.9.4/bin/named/server.c.CVE-2014-8500 bind-9.9.4/bin/named/server.c
5c48e4
--- bind-9.9.4/bin/named/server.c.CVE-2014-8500	2014-12-10 14:56:24.913552507 +0100
5c48e4
+++ bind-9.9.4/bin/named/server.c	2014-12-10 14:56:24.961552561 +0100
5c48e4
@@ -3205,6 +3205,16 @@ configure_view(dns_view_t *view, cfg_obj
5c48e4
 					cfg_obj_asuint32(obj),
5c48e4
 					max_clients_per_query);
5c48e4
 
5c48e4
+	obj = NULL;
5c48e4
+	result = ns_config_get(maps, "max-recursion-depth", &obj);
5c48e4
+	INSIST(result == ISC_R_SUCCESS);
5c48e4
+	dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
5c48e4
+
5c48e4
+	obj = NULL;
5c48e4
+	result = ns_config_get(maps, "max-recursion-queries", &obj);
5c48e4
+	INSIST(result == ISC_R_SUCCESS);
5c48e4
+	dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
5c48e4
+
5c48e4
 #ifdef ALLOW_FILTER_AAAA_ON_V4
5c48e4
 	obj = NULL;
5c48e4
 	result = ns_config_get(maps, "filter-aaaa-on-v4", &obj);
5c48e4
diff -up bind-9.9.4/doc/arm/Bv9ARM-book.xml.CVE-2014-8500 bind-9.9.4/doc/arm/Bv9ARM-book.xml
5c48e4
--- bind-9.9.4/doc/arm/Bv9ARM-book.xml.CVE-2014-8500	2014-12-10 14:56:24.957552556 +0100
5c48e4
+++ bind-9.9.4/doc/arm/Bv9ARM-book.xml	2014-12-10 15:00:53.108931629 +0100
5c48e4
@@ -4874,6 +4874,8 @@ badresp:1,adberr:0,findfail:0,valfail:0]
5c48e4
     <optional> max-acache-size <replaceable>size_spec</replaceable> ; </optional>
5c48e4
     <optional> clients-per-query <replaceable>number</replaceable> ; </optional>
5c48e4
     <optional> max-clients-per-query <replaceable>number</replaceable> ; </optional>
5c48e4
+    <optional> max-recursion-depth <replaceable>number</replaceable> ; </optional>
5c48e4
+    <optional> max-recursion-queries <replaceable>number</replaceable> ; </optional>
5c48e4
     <optional> masterfile-format (<constant>text</constant>|<constant>raw</constant>) ; </optional>
5c48e4
     <optional> empty-server <replaceable>name</replaceable> ; </optional>
5c48e4
     <optional> empty-contact <replaceable>name</replaceable> ; </optional>
5c48e4
@@ -8623,6 +8625,35 @@ avoid-v6-udp-ports { 40000; range 50000
5c48e4
 		</para>
5c48e4
               </listitem>
5c48e4
 	    </varlistentry>
5c48e4
+        
5c48e4
+	    <varlistentry id="max-recursion-depth">
5c48e4
+	      <term><command>max-recursion-depth</command></term>
5c48e4
+	      <listitem>
5c48e4
+		<para>
5c48e4
+		  Sets the maximum number of levels of recursion
5c48e4
+		  that are permitted at any one time while servicing
5c48e4
+		  a recursive query. Resolving a name may require
5c48e4
+		  looking up a name server address, which in turn
5c48e4
+		  requires resolving another name, etc; if the number
5c48e4
+		  of indirections exceeds this value, the recursive
5c48e4
+		  query is terminated and returns SERVFAIL.  The
5c48e4
+		  default is 7.
5c48e4
+		</para>
5c48e4
+	      </listitem>
5c48e4
+	    </varlistentry>
5c48e4
+
5c48e4
+	    <varlistentry id="max-recursion-queries">
5c48e4
+	      <term><command>max-recursion-queries</command></term>
5c48e4
+	      <listitem>
5c48e4
+		<para>
5c48e4
+		  Sets the maximum number of iterative queries that
5c48e4
+		  may be sent while servicing a recursive query.
5c48e4
+		  If more queries are sent, the recursive query
5c48e4
+		  is terminated and returns SERVFAIL. The default
5c48e4
+		  is 50.
5c48e4
+		</para>
5c48e4
+	      </listitem>
5c48e4
+	    </varlistentry>
5c48e4
 
5c48e4
             <varlistentry>
5c48e4
               <term><command>notify-delay</command></term>
5c48e4
diff -up bind-9.9.4/doc/misc/options.CVE-2014-8500 bind-9.9.4/doc/misc/options
5c48e4
--- bind-9.9.4/doc/misc/options.CVE-2014-8500	2013-09-05 07:09:08.000000000 +0200
5c48e4
+++ bind-9.9.4/doc/misc/options	2014-12-10 14:56:24.964552564 +0100
5c48e4
@@ -162,6 +162,8 @@ options {
5c48e4
         max-ixfr-log-size <size>; // obsolete
5c48e4
         max-journal-size <size_no_default>;
5c48e4
         max-ncache-ttl <integer>;
5c48e4
+        max-recursion-depth <integer>;
5c48e4
+        max-recursion-queries <integer>;
5c48e4
         max-refresh-time <integer>;
5c48e4
         max-retry-time <integer>;
5c48e4
         max-rsa-exponent-size <integer>;
5c48e4
@@ -385,6 +387,8 @@ view <string> <optional_class> {
5c48e4
         max-ixfr-log-size <size>; // obsolete
5c48e4
         max-journal-size <size_no_default>;
5c48e4
         max-ncache-ttl <integer>;
5c48e4
+        max-recursion-depth <integer>;
5c48e4
+        max-recursion-queries <integer>;
5c48e4
         max-refresh-time <integer>;
5c48e4
         max-retry-time <integer>;
5c48e4
         max-transfer-idle-in <integer>;
5c48e4
diff -up bind-9.9.4/lib/dns/adb.c.CVE-2014-8500 bind-9.9.4/lib/dns/adb.c
5c48e4
--- bind-9.9.4/lib/dns/adb.c.CVE-2014-8500	2013-09-05 07:09:08.000000000 +0200
5c48e4
+++ bind-9.9.4/lib/dns/adb.c	2014-12-10 14:56:24.965552566 +0100
5c48e4
@@ -201,6 +201,7 @@ struct dns_adbfetch {
5c48e4
 	unsigned int                    magic;
5c48e4
 	dns_fetch_t                    *fetch;
5c48e4
 	dns_rdataset_t                  rdataset;
5c48e4
+	unsigned int			depth;
5c48e4
 };
5c48e4
 
5c48e4
 /*%
5c48e4
@@ -300,8 +301,7 @@ static inline isc_boolean_t dec_entry_re
5c48e4
 static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
5c48e4
 static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
5c48e4
 static void clean_target(dns_adb_t *, dns_name_t *);
5c48e4
-static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
5c48e4
-				unsigned int);
5c48e4
+static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, unsigned int);
5c48e4
 static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
5c48e4
 static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **,
5c48e4
 					isc_stdtime_t);
5c48e4
@@ -309,6 +309,7 @@ static void cancel_fetches_at_name(dns_a
5c48e4
 static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
5c48e4
 				dns_rdatatype_t);
5c48e4
 static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
5c48e4
+			       unsigned int, isc_counter_t *qc,
5c48e4
 			       dns_rdatatype_t);
5c48e4
 static inline void check_exit(dns_adb_t *);
5c48e4
 static void destroy(dns_adb_t *);
5c48e4
@@ -2770,6 +2771,19 @@ dns_adb_createfind(dns_adb_t *adb, isc_t
5c48e4
 		   isc_stdtime_t now, dns_name_t *target,
5c48e4
 		   in_port_t port, dns_adbfind_t **findp)
5c48e4
 {
5c48e4
+	return (dns_adb_createfind2(adb, task, action, arg, name,
5c48e4
+				    qname, qtype, options, now,
5c48e4
+				    target, port, 0, NULL, findp));
5c48e4
+}
5c48e4
+
5c48e4
+isc_result_t
5c48e4
+dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
5c48e4
+		    void *arg, dns_name_t *name, dns_name_t *qname,
5c48e4
+		    dns_rdatatype_t qtype, unsigned int options,
5c48e4
+		    isc_stdtime_t now, dns_name_t *target,
5c48e4
+		    in_port_t port, unsigned int depth, isc_counter_t *qc,
5c48e4
+		    dns_adbfind_t **findp)
5c48e4
+{
5c48e4
 	dns_adbfind_t *find;
5c48e4
 	dns_adbname_t *adbname;
5c48e4
 	int bucket;
5c48e4
@@ -3000,7 +3014,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_t
5c48e4
 		 * Start V4.
5c48e4
 		 */
5c48e4
 		if (WANT_INET(wanted_fetches) &&
5c48e4
-		    fetch_name(adbname, start_at_zone,
5c48e4
+		    fetch_name(adbname, start_at_zone, depth, qc,
5c48e4
 			       dns_rdatatype_a) == ISC_R_SUCCESS) {
5c48e4
 			DP(DEF_LEVEL,
5c48e4
 			   "dns_adb_createfind: started A fetch for name %p",
5c48e4
@@ -3011,7 +3025,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_t
5c48e4
 		 * Start V6.
5c48e4
 		 */
5c48e4
 		if (WANT_INET6(wanted_fetches) &&
5c48e4
-		    fetch_name(adbname, start_at_zone,
5c48e4
+		    fetch_name(adbname, start_at_zone, depth, qc,
5c48e4
 			       dns_rdatatype_aaaa) == ISC_R_SUCCESS) {
5c48e4
 			DP(DEF_LEVEL,
5c48e4
 			   "dns_adb_createfind: "
5c48e4
@@ -3754,6 +3768,12 @@ fetch_callback(isc_task_t *task, isc_eve
5c48e4
 		DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s",
5c48e4
 		   buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA",
5c48e4
 		   dns_result_totext(dev->result));
5c48e4
+		/*
5c48e4
+		 * Don't record a failure unless this is the initial
5c48e4
+		 * fetch of a chain.
5c48e4
+		 */
5c48e4
+		if (fetch->depth > 1)
5c48e4
+			goto out;
5c48e4
 		/* XXXMLG Don't pound on bad servers. */
5c48e4
 		if (address_type == DNS_ADBFIND_INET) {
5c48e4
 			name->expire_v4 = ISC_MIN(name->expire_v4, now + 300);
5c48e4
@@ -3791,9 +3811,8 @@ fetch_callback(isc_task_t *task, isc_eve
5c48e4
 }
5c48e4
 
5c48e4
 static isc_result_t
5c48e4
-fetch_name(dns_adbname_t *adbname,
5c48e4
-	   isc_boolean_t start_at_zone,
5c48e4
-	   dns_rdatatype_t type)
5c48e4
+fetch_name(dns_adbname_t *adbname, isc_boolean_t start_at_zone,
5c48e4
+	   unsigned int depth, isc_counter_t *qc, dns_rdatatype_t type)
5c48e4
 {
5c48e4
 	isc_result_t result;
5c48e4
 	dns_adbfetch_t *fetch = NULL;
5c48e4
@@ -3838,12 +3857,14 @@ fetch_name(dns_adbname_t *adbname,
5c48e4
 		result = ISC_R_NOMEMORY;
5c48e4
 		goto cleanup;
5c48e4
 	}
5c48e4
+	fetch->depth = depth;
5c48e4
 
5c48e4
-	result = dns_resolver_createfetch(adb->view->resolver, &adbname->name,
5c48e4
-					  type, name, nameservers, NULL,
5c48e4
-					  options, adb->task, fetch_callback,
5c48e4
-					  adbname, &fetch->rdataset, NULL,
5c48e4
-					  &fetch->fetch);
5c48e4
+	result = dns_resolver_createfetch3(adb->view->resolver, &adbname->name,
5c48e4
+					   type, name, nameservers, NULL,
5c48e4
+					   NULL, 0, options, depth, qc,
5c48e4
+					   adb->task, fetch_callback, adbname,
5c48e4
+					   &fetch->rdataset, NULL,
5c48e4
+					   &fetch->fetch);
5c48e4
 	if (result != ISC_R_SUCCESS)
5c48e4
 		goto cleanup;
5c48e4
 
5c48e4
diff -up bind-9.9.4/lib/dns/include/dns/adb.h.CVE-2014-8500 bind-9.9.4/lib/dns/include/dns/adb.h
5c48e4
--- bind-9.9.4/lib/dns/include/dns/adb.h.CVE-2014-8500	2013-09-05 07:09:08.000000000 +0200
5c48e4
+++ bind-9.9.4/lib/dns/include/dns/adb.h	2014-12-10 14:56:24.965552566 +0100
5c48e4
@@ -334,6 +334,13 @@ dns_adb_createfind(dns_adb_t *adb, isc_t
5c48e4
 		   dns_rdatatype_t qtype, unsigned int options,
5c48e4
 		   isc_stdtime_t now, dns_name_t *target,
5c48e4
 		   in_port_t port, dns_adbfind_t **find);
5c48e4
+isc_result_t
5c48e4
+dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
5c48e4
+		    void *arg, dns_name_t *name, dns_name_t *qname,
5c48e4
+		    dns_rdatatype_t qtype, unsigned int options,
5c48e4
+		    isc_stdtime_t now, dns_name_t *target, in_port_t port,
5c48e4
+		    unsigned int depth, isc_counter_t *qc,
5c48e4
+		    dns_adbfind_t **find);
5c48e4
 /*%<
5c48e4
  * Main interface for clients. The adb will look up the name given in
5c48e4
  * "name" and will build up a list of found addresses, and perhaps start
5c48e4
diff -up bind-9.9.4/lib/dns/include/dns/resolver.h.CVE-2014-8500 bind-9.9.4/lib/dns/include/dns/resolver.h
5c48e4
--- bind-9.9.4/lib/dns/include/dns/resolver.h.CVE-2014-8500	2013-09-05 07:09:08.000000000 +0200
5c48e4
+++ bind-9.9.4/lib/dns/include/dns/resolver.h	2014-12-10 14:56:24.965552566 +0100
5c48e4
@@ -274,6 +274,18 @@ dns_resolver_createfetch2(dns_resolver_t
5c48e4
 			  dns_rdataset_t *rdataset,
5c48e4
 			  dns_rdataset_t *sigrdataset,
5c48e4
 			  dns_fetch_t **fetchp);
5c48e4
+isc_result_t
5c48e4
+dns_resolver_createfetch3(dns_resolver_t *res, dns_name_t *name,
5c48e4
+			  dns_rdatatype_t type,
5c48e4
+			  dns_name_t *domain, dns_rdataset_t *nameservers,
5c48e4
+			  dns_forwarders_t *forwarders,
5c48e4
+			  isc_sockaddr_t *client, isc_uint16_t id,
5c48e4
+			  unsigned int options, unsigned int depth,
5c48e4
+			  isc_counter_t *qc, isc_task_t *task,
5c48e4
+			  isc_taskaction_t action, void *arg,
5c48e4
+			  dns_rdataset_t *rdataset,
5c48e4
+			  dns_rdataset_t *sigrdataset,
5c48e4
+			  dns_fetch_t **fetchp);
5c48e4
 /*%<
5c48e4
  * Recurse to answer a question.
5c48e4
  *
5c48e4
@@ -573,6 +585,30 @@ dns_resolver_printbadcache(dns_resolver_
5c48e4
  *
5c48e4
  * Requires:
5c48e4
  * \li	resolver to be valid.
5c48e4
+ */
5c48e4
+
5c48e4
+void
5c48e4
+dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth);
5c48e4
+unsigned int
5c48e4
+dns_resolver_getmaxdepth(dns_resolver_t *resolver);
5c48e4
+/*%
5c48e4
+ * Get and set how many NS indirections will be followed when looking for
5c48e4
+ * nameserver addresses.
5c48e4
+ *
5c48e4
+ * Requires:
5c48e4
+ * \li	resolver to be valid.
5c48e4
+ */
5c48e4
+
5c48e4
+void
5c48e4
+dns_resolver_setmaxqueries(dns_resolver_t *resolver, unsigned int queries);
5c48e4
+unsigned int
5c48e4
+dns_resolver_getmaxqueries(dns_resolver_t *resolver);
5c48e4
+/*%
5c48e4
+ * Get and set how many iterative queries will be allowed before
5c48e4
+ * terminating a recursive query.
5c48e4
+ *
5c48e4
+ * Requires:
5c48e4
+ * \li	resolver to be valid.
5c48e4
  */
5c48e4
 
5c48e4
 ISC_LANG_ENDDECLS
5c48e4
diff -up bind-9.9.4/lib/dns/resolver.c.CVE-2014-8500 bind-9.9.4/lib/dns/resolver.c
5c48e4
--- bind-9.9.4/lib/dns/resolver.c.CVE-2014-8500	2014-12-10 14:56:24.952552551 +0100
5c48e4
+++ bind-9.9.4/lib/dns/resolver.c	2014-12-10 15:01:56.855970646 +0100
5c48e4
@@ -21,6 +21,7 @@
5c48e4
 
5c48e4
 #include <config.h>
5c48e4
 
5c48e4
+#include <isc/counter.h>
5c48e4
 #include <isc/log.h>
5c48e4
 #include <isc/platform.h>
5c48e4
 #include <isc/print.h>
5c48e4
@@ -130,6 +131,16 @@
5c48e4
 #define MAXIMUM_QUERY_TIMEOUT 30 /* The maximum time in seconds for the whole query to live. */
5c48e4
 #endif
5c48e4
 
5c48e4
+/* The default maximum number of recursions to follow before giving up. */
5c48e4
+#ifndef DEFAULT_RECURSION_DEPTH
5c48e4
+#define DEFAULT_RECURSION_DEPTH 7
5c48e4
+#endif
5c48e4
+
5c48e4
+/* The default maximum number of iterative queries to allow before giving up. */
5c48e4
+#ifndef DEFAULT_MAX_QUERIES
5c48e4
+#define DEFAULT_MAX_QUERIES 50
5c48e4
+#endif
5c48e4
+
5c48e4
 /*%
5c48e4
  * Maximum EDNS0 input packet size.
5c48e4
  */
5c48e4
@@ -233,12 +244,13 @@ struct fetchctx {
5c48e4
 	isc_sockaddrlist_t		edns;
5c48e4
 	isc_sockaddrlist_t		edns512;
5c48e4
 	isc_sockaddrlist_t		bad_edns;
5c48e4
-	dns_validator_t			*validator;
5c48e4
+	dns_validator_t *		validator;
5c48e4
 	ISC_LIST(dns_validator_t)       validators;
5c48e4
 	dns_db_t *			cache;
5c48e4
 	dns_adb_t *			adb;
5c48e4
 	isc_boolean_t			ns_ttl_ok;
5c48e4
 	isc_uint32_t			ns_ttl;
5c48e4
+	isc_counter_t *			qc;
5c48e4
 
5c48e4
 	/*%
5c48e4
 	 * The number of events we're waiting for.
5c48e4
@@ -306,6 +318,7 @@ struct fetchctx {
5c48e4
 	isc_boolean_t			timeout;
5c48e4
 	dns_adbaddrinfo_t 		*addrinfo;
5c48e4
 	isc_sockaddr_t			*client;
5c48e4
+	unsigned int			depth;
5c48e4
 };
5c48e4
 
5c48e4
 #define FCTX_MAGIC			ISC_MAGIC('F', '!', '!', '!')
5c48e4
@@ -418,6 +431,8 @@ struct dns_resolver {
5c48e4
 	isc_timer_t *			spillattimer;
5c48e4
 	isc_boolean_t			zero_no_soa_ttl;
5c48e4
 	unsigned int			query_timeout;
5c48e4
+	unsigned int			maxdepth;
5c48e4
+	unsigned int			maxqueries;
5c48e4
 
5c48e4
 	/* Locked by lock. */
5c48e4
 	unsigned int			references;
5c48e4
@@ -1533,6 +1548,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddr
5c48e4
 		if (result != ISC_R_SUCCESS)
5c48e4
 			goto cleanup_dispatch;
5c48e4
 	}
5c48e4
+
5c48e4
 	fctx->querysent++;
5c48e4
 
5c48e4
 	ISC_LIST_APPEND(fctx->queries, query, link);
5c48e4
@@ -2186,9 +2202,9 @@ fctx_finddone(isc_task_t *task, isc_even
5c48e4
 		 */
5c48e4
 		INSIST(!SHUTTINGDOWN(fctx));
5c48e4
 		fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
5c48e4
-		if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES)
5c48e4
+		if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES) {
5c48e4
 			want_try = ISC_TRUE;
5c48e4
-		else {
5c48e4
+		} else {
5c48e4
 			fctx->findfail++;
5c48e4
 			if (fctx->pending == 0) {
5c48e4
 				/*
5c48e4
@@ -2471,12 +2487,13 @@ findname(fetchctx_t *fctx, dns_name_t *n
5c48e4
 	 * See what we know about this address.
5c48e4
 	 */
5c48e4
 	find = NULL;
5c48e4
-	result = dns_adb_createfind(fctx->adb,
5c48e4
-				    res->buckets[fctx->bucketnum].task,
5c48e4
-				    fctx_finddone, fctx, name,
5c48e4
-				    &fctx->name, fctx->type,
5c48e4
-				    options, now, NULL,
5c48e4
-				    res->view->dstport, &find);
5c48e4
+	result = dns_adb_createfind2(fctx->adb,
5c48e4
+				     res->buckets[fctx->bucketnum].task,
5c48e4
+				     fctx_finddone, fctx, name,
5c48e4
+				     &fctx->name, fctx->type,
5c48e4
+				     options, now, NULL,
5c48e4
+				     res->view->dstport,
5c48e4
+				     fctx->depth + 1, fctx->qc, &find);
5c48e4
 	if (result != ISC_R_SUCCESS) {
5c48e4
 		if (result == DNS_R_ALIAS) {
5c48e4
 			/*
5c48e4
@@ -2584,6 +2601,14 @@ fctx_getaddresses(fetchctx_t *fctx, isc_
5c48e4
 
5c48e4
 	res = fctx->res;
5c48e4
 
5c48e4
+	if (fctx->depth > res->maxdepth) {
5c48e4
+		isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
5c48e4
+			      DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
5c48e4
+			      "too much NS indirection resolving '%s'",
5c48e4
+			      fctx->info);
5c48e4
+		return (DNS_R_SERVFAIL);
5c48e4
+	}
5c48e4
+
5c48e4
 	/*
5c48e4
 	 * Forwarders.
5c48e4
 	 */
5c48e4
@@ -3059,6 +3084,16 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t
5c48e4
 		}
5c48e4
 	}
5c48e4
 
5c48e4
+	result = isc_counter_increment(fctx->qc);
5c48e4
+	if (result != ISC_R_SUCCESS) {
5c48e4
+		isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
5c48e4
+			      DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3),
5c48e4
+			      "exceeded max queries resolving '%s'",
5c48e4
+			      fctx->info);
5c48e4
+		fctx_done(fctx, DNS_R_SERVFAIL, __LINE__);
5c48e4
+		return;
5c48e4
+	}
5c48e4
+
5c48e4
 	result = fctx_query(fctx, addrinfo, fctx->options);
5c48e4
 	if (result != ISC_R_SUCCESS)
5c48e4
 		fctx_done(fctx, result, __LINE__);
5c48e4
@@ -3157,6 +3192,7 @@ fctx_destroy(fetchctx_t *fctx) {
5c48e4
 		isc_mem_put(fctx->mctx, sa, sizeof(*sa));
5c48e4
 	}
5c48e4
 
5c48e4
+	isc_counter_detach(&fctx->qc);
5c48e4
 	isc_timer_detach(&fctx->timer);
5c48e4
 	dns_message_destroy(&fctx->rmessage);
5c48e4
 	dns_message_destroy(&fctx->qmessage);
5c48e4
@@ -3485,7 +3521,8 @@ log_ns_ttl(fetchctx_t *fctx, const char
5c48e4
 static isc_result_t
5c48e4
 fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
5c48e4
 	    dns_name_t *domain, dns_rdataset_t *nameservers,
5c48e4
-	    unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp)
5c48e4
+	    unsigned int options, unsigned int bucketnum, unsigned int depth,
5c48e4
+	    isc_counter_t *qc, fetchctx_t **fctxp)
5c48e4
 {
5c48e4
 	fetchctx_t *fctx;
5c48e4
 	isc_result_t result;
5c48e4
@@ -3507,6 +3544,21 @@ fctx_create(dns_resolver_t *res, dns_nam
5c48e4
 	fctx = isc_mem_get(mctx, sizeof(*fctx));
5c48e4
 	if (fctx == NULL)
5c48e4
 		return (ISC_R_NOMEMORY);
5c48e4
+
5c48e4
+	fctx->qc = NULL;
5c48e4
+	if (qc != NULL) {
5c48e4
+		isc_counter_attach(qc, &fctx->qc);
5c48e4
+	} else {
5c48e4
+		result = isc_counter_create(res->mctx,
5c48e4
+					    res->maxqueries, &fctx->qc);
5c48e4
+		if (result != ISC_R_SUCCESS)
5c48e4
+			goto cleanup_fetch;
5c48e4
+	}
5c48e4
+
5c48e4
+	/*
5c48e4
+	 * Make fctx->info point to a copy of a formatted string
5c48e4
+	 * "name/type".
5c48e4
+	 */
5c48e4
 	dns_name_format(name, buf, sizeof(buf));
5c48e4
 	dns_rdatatype_format(type, typebuf, sizeof(typebuf));
5c48e4
 	strcat(buf, "/");       /* checked */
5c48e4
@@ -3514,7 +3566,7 @@ fctx_create(dns_resolver_t *res, dns_nam
5c48e4
 	fctx->info = isc_mem_strdup(mctx, buf);
5c48e4
 	if (fctx->info == NULL) {
5c48e4
 		result = ISC_R_NOMEMORY;
5c48e4
-		goto cleanup_fetch;
5c48e4
+		goto cleanup_counter;
5c48e4
 	}
5c48e4
 	FCTXTRACE("create");
5c48e4
 	dns_name_init(&fctx->name, NULL);
5c48e4
@@ -3537,6 +3589,7 @@ fctx_create(dns_resolver_t *res, dns_nam
5c48e4
 	fctx->state = fetchstate_init;
5c48e4
 	fctx->want_shutdown = ISC_FALSE;
5c48e4
 	fctx->cloned = ISC_FALSE;
5c48e4
+	fctx->depth = depth;
5c48e4
 	ISC_LIST_INIT(fctx->queries);
5c48e4
 	ISC_LIST_INIT(fctx->finds);
5c48e4
 	ISC_LIST_INIT(fctx->altfinds);
5c48e4
@@ -3742,6 +3795,9 @@ fctx_create(dns_resolver_t *res, dns_nam
5c48e4
  cleanup_info:
5c48e4
 	isc_mem_free(mctx, fctx->info);
5c48e4
 
5c48e4
+ cleanup_counter:
5c48e4
+	isc_counter_detach(&fctx->qc);
5c48e4
+
5c48e4
  cleanup_fetch:
5c48e4
 	isc_mem_put(mctx, fctx, sizeof(*fctx));
5c48e4
 
5c48e4
@@ -5655,7 +5711,7 @@ noanswer_response(fetchctx_t *fctx, dns_
5c48e4
 					char qbuf[DNS_NAME_FORMATSIZE];
5c48e4
 					char nbuf[DNS_NAME_FORMATSIZE];
5c48e4
 					char tbuf[DNS_RDATATYPE_FORMATSIZE];
5c48e4
-					dns_rdatatype_format(fctx->type, tbuf,
5c48e4
+					dns_rdatatype_format(type, tbuf,
5c48e4
 							     sizeof(tbuf));
5c48e4
 					dns_name_format(name, nbuf,
5c48e4
 							     sizeof(nbuf));
5c48e4
@@ -5664,7 +5720,7 @@ noanswer_response(fetchctx_t *fctx, dns_
5c48e4
 					log_formerr(fctx,
5c48e4
 						    "unrelated %s %s in "
5c48e4
 						    "%s authority section",
5c48e4
-						    tbuf, qbuf, nbuf);
5c48e4
+						    tbuf, nbuf, qbuf);
5c48e4
 					return (DNS_R_FORMERR);
5c48e4
 				}
5c48e4
 				if (type == dns_rdatatype_ns) {
5c48e4
@@ -7725,6 +7781,8 @@ dns_resolver_create(dns_view_t *view,
5c48e4
 	res->spillattimer = NULL;
5c48e4
 	res->zero_no_soa_ttl = ISC_FALSE;
5c48e4
 	res->query_timeout = DEFAULT_QUERY_TIMEOUT;
5c48e4
+	res->maxdepth = DEFAULT_RECURSION_DEPTH;
5c48e4
+	res->maxqueries = DEFAULT_MAX_QUERIES;
5c48e4
 	res->nbuckets = ntasks;
5c48e4
 	res->activebuckets = ntasks;
5c48e4
 	res->buckets = isc_mem_get(view->mctx,
5c48e4
@@ -8163,9 +8221,9 @@ dns_resolver_createfetch(dns_resolver_t
5c48e4
 			 dns_rdataset_t *sigrdataset,
5c48e4
 			 dns_fetch_t **fetchp)
5c48e4
 {
5c48e4
-	return (dns_resolver_createfetch2(res, name, type, domain,
5c48e4
+	return (dns_resolver_createfetch3(res, name, type, domain,
5c48e4
 					  nameservers, forwarders, NULL, 0,
5c48e4
-					  options, task, action, arg,
5c48e4
+					  options, 0, NULL, task, action, arg,
5c48e4
 					  rdataset, sigrdataset, fetchp));
5c48e4
 }
5c48e4
 
5c48e4
@@ -8181,6 +8239,25 @@ dns_resolver_createfetch2(dns_resolver_t
5c48e4
 			  dns_rdataset_t *sigrdataset,
5c48e4
 			  dns_fetch_t **fetchp)
5c48e4
 {
5c48e4
+	return (dns_resolver_createfetch3(res, name, type, domain,
5c48e4
+					  nameservers, forwarders, client, id,
5c48e4
+					  options, 0, NULL, task, action, arg,
5c48e4
+					  rdataset, sigrdataset, fetchp));
5c48e4
+}
5c48e4
+
5c48e4
+isc_result_t
5c48e4
+dns_resolver_createfetch3(dns_resolver_t *res, dns_name_t *name,
5c48e4
+			  dns_rdatatype_t type,
5c48e4
+			  dns_name_t *domain, dns_rdataset_t *nameservers,
5c48e4
+			  dns_forwarders_t *forwarders,
5c48e4
+			  isc_sockaddr_t *client, dns_messageid_t id,
5c48e4
+			  unsigned int options, unsigned int depth,
5c48e4
+			  isc_counter_t *qc, isc_task_t *task,
5c48e4
+			  isc_taskaction_t action, void *arg,
5c48e4
+			  dns_rdataset_t *rdataset,
5c48e4
+			  dns_rdataset_t *sigrdataset,
5c48e4
+			  dns_fetch_t **fetchp)
5c48e4
+{
5c48e4
 	dns_fetch_t *fetch;
5c48e4
 	fetchctx_t *fctx = NULL;
5c48e4
 	isc_result_t result = ISC_R_SUCCESS;
5c48e4
@@ -8269,11 +8346,12 @@ dns_resolver_createfetch2(dns_resolver_t
5c48e4
 
5c48e4
 	if (fctx == NULL) {
5c48e4
 		result = fctx_create(res, name, type, domain, nameservers,
5c48e4
-				     options, bucketnum, &fctx);
5c48e4
+				     options, bucketnum, depth, qc, &fctx);
5c48e4
 		if (result != ISC_R_SUCCESS)
5c48e4
 			goto unlock;
5c48e4
 		new_fctx = ISC_TRUE;
5c48e4
-	}
5c48e4
+	} else if (fctx->depth > depth)
5c48e4
+		fctx->depth = depth;
5c48e4
 
5c48e4
 	result = fctx_join(fctx, task, client, id, action, arg,
5c48e4
 			   rdataset, sigrdataset, fetch);
5c48e4
@@ -9045,3 +9123,27 @@ dns_resolver_settimeout(dns_resolver_t *
5c48e4
 
5c48e4
 	resolver->query_timeout = seconds;
5c48e4
 }
5c48e4
+
5c48e4
+void
5c48e4
+dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth) {
5c48e4
+	REQUIRE(VALID_RESOLVER(resolver));
5c48e4
+	resolver->maxdepth = maxdepth;
5c48e4
+}
5c48e4
+
5c48e4
+unsigned int
5c48e4
+dns_resolver_getmaxdepth(dns_resolver_t *resolver) {
5c48e4
+	REQUIRE(VALID_RESOLVER(resolver));
5c48e4
+	return (resolver->maxdepth);
5c48e4
+}
5c48e4
+
5c48e4
+void
5c48e4
+dns_resolver_setmaxqueries(dns_resolver_t *resolver, unsigned int queries) {
5c48e4
+	REQUIRE(VALID_RESOLVER(resolver));
5c48e4
+	resolver->maxqueries = queries;
5c48e4
+}
5c48e4
+
5c48e4
+unsigned int
5c48e4
+dns_resolver_getmaxqueries(dns_resolver_t *resolver) {
5c48e4
+	REQUIRE(VALID_RESOLVER(resolver));
5c48e4
+	return (resolver->maxqueries);
5c48e4
+}
5c48e4
diff -up bind-9.9.4/lib/export/isc/Makefile.in.CVE-2014-8500 bind-9.9.4/lib/export/isc/Makefile.in
5c48e4
--- bind-9.9.4/lib/export/isc/Makefile.in.CVE-2014-8500	2014-12-10 14:56:24.907552500 +0100
5c48e4
+++ bind-9.9.4/lib/export/isc/Makefile.in	2014-12-10 14:56:24.967552568 +0100
5c48e4
@@ -63,7 +63,7 @@ WIN32OBJS = 	win32/condition.@O@ win32/d
5c48e4
 # Alphabetically
5c48e4
 OBJS =		@ISC_EXTRA_OBJS@ \
5c48e4
 		assertions.@O@ backtrace.@O@ backtrace-emptytbl.@O@ base32.@O@ \
5c48e4
-		base64.@O@ buffer.@O@ bufferlist.@O@ \
5c48e4
+		base64.@O@ buffer.@O@ bufferlist.@O@ counter.@O@ \
5c48e4
 		error.@O@ event.@O@ \
5c48e4
 		hash.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \
5c48e4
 		inet_aton.@O@ iterated_hash.@O@ lex.@O@ lfsr.@O@ log.@O@ \
5c48e4
@@ -85,7 +85,7 @@ ISCDRIVERSRCS =	mem.c task.c lib.c timer
5c48e4
 
5c48e4
 SRCS =		@ISC_EXTRA_SRCS@ \
5c48e4
 		assertions.c backtrace.c backtrace-emptytbl.c base32.c \
5c48e4
-		base64.c buffer.c bufferlist.c \
5c48e4
+		base64.c buffer.c bufferlist.c counter.c \
5c48e4
 		error.c event.c \
5c48e4
 		hash.c hex.c hmacmd5.c hmacsha.c \
5c48e4
 		inet_aton.c iterated_hash.c lex.c log.c lfsr.c \
5c48e4
diff -up bind-9.9.4/lib/isccfg/namedconf.c.CVE-2014-8500 bind-9.9.4/lib/isccfg/namedconf.c
5c48e4
--- bind-9.9.4/lib/isccfg/namedconf.c.CVE-2014-8500	2014-12-10 14:56:24.969552570 +0100
5c48e4
+++ bind-9.9.4/lib/isccfg/namedconf.c	2014-12-10 15:04:14.636091707 +0100
5c48e4
@@ -1421,6 +1421,8 @@ view_clauses[] = {
5c48e4
 	{ "max-cache-ttl", &cfg_type_uint32, 0 },
5c48e4
 	{ "max-clients-per-query", &cfg_type_uint32, 0 },
5c48e4
 	{ "max-ncache-ttl", &cfg_type_uint32, 0 },
5c48e4
+	{ "max-recursion-depth", &cfg_type_uint32, 0 },
5c48e4
+	{ "max-recursion-queries", &cfg_type_uint32, 0 },
5c48e4
 	{ "max-udp-size", &cfg_type_uint32, 0 },
5c48e4
 	{ "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
5c48e4
 	{ "minimal-responses", &cfg_type_boolean, 0 },
5c48e4
diff -up bind-9.9.4/lib/isc/counter.c.CVE-2014-8500 bind-9.9.4/lib/isc/counter.c
5c48e4
--- bind-9.9.4/lib/isc/counter.c.CVE-2014-8500	2014-12-10 14:56:24.968552569 +0100
5c48e4
+++ bind-9.9.4/lib/isc/counter.c	2014-12-10 14:56:24.968552569 +0100
5c48e4
@@ -0,0 +1,138 @@
5c48e4
+/*
5c48e4
+ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
5c48e4
+ *
5c48e4
+ * Permission to use, copy, modify, and/or distribute this software for any
5c48e4
+ * purpose with or without fee is hereby granted, provided that the above
5c48e4
+ * copyright notice and this permission notice appear in all copies.
5c48e4
+ *
5c48e4
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
5c48e4
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
5c48e4
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
5c48e4
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
5c48e4
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
5c48e4
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
5c48e4
+ * PERFORMANCE OF THIS SOFTWARE.
5c48e4
+ */
5c48e4
+
5c48e4
+/*! \file */
5c48e4
+
5c48e4
+#include <config.h>
5c48e4
+
5c48e4
+#include <stddef.h>
5c48e4
+
5c48e4
+#include <isc/counter.h>
5c48e4
+#include <isc/magic.h>
5c48e4
+#include <isc/mem.h>
5c48e4
+#include <isc/util.h>
5c48e4
+
5c48e4
+#define COUNTER_MAGIC			ISC_MAGIC('C', 'n', 't', 'r')
5c48e4
+#define VALID_COUNTER(r)		ISC_MAGIC_VALID(r, COUNTER_MAGIC)
5c48e4
+
5c48e4
+struct isc_counter {
5c48e4
+	unsigned int	magic;
5c48e4
+	isc_mem_t	*mctx;
5c48e4
+	isc_mutex_t	lock;
5c48e4
+	unsigned int	references;
5c48e4
+	unsigned int	limit;
5c48e4
+	unsigned int	used;
5c48e4
+};
5c48e4
+
5c48e4
+isc_result_t
5c48e4
+isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp) {
5c48e4
+	isc_result_t result;
5c48e4
+	isc_counter_t *counter;
5c48e4
+
5c48e4
+	REQUIRE(counterp != NULL && *counterp == NULL);
5c48e4
+
5c48e4
+	counter = isc_mem_get(mctx, sizeof(*counter));
5c48e4
+	if (counter == NULL)
5c48e4
+		return (ISC_R_NOMEMORY);
5c48e4
+
5c48e4
+	result = isc_mutex_init(&counter->lock);
5c48e4
+	if (result != ISC_R_SUCCESS) {
5c48e4
+		isc_mem_put(mctx, counter, sizeof(*counter));
5c48e4
+		return (result);
5c48e4
+	}
5c48e4
+
5c48e4
+	counter->mctx = NULL;
5c48e4
+	isc_mem_attach(mctx, &counter->mctx);
5c48e4
+
5c48e4
+	counter->references = 1;
5c48e4
+	counter->limit = limit;
5c48e4
+	counter->used = 0;
5c48e4
+
5c48e4
+	counter->magic = COUNTER_MAGIC;
5c48e4
+	*counterp = counter;
5c48e4
+	return (ISC_R_SUCCESS);
5c48e4
+}
5c48e4
+
5c48e4
+isc_result_t
5c48e4
+isc_counter_increment(isc_counter_t *counter) {
5c48e4
+	isc_result_t result = ISC_R_SUCCESS;
5c48e4
+
5c48e4
+	LOCK(&counter->lock);
5c48e4
+	counter->used++;
5c48e4
+	if (counter->limit != 0 && counter->used >= counter->limit)
5c48e4
+		result = ISC_R_QUOTA;
5c48e4
+	UNLOCK(&counter->lock);
5c48e4
+
5c48e4
+	return (result);
5c48e4
+}
5c48e4
+
5c48e4
+unsigned int
5c48e4
+isc_counter_used(isc_counter_t *counter) {
5c48e4
+	REQUIRE(VALID_COUNTER(counter));
5c48e4
+
5c48e4
+	return (counter->used);
5c48e4
+}
5c48e4
+
5c48e4
+void
5c48e4
+isc_counter_setlimit(isc_counter_t *counter, int limit) {
5c48e4
+	REQUIRE(VALID_COUNTER(counter));
5c48e4
+
5c48e4
+	LOCK(&counter->lock);
5c48e4
+	counter->limit = limit;
5c48e4
+	UNLOCK(&counter->lock);
5c48e4
+}
5c48e4
+
5c48e4
+void
5c48e4
+isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp) {
5c48e4
+	REQUIRE(VALID_COUNTER(source));
5c48e4
+	REQUIRE(targetp != NULL && *targetp == NULL);
5c48e4
+
5c48e4
+	LOCK(&source->lock);
5c48e4
+	source->references++;
5c48e4
+	INSIST(source->references > 0);
5c48e4
+	UNLOCK(&source->lock);
5c48e4
+
5c48e4
+	*targetp = source;
5c48e4
+}
5c48e4
+
5c48e4
+static void
5c48e4
+destroy(isc_counter_t *counter) {
5c48e4
+	counter->magic = 0;
5c48e4
+	isc_mutex_destroy(&counter->lock);
5c48e4
+	isc_mem_putanddetach(&counter->mctx, counter, sizeof(*counter));
5c48e4
+}
5c48e4
+
5c48e4
+void
5c48e4
+isc_counter_detach(isc_counter_t **counterp) {
5c48e4
+	isc_counter_t *counter;
5c48e4
+	isc_boolean_t want_destroy = ISC_FALSE;
5c48e4
+
5c48e4
+	REQUIRE(counterp != NULL && *counterp != NULL);
5c48e4
+	counter = *counterp;
5c48e4
+	REQUIRE(VALID_COUNTER(counter));
5c48e4
+
5c48e4
+	*counterp = NULL;
5c48e4
+
5c48e4
+	LOCK(&counter->lock);
5c48e4
+	INSIST(counter->references > 0);
5c48e4
+	counter->references--;
5c48e4
+	if (counter->references == 0)
5c48e4
+		want_destroy = ISC_TRUE;
5c48e4
+	UNLOCK(&counter->lock);
5c48e4
+
5c48e4
+	if (want_destroy)
5c48e4
+		destroy(counter);
5c48e4
+}
5c48e4
diff -up bind-9.9.4/lib/isc/include/isc/counter.h.CVE-2014-8500 bind-9.9.4/lib/isc/include/isc/counter.h
5c48e4
--- bind-9.9.4/lib/isc/include/isc/counter.h.CVE-2014-8500	2014-12-10 14:56:24.968552569 +0100
5c48e4
+++ bind-9.9.4/lib/isc/include/isc/counter.h	2014-12-10 14:56:24.968552569 +0100
5c48e4
@@ -0,0 +1,90 @@
5c48e4
+/*
5c48e4
+ * Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
5c48e4
+ *
5c48e4
+ * Permission to use, copy, modify, and/or distribute this software for any
5c48e4
+ * purpose with or without fee is hereby granted, provided that the above
5c48e4
+ * copyright notice and this permission notice appear in all copies.
5c48e4
+ *
5c48e4
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
5c48e4
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
5c48e4
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
5c48e4
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
5c48e4
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
5c48e4
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
5c48e4
+ * PERFORMANCE OF THIS SOFTWARE.
5c48e4
+ */
5c48e4
+
5c48e4
+#ifndef ISC_COUNTER_H
5c48e4
+#define ISC_COUNTER_H 1
5c48e4
+
5c48e4
+/*****
5c48e4
+ ***** Module Info
5c48e4
+ *****/
5c48e4
+
5c48e4
+/*! \file isc/counter.h
5c48e4
+ *
5c48e4
+ * \brief The isc_counter_t object is a simplified version of the
5c48e4
+ * isc_quota_t object; it tracks the consumption of limited
5c48e4
+ * resources, returning an error condition when the quota is
5c48e4
+ * exceeded.  However, unlike isc_quota_t, attaching and detaching
5c48e4
+ * from a counter object does not increment or decrement the counter.
5c48e4
+ */
5c48e4
+
5c48e4
+/***
5c48e4
+ *** Imports.
5c48e4
+ ***/
5c48e4
+
5c48e4
+#include <isc/lang.h>
5c48e4
+#include <isc/mutex.h>
5c48e4
+#include <isc/types.h>
5c48e4
+
5c48e4
+/*****
5c48e4
+ ***** Types.
5c48e4
+ *****/
5c48e4
+
5c48e4
+ISC_LANG_BEGINDECLS
5c48e4
+
5c48e4
+isc_result_t
5c48e4
+isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp);
5c48e4
+/*%<
5c48e4
+ * Allocate and initialize a counter object.
5c48e4
+ */
5c48e4
+
5c48e4
+isc_result_t
5c48e4
+isc_counter_increment(isc_counter_t *counter);
5c48e4
+/*%<
5c48e4
+ * Increment the counter.
5c48e4
+ *
5c48e4
+ * If the counter limit is nonzero and has been reached, then
5c48e4
+ * return ISC_R_QUOTA, otherwise ISC_R_SUCCESS. (The counter is
5c48e4
+ * incremented regardless of return value.)
5c48e4
+ */
5c48e4
+
5c48e4
+unsigned int
5c48e4
+isc_counter_used(isc_counter_t *counter);
5c48e4
+/*%<
5c48e4
+ * Return the current counter value.
5c48e4
+ */
5c48e4
+
5c48e4
+void
5c48e4
+isc_counter_setlimit(isc_counter_t *counter, int limit);
5c48e4
+/*%<
5c48e4
+ * Set the counter limit.
5c48e4
+ */
5c48e4
+
5c48e4
+void
5c48e4
+isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp);
5c48e4
+/*%<
5c48e4
+ * Attach to a counter object, increasing its reference counter.
5c48e4
+ */
5c48e4
+
5c48e4
+void
5c48e4
+isc_counter_detach(isc_counter_t **counterp);
5c48e4
+/*%<
5c48e4
+ * Detach (and destroy if reference counter has dropped to zero)
5c48e4
+ * a counter object.
5c48e4
+ */
5c48e4
+
5c48e4
+ISC_LANG_ENDDECLS
5c48e4
+
5c48e4
+#endif /* ISC_COUNTER_H */
5c48e4
diff -up bind-9.9.4/lib/isc/include/isc/Makefile.in.CVE-2014-8500 bind-9.9.4/lib/isc/include/isc/Makefile.in
5c48e4
--- bind-9.9.4/lib/isc/include/isc/Makefile.in.CVE-2014-8500	2014-12-10 15:02:34.811005903 +0100
5c48e4
+++ bind-9.9.4/lib/isc/include/isc/Makefile.in	2014-12-10 15:03:01.099030322 +0100
5c48e4
@@ -27,7 +27,7 @@ top_srcdir =	@top_srcdir@
5c48e4
 # install target below.
5c48e4
 #
5c48e4
 HEADERS =	app.h assertions.h base64.h bind9.h bitstring.h boolean.h \
5c48e4
-		buffer.h bufferlist.h commandline.h entropy.h error.h event.h \
5c48e4
+		buffer.h bufferlist.h commandline.h counter.h entropy.h error.h event.h \
5c48e4
 		eventclass.h file.h formatcheck.h fsaccess.h \
5c48e4
 		hash.h heap.h hex.h hmacmd5.h hmacsha.h \
5c48e4
 		httpd.h \
5c48e4
diff -up bind-9.9.4/lib/isc/include/isc/types.h.CVE-2014-8500 bind-9.9.4/lib/isc/include/isc/types.h
5c48e4
--- bind-9.9.4/lib/isc/include/isc/types.h.CVE-2014-8500	2013-09-05 07:09:08.000000000 +0200
5c48e4
+++ bind-9.9.4/lib/isc/include/isc/types.h	2014-12-10 14:56:24.968552569 +0100
5c48e4
@@ -50,6 +50,7 @@ typedef struct isc_buffer		isc_buffer_t;
5c48e4
 typedef ISC_LIST(isc_buffer_t)		isc_bufferlist_t;	/*%< Buffer List */
5c48e4
 typedef struct isc_constregion		isc_constregion_t;	/*%< Const region */
5c48e4
 typedef struct isc_consttextregion	isc_consttextregion_t;	/*%< Const Text Region */
5c48e4
+typedef struct isc_counter		isc_counter_t;		/*%< Counter */
5c48e4
 typedef struct isc_entropy		isc_entropy_t;		/*%< Entropy */
5c48e4
 typedef struct isc_entropysource	isc_entropysource_t;	/*%< Entropy Source */
5c48e4
 typedef struct isc_event		isc_event_t;		/*%< Event */
5c48e4
diff -up bind-9.9.4/lib/isc/Makefile.in.CVE-2014-8500 bind-9.9.4/lib/isc/Makefile.in
5c48e4
--- bind-9.9.4/lib/isc/Makefile.in.CVE-2014-8500	2014-12-10 14:56:24.860552447 +0100
5c48e4
+++ bind-9.9.4/lib/isc/Makefile.in	2014-12-10 14:56:24.968552569 +0100
5c48e4
@@ -53,7 +53,7 @@ WIN32OBJS = 	win32/condition.@O@ win32/d
5c48e4
 OBJS =		@ISC_EXTRA_OBJS@ \
5c48e4
 		assertions.@O@ backtrace.@O@ base32.@O@ base64.@O@ \
5c48e4
 		bitstring.@O@ buffer.@O@ bufferlist.@O@ commandline.@O@ \
5c48e4
-		error.@O@ event.@O@ \
5c48e4
+		counter.@O@ error.@O@ event.@O@ \
5c48e4
 		hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \
5c48e4
 		httpd.@O@ inet_aton.@O@ iterated_hash.@O@ \
5c48e4
 		lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
5c48e4
@@ -70,8 +70,8 @@ SYMTBLOBJS =	backtrace-emptytbl.@O@
5c48e4
 # Alphabetically
5c48e4
 SRCS =		@ISC_EXTRA_SRCS@ \
5c48e4
 		assertions.c backtrace.c base32.c base64.c bitstring.c \
5c48e4
-		buffer.c bufferlist.c commandline.c error.c event.c \
5c48e4
-		heap.c hex.c hmacmd5.c hmacsha.c \
5c48e4
+		buffer.c bufferlist.c commandline.c counter.c \
5c48e4
+		error.c event.c heap.c hex.c hmacmd5.c hmacsha.c \
5c48e4
 		httpd.c inet_aton.c iterated_hash.c \
5c48e4
 		lex.c lfsr.c lib.c log.c \
5c48e4
 		md5.c mem.c mutexblock.c \