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 * 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 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 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 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 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 149 question_disassociate(dns_rdataset_t *rdataset) { 150 UNUSED(rdataset); 151 } 152 153 static isc_result_t 154 question_cursor(dns_rdataset_t *rdataset) { 155 UNUSED(rdataset); 156 157 return (ISC_R_NOMORE); 158 } 159 160 static void 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 172 question_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 173 *target = *source; 174 } 175 176 static unsigned int 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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