ncache.c revision 287410
1226048Sobrien/*
2226048Sobrien * Copyright (C) 2004, 2005, 2007, 2008, 2010-2013  Internet Systems Consortium, Inc. ("ISC")
3362844Sdelphij * Copyright (C) 1999-2003  Internet Software Consortium.
4226048Sobrien *
5226048Sobrien * Permission to use, copy, modify, and/or distribute this software for any
6226048Sobrien * purpose with or without fee is hereby granted, provided that the above
7226048Sobrien * copyright notice and this permission notice appear in all copies.
8354939Sdelphij *
9354939Sdelphij * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10354939Sdelphij * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11354939Sdelphij * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12226048Sobrien * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13354939Sdelphij * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14354939Sdelphij * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15354939Sdelphij * PERFORMANCE OF THIS SOFTWARE.
16354939Sdelphij */
17354939Sdelphij
18354939Sdelphij/* $Id$ */
19354939Sdelphij
20354939Sdelphij/*! \file */
21354939Sdelphij
22354939Sdelphij#include <config.h>
23354939Sdelphij
24354939Sdelphij#include <isc/buffer.h>
25354939Sdelphij#include <isc/util.h>
26354939Sdelphij
27354939Sdelphij#include <dns/db.h>
28354939Sdelphij#include <dns/message.h>
29354939Sdelphij#include <dns/ncache.h>
30354939Sdelphij#include <dns/rdata.h>
31354939Sdelphij#include <dns/rdatalist.h>
32354939Sdelphij#include <dns/rdataset.h>
33354939Sdelphij#include <dns/rdatastruct.h>
34354939Sdelphij
35354939Sdelphij#define DNS_NCACHE_RDATA 20U
36354939Sdelphij
37354939Sdelphij/*
38354939Sdelphij * The format of an ncache rdata is a sequence of zero or more records of
39354939Sdelphij * the following format:
40354939Sdelphij *
41354939Sdelphij *	owner name
42354939Sdelphij *	type
43354939Sdelphij *	trust
44354939Sdelphij *	rdata count
45354939Sdelphij *		rdata length			These two occur 'rdata count'
46354939Sdelphij *		rdata				times.
47354939Sdelphij *
48354939Sdelphij */
49354939Sdelphij
50354939Sdelphijstatic isc_result_t
51354939Sdelphijaddoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
52354939Sdelphij	  dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
53354939Sdelphij	  isc_boolean_t optout, isc_boolean_t secure,
54354939Sdelphij	  dns_rdataset_t *addedrdataset);
55354939Sdelphij
56354939Sdelphijstatic inline isc_result_t
57354939Sdelphijcopy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
58354939Sdelphij	isc_result_t result;
59354939Sdelphij	unsigned int count;
60354939Sdelphij	isc_region_t ar, r;
61354939Sdelphij	dns_rdata_t rdata = DNS_RDATA_INIT;
62354939Sdelphij
63354939Sdelphij	/*
64354939Sdelphij	 * Copy the rdataset count to the buffer.
65354939Sdelphij	 */
66354939Sdelphij	isc_buffer_availableregion(buffer, &ar);
67354939Sdelphij	if (ar.length < 2)
68354939Sdelphij		return (ISC_R_NOSPACE);
69354939Sdelphij	count = dns_rdataset_count(rdataset);
70354939Sdelphij	INSIST(count <= 65535);
71354939Sdelphij	isc_buffer_putuint16(buffer, (isc_uint16_t)count);
72226048Sobrien
73354939Sdelphij	result = dns_rdataset_first(rdataset);
74354939Sdelphij	while (result == ISC_R_SUCCESS) {
75354939Sdelphij		dns_rdataset_current(rdataset, &rdata);
76354939Sdelphij		dns_rdata_toregion(&rdata, &r);
77354939Sdelphij		INSIST(r.length <= 65535);
78354939Sdelphij		isc_buffer_availableregion(buffer, &ar);
79354939Sdelphij		if (ar.length < 2)
80354939Sdelphij			return (ISC_R_NOSPACE);
81354939Sdelphij		/*
82354939Sdelphij		 * Copy the rdata length to the buffer.
83354939Sdelphij		 */
84354939Sdelphij		isc_buffer_putuint16(buffer, (isc_uint16_t)r.length);
85354939Sdelphij		/*
86354939Sdelphij		 * Copy the rdata to the buffer.
87354939Sdelphij		 */
88354939Sdelphij		result = isc_buffer_copyregion(buffer, &r);
89354939Sdelphij		if (result != ISC_R_SUCCESS)
90354939Sdelphij			return (result);
91354939Sdelphij		dns_rdata_reset(&rdata);
92354939Sdelphij		result = dns_rdataset_next(rdataset);
93354939Sdelphij	}
94354939Sdelphij	if (result != ISC_R_NOMORE)
95354939Sdelphij		return (result);
96354939Sdelphij
97354939Sdelphij	return (ISC_R_SUCCESS);
98354939Sdelphij}
99354939Sdelphij
100354939Sdelphijisc_result_t
101354939Sdelphijdns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
102354939Sdelphij	       dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
103354939Sdelphij	       dns_rdataset_t *addedrdataset)
104354939Sdelphij{
105354939Sdelphij	return (addoptout(message, cache, node, covers, now, maxttl,
106354939Sdelphij			  ISC_FALSE, ISC_FALSE, addedrdataset));
107354939Sdelphij}
108354939Sdelphij
109354939Sdelphijisc_result_t
110354939Sdelphijdns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
111354939Sdelphij		     dns_dbnode_t *node, dns_rdatatype_t covers,
112354939Sdelphij		     isc_stdtime_t now, dns_ttl_t maxttl,
113354939Sdelphij		     isc_boolean_t optout, dns_rdataset_t *addedrdataset)
114354939Sdelphij{
115354939Sdelphij	return (addoptout(message, cache, node, covers, now, maxttl,
116354939Sdelphij			  optout, ISC_TRUE, addedrdataset));
117354939Sdelphij}
118354939Sdelphij
119354939Sdelphijstatic isc_result_t
120354939Sdelphijaddoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
121354939Sdelphij	  dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
122354939Sdelphij	  isc_boolean_t optout, isc_boolean_t secure,
123354939Sdelphij	  dns_rdataset_t *addedrdataset)
124354939Sdelphij{
125354939Sdelphij	isc_result_t result;
126354939Sdelphij	isc_buffer_t buffer;
127354939Sdelphij	isc_region_t r;
128354939Sdelphij	dns_rdataset_t *rdataset;
129354939Sdelphij	dns_rdatatype_t type;
130354939Sdelphij	dns_name_t *name;
131354939Sdelphij	dns_ttl_t ttl;
132354939Sdelphij	dns_trust_t trust;
133354939Sdelphij	dns_rdata_t rdata[DNS_NCACHE_RDATA];
134354939Sdelphij	dns_rdataset_t ncrdataset;
135354939Sdelphij	dns_rdatalist_t ncrdatalist;
136354939Sdelphij	unsigned char data[4096];
137354939Sdelphij	unsigned int next = 0;
138354939Sdelphij
139354939Sdelphij	/*
140354939Sdelphij	 * Convert the authority data from 'message' into a negative cache
141354939Sdelphij	 * rdataset, and store it in 'cache' at 'node'.
142354939Sdelphij	 */
143354939Sdelphij
144354939Sdelphij	REQUIRE(message != NULL);
145354939Sdelphij
146354939Sdelphij	/*
147354939Sdelphij	 * We assume that all data in the authority section has been
148354939Sdelphij	 * validated by the caller.
149354939Sdelphij	 */
150354939Sdelphij
151354939Sdelphij	/*
152354939Sdelphij	 * Initialize the list.
153354939Sdelphij	 */
154354939Sdelphij	ncrdatalist.rdclass = dns_db_class(cache);
155354939Sdelphij	ncrdatalist.type = 0;
156354939Sdelphij	ncrdatalist.covers = covers;
157354939Sdelphij	ncrdatalist.ttl = maxttl;
158354939Sdelphij	ISC_LIST_INIT(ncrdatalist.rdata);
159354939Sdelphij	ISC_LINK_INIT(&ncrdatalist, link);
160354939Sdelphij
161354939Sdelphij	/*
162354939Sdelphij	 * Build an ncache rdatas into buffer.
163354939Sdelphij	 */
164354939Sdelphij	ttl = maxttl;
165354939Sdelphij	trust = 0xffff;
166354939Sdelphij	isc_buffer_init(&buffer, data, sizeof(data));
167354939Sdelphij	if (message->counts[DNS_SECTION_AUTHORITY])
168354939Sdelphij		result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
169354939Sdelphij	else
170354939Sdelphij		result = ISC_R_NOMORE;
171354939Sdelphij	while (result == ISC_R_SUCCESS) {
172354939Sdelphij		name = NULL;
173354939Sdelphij		dns_message_currentname(message, DNS_SECTION_AUTHORITY,
174354939Sdelphij					&name);
175354939Sdelphij		if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
176354939Sdelphij			for (rdataset = ISC_LIST_HEAD(name->list);
177354939Sdelphij			     rdataset != NULL;
178354939Sdelphij			     rdataset = ISC_LIST_NEXT(rdataset, link)) {
179354939Sdelphij				if ((rdataset->attributes &
180354939Sdelphij				     DNS_RDATASETATTR_NCACHE) == 0)
181354939Sdelphij					continue;
182354939Sdelphij				type = rdataset->type;
183354939Sdelphij				if (type == dns_rdatatype_rrsig)
184354939Sdelphij					type = rdataset->covers;
185354939Sdelphij				if (type == dns_rdatatype_soa ||
186354939Sdelphij				    type == dns_rdatatype_nsec ||
187354939Sdelphij				    type == dns_rdatatype_nsec3) {
188354939Sdelphij					if (ttl > rdataset->ttl)
189354939Sdelphij						ttl = rdataset->ttl;
190354939Sdelphij					if (trust > rdataset->trust)
191354939Sdelphij						trust = rdataset->trust;
192354939Sdelphij					/*
193354939Sdelphij					 * Copy the owner name to the buffer.
194354939Sdelphij					 */
195267843Sdelphij					dns_name_toregion(name, &r);
196267843Sdelphij					result = isc_buffer_copyregion(&buffer,
197267843Sdelphij								       &r);
198267843Sdelphij					if (result != ISC_R_SUCCESS)
199267843Sdelphij						return (result);
200267843Sdelphij					/*
201267843Sdelphij					 * Copy the type to the buffer.
202267843Sdelphij					 */
203267843Sdelphij					isc_buffer_availableregion(&buffer,
204267843Sdelphij								   &r);
205267843Sdelphij					if (r.length < 3)
206267843Sdelphij						return (ISC_R_NOSPACE);
207267843Sdelphij					isc_buffer_putuint16(&buffer,
208267843Sdelphij							     rdataset->type);
209267843Sdelphij					isc_buffer_putuint8(&buffer,
210267843Sdelphij					       (unsigned char)rdataset->trust);
211267843Sdelphij					/*
212267843Sdelphij					 * Copy the rdataset into the buffer.
213267843Sdelphij					 */
214267843Sdelphij					result = copy_rdataset(rdataset,
215267843Sdelphij							       &buffer);
216267843Sdelphij					if (result != ISC_R_SUCCESS)
217267843Sdelphij						return (result);
218267843Sdelphij
219267843Sdelphij					if (next >= DNS_NCACHE_RDATA)
220267843Sdelphij						return (ISC_R_NOSPACE);
221267843Sdelphij					dns_rdata_init(&rdata[next]);
222354939Sdelphij					isc_buffer_remainingregion(&buffer, &r);
223267843Sdelphij					rdata[next].data = r.base;
224267843Sdelphij					rdata[next].length = r.length;
225267843Sdelphij					rdata[next].rdclass =
226267843Sdelphij						ncrdatalist.rdclass;
227267843Sdelphij					rdata[next].type = 0;
228267843Sdelphij					rdata[next].flags = 0;
229354939Sdelphij					ISC_LIST_APPEND(ncrdatalist.rdata,
230354939Sdelphij							&rdata[next], link);
231354939Sdelphij					isc_buffer_forward(&buffer, r.length);
232267843Sdelphij					next++;
233267843Sdelphij				}
234267843Sdelphij			}
235267843Sdelphij		}
236267843Sdelphij		result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
237267843Sdelphij	}
238267843Sdelphij	if (result != ISC_R_NOMORE)
239267843Sdelphij		return (result);
240267843Sdelphij
241267843Sdelphij	if (trust == 0xffff) {
242267843Sdelphij		if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
243267843Sdelphij		    message->counts[DNS_SECTION_ANSWER] == 0) {
244267843Sdelphij			/*
245267843Sdelphij			 * The response has aa set and we haven't followed
246267843Sdelphij			 * any CNAME or DNAME chains.
247267843Sdelphij			 */
248267843Sdelphij			trust = dns_trust_authauthority;
249267843Sdelphij		} else
250267843Sdelphij			trust = dns_trust_additional;
251267843Sdelphij		ttl = 0;
252267843Sdelphij	}
253354939Sdelphij
254267843Sdelphij	INSIST(trust != 0xffff);
255267843Sdelphij
256267843Sdelphij	ncrdatalist.ttl = ttl;
257267843Sdelphij
258267843Sdelphij	dns_rdataset_init(&ncrdataset);
259267843Sdelphij	RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
260267843Sdelphij		      == ISC_R_SUCCESS);
261267843Sdelphij	if (!secure && trust > dns_trust_answer)
262267843Sdelphij		trust = dns_trust_answer;
263267843Sdelphij	ncrdataset.trust = trust;
264267843Sdelphij	ncrdataset.attributes |= DNS_RDATASETATTR_NEGATIVE;
265267843Sdelphij	if (message->rcode == dns_rcode_nxdomain)
266267843Sdelphij		ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
267267843Sdelphij	if (optout)
268267843Sdelphij		ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT;
269267843Sdelphij
270267843Sdelphij	return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
271267843Sdelphij				   0, addedrdataset));
272267843Sdelphij}
273267843Sdelphij
274267843Sdelphijisc_result_t
275267843Sdelphijdns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
276267843Sdelphij		  isc_buffer_t *target, unsigned int options,
277267843Sdelphij		  unsigned int *countp)
278267843Sdelphij{
279267843Sdelphij	dns_rdata_t rdata = DNS_RDATA_INIT;
280267843Sdelphij	isc_result_t result;
281267843Sdelphij	isc_region_t remaining, tavailable;
282267843Sdelphij	isc_buffer_t source, savedbuffer, rdlen;
283267843Sdelphij	dns_name_t name;
284267843Sdelphij	dns_rdatatype_t type;
285267843Sdelphij	unsigned int i, rcount, count;
286267843Sdelphij
287267843Sdelphij	/*
288267843Sdelphij	 * Convert the negative caching rdataset 'rdataset' to wire format,
289354939Sdelphij	 * compressing names as specified in 'cctx', and storing the result in
290267843Sdelphij	 * 'target'.
291267843Sdelphij	 */
292267843Sdelphij
293226048Sobrien	REQUIRE(rdataset != NULL);
294234250Sobrien	REQUIRE(rdataset->type == 0);
295234250Sobrien	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
296234250Sobrien
297234250Sobrien	savedbuffer = *target;
298234250Sobrien	count = 0;
299267843Sdelphij
300267843Sdelphij	result = dns_rdataset_first(rdataset);
301267843Sdelphij	while (result == ISC_R_SUCCESS) {
302267843Sdelphij		dns_rdataset_current(rdataset, &rdata);
303267843Sdelphij		isc_buffer_init(&source, rdata.data, rdata.length);
304267843Sdelphij		isc_buffer_add(&source, rdata.length);
305267843Sdelphij		dns_name_init(&name, NULL);
306267843Sdelphij		isc_buffer_remainingregion(&source, &remaining);
307267843Sdelphij		dns_name_fromregion(&name, &remaining);
308		INSIST(remaining.length >= name.length);
309		isc_buffer_forward(&source, name.length);
310		remaining.length -= name.length;
311
312		INSIST(remaining.length >= 5);
313		type = isc_buffer_getuint16(&source);
314		isc_buffer_forward(&source, 1);
315		rcount = isc_buffer_getuint16(&source);
316
317		for (i = 0; i < rcount; i++) {
318			/*
319			 * Get the length of this rdata and set up an
320			 * rdata structure for it.
321			 */
322			isc_buffer_remainingregion(&source, &remaining);
323			INSIST(remaining.length >= 2);
324			dns_rdata_reset(&rdata);
325			rdata.length = isc_buffer_getuint16(&source);
326			isc_buffer_remainingregion(&source, &remaining);
327			rdata.data = remaining.base;
328			rdata.type = type;
329			rdata.rdclass = rdataset->rdclass;
330			INSIST(remaining.length >= rdata.length);
331			isc_buffer_forward(&source, rdata.length);
332
333			if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
334			    dns_rdatatype_isdnssec(type))
335				continue;
336
337			/*
338			 * Write the name.
339			 */
340			dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
341			result = dns_name_towire(&name, cctx, target);
342			if (result != ISC_R_SUCCESS)
343				goto rollback;
344
345			/*
346			 * See if we have space for type, class, ttl, and
347			 * rdata length.  Write the type, class, and ttl.
348			 */
349			isc_buffer_availableregion(target, &tavailable);
350			if (tavailable.length < 10) {
351				result = ISC_R_NOSPACE;
352				goto rollback;
353			}
354			isc_buffer_putuint16(target, type);
355			isc_buffer_putuint16(target, rdataset->rdclass);
356			isc_buffer_putuint32(target, rdataset->ttl);
357
358			/*
359			 * Save space for rdata length.
360			 */
361			rdlen = *target;
362			isc_buffer_add(target, 2);
363
364			/*
365			 * Write the rdata.
366			 */
367			result = dns_rdata_towire(&rdata, cctx, target);
368			if (result != ISC_R_SUCCESS)
369				goto rollback;
370
371			/*
372			 * Set the rdata length field to the compressed
373			 * length.
374			 */
375			INSIST((target->used >= rdlen.used + 2) &&
376			       (target->used - rdlen.used - 2 < 65536));
377			isc_buffer_putuint16(&rdlen,
378					     (isc_uint16_t)(target->used -
379							    rdlen.used - 2));
380
381			count++;
382		}
383		INSIST(isc_buffer_remaininglength(&source) == 0);
384		result = dns_rdataset_next(rdataset);
385		dns_rdata_reset(&rdata);
386	}
387	if (result != ISC_R_NOMORE)
388		goto rollback;
389
390	*countp = count;
391
392	return (ISC_R_SUCCESS);
393
394 rollback:
395	INSIST(savedbuffer.used < 65536);
396	dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
397	*countp = 0;
398	*target = savedbuffer;
399
400	return (result);
401}
402
403static void
404rdataset_disassociate(dns_rdataset_t *rdataset) {
405	UNUSED(rdataset);
406}
407
408static isc_result_t
409rdataset_first(dns_rdataset_t *rdataset) {
410	unsigned char *raw = rdataset->private3;
411	unsigned int count;
412
413	count = raw[0] * 256 + raw[1];
414	if (count == 0) {
415		rdataset->private5 = NULL;
416		return (ISC_R_NOMORE);
417	}
418	raw += 2;
419	/*
420	 * The privateuint4 field is the number of rdata beyond the cursor
421	 * position, so we decrement the total count by one before storing
422	 * it.
423	 */
424	count--;
425	rdataset->privateuint4 = count;
426	rdataset->private5 = raw;
427
428	return (ISC_R_SUCCESS);
429}
430
431static isc_result_t
432rdataset_next(dns_rdataset_t *rdataset) {
433	unsigned int count;
434	unsigned int length;
435	unsigned char *raw;
436
437	count = rdataset->privateuint4;
438	if (count == 0)
439		return (ISC_R_NOMORE);
440	count--;
441	rdataset->privateuint4 = count;
442	raw = rdataset->private5;
443	length = raw[0] * 256 + raw[1];
444	raw += length + 2;
445	rdataset->private5 = raw;
446
447	return (ISC_R_SUCCESS);
448}
449
450static void
451rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
452	unsigned char *raw = rdataset->private5;
453	isc_region_t r;
454
455	REQUIRE(raw != NULL);
456
457	r.length = raw[0] * 256 + raw[1];
458	raw += 2;
459	r.base = raw;
460	dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
461}
462
463static void
464rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
465	*target = *source;
466
467	/*
468	 * Reset iterator state.
469	 */
470	target->privateuint4 = 0;
471	target->private5 = NULL;
472}
473
474static unsigned int
475rdataset_count(dns_rdataset_t *rdataset) {
476	unsigned char *raw = rdataset->private3;
477	unsigned int count;
478
479	count = raw[0] * 256 + raw[1];
480
481	return (count);
482}
483
484static void
485rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
486	unsigned char *raw = rdataset->private3;
487
488	raw[-1] = (unsigned char)trust;
489}
490
491static dns_rdatasetmethods_t rdataset_methods = {
492	rdataset_disassociate,
493	rdataset_first,
494	rdataset_next,
495	rdataset_current,
496	rdataset_clone,
497	rdataset_count,
498	NULL,
499	NULL,
500	NULL,
501	NULL,
502	NULL,
503	NULL,
504	NULL,
505	rdataset_settrust,
506	NULL
507};
508
509isc_result_t
510dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
511		       dns_rdatatype_t type, dns_rdataset_t *rdataset)
512{
513	isc_result_t result;
514	dns_rdata_t rdata = DNS_RDATA_INIT;
515	isc_region_t remaining;
516	isc_buffer_t source;
517	dns_name_t tname;
518	dns_rdatatype_t ttype;
519	dns_trust_t trust = dns_trust_none;
520	dns_rdataset_t clone;
521
522	REQUIRE(ncacherdataset != NULL);
523	REQUIRE(ncacherdataset->type == 0);
524	REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
525	REQUIRE(name != NULL);
526	REQUIRE(!dns_rdataset_isassociated(rdataset));
527	REQUIRE(type != dns_rdatatype_rrsig);
528
529	dns_rdataset_init(&clone);
530	dns_rdataset_clone(ncacherdataset, &clone);
531	result = dns_rdataset_first(&clone);
532	while (result == ISC_R_SUCCESS) {
533		dns_rdataset_current(&clone, &rdata);
534		isc_buffer_init(&source, rdata.data, rdata.length);
535		isc_buffer_add(&source, rdata.length);
536		dns_name_init(&tname, NULL);
537		isc_buffer_remainingregion(&source, &remaining);
538		dns_name_fromregion(&tname, &remaining);
539		INSIST(remaining.length >= tname.length);
540		isc_buffer_forward(&source, tname.length);
541		remaining.length -= tname.length;
542
543		INSIST(remaining.length >= 3);
544		ttype = isc_buffer_getuint16(&source);
545
546		if (ttype == type && dns_name_equal(&tname, name)) {
547			trust = isc_buffer_getuint8(&source);
548			INSIST(trust <= dns_trust_ultimate);
549			isc_buffer_remainingregion(&source, &remaining);
550			break;
551		}
552		result = dns_rdataset_next(&clone);
553		dns_rdata_reset(&rdata);
554	}
555	dns_rdataset_disassociate(&clone);
556	if (result == ISC_R_NOMORE)
557		return (ISC_R_NOTFOUND);
558	if (result != ISC_R_SUCCESS)
559		return (result);
560
561	INSIST(remaining.length != 0);
562
563	rdataset->methods = &rdataset_methods;
564	rdataset->rdclass = ncacherdataset->rdclass;
565	rdataset->type = type;
566	rdataset->covers = 0;
567	rdataset->ttl = ncacherdataset->ttl;
568	rdataset->trust = trust;
569	rdataset->private1 = NULL;
570	rdataset->private2 = NULL;
571
572	rdataset->private3 = remaining.base;
573
574	/*
575	 * Reset iterator state.
576	 */
577	rdataset->privateuint4 = 0;
578	rdataset->private5 = NULL;
579	rdataset->private6 = NULL;
580	return (ISC_R_SUCCESS);
581}
582
583isc_result_t
584dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
585			  dns_rdatatype_t covers, dns_rdataset_t *rdataset)
586{
587	dns_name_t tname;
588	dns_rdata_rrsig_t rrsig;
589	dns_rdata_t rdata = DNS_RDATA_INIT;
590	dns_rdataset_t clone;
591	dns_rdatatype_t type;
592	dns_trust_t trust = dns_trust_none;
593	isc_buffer_t source;
594	isc_region_t remaining, sigregion;
595	isc_result_t result;
596	unsigned char *raw;
597	unsigned int count;
598
599	REQUIRE(ncacherdataset != NULL);
600	REQUIRE(ncacherdataset->type == 0);
601	REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
602	REQUIRE(name != NULL);
603	REQUIRE(!dns_rdataset_isassociated(rdataset));
604
605	dns_rdataset_init(&clone);
606	dns_rdataset_clone(ncacherdataset, &clone);
607	result = dns_rdataset_first(&clone);
608	while (result == ISC_R_SUCCESS) {
609		dns_rdataset_current(&clone, &rdata);
610		isc_buffer_init(&source, rdata.data, rdata.length);
611		isc_buffer_add(&source, rdata.length);
612		dns_name_init(&tname, NULL);
613		isc_buffer_remainingregion(&source, &remaining);
614		dns_name_fromregion(&tname, &remaining);
615		INSIST(remaining.length >= tname.length);
616		isc_buffer_forward(&source, tname.length);
617		isc_region_consume(&remaining, tname.length);
618
619		INSIST(remaining.length >= 2);
620		type = isc_buffer_getuint16(&source);
621		isc_region_consume(&remaining, 2);
622
623		if (type != dns_rdatatype_rrsig ||
624		    !dns_name_equal(&tname, name)) {
625			result = dns_rdataset_next(&clone);
626			dns_rdata_reset(&rdata);
627			continue;
628		}
629
630		INSIST(remaining.length >= 1);
631		trust = isc_buffer_getuint8(&source);
632		INSIST(trust <= dns_trust_ultimate);
633		isc_region_consume(&remaining, 1);
634
635		raw = remaining.base;
636		count = raw[0] * 256 + raw[1];
637		INSIST(count > 0);
638		raw += 2;
639		sigregion.length = raw[0] * 256 + raw[1];
640		raw += 2;
641		sigregion.base = raw;
642		dns_rdata_reset(&rdata);
643		dns_rdata_fromregion(&rdata, rdataset->rdclass,
644				     dns_rdatatype_rrsig, &sigregion);
645		(void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
646		if (rrsig.covered == covers) {
647			isc_buffer_remainingregion(&source, &remaining);
648			break;
649		}
650
651		result = dns_rdataset_next(&clone);
652		dns_rdata_reset(&rdata);
653	}
654	dns_rdataset_disassociate(&clone);
655	if (result == ISC_R_NOMORE)
656		return (ISC_R_NOTFOUND);
657	if (result != ISC_R_SUCCESS)
658		return (result);
659
660	INSIST(remaining.length != 0);
661
662	rdataset->methods = &rdataset_methods;
663	rdataset->rdclass = ncacherdataset->rdclass;
664	rdataset->type = dns_rdatatype_rrsig;
665	rdataset->covers = covers;
666	rdataset->ttl = ncacherdataset->ttl;
667	rdataset->trust = trust;
668	rdataset->private1 = NULL;
669	rdataset->private2 = NULL;
670
671	rdataset->private3 = remaining.base;
672
673	/*
674	 * Reset iterator state.
675	 */
676	rdataset->privateuint4 = 0;
677	rdataset->private5 = NULL;
678	rdataset->private6 = NULL;
679	return (ISC_R_SUCCESS);
680}
681
682void
683dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
684		   dns_rdataset_t *rdataset)
685{
686	dns_rdata_t rdata = DNS_RDATA_INIT;
687	dns_trust_t trust;
688	isc_region_t remaining, sigregion;
689	isc_buffer_t source;
690	dns_name_t tname;
691	dns_rdatatype_t type;
692	unsigned int count;
693	dns_rdata_rrsig_t rrsig;
694	unsigned char *raw;
695
696	REQUIRE(ncacherdataset != NULL);
697	REQUIRE(ncacherdataset->type == 0);
698	REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
699	REQUIRE(found != NULL);
700	REQUIRE(!dns_rdataset_isassociated(rdataset));
701
702	dns_rdataset_current(ncacherdataset, &rdata);
703	isc_buffer_init(&source, rdata.data, rdata.length);
704	isc_buffer_add(&source, rdata.length);
705
706	dns_name_init(&tname, NULL);
707	isc_buffer_remainingregion(&source, &remaining);
708	dns_name_fromregion(found, &remaining);
709	INSIST(remaining.length >= found->length);
710	isc_buffer_forward(&source, found->length);
711	remaining.length -= found->length;
712
713	INSIST(remaining.length >= 5);
714	type = isc_buffer_getuint16(&source);
715	trust = isc_buffer_getuint8(&source);
716	INSIST(trust <= dns_trust_ultimate);
717	isc_buffer_remainingregion(&source, &remaining);
718
719	rdataset->methods = &rdataset_methods;
720	rdataset->rdclass = ncacherdataset->rdclass;
721	rdataset->type = type;
722	if (type == dns_rdatatype_rrsig) {
723		/*
724		 * Extract covers from RRSIG.
725		 */
726		raw = remaining.base;
727		count = raw[0] * 256 + raw[1];
728		INSIST(count > 0);
729		raw += 2;
730		sigregion.length = raw[0] * 256 + raw[1];
731		raw += 2;
732		sigregion.base = raw;
733		dns_rdata_reset(&rdata);
734		dns_rdata_fromregion(&rdata, rdataset->rdclass,
735				     rdataset->type, &sigregion);
736		(void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
737		rdataset->covers = rrsig.covered;
738	} else
739		rdataset->covers = 0;
740	rdataset->ttl = ncacherdataset->ttl;
741	rdataset->trust = trust;
742	rdataset->private1 = NULL;
743	rdataset->private2 = NULL;
744
745	rdataset->private3 = remaining.base;
746
747	/*
748	 * Reset iterator state.
749	 */
750	rdataset->privateuint4 = 0;
751	rdataset->private5 = NULL;
752	rdataset->private6 = NULL;
753}
754