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
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 minttl,
48	  dns_ttl_t maxttl, bool optout, bool 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	}
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
99isc_result_t
100dns_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
107isc_result_t
108dns_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
116static isc_result_t
117addoptout(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
287isc_result_t
288dns_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
411rollback:
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
420static void
421rdataset_disassociate(dns_rdataset_t *rdataset) {
422	UNUSED(rdataset);
423}
424
425static isc_result_t
426rdataset_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
448static isc_result_t
449rdataset_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
468static void
469rdataset_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
481static void
482rdataset_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
492static unsigned int
493rdataset_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
502static void
503rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
504	unsigned char *raw = rdataset->private3;
505
506	raw[-1] = (unsigned char)trust;
507}
508
509static 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
528isc_result_t
529dns_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
603isc_result_t
604dns_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
703void
704dns_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