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