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