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