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