xref: /minix3/external/bsd/bind/dist/lib/dns/rdataset.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1 /*	$NetBSD: rdataset.c,v 1.8 2015/07/08 17:28:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2012, 2014, 2015  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 <stdlib.h>
27 
28 #include <isc/buffer.h>
29 #include <isc/mem.h>
30 #include <isc/random.h>
31 #include <isc/serial.h>
32 #include <isc/util.h>
33 
34 #include <dns/name.h>
35 #include <dns/ncache.h>
36 #include <dns/rdata.h>
37 #include <dns/rdataset.h>
38 #include <dns/compress.h>
39 
40 static const char *trustnames[] = {
41 	"none",
42 	"pending-additional",
43 	"pending-answer",
44 	"additional",
45 	"glue",
46 	"answer",
47 	"authauthority",
48 	"authanswer",
49 	"secure",
50 	"local" /* aka ultimate */
51 };
52 
53 const char *
dns_trust_totext(dns_trust_t trust)54 dns_trust_totext(dns_trust_t trust) {
55 	if (trust >= sizeof(trustnames)/sizeof(*trustnames))
56 		return ("bad");
57 	return (trustnames[trust]);
58 }
59 
60 void
dns_rdataset_init(dns_rdataset_t * rdataset)61 dns_rdataset_init(dns_rdataset_t *rdataset) {
62 
63 	/*
64 	 * Make 'rdataset' a valid, disassociated rdataset.
65 	 */
66 
67 	REQUIRE(rdataset != NULL);
68 
69 	rdataset->magic = DNS_RDATASET_MAGIC;
70 	rdataset->methods = NULL;
71 	ISC_LINK_INIT(rdataset, link);
72 	rdataset->rdclass = 0;
73 	rdataset->type = 0;
74 	rdataset->ttl = 0;
75 	rdataset->trust = 0;
76 	rdataset->covers = 0;
77 	rdataset->attributes = 0;
78 	rdataset->count = ISC_UINT32_MAX;
79 	rdataset->private1 = NULL;
80 	rdataset->private2 = NULL;
81 	rdataset->private3 = NULL;
82 	rdataset->privateuint4 = 0;
83 	rdataset->private5 = NULL;
84 	rdataset->private6 = NULL;
85 	rdataset->private7 = NULL;
86 	rdataset->resign = 0;
87 }
88 
89 void
dns_rdataset_invalidate(dns_rdataset_t * rdataset)90 dns_rdataset_invalidate(dns_rdataset_t *rdataset) {
91 
92 	/*
93 	 * Invalidate 'rdataset'.
94 	 */
95 
96 	REQUIRE(DNS_RDATASET_VALID(rdataset));
97 	REQUIRE(rdataset->methods == NULL);
98 
99 	rdataset->magic = 0;
100 	ISC_LINK_INIT(rdataset, link);
101 	rdataset->rdclass = 0;
102 	rdataset->type = 0;
103 	rdataset->ttl = 0;
104 	rdataset->trust = 0;
105 	rdataset->covers = 0;
106 	rdataset->attributes = 0;
107 	rdataset->count = ISC_UINT32_MAX;
108 	rdataset->private1 = NULL;
109 	rdataset->private2 = NULL;
110 	rdataset->private3 = NULL;
111 	rdataset->privateuint4 = 0;
112 	rdataset->private5 = NULL;
113 }
114 
115 void
dns_rdataset_disassociate(dns_rdataset_t * rdataset)116 dns_rdataset_disassociate(dns_rdataset_t *rdataset) {
117 
118 	/*
119 	 * Disassociate 'rdataset' from its rdata, allowing it to be reused.
120 	 */
121 
122 	REQUIRE(DNS_RDATASET_VALID(rdataset));
123 	REQUIRE(rdataset->methods != NULL);
124 
125 	(rdataset->methods->disassociate)(rdataset);
126 	rdataset->methods = NULL;
127 	ISC_LINK_INIT(rdataset, link);
128 	rdataset->rdclass = 0;
129 	rdataset->type = 0;
130 	rdataset->ttl = 0;
131 	rdataset->trust = 0;
132 	rdataset->covers = 0;
133 	rdataset->attributes = 0;
134 	rdataset->count = ISC_UINT32_MAX;
135 	rdataset->private1 = NULL;
136 	rdataset->private2 = NULL;
137 	rdataset->private3 = NULL;
138 	rdataset->privateuint4 = 0;
139 	rdataset->private5 = NULL;
140 	rdataset->private6 = NULL;
141 }
142 
143 isc_boolean_t
dns_rdataset_isassociated(dns_rdataset_t * rdataset)144 dns_rdataset_isassociated(dns_rdataset_t *rdataset) {
145 	/*
146 	 * Is 'rdataset' associated?
147 	 */
148 
149 	REQUIRE(DNS_RDATASET_VALID(rdataset));
150 
151 	if (rdataset->methods != NULL)
152 		return (ISC_TRUE);
153 
154 	return (ISC_FALSE);
155 }
156 
157 static void
question_disassociate(dns_rdataset_t * rdataset)158 question_disassociate(dns_rdataset_t *rdataset) {
159 	UNUSED(rdataset);
160 }
161 
162 static isc_result_t
question_cursor(dns_rdataset_t * rdataset)163 question_cursor(dns_rdataset_t *rdataset) {
164 	UNUSED(rdataset);
165 
166 	return (ISC_R_NOMORE);
167 }
168 
169 static void
question_current(dns_rdataset_t * rdataset,dns_rdata_t * rdata)170 question_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
171 	/*
172 	 * This routine should never be called.
173 	 */
174 	UNUSED(rdataset);
175 	UNUSED(rdata);
176 
177 	REQUIRE(0);
178 }
179 
180 static void
question_clone(dns_rdataset_t * source,dns_rdataset_t * target)181 question_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
182 	*target = *source;
183 }
184 
185 static unsigned int
question_count(dns_rdataset_t * rdataset)186 question_count(dns_rdataset_t *rdataset) {
187 	/*
188 	 * This routine should never be called.
189 	 */
190 	UNUSED(rdataset);
191 	REQUIRE(0);
192 
193 	return (0);
194 }
195 
196 static dns_rdatasetmethods_t question_methods = {
197 	question_disassociate,
198 	question_cursor,
199 	question_cursor,
200 	question_current,
201 	question_clone,
202 	question_count,
203 	NULL,
204 	NULL,
205 	NULL,
206 	NULL,
207 	NULL,
208 	NULL,
209 	NULL,
210 	NULL,
211 	NULL,
212 	NULL
213 };
214 
215 void
dns_rdataset_makequestion(dns_rdataset_t * rdataset,dns_rdataclass_t rdclass,dns_rdatatype_t type)216 dns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass,
217 			  dns_rdatatype_t type)
218 {
219 
220 	/*
221 	 * Make 'rdataset' a valid, associated, question rdataset, with a
222 	 * question class of 'rdclass' and type 'type'.
223 	 */
224 
225 	REQUIRE(DNS_RDATASET_VALID(rdataset));
226 	REQUIRE(rdataset->methods == NULL);
227 
228 	rdataset->methods = &question_methods;
229 	rdataset->rdclass = rdclass;
230 	rdataset->type = type;
231 	rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
232 }
233 
234 unsigned int
dns_rdataset_count(dns_rdataset_t * rdataset)235 dns_rdataset_count(dns_rdataset_t *rdataset) {
236 
237 	/*
238 	 * Return the number of records in 'rdataset'.
239 	 */
240 
241 	REQUIRE(DNS_RDATASET_VALID(rdataset));
242 	REQUIRE(rdataset->methods != NULL);
243 
244 	return ((rdataset->methods->count)(rdataset));
245 }
246 
247 void
dns_rdataset_clone(dns_rdataset_t * source,dns_rdataset_t * target)248 dns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
249 
250 	/*
251 	 * Make 'target' refer to the same rdataset as 'source'.
252 	 */
253 
254 	REQUIRE(DNS_RDATASET_VALID(source));
255 	REQUIRE(source->methods != NULL);
256 	REQUIRE(DNS_RDATASET_VALID(target));
257 	REQUIRE(target->methods == NULL);
258 
259 	(source->methods->clone)(source, target);
260 }
261 
262 isc_result_t
dns_rdataset_first(dns_rdataset_t * rdataset)263 dns_rdataset_first(dns_rdataset_t *rdataset) {
264 
265 	/*
266 	 * Move the rdata cursor to the first rdata in the rdataset (if any).
267 	 */
268 
269 	REQUIRE(DNS_RDATASET_VALID(rdataset));
270 	REQUIRE(rdataset->methods != NULL);
271 
272 	return ((rdataset->methods->first)(rdataset));
273 }
274 
275 isc_result_t
dns_rdataset_next(dns_rdataset_t * rdataset)276 dns_rdataset_next(dns_rdataset_t *rdataset) {
277 
278 	/*
279 	 * Move the rdata cursor to the next rdata in the rdataset (if any).
280 	 */
281 
282 	REQUIRE(DNS_RDATASET_VALID(rdataset));
283 	REQUIRE(rdataset->methods != NULL);
284 
285 	return ((rdataset->methods->next)(rdataset));
286 }
287 
288 void
dns_rdataset_current(dns_rdataset_t * rdataset,dns_rdata_t * rdata)289 dns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
290 
291 	/*
292 	 * Make 'rdata' refer to the current rdata.
293 	 */
294 
295 	REQUIRE(DNS_RDATASET_VALID(rdataset));
296 	REQUIRE(rdataset->methods != NULL);
297 
298 	(rdataset->methods->current)(rdataset, rdata);
299 }
300 
301 #define MAX_SHUFFLE	32
302 #define WANT_FIXED(r)	(((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
303 #define WANT_RANDOM(r)	(((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
304 
305 struct towire_sort {
306 	int key;
307 	dns_rdata_t *rdata;
308 };
309 
310 static int
towire_compare(const void * av,const void * bv)311 towire_compare(const void *av, const void *bv) {
312 	const struct towire_sort *a = (const struct towire_sort *) av;
313 	const struct towire_sort *b = (const struct towire_sort *) bv;
314 	return (a->key - b->key);
315 }
316 
317 static isc_result_t
towiresorted(dns_rdataset_t * rdataset,const dns_name_t * owner_name,dns_compress_t * cctx,isc_buffer_t * target,dns_rdatasetorderfunc_t order,const void * order_arg,isc_boolean_t partial,unsigned int options,unsigned int * countp,void ** state)318 towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
319 	     dns_compress_t *cctx, isc_buffer_t *target,
320 	     dns_rdatasetorderfunc_t order, const void *order_arg,
321 	     isc_boolean_t partial, unsigned int options,
322 	     unsigned int *countp, void **state)
323 {
324 	dns_rdata_t rdata = DNS_RDATA_INIT;
325 	isc_region_t r;
326 	isc_result_t result;
327 	unsigned int i, count = 0, added, choice;
328 	isc_buffer_t savedbuffer, rdlen, rrbuffer;
329 	unsigned int headlen;
330 	isc_boolean_t question = ISC_FALSE;
331 	isc_boolean_t shuffle = ISC_FALSE;
332 	dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE];
333 	struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE];
334 
335 	UNUSED(state);
336 
337 	/*
338 	 * Convert 'rdataset' to wire format, compressing names as specified
339 	 * in cctx, and storing the result in 'target'.
340 	 */
341 
342 	REQUIRE(DNS_RDATASET_VALID(rdataset));
343 	REQUIRE(countp != NULL);
344 	REQUIRE((order == NULL) == (order_arg == NULL));
345 	REQUIRE(cctx != NULL && cctx->mctx != NULL);
346 
347 	if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
348 		question = ISC_TRUE;
349 		count = 1;
350 		result = dns_rdataset_first(rdataset);
351 		INSIST(result == ISC_R_NOMORE);
352 	} else if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
353 		/*
354 		 * This is a negative caching rdataset.
355 		 */
356 		unsigned int ncache_opts = 0;
357 		if ((options & DNS_RDATASETTOWIRE_OMITDNSSEC) != 0)
358 			ncache_opts |= DNS_NCACHETOWIRE_OMITDNSSEC;
359 		return (dns_ncache_towire(rdataset, cctx, target, ncache_opts,
360 					  countp));
361 	} else {
362 		count = (rdataset->methods->count)(rdataset);
363 		result = dns_rdataset_first(rdataset);
364 		if (result == ISC_R_NOMORE)
365 			return (ISC_R_SUCCESS);
366 		if (result != ISC_R_SUCCESS)
367 			return (result);
368 	}
369 
370 	/*
371 	 * Do we want to shuffle this answer?
372 	 */
373 	if (!question && count > 1 &&
374 	    (!WANT_FIXED(rdataset) || order != NULL) &&
375 	    rdataset->type != dns_rdatatype_rrsig)
376 		shuffle = ISC_TRUE;
377 
378 	if (shuffle && count > MAX_SHUFFLE) {
379 		shuffled = isc_mem_get(cctx->mctx, count * sizeof(*shuffled));
380 		sorted = isc_mem_get(cctx->mctx, count * sizeof(*sorted));
381 		if (shuffled == NULL || sorted == NULL)
382 			shuffle = ISC_FALSE;
383 	} else {
384 		shuffled = shuffled_fixed;
385 		sorted = sorted_fixed;
386 	}
387 
388 	if (shuffle) {
389 		/*
390 		 * First we get handles to all of the rdata.
391 		 */
392 		i = 0;
393 		do {
394 			INSIST(i < count);
395 			dns_rdata_init(&shuffled[i]);
396 			dns_rdataset_current(rdataset, &shuffled[i]);
397 			i++;
398 			result = dns_rdataset_next(rdataset);
399 		} while (result == ISC_R_SUCCESS);
400 		if (result != ISC_R_NOMORE)
401 			goto cleanup;
402 		INSIST(i == count);
403 
404 		/*
405 		 * Now we shuffle.
406 		 */
407 		if (WANT_FIXED(rdataset)) {
408 			/*
409 			 * 'Fixed' order.
410 			 */
411 			INSIST(order != NULL);
412 			for (i = 0; i < count; i++) {
413 				sorted[i].key = (*order)(&shuffled[i],
414 							 order_arg);
415 				sorted[i].rdata = &shuffled[i];
416 			}
417 		} else if (WANT_RANDOM(rdataset)) {
418 			/*
419 			 * 'Random' order.
420 			 */
421 			for (i = 0; i < count; i++) {
422 				isc_uint32_t val;
423 
424 				isc_random_get(&val);
425 				choice = i + (val % (count - i));
426 				rdata = shuffled[i];
427 				shuffled[i] = shuffled[choice];
428 				shuffled[choice] = rdata;
429 				if (order != NULL)
430 					sorted[i].key = (*order)(&shuffled[i],
431 								 order_arg);
432 				else
433 					sorted[i].key = 0; /* Unused */
434 				sorted[i].rdata = &shuffled[i];
435 			}
436 		} else {
437 			/*
438 			 * "Cyclic" order.
439 			 */
440 			isc_uint32_t val;
441 			unsigned int j;
442 
443 			val = rdataset->count;
444 			if (val == ISC_UINT32_MAX)
445 				isc_random_get(&val);
446 			j = val % count;
447 			for (i = 0; i < count; i++) {
448 				if (order != NULL)
449 					sorted[i].key = (*order)(&shuffled[j],
450 								 order_arg);
451 				else
452 					sorted[i].key = 0; /* Unused */
453 				sorted[i].rdata = &shuffled[j];
454 				j++;
455 				if (j == count)
456 					j = 0; /* Wrap around. */
457 			}
458 		}
459 
460 		/*
461 		 * Sorted order.
462 		 */
463 		if (order != NULL)
464 			qsort(sorted, count, sizeof(sorted[0]),
465 			      towire_compare);
466 	}
467 
468 	savedbuffer = *target;
469 	i = 0;
470 	added = 0;
471 
472 	do {
473 		/*
474 		 * Copy out the name, type, class, ttl.
475 		 */
476 
477 		rrbuffer = *target;
478 		dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
479 		result = dns_name_towire(owner_name, cctx, target);
480 		if (result != ISC_R_SUCCESS)
481 			goto rollback;
482 		headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
483 		if (!question)
484 			headlen += sizeof(dns_ttl_t)
485 				+ 2;  /* XXX 2 for rdata len */
486 		isc_buffer_availableregion(target, &r);
487 		if (r.length < headlen) {
488 			result = ISC_R_NOSPACE;
489 			goto rollback;
490 		}
491 		isc_buffer_putuint16(target, rdataset->type);
492 		isc_buffer_putuint16(target, rdataset->rdclass);
493 		if (!question) {
494 			isc_buffer_putuint32(target, rdataset->ttl);
495 
496 			/*
497 			 * Save space for rdlen.
498 			 */
499 			rdlen = *target;
500 			isc_buffer_add(target, 2);
501 
502 			/*
503 			 * Copy out the rdata
504 			 */
505 			if (shuffle)
506 				rdata = *(sorted[i].rdata);
507 			else {
508 				dns_rdata_reset(&rdata);
509 				dns_rdataset_current(rdataset, &rdata);
510 			}
511 			result = dns_rdata_towire(&rdata, cctx, target);
512 			if (result != ISC_R_SUCCESS)
513 				goto rollback;
514 			INSIST((target->used >= rdlen.used + 2) &&
515 			       (target->used - rdlen.used - 2 < 65536));
516 			isc_buffer_putuint16(&rdlen,
517 					     (isc_uint16_t)(target->used -
518 							    rdlen.used - 2));
519 			added++;
520 		}
521 
522 		if (shuffle) {
523 			i++;
524 			if (i == count)
525 				result = ISC_R_NOMORE;
526 			else
527 				result = ISC_R_SUCCESS;
528 		} else {
529 			result = dns_rdataset_next(rdataset);
530 		}
531 	} while (result == ISC_R_SUCCESS);
532 
533 	if (result != ISC_R_NOMORE)
534 		goto rollback;
535 
536 	*countp += count;
537 
538 	result = ISC_R_SUCCESS;
539 	goto cleanup;
540 
541  rollback:
542 	if (partial && result == ISC_R_NOSPACE) {
543 		INSIST(rrbuffer.used < 65536);
544 		dns_compress_rollback(cctx, (isc_uint16_t)rrbuffer.used);
545 		*countp += added;
546 		*target = rrbuffer;
547 		goto cleanup;
548 	}
549 	INSIST(savedbuffer.used < 65536);
550 	dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
551 	*countp = 0;
552 	*target = savedbuffer;
553 
554  cleanup:
555 	if (sorted != NULL && sorted != sorted_fixed)
556 		isc_mem_put(cctx->mctx, sorted, count * sizeof(*sorted));
557 	if (shuffled != NULL && shuffled != shuffled_fixed)
558 		isc_mem_put(cctx->mctx, shuffled, count * sizeof(*shuffled));
559 	return (result);
560 }
561 
562 isc_result_t
dns_rdataset_towiresorted(dns_rdataset_t * rdataset,const dns_name_t * owner_name,dns_compress_t * cctx,isc_buffer_t * target,dns_rdatasetorderfunc_t order,const void * order_arg,unsigned int options,unsigned int * countp)563 dns_rdataset_towiresorted(dns_rdataset_t *rdataset,
564 			  const dns_name_t *owner_name,
565 			  dns_compress_t *cctx,
566 			  isc_buffer_t *target,
567 			  dns_rdatasetorderfunc_t order,
568 			  const void *order_arg,
569 			  unsigned int options,
570 			  unsigned int *countp)
571 {
572 	return (towiresorted(rdataset, owner_name, cctx, target,
573 			     order, order_arg, ISC_FALSE, options,
574 			     countp, NULL));
575 }
576 
577 isc_result_t
dns_rdataset_towirepartial(dns_rdataset_t * rdataset,const dns_name_t * owner_name,dns_compress_t * cctx,isc_buffer_t * target,dns_rdatasetorderfunc_t order,const void * order_arg,unsigned int options,unsigned int * countp,void ** state)578 dns_rdataset_towirepartial(dns_rdataset_t *rdataset,
579 			   const dns_name_t *owner_name,
580 			   dns_compress_t *cctx,
581 			   isc_buffer_t *target,
582 			   dns_rdatasetorderfunc_t order,
583 			   const void *order_arg,
584 			   unsigned int options,
585 			   unsigned int *countp,
586 			   void **state)
587 {
588 	REQUIRE(state == NULL);	/* XXX remove when implemented */
589 	return (towiresorted(rdataset, owner_name, cctx, target,
590 			     order, order_arg, ISC_TRUE, options,
591 			     countp, state));
592 }
593 
594 isc_result_t
dns_rdataset_towire(dns_rdataset_t * rdataset,dns_name_t * owner_name,dns_compress_t * cctx,isc_buffer_t * target,unsigned int options,unsigned int * countp)595 dns_rdataset_towire(dns_rdataset_t *rdataset,
596 		    dns_name_t *owner_name,
597 		    dns_compress_t *cctx,
598 		    isc_buffer_t *target,
599 		    unsigned int options,
600 		    unsigned int *countp)
601 {
602 	return (towiresorted(rdataset, owner_name, cctx, target,
603 			     NULL, NULL, ISC_FALSE, options, countp, NULL));
604 }
605 
606 isc_result_t
dns_rdataset_additionaldata(dns_rdataset_t * rdataset,dns_additionaldatafunc_t add,void * arg)607 dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
608 			    dns_additionaldatafunc_t add, void *arg)
609 {
610 	dns_rdata_t rdata = DNS_RDATA_INIT;
611 	isc_result_t result;
612 
613 	/*
614 	 * For each rdata in rdataset, call 'add' for each name and type in the
615 	 * rdata which is subject to additional section processing.
616 	 */
617 
618 	REQUIRE(DNS_RDATASET_VALID(rdataset));
619 	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
620 
621 	result = dns_rdataset_first(rdataset);
622 	if (result != ISC_R_SUCCESS)
623 		return (result);
624 
625 	do {
626 		dns_rdataset_current(rdataset, &rdata);
627 		result = dns_rdata_additionaldata(&rdata, add, arg);
628 		if (result == ISC_R_SUCCESS)
629 			result = dns_rdataset_next(rdataset);
630 		dns_rdata_reset(&rdata);
631 	} while (result == ISC_R_SUCCESS);
632 
633 	if (result != ISC_R_NOMORE)
634 		return (result);
635 
636 	return (ISC_R_SUCCESS);
637 }
638 
639 isc_result_t
dns_rdataset_addnoqname(dns_rdataset_t * rdataset,dns_name_t * name)640 dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
641 
642 	REQUIRE(DNS_RDATASET_VALID(rdataset));
643 	REQUIRE(rdataset->methods != NULL);
644 	if (rdataset->methods->addnoqname == NULL)
645 		return (ISC_R_NOTIMPLEMENTED);
646 	return((rdataset->methods->addnoqname)(rdataset, name));
647 }
648 
649 isc_result_t
dns_rdataset_getnoqname(dns_rdataset_t * rdataset,dns_name_t * name,dns_rdataset_t * neg,dns_rdataset_t * negsig)650 dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
651 			dns_rdataset_t *neg, dns_rdataset_t *negsig)
652 {
653 	REQUIRE(DNS_RDATASET_VALID(rdataset));
654 	REQUIRE(rdataset->methods != NULL);
655 
656 	if (rdataset->methods->getnoqname == NULL)
657 		return (ISC_R_NOTIMPLEMENTED);
658 	return((rdataset->methods->getnoqname)(rdataset, name, neg, negsig));
659 }
660 
661 isc_result_t
dns_rdataset_addclosest(dns_rdataset_t * rdataset,dns_name_t * name)662 dns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) {
663 
664 	REQUIRE(DNS_RDATASET_VALID(rdataset));
665 	REQUIRE(rdataset->methods != NULL);
666 	if (rdataset->methods->addclosest == NULL)
667 		return (ISC_R_NOTIMPLEMENTED);
668 	return((rdataset->methods->addclosest)(rdataset, name));
669 }
670 
671 isc_result_t
dns_rdataset_getclosest(dns_rdataset_t * rdataset,dns_name_t * name,dns_rdataset_t * neg,dns_rdataset_t * negsig)672 dns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
673 			dns_rdataset_t *neg, dns_rdataset_t *negsig)
674 {
675 	REQUIRE(DNS_RDATASET_VALID(rdataset));
676 	REQUIRE(rdataset->methods != NULL);
677 
678 	if (rdataset->methods->getclosest == NULL)
679 		return (ISC_R_NOTIMPLEMENTED);
680 	return((rdataset->methods->getclosest)(rdataset, name, neg, negsig));
681 }
682 
683 /*
684  * Additional cache stuff
685  */
686 isc_result_t
dns_rdataset_getadditional(dns_rdataset_t * rdataset,dns_rdatasetadditional_t type,dns_rdatatype_t qtype,dns_acache_t * acache,dns_zone_t ** zonep,dns_db_t ** dbp,dns_dbversion_t ** versionp,dns_dbnode_t ** nodep,dns_name_t * fname,dns_message_t * msg,isc_stdtime_t now)687 dns_rdataset_getadditional(dns_rdataset_t *rdataset,
688 			   dns_rdatasetadditional_t type,
689 			   dns_rdatatype_t qtype,
690 			   dns_acache_t *acache,
691 			   dns_zone_t **zonep,
692 			   dns_db_t **dbp,
693 			   dns_dbversion_t **versionp,
694 			   dns_dbnode_t **nodep,
695 			   dns_name_t *fname,
696 			   dns_message_t *msg,
697 			   isc_stdtime_t now)
698 {
699 	REQUIRE(DNS_RDATASET_VALID(rdataset));
700 	REQUIRE(rdataset->methods != NULL);
701 	REQUIRE(zonep == NULL || *zonep == NULL);
702 	REQUIRE(dbp != NULL && *dbp == NULL);
703 	REQUIRE(versionp != NULL && *versionp == NULL);
704 	REQUIRE(nodep != NULL && *nodep == NULL);
705 	REQUIRE(fname != NULL);
706 	REQUIRE(msg != NULL);
707 
708 	if (acache != NULL && rdataset->methods->getadditional != NULL) {
709 		return ((rdataset->methods->getadditional)(rdataset, type,
710 							   qtype, acache,
711 							   zonep, dbp,
712 							   versionp, nodep,
713 							   fname, msg, now));
714 	}
715 
716 	return (ISC_R_FAILURE);
717 }
718 
719 isc_result_t
dns_rdataset_setadditional(dns_rdataset_t * rdataset,dns_rdatasetadditional_t type,dns_rdatatype_t qtype,dns_acache_t * acache,dns_zone_t * zone,dns_db_t * db,dns_dbversion_t * version,dns_dbnode_t * node,dns_name_t * fname)720 dns_rdataset_setadditional(dns_rdataset_t *rdataset,
721 			   dns_rdatasetadditional_t type,
722 			   dns_rdatatype_t qtype,
723 			   dns_acache_t *acache,
724 			   dns_zone_t *zone,
725 			   dns_db_t *db,
726 			   dns_dbversion_t *version,
727 			   dns_dbnode_t *node,
728 			   dns_name_t *fname)
729 {
730 	REQUIRE(DNS_RDATASET_VALID(rdataset));
731 	REQUIRE(rdataset->methods != NULL);
732 
733 	if (acache != NULL && rdataset->methods->setadditional != NULL) {
734 		return ((rdataset->methods->setadditional)(rdataset, type,
735 							   qtype, acache, zone,
736 							   db, version,
737 							   node, fname));
738 	}
739 
740 	return (ISC_R_FAILURE);
741 }
742 
743 isc_result_t
dns_rdataset_putadditional(dns_acache_t * acache,dns_rdataset_t * rdataset,dns_rdatasetadditional_t type,dns_rdatatype_t qtype)744 dns_rdataset_putadditional(dns_acache_t *acache,
745 			   dns_rdataset_t *rdataset,
746 			   dns_rdatasetadditional_t type,
747 			   dns_rdatatype_t qtype)
748 {
749 	REQUIRE(DNS_RDATASET_VALID(rdataset));
750 	REQUIRE(rdataset->methods != NULL);
751 
752 	if (acache != NULL && rdataset->methods->putadditional != NULL) {
753 		return ((rdataset->methods->putadditional)(acache, rdataset,
754 							   type, qtype));
755 	}
756 
757 	return (ISC_R_FAILURE);
758 }
759 
760 void
dns_rdataset_settrust(dns_rdataset_t * rdataset,dns_trust_t trust)761 dns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
762 	REQUIRE(DNS_RDATASET_VALID(rdataset));
763 	REQUIRE(rdataset->methods != NULL);
764 
765 	if (rdataset->methods->settrust != NULL)
766 		(rdataset->methods->settrust)(rdataset, trust);
767 	else
768 		rdataset->trust = trust;
769 }
770 
771 void
dns_rdataset_expire(dns_rdataset_t * rdataset)772 dns_rdataset_expire(dns_rdataset_t *rdataset) {
773 	REQUIRE(DNS_RDATASET_VALID(rdataset));
774 	REQUIRE(rdataset->methods != NULL);
775 
776 	if (rdataset->methods->expire != NULL)
777 		(rdataset->methods->expire)(rdataset);
778 }
779 
780 void
dns_rdataset_clearprefetch(dns_rdataset_t * rdataset)781 dns_rdataset_clearprefetch(dns_rdataset_t *rdataset) {
782 	REQUIRE(DNS_RDATASET_VALID(rdataset));
783 	REQUIRE(rdataset->methods != NULL);
784 
785 	if (rdataset->methods->clearprefetch != NULL)
786 		(rdataset->methods->clearprefetch)(rdataset);
787 }
788 
789 void
dns_rdataset_trimttl(dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset,dns_rdata_rrsig_t * rrsig,isc_stdtime_t now,isc_boolean_t acceptexpired)790 dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
791 		     dns_rdata_rrsig_t *rrsig, isc_stdtime_t now,
792 		     isc_boolean_t acceptexpired)
793 {
794 	isc_uint32_t ttl = 0;
795 
796 	REQUIRE(DNS_RDATASET_VALID(rdataset));
797 	REQUIRE(DNS_RDATASET_VALID(sigrdataset));
798 	REQUIRE(rrsig != NULL);
799 
800 	/*
801 	 * If we accept expired RRsets keep them for no more than 120 seconds.
802 	 */
803 	if (acceptexpired &&
804 	    (isc_serial_le(rrsig->timeexpire, ((now + 120) & 0xffffffff)) ||
805 	     isc_serial_le(rrsig->timeexpire, now)))
806 		ttl = 120;
807 	else if (isc_serial_ge(rrsig->timeexpire, now))
808 		ttl = rrsig->timeexpire - now;
809 
810 	ttl = ISC_MIN(ISC_MIN(rdataset->ttl, sigrdataset->ttl),
811 		      ISC_MIN(rrsig->originalttl, ttl));
812 	rdataset->ttl = ttl;
813 	sigrdataset->ttl = ttl;
814 }
815