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