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