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