PageRenderTime 73ms CodeModel.GetById 11ms app.highlight 56ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/lib/dns/ncache.c

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