20089043 Upgrade Solaris to BIND 9.6-ESV-R11-P1
authorWilliam.D.Johnston <William.D.Johnston@oracle.com>
Fri, 12 Dec 2014 08:20:34 -0800
changeset 3541 37a03b73b5a4
parent 3540 4f3892464f83
child 3543 206d6ffc614a
20089043 Upgrade Solaris to BIND 9.6-ESV-R11-P1 20089135 problem in SERVICE/DNS-SERVER
components/bind/Makefile
components/bind/bind.p5m
components/bind/bindc.p5m
components/bind/patches/reclimit-v96.patch
--- a/components/bind/Makefile	Wed Dec 03 06:13:04 2014 -0800
+++ b/components/bind/Makefile	Fri Dec 12 08:20:34 2014 -0800
@@ -24,7 +24,8 @@
 
 COMPONENT_NAME=		bind
 COMPONENT_VERSION=	9.6-ESV-R11
-IPS_COMPONENT_VERSION=	9.6.3.11.0
+HUMAN_VERSION=	$(COMPONENT_VERSION)-P1
+IPS_COMPONENT_VERSION=	9.6.3.11.1
 COMPONENT_SRC=		$(COMPONENT_NAME)-$(COMPONENT_VERSION)
 COMPONENT_ARCHIVE=	$(COMPONENT_SRC).tar.gz
 COMPONENT_PROJECT_URL=	http://www.isc.org/software/bind/
@@ -36,7 +37,7 @@
 	http://ftp.isc.org/isc/bind9/$(COMPONENT_VERSION)/$(COMPONENT_ARCHIVE)
 COMPONENT_BUGDB=	service/dns-server
 
-TPNO=			16931
+TPNO=			20537
 
 include ../../make-rules/prep.mk
 include ../../make-rules/configure.mk
--- a/components/bind/bind.p5m	Wed Dec 03 06:13:04 2014 -0800
+++ b/components/bind/bind.p5m	Fri Dec 12 08:20:34 2014 -0800
@@ -26,7 +26,7 @@
 
 set name=pkg.fmri \
     value=pkg:/service/network/dns/[email protected]$(IPS_COMPONENT_VERSION),$(BUILD_VERSION)
-set name=pkg.human-version value=$(COMPONENT_VERSION)
+set name=pkg.human-version value=$(HUMAN_VERSION)
 set name=pkg.description \
     value="BIND is open source software that implements the Domain Name System (DNS) protocols for the Internet.  This package contains the DNS server 'named' and tools used to setup and validate configuration."
 set name=pkg.summary \
--- a/components/bind/bindc.p5m	Wed Dec 03 06:13:04 2014 -0800
+++ b/components/bind/bindc.p5m	Fri Dec 12 08:20:34 2014 -0800
@@ -23,7 +23,7 @@
 
 set name=pkg.fmri \
     value=pkg:/network/dns/[email protected]$(IPS_COMPONENT_VERSION),$(BUILD_VERSION)
-set name=pkg.human-version value=$(COMPONENT_VERSION)
+set name=pkg.human-version value=$(HUMAN_VERSION)
 set name=pkg.summary value="BIND DNS tools"
 set name=com.oracle.info.description value="the BIND DNS tools"
 set name=com.oracle.info.tpno value=$(TPNO)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/bind/patches/reclimit-v96.patch	Fri Dec 12 08:20:34 2014 -0800
@@ -0,0 +1,1064 @@
+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
[email protected]@ -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
[email protected]@ -15,8 +15,6 @@
+  * PERFORMANCE OF THIS SOFTWARE.
+  */
+ 
+-/* $Id$ */
+-
+ /*! \file */
+ 
+ #include <config.h>
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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
[email protected]@ -15,8 +15,6 @@
+  * PERFORMANCE OF THIS SOFTWARE.
+  */
+ 
+-/* $Id$ */
+-
+ /*! \file */
+ 
+ #include <config.h>
[email protected]@ -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
[email protected]@ -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>
[email protected]@ -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
[email protected]@ -200,6 +200,7 @@ struct dns_adbfetch {
+ 	unsigned int                    magic;
+ 	dns_fetch_t                    *fetch;
+ 	dns_rdataset_t                  rdataset;
++	unsigned int			depth;
+ };
+ 
+ /*%
[email protected]@ -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);
[email protected]@ -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 *);
[email protected]@ -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;
[email protected]@ -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",
[email protected]@ -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: "
[email protected]@ -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);
[email protected]@ -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;
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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.
+  *
[email protected]@ -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
[email protected]@ -21,6 +21,7 @@
+ 
+ #include <config.h>
+ 
++#include <isc/counter.h>
+ #include <isc/log.h>
+ #include <isc/platform.h>
+ #include <isc/print.h>
[email protected]@ -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.
+  */
[email protected]@ -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.
[email protected]@ -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', '!', '!', '!')
[email protected]@ -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;
[email protected]@ -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);
[email protected]@ -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) {
+ 				/*
[email protected]@ -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);
+ 	}
[email protected]@ -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) {
+ 			/*
[email protected]@ -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.
+ 	 */
[email protected]@ -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__);
[email protected]@ -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);
[email protected]@ -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;
[email protected]@ -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 */
[email protected]@ -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);
[email protected]@ -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);
[email protected]@ -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));
+ 
[email protected]@ -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,
[email protected]@ -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));
+ }
+ 
[email protected]@ -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;
[email protected]@ -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);
[email protected]@ -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
[email protected]@ -13,8 +13,6 @@
+ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ # PERFORMANCE OF THIS SOFTWARE.
+ 
+-# $Id$
+-
+ srcdir =	@[email protected]
+ VPATH =		@[email protected]
+ top_srcdir =	@[email protected]
[email protected]@ -53,7 +51,7 @@ WIN32OBJS = 	win32/[email protected]@ win32/[email protected]@ win32/[email protected]@ \
+ # Alphabetically
+ OBJS =		@[email protected] \
+ 		[email protected]@ [email protected]@ [email protected]@ [email protected]@ [email protected]@ \
+-		[email protected]@ [email protected]@ [email protected]@ [email protected]@ \
++		[email protected]@ commandline[email protected]@ [email protected]@ [email protected]@ [email protected]@ \
+ 		[email protected]@ [email protected]@ [email protected]@ [email protected]@ [email protected]@ \
+ 		[email protected]@ [email protected]@ [email protected]@ \
+ 		[email protected]@ [email protected]@ [email protected]@ [email protected]@ \
[email protected]@ -68,7 +66,7 @@ OBJS =		@[email protected] \
+ # Alphabetically
+ SRCS =		@[email protected] \
+ 		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
[email protected]@ -13,8 +13,6 @@
+ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ # PERFORMANCE OF THIS SOFTWARE.
+ 
+-# $Id$
+-
+ srcdir =	@[email protected]
+ VPATH =		@[email protected]
+ top_srcdir =	@[email protected]
[email protected]@ -27,7 +25,7 @@ top_srcdir =	@[email protected]
+ # 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
[email protected]@ -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
[email protected]@ -15,8 +15,6 @@
+  * PERFORMANCE OF THIS SOFTWARE.
+  */
+ 
+-/* $Id$ */
+-
+ /*! \file */
+ 
+ #include <config.h>
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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
[email protected]@ -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());
++}
++