/contrib/bind9/lib/dns/rdataslab.c
C | 1109 lines | 760 code | 131 blank | 218 comment | 159 complexity | d7233b701e5ac6b8993f3f61d6a441df MD5 | raw file
1/* 2 * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id$ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <stdlib.h> 25 26#include <isc/mem.h> 27#include <isc/region.h> 28#include <isc/string.h> /* Required for HP/UX (and others?) */ 29#include <isc/util.h> 30 31#include <dns/result.h> 32#include <dns/rdata.h> 33#include <dns/rdataset.h> 34#include <dns/rdataslab.h> 35 36/* 37 * The rdataslab structure allows iteration to occur in both load order 38 * and DNSSEC order. The structure is as follows: 39 * 40 * header (reservelen bytes) 41 * record count (2 bytes) 42 * offset table (4 x record count bytes in load order) 43 * data records 44 * data length (2 bytes) 45 * order (2 bytes) 46 * meta data (1 byte for RRSIG's) 47 * data (data length bytes) 48 * 49 * If DNS_RDATASET_FIXED is defined to be zero (0) the format of a 50 * rdataslab is as follows: 51 * 52 * header (reservelen bytes) 53 * record count (2 bytes) 54 * data records 55 * data length (2 bytes) 56 * meta data (1 byte for RRSIG's) 57 * data (data length bytes) 58 * 59 * Offsets are from the end of the header. 60 * 61 * Load order traversal is performed by walking the offset table to find 62 * the start of the record (DNS_RDATASET_FIXED = 1). 63 * 64 * DNSSEC order traversal is performed by walking the data records. 65 * 66 * The order is stored with record to allow for efficient reconstruction 67 * of the offset table following a merge or subtraction. 68 * 69 * The iterator methods here currently only support DNSSEC order iteration. 70 * 71 * The iterator methods in rbtdb support both load order and DNSSEC order 72 * iteration. 73 * 74 * WARNING: 75 * rbtdb.c directly interacts with the slab's raw structures. If the 76 * structure changes then rbtdb.c also needs to be updated to reflect 77 * the changes. See the areas tagged with "RDATASLAB". 78 */ 79 80struct xrdata { 81 dns_rdata_t rdata; 82 unsigned int order; 83}; 84 85/*% Note: the "const void *" are just to make qsort happy. */ 86static int 87compare_rdata(const void *p1, const void *p2) { 88 const struct xrdata *x1 = p1; 89 const struct xrdata *x2 = p2; 90 return (dns_rdata_compare(&x1->rdata, &x2->rdata)); 91} 92 93#if DNS_RDATASET_FIXED 94static void 95fillin_offsets(unsigned char *offsetbase, unsigned int *offsettable, 96 unsigned length) 97{ 98 unsigned int i, j; 99 unsigned char *raw; 100 101 for (i = 0, j = 0; i < length; i++) { 102 103 if (offsettable[i] == 0) 104 continue; 105 106 /* 107 * Fill in offset table. 108 */ 109 raw = &offsetbase[j*4 + 2]; 110 *raw++ = (offsettable[i] & 0xff000000) >> 24; 111 *raw++ = (offsettable[i] & 0xff0000) >> 16; 112 *raw++ = (offsettable[i] & 0xff00) >> 8; 113 *raw = offsettable[i] & 0xff; 114 115 /* 116 * Fill in table index. 117 */ 118 raw = offsetbase + offsettable[i] + 2; 119 *raw++ = (j & 0xff00) >> 8; 120 *raw = j++ & 0xff; 121 } 122} 123#endif 124 125isc_result_t 126dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, 127 isc_region_t *region, unsigned int reservelen) 128{ 129 /* 130 * Use &removed as a sentinal pointer for duplicate 131 * rdata as rdata.data == NULL is valid. 132 */ 133 static unsigned char removed; 134 struct xrdata *x; 135 unsigned char *rawbuf; 136#if DNS_RDATASET_FIXED 137 unsigned char *offsetbase; 138#endif 139 unsigned int buflen; 140 isc_result_t result; 141 unsigned int nitems; 142 unsigned int nalloc; 143 unsigned int i; 144#if DNS_RDATASET_FIXED 145 unsigned int *offsettable; 146#endif 147 unsigned int length; 148 149 buflen = reservelen + 2; 150 151 nalloc = dns_rdataset_count(rdataset); 152 nitems = nalloc; 153 if (nitems == 0 && rdataset->type != 0) 154 return (ISC_R_FAILURE); 155 156 if (nalloc > 0xffff) 157 return (ISC_R_NOSPACE); 158 159 160 if (nalloc != 0) { 161 x = isc_mem_get(mctx, nalloc * sizeof(struct xrdata)); 162 if (x == NULL) 163 return (ISC_R_NOMEMORY); 164 } else 165 x = NULL; 166 167 /* 168 * Save all of the rdata members into an array. 169 */ 170 result = dns_rdataset_first(rdataset); 171 if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) 172 goto free_rdatas; 173 for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) { 174 INSIST(result == ISC_R_SUCCESS); 175 dns_rdata_init(&x[i].rdata); 176 dns_rdataset_current(rdataset, &x[i].rdata); 177 INSIST(x[i].rdata.data != &removed); 178#if DNS_RDATASET_FIXED 179 x[i].order = i; 180#endif 181 result = dns_rdataset_next(rdataset); 182 } 183 if (result != ISC_R_NOMORE) 184 goto free_rdatas; 185 if (i != nalloc) { 186 /* 187 * Somehow we iterated over fewer rdatas than 188 * dns_rdataset_count() said there were! 189 */ 190 result = ISC_R_FAILURE; 191 goto free_rdatas; 192 } 193 194 /* 195 * Put into DNSSEC order. 196 */ 197 qsort(x, nalloc, sizeof(struct xrdata), compare_rdata); 198 199 /* 200 * Remove duplicates and compute the total storage required. 201 * 202 * If an rdata is not a duplicate, accumulate the storage size 203 * required for the rdata. We do not store the class, type, etc, 204 * just the rdata, so our overhead is 2 bytes for the number of 205 * records, and 8 for each rdata, (length(2), offset(4) and order(2)) 206 * and then the rdata itself. 207 */ 208 for (i = 1; i < nalloc; i++) { 209 if (compare_rdata(&x[i-1].rdata, &x[i].rdata) == 0) { 210 x[i-1].rdata.data = &removed; 211#if DNS_RDATASET_FIXED 212 /* 213 * Preserve the least order so A, B, A -> A, B 214 * after duplicate removal. 215 */ 216 if (x[i-1].order < x[i].order) 217 x[i].order = x[i-1].order; 218#endif 219 nitems--; 220 } else { 221#if DNS_RDATASET_FIXED 222 buflen += (8 + x[i-1].rdata.length); 223#else 224 buflen += (2 + x[i-1].rdata.length); 225#endif 226 /* 227 * Provide space to store the per RR meta data. 228 */ 229 if (rdataset->type == dns_rdatatype_rrsig) 230 buflen++; 231 } 232 } 233 /* 234 * Don't forget the last item! 235 */ 236 if (nalloc != 0) { 237#if DNS_RDATASET_FIXED 238 buflen += (8 + x[i-1].rdata.length); 239#else 240 buflen += (2 + x[i-1].rdata.length); 241#endif 242 } 243 244 /* 245 * Provide space to store the per RR meta data. 246 */ 247 if (rdataset->type == dns_rdatatype_rrsig) 248 buflen++; 249 250 /* 251 * Ensure that singleton types are actually singletons. 252 */ 253 if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) { 254 /* 255 * We have a singleton type, but there's more than one 256 * RR in the rdataset. 257 */ 258 result = DNS_R_SINGLETON; 259 goto free_rdatas; 260 } 261 262 /* 263 * Allocate the memory, set up a buffer, start copying in 264 * data. 265 */ 266 rawbuf = isc_mem_get(mctx, buflen); 267 if (rawbuf == NULL) { 268 result = ISC_R_NOMEMORY; 269 goto free_rdatas; 270 } 271 272#if DNS_RDATASET_FIXED 273 /* Allocate temporary offset table. */ 274 offsettable = isc_mem_get(mctx, nalloc * sizeof(unsigned int)); 275 if (offsettable == NULL) { 276 isc_mem_put(mctx, rawbuf, buflen); 277 result = ISC_R_NOMEMORY; 278 goto free_rdatas; 279 } 280 memset(offsettable, 0, nalloc * sizeof(unsigned int)); 281#endif 282 283 region->base = rawbuf; 284 region->length = buflen; 285 286 rawbuf += reservelen; 287#if DNS_RDATASET_FIXED 288 offsetbase = rawbuf; 289#endif 290 291 *rawbuf++ = (nitems & 0xff00) >> 8; 292 *rawbuf++ = (nitems & 0x00ff); 293 294#if DNS_RDATASET_FIXED 295 /* Skip load order table. Filled in later. */ 296 rawbuf += nitems * 4; 297#endif 298 299 for (i = 0; i < nalloc; i++) { 300 if (x[i].rdata.data == &removed) 301 continue; 302#if DNS_RDATASET_FIXED 303 offsettable[x[i].order] = rawbuf - offsetbase; 304#endif 305 length = x[i].rdata.length; 306 if (rdataset->type == dns_rdatatype_rrsig) 307 length++; 308 INSIST(length <= 0xffff); 309 *rawbuf++ = (length & 0xff00) >> 8; 310 *rawbuf++ = (length & 0x00ff); 311#if DNS_RDATASET_FIXED 312 rawbuf += 2; /* filled in later */ 313#endif 314 /* 315 * Store the per RR meta data. 316 */ 317 if (rdataset->type == dns_rdatatype_rrsig) { 318 *rawbuf++ |= (x[i].rdata.flags & DNS_RDATA_OFFLINE) ? 319 DNS_RDATASLAB_OFFLINE : 0; 320 } 321 memcpy(rawbuf, x[i].rdata.data, x[i].rdata.length); 322 rawbuf += x[i].rdata.length; 323 } 324 325#if DNS_RDATASET_FIXED 326 fillin_offsets(offsetbase, offsettable, nalloc); 327 isc_mem_put(mctx, offsettable, nalloc * sizeof(unsigned int)); 328#endif 329 330 result = ISC_R_SUCCESS; 331 332 free_rdatas: 333 if (x != NULL) 334 isc_mem_put(mctx, x, nalloc * sizeof(struct xrdata)); 335 return (result); 336} 337 338static void 339rdataset_disassociate(dns_rdataset_t *rdataset) { 340 UNUSED(rdataset); 341} 342 343static isc_result_t 344rdataset_first(dns_rdataset_t *rdataset) { 345 unsigned char *raw = rdataset->private3; 346 unsigned int count; 347 348 count = raw[0] * 256 + raw[1]; 349 if (count == 0) { 350 rdataset->private5 = NULL; 351 return (ISC_R_NOMORE); 352 } 353#if DNS_RDATASET_FIXED 354 raw += 2 + (4 * count); 355#else 356 raw += 2; 357#endif 358 /* 359 * The privateuint4 field is the number of rdata beyond the cursor 360 * position, so we decrement the total count by one before storing 361 * it. 362 */ 363 count--; 364 rdataset->privateuint4 = count; 365 rdataset->private5 = raw; 366 367 return (ISC_R_SUCCESS); 368} 369 370static isc_result_t 371rdataset_next(dns_rdataset_t *rdataset) { 372 unsigned int count; 373 unsigned int length; 374 unsigned char *raw; 375 376 count = rdataset->privateuint4; 377 if (count == 0) 378 return (ISC_R_NOMORE); 379 count--; 380 rdataset->privateuint4 = count; 381 raw = rdataset->private5; 382 length = raw[0] * 256 + raw[1]; 383#if DNS_RDATASET_FIXED 384 raw += length + 4; 385#else 386 raw += length + 2; 387#endif 388 rdataset->private5 = raw; 389 390 return (ISC_R_SUCCESS); 391} 392 393static void 394rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { 395 unsigned char *raw = rdataset->private5; 396 isc_region_t r; 397 unsigned int length; 398 unsigned int flags = 0; 399 400 REQUIRE(raw != NULL); 401 402 length = raw[0] * 256 + raw[1]; 403#if DNS_RDATASET_FIXED 404 raw += 4; 405#else 406 raw += 2; 407#endif 408 if (rdataset->type == dns_rdatatype_rrsig) { 409 if (*raw & DNS_RDATASLAB_OFFLINE) 410 flags |= DNS_RDATA_OFFLINE; 411 length--; 412 raw++; 413 } 414 r.length = length; 415 r.base = raw; 416 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r); 417 rdata->flags |= flags; 418} 419 420static void 421rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) { 422 *target = *source; 423 424 /* 425 * Reset iterator state. 426 */ 427 target->privateuint4 = 0; 428 target->private5 = NULL; 429} 430 431static unsigned int 432rdataset_count(dns_rdataset_t *rdataset) { 433 unsigned char *raw = rdataset->private3; 434 unsigned int count; 435 436 count = raw[0] * 256 + raw[1]; 437 438 return (count); 439} 440 441static dns_rdatasetmethods_t rdataset_methods = { 442 rdataset_disassociate, 443 rdataset_first, 444 rdataset_next, 445 rdataset_current, 446 rdataset_clone, 447 rdataset_count, 448 NULL, 449 NULL, 450 NULL, 451 NULL, 452 NULL, 453 NULL, 454 NULL, 455 NULL, 456 NULL 457}; 458 459void 460dns_rdataslab_tordataset(unsigned char *slab, unsigned int reservelen, 461 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype, 462 dns_rdatatype_t covers, dns_ttl_t ttl, 463 dns_rdataset_t *rdataset) 464{ 465 REQUIRE(slab != NULL); 466 REQUIRE(!dns_rdataset_isassociated(rdataset)); 467 468 rdataset->methods = &rdataset_methods; 469 rdataset->rdclass = rdclass; 470 rdataset->type = rdtype; 471 rdataset->covers = covers; 472 rdataset->ttl = ttl; 473 rdataset->trust = 0; 474 rdataset->private1 = NULL; 475 rdataset->private2 = NULL; 476 rdataset->private3 = slab + reservelen; 477 478 /* 479 * Reset iterator state. 480 */ 481 rdataset->privateuint4 = 0; 482 rdataset->private5 = NULL; 483} 484 485unsigned int 486dns_rdataslab_size(unsigned char *slab, unsigned int reservelen) { 487 unsigned int count, length; 488 unsigned char *current; 489 490 REQUIRE(slab != NULL); 491 492 current = slab + reservelen; 493 count = *current++ * 256; 494 count += *current++; 495#if DNS_RDATASET_FIXED 496 current += (4 * count); 497#endif 498 while (count > 0) { 499 count--; 500 length = *current++ * 256; 501 length += *current++; 502#if DNS_RDATASET_FIXED 503 current += length + 2; 504#else 505 current += length; 506#endif 507 } 508 509 return ((unsigned int)(current - slab)); 510} 511 512/* 513 * Make the dns_rdata_t 'rdata' refer to the slab item 514 * beginning at '*current', which is part of a slab of type 515 * 'type' and class 'rdclass', and advance '*current' to 516 * point to the next item in the slab. 517 */ 518static inline void 519rdata_from_slab(unsigned char **current, 520 dns_rdataclass_t rdclass, dns_rdatatype_t type, 521 dns_rdata_t *rdata) 522{ 523 unsigned char *tcurrent = *current; 524 isc_region_t region; 525 unsigned int length; 526 isc_boolean_t offline = ISC_FALSE; 527 528 length = *tcurrent++ * 256; 529 length += *tcurrent++; 530 531 if (type == dns_rdatatype_rrsig) { 532 if ((*tcurrent & DNS_RDATASLAB_OFFLINE) != 0) 533 offline = ISC_TRUE; 534 length--; 535 tcurrent++; 536 } 537 region.length = length; 538#if DNS_RDATASET_FIXED 539 tcurrent += 2; 540#endif 541 region.base = tcurrent; 542 tcurrent += region.length; 543 dns_rdata_fromregion(rdata, rdclass, type, ®ion); 544 if (offline) 545 rdata->flags |= DNS_RDATA_OFFLINE; 546 *current = tcurrent; 547} 548 549/* 550 * Return true iff 'slab' (slab data of type 'type' and class 'rdclass') 551 * contains an rdata identical to 'rdata'. This does case insensitive 552 * comparisons per DNSSEC. 553 */ 554static inline isc_boolean_t 555rdata_in_slab(unsigned char *slab, unsigned int reservelen, 556 dns_rdataclass_t rdclass, dns_rdatatype_t type, 557 dns_rdata_t *rdata) 558{ 559 unsigned int count, i; 560 unsigned char *current; 561 dns_rdata_t trdata = DNS_RDATA_INIT; 562 int n; 563 564 current = slab + reservelen; 565 count = *current++ * 256; 566 count += *current++; 567 568#if DNS_RDATASET_FIXED 569 current += (4 * count); 570#endif 571 572 for (i = 0; i < count; i++) { 573 rdata_from_slab(¤t, rdclass, type, &trdata); 574 575 n = dns_rdata_compare(&trdata, rdata); 576 if (n == 0) 577 return (ISC_TRUE); 578 if (n > 0) /* In DNSSEC order. */ 579 break; 580 dns_rdata_reset(&trdata); 581 } 582 return (ISC_FALSE); 583} 584 585isc_result_t 586dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab, 587 unsigned int reservelen, isc_mem_t *mctx, 588 dns_rdataclass_t rdclass, dns_rdatatype_t type, 589 unsigned int flags, unsigned char **tslabp) 590{ 591 unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent, *data; 592 unsigned int ocount, ncount, count, olength, tlength, tcount, length; 593 dns_rdata_t ordata = DNS_RDATA_INIT; 594 dns_rdata_t nrdata = DNS_RDATA_INIT; 595 isc_boolean_t added_something = ISC_FALSE; 596 unsigned int oadded = 0; 597 unsigned int nadded = 0; 598 unsigned int nncount = 0; 599#if DNS_RDATASET_FIXED 600 unsigned int oncount; 601 unsigned int norder = 0; 602 unsigned int oorder = 0; 603 unsigned char *offsetbase; 604 unsigned int *offsettable; 605#endif 606 607 /* 608 * XXX Need parameter to allow "delete rdatasets in nslab" merge, 609 * or perhaps another merge routine for this purpose. 610 */ 611 612 REQUIRE(tslabp != NULL && *tslabp == NULL); 613 REQUIRE(oslab != NULL && nslab != NULL); 614 615 ocurrent = oslab + reservelen; 616 ocount = *ocurrent++ * 256; 617 ocount += *ocurrent++; 618#if DNS_RDATASET_FIXED 619 ocurrent += (4 * ocount); 620#endif 621 ostart = ocurrent; 622 ncurrent = nslab + reservelen; 623 ncount = *ncurrent++ * 256; 624 ncount += *ncurrent++; 625#if DNS_RDATASET_FIXED 626 ncurrent += (4 * ncount); 627#endif 628 INSIST(ocount > 0 && ncount > 0); 629 630#if DNS_RDATASET_FIXED 631 oncount = ncount; 632#endif 633 634 /* 635 * Yes, this is inefficient! 636 */ 637 638 /* 639 * Figure out the length of the old slab's data. 640 */ 641 olength = 0; 642 for (count = 0; count < ocount; count++) { 643 length = *ocurrent++ * 256; 644 length += *ocurrent++; 645#if DNS_RDATASET_FIXED 646 olength += length + 8; 647 ocurrent += length + 2; 648#else 649 olength += length + 2; 650 ocurrent += length; 651#endif 652 } 653 654 /* 655 * Start figuring out the target length and count. 656 */ 657 tlength = reservelen + 2 + olength; 658 tcount = ocount; 659 660 /* 661 * Add in the length of rdata in the new slab that aren't in 662 * the old slab. 663 */ 664 do { 665 dns_rdata_init(&nrdata); 666 rdata_from_slab(&ncurrent, rdclass, type, &nrdata); 667 if (!rdata_in_slab(oslab, reservelen, rdclass, type, &nrdata)) 668 { 669 /* 670 * This rdata isn't in the old slab. 671 */ 672#if DNS_RDATASET_FIXED 673 tlength += nrdata.length + 8; 674#else 675 tlength += nrdata.length + 2; 676#endif 677 if (type == dns_rdatatype_rrsig) 678 tlength++; 679 tcount++; 680 nncount++; 681 added_something = ISC_TRUE; 682 } 683 ncount--; 684 } while (ncount > 0); 685 ncount = nncount; 686 687 if (((flags & DNS_RDATASLAB_EXACT) != 0) && 688 (tcount != ncount + ocount)) 689 return (DNS_R_NOTEXACT); 690 691 if (!added_something && (flags & DNS_RDATASLAB_FORCE) == 0) 692 return (DNS_R_UNCHANGED); 693 694 /* 695 * Ensure that singleton types are actually singletons. 696 */ 697 if (tcount > 1 && dns_rdatatype_issingleton(type)) { 698 /* 699 * We have a singleton type, but there's more than one 700 * RR in the rdataset. 701 */ 702 return (DNS_R_SINGLETON); 703 } 704 705 if (tcount > 0xffff) 706 return (ISC_R_NOSPACE); 707 708 /* 709 * Copy the reserved area from the new slab. 710 */ 711 tstart = isc_mem_get(mctx, tlength); 712 if (tstart == NULL) 713 return (ISC_R_NOMEMORY); 714 memcpy(tstart, nslab, reservelen); 715 tcurrent = tstart + reservelen; 716#if DNS_RDATASET_FIXED 717 offsetbase = tcurrent; 718#endif 719 720 /* 721 * Write the new count. 722 */ 723 *tcurrent++ = (tcount & 0xff00) >> 8; 724 *tcurrent++ = (tcount & 0x00ff); 725 726#if DNS_RDATASET_FIXED 727 /* 728 * Skip offset table. 729 */ 730 tcurrent += (tcount * 4); 731 732 offsettable = isc_mem_get(mctx, 733 (ocount + oncount) * sizeof(unsigned int)); 734 if (offsettable == NULL) { 735 isc_mem_put(mctx, tstart, tlength); 736 return (ISC_R_NOMEMORY); 737 } 738 memset(offsettable, 0, (ocount + oncount) * sizeof(unsigned int)); 739#endif 740 741 /* 742 * Merge the two slabs. 743 */ 744 ocurrent = ostart; 745 INSIST(ocount != 0); 746#if DNS_RDATASET_FIXED 747 oorder = ocurrent[2] * 256 + ocurrent[3]; 748 INSIST(oorder < ocount); 749#endif 750 rdata_from_slab(&ocurrent, rdclass, type, &ordata); 751 752 ncurrent = nslab + reservelen + 2; 753#if DNS_RDATASET_FIXED 754 ncurrent += (4 * oncount); 755#endif 756 757 if (ncount > 0) { 758 do { 759 dns_rdata_reset(&nrdata); 760#if DNS_RDATASET_FIXED 761 norder = ncurrent[2] * 256 + ncurrent[3]; 762 763 INSIST(norder < oncount); 764#endif 765 rdata_from_slab(&ncurrent, rdclass, type, &nrdata); 766 } while (rdata_in_slab(oslab, reservelen, rdclass, 767 type, &nrdata)); 768 } 769 770 while (oadded < ocount || nadded < ncount) { 771 isc_boolean_t fromold; 772 if (oadded == ocount) 773 fromold = ISC_FALSE; 774 else if (nadded == ncount) 775 fromold = ISC_TRUE; 776 else 777 fromold = ISC_TF(compare_rdata(&ordata, &nrdata) < 0); 778 if (fromold) { 779#if DNS_RDATASET_FIXED 780 offsettable[oorder] = tcurrent - offsetbase; 781#endif 782 length = ordata.length; 783 data = ordata.data; 784 if (type == dns_rdatatype_rrsig) { 785 length++; 786 data--; 787 } 788 *tcurrent++ = (length & 0xff00) >> 8; 789 *tcurrent++ = (length & 0x00ff); 790#if DNS_RDATASET_FIXED 791 tcurrent += 2; /* fill in later */ 792#endif 793 memcpy(tcurrent, data, length); 794 tcurrent += length; 795 oadded++; 796 if (oadded < ocount) { 797 dns_rdata_reset(&ordata); 798#if DNS_RDATASET_FIXED 799 oorder = ocurrent[2] * 256 + ocurrent[3]; 800 INSIST(oorder < ocount); 801#endif 802 rdata_from_slab(&ocurrent, rdclass, type, 803 &ordata); 804 } 805 } else { 806#if DNS_RDATASET_FIXED 807 offsettable[ocount + norder] = tcurrent - offsetbase; 808#endif 809 length = nrdata.length; 810 data = nrdata.data; 811 if (type == dns_rdatatype_rrsig) { 812 length++; 813 data--; 814 } 815 *tcurrent++ = (length & 0xff00) >> 8; 816 *tcurrent++ = (length & 0x00ff); 817#if DNS_RDATASET_FIXED 818 tcurrent += 2; /* fill in later */ 819#endif 820 memcpy(tcurrent, data, length); 821 tcurrent += length; 822 nadded++; 823 if (nadded < ncount) { 824 do { 825 dns_rdata_reset(&nrdata); 826#if DNS_RDATASET_FIXED 827 norder = ncurrent[2] * 256 + ncurrent[3]; 828 INSIST(norder < oncount); 829#endif 830 rdata_from_slab(&ncurrent, rdclass, 831 type, &nrdata); 832 } while (rdata_in_slab(oslab, reservelen, 833 rdclass, type, 834 &nrdata)); 835 } 836 } 837 } 838 839#if DNS_RDATASET_FIXED 840 fillin_offsets(offsetbase, offsettable, ocount + oncount); 841 842 isc_mem_put(mctx, offsettable, 843 (ocount + oncount) * sizeof(unsigned int)); 844#endif 845 846 INSIST(tcurrent == tstart + tlength); 847 848 *tslabp = tstart; 849 850 return (ISC_R_SUCCESS); 851} 852 853isc_result_t 854dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab, 855 unsigned int reservelen, isc_mem_t *mctx, 856 dns_rdataclass_t rdclass, dns_rdatatype_t type, 857 unsigned int flags, unsigned char **tslabp) 858{ 859 unsigned char *mcurrent, *sstart, *scurrent, *tstart, *tcurrent; 860 unsigned int mcount, scount, rcount ,count, tlength, tcount, i; 861 dns_rdata_t srdata = DNS_RDATA_INIT; 862 dns_rdata_t mrdata = DNS_RDATA_INIT; 863#if DNS_RDATASET_FIXED 864 unsigned char *offsetbase; 865 unsigned int *offsettable; 866 unsigned int order; 867#endif 868 869 REQUIRE(tslabp != NULL && *tslabp == NULL); 870 REQUIRE(mslab != NULL && sslab != NULL); 871 872 mcurrent = mslab + reservelen; 873 mcount = *mcurrent++ * 256; 874 mcount += *mcurrent++; 875 scurrent = sslab + reservelen; 876 scount = *scurrent++ * 256; 877 scount += *scurrent++; 878 INSIST(mcount > 0 && scount > 0); 879 880 /* 881 * Yes, this is inefficient! 882 */ 883 884 /* 885 * Start figuring out the target length and count. 886 */ 887 tlength = reservelen + 2; 888 tcount = 0; 889 rcount = 0; 890 891#if DNS_RDATASET_FIXED 892 mcurrent += 4 * mcount; 893 scurrent += 4 * scount; 894#endif 895 sstart = scurrent; 896 897 /* 898 * Add in the length of rdata in the mslab that aren't in 899 * the sslab. 900 */ 901 for (i = 0; i < mcount; i++) { 902 unsigned char *mrdatabegin = mcurrent; 903 rdata_from_slab(&mcurrent, rdclass, type, &mrdata); 904 scurrent = sstart; 905 for (count = 0; count < scount; count++) { 906 dns_rdata_reset(&srdata); 907 rdata_from_slab(&scurrent, rdclass, type, &srdata); 908 if (dns_rdata_compare(&mrdata, &srdata) == 0) 909 break; 910 } 911 if (count == scount) { 912 /* 913 * This rdata isn't in the sslab, and thus isn't 914 * being subtracted. 915 */ 916 tlength += mcurrent - mrdatabegin; 917 tcount++; 918 } else 919 rcount++; 920 dns_rdata_reset(&mrdata); 921 } 922 923#if DNS_RDATASET_FIXED 924 tlength += (4 * tcount); 925#endif 926 927 /* 928 * Check that all the records originally existed. The numeric 929 * check only works as rdataslabs do not contain duplicates. 930 */ 931 if (((flags & DNS_RDATASLAB_EXACT) != 0) && (rcount != scount)) 932 return (DNS_R_NOTEXACT); 933 934 /* 935 * Don't continue if the new rdataslab would be empty. 936 */ 937 if (tcount == 0) 938 return (DNS_R_NXRRSET); 939 940 /* 941 * If nothing is going to change, we can stop. 942 */ 943 if (rcount == 0) 944 return (DNS_R_UNCHANGED); 945 946 /* 947 * Copy the reserved area from the mslab. 948 */ 949 tstart = isc_mem_get(mctx, tlength); 950 if (tstart == NULL) 951 return (ISC_R_NOMEMORY); 952 memcpy(tstart, mslab, reservelen); 953 tcurrent = tstart + reservelen; 954#if DNS_RDATASET_FIXED 955 offsetbase = tcurrent; 956 957 offsettable = isc_mem_get(mctx, mcount * sizeof(unsigned int)); 958 if (offsettable == NULL) { 959 isc_mem_put(mctx, tstart, tlength); 960 return (ISC_R_NOMEMORY); 961 } 962 memset(offsettable, 0, mcount * sizeof(unsigned int)); 963#endif 964 965 /* 966 * Write the new count. 967 */ 968 *tcurrent++ = (tcount & 0xff00) >> 8; 969 *tcurrent++ = (tcount & 0x00ff); 970 971#if DNS_RDATASET_FIXED 972 tcurrent += (4 * tcount); 973#endif 974 975 /* 976 * Copy the parts of mslab not in sslab. 977 */ 978 mcurrent = mslab + reservelen; 979 mcount = *mcurrent++ * 256; 980 mcount += *mcurrent++; 981#if DNS_RDATASET_FIXED 982 mcurrent += (4 * mcount); 983#endif 984 for (i = 0; i < mcount; i++) { 985 unsigned char *mrdatabegin = mcurrent; 986#if DNS_RDATASET_FIXED 987 order = mcurrent[2] * 256 + mcurrent[3]; 988 INSIST(order < mcount); 989#endif 990 rdata_from_slab(&mcurrent, rdclass, type, &mrdata); 991 scurrent = sstart; 992 for (count = 0; count < scount; count++) { 993 dns_rdata_reset(&srdata); 994 rdata_from_slab(&scurrent, rdclass, type, &srdata); 995 if (dns_rdata_compare(&mrdata, &srdata) == 0) 996 break; 997 } 998 if (count == scount) { 999 /* 1000 * This rdata isn't in the sslab, and thus should be 1001 * copied to the tslab. 1002 */ 1003 unsigned int length = mcurrent - mrdatabegin; 1004#if DNS_RDATASET_FIXED 1005 offsettable[order] = tcurrent - offsetbase; 1006#endif 1007 memcpy(tcurrent, mrdatabegin, length); 1008 tcurrent += length; 1009 } 1010 dns_rdata_reset(&mrdata); 1011 } 1012 1013#if DNS_RDATASET_FIXED 1014 fillin_offsets(offsetbase, offsettable, mcount); 1015 1016 isc_mem_put(mctx, offsettable, mcount * sizeof(unsigned int)); 1017#endif 1018 1019 INSIST(tcurrent == tstart + tlength); 1020 1021 *tslabp = tstart; 1022 1023 return (ISC_R_SUCCESS); 1024} 1025 1026isc_boolean_t 1027dns_rdataslab_equal(unsigned char *slab1, unsigned char *slab2, 1028 unsigned int reservelen) 1029{ 1030 unsigned char *current1, *current2; 1031 unsigned int count1, count2; 1032 unsigned int length1, length2; 1033 1034 current1 = slab1 + reservelen; 1035 count1 = *current1++ * 256; 1036 count1 += *current1++; 1037 1038 current2 = slab2 + reservelen; 1039 count2 = *current2++ * 256; 1040 count2 += *current2++; 1041 1042 if (count1 != count2) 1043 return (ISC_FALSE); 1044 1045#if DNS_RDATASET_FIXED 1046 current1 += (4 * count1); 1047 current2 += (4 * count2); 1048#endif 1049 1050 while (count1 > 0) { 1051 length1 = *current1++ * 256; 1052 length1 += *current1++; 1053 1054 length2 = *current2++ * 256; 1055 length2 += *current2++; 1056 1057#if DNS_RDATASET_FIXED 1058 current1 += 2; 1059 current2 += 2; 1060#endif 1061 1062 if (length1 != length2 || 1063 memcmp(current1, current2, length1) != 0) 1064 return (ISC_FALSE); 1065 1066 current1 += length1; 1067 current2 += length1; 1068 1069 count1--; 1070 } 1071 return (ISC_TRUE); 1072} 1073 1074isc_boolean_t 1075dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2, 1076 unsigned int reservelen, dns_rdataclass_t rdclass, 1077 dns_rdatatype_t type) 1078{ 1079 unsigned char *current1, *current2; 1080 unsigned int count1, count2; 1081 dns_rdata_t rdata1 = DNS_RDATA_INIT; 1082 dns_rdata_t rdata2 = DNS_RDATA_INIT; 1083 1084 current1 = slab1 + reservelen; 1085 count1 = *current1++ * 256; 1086 count1 += *current1++; 1087 1088 current2 = slab2 + reservelen; 1089 count2 = *current2++ * 256; 1090 count2 += *current2++; 1091 1092 if (count1 != count2) 1093 return (ISC_FALSE); 1094 1095#if DNS_RDATASET_FIXED 1096 current1 += (4 * count1); 1097 current2 += (4 * count2); 1098#endif 1099 1100 while (count1-- > 0) { 1101 rdata_from_slab(¤t1, rdclass, type, &rdata1); 1102 rdata_from_slab(¤t2, rdclass, type, &rdata2); 1103 if (dns_rdata_compare(&rdata1, &rdata2) != 0) 1104 return (ISC_FALSE); 1105 dns_rdata_reset(&rdata1); 1106 dns_rdata_reset(&rdata2); 1107 } 1108 return (ISC_TRUE); 1109}