1 /* $NetBSD: rdataslab.c,v 1.10 2025/01/26 16:25:24 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 <ctype.h> 19 #include <stdbool.h> 20 #include <stdlib.h> 21 22 #include <isc/ascii.h> 23 #include <isc/mem.h> 24 #include <isc/region.h> 25 #include <isc/result.h> 26 #include <isc/string.h> 27 #include <isc/util.h> 28 29 #include <dns/db.h> 30 #include <dns/rdata.h> 31 #include <dns/rdataset.h> 32 #include <dns/rdataslab.h> 33 #include <dns/stats.h> 34 35 #define CASESET(header) \ 36 ((atomic_load_acquire(&(header)->attributes) & \ 37 DNS_SLABHEADERATTR_CASESET) != 0) 38 #define CASEFULLYLOWER(header) \ 39 ((atomic_load_acquire(&(header)->attributes) & \ 40 DNS_SLABHEADERATTR_CASEFULLYLOWER) != 0) 41 #define NONEXISTENT(header) \ 42 ((atomic_load_acquire(&(header)->attributes) & \ 43 DNS_SLABHEADERATTR_NONEXISTENT) != 0) 44 45 /* 46 * The rdataslab structure allows iteration to occur in both load order 47 * and DNSSEC order. The structure is as follows: 48 * 49 * header (reservelen bytes) 50 * record count (2 bytes) 51 * offset table (4 x record count bytes in load order) 52 * data records 53 * data length (2 bytes) 54 * order (2 bytes) 55 * meta data (1 byte for RRSIG's) 56 * data (data length bytes) 57 * 58 * If DNS_RDATASET_FIXED is defined to be zero (0) the format of a 59 * rdataslab is as follows: 60 * 61 * header (reservelen bytes) 62 * record count (2 bytes) 63 * data records 64 * data length (2 bytes) 65 * meta data (1 byte for RRSIG's) 66 * data (data length bytes) 67 * 68 * Offsets are from the end of the header. 69 * 70 * Load order traversal is performed by walking the offset table to find 71 * the start of the record (DNS_RDATASET_FIXED = 1). 72 * 73 * DNSSEC order traversal is performed by walking the data records. 74 * 75 * The order is stored with record to allow for efficient reconstruction 76 * of the offset table following a merge or subtraction. 77 * 78 * The iterator methods in rbtdb support both load order and DNSSEC order 79 * iteration. 80 * 81 * WARNING: 82 * rbtdb.c directly interacts with the slab's raw structures. If the 83 * structure changes then rbtdb.c also needs to be updated to reflect 84 * the changes. See the areas tagged with "RDATASLAB". 85 */ 86 87 struct xrdata { 88 dns_rdata_t rdata; 89 #if DNS_RDATASET_FIXED 90 unsigned int order; 91 #endif /* if DNS_RDATASET_FIXED */ 92 }; 93 94 #define peek_uint16(buffer) ({ ((uint16_t)*(buffer) << 8) | *((buffer) + 1); }) 95 #define get_uint16(buffer) \ 96 ({ \ 97 uint16_t __ret = peek_uint16(buffer); \ 98 buffer += sizeof(uint16_t); \ 99 __ret; \ 100 }) 101 102 static void 103 rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG); 104 static isc_result_t 105 rdataset_first(dns_rdataset_t *rdataset); 106 static isc_result_t 107 rdataset_next(dns_rdataset_t *rdataset); 108 static void 109 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata); 110 static void 111 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG); 112 static unsigned int 113 rdataset_count(dns_rdataset_t *rdataset); 114 static isc_result_t 115 rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, 116 dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG); 117 static isc_result_t 118 rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, 119 dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG); 120 static void 121 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust); 122 static void 123 rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG); 124 static void 125 rdataset_clearprefetch(dns_rdataset_t *rdataset); 126 static void 127 rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name); 128 static void 129 rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name); 130 131 /*% Note: the "const void *" are just to make qsort happy. */ 132 static int 133 compare_rdata(const void *p1, const void *p2) { 134 const struct xrdata *x1 = p1; 135 const struct xrdata *x2 = p2; 136 return dns_rdata_compare(&x1->rdata, &x2->rdata); 137 } 138 139 #if DNS_RDATASET_FIXED 140 static void 141 fillin_offsets(unsigned char *offsetbase, unsigned int *offsettable, 142 unsigned int length) { 143 unsigned int i, j; 144 unsigned char *raw = NULL; 145 146 for (i = 0, j = 0; i < length; i++) { 147 if (offsettable[i] == 0) { 148 continue; 149 } 150 151 /* 152 * Fill in offset table. 153 */ 154 raw = &offsetbase[j * 4 + 2]; 155 *raw++ = (offsettable[i] & 0xff000000) >> 24; 156 *raw++ = (offsettable[i] & 0xff0000) >> 16; 157 *raw++ = (offsettable[i] & 0xff00) >> 8; 158 *raw = offsettable[i] & 0xff; 159 160 /* 161 * Fill in table index. 162 */ 163 raw = offsetbase + offsettable[i] + 2; 164 *raw++ = (j & 0xff00) >> 8; 165 *raw = j++ & 0xff; 166 } 167 } 168 #endif /* if DNS_RDATASET_FIXED */ 169 170 isc_result_t 171 dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, 172 isc_region_t *region, unsigned int reservelen, 173 uint32_t maxrrperset) { 174 /* 175 * Use &removed as a sentinel pointer for duplicate 176 * rdata as rdata.data == NULL is valid. 177 */ 178 static unsigned char removed; 179 struct xrdata *x = NULL; 180 unsigned char *rawbuf = NULL; 181 unsigned int buflen; 182 isc_result_t result; 183 unsigned int nitems; 184 unsigned int nalloc; 185 unsigned int length; 186 unsigned int i; 187 #if DNS_RDATASET_FIXED 188 unsigned char *offsetbase = NULL; 189 unsigned int *offsettable = NULL; 190 #endif /* if DNS_RDATASET_FIXED */ 191 192 buflen = reservelen + 2; 193 194 nitems = dns_rdataset_count(rdataset); 195 196 /* 197 * If there are no rdata then we can just need to allocate a header 198 * with zero a record count. 199 */ 200 if (nitems == 0) { 201 if (rdataset->type != 0) { 202 return ISC_R_FAILURE; 203 } 204 rawbuf = isc_mem_get(mctx, buflen); 205 region->base = rawbuf; 206 region->length = buflen; 207 rawbuf += reservelen; 208 *rawbuf++ = 0; 209 *rawbuf = 0; 210 return ISC_R_SUCCESS; 211 } 212 213 if (maxrrperset > 0 && nitems > maxrrperset) { 214 return DNS_R_TOOMANYRECORDS; 215 } 216 217 if (nitems > 0xffff) { 218 return ISC_R_NOSPACE; 219 } 220 221 /* 222 * Remember the original number of items. 223 */ 224 nalloc = nitems; 225 x = isc_mem_cget(mctx, nalloc, sizeof(struct xrdata)); 226 227 /* 228 * Save all of the rdata members into an array. 229 */ 230 result = dns_rdataset_first(rdataset); 231 if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) { 232 goto free_rdatas; 233 } 234 for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) { 235 INSIST(result == ISC_R_SUCCESS); 236 dns_rdata_init(&x[i].rdata); 237 dns_rdataset_current(rdataset, &x[i].rdata); 238 INSIST(x[i].rdata.data != &removed); 239 #if DNS_RDATASET_FIXED 240 x[i].order = i; 241 #endif /* if DNS_RDATASET_FIXED */ 242 result = dns_rdataset_next(rdataset); 243 } 244 if (i != nalloc || result != ISC_R_NOMORE) { 245 /* 246 * Somehow we iterated over fewer rdatas than 247 * dns_rdataset_count() said there were or there 248 * were more items than dns_rdataset_count said 249 * there were. 250 */ 251 result = ISC_R_FAILURE; 252 goto free_rdatas; 253 } 254 255 /* 256 * Put into DNSSEC order. 257 */ 258 if (nalloc > 1U) { 259 qsort(x, nalloc, sizeof(struct xrdata), compare_rdata); 260 } 261 262 /* 263 * Remove duplicates and compute the total storage required. 264 * 265 * If an rdata is not a duplicate, accumulate the storage size 266 * required for the rdata. We do not store the class, type, etc, 267 * just the rdata, so our overhead is 2 bytes for the number of 268 * records, and 8 for each rdata, (length(2), offset(4) and order(2)) 269 * and then the rdata itself. 270 */ 271 for (i = 1; i < nalloc; i++) { 272 if (compare_rdata(&x[i - 1].rdata, &x[i].rdata) == 0) { 273 x[i - 1].rdata.data = &removed; 274 #if DNS_RDATASET_FIXED 275 /* 276 * Preserve the least order so A, B, A -> A, B 277 * after duplicate removal. 278 */ 279 if (x[i - 1].order < x[i].order) { 280 x[i].order = x[i - 1].order; 281 } 282 #endif /* if DNS_RDATASET_FIXED */ 283 nitems--; 284 } else { 285 #if DNS_RDATASET_FIXED 286 buflen += (8 + x[i - 1].rdata.length); 287 #else /* if DNS_RDATASET_FIXED */ 288 buflen += (2 + x[i - 1].rdata.length); 289 #endif /* if DNS_RDATASET_FIXED */ 290 /* 291 * Provide space to store the per RR meta data. 292 */ 293 if (rdataset->type == dns_rdatatype_rrsig) { 294 buflen++; 295 } 296 } 297 } 298 299 /* 300 * Don't forget the last item! 301 */ 302 #if DNS_RDATASET_FIXED 303 buflen += (8 + x[i - 1].rdata.length); 304 #else /* if DNS_RDATASET_FIXED */ 305 buflen += (2 + x[i - 1].rdata.length); 306 #endif /* if DNS_RDATASET_FIXED */ 307 /* 308 * Provide space to store the per RR meta data. 309 */ 310 if (rdataset->type == dns_rdatatype_rrsig) { 311 buflen++; 312 } 313 314 /* 315 * Ensure that singleton types are actually singletons. 316 */ 317 if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) { 318 /* 319 * We have a singleton type, but there's more than one 320 * RR in the rdataset. 321 */ 322 result = DNS_R_SINGLETON; 323 goto free_rdatas; 324 } 325 326 /* 327 * Allocate the memory, set up a buffer, start copying in 328 * data. 329 */ 330 rawbuf = isc_mem_cget(mctx, 1, buflen); 331 332 #if DNS_RDATASET_FIXED 333 /* Allocate temporary offset table. */ 334 offsettable = isc_mem_cget(mctx, nalloc, sizeof(unsigned int)); 335 #endif /* if DNS_RDATASET_FIXED */ 336 337 region->base = rawbuf; 338 region->length = buflen; 339 340 rawbuf += reservelen; 341 342 #if DNS_RDATASET_FIXED 343 offsetbase = rawbuf; 344 #endif /* if DNS_RDATASET_FIXED */ 345 346 *rawbuf++ = (nitems & 0xff00) >> 8; 347 *rawbuf++ = (nitems & 0x00ff); 348 349 #if DNS_RDATASET_FIXED 350 /* Skip load order table. Filled in later. */ 351 rawbuf += nitems * 4; 352 #endif /* if DNS_RDATASET_FIXED */ 353 354 for (i = 0; i < nalloc; i++) { 355 if (x[i].rdata.data == &removed) { 356 continue; 357 } 358 #if DNS_RDATASET_FIXED 359 offsettable[x[i].order] = rawbuf - offsetbase; 360 #endif /* if DNS_RDATASET_FIXED */ 361 length = x[i].rdata.length; 362 if (rdataset->type == dns_rdatatype_rrsig) { 363 length++; 364 } 365 INSIST(length <= 0xffff); 366 *rawbuf++ = (length & 0xff00) >> 8; 367 *rawbuf++ = (length & 0x00ff); 368 #if DNS_RDATASET_FIXED 369 rawbuf += 2; /* filled in later */ 370 #endif /* if DNS_RDATASET_FIXED */ 371 /* 372 * Store the per RR meta data. 373 */ 374 if (rdataset->type == dns_rdatatype_rrsig) { 375 *rawbuf++ = (x[i].rdata.flags & DNS_RDATA_OFFLINE) 376 ? DNS_RDATASLAB_OFFLINE 377 : 0; 378 } 379 if (x[i].rdata.length != 0) { 380 memmove(rawbuf, x[i].rdata.data, x[i].rdata.length); 381 } 382 rawbuf += x[i].rdata.length; 383 } 384 385 #if DNS_RDATASET_FIXED 386 fillin_offsets(offsetbase, offsettable, nalloc); 387 isc_mem_cput(mctx, offsettable, nalloc, sizeof(unsigned int)); 388 #endif /* if DNS_RDATASET_FIXED */ 389 390 result = ISC_R_SUCCESS; 391 392 free_rdatas: 393 isc_mem_cput(mctx, x, nalloc, sizeof(struct xrdata)); 394 return result; 395 } 396 397 unsigned int 398 dns_rdataslab_size(unsigned char *slab, unsigned int reservelen) { 399 REQUIRE(slab != NULL); 400 401 unsigned char *current = slab + reservelen; 402 uint16_t count = get_uint16(current); 403 404 #if DNS_RDATASET_FIXED 405 current += (4 * count); 406 #endif /* if DNS_RDATASET_FIXED */ 407 408 while (count-- > 0) { 409 uint16_t length = get_uint16(current); 410 current += length; 411 #if DNS_RDATASET_FIXED 412 current += 2; 413 #endif /* if DNS_RDATASET_FIXED */ 414 } 415 416 return (unsigned int)(current - slab); 417 } 418 419 unsigned int 420 dns_rdataslab_rdatasize(unsigned char *slab, unsigned int reservelen) { 421 REQUIRE(slab != NULL); 422 423 uint16_t rdatalen = 0; 424 unsigned char *current = slab + reservelen; 425 uint16_t count = get_uint16(current); 426 427 #if DNS_RDATASET_FIXED 428 current += (4 * count); 429 #endif /* if DNS_RDATASET_FIXED */ 430 431 while (count-- > 0) { 432 uint16_t length = get_uint16(current); 433 rdatalen += length; 434 current += length; 435 #if DNS_RDATASET_FIXED 436 current += 2; 437 #endif /* if DNS_RDATASET_FIXED */ 438 } 439 440 return rdatalen; 441 } 442 443 unsigned int 444 dns_rdataslab_count(unsigned char *slab, unsigned int reservelen) { 445 REQUIRE(slab != NULL); 446 447 unsigned char *current = slab + reservelen; 448 uint16_t count = get_uint16(current); 449 450 return count; 451 } 452 453 /* 454 * Make the dns_rdata_t 'rdata' refer to the slab item 455 * beginning at '*current', which is part of a slab of type 456 * 'type' and class 'rdclass', and advance '*current' to 457 * point to the next item in the slab. 458 */ 459 static void 460 rdata_from_slab(unsigned char **current, dns_rdataclass_t rdclass, 461 dns_rdatatype_t type, dns_rdata_t *rdata) { 462 unsigned char *tcurrent = *current; 463 isc_region_t region; 464 bool offline = false; 465 uint16_t length = get_uint16(tcurrent); 466 467 if (type == dns_rdatatype_rrsig) { 468 if ((*tcurrent & DNS_RDATASLAB_OFFLINE) != 0) { 469 offline = true; 470 } 471 length--; 472 tcurrent++; 473 } 474 region.length = length; 475 #if DNS_RDATASET_FIXED 476 tcurrent += 2; 477 #endif /* if DNS_RDATASET_FIXED */ 478 region.base = tcurrent; 479 tcurrent += region.length; 480 dns_rdata_fromregion(rdata, rdclass, type, ®ion); 481 if (offline) { 482 rdata->flags |= DNS_RDATA_OFFLINE; 483 } 484 *current = tcurrent; 485 } 486 487 /* 488 * Return true iff 'slab' (slab data of type 'type' and class 'rdclass') 489 * contains an rdata identical to 'rdata'. This does case insensitive 490 * comparisons per DNSSEC. 491 */ 492 static bool 493 rdata_in_slab(unsigned char *slab, unsigned int reservelen, 494 dns_rdataclass_t rdclass, dns_rdatatype_t type, 495 dns_rdata_t *rdata) { 496 unsigned char *current = slab + reservelen; 497 498 uint16_t count = get_uint16(current); 499 500 #if DNS_RDATASET_FIXED 501 current += (4 * count); 502 #endif /* if DNS_RDATASET_FIXED */ 503 504 for (size_t i = 0; i < count; i++) { 505 dns_rdata_t trdata = DNS_RDATA_INIT; 506 rdata_from_slab(¤t, rdclass, type, &trdata); 507 508 int n = dns_rdata_compare(&trdata, rdata); 509 if (n == 0) { 510 return true; 511 } 512 if (n > 0) { /* In DNSSEC order. */ 513 break; 514 } 515 dns_rdata_reset(&trdata); 516 } 517 return false; 518 } 519 520 isc_result_t 521 dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab, 522 unsigned int reservelen, isc_mem_t *mctx, 523 dns_rdataclass_t rdclass, dns_rdatatype_t type, 524 unsigned int flags, uint32_t maxrrperset, 525 unsigned char **tslabp) { 526 unsigned char *ocurrent = NULL, *ostart = NULL, *ncurrent = NULL; 527 unsigned char *tstart = NULL, *tcurrent = NULL, *data = NULL; 528 unsigned int ocount, ncount, count, olength, tlength, tcount, length; 529 dns_rdata_t ordata = DNS_RDATA_INIT; 530 dns_rdata_t nrdata = DNS_RDATA_INIT; 531 bool added_something = false; 532 unsigned int oadded = 0; 533 unsigned int nadded = 0; 534 unsigned int nncount = 0; 535 #if DNS_RDATASET_FIXED 536 unsigned int oncount; 537 unsigned int norder = 0; 538 unsigned int oorder = 0; 539 unsigned char *offsetbase = NULL; 540 unsigned int *offsettable = NULL; 541 #endif /* if DNS_RDATASET_FIXED */ 542 543 /* 544 * XXX Need parameter to allow "delete rdatasets in nslab" merge, 545 * or perhaps another merge routine for this purpose. 546 */ 547 548 REQUIRE(tslabp != NULL && *tslabp == NULL); 549 REQUIRE(oslab != NULL && nslab != NULL); 550 551 ocurrent = oslab + reservelen; 552 ocount = get_uint16(ocurrent); 553 #if DNS_RDATASET_FIXED 554 ocurrent += (4 * ocount); 555 #endif /* if DNS_RDATASET_FIXED */ 556 ostart = ocurrent; 557 ncurrent = nslab + reservelen; 558 ncount = get_uint16(ncurrent); 559 #if DNS_RDATASET_FIXED 560 ncurrent += (4 * ncount); 561 #endif /* if DNS_RDATASET_FIXED */ 562 INSIST(ocount > 0 && ncount > 0); 563 564 if (maxrrperset > 0 && ocount + ncount > maxrrperset) { 565 return DNS_R_TOOMANYRECORDS; 566 } 567 568 #if DNS_RDATASET_FIXED 569 oncount = ncount; 570 #endif /* if DNS_RDATASET_FIXED */ 571 572 /* 573 * Yes, this is inefficient! 574 */ 575 576 /* 577 * Figure out the length of the old slab's data. 578 */ 579 olength = 0; 580 for (count = 0; count < ocount; count++) { 581 length = get_uint16(ocurrent); 582 #if DNS_RDATASET_FIXED 583 olength += length + 8; 584 ocurrent += length + 2; 585 #else /* if DNS_RDATASET_FIXED */ 586 olength += length + 2; 587 ocurrent += length; 588 #endif /* if DNS_RDATASET_FIXED */ 589 } 590 591 /* 592 * Start figuring out the target length and count. 593 */ 594 tlength = reservelen + 2 + olength; 595 tcount = ocount; 596 597 /* 598 * Add in the length of rdata in the new slab that aren't in 599 * the old slab. 600 */ 601 do { 602 dns_rdata_init(&nrdata); 603 rdata_from_slab(&ncurrent, rdclass, type, &nrdata); 604 if (!rdata_in_slab(oslab, reservelen, rdclass, type, &nrdata)) { 605 /* 606 * This rdata isn't in the old slab. 607 */ 608 #if DNS_RDATASET_FIXED 609 tlength += nrdata.length + 8; 610 #else /* if DNS_RDATASET_FIXED */ 611 tlength += nrdata.length + 2; 612 #endif /* if DNS_RDATASET_FIXED */ 613 if (type == dns_rdatatype_rrsig) { 614 tlength++; 615 } 616 tcount++; 617 nncount++; 618 added_something = true; 619 } 620 ncount--; 621 } while (ncount > 0); 622 ncount = nncount; 623 624 if (((flags & DNS_RDATASLAB_EXACT) != 0) && (tcount != ncount + ocount)) 625 { 626 return DNS_R_NOTEXACT; 627 } 628 629 if (!added_something && (flags & DNS_RDATASLAB_FORCE) == 0) { 630 return DNS_R_UNCHANGED; 631 } 632 633 /* 634 * Ensure that singleton types are actually singletons. 635 */ 636 if (tcount > 1 && dns_rdatatype_issingleton(type)) { 637 /* 638 * We have a singleton type, but there's more than one 639 * RR in the rdataset. 640 */ 641 return DNS_R_SINGLETON; 642 } 643 644 if (tcount > 0xffff) { 645 return ISC_R_NOSPACE; 646 } 647 648 /* 649 * Copy the reserved area from the new slab. 650 */ 651 tstart = isc_mem_get(mctx, tlength); 652 memmove(tstart, nslab, reservelen); 653 tcurrent = tstart + reservelen; 654 #if DNS_RDATASET_FIXED 655 offsetbase = tcurrent; 656 #endif /* if DNS_RDATASET_FIXED */ 657 658 /* 659 * Write the new count. 660 */ 661 *tcurrent++ = (tcount & 0xff00) >> 8; 662 *tcurrent++ = (tcount & 0x00ff); 663 664 #if DNS_RDATASET_FIXED 665 /* 666 * Skip offset table. 667 */ 668 tcurrent += (tcount * 4); 669 670 offsettable = isc_mem_cget(mctx, (ocount + oncount), 671 sizeof(unsigned int)); 672 #endif /* if DNS_RDATASET_FIXED */ 673 674 /* 675 * Merge the two slabs. 676 */ 677 ocurrent = ostart; 678 INSIST(ocount != 0); 679 #if DNS_RDATASET_FIXED 680 oorder = peek_uint16(&ocurrent[2]); 681 INSIST(oorder < ocount); 682 #endif /* if DNS_RDATASET_FIXED */ 683 rdata_from_slab(&ocurrent, rdclass, type, &ordata); 684 685 ncurrent = nslab + reservelen + 2; 686 #if DNS_RDATASET_FIXED 687 ncurrent += (4 * oncount); 688 #endif /* if DNS_RDATASET_FIXED */ 689 690 if (ncount > 0) { 691 do { 692 dns_rdata_reset(&nrdata); 693 #if DNS_RDATASET_FIXED 694 norder = peek_uint16(&ncurrent[2]); 695 696 INSIST(norder < oncount); 697 #endif /* if DNS_RDATASET_FIXED */ 698 rdata_from_slab(&ncurrent, rdclass, type, &nrdata); 699 } while (rdata_in_slab(oslab, reservelen, rdclass, type, 700 &nrdata)); 701 } 702 703 while (oadded < ocount || nadded < ncount) { 704 bool fromold; 705 if (oadded == ocount) { 706 fromold = false; 707 } else if (nadded == ncount) { 708 fromold = true; 709 } else { 710 fromold = (dns_rdata_compare(&ordata, &nrdata) < 0); 711 } 712 if (fromold) { 713 #if DNS_RDATASET_FIXED 714 offsettable[oorder] = tcurrent - offsetbase; 715 #endif /* if DNS_RDATASET_FIXED */ 716 length = ordata.length; 717 data = ordata.data; 718 if (type == dns_rdatatype_rrsig) { 719 length++; 720 data--; 721 } 722 *tcurrent++ = (length & 0xff00) >> 8; 723 *tcurrent++ = (length & 0x00ff); 724 #if DNS_RDATASET_FIXED 725 tcurrent += 2; /* fill in later */ 726 #endif /* if DNS_RDATASET_FIXED */ 727 memmove(tcurrent, data, length); 728 tcurrent += length; 729 oadded++; 730 if (oadded < ocount) { 731 dns_rdata_reset(&ordata); 732 #if DNS_RDATASET_FIXED 733 oorder = peek_uint16(&ocurrent[2]); 734 INSIST(oorder < ocount); 735 #endif /* if DNS_RDATASET_FIXED */ 736 rdata_from_slab(&ocurrent, rdclass, type, 737 &ordata); 738 } 739 } else { 740 #if DNS_RDATASET_FIXED 741 offsettable[ocount + norder] = tcurrent - offsetbase; 742 #endif /* if DNS_RDATASET_FIXED */ 743 length = nrdata.length; 744 data = nrdata.data; 745 if (type == dns_rdatatype_rrsig) { 746 length++; 747 data--; 748 } 749 *tcurrent++ = (length & 0xff00) >> 8; 750 *tcurrent++ = (length & 0x00ff); 751 #if DNS_RDATASET_FIXED 752 tcurrent += 2; /* fill in later */ 753 #endif /* if DNS_RDATASET_FIXED */ 754 memmove(tcurrent, data, length); 755 tcurrent += length; 756 nadded++; 757 if (nadded < ncount) { 758 do { 759 dns_rdata_reset(&nrdata); 760 #if DNS_RDATASET_FIXED 761 norder = peek_uint16(&ncurrent[2]); 762 INSIST(norder < oncount); 763 #endif /* if DNS_RDATASET_FIXED */ 764 rdata_from_slab(&ncurrent, rdclass, 765 type, &nrdata); 766 } while (rdata_in_slab(oslab, reservelen, 767 rdclass, type, &nrdata)); 768 } 769 } 770 } 771 772 #if DNS_RDATASET_FIXED 773 fillin_offsets(offsetbase, offsettable, ocount + oncount); 774 775 isc_mem_cput(mctx, offsettable, (ocount + oncount), 776 sizeof(unsigned int)); 777 #endif /* if DNS_RDATASET_FIXED */ 778 779 INSIST(tcurrent == tstart + tlength); 780 781 *tslabp = tstart; 782 783 return ISC_R_SUCCESS; 784 } 785 786 isc_result_t 787 dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab, 788 unsigned int reservelen, isc_mem_t *mctx, 789 dns_rdataclass_t rdclass, dns_rdatatype_t type, 790 unsigned int flags, unsigned char **tslabp) { 791 unsigned char *mcurrent = NULL, *sstart = NULL, *scurrent = NULL; 792 unsigned char *tstart = NULL, *tcurrent = NULL; 793 unsigned int mcount, scount, rcount, count, tlength, tcount, i; 794 dns_rdata_t srdata = DNS_RDATA_INIT; 795 dns_rdata_t mrdata = DNS_RDATA_INIT; 796 #if DNS_RDATASET_FIXED 797 unsigned char *offsetbase = NULL; 798 unsigned int *offsettable = NULL; 799 unsigned int order; 800 #endif /* if DNS_RDATASET_FIXED */ 801 802 REQUIRE(tslabp != NULL && *tslabp == NULL); 803 REQUIRE(mslab != NULL && sslab != NULL); 804 805 mcurrent = mslab + reservelen; 806 mcount = get_uint16(mcurrent); 807 scurrent = sslab + reservelen; 808 scount = get_uint16(scurrent); 809 INSIST(mcount > 0 && scount > 0); 810 811 /* 812 * Yes, this is inefficient! 813 */ 814 815 /* 816 * Start figuring out the target length and count. 817 */ 818 tlength = reservelen + 2; 819 tcount = 0; 820 rcount = 0; 821 822 #if DNS_RDATASET_FIXED 823 mcurrent += 4 * mcount; 824 scurrent += 4 * scount; 825 #endif /* if DNS_RDATASET_FIXED */ 826 sstart = scurrent; 827 828 /* 829 * Add in the length of rdata in the mslab that aren't in 830 * the sslab. 831 */ 832 for (i = 0; i < mcount; i++) { 833 unsigned char *mrdatabegin = mcurrent; 834 rdata_from_slab(&mcurrent, rdclass, type, &mrdata); 835 scurrent = sstart; 836 for (count = 0; count < scount; count++) { 837 dns_rdata_reset(&srdata); 838 rdata_from_slab(&scurrent, rdclass, type, &srdata); 839 if (dns_rdata_compare(&mrdata, &srdata) == 0) { 840 break; 841 } 842 } 843 if (count == scount) { 844 /* 845 * This rdata isn't in the sslab, and thus isn't 846 * being subtracted. 847 */ 848 tlength += (unsigned int)(mcurrent - mrdatabegin); 849 tcount++; 850 } else { 851 rcount++; 852 } 853 dns_rdata_reset(&mrdata); 854 } 855 856 #if DNS_RDATASET_FIXED 857 tlength += (4 * tcount); 858 #endif /* if DNS_RDATASET_FIXED */ 859 860 /* 861 * Check that all the records originally existed. The numeric 862 * check only works as rdataslabs do not contain duplicates. 863 */ 864 if (((flags & DNS_RDATASLAB_EXACT) != 0) && (rcount != scount)) { 865 return DNS_R_NOTEXACT; 866 } 867 868 /* 869 * Don't continue if the new rdataslab would be empty. 870 */ 871 if (tcount == 0) { 872 return DNS_R_NXRRSET; 873 } 874 875 /* 876 * If nothing is going to change, we can stop. 877 */ 878 if (rcount == 0) { 879 return DNS_R_UNCHANGED; 880 } 881 882 /* 883 * Copy the reserved area from the mslab. 884 */ 885 tstart = isc_mem_get(mctx, tlength); 886 memmove(tstart, mslab, reservelen); 887 tcurrent = tstart + reservelen; 888 #if DNS_RDATASET_FIXED 889 offsetbase = tcurrent; 890 891 offsettable = isc_mem_cget(mctx, mcount, sizeof(unsigned int)); 892 #endif /* if DNS_RDATASET_FIXED */ 893 894 /* 895 * Write the new count. 896 */ 897 *tcurrent++ = (tcount & 0xff00) >> 8; 898 *tcurrent++ = (tcount & 0x00ff); 899 900 #if DNS_RDATASET_FIXED 901 tcurrent += (4 * tcount); 902 #endif /* if DNS_RDATASET_FIXED */ 903 904 /* 905 * Copy the parts of mslab not in sslab. 906 */ 907 mcurrent = mslab + reservelen; 908 mcount = get_uint16(mcurrent); 909 #if DNS_RDATASET_FIXED 910 mcurrent += (4 * mcount); 911 #endif /* if DNS_RDATASET_FIXED */ 912 for (i = 0; i < mcount; i++) { 913 unsigned char *mrdatabegin = mcurrent; 914 #if DNS_RDATASET_FIXED 915 order = peek_uint16(&mcurrent[2]); 916 INSIST(order < mcount); 917 #endif /* if DNS_RDATASET_FIXED */ 918 rdata_from_slab(&mcurrent, rdclass, type, &mrdata); 919 scurrent = sstart; 920 for (count = 0; count < scount; count++) { 921 dns_rdata_reset(&srdata); 922 rdata_from_slab(&scurrent, rdclass, type, &srdata); 923 if (dns_rdata_compare(&mrdata, &srdata) == 0) { 924 break; 925 } 926 } 927 if (count == scount) { 928 /* 929 * This rdata isn't in the sslab, and thus should be 930 * copied to the tslab. 931 */ 932 unsigned int length; 933 length = (unsigned int)(mcurrent - mrdatabegin); 934 #if DNS_RDATASET_FIXED 935 offsettable[order] = tcurrent - offsetbase; 936 #endif /* if DNS_RDATASET_FIXED */ 937 memmove(tcurrent, mrdatabegin, length); 938 tcurrent += length; 939 } 940 dns_rdata_reset(&mrdata); 941 } 942 943 #if DNS_RDATASET_FIXED 944 fillin_offsets(offsetbase, offsettable, mcount); 945 946 isc_mem_cput(mctx, offsettable, mcount, sizeof(unsigned int)); 947 #endif /* if DNS_RDATASET_FIXED */ 948 949 INSIST(tcurrent == tstart + tlength); 950 951 *tslabp = tstart; 952 953 return ISC_R_SUCCESS; 954 } 955 956 bool 957 dns_rdataslab_equal(unsigned char *slab1, unsigned char *slab2, 958 unsigned int reservelen) { 959 unsigned char *current1 = NULL, *current2 = NULL; 960 unsigned int count1, count2; 961 unsigned int length1, length2; 962 963 current1 = slab1 + reservelen; 964 count1 = get_uint16(current1); 965 966 current2 = slab2 + reservelen; 967 count2 = get_uint16(current2); 968 969 if (count1 != count2) { 970 return false; 971 } 972 973 #if DNS_RDATASET_FIXED 974 current1 += (4 * count1); 975 current2 += (4 * count2); 976 #endif /* if DNS_RDATASET_FIXED */ 977 978 while (count1-- > 0) { 979 length1 = get_uint16(current1); 980 length2 = get_uint16(current2); 981 982 #if DNS_RDATASET_FIXED 983 current1 += 2; 984 current2 += 2; 985 #endif /* if DNS_RDATASET_FIXED */ 986 987 if (length1 != length2 || 988 memcmp(current1, current2, length1) != 0) 989 { 990 return false; 991 } 992 993 current1 += length1; 994 current2 += length1; 995 } 996 return true; 997 } 998 999 bool 1000 dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2, 1001 unsigned int reservelen, dns_rdataclass_t rdclass, 1002 dns_rdatatype_t type) { 1003 unsigned char *current1 = NULL, *current2 = NULL; 1004 unsigned int count1, count2; 1005 dns_rdata_t rdata1 = DNS_RDATA_INIT; 1006 dns_rdata_t rdata2 = DNS_RDATA_INIT; 1007 1008 current1 = slab1 + reservelen; 1009 count1 = get_uint16(current1); 1010 1011 current2 = slab2 + reservelen; 1012 count2 = get_uint16(current2); 1013 1014 if (count1 != count2) { 1015 return false; 1016 } 1017 1018 #if DNS_RDATASET_FIXED 1019 current1 += (4 * count1); 1020 current2 += (4 * count2); 1021 #endif /* if DNS_RDATASET_FIXED */ 1022 1023 while (count1-- > 0) { 1024 rdata_from_slab(¤t1, rdclass, type, &rdata1); 1025 rdata_from_slab(¤t2, rdclass, type, &rdata2); 1026 if (dns_rdata_compare(&rdata1, &rdata2) != 0) { 1027 return false; 1028 } 1029 dns_rdata_reset(&rdata1); 1030 dns_rdata_reset(&rdata2); 1031 } 1032 return true; 1033 } 1034 1035 dns_slabheader_t * 1036 dns_slabheader_fromrdataset(const dns_rdataset_t *rdataset) { 1037 dns_slabheader_t *header = (dns_slabheader_t *)rdataset->slab.raw; 1038 return header - 1; 1039 } 1040 1041 void * 1042 dns_slabheader_raw(dns_slabheader_t *header) { 1043 return header + 1; 1044 } 1045 1046 void 1047 dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name) { 1048 unsigned int i; 1049 bool fully_lower; 1050 1051 /* 1052 * We do not need to worry about label lengths as they are all 1053 * less than or equal to 63. 1054 */ 1055 memset(header->upper, 0, sizeof(header->upper)); 1056 fully_lower = true; 1057 for (i = 0; i < name->length; i++) { 1058 if (isupper(name->ndata[i])) { 1059 header->upper[i / 8] |= 1 << (i % 8); 1060 fully_lower = false; 1061 } 1062 } 1063 DNS_SLABHEADER_SETATTR(header, DNS_SLABHEADERATTR_CASESET); 1064 if (fully_lower) { 1065 DNS_SLABHEADER_SETATTR(header, 1066 DNS_SLABHEADERATTR_CASEFULLYLOWER); 1067 } 1068 } 1069 1070 void 1071 dns_slabheader_copycase(dns_slabheader_t *dest, dns_slabheader_t *src) { 1072 if (CASESET(src)) { 1073 uint_least16_t attr = DNS_SLABHEADER_GETATTR( 1074 src, (DNS_SLABHEADERATTR_CASESET | 1075 DNS_SLABHEADERATTR_CASEFULLYLOWER)); 1076 DNS_SLABHEADER_SETATTR(dest, attr); 1077 memmove(dest->upper, src->upper, sizeof(src->upper)); 1078 } 1079 } 1080 1081 void 1082 dns_slabheader_reset(dns_slabheader_t *h, dns_db_t *db, dns_dbnode_t *node) { 1083 ISC_LINK_INIT(h, link); 1084 h->heap_index = 0; 1085 h->heap = NULL; 1086 h->db = db; 1087 h->node = node; 1088 1089 atomic_init(&h->attributes, 0); 1090 atomic_init(&h->last_refresh_fail_ts, 0); 1091 1092 STATIC_ASSERT((sizeof(h->attributes) == 2), 1093 "The .attributes field of dns_slabheader_t needs to be " 1094 "16-bit int type exactly."); 1095 } 1096 1097 dns_slabheader_t * 1098 dns_slabheader_new(dns_db_t *db, dns_dbnode_t *node) { 1099 dns_slabheader_t *h = NULL; 1100 1101 h = isc_mem_get(db->mctx, sizeof(*h)); 1102 *h = (dns_slabheader_t){ 1103 .link = ISC_LINK_INITIALIZER, 1104 }; 1105 dns_slabheader_reset(h, db, node); 1106 return h; 1107 } 1108 1109 void 1110 dns_slabheader_destroy(dns_slabheader_t **headerp) { 1111 unsigned int size; 1112 dns_slabheader_t *header = *headerp; 1113 1114 *headerp = NULL; 1115 1116 isc_mem_t *mctx = header->db->mctx; 1117 1118 dns_db_deletedata(header->db, header->node, header); 1119 1120 if (NONEXISTENT(header)) { 1121 size = sizeof(*header); 1122 } else { 1123 size = dns_rdataslab_size((unsigned char *)header, 1124 sizeof(*header)); 1125 } 1126 1127 isc_mem_put(mctx, header, size); 1128 } 1129 1130 void 1131 dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proof) { 1132 if (dns_name_dynamic(&(*proof)->name)) { 1133 dns_name_free(&(*proof)->name, mctx); 1134 } 1135 if ((*proof)->neg != NULL) { 1136 isc_mem_put(mctx, (*proof)->neg, 1137 dns_rdataslab_size((*proof)->neg, 0)); 1138 } 1139 if ((*proof)->negsig != NULL) { 1140 isc_mem_put(mctx, (*proof)->negsig, 1141 dns_rdataslab_size((*proof)->negsig, 0)); 1142 } 1143 isc_mem_put(mctx, *proof, sizeof(**proof)); 1144 *proof = NULL; 1145 } 1146 1147 dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods = { 1148 .disassociate = rdataset_disassociate, 1149 .first = rdataset_first, 1150 .next = rdataset_next, 1151 .current = rdataset_current, 1152 .clone = rdataset_clone, 1153 .count = rdataset_count, 1154 .getnoqname = rdataset_getnoqname, 1155 .getclosest = rdataset_getclosest, 1156 .settrust = rdataset_settrust, 1157 .expire = rdataset_expire, 1158 .clearprefetch = rdataset_clearprefetch, 1159 .setownercase = rdataset_setownercase, 1160 .getownercase = rdataset_getownercase, 1161 }; 1162 1163 /* Fixed RRSet helper macros */ 1164 1165 #define DNS_RDATASET_LENGTH 2; 1166 1167 #if DNS_RDATASET_FIXED 1168 #define DNS_RDATASET_ORDER 2 1169 #define DNS_RDATASET_COUNT (count * 4) 1170 #else /* !DNS_RDATASET_FIXED */ 1171 #define DNS_RDATASET_ORDER 0 1172 #define DNS_RDATASET_COUNT 0 1173 #endif /* DNS_RDATASET_FIXED */ 1174 1175 static void 1176 rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) { 1177 dns_db_t *db = rdataset->slab.db; 1178 dns_dbnode_t *node = rdataset->slab.node; 1179 1180 dns__db_detachnode(db, &node DNS__DB_FLARG_PASS); 1181 } 1182 1183 static isc_result_t 1184 rdataset_first(dns_rdataset_t *rdataset) { 1185 unsigned char *raw = rdataset->slab.raw; 1186 uint16_t count = peek_uint16(raw); 1187 if (count == 0) { 1188 rdataset->slab.iter_pos = NULL; 1189 rdataset->slab.iter_count = 0; 1190 return ISC_R_NOMORE; 1191 } 1192 1193 if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0) { 1194 raw += DNS_RDATASET_COUNT; 1195 } 1196 1197 /* 1198 * iter_count is the number of rdata beyond the cursor 1199 * position, so we decrement the total count by one before 1200 * storing it. 1201 * 1202 * If DNS_RDATASETATTR_LOADORDER is not set 'raw' points to the 1203 * first record. If DNS_RDATASETATTR_LOADORDER is set 'raw' points 1204 * to the first entry in the offset table. 1205 */ 1206 rdataset->slab.iter_pos = raw + DNS_RDATASET_LENGTH; 1207 rdataset->slab.iter_count = count - 1; 1208 1209 return ISC_R_SUCCESS; 1210 } 1211 1212 static isc_result_t 1213 rdataset_next(dns_rdataset_t *rdataset) { 1214 uint16_t count = rdataset->slab.iter_count; 1215 if (count == 0) { 1216 rdataset->slab.iter_pos = NULL; 1217 return ISC_R_NOMORE; 1218 } 1219 rdataset->slab.iter_count = count - 1; 1220 1221 /* 1222 * Skip forward one record (length + 4) or one offset (4). 1223 */ 1224 unsigned char *raw = rdataset->slab.iter_pos; 1225 #if DNS_RDATASET_FIXED 1226 if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) == 0) 1227 #endif /* DNS_RDATASET_FIXED */ 1228 { 1229 uint16_t length = peek_uint16(raw); 1230 raw += length; 1231 } 1232 rdataset->slab.iter_pos = raw + DNS_RDATASET_ORDER + 1233 DNS_RDATASET_LENGTH; 1234 1235 return ISC_R_SUCCESS; 1236 } 1237 1238 static void 1239 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { 1240 unsigned char *raw = NULL; 1241 unsigned int length; 1242 isc_region_t r; 1243 unsigned int flags = 0; 1244 1245 raw = rdataset->slab.iter_pos; 1246 REQUIRE(raw != NULL); 1247 1248 /* 1249 * Find the start of the record if not already in iter_pos 1250 * then skip the length and order fields. 1251 */ 1252 #if DNS_RDATASET_FIXED 1253 if ((rdataset->attributes & DNS_RDATASETATTR_LOADORDER) != 0) { 1254 unsigned int offset; 1255 offset = ((unsigned int)raw[0] << 24) + 1256 ((unsigned int)raw[1] << 16) + 1257 ((unsigned int)raw[2] << 8) + (unsigned int)raw[3]; 1258 raw = rdataset->slab.raw + offset; 1259 } 1260 #endif /* if DNS_RDATASET_FIXED */ 1261 1262 length = peek_uint16(raw); 1263 1264 raw += DNS_RDATASET_ORDER + DNS_RDATASET_LENGTH; 1265 1266 if (rdataset->type == dns_rdatatype_rrsig) { 1267 if (*raw & DNS_RDATASLAB_OFFLINE) { 1268 flags |= DNS_RDATA_OFFLINE; 1269 } 1270 length--; 1271 raw++; 1272 } 1273 r.length = length; 1274 r.base = raw; 1275 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r); 1276 rdata->flags |= flags; 1277 } 1278 1279 static void 1280 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) { 1281 dns_db_t *db = source->slab.db; 1282 dns_dbnode_t *node = source->slab.node; 1283 dns_dbnode_t *cloned_node = NULL; 1284 1285 dns__db_attachnode(db, node, &cloned_node DNS__DB_FLARG_PASS); 1286 INSIST(!ISC_LINK_LINKED(target, link)); 1287 *target = *source; 1288 ISC_LINK_INIT(target, link); 1289 1290 target->slab.iter_pos = NULL; 1291 target->slab.iter_count = 0; 1292 } 1293 1294 static unsigned int 1295 rdataset_count(dns_rdataset_t *rdataset) { 1296 unsigned char *raw = NULL; 1297 unsigned int count; 1298 1299 raw = rdataset->slab.raw; 1300 count = get_uint16(raw); 1301 1302 return count; 1303 } 1304 1305 static isc_result_t 1306 rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, 1307 dns_rdataset_t *nsec, 1308 dns_rdataset_t *nsecsig DNS__DB_FLARG) { 1309 dns_db_t *db = rdataset->slab.db; 1310 dns_dbnode_t *node = rdataset->slab.node; 1311 const dns_slabheader_proof_t *noqname = rdataset->slab.noqname; 1312 1313 /* 1314 * Usually, rdataset->slab.raw refers the data following a 1315 * dns_slabheader, but in this case it points to a bare 1316 * rdataslab belonging to the dns_slabheader's `noqname` field. 1317 * The DNS_RDATASETATTR_KEEPCASE attribute is set to prevent 1318 * setownercase and getownercase methods from affecting the 1319 * case of NSEC/NSEC3 owner names. 1320 */ 1321 dns__db_attachnode(db, node, 1322 &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); 1323 *nsec = (dns_rdataset_t){ 1324 .methods = &dns_rdataslab_rdatasetmethods, 1325 .rdclass = db->rdclass, 1326 .type = noqname->type, 1327 .ttl = rdataset->ttl, 1328 .trust = rdataset->trust, 1329 .slab.db = db, 1330 .slab.node = node, 1331 .slab.raw = noqname->neg, 1332 .link = nsec->link, 1333 .count = nsec->count, 1334 .attributes = nsec->attributes | DNS_RDATASETATTR_KEEPCASE, 1335 .magic = nsec->magic, 1336 }; 1337 1338 dns__db_attachnode(db, node, 1339 &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); 1340 *nsecsig = (dns_rdataset_t){ 1341 .methods = &dns_rdataslab_rdatasetmethods, 1342 .rdclass = db->rdclass, 1343 .type = dns_rdatatype_rrsig, 1344 .covers = noqname->type, 1345 .ttl = rdataset->ttl, 1346 .trust = rdataset->trust, 1347 .slab.db = db, 1348 .slab.node = node, 1349 .slab.raw = noqname->negsig, 1350 .link = nsecsig->link, 1351 .count = nsecsig->count, 1352 .attributes = nsecsig->attributes | DNS_RDATASETATTR_KEEPCASE, 1353 .magic = nsecsig->magic, 1354 }; 1355 1356 dns_name_clone(&noqname->name, name); 1357 1358 return ISC_R_SUCCESS; 1359 } 1360 1361 static isc_result_t 1362 rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, 1363 dns_rdataset_t *nsec, 1364 dns_rdataset_t *nsecsig DNS__DB_FLARG) { 1365 dns_db_t *db = rdataset->slab.db; 1366 dns_dbnode_t *node = rdataset->slab.node; 1367 const dns_slabheader_proof_t *closest = rdataset->slab.closest; 1368 1369 /* 1370 * As mentioned above, rdataset->slab.raw usually refers the data 1371 * following an dns_slabheader, but in this case it points to a bare 1372 * rdataslab belonging to the dns_slabheader's `closest` field. 1373 */ 1374 dns__db_attachnode(db, node, 1375 &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); 1376 *nsec = (dns_rdataset_t){ 1377 .methods = &dns_rdataslab_rdatasetmethods, 1378 .rdclass = db->rdclass, 1379 .type = closest->type, 1380 .ttl = rdataset->ttl, 1381 .trust = rdataset->trust, 1382 .slab.db = db, 1383 .slab.node = node, 1384 .slab.raw = closest->neg, 1385 .link = nsec->link, 1386 .count = nsec->count, 1387 .attributes = nsec->attributes | DNS_RDATASETATTR_KEEPCASE, 1388 .magic = nsec->magic, 1389 }; 1390 1391 dns__db_attachnode(db, node, 1392 &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); 1393 *nsecsig = (dns_rdataset_t){ 1394 .methods = &dns_rdataslab_rdatasetmethods, 1395 .rdclass = db->rdclass, 1396 .type = dns_rdatatype_rrsig, 1397 .covers = closest->type, 1398 .ttl = rdataset->ttl, 1399 .trust = rdataset->trust, 1400 .slab.db = db, 1401 .slab.node = node, 1402 .slab.raw = closest->negsig, 1403 .link = nsecsig->link, 1404 .count = nsecsig->count, 1405 .attributes = nsecsig->attributes | DNS_RDATASETATTR_KEEPCASE, 1406 .magic = nsecsig->magic, 1407 }; 1408 1409 dns_name_clone(&closest->name, name); 1410 1411 return ISC_R_SUCCESS; 1412 } 1413 1414 static void 1415 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { 1416 dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset); 1417 1418 dns_db_locknode(header->db, header->node, isc_rwlocktype_write); 1419 header->trust = rdataset->trust = trust; 1420 dns_db_unlocknode(header->db, header->node, isc_rwlocktype_write); 1421 } 1422 1423 static void 1424 rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG) { 1425 dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset); 1426 1427 dns_db_expiredata(header->db, header->node, header); 1428 } 1429 1430 static void 1431 rdataset_clearprefetch(dns_rdataset_t *rdataset) { 1432 dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset); 1433 1434 dns_db_locknode(header->db, header->node, isc_rwlocktype_write); 1435 DNS_SLABHEADER_CLRATTR(header, DNS_SLABHEADERATTR_PREFETCH); 1436 dns_db_unlocknode(header->db, header->node, isc_rwlocktype_write); 1437 } 1438 1439 static void 1440 rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) { 1441 dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset); 1442 1443 dns_db_locknode(header->db, header->node, isc_rwlocktype_write); 1444 dns_slabheader_setownercase(header, name); 1445 dns_db_unlocknode(header->db, header->node, isc_rwlocktype_write); 1446 } 1447 1448 static void 1449 rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { 1450 dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset); 1451 uint8_t mask = (1 << 7); 1452 uint8_t bits = 0; 1453 1454 dns_db_locknode(header->db, header->node, isc_rwlocktype_read); 1455 1456 if (!CASESET(header)) { 1457 goto unlock; 1458 } 1459 1460 if (CASEFULLYLOWER(header)) { 1461 isc_ascii_lowercopy(name->ndata, name->ndata, name->length); 1462 } else { 1463 uint8_t *nd = name->ndata; 1464 for (size_t i = 0; i < name->length; i++) { 1465 if (mask == (1 << 7)) { 1466 bits = header->upper[i / 8]; 1467 mask = 1; 1468 } else { 1469 mask <<= 1; 1470 } 1471 nd[i] = (bits & mask) ? isc_ascii_toupper(nd[i]) 1472 : isc_ascii_tolower(nd[i]); 1473 } 1474 } 1475 1476 unlock: 1477 dns_db_unlocknode(header->db, header->node, isc_rwlocktype_read); 1478 } 1479