1 /* $NetBSD: ncache.c,v 1.8 2023/01/25 21:43: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 21 #include <isc/buffer.h> 22 #include <isc/util.h> 23 24 #include <dns/db.h> 25 #include <dns/message.h> 26 #include <dns/ncache.h> 27 #include <dns/rdata.h> 28 #include <dns/rdatalist.h> 29 #include <dns/rdataset.h> 30 #include <dns/rdatastruct.h> 31 32 #define DNS_NCACHE_RDATA 100U 33 34 /* 35 * The format of an ncache rdata is a sequence of zero or more records of 36 * the following format: 37 * 38 * owner name 39 * type 40 * trust 41 * rdata count 42 * rdata length These two occur 'rdata count' 43 * rdata times. 44 * 45 */ 46 47 static isc_result_t 48 addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, 49 dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, 50 dns_ttl_t maxttl, bool optout, bool secure, 51 dns_rdataset_t *addedrdataset); 52 53 static isc_result_t 54 copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) { 55 isc_result_t result; 56 unsigned int count; 57 isc_region_t ar, r; 58 dns_rdata_t rdata = DNS_RDATA_INIT; 59 60 /* 61 * Copy the rdataset count to the buffer. 62 */ 63 isc_buffer_availableregion(buffer, &ar); 64 if (ar.length < 2) { 65 return (ISC_R_NOSPACE); 66 } 67 count = dns_rdataset_count(rdataset); 68 INSIST(count <= 65535); 69 isc_buffer_putuint16(buffer, (uint16_t)count); 70 71 result = dns_rdataset_first(rdataset); 72 while (result == ISC_R_SUCCESS) { 73 dns_rdataset_current(rdataset, &rdata); 74 dns_rdata_toregion(&rdata, &r); 75 INSIST(r.length <= 65535); 76 isc_buffer_availableregion(buffer, &ar); 77 if (ar.length < 2) { 78 return (ISC_R_NOSPACE); 79 } 80 /* 81 * Copy the rdata length to the buffer. 82 */ 83 isc_buffer_putuint16(buffer, (uint16_t)r.length); 84 /* 85 * Copy the rdata to the buffer. 86 */ 87 result = isc_buffer_copyregion(buffer, &r); 88 if (result != ISC_R_SUCCESS) { 89 return (result); 90 } 91 dns_rdata_reset(&rdata); 92 result = dns_rdataset_next(rdataset); 93 } 94 if (result != ISC_R_NOMORE) { 95 return (result); 96 } 97 98 return (ISC_R_SUCCESS); 99 } 100 101 isc_result_t 102 dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, 103 dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, 104 dns_ttl_t maxttl, dns_rdataset_t *addedrdataset) { 105 return (addoptout(message, cache, node, covers, now, minttl, maxttl, 106 false, false, addedrdataset)); 107 } 108 109 isc_result_t 110 dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, 111 dns_dbnode_t *node, dns_rdatatype_t covers, 112 isc_stdtime_t now, dns_ttl_t minttl, dns_ttl_t maxttl, 113 bool optout, dns_rdataset_t *addedrdataset) { 114 return (addoptout(message, cache, node, covers, now, minttl, maxttl, 115 optout, true, addedrdataset)); 116 } 117 118 static isc_result_t 119 addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, 120 dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl, 121 dns_ttl_t maxttl, bool optout, bool secure, 122 dns_rdataset_t *addedrdataset) { 123 isc_result_t result; 124 isc_buffer_t buffer; 125 isc_region_t r; 126 dns_rdataset_t *rdataset; 127 dns_rdatatype_t type; 128 dns_name_t *name; 129 dns_ttl_t ttl; 130 dns_trust_t trust; 131 dns_rdata_t rdata[DNS_NCACHE_RDATA]; 132 dns_rdataset_t ncrdataset; 133 dns_rdatalist_t ncrdatalist; 134 unsigned char data[65536]; 135 unsigned int next = 0; 136 137 /* 138 * Convert the authority data from 'message' into a negative cache 139 * rdataset, and store it in 'cache' at 'node'. 140 */ 141 142 REQUIRE(message != NULL); 143 144 /* 145 * We assume that all data in the authority section has been 146 * validated by the caller. 147 */ 148 149 /* 150 * Initialize the list. 151 */ 152 dns_rdatalist_init(&ncrdatalist); 153 ncrdatalist.rdclass = dns_db_class(cache); 154 ncrdatalist.covers = covers; 155 ncrdatalist.ttl = maxttl; 156 157 /* 158 * Build an ncache rdatas into buffer. 159 */ 160 ttl = maxttl; 161 trust = 0xffff; 162 isc_buffer_init(&buffer, data, sizeof(data)); 163 if (message->counts[DNS_SECTION_AUTHORITY]) { 164 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); 165 } else { 166 result = ISC_R_NOMORE; 167 } 168 while (result == ISC_R_SUCCESS) { 169 name = NULL; 170 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); 171 if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) { 172 for (rdataset = ISC_LIST_HEAD(name->list); 173 rdataset != NULL; 174 rdataset = ISC_LIST_NEXT(rdataset, link)) 175 { 176 if ((rdataset->attributes & 177 DNS_RDATASETATTR_NCACHE) == 0) 178 { 179 continue; 180 } 181 type = rdataset->type; 182 if (type == dns_rdatatype_rrsig) { 183 type = rdataset->covers; 184 } 185 if (type == dns_rdatatype_soa || 186 type == dns_rdatatype_nsec || 187 type == dns_rdatatype_nsec3) 188 { 189 if (ttl > rdataset->ttl) { 190 ttl = rdataset->ttl; 191 } 192 if (ttl < minttl) { 193 ttl = minttl; 194 } 195 if (trust > rdataset->trust) { 196 trust = rdataset->trust; 197 } 198 /* 199 * Copy the owner name to the buffer. 200 */ 201 dns_name_toregion(name, &r); 202 result = isc_buffer_copyregion(&buffer, 203 &r); 204 if (result != ISC_R_SUCCESS) { 205 return (result); 206 } 207 /* 208 * Copy the type to the buffer. 209 */ 210 isc_buffer_availableregion(&buffer, &r); 211 if (r.length < 3) { 212 return (ISC_R_NOSPACE); 213 } 214 isc_buffer_putuint16(&buffer, 215 rdataset->type); 216 isc_buffer_putuint8( 217 &buffer, 218 (unsigned char)rdataset->trust); 219 /* 220 * Copy the rdataset into the buffer. 221 */ 222 result = copy_rdataset(rdataset, 223 &buffer); 224 if (result != ISC_R_SUCCESS) { 225 return (result); 226 } 227 228 if (next >= DNS_NCACHE_RDATA) { 229 return (ISC_R_NOSPACE); 230 } 231 dns_rdata_init(&rdata[next]); 232 isc_buffer_remainingregion(&buffer, &r); 233 rdata[next].data = r.base; 234 rdata[next].length = r.length; 235 rdata[next].rdclass = 236 ncrdatalist.rdclass; 237 rdata[next].type = 0; 238 rdata[next].flags = 0; 239 ISC_LIST_APPEND(ncrdatalist.rdata, 240 &rdata[next], link); 241 isc_buffer_forward(&buffer, r.length); 242 next++; 243 } 244 } 245 } 246 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY); 247 } 248 if (result != ISC_R_NOMORE) { 249 return (result); 250 } 251 252 if (trust == 0xffff) { 253 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 && 254 message->counts[DNS_SECTION_ANSWER] == 0) 255 { 256 /* 257 * The response has aa set and we haven't followed 258 * any CNAME or DNAME chains. 259 */ 260 trust = dns_trust_authauthority; 261 } else { 262 trust = dns_trust_additional; 263 } 264 ttl = 0; 265 } 266 267 INSIST(trust != 0xffff); 268 269 ncrdatalist.ttl = ttl; 270 271 dns_rdataset_init(&ncrdataset); 272 RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset) == 273 ISC_R_SUCCESS); 274 if (!secure && trust > dns_trust_answer) { 275 trust = dns_trust_answer; 276 } 277 ncrdataset.trust = trust; 278 ncrdataset.attributes |= DNS_RDATASETATTR_NEGATIVE; 279 if (message->rcode == dns_rcode_nxdomain) { 280 ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN; 281 } 282 if (optout) { 283 ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT; 284 } 285 286 return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset, 0, 287 addedrdataset)); 288 } 289 290 isc_result_t 291 dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx, 292 isc_buffer_t *target, unsigned int options, 293 unsigned int *countp) { 294 dns_rdata_t rdata = DNS_RDATA_INIT; 295 isc_result_t result; 296 isc_region_t remaining, tavailable; 297 isc_buffer_t source, savedbuffer, rdlen; 298 dns_name_t name; 299 dns_rdatatype_t type; 300 unsigned int i, rcount, count; 301 302 /* 303 * Convert the negative caching rdataset 'rdataset' to wire format, 304 * compressing names as specified in 'cctx', and storing the result in 305 * 'target'. 306 */ 307 308 REQUIRE(rdataset != NULL); 309 REQUIRE(rdataset->type == 0); 310 REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 311 312 savedbuffer = *target; 313 count = 0; 314 315 result = dns_rdataset_first(rdataset); 316 while (result == ISC_R_SUCCESS) { 317 dns_rdataset_current(rdataset, &rdata); 318 isc_buffer_init(&source, rdata.data, rdata.length); 319 isc_buffer_add(&source, rdata.length); 320 dns_name_init(&name, NULL); 321 isc_buffer_remainingregion(&source, &remaining); 322 dns_name_fromregion(&name, &remaining); 323 INSIST(remaining.length >= name.length); 324 isc_buffer_forward(&source, name.length); 325 remaining.length -= name.length; 326 327 INSIST(remaining.length >= 5); 328 type = isc_buffer_getuint16(&source); 329 isc_buffer_forward(&source, 1); 330 rcount = isc_buffer_getuint16(&source); 331 332 for (i = 0; i < rcount; i++) { 333 /* 334 * Get the length of this rdata and set up an 335 * rdata structure for it. 336 */ 337 isc_buffer_remainingregion(&source, &remaining); 338 INSIST(remaining.length >= 2); 339 dns_rdata_reset(&rdata); 340 rdata.length = isc_buffer_getuint16(&source); 341 isc_buffer_remainingregion(&source, &remaining); 342 rdata.data = remaining.base; 343 rdata.type = type; 344 rdata.rdclass = rdataset->rdclass; 345 INSIST(remaining.length >= rdata.length); 346 isc_buffer_forward(&source, rdata.length); 347 348 if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 && 349 dns_rdatatype_isdnssec(type)) 350 { 351 continue; 352 } 353 354 /* 355 * Write the name. 356 */ 357 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14); 358 result = dns_name_towire(&name, cctx, target); 359 if (result != ISC_R_SUCCESS) { 360 goto rollback; 361 } 362 363 /* 364 * See if we have space for type, class, ttl, and 365 * rdata length. Write the type, class, and ttl. 366 */ 367 isc_buffer_availableregion(target, &tavailable); 368 if (tavailable.length < 10) { 369 result = ISC_R_NOSPACE; 370 goto rollback; 371 } 372 isc_buffer_putuint16(target, type); 373 isc_buffer_putuint16(target, rdataset->rdclass); 374 isc_buffer_putuint32(target, rdataset->ttl); 375 376 /* 377 * Save space for rdata length. 378 */ 379 rdlen = *target; 380 isc_buffer_add(target, 2); 381 382 /* 383 * Write the rdata. 384 */ 385 result = dns_rdata_towire(&rdata, cctx, target); 386 if (result != ISC_R_SUCCESS) { 387 goto rollback; 388 } 389 390 /* 391 * Set the rdata length field to the compressed 392 * length. 393 */ 394 INSIST((target->used >= rdlen.used + 2) && 395 (target->used - rdlen.used - 2 < 65536)); 396 isc_buffer_putuint16( 397 &rdlen, 398 (uint16_t)(target->used - rdlen.used - 2)); 399 400 count++; 401 } 402 INSIST(isc_buffer_remaininglength(&source) == 0); 403 result = dns_rdataset_next(rdataset); 404 dns_rdata_reset(&rdata); 405 } 406 if (result != ISC_R_NOMORE) { 407 goto rollback; 408 } 409 410 *countp = count; 411 412 return (ISC_R_SUCCESS); 413 414 rollback: 415 INSIST(savedbuffer.used < 65536); 416 dns_compress_rollback(cctx, (uint16_t)savedbuffer.used); 417 *countp = 0; 418 *target = savedbuffer; 419 420 return (result); 421 } 422 423 static void 424 rdataset_disassociate(dns_rdataset_t *rdataset) { 425 UNUSED(rdataset); 426 } 427 428 static isc_result_t 429 rdataset_first(dns_rdataset_t *rdataset) { 430 unsigned char *raw = rdataset->private3; 431 unsigned int count; 432 433 count = raw[0] * 256 + raw[1]; 434 if (count == 0) { 435 rdataset->private5 = NULL; 436 return (ISC_R_NOMORE); 437 } 438 raw += 2; 439 /* 440 * The privateuint4 field is the number of rdata beyond the cursor 441 * position, so we decrement the total count by one before storing 442 * it. 443 */ 444 count--; 445 rdataset->privateuint4 = count; 446 rdataset->private5 = raw; 447 448 return (ISC_R_SUCCESS); 449 } 450 451 static isc_result_t 452 rdataset_next(dns_rdataset_t *rdataset) { 453 unsigned int count; 454 unsigned int length; 455 unsigned char *raw; 456 457 count = rdataset->privateuint4; 458 if (count == 0) { 459 return (ISC_R_NOMORE); 460 } 461 count--; 462 rdataset->privateuint4 = count; 463 raw = rdataset->private5; 464 length = raw[0] * 256 + raw[1]; 465 raw += length + 2; 466 rdataset->private5 = raw; 467 468 return (ISC_R_SUCCESS); 469 } 470 471 static void 472 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { 473 unsigned char *raw = rdataset->private5; 474 isc_region_t r; 475 476 REQUIRE(raw != NULL); 477 478 r.length = raw[0] * 256 + raw[1]; 479 raw += 2; 480 r.base = raw; 481 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r); 482 } 483 484 static void 485 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 486 *target = *source; 487 488 /* 489 * Reset iterator state. 490 */ 491 target->privateuint4 = 0; 492 target->private5 = NULL; 493 } 494 495 static unsigned int 496 rdataset_count(dns_rdataset_t *rdataset) { 497 unsigned char *raw = rdataset->private3; 498 unsigned int count; 499 500 count = raw[0] * 256 + raw[1]; 501 502 return (count); 503 } 504 505 static void 506 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { 507 unsigned char *raw = rdataset->private3; 508 509 raw[-1] = (unsigned char)trust; 510 rdataset->trust = trust; 511 } 512 513 static dns_rdatasetmethods_t rdataset_methods = { 514 rdataset_disassociate, 515 rdataset_first, 516 rdataset_next, 517 rdataset_current, 518 rdataset_clone, 519 rdataset_count, 520 NULL, /* addnoqname */ 521 NULL, /* getnoqname */ 522 NULL, /* addclosest */ 523 NULL, /* getclosest */ 524 rdataset_settrust, /* settrust */ 525 NULL, /* expire */ 526 NULL, /* clearprefetch */ 527 NULL, /* setownercase */ 528 NULL, /* getownercase */ 529 NULL /* addglue */ 530 }; 531 532 isc_result_t 533 dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, 534 dns_rdatatype_t type, dns_rdataset_t *rdataset) { 535 isc_result_t result; 536 dns_rdata_t rdata = DNS_RDATA_INIT; 537 isc_region_t remaining; 538 isc_buffer_t source; 539 dns_name_t tname; 540 dns_rdatatype_t ttype; 541 dns_trust_t trust = dns_trust_none; 542 dns_rdataset_t rclone; 543 544 REQUIRE(ncacherdataset != NULL); 545 REQUIRE(ncacherdataset->type == 0); 546 REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 547 REQUIRE(name != NULL); 548 REQUIRE(!dns_rdataset_isassociated(rdataset)); 549 REQUIRE(type != dns_rdatatype_rrsig); 550 551 dns_rdataset_init(&rclone); 552 dns_rdataset_clone(ncacherdataset, &rclone); 553 result = dns_rdataset_first(&rclone); 554 while (result == ISC_R_SUCCESS) { 555 dns_rdataset_current(&rclone, &rdata); 556 isc_buffer_init(&source, rdata.data, rdata.length); 557 isc_buffer_add(&source, rdata.length); 558 dns_name_init(&tname, NULL); 559 isc_buffer_remainingregion(&source, &remaining); 560 dns_name_fromregion(&tname, &remaining); 561 INSIST(remaining.length >= tname.length); 562 isc_buffer_forward(&source, tname.length); 563 remaining.length -= tname.length; 564 565 INSIST(remaining.length >= 3); 566 ttype = isc_buffer_getuint16(&source); 567 568 if (ttype == type && dns_name_equal(&tname, name)) { 569 trust = isc_buffer_getuint8(&source); 570 INSIST(trust <= dns_trust_ultimate); 571 isc_buffer_remainingregion(&source, &remaining); 572 break; 573 } 574 result = dns_rdataset_next(&rclone); 575 dns_rdata_reset(&rdata); 576 } 577 dns_rdataset_disassociate(&rclone); 578 if (result == ISC_R_NOMORE) { 579 return (ISC_R_NOTFOUND); 580 } 581 if (result != ISC_R_SUCCESS) { 582 return (result); 583 } 584 585 INSIST(remaining.length != 0); 586 587 rdataset->methods = &rdataset_methods; 588 rdataset->rdclass = ncacherdataset->rdclass; 589 rdataset->type = type; 590 rdataset->covers = 0; 591 rdataset->ttl = ncacherdataset->ttl; 592 rdataset->trust = trust; 593 rdataset->private1 = NULL; 594 rdataset->private2 = NULL; 595 596 rdataset->private3 = remaining.base; 597 598 /* 599 * Reset iterator state. 600 */ 601 rdataset->privateuint4 = 0; 602 rdataset->private5 = NULL; 603 rdataset->private6 = NULL; 604 return (ISC_R_SUCCESS); 605 } 606 607 isc_result_t 608 dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, 609 dns_rdatatype_t covers, dns_rdataset_t *rdataset) { 610 dns_name_t tname; 611 dns_rdata_rrsig_t rrsig; 612 dns_rdata_t rdata = DNS_RDATA_INIT; 613 dns_rdataset_t rclone; 614 dns_rdatatype_t type; 615 dns_trust_t trust = dns_trust_none; 616 isc_buffer_t source; 617 isc_region_t remaining, sigregion; 618 isc_result_t result; 619 unsigned char *raw; 620 unsigned int count; 621 622 REQUIRE(ncacherdataset != NULL); 623 REQUIRE(ncacherdataset->type == 0); 624 REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 625 REQUIRE(name != NULL); 626 REQUIRE(!dns_rdataset_isassociated(rdataset)); 627 628 dns_rdataset_init(&rclone); 629 dns_rdataset_clone(ncacherdataset, &rclone); 630 result = dns_rdataset_first(&rclone); 631 while (result == ISC_R_SUCCESS) { 632 dns_rdataset_current(&rclone, &rdata); 633 isc_buffer_init(&source, rdata.data, rdata.length); 634 isc_buffer_add(&source, rdata.length); 635 dns_name_init(&tname, NULL); 636 isc_buffer_remainingregion(&source, &remaining); 637 dns_name_fromregion(&tname, &remaining); 638 INSIST(remaining.length >= tname.length); 639 isc_buffer_forward(&source, tname.length); 640 isc_region_consume(&remaining, tname.length); 641 642 INSIST(remaining.length >= 2); 643 type = isc_buffer_getuint16(&source); 644 isc_region_consume(&remaining, 2); 645 646 if (type != dns_rdatatype_rrsig || 647 !dns_name_equal(&tname, name)) 648 { 649 result = dns_rdataset_next(&rclone); 650 dns_rdata_reset(&rdata); 651 continue; 652 } 653 654 INSIST(remaining.length >= 1); 655 trust = isc_buffer_getuint8(&source); 656 INSIST(trust <= dns_trust_ultimate); 657 isc_region_consume(&remaining, 1); 658 659 raw = remaining.base; 660 count = raw[0] * 256 + raw[1]; 661 INSIST(count > 0); 662 raw += 2; 663 sigregion.length = raw[0] * 256 + raw[1]; 664 raw += 2; 665 sigregion.base = raw; 666 dns_rdata_reset(&rdata); 667 dns_rdata_fromregion(&rdata, rdataset->rdclass, 668 dns_rdatatype_rrsig, &sigregion); 669 (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); 670 if (rrsig.covered == covers) { 671 isc_buffer_remainingregion(&source, &remaining); 672 break; 673 } 674 675 result = dns_rdataset_next(&rclone); 676 dns_rdata_reset(&rdata); 677 } 678 dns_rdataset_disassociate(&rclone); 679 if (result == ISC_R_NOMORE) { 680 return (ISC_R_NOTFOUND); 681 } 682 if (result != ISC_R_SUCCESS) { 683 return (result); 684 } 685 686 INSIST(remaining.length != 0); 687 688 rdataset->methods = &rdataset_methods; 689 rdataset->rdclass = ncacherdataset->rdclass; 690 rdataset->type = dns_rdatatype_rrsig; 691 rdataset->covers = covers; 692 rdataset->ttl = ncacherdataset->ttl; 693 rdataset->trust = trust; 694 rdataset->private1 = NULL; 695 rdataset->private2 = NULL; 696 697 rdataset->private3 = remaining.base; 698 699 /* 700 * Reset iterator state. 701 */ 702 rdataset->privateuint4 = 0; 703 rdataset->private5 = NULL; 704 rdataset->private6 = NULL; 705 return (ISC_R_SUCCESS); 706 } 707 708 void 709 dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found, 710 dns_rdataset_t *rdataset) { 711 dns_rdata_t rdata = DNS_RDATA_INIT; 712 dns_trust_t trust; 713 isc_region_t remaining, sigregion; 714 isc_buffer_t source; 715 dns_name_t tname; 716 dns_rdatatype_t type; 717 unsigned int count; 718 dns_rdata_rrsig_t rrsig; 719 unsigned char *raw; 720 721 REQUIRE(ncacherdataset != NULL); 722 REQUIRE(ncacherdataset->type == 0); 723 REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0); 724 REQUIRE(found != NULL); 725 REQUIRE(!dns_rdataset_isassociated(rdataset)); 726 727 dns_rdataset_current(ncacherdataset, &rdata); 728 isc_buffer_init(&source, rdata.data, rdata.length); 729 isc_buffer_add(&source, rdata.length); 730 731 dns_name_init(&tname, NULL); 732 isc_buffer_remainingregion(&source, &remaining); 733 dns_name_fromregion(found, &remaining); 734 INSIST(remaining.length >= found->length); 735 isc_buffer_forward(&source, found->length); 736 remaining.length -= found->length; 737 738 INSIST(remaining.length >= 5); 739 type = isc_buffer_getuint16(&source); 740 trust = isc_buffer_getuint8(&source); 741 INSIST(trust <= dns_trust_ultimate); 742 isc_buffer_remainingregion(&source, &remaining); 743 744 rdataset->methods = &rdataset_methods; 745 rdataset->rdclass = ncacherdataset->rdclass; 746 rdataset->type = type; 747 if (type == dns_rdatatype_rrsig) { 748 /* 749 * Extract covers from RRSIG. 750 */ 751 raw = remaining.base; 752 count = raw[0] * 256 + raw[1]; 753 INSIST(count > 0); 754 raw += 2; 755 sigregion.length = raw[0] * 256 + raw[1]; 756 raw += 2; 757 sigregion.base = raw; 758 dns_rdata_reset(&rdata); 759 dns_rdata_fromregion(&rdata, rdataset->rdclass, rdataset->type, 760 &sigregion); 761 (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); 762 rdataset->covers = rrsig.covered; 763 } else { 764 rdataset->covers = 0; 765 } 766 rdataset->ttl = ncacherdataset->ttl; 767 rdataset->trust = trust; 768 rdataset->private1 = NULL; 769 rdataset->private2 = NULL; 770 771 rdataset->private3 = remaining.base; 772 773 /* 774 * Reset iterator state. 775 */ 776 rdataset->privateuint4 = 0; 777 rdataset->private5 = NULL; 778 rdataset->private6 = NULL; 779 } 780