--- a/components/bind/patches/reclimit-v96.patch Mon Jul 20 23:01:54 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1064 +0,0 @@
-This patch was obtained from ISC for 9.6-ESV-R11-P1. The patch can
-only be obtained from [email protected] on an as needed
-basis.
-
-diff --git a/CHANGES b/CHANGES
-index 178f73d..8ace4fb 100644
---- a/CHANGES
-+++ b/CHANGES
-@@ -1,3 +1,17 @@
-+ --- 9.6-ESV-R11-P1 released ---
-+
-+4006. [security] A flaw in delegation handling could be exploited
-+ to put named into an infinite loop. This has
-+ been addressed by placing limits on the number
-+ of levels of recursion named will allow (default 7),
-+ and the number of iterative queries that it will
-+ send (default 50) before terminating a recursive
-+ query (CVE-2014-8500).
-+
-+ The recursion depth limit is configured via the
-+ "max-recursion-depth" option, and the query limit
-+ via the "max-recursion-queries" option. [RT #37580]
-+
- --- 9.6-ESV-R11 released ---
-
- --- 9.6-ESV-R11rc2 released ---
-diff --git a/bin/named/config.c b/bin/named/config.c
-index d85afa7..823d101 100644
---- a/bin/named/config.c
-+++ b/bin/named/config.c
-@@ -15,8 +15,6 @@
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
--/* $Id$ */
--
- /*! \file */
-
- #include <config.h>
-@@ -145,6 +143,8 @@ options {\n\
- dnssec-accept-expired no;\n\
- clients-per-query 10;\n\
- max-clients-per-query 100;\n\
-+ max-recursion-depth 7;\n\
-+ max-recursion-queries 50;\n\
- zero-no-soa-ttl-cache no;\n\
- nsec3-test-zone no;\n\
- "
-diff --git a/bin/named/include/named/query.h b/bin/named/include/named/query.h
-index 20aff40..771345e 100644
---- a/bin/named/include/named/query.h
-+++ b/bin/named/include/named/query.h
-@@ -1,5 +1,5 @@
- /*
-- * Copyright (C) 2004, 2005, 2007, 2010, 2012 Internet Systems Consortium, Inc. ("ISC")
-+ * Copyright (C) 2004, 2005, 2007, 2010, 2011, 2013, 2014 Internet Systems Consortium, Inc. ("ISC")
- * Copyright (C) 1999-2002 Internet Software Consortium.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
-@@ -15,8 +15,6 @@
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
--/* $Id$ */
--
- #ifndef NAMED_QUERY_H
- #define NAMED_QUERY_H 1
-
-diff --git a/bin/named/query.c b/bin/named/query.c
-index 10a7d9a..48e4822 100644
---- a/bin/named/query.c
-+++ b/bin/named/query.c
-@@ -3343,13 +3343,12 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain,
- peeraddr = &client->peeraddr;
- else
- peeraddr = NULL;
-- result = dns_resolver_createfetch2(client->view->resolver,
-+ result = dns_resolver_createfetch3(client->view->resolver,
- client->query.qname,
- qtype, qdomain, nameservers,
- NULL, peeraddr, client->message->id,
-- client->query.fetchoptions,
-- client->task,
-- query_resume, client,
-+ client->query.fetchoptions, 0, NULL,
-+ client->task, query_resume, client,
- rdataset, sigrdataset,
- &client->query.fetch);
-
-diff --git a/bin/named/server.c b/bin/named/server.c
-index af53b48..4d48074 100644
---- a/bin/named/server.c
-+++ b/bin/named/server.c
-@@ -15,8 +15,6 @@
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
--/* $Id$ */
--
- /*! \file */
-
- #include <config.h>
-@@ -2048,6 +2046,16 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
- max_clients_per_query);
-
- 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 --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
-index f894aab..b823dc4 100644
---- a/doc/arm/Bv9ARM-book.xml
-+++ b/doc/arm/Bv9ARM-book.xml
-@@ -4652,6 +4652,8 @@ category notify { null; };
- <optional> max-acache-size <replaceable>size_spec</replaceable> ; </optional>
- <optional> clients-per-query <replaceable>number</replaceable> ; </optional>
- <optional> max-clients-per-query <replaceable>number</replaceable> ; </optional>
-+ <optional> max-recursion-depth <replaceable>number</replaceable> ; </optional>
-+ <optional> max-recursion-queries <replaceable>number</replaceable> ; </optional>
- <optional> masterfile-format (<constant>text</constant>|<constant>raw</constant>) ; </optional>
- <optional> empty-server <replaceable>name</replaceable> ; </optional>
- <optional> empty-contact <replaceable>name</replaceable> ; </optional>
-@@ -4729,6 +4731,35 @@ category notify { null; };
- </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>tkey-gssapi-credential</command></term>
- <listitem>
-diff --git a/lib/dns/adb.c b/lib/dns/adb.c
-index 2d7b904..422e59c 100644
---- a/lib/dns/adb.c
-+++ b/lib/dns/adb.c
-@@ -200,6 +200,7 @@ struct dns_adbfetch {
- unsigned int magic;
- dns_fetch_t *fetch;
- dns_rdataset_t rdataset;
-+ unsigned int depth;
- };
-
- /*%
-@@ -298,8 +299,7 @@ static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, isc_boolean_t,
- static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
- static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
- static void clean_target(dns_adb_t *, dns_name_t *);
--static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
-- unsigned int);
-+static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, unsigned int);
- static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
- static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **,
- isc_stdtime_t);
-@@ -307,6 +307,7 @@ static void cancel_fetches_at_name(dns_adbname_t *);
- 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 destroy(dns_adb_t *);
-@@ -2282,6 +2283,19 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
- 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,
-+ qname, qtype, 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 *qname,
-+ dns_rdatatype_t qtype, 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;
-@@ -2512,7 +2526,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
- * 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",
-@@ -2523,7 +2537,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
- * 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: "
-@@ -3256,6 +3270,12 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) {
- 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);
-@@ -3293,9 +3313,8 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) {
- }
-
- 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;
-@@ -3340,12 +3359,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,
-+ NULL, 0, options, depth, qc,
-+ adb->task, fetch_callback, adbname,
-+ &fetch->rdataset, NULL,
-+ &fetch->fetch);
- if (result != ISC_R_SUCCESS)
- goto cleanup;
-
-diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h
-index d4d1b05..556fcc2 100644
---- a/lib/dns/include/dns/adb.h
-+++ b/lib/dns/include/dns/adb.h
-@@ -334,6 +334,13 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
- dns_rdatatype_t qtype, 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 *qname,
-+ dns_rdatatype_t qtype, 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 --git a/lib/dns/include/dns/resolver.h b/lib/dns/include/dns/resolver.h
-index d293daa..10c3a3a 100644
---- a/lib/dns/include/dns/resolver.h
-+++ b/lib/dns/include/dns/resolver.h
-@@ -270,6 +270,18 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
- 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,
-+ isc_sockaddr_t *client, isc_uint16_t id,
-+ 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.
- *
-@@ -550,6 +562,30 @@ dns_resolver_printbadcache(dns_resolver_t *resolver, FILE *fp);
- * \li 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:
-+ * \li 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:
-+ * \li resolver to be valid.
-+ */
-+
- ISC_LANG_ENDDECLS
-
- #endif /* DNS_RESOLVER_H */
-diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c
-index 7dcea6d..bd3d9fd 100644
---- a/lib/dns/resolver.c
-+++ b/lib/dns/resolver.c
-@@ -21,6 +21,7 @@
-
- #include <config.h>
-
-+#include <isc/counter.h>
- #include <isc/log.h>
- #include <isc/platform.h>
- #include <isc/print.h>
-@@ -109,6 +110,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.
- */
-@@ -211,12 +222,13 @@ struct fetchctx {
- isc_sockaddrlist_t edns;
- isc_sockaddrlist_t edns512;
- isc_sockaddrlist_t bad_edns;
-- dns_validator_t *validator;
-+ dns_validator_t * validator;
- ISC_LIST(dns_validator_t) validators;
- dns_db_t * cache;
- 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.
-@@ -283,6 +295,7 @@ struct fetchctx {
- unsigned int valfail;
- isc_boolean_t timeout;
- dns_adbaddrinfo_t *addrinfo;
-+ unsigned int depth;
- };
-
- #define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!')
-@@ -394,6 +407,8 @@ struct dns_resolver {
- unsigned int spillatmin;
- isc_timer_t * spillattimer;
- isc_boolean_t zero_no_soa_ttl;
-+ unsigned int maxdepth;
-+ unsigned int maxqueries;
-
- /* Locked by lock. */
- unsigned int references;
-@@ -1495,6 +1510,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
- if (result != ISC_R_SUCCESS)
- goto cleanup_dispatch;
- }
-+
- fctx->querysent++;
-
- ISC_LIST_APPEND(fctx->queries, query, link);
-@@ -2146,9 +2162,9 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
- */
- INSIST(!SHUTTINGDOWN(fctx));
- fctx->attributes &= ~FCTX_ATTR_ADDRWAIT;
-- if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES)
-+ if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES) {
- want_try = ISC_TRUE;
-- else {
-+ } else {
- fctx->findfail++;
- if (fctx->pending == 0) {
- /*
-@@ -2177,7 +2193,7 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) {
- else if (want_done)
- fctx_done(fctx, ISC_R_FAILURE, __LINE__);
- else if (destroy) {
-- fctx_destroy(fctx);
-+ fctx_destroy(fctx);
- if (bucket_empty)
- empty_bucket(res);
- }
-@@ -2499,12 +2515,13 @@ findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port,
- * See what we know about this address.
- */
- find = NULL;
-- result = dns_adb_createfind(fctx->adb,
-- res->buckets[fctx->bucketnum].task,
-- fctx_finddone, fctx, name,
-- &fctx->name, fctx->type,
-- options, now, NULL,
-- res->view->dstport, &find);
-+ result = dns_adb_createfind2(fctx->adb,
-+ res->buckets[fctx->bucketnum].task,
-+ fctx_finddone, fctx, name,
-+ &fctx->name, fctx->type,
-+ options, now, NULL,
-+ res->view->dstport,
-+ fctx->depth + 1, fctx->qc, &find);
- if (result != ISC_R_SUCCESS) {
- if (result == DNS_R_ALIAS) {
- /*
-@@ -2612,6 +2629,14 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) {
-
- res = fctx->res;
-
-+ 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.
- */
-@@ -3087,6 +3112,16 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache) {
- }
- }
-
-+ 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, __LINE__);
-+ return;
-+ }
-+
- result = fctx_query(fctx, addrinfo, fctx->options);
- if (result != ISC_R_SUCCESS)
- fctx_done(fctx, result, __LINE__);
-@@ -3185,6 +3220,7 @@ fctx_destroy(fetchctx_t *fctx) {
- isc_mem_put(fctx->mctx, sa, sizeof(*sa));
- }
-
-+ isc_counter_detach(&fctx->qc);
- isc_timer_detach(&fctx->timer);
- dns_message_destroy(&fctx->rmessage);
- dns_message_destroy(&fctx->qmessage);
-@@ -3512,7 +3548,8 @@ log_ns_ttl(fetchctx_t *fctx, const char *where) {
- 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;
-@@ -3534,6 +3571,21 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
- fctx = isc_mem_get(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;
-+ }
-+
-+ /*
-+ * Make fctx->info point to a copy of a formatted string
-+ * "name/type".
-+ */
- dns_name_format(name, buf, sizeof(buf));
- dns_rdatatype_format(type, typebuf, sizeof(typebuf));
- strcat(buf, "/"); /* checked */
-@@ -3541,7 +3593,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
- fctx->info = isc_mem_strdup(mctx, buf);
- if (fctx->info == NULL) {
- result = ISC_R_NOMEMORY;
-- goto cleanup_fetch;
-+ goto cleanup_counter;
- }
- FCTXTRACE("create");
- dns_name_init(&fctx->name, NULL);
-@@ -3564,6 +3616,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
- 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);
-@@ -3768,6 +3821,9 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
- cleanup_info:
- isc_mem_free(mctx, fctx->info);
-
-+ cleanup_counter:
-+ isc_counter_detach(&fctx->qc);
-+
- cleanup_fetch:
- isc_mem_put(mctx, fctx, sizeof(*fctx));
-
-@@ -7339,6 +7395,8 @@ dns_resolver_create(dns_view_t *view,
- res->zero_no_soa_ttl = ISC_FALSE;
- res->ndisps = 0;
- res->nextdisp = 0; /* meaningless at this point, but init it */
-+ res->maxdepth = DEFAULT_RECURSION_DEPTH;
-+ res->maxqueries = DEFAULT_MAX_QUERIES;
- res->nbuckets = ntasks;
- res->activebuckets = ntasks;
- res->buckets = isc_mem_get(view->mctx,
-@@ -7778,9 +7836,9 @@ dns_resolver_createfetch(dns_resolver_t *res, dns_name_t *name,
- dns_rdataset_t *sigrdataset,
- dns_fetch_t **fetchp)
- {
-- return (dns_resolver_createfetch2(res, name, type, domain,
-+ return (dns_resolver_createfetch3(res, name, type, domain,
- nameservers, forwarders, NULL, 0,
-- options, task, action, arg,
-+ options, 0, NULL, task, action, arg,
- rdataset, sigrdataset, fetchp));
- }
-
-@@ -7796,6 +7854,25 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
- dns_rdataset_t *sigrdataset,
- dns_fetch_t **fetchp)
- {
-+ return (dns_resolver_createfetch3(res, name, type, domain,
-+ nameservers, forwarders, client, id,
-+ 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,
-+ isc_sockaddr_t *client, dns_messageid_t id,
-+ 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 = ISC_R_SUCCESS;
-@@ -7882,11 +7959,12 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name,
-
- if (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, client, id, action, arg,
- rdataset, sigrdataset, fetch);
-@@ -8637,3 +8715,27 @@ dns_resolver_getoptions(dns_resolver_t *resolver) {
-
- return (resolver->options);
- }
-+
-+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 --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in
-index 0b4020b..afc19ee 100644
---- a/lib/isc/Makefile.in
-+++ b/lib/isc/Makefile.in
-@@ -13,8 +13,6 @@
- # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- # PERFORMANCE OF THIS SOFTWARE.
-
--# $Id$
--
- srcdir = @srcdir@
- VPATH = @srcdir@
- top_srcdir = @top_srcdir@
-@@ -53,7 +51,7 @@ WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \
- # Alphabetically
- OBJS = @ISC_EXTRA_OBJS@ \
- assertions.@O@ base32.@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@ hmacsha.@O@ \
- httpd.@O@ inet_aton.@O@ iterated_hash.@O@ \
- lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \
-@@ -68,7 +66,7 @@ OBJS = @ISC_EXTRA_OBJS@ \
- # Alphabetically
- SRCS = @ISC_EXTRA_SRCS@ \
- assertions.c base32.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 hmacsha.c \
- httpd.c inet_aton.c iterated_hash.c \
- lex.c lfsr.c lib.c log.c \
-diff --git a/lib/isc/include/isc/Makefile.in b/lib/isc/include/isc/Makefile.in
-index 9adca3e..1cfbbd1 100644
---- a/lib/isc/include/isc/Makefile.in
-+++ b/lib/isc/include/isc/Makefile.in
-@@ -13,8 +13,6 @@
- # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- # PERFORMANCE OF THIS SOFTWARE.
-
--# $Id$
--
- srcdir = @srcdir@
- VPATH = @srcdir@
- top_srcdir = @top_srcdir@
-@@ -27,7 +25,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 hmacsha.h \
- httpd.h \
-diff --git a/lib/isc/include/isc/types.h b/lib/isc/include/isc/types.h
-index 8e8b08f..a646b8b 100644
---- a/lib/isc/include/isc/types.h
-+++ b/lib/isc/include/isc/types.h
-@@ -45,6 +45,7 @@ typedef struct isc_buffer isc_buffer_t; /*%< Buffer */
- typedef ISC_LIST(isc_buffer_t) isc_bufferlist_t; /*%< Buffer List */
- typedef struct isc_constregion isc_constregion_t; /*%< Const region */
- typedef struct isc_consttextregion isc_consttextregion_t; /*%< Const Text Region */
-+typedef struct isc_counter isc_counter_t; /*%< Counter */
- typedef struct isc_entropy isc_entropy_t; /*%< Entropy */
- typedef struct isc_entropysource isc_entropysource_t; /*%< Entropy Source */
- typedef struct isc_event isc_event_t; /*%< Event */
-diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
-index fac2633..3023dcc 100644
---- a/lib/isccfg/namedconf.c
-+++ b/lib/isccfg/namedconf.c
-@@ -15,8 +15,6 @@
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
--/* $Id$ */
--
- /*! \file */
-
- #include <config.h>
-@@ -830,6 +828,8 @@ view_clauses[] = {
- { "max-cache-ttl", &cfg_type_uint32, 0 },
- { "max-clients-per-query", &cfg_type_uint32, 0 },
- { "max-ncache-ttl", &cfg_type_uint32, 0 },
-+ { "max-recursion-depth", &cfg_type_uint32, 0 },
-+ { "max-recursion-queries", &cfg_type_uint32, 0 },
- { "max-udp-size", &cfg_type_uint32, 0 },
- { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
- { "minimal-responses", &cfg_type_boolean, 0 },
-diff --git a/version b/version
-index 1be3c16..2058444 100644
---- a/version
-+++ b/version
-@@ -10,4 +10,4 @@ MINORVER=6
- PATCHVER=
- RELEASETYPE=-ESV
- RELEASEVER=-R11
--EXTENSIONS=
-+EXTENSIONS=-P1
-diff --git a/lib/isc/counter.c b/lib/isc/counter.c
-new file mode 100644
-index 0000000..d7d187b
---- /dev/null
-+++ b/lib/isc/counter.c
-@@ -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 --git a/lib/isc/include/isc/counter.h b/lib/isc/include/isc/counter.h
-new file mode 100644
-index 0000000..e7ebd25
---- /dev/null
-+++ b/lib/isc/include/isc/counter.h
-@@ -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 --git a/lib/isc/tests/counter_test.c b/lib/isc/tests/counter_test.c
-new file mode 100644
-index 0000000..a7a1997
---- /dev/null
-+++ b/lib/isc/tests/counter_test.c
-@@ -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());
-+}
-+