Home | History | Annotate | Line # | Download | only in dns
ncache.c revision 1.1.1.1
      1 /*	$NetBSD: ncache.c,v 1.1.1.1 2018/08/12 12:08:09 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * This Source Code Form is subject to the terms of the Mozilla Public
      7  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9  *
     10  * See the COPYRIGHT file distributed with this work for additional
     11  * information regarding copyright ownership.
     12  */
     13 
     14 
     15 /*! \file */
     16 
     17 #include <config.h>
     18 
     19 #include <isc/buffer.h>
     20 #include <isc/util.h>
     21 
     22 #include <dns/db.h>
     23 #include <dns/message.h>
     24 #include <dns/ncache.h>
     25 #include <dns/rdata.h>
     26 #include <dns/rdatalist.h>
     27 #include <dns/rdataset.h>
     28 #include <dns/rdatastruct.h>
     29 
     30 #define DNS_NCACHE_RDATA 20U
     31 
     32 /*
     33  * The format of an ncache rdata is a sequence of zero or more records of
     34  * the following format:
     35  *
     36  *	owner name
     37  *	type
     38  *	trust
     39  *	rdata count
     40  *		rdata length			These two occur 'rdata count'
     41  *		rdata				times.
     42  *
     43  */
     44 
     45 static isc_result_t
     46 addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
     47 	  dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
     48 	  isc_boolean_t optout, isc_boolean_t secure,
     49 	  dns_rdataset_t *addedrdataset);
     50 
     51 static inline isc_result_t
     52 copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
     53 	isc_result_t result;
     54 	unsigned int count;
     55 	isc_region_t ar, r;
     56 	dns_rdata_t rdata = DNS_RDATA_INIT;
     57 
     58 	/*
     59 	 * Copy the rdataset count to the buffer.
     60 	 */
     61 	isc_buffer_availableregion(buffer, &ar);
     62 	if (ar.length < 2)
     63 		return (ISC_R_NOSPACE);
     64 	count = dns_rdataset_count(rdataset);
     65 	INSIST(count <= 65535);
     66 	isc_buffer_putuint16(buffer, (isc_uint16_t)count);
     67 
     68 	result = dns_rdataset_first(rdataset);
     69 	while (result == ISC_R_SUCCESS) {
     70 		dns_rdataset_current(rdataset, &rdata);
     71 		dns_rdata_toregion(&rdata, &r);
     72 		INSIST(r.length <= 65535);
     73 		isc_buffer_availableregion(buffer, &ar);
     74 		if (ar.length < 2)
     75 			return (ISC_R_NOSPACE);
     76 		/*
     77 		 * Copy the rdata length to the buffer.
     78 		 */
     79 		isc_buffer_putuint16(buffer, (isc_uint16_t)r.length);
     80 		/*
     81 		 * Copy the rdata to the buffer.
     82 		 */
     83 		result = isc_buffer_copyregion(buffer, &r);
     84 		if (result != ISC_R_SUCCESS)
     85 			return (result);
     86 		dns_rdata_reset(&rdata);
     87 		result = dns_rdataset_next(rdataset);
     88 	}
     89 	if (result != ISC_R_NOMORE)
     90 		return (result);
     91 
     92 	return (ISC_R_SUCCESS);
     93 }
     94 
     95 isc_result_t
     96 dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
     97 	       dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
     98 	       dns_rdataset_t *addedrdataset)
     99 {
    100 	return (addoptout(message, cache, node, covers, now, maxttl,
    101 			  ISC_FALSE, ISC_FALSE, addedrdataset));
    102 }
    103 
    104 isc_result_t
    105 dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
    106 		     dns_dbnode_t *node, dns_rdatatype_t covers,
    107 		     isc_stdtime_t now, dns_ttl_t maxttl,
    108 		     isc_boolean_t optout, dns_rdataset_t *addedrdataset)
    109 {
    110 	return (addoptout(message, cache, node, covers, now, maxttl,
    111 			  optout, ISC_TRUE, addedrdataset));
    112 }
    113 
    114 static isc_result_t
    115 addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
    116 	  dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
    117 	  isc_boolean_t optout, isc_boolean_t secure,
    118 	  dns_rdataset_t *addedrdataset)
    119 {
    120 	isc_result_t result;
    121 	isc_buffer_t buffer;
    122 	isc_region_t r;
    123 	dns_rdataset_t *rdataset;
    124 	dns_rdatatype_t type;
    125 	dns_name_t *name;
    126 	dns_ttl_t ttl;
    127 	dns_trust_t trust;
    128 	dns_rdata_t rdata[DNS_NCACHE_RDATA];
    129 	dns_rdataset_t ncrdataset;
    130 	dns_rdatalist_t ncrdatalist;
    131 	unsigned char data[4096];
    132 	unsigned int next = 0;
    133 
    134 	/*
    135 	 * Convert the authority data from 'message' into a negative cache
    136 	 * rdataset, and store it in 'cache' at 'node'.
    137 	 */
    138 
    139 	REQUIRE(message != NULL);
    140 
    141 	/*
    142 	 * We assume that all data in the authority section has been
    143 	 * validated by the caller.
    144 	 */
    145 
    146 	/*
    147 	 * Initialize the list.
    148 	 */
    149 	dns_rdatalist_init(&ncrdatalist);
    150 	ncrdatalist.rdclass = dns_db_class(cache);
    151 	ncrdatalist.covers = covers;
    152 	ncrdatalist.ttl = maxttl;
    153 
    154 	/*
    155 	 * Build an ncache rdatas into buffer.
    156 	 */
    157 	ttl = maxttl;
    158 	trust = 0xffff;
    159 	isc_buffer_init(&buffer, data, sizeof(data));
    160 	if (message->counts[DNS_SECTION_AUTHORITY])
    161 		result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
    162 	else
    163 		result = ISC_R_NOMORE;
    164 	while (result == ISC_R_SUCCESS) {
    165 		name = NULL;
    166 		dns_message_currentname(message, DNS_SECTION_AUTHORITY,
    167 					&name);
    168 		if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
    169 			for (rdataset = ISC_LIST_HEAD(name->list);
    170 			     rdataset != NULL;
    171 			     rdataset = ISC_LIST_NEXT(rdataset, link)) {
    172 				if ((rdataset->attributes &
    173 				     DNS_RDATASETATTR_NCACHE) == 0)
    174 					continue;
    175 				type = rdataset->type;
    176 				if (type == dns_rdatatype_rrsig)
    177 					type = rdataset->covers;
    178 				if (type == dns_rdatatype_soa ||
    179 				    type == dns_rdatatype_nsec ||
    180 				    type == dns_rdatatype_nsec3) {
    181 					if (ttl > rdataset->ttl)
    182 						ttl = rdataset->ttl;
    183 					if (trust > rdataset->trust)
    184 						trust = rdataset->trust;
    185 					/*
    186 					 * Copy the owner name to the buffer.
    187 					 */
    188 					dns_name_toregion(name, &r);
    189 					result = isc_buffer_copyregion(&buffer,
    190 								       &r);
    191 					if (result != ISC_R_SUCCESS)
    192 						return (result);
    193 					/*
    194 					 * Copy the type to the buffer.
    195 					 */
    196 					isc_buffer_availableregion(&buffer,
    197 								   &r);
    198 					if (r.length < 3)
    199 						return (ISC_R_NOSPACE);
    200 					isc_buffer_putuint16(&buffer,
    201 							     rdataset->type);
    202 					isc_buffer_putuint8(&buffer,
    203 					       (unsigned char)rdataset->trust);
    204 					/*
    205 					 * Copy the rdataset into the buffer.
    206 					 */
    207 					result = copy_rdataset(rdataset,
    208 							       &buffer);
    209 					if (result != ISC_R_SUCCESS)
    210 						return (result);
    211 
    212 					if (next >= DNS_NCACHE_RDATA)
    213 						return (ISC_R_NOSPACE);
    214 					dns_rdata_init(&rdata[next]);
    215 					isc_buffer_remainingregion(&buffer, &r);
    216 					rdata[next].data = r.base;
    217 					rdata[next].length = r.length;
    218 					rdata[next].rdclass =
    219 						ncrdatalist.rdclass;
    220 					rdata[next].type = 0;
    221 					rdata[next].flags = 0;
    222 					ISC_LIST_APPEND(ncrdatalist.rdata,
    223 							&rdata[next], link);
    224 					isc_buffer_forward(&buffer, r.length);
    225 					next++;
    226 				}
    227 			}
    228 		}
    229 		result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
    230 	}
    231 	if (result != ISC_R_NOMORE)
    232 		return (result);
    233 
    234 	if (trust == 0xffff) {
    235 		if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
    236 		    message->counts[DNS_SECTION_ANSWER] == 0) {
    237 			/*
    238 			 * The response has aa set and we haven't followed
    239 			 * any CNAME or DNAME chains.
    240 			 */
    241 			trust = dns_trust_authauthority;
    242 		} else
    243 			trust = dns_trust_additional;
    244 		ttl = 0;
    245 	}
    246 
    247 	INSIST(trust != 0xffff);
    248 
    249 	ncrdatalist.ttl = ttl;
    250 
    251 	dns_rdataset_init(&ncrdataset);
    252 	RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
    253 		      == ISC_R_SUCCESS);
    254 	if (!secure && trust > dns_trust_answer)
    255 		trust = dns_trust_answer;
    256 	ncrdataset.trust = trust;
    257 	ncrdataset.attributes |= DNS_RDATASETATTR_NEGATIVE;
    258 	if (message->rcode == dns_rcode_nxdomain)
    259 		ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
    260 	if (optout)
    261 		ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT;
    262 
    263 	return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
    264 				   0, addedrdataset));
    265 }
    266 
    267 isc_result_t
    268 dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
    269 		  isc_buffer_t *target, unsigned int options,
    270 		  unsigned int *countp)
    271 {
    272 	dns_rdata_t rdata = DNS_RDATA_INIT;
    273 	isc_result_t result;
    274 	isc_region_t remaining, tavailable;
    275 	isc_buffer_t source, savedbuffer, rdlen;
    276 	dns_name_t name;
    277 	dns_rdatatype_t type;
    278 	unsigned int i, rcount, count;
    279 
    280 	/*
    281 	 * Convert the negative caching rdataset 'rdataset' to wire format,
    282 	 * compressing names as specified in 'cctx', and storing the result in
    283 	 * 'target'.
    284 	 */
    285 
    286 	REQUIRE(rdataset != NULL);
    287 	REQUIRE(rdataset->type == 0);
    288 	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
    289 
    290 	savedbuffer = *target;
    291 	count = 0;
    292 
    293 	result = dns_rdataset_first(rdataset);
    294 	while (result == ISC_R_SUCCESS) {
    295 		dns_rdataset_current(rdataset, &rdata);
    296 		isc_buffer_init(&source, rdata.data, rdata.length);
    297 		isc_buffer_add(&source, rdata.length);
    298 		dns_name_init(&name, NULL);
    299 		isc_buffer_remainingregion(&source, &remaining);
    300 		dns_name_fromregion(&name, &remaining);
    301 		INSIST(remaining.length >= name.length);
    302 		isc_buffer_forward(&source, name.length);
    303 		remaining.length -= name.length;
    304 
    305 		INSIST(remaining.length >= 5);
    306 		type = isc_buffer_getuint16(&source);
    307 		isc_buffer_forward(&source, 1);
    308 		rcount = isc_buffer_getuint16(&source);
    309 
    310 		for (i = 0; i < rcount; i++) {
    311 			/*
    312 			 * Get the length of this rdata and set up an
    313 			 * rdata structure for it.
    314 			 */
    315 			isc_buffer_remainingregion(&source, &remaining);
    316 			INSIST(remaining.length >= 2);
    317 			dns_rdata_reset(&rdata);
    318 			rdata.length = isc_buffer_getuint16(&source);
    319 			isc_buffer_remainingregion(&source, &remaining);
    320 			rdata.data = remaining.base;
    321 			rdata.type = type;
    322 			rdata.rdclass = rdataset->rdclass;
    323 			INSIST(remaining.length >= rdata.length);
    324 			isc_buffer_forward(&source, rdata.length);
    325 
    326 			if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
    327 			    dns_rdatatype_isdnssec(type))
    328 				continue;
    329 
    330 			/*
    331 			 * Write the name.
    332 			 */
    333 			dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
    334 			result = dns_name_towire(&name, cctx, target);
    335 			if (result != ISC_R_SUCCESS)
    336 				goto rollback;
    337 
    338 			/*
    339 			 * See if we have space for type, class, ttl, and
    340 			 * rdata length.  Write the type, class, and ttl.
    341 			 */
    342 			isc_buffer_availableregion(target, &tavailable);
    343 			if (tavailable.length < 10) {
    344 				result = ISC_R_NOSPACE;
    345 				goto rollback;
    346 			}
    347 			isc_buffer_putuint16(target, type);
    348 			isc_buffer_putuint16(target, rdataset->rdclass);
    349 			isc_buffer_putuint32(target, rdataset->ttl);
    350 
    351 			/*
    352 			 * Save space for rdata length.
    353 			 */
    354 			rdlen = *target;
    355 			isc_buffer_add(target, 2);
    356 
    357 			/*
    358 			 * Write the rdata.
    359 			 */
    360 			result = dns_rdata_towire(&rdata, cctx, target);
    361 			if (result != ISC_R_SUCCESS)
    362 				goto rollback;
    363 
    364 			/*
    365 			 * Set the rdata length field to the compressed
    366 			 * length.
    367 			 */
    368 			INSIST((target->used >= rdlen.used + 2) &&
    369 			       (target->used - rdlen.used - 2 < 65536));
    370 			isc_buffer_putuint16(&rdlen,
    371 					     (isc_uint16_t)(target->used -
    372 							    rdlen.used - 2));
    373 
    374 			count++;
    375 		}
    376 		INSIST(isc_buffer_remaininglength(&source) == 0);
    377 		result = dns_rdataset_next(rdataset);
    378 		dns_rdata_reset(&rdata);
    379 	}
    380 	if (result != ISC_R_NOMORE)
    381 		goto rollback;
    382 
    383 	*countp = count;
    384 
    385 	return (ISC_R_SUCCESS);
    386 
    387  rollback:
    388 	INSIST(savedbuffer.used < 65536);
    389 	dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
    390 	*countp = 0;
    391 	*target = savedbuffer;
    392 
    393 	return (result);
    394 }
    395 
    396 static void
    397 rdataset_disassociate(dns_rdataset_t *rdataset) {
    398 	UNUSED(rdataset);
    399 }
    400 
    401 static isc_result_t
    402 rdataset_first(dns_rdataset_t *rdataset) {
    403 	unsigned char *raw = rdataset->private3;
    404 	unsigned int count;
    405 
    406 	count = raw[0] * 256 + raw[1];
    407 	if (count == 0) {
    408 		rdataset->private5 = NULL;
    409 		return (ISC_R_NOMORE);
    410 	}
    411 	raw += 2;
    412 	/*
    413 	 * The privateuint4 field is the number of rdata beyond the cursor
    414 	 * position, so we decrement the total count by one before storing
    415 	 * it.
    416 	 */
    417 	count--;
    418 	rdataset->privateuint4 = count;
    419 	rdataset->private5 = raw;
    420 
    421 	return (ISC_R_SUCCESS);
    422 }
    423 
    424 static isc_result_t
    425 rdataset_next(dns_rdataset_t *rdataset) {
    426 	unsigned int count;
    427 	unsigned int length;
    428 	unsigned char *raw;
    429 
    430 	count = rdataset->privateuint4;
    431 	if (count == 0)
    432 		return (ISC_R_NOMORE);
    433 	count--;
    434 	rdataset->privateuint4 = count;
    435 	raw = rdataset->private5;
    436 	length = raw[0] * 256 + raw[1];
    437 	raw += length + 2;
    438 	rdataset->private5 = raw;
    439 
    440 	return (ISC_R_SUCCESS);
    441 }
    442 
    443 static void
    444 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
    445 	unsigned char *raw = rdataset->private5;
    446 	isc_region_t r;
    447 
    448 	REQUIRE(raw != NULL);
    449 
    450 	r.length = raw[0] * 256 + raw[1];
    451 	raw += 2;
    452 	r.base = raw;
    453 	dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
    454 }
    455 
    456 static void
    457 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
    458 	*target = *source;
    459 
    460 	/*
    461 	 * Reset iterator state.
    462 	 */
    463 	target->privateuint4 = 0;
    464 	target->private5 = NULL;
    465 }
    466 
    467 static unsigned int
    468 rdataset_count(dns_rdataset_t *rdataset) {
    469 	unsigned char *raw = rdataset->private3;
    470 	unsigned int count;
    471 
    472 	count = raw[0] * 256 + raw[1];
    473 
    474 	return (count);
    475 }
    476 
    477 static void
    478 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
    479 	unsigned char *raw = rdataset->private3;
    480 
    481 	raw[-1] = (unsigned char)trust;
    482 }
    483 
    484 static dns_rdatasetmethods_t rdataset_methods = {
    485 	rdataset_disassociate,
    486 	rdataset_first,
    487 	rdataset_next,
    488 	rdataset_current,
    489 	rdataset_clone,
    490 	rdataset_count,
    491 	NULL,			/* addnoqname */
    492 	NULL,			/* getnoqname */
    493 	NULL,			/* addclosest */
    494 	NULL,			/* getclosest */
    495 	rdataset_settrust,	/* settrust */
    496 	NULL,			/* expire */
    497 	NULL,			/* clearprefetch */
    498 	NULL,			/* setownercase */
    499 	NULL,			/* getownercase */
    500 	NULL			/* addglue */
    501 };
    502 
    503 isc_result_t
    504 dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
    505 		       dns_rdatatype_t type, dns_rdataset_t *rdataset)
    506 {
    507 	isc_result_t result;
    508 	dns_rdata_t rdata = DNS_RDATA_INIT;
    509 	isc_region_t remaining;
    510 	isc_buffer_t source;
    511 	dns_name_t tname;
    512 	dns_rdatatype_t ttype;
    513 	dns_trust_t trust = dns_trust_none;
    514 	dns_rdataset_t rclone;
    515 
    516 	REQUIRE(ncacherdataset != NULL);
    517 	REQUIRE(ncacherdataset->type == 0);
    518 	REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
    519 	REQUIRE(name != NULL);
    520 	REQUIRE(!dns_rdataset_isassociated(rdataset));
    521 	REQUIRE(type != dns_rdatatype_rrsig);
    522 
    523 	dns_rdataset_init(&rclone);
    524 	dns_rdataset_clone(ncacherdataset, &rclone);
    525 	result = dns_rdataset_first(&rclone);
    526 	while (result == ISC_R_SUCCESS) {
    527 		dns_rdataset_current(&rclone, &rdata);
    528 		isc_buffer_init(&source, rdata.data, rdata.length);
    529 		isc_buffer_add(&source, rdata.length);
    530 		dns_name_init(&tname, NULL);
    531 		isc_buffer_remainingregion(&source, &remaining);
    532 		dns_name_fromregion(&tname, &remaining);
    533 		INSIST(remaining.length >= tname.length);
    534 		isc_buffer_forward(&source, tname.length);
    535 		remaining.length -= tname.length;
    536 
    537 		INSIST(remaining.length >= 3);
    538 		ttype = isc_buffer_getuint16(&source);
    539 
    540 		if (ttype == type && dns_name_equal(&tname, name)) {
    541 			trust = isc_buffer_getuint8(&source);
    542 			INSIST(trust <= dns_trust_ultimate);
    543 			isc_buffer_remainingregion(&source, &remaining);
    544 			break;
    545 		}
    546 		result = dns_rdataset_next(&rclone);
    547 		dns_rdata_reset(&rdata);
    548 	}
    549 	dns_rdataset_disassociate(&rclone);
    550 	if (result == ISC_R_NOMORE)
    551 		return (ISC_R_NOTFOUND);
    552 	if (result != ISC_R_SUCCESS)
    553 		return (result);
    554 
    555 	INSIST(remaining.length != 0);
    556 
    557 	rdataset->methods = &rdataset_methods;
    558 	rdataset->rdclass = ncacherdataset->rdclass;
    559 	rdataset->type = type;
    560 	rdataset->covers = 0;
    561 	rdataset->ttl = ncacherdataset->ttl;
    562 	rdataset->trust = trust;
    563 	rdataset->private1 = NULL;
    564 	rdataset->private2 = NULL;
    565 
    566 	rdataset->private3 = remaining.base;
    567 
    568 	/*
    569 	 * Reset iterator state.
    570 	 */
    571 	rdataset->privateuint4 = 0;
    572 	rdataset->private5 = NULL;
    573 	rdataset->private6 = NULL;
    574 	return (ISC_R_SUCCESS);
    575 }
    576 
    577 isc_result_t
    578 dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
    579 			  dns_rdatatype_t covers, dns_rdataset_t *rdataset)
    580 {
    581 	dns_name_t tname;
    582 	dns_rdata_rrsig_t rrsig;
    583 	dns_rdata_t rdata = DNS_RDATA_INIT;
    584 	dns_rdataset_t rclone;
    585 	dns_rdatatype_t type;
    586 	dns_trust_t trust = dns_trust_none;
    587 	isc_buffer_t source;
    588 	isc_region_t remaining, sigregion;
    589 	isc_result_t result;
    590 	unsigned char *raw;
    591 	unsigned int count;
    592 
    593 	REQUIRE(ncacherdataset != NULL);
    594 	REQUIRE(ncacherdataset->type == 0);
    595 	REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
    596 	REQUIRE(name != NULL);
    597 	REQUIRE(!dns_rdataset_isassociated(rdataset));
    598 
    599 	dns_rdataset_init(&rclone);
    600 	dns_rdataset_clone(ncacherdataset, &rclone);
    601 	result = dns_rdataset_first(&rclone);
    602 	while (result == ISC_R_SUCCESS) {
    603 		dns_rdataset_current(&rclone, &rdata);
    604 		isc_buffer_init(&source, rdata.data, rdata.length);
    605 		isc_buffer_add(&source, rdata.length);
    606 		dns_name_init(&tname, NULL);
    607 		isc_buffer_remainingregion(&source, &remaining);
    608 		dns_name_fromregion(&tname, &remaining);
    609 		INSIST(remaining.length >= tname.length);
    610 		isc_buffer_forward(&source, tname.length);
    611 		isc_region_consume(&remaining, tname.length);
    612 
    613 		INSIST(remaining.length >= 2);
    614 		type = isc_buffer_getuint16(&source);
    615 		isc_region_consume(&remaining, 2);
    616 
    617 		if (type != dns_rdatatype_rrsig ||
    618 		    !dns_name_equal(&tname, name)) {
    619 			result = dns_rdataset_next(&rclone);
    620 			dns_rdata_reset(&rdata);
    621 			continue;
    622 		}
    623 
    624 		INSIST(remaining.length >= 1);
    625 		trust = isc_buffer_getuint8(&source);
    626 		INSIST(trust <= dns_trust_ultimate);
    627 		isc_region_consume(&remaining, 1);
    628 
    629 		raw = remaining.base;
    630 		count = raw[0] * 256 + raw[1];
    631 		INSIST(count > 0);
    632 		raw += 2;
    633 		sigregion.length = raw[0] * 256 + raw[1];
    634 		raw += 2;
    635 		sigregion.base = raw;
    636 		dns_rdata_reset(&rdata);
    637 		dns_rdata_fromregion(&rdata, rdataset->rdclass,
    638 				     dns_rdatatype_rrsig, &sigregion);
    639 		(void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
    640 		if (rrsig.covered == covers) {
    641 			isc_buffer_remainingregion(&source, &remaining);
    642 			break;
    643 		}
    644 
    645 		result = dns_rdataset_next(&rclone);
    646 		dns_rdata_reset(&rdata);
    647 	}
    648 	dns_rdataset_disassociate(&rclone);
    649 	if (result == ISC_R_NOMORE)
    650 		return (ISC_R_NOTFOUND);
    651 	if (result != ISC_R_SUCCESS)
    652 		return (result);
    653 
    654 	INSIST(remaining.length != 0);
    655 
    656 	rdataset->methods = &rdataset_methods;
    657 	rdataset->rdclass = ncacherdataset->rdclass;
    658 	rdataset->type = dns_rdatatype_rrsig;
    659 	rdataset->covers = covers;
    660 	rdataset->ttl = ncacherdataset->ttl;
    661 	rdataset->trust = trust;
    662 	rdataset->private1 = NULL;
    663 	rdataset->private2 = NULL;
    664 
    665 	rdataset->private3 = remaining.base;
    666 
    667 	/*
    668 	 * Reset iterator state.
    669 	 */
    670 	rdataset->privateuint4 = 0;
    671 	rdataset->private5 = NULL;
    672 	rdataset->private6 = NULL;
    673 	return (ISC_R_SUCCESS);
    674 }
    675 
    676 void
    677 dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
    678 		   dns_rdataset_t *rdataset)
    679 {
    680 	dns_rdata_t rdata = DNS_RDATA_INIT;
    681 	dns_trust_t trust;
    682 	isc_region_t remaining, sigregion;
    683 	isc_buffer_t source;
    684 	dns_name_t tname;
    685 	dns_rdatatype_t type;
    686 	unsigned int count;
    687 	dns_rdata_rrsig_t rrsig;
    688 	unsigned char *raw;
    689 
    690 	REQUIRE(ncacherdataset != NULL);
    691 	REQUIRE(ncacherdataset->type == 0);
    692 	REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
    693 	REQUIRE(found != NULL);
    694 	REQUIRE(!dns_rdataset_isassociated(rdataset));
    695 
    696 	dns_rdataset_current(ncacherdataset, &rdata);
    697 	isc_buffer_init(&source, rdata.data, rdata.length);
    698 	isc_buffer_add(&source, rdata.length);
    699 
    700 	dns_name_init(&tname, NULL);
    701 	isc_buffer_remainingregion(&source, &remaining);
    702 	dns_name_fromregion(found, &remaining);
    703 	INSIST(remaining.length >= found->length);
    704 	isc_buffer_forward(&source, found->length);
    705 	remaining.length -= found->length;
    706 
    707 	INSIST(remaining.length >= 5);
    708 	type = isc_buffer_getuint16(&source);
    709 	trust = isc_buffer_getuint8(&source);
    710 	INSIST(trust <= dns_trust_ultimate);
    711 	isc_buffer_remainingregion(&source, &remaining);
    712 
    713 	rdataset->methods = &rdataset_methods;
    714 	rdataset->rdclass = ncacherdataset->rdclass;
    715 	rdataset->type = type;
    716 	if (type == dns_rdatatype_rrsig) {
    717 		/*
    718 		 * Extract covers from RRSIG.
    719 		 */
    720 		raw = remaining.base;
    721 		count = raw[0] * 256 + raw[1];
    722 		INSIST(count > 0);
    723 		raw += 2;
    724 		sigregion.length = raw[0] * 256 + raw[1];
    725 		raw += 2;
    726 		sigregion.base = raw;
    727 		dns_rdata_reset(&rdata);
    728 		dns_rdata_fromregion(&rdata, rdataset->rdclass,
    729 				     rdataset->type, &sigregion);
    730 		(void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
    731 		rdataset->covers = rrsig.covered;
    732 	} else
    733 		rdataset->covers = 0;
    734 	rdataset->ttl = ncacherdataset->ttl;
    735 	rdataset->trust = trust;
    736 	rdataset->private1 = NULL;
    737 	rdataset->private2 = NULL;
    738 
    739 	rdataset->private3 = remaining.base;
    740 
    741 	/*
    742 	 * Reset iterator state.
    743 	 */
    744 	rdataset->privateuint4 = 0;
    745 	rdataset->private5 = NULL;
    746 	rdataset->private6 = NULL;
    747 }
    748