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