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