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