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