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