1 /* $NetBSD: rdataset.c,v 1.5 2020/05/24 19:46:23 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 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 http://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 * 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 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 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 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 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 147 question_disassociate(dns_rdataset_t *rdataset) { 148 UNUSED(rdataset); 149 } 150 151 static isc_result_t 152 question_cursor(dns_rdataset_t *rdataset) { 153 UNUSED(rdataset); 154 155 return (ISC_R_NOMORE); 156 } 157 158 static void 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 170 question_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 171 *target = *source; 172 } 173 174 static unsigned int 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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