[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Bug#773548: unblock: bind9/1:9.9.5.dfsg-7



Control: tag -1 confirmed

Jonathan Wiltshire <jmw@debian.org> (2014-12-19):
> Package: release.debian.org
> Severity: normal
> Tags: d-i
> User: release.debian.org@packages.debian.org
> Usertags: unblock
> 
> Please unblock package bind9
> 
> Fix for RC bug #772610, for some reason no unblock request from the maintainer
> or uploader. I have not reviewed the attached debdiff; also needs a kibi-ack.
> 
> unblock bind9/1:9.9.5.dfsg-7

bind9 is only related to d-i on non-linux architectures (through netcfg
→ isc-dhcp → bind9), so no objection from me.

Non-linux porters may want to double check this new version isn't going
to lead to regressions on their architecture(s) though, so letting them
know through Cc (patch available below).

Mraw,
KiBi.

> -- System Information:
> Debian Release: 8.0
>   APT prefers testing
>   APT policy: (990, 'testing'), (500, 'testing-proposed-updates'), (500, 'unstable'), (500, 'stable'), (1, 'experimental')
> Architecture: amd64 (x86_64)
> Foreign Architectures: i386
> 
> Kernel: Linux 3.16.0-4-amd64 (SMP w/4 CPU cores)
> Locale: LANG=en_GB.utf8, LC_CTYPE=en_GB.utf8 (charmap=UTF-8)
> Shell: /bin/sh linked to /bin/dash
> Init: systemd (via /run/systemd/system)

> diff -u bind9-9.9.5.dfsg/bin/named/config.c bind9-9.9.5.dfsg/bin/named/config.c
> --- bind9-9.9.5.dfsg/bin/named/config.c
> +++ bind9-9.9.5.dfsg/bin/named/config.c
> @@ -162,6 +162,8 @@
>  	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\
>  	allow-new-zones no;\n\
> diff -u bind9-9.9.5.dfsg/bin/named/server.c bind9-9.9.5.dfsg/bin/named/server.c
> --- bind9-9.9.5.dfsg/bin/named/server.c
> +++ bind9-9.9.5.dfsg/bin/named/server.c
> @@ -3223,6 +3223,16 @@
>  					cfg_obj_asuint32(obj),
>  					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));
> +
>  #ifdef ALLOW_FILTER_AAAA_ON_V4
>  	obj = NULL;
>  	result = ns_config_get(maps, "filter-aaaa-on-v4", &obj);
> diff -u bind9-9.9.5.dfsg/debian/changelog bind9-9.9.5.dfsg/debian/changelog
> --- bind9-9.9.5.dfsg/debian/changelog
> +++ bind9-9.9.5.dfsg/debian/changelog
> @@ -1,3 +1,10 @@
> +bind9 (1:9.9.5.dfsg-7) unstable; urgency=medium
> +
> +  * Fix CVE-2014-8500: limit recursion in order to avoid memory consuption
> +    issues that can lead to denial-of-service (closes: #772610).
> +
> + -- Michael Gilbert <mgilbert@debian.org>  Sun, 14 Dec 2014 05:05:48 +0000
> +
>  bind9 (1:9.9.5.dfsg-6) unstable; urgency=medium
>  
>    * Include dlz_dlopen.h in libbind-dev (closes: #769117).
> diff -u bind9-9.9.5.dfsg/lib/dns/resolver.c bind9-9.9.5.dfsg/lib/dns/resolver.c
> --- bind9-9.9.5.dfsg/lib/dns/resolver.c
> +++ bind9-9.9.5.dfsg/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>
> @@ -131,6 +132,16 @@
>  #define MAXIMUM_QUERY_TIMEOUT 30 /* The maximum time in seconds for the whole query to live. */
>  #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.
>   */
> @@ -234,12 +245,13 @@
>  	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.
> @@ -307,6 +319,7 @@
>  	isc_boolean_t			timeout;
>  	dns_adbaddrinfo_t 		*addrinfo;
>  	isc_sockaddr_t			*client;
> +	unsigned int			depth;
>  };
>  
>  #define FCTX_MAGIC			ISC_MAGIC('F', '!', '!', '!')
> @@ -418,6 +431,8 @@
>  	isc_timer_t *			spillattimer;
>  	isc_boolean_t			zero_no_soa_ttl;
>  	unsigned int			query_timeout;
> +	unsigned int			maxdepth;
> +	unsigned int			maxqueries;
>  
>  	/* Locked by lock. */
>  	unsigned int			references;
> @@ -1535,6 +1550,7 @@
>  		if (result != ISC_R_SUCCESS)
>  			goto cleanup_dispatch;
>  	}
> +
>  	fctx->querysent++;
>  
>  	ISC_LIST_APPEND(fctx->queries, query, link);
> @@ -2188,9 +2204,9 @@
>  		 */
>  		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) {
>  				/*
> @@ -2219,7 +2235,7 @@
>  	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);
>  	}
> @@ -2473,12 +2489,13 @@
>  	 * 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) {
>  			/*
> @@ -2586,6 +2603,14 @@
>  
>  	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.
>  	 */
> @@ -3061,6 +3086,16 @@
>  		}
>  	}
>  
> +	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__);
> @@ -3159,6 +3194,7 @@
>  		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);
> @@ -3487,7 +3523,8 @@
>  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;
> @@ -3509,6 +3546,21 @@
>  	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 */
> @@ -3516,7 +3568,7 @@
>  	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);
> @@ -3539,6 +3591,7 @@
>  	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);
> @@ -3746,6 +3799,9 @@
>   cleanup_info:
>  	isc_mem_free(mctx, fctx->info);
>  
> + cleanup_counter:
> +	isc_counter_detach(&fctx->qc);
> +
>   cleanup_fetch:
>  	isc_mem_put(mctx, fctx, sizeof(*fctx));
>  
> @@ -5665,7 +5721,7 @@
>  					char qbuf[DNS_NAME_FORMATSIZE];
>  					char nbuf[DNS_NAME_FORMATSIZE];
>  					char tbuf[DNS_RDATATYPE_FORMATSIZE];
> -					dns_rdatatype_format(fctx->type, tbuf,
> +					dns_rdatatype_format(type, tbuf,
>  							     sizeof(tbuf));
>  					dns_name_format(name, nbuf,
>  							     sizeof(nbuf));
> @@ -5674,7 +5730,7 @@
>  					log_formerr(fctx,
>  						    "unrelated %s %s in "
>  						    "%s authority section",
> -						    tbuf, qbuf, nbuf);
> +						    tbuf, nbuf, qbuf);
>  					return (DNS_R_FORMERR);
>  				}
>  				if (type == dns_rdatatype_ns) {
> @@ -7739,6 +7795,8 @@
>  	res->spillattimer = NULL;
>  	res->zero_no_soa_ttl = ISC_FALSE;
>  	res->query_timeout = DEFAULT_QUERY_TIMEOUT;
> +	res->maxdepth = DEFAULT_RECURSION_DEPTH;
> +	res->maxqueries = DEFAULT_MAX_QUERIES;
>  	res->nbuckets = ntasks;
>  	res->activebuckets = ntasks;
>  	res->buckets = isc_mem_get(view->mctx,
> @@ -8177,9 +8235,9 @@
>  			 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));
>  }
>  
> @@ -8195,6 +8253,25 @@
>  			  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;
> @@ -8281,11 +8358,12 @@
>  
>  	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);
> @@ -9059,0 +9138,24 @@
> +
> +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 -u bind9-9.9.5.dfsg/lib/export/isc/Makefile.in bind9-9.9.5.dfsg/lib/export/isc/Makefile.in
> --- bind9-9.9.5.dfsg/lib/export/isc/Makefile.in
> +++ bind9-9.9.5.dfsg/lib/export/isc/Makefile.in
> @@ -63,7 +63,7 @@
>  # Alphabetically
>  OBJS =		@ISC_EXTRA_OBJS@ \
>  		assertions.@O@ backtrace.@O@ backtrace-emptytbl.@O@ base32.@O@ \
> -		base64.@O@ buffer.@O@ bufferlist.@O@ \
> +		base64.@O@ buffer.@O@ bufferlist.@O@ counter.@O@ \
>  		error.@O@ event.@O@ \
>  		hash.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \
>  		inet_aton.@O@ iterated_hash.@O@ lex.@O@ lfsr.@O@ log.@O@ \
> @@ -86,7 +86,7 @@
>  
>  SRCS =		@ISC_EXTRA_SRCS@ \
>  		assertions.c backtrace.c backtrace-emptytbl.c base32.c \
> -		base64.c buffer.c bufferlist.c \
> +		base64.c buffer.c bufferlist.c counter.c \
>  		error.c event.c \
>  		hash.c hex.c hmacmd5.c hmacsha.c \
>  		inet_aton.c iterated_hash.c lex.c log.c lfsr.c \
> diff -u bind9-9.9.5.dfsg/lib/isc/Makefile.in bind9-9.9.5.dfsg/lib/isc/Makefile.in
> --- bind9-9.9.5.dfsg/lib/isc/Makefile.in
> +++ bind9-9.9.5.dfsg/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 @@
>  OBJS =		@ISC_EXTRA_OBJS@ \
>  		assertions.@O@ backtrace.@O@ base32.@O@ base64.@O@ \
>  		bitstring.@O@ buffer.@O@ bufferlist.@O@ commandline.@O@ \
> -		error.@O@ event.@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@ \
> @@ -71,8 +69,8 @@
>  # Alphabetically
>  SRCS =		@ISC_EXTRA_SRCS@ \
>  		assertions.c backtrace.c base32.c base64.c bitstring.c \
> -		buffer.c bufferlist.c commandline.c error.c event.c \
> -		heap.c hex.c hmacmd5.c hmacsha.c \
> +		buffer.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 \
>  		md5.c mem.c mutexblock.c \
> diff -u bind9-9.9.5.dfsg/lib/isccfg/namedconf.c bind9-9.9.5.dfsg/lib/isccfg/namedconf.c
> --- bind9-9.9.5.dfsg/lib/isccfg/namedconf.c
> +++ bind9-9.9.5.dfsg/lib/isccfg/namedconf.c
> @@ -1421,6 +1421,8 @@
>  	{ "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-cache-ttl", &cfg_type_uint32, 0 },
>  	{ "min-ncache-ttl", &cfg_type_uint32, 0 },
> only in patch2:
> unchanged:
> --- bind9-9.9.5.dfsg.orig/bin/named/query.c
> +++ bind9-9.9.5.dfsg/bin/named/query.c
> @@ -3872,12 +3872,11 @@
>  		peeraddr = &client->peeraddr;
>  	else
>  		peeraddr = NULL;
> -	result = dns_resolver_createfetch2(client->view->resolver,
> +	result = dns_resolver_createfetch3(client->view->resolver,
>  					   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);
>  
> only in patch2:
> unchanged:
> --- bind9-9.9.5.dfsg.orig/doc/arm/Bv9ARM-book.xml
> +++ bind9-9.9.5.dfsg/doc/arm/Bv9ARM-book.xml
> @@ -4845,6 +4845,8 @@
>      <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>
> @@ -8524,6 +8526,35 @@
>  		</para>
>  	      </listitem>
>  	    </varlistentry>
> +
> +	    <varlistentry id="max-recursion-depth">
> +	      <term><command>max-recursion-depth</command></term>
> +	      <listitem>
> +		<para>
> +		  Sets the maximum number of levels of recursion
> +		  that are permitted at any one time while servicing
> +		  a recursive query. Resolving a name may require
> +		  looking up a name server address, which in turn
> +		  requires resolving another name, etc; if the number
> +		  of indirections exceeds this value, the recursive
> +		  query is terminated and returns SERVFAIL.  The
> +		  default is 7.
> +		</para>
> +	      </listitem>
> +	    </varlistentry>
> +
> +	    <varlistentry id="max-recursion-queries">
> +	      <term><command>max-recursion-queries</command></term>
> +	      <listitem>
> +		<para>
> +		  Sets the maximum number of iterative queries that
> +		  may be sent while servicing a recursive query.
> +		  If more queries are sent, the recursive query
> +		  is terminated and returns SERVFAIL. The default
> +		  is 50.
> +		</para>
> +	      </listitem>
> +	    </varlistentry>
>  
>  	    <varlistentry>
>  	      <term><command>masterfile-format</command></term>
> only in patch2:
> unchanged:
> --- bind9-9.9.5.dfsg.orig/lib/dns/adb.c
> +++ bind9-9.9.5.dfsg/lib/dns/adb.c
> @@ -201,6 +201,7 @@
>  	unsigned int                    magic;
>  	dns_fetch_t                    *fetch;
>  	dns_rdataset_t                  rdataset;
> +	unsigned int			depth;
>  };
>  
>  /*%
> @@ -300,8 +301,7 @@
>  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);
> @@ -309,6 +309,7 @@
>  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 *);
> @@ -2770,6 +2771,19 @@
>  		   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;
> @@ -3000,7 +3014,7 @@
>  		 * 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",
> @@ -3011,7 +3025,7 @@
>  		 * 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: "
> @@ -3754,6 +3768,12 @@
>  		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);
> @@ -3791,9 +3811,8 @@
>  }
>  
>  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;
> @@ -3838,12 +3857,14 @@
>  		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;
>  
> only in patch2:
> unchanged:
> --- bind9-9.9.5.dfsg.orig/lib/dns/include/dns/adb.h
> +++ bind9-9.9.5.dfsg/lib/dns/include/dns/adb.h
> @@ -334,6 +334,13 @@
>  		   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
> only in patch2:
> unchanged:
> --- bind9-9.9.5.dfsg.orig/lib/dns/include/dns/resolver.h
> +++ bind9-9.9.5.dfsg/lib/dns/include/dns/resolver.h
> @@ -274,6 +274,18 @@
>  			  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.
>   *
> @@ -573,6 +585,30 @@
>   *
>   * Requires:
>   * \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
> only in patch2:
> unchanged:
> --- bind9-9.9.5.dfsg.orig/lib/isc/counter.c
> +++ bind9-9.9.5.dfsg/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);
> +}
> only in patch2:
> unchanged:
> --- bind9-9.9.5.dfsg.orig/lib/isc/include/isc/Makefile.in
> +++ bind9-9.9.5.dfsg/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 @@
>  # install target below.
>  #
>  HEADERS =	app.h assertions.h base64.h bind9.h bitstring.h boolean.h \
> -		buffer.h bufferlist.h commandline.h entropy.h error.h event.h \
> +		buffer.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 \
>  		interfaceiter.h @ISC_IPV6_H@ iterated_hash.h \
> only in patch2:
> unchanged:
> --- bind9-9.9.5.dfsg.orig/lib/isc/include/isc/counter.h
> +++ bind9-9.9.5.dfsg/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 */
> only in patch2:
> unchanged:
> --- bind9-9.9.5.dfsg.orig/lib/isc/include/isc/types.h
> +++ bind9-9.9.5.dfsg/lib/isc/include/isc/types.h
> @@ -50,6 +50,7 @@
>  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 */
> only in patch2:
> unchanged:
> --- bind9-9.9.5.dfsg.orig/lib/isc/tests/Makefile.in
> +++ bind9-9.9.5.dfsg/lib/isc/tests/Makefile.in
> @@ -39,7 +39,7 @@
>  		lex_test.c \
>  		sockaddr_test.c symtab_test.c task_test.c queue_test.c \
>  		parse_test.c pool_test.c regex_test.c safe_test.c \
> -		time_test.c
> +		time_test.c counter_test.c
>  
>  SUBDIRS =
>  TARGETS =	taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@ \
> @@ -47,7 +47,7 @@
>  		sockaddr_test@EXEEXT@ symtab_test@EXEEXT@ task_test@EXEEXT@ \
>  		queue_test@EXEEXT@ parse_test@EXEEXT@ pool_test@EXEEXT@ \
>  		regex_test@EXEEXT@ safe_test@EXEEXT@ \
> -		time_test@EXEEXT@
> +		time_test@EXEEXT@ counter_test@EXEEXT@
>  
>  @BIND9_MAKE_RULES@
>  
> @@ -103,6 +103,10 @@
>  	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
>  			time_test.@O@ ${ISCLIBS} ${LIBS}
>  
> +counter_test@EXEEXT@: counter_test.@O@ ${ISCDEPLIBS}
> +	${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
> +			counter_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
> +
>  unit::
>  	sh ${top_srcdir}/unit/unittest.sh
>  
> only in patch2:
> unchanged:
> --- bind9-9.9.5.dfsg.orig/lib/isc/tests/counter_test.c
> +++ bind9-9.9.5.dfsg/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());
> +}
> +

Attachment: signature.asc
Description: Digital signature


Reply to: