1/* $NetBSD: rdataset.c,v 1.8 2024/02/21 22:52:08 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 35static const char *trustnames[] = { 36 "none", "pending-additional", 37 "pending-answer", "additional", 38 "glue", "answer", 39 "authauthority", "authanswer", 40 "secure", "local" /* aka ultimate */ 41}; 42 43const char * 44dns_trust_totext(dns_trust_t trust) { 45 if (trust >= sizeof(trustnames) / sizeof(*trustnames)) { 46 return ("bad"); 47 } 48 return (trustnames[trust]); 49} 50 51void 52dns_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 79void 80dns_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 104void 105dns_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 131bool 132dns_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 146static void 147question_disassociate(dns_rdataset_t *rdataset) { 148 UNUSED(rdataset); 149} 150 151static isc_result_t 152question_cursor(dns_rdataset_t *rdataset) { 153 UNUSED(rdataset); 154 155 return (ISC_R_NOMORE); 156} 157 158static void 159question_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 169static void 170question_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 171 *target = *source; 172} 173 174static unsigned int 175question_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 185static 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 204void 205dns_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 221unsigned int 222dns_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 233void 234dns_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 247isc_result_t 248dns_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 259isc_result_t 260dns_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 271void 272dns_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 288struct towire_sort { 289 int key; 290 dns_rdata_t *rdata; 291}; 292 293static int 294towire_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 300static void 301swap_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 307static isc_result_t 308towiresorted(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 (want_random) { 412 seed = isc_random32(); 413 } 414 415 if (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 (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_copy(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 527rollback: 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 540cleanup: 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 550isc_result_t 551dns_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 560isc_result_t 561dns_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 571isc_result_t 572dns_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 579isc_result_t 580dns_rdataset_additionaldata(dns_rdataset_t *rdataset, 581 const dns_name_t *owner_name, 582 dns_additionaldatafunc_t add, void *arg) { 583 dns_rdata_t rdata = DNS_RDATA_INIT; 584 isc_result_t result; 585 586 /* 587 * For each rdata in rdataset, call 'add' for each name and type in the 588 * rdata which is subject to additional section processing. 589 */ 590 591 REQUIRE(DNS_RDATASET_VALID(rdataset)); 592 REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0); 593 594 result = dns_rdataset_first(rdataset); 595 if (result != ISC_R_SUCCESS) { 596 return (result); 597 } 598 599 do { 600 dns_rdataset_current(rdataset, &rdata); 601 result = dns_rdata_additionaldata(&rdata, owner_name, add, arg); 602 if (result == ISC_R_SUCCESS) { 603 result = dns_rdataset_next(rdataset); 604 } 605 dns_rdata_reset(&rdata); 606 } while (result == ISC_R_SUCCESS); 607 608 if (result != ISC_R_NOMORE) { 609 return (result); 610 } 611 612 return (ISC_R_SUCCESS); 613} 614 615isc_result_t 616dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) { 617 REQUIRE(DNS_RDATASET_VALID(rdataset)); 618 REQUIRE(rdataset->methods != NULL); 619 if (rdataset->methods->addnoqname == NULL) { 620 return (ISC_R_NOTIMPLEMENTED); 621 } 622 return ((rdataset->methods->addnoqname)(rdataset, name)); 623} 624 625isc_result_t 626dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, 627 dns_rdataset_t *neg, dns_rdataset_t *negsig) { 628 REQUIRE(DNS_RDATASET_VALID(rdataset)); 629 REQUIRE(rdataset->methods != NULL); 630 631 if (rdataset->methods->getnoqname == NULL) { 632 return (ISC_R_NOTIMPLEMENTED); 633 } 634 return ((rdataset->methods->getnoqname)(rdataset, name, neg, negsig)); 635} 636 637isc_result_t 638dns_rdataset_addclosest(dns_rdataset_t *rdataset, const dns_name_t *name) { 639 REQUIRE(DNS_RDATASET_VALID(rdataset)); 640 REQUIRE(rdataset->methods != NULL); 641 if (rdataset->methods->addclosest == NULL) { 642 return (ISC_R_NOTIMPLEMENTED); 643 } 644 return ((rdataset->methods->addclosest)(rdataset, name)); 645} 646 647isc_result_t 648dns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, 649 dns_rdataset_t *neg, dns_rdataset_t *negsig) { 650 REQUIRE(DNS_RDATASET_VALID(rdataset)); 651 REQUIRE(rdataset->methods != NULL); 652 653 if (rdataset->methods->getclosest == NULL) { 654 return (ISC_R_NOTIMPLEMENTED); 655 } 656 return ((rdataset->methods->getclosest)(rdataset, name, neg, negsig)); 657} 658 659void 660dns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { 661 REQUIRE(DNS_RDATASET_VALID(rdataset)); 662 REQUIRE(rdataset->methods != NULL); 663 664 if (rdataset->methods->settrust != NULL) { 665 (rdataset->methods->settrust)(rdataset, trust); 666 } else { 667 rdataset->trust = trust; 668 } 669} 670 671void 672dns_rdataset_expire(dns_rdataset_t *rdataset) { 673 REQUIRE(DNS_RDATASET_VALID(rdataset)); 674 REQUIRE(rdataset->methods != NULL); 675 676 if (rdataset->methods->expire != NULL) { 677 (rdataset->methods->expire)(rdataset); 678 } 679} 680 681void 682dns_rdataset_clearprefetch(dns_rdataset_t *rdataset) { 683 REQUIRE(DNS_RDATASET_VALID(rdataset)); 684 REQUIRE(rdataset->methods != NULL); 685 686 if (rdataset->methods->clearprefetch != NULL) { 687 (rdataset->methods->clearprefetch)(rdataset); 688 } 689} 690 691void 692dns_rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) { 693 REQUIRE(DNS_RDATASET_VALID(rdataset)); 694 REQUIRE(rdataset->methods != NULL); 695 696 if (rdataset->methods->setownercase != NULL) { 697 (rdataset->methods->setownercase)(rdataset, name); 698 } 699} 700 701void 702dns_rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { 703 REQUIRE(DNS_RDATASET_VALID(rdataset)); 704 REQUIRE(rdataset->methods != NULL); 705 706 if (rdataset->methods->getownercase != NULL) { 707 (rdataset->methods->getownercase)(rdataset, name); 708 } 709} 710 711void 712dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, 713 dns_rdata_rrsig_t *rrsig, isc_stdtime_t now, 714 bool acceptexpired) { 715 uint32_t ttl = 0; 716 717 REQUIRE(DNS_RDATASET_VALID(rdataset)); 718 REQUIRE(DNS_RDATASET_VALID(sigrdataset)); 719 REQUIRE(rrsig != NULL); 720 721 /* 722 * If we accept expired RRsets keep them for no more than 120 seconds. 723 */ 724 if (acceptexpired && 725 (isc_serial_le(rrsig->timeexpire, ((now + 120) & 0xffffffff)) || 726 isc_serial_le(rrsig->timeexpire, now))) 727 { 728 ttl = 120; 729 } else if (isc_serial_ge(rrsig->timeexpire, now)) { 730 ttl = rrsig->timeexpire - now; 731 } 732 733 ttl = ISC_MIN(ISC_MIN(rdataset->ttl, sigrdataset->ttl), 734 ISC_MIN(rrsig->originalttl, ttl)); 735 rdataset->ttl = ttl; 736 sigrdataset->ttl = ttl; 737} 738 739isc_result_t 740dns_rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version, 741 dns_message_t *msg) { 742 REQUIRE(DNS_RDATASET_VALID(rdataset)); 743 REQUIRE(rdataset->methods != NULL); 744 REQUIRE(rdataset->type == dns_rdatatype_ns); 745 746 if (rdataset->methods->addglue == NULL) { 747 return (ISC_R_NOTIMPLEMENTED); 748 } 749 750 return ((rdataset->methods->addglue)(rdataset, version, msg)); 751} 752