rdataslab.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <stdlib.h>
00025 
00026 #include <isc/mem.h>
00027 #include <isc/region.h>
00028 #include <isc/string.h>         /* Required for HP/UX (and others?) */
00029 #include <isc/util.h>
00030 
00031 #include <dns/result.h>
00032 #include <dns/rdata.h>
00033 #include <dns/rdataset.h>
00034 #include <dns/rdataslab.h>
00035 
00036 /*
00037  * The rdataslab structure allows iteration to occur in both load order
00038  * and DNSSEC order.  The structure is as follows:
00039  *
00040  *      header          (reservelen bytes)
00041  *      record count    (2 bytes)
00042  *      offset table    (4 x record count bytes in load order)
00043  *      data records
00044  *              data length     (2 bytes)
00045  *              order           (2 bytes)
00046  *              meta data       (1 byte for RRSIG's)
00047  *              data            (data length bytes)
00048  *
00049  * If DNS_RDATASET_FIXED is defined to be zero (0) the format of a
00050  * rdataslab is as follows:
00051  *
00052  *      header          (reservelen bytes)
00053  *      record count    (2 bytes)
00054  *      data records
00055  *              data length     (2 bytes)
00056  *              meta data       (1 byte for RRSIG's)
00057  *              data            (data length bytes)
00058  *
00059  * Offsets are from the end of the header.
00060  *
00061  * Load order traversal is performed by walking the offset table to find
00062  * the start of the record (DNS_RDATASET_FIXED = 1).
00063  *
00064  * DNSSEC order traversal is performed by walking the data records.
00065  *
00066  * The order is stored with record to allow for efficient reconstruction
00067  * of the offset table following a merge or subtraction.
00068  *
00069  * The iterator methods here currently only support DNSSEC order iteration.
00070  *
00071  * The iterator methods in rbtdb support both load order and DNSSEC order
00072  * iteration.
00073  *
00074  * WARNING:
00075  *      rbtdb.c directly interacts with the slab's raw structures.  If the
00076  *      structure changes then rbtdb.c also needs to be updated to reflect
00077  *      the changes.  See the areas tagged with "RDATASLAB".
00078  */
00079 
00080 struct xrdata {
00081         dns_rdata_t     rdata;
00082         unsigned int    order;
00083 };
00084 
00085 /*% Note: the "const void *" are just to make qsort happy.  */
00086 static int
00087 compare_rdata(const void *p1, const void *p2) {
00088         const struct xrdata *x1 = p1;
00089         const struct xrdata *x2 = p2;
00090         return (dns_rdata_compare(&x1->rdata, &x2->rdata));
00091 }
00092 
00093 #if DNS_RDATASET_FIXED
00094 static void
00095 fillin_offsets(unsigned char *offsetbase, unsigned int *offsettable,
00096                unsigned length)
00097 {
00098         unsigned int i, j;
00099         unsigned char *raw;
00100 
00101         for (i = 0, j = 0; i < length; i++) {
00102 
00103                 if (offsettable[i] == 0)
00104                         continue;
00105 
00106                 /*
00107                  * Fill in offset table.
00108                  */
00109                 raw = &offsetbase[j*4 + 2];
00110                 *raw++ = (offsettable[i] & 0xff000000) >> 24;
00111                 *raw++ = (offsettable[i] & 0xff0000) >> 16;
00112                 *raw++ = (offsettable[i] & 0xff00) >> 8;
00113                 *raw = offsettable[i] & 0xff;
00114 
00115                 /*
00116                  * Fill in table index.
00117                  */
00118                 raw = offsetbase + offsettable[i] + 2;
00119                 *raw++ = (j & 0xff00) >> 8;
00120                 *raw = j++ & 0xff;
00121         }
00122 }
00123 #endif
00124 
00125 isc_result_t
00126 dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
00127                            isc_region_t *region, unsigned int reservelen)
00128 {
00129         /*
00130          * Use &removed as a sentinal pointer for duplicate
00131          * rdata as rdata.data == NULL is valid.
00132          */
00133         static unsigned char removed;
00134         struct xrdata  *x;
00135         unsigned char  *rawbuf;
00136 #if DNS_RDATASET_FIXED
00137         unsigned char  *offsetbase;
00138 #endif
00139         unsigned int    buflen;
00140         isc_result_t    result;
00141         unsigned int    nitems;
00142         unsigned int    nalloc;
00143         unsigned int    i;
00144 #if DNS_RDATASET_FIXED
00145         unsigned int   *offsettable;
00146 #endif
00147         unsigned int    length;
00148 
00149         buflen = reservelen + 2;
00150 
00151         nitems = dns_rdataset_count(rdataset);
00152 
00153         /*
00154          * If there are no rdata then we can just need to allocate a header
00155          * with zero a record count.
00156          */
00157         if (nitems == 0) {
00158                 if (rdataset->type != 0)
00159                         return (ISC_R_FAILURE);
00160                 rawbuf = isc_mem_get(mctx, buflen);
00161                 if (rawbuf == NULL)
00162                         return (ISC_R_NOMEMORY);
00163                 region->base = rawbuf;
00164                 region->length = buflen;
00165                 rawbuf += reservelen;
00166                 *rawbuf++ = 0;
00167                 *rawbuf = 0;
00168                 return (ISC_R_SUCCESS);
00169         }
00170 
00171         if (nitems > 0xffff)
00172                 return (ISC_R_NOSPACE);
00173 
00174         /*
00175          * Remember the original number of items.
00176          */
00177         nalloc = nitems;
00178         x = isc_mem_get(mctx, nalloc * sizeof(struct xrdata));
00179         if (x == NULL)
00180                 return (ISC_R_NOMEMORY);
00181 
00182         /*
00183          * Save all of the rdata members into an array.
00184          */
00185         result = dns_rdataset_first(rdataset);
00186         if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
00187                 goto free_rdatas;
00188         for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) {
00189                 INSIST(result == ISC_R_SUCCESS);
00190                 dns_rdata_init(&x[i].rdata);
00191                 dns_rdataset_current(rdataset, &x[i].rdata);
00192                 INSIST(x[i].rdata.data != &removed);
00193 #if DNS_RDATASET_FIXED
00194                 x[i].order = i;
00195 #endif
00196                 result = dns_rdataset_next(rdataset);
00197         }
00198         if (i != nalloc || result != ISC_R_NOMORE) {
00199                 /*
00200                  * Somehow we iterated over fewer rdatas than
00201                  * dns_rdataset_count() said there were or there
00202                  * were more items than dns_rdataset_count said
00203                  * there were.
00204                  */
00205                 result = ISC_R_FAILURE;
00206                 goto free_rdatas;
00207         }
00208 
00209         /*
00210          * Put into DNSSEC order.
00211          */
00212         if (nalloc > 1U)
00213                 qsort(x, nalloc, sizeof(struct xrdata), compare_rdata);
00214 
00215         /*
00216          * Remove duplicates and compute the total storage required.
00217          *
00218          * If an rdata is not a duplicate, accumulate the storage size
00219          * required for the rdata.  We do not store the class, type, etc,
00220          * just the rdata, so our overhead is 2 bytes for the number of
00221          * records, and 8 for each rdata, (length(2), offset(4) and order(2))
00222          * and then the rdata itself.
00223          */
00224         for (i = 1; i < nalloc; i++) {
00225                 if (compare_rdata(&x[i-1].rdata, &x[i].rdata) == 0) {
00226                         x[i-1].rdata.data = &removed;
00227 #if DNS_RDATASET_FIXED
00228                         /*
00229                          * Preserve the least order so A, B, A -> A, B
00230                          * after duplicate removal.
00231                          */
00232                         if (x[i-1].order < x[i].order)
00233                                 x[i].order = x[i-1].order;
00234 #endif
00235                         nitems--;
00236                 } else {
00237 #if DNS_RDATASET_FIXED
00238                         buflen += (8 + x[i-1].rdata.length);
00239 #else
00240                         buflen += (2 + x[i-1].rdata.length);
00241 #endif
00242                         /*
00243                          * Provide space to store the per RR meta data.
00244                          */
00245                         if (rdataset->type == dns_rdatatype_rrsig)
00246                                 buflen++;
00247                 }
00248         }
00249 
00250         /*
00251          * Don't forget the last item!
00252          */
00253 #if DNS_RDATASET_FIXED
00254         buflen += (8 + x[i-1].rdata.length);
00255 #else
00256         buflen += (2 + x[i-1].rdata.length);
00257 #endif
00258         /*
00259          * Provide space to store the per RR meta data.
00260          */
00261         if (rdataset->type == dns_rdatatype_rrsig)
00262                 buflen++;
00263 
00264         /*
00265          * Ensure that singleton types are actually singletons.
00266          */
00267         if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) {
00268                 /*
00269                  * We have a singleton type, but there's more than one
00270                  * RR in the rdataset.
00271                  */
00272                 result = DNS_R_SINGLETON;
00273                 goto free_rdatas;
00274         }
00275 
00276         /*
00277          * Allocate the memory, set up a buffer, start copying in
00278          * data.
00279          */
00280         rawbuf = isc_mem_get(mctx, buflen);
00281         if (rawbuf == NULL) {
00282                 result = ISC_R_NOMEMORY;
00283                 goto free_rdatas;
00284         }
00285 
00286 #if DNS_RDATASET_FIXED
00287         /* Allocate temporary offset table. */
00288         offsettable = isc_mem_get(mctx, nalloc * sizeof(unsigned int));
00289         if (offsettable == NULL) {
00290                 isc_mem_put(mctx, rawbuf, buflen);
00291                 result = ISC_R_NOMEMORY;
00292                 goto free_rdatas;
00293         }
00294         memset(offsettable, 0, nalloc * sizeof(unsigned int));
00295 #endif
00296 
00297         region->base = rawbuf;
00298         region->length = buflen;
00299 
00300         rawbuf += reservelen;
00301 #if DNS_RDATASET_FIXED
00302         offsetbase = rawbuf;
00303 #endif
00304 
00305         *rawbuf++ = (nitems & 0xff00) >> 8;
00306         *rawbuf++ = (nitems & 0x00ff);
00307 
00308 #if DNS_RDATASET_FIXED
00309         /* Skip load order table.  Filled in later. */
00310         rawbuf += nitems * 4;
00311 #endif
00312 
00313         for (i = 0; i < nalloc; i++) {
00314                 if (x[i].rdata.data == &removed)
00315                         continue;
00316 #if DNS_RDATASET_FIXED
00317                 offsettable[x[i].order] = rawbuf - offsetbase;
00318 #endif
00319                 length = x[i].rdata.length;
00320                 if (rdataset->type == dns_rdatatype_rrsig)
00321                         length++;
00322                 INSIST(length <= 0xffff);
00323                 *rawbuf++ = (length & 0xff00) >> 8;
00324                 *rawbuf++ = (length & 0x00ff);
00325 #if DNS_RDATASET_FIXED
00326                 rawbuf += 2;    /* filled in later */
00327 #endif
00328                 /*
00329                  * Store the per RR meta data.
00330                  */
00331                 if (rdataset->type == dns_rdatatype_rrsig) {
00332                         *rawbuf++ |= (x[i].rdata.flags & DNS_RDATA_OFFLINE) ?
00333                                             DNS_RDATASLAB_OFFLINE : 0;
00334                 }
00335                 memmove(rawbuf, x[i].rdata.data, x[i].rdata.length);
00336                 rawbuf += x[i].rdata.length;
00337         }
00338 
00339 #if DNS_RDATASET_FIXED
00340         fillin_offsets(offsetbase, offsettable, nalloc);
00341         isc_mem_put(mctx, offsettable, nalloc * sizeof(unsigned int));
00342 #endif
00343 
00344         result = ISC_R_SUCCESS;
00345 
00346  free_rdatas:
00347         isc_mem_put(mctx, x, nalloc * sizeof(struct xrdata));
00348         return (result);
00349 }
00350 
00351 static void
00352 rdataset_disassociate(dns_rdataset_t *rdataset) {
00353         UNUSED(rdataset);
00354 }
00355 
00356 static isc_result_t
00357 rdataset_first(dns_rdataset_t *rdataset) {
00358         unsigned char *raw = rdataset->private3;
00359         unsigned int count;
00360 
00361         count = raw[0] * 256 + raw[1];
00362         if (count == 0) {
00363                 rdataset->private5 = NULL;
00364                 return (ISC_R_NOMORE);
00365         }
00366 #if DNS_RDATASET_FIXED
00367         raw += 2 + (4 * count);
00368 #else
00369         raw += 2;
00370 #endif
00371         /*
00372          * The privateuint4 field is the number of rdata beyond the cursor
00373          * position, so we decrement the total count by one before storing
00374          * it.
00375          */
00376         count--;
00377         rdataset->privateuint4 = count;
00378         rdataset->private5 = raw;
00379 
00380         return (ISC_R_SUCCESS);
00381 }
00382 
00383 static isc_result_t
00384 rdataset_next(dns_rdataset_t *rdataset) {
00385         unsigned int count;
00386         unsigned int length;
00387         unsigned char *raw;
00388 
00389         count = rdataset->privateuint4;
00390         if (count == 0)
00391                 return (ISC_R_NOMORE);
00392         count--;
00393         rdataset->privateuint4 = count;
00394         raw = rdataset->private5;
00395         length = raw[0] * 256 + raw[1];
00396 #if DNS_RDATASET_FIXED
00397         raw += length + 4;
00398 #else
00399         raw += length + 2;
00400 #endif
00401         rdataset->private5 = raw;
00402 
00403         return (ISC_R_SUCCESS);
00404 }
00405 
00406 static void
00407 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
00408         unsigned char *raw = rdataset->private5;
00409         isc_region_t r;
00410         unsigned int length;
00411         unsigned int flags = 0;
00412 
00413         REQUIRE(raw != NULL);
00414 
00415         length = raw[0] * 256 + raw[1];
00416 #if DNS_RDATASET_FIXED
00417         raw += 4;
00418 #else
00419         raw += 2;
00420 #endif
00421         if (rdataset->type == dns_rdatatype_rrsig) {
00422                 if (*raw & DNS_RDATASLAB_OFFLINE)
00423                         flags |= DNS_RDATA_OFFLINE;
00424                 length--;
00425                 raw++;
00426         }
00427         r.length = length;
00428         r.base = raw;
00429         dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
00430         rdata->flags |= flags;
00431 }
00432 
00433 static void
00434 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
00435         *target = *source;
00436 
00437         /*
00438          * Reset iterator state.
00439          */
00440         target->privateuint4 = 0;
00441         target->private5 = NULL;
00442 }
00443 
00444 static unsigned int
00445 rdataset_count(dns_rdataset_t *rdataset) {
00446         unsigned char *raw = rdataset->private3;
00447         unsigned int count;
00448 
00449         count = raw[0] * 256 + raw[1];
00450 
00451         return (count);
00452 }
00453 
00454 static dns_rdatasetmethods_t rdataset_methods = {
00455         rdataset_disassociate,
00456         rdataset_first,
00457         rdataset_next,
00458         rdataset_current,
00459         rdataset_clone,
00460         rdataset_count,
00461         NULL,
00462         NULL,
00463         NULL,
00464         NULL,
00465         NULL,
00466         NULL,
00467         NULL,
00468         NULL,
00469         NULL,
00470         NULL,
00471         NULL,
00472         NULL
00473 };
00474 
00475 void
00476 dns_rdataslab_tordataset(unsigned char *slab, unsigned int reservelen,
00477                          dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
00478                          dns_rdatatype_t covers, dns_ttl_t ttl,
00479                          dns_rdataset_t *rdataset)
00480 {
00481         REQUIRE(slab != NULL);
00482         REQUIRE(!dns_rdataset_isassociated(rdataset));
00483 
00484         rdataset->methods = &rdataset_methods;
00485         rdataset->rdclass = rdclass;
00486         rdataset->type = rdtype;
00487         rdataset->covers = covers;
00488         rdataset->ttl = ttl;
00489         rdataset->trust = 0;
00490         rdataset->private1 = NULL;
00491         rdataset->private2 = NULL;
00492         rdataset->private3 = slab + reservelen;
00493 
00494         /*
00495          * Reset iterator state.
00496          */
00497         rdataset->privateuint4 = 0;
00498         rdataset->private5 = NULL;
00499 }
00500 
00501 unsigned int
00502 dns_rdataslab_size(unsigned char *slab, unsigned int reservelen) {
00503         unsigned int count, length;
00504         unsigned char *current;
00505 
00506         REQUIRE(slab != NULL);
00507 
00508         current = slab + reservelen;
00509         count = *current++ * 256;
00510         count += *current++;
00511 #if DNS_RDATASET_FIXED
00512         current += (4 * count);
00513 #endif
00514         while (count > 0) {
00515                 count--;
00516                 length = *current++ * 256;
00517                 length += *current++;
00518 #if DNS_RDATASET_FIXED
00519                 current += length + 2;
00520 #else
00521                 current += length;
00522 #endif
00523         }
00524 
00525         return ((unsigned int)(current - slab));
00526 }
00527 
00528 /*
00529  * Make the dns_rdata_t 'rdata' refer to the slab item
00530  * beginning at '*current', which is part of a slab of type
00531  * 'type' and class 'rdclass', and advance '*current' to
00532  * point to the next item in the slab.
00533  */
00534 static inline void
00535 rdata_from_slab(unsigned char **current,
00536               dns_rdataclass_t rdclass, dns_rdatatype_t type,
00537               dns_rdata_t *rdata)
00538 {
00539         unsigned char *tcurrent = *current;
00540         isc_region_t region;
00541         unsigned int length;
00542         isc_boolean_t offline = ISC_FALSE;
00543 
00544         length = *tcurrent++ * 256;
00545         length += *tcurrent++;
00546 
00547         if (type == dns_rdatatype_rrsig) {
00548                 if ((*tcurrent & DNS_RDATASLAB_OFFLINE) != 0)
00549                         offline = ISC_TRUE;
00550                 length--;
00551                 tcurrent++;
00552         }
00553         region.length = length;
00554 #if DNS_RDATASET_FIXED
00555         tcurrent += 2;
00556 #endif
00557         region.base = tcurrent;
00558         tcurrent += region.length;
00559         dns_rdata_fromregion(rdata, rdclass, type, &region);
00560         if (offline)
00561                 rdata->flags |= DNS_RDATA_OFFLINE;
00562         *current = tcurrent;
00563 }
00564 
00565 /*
00566  * Return true iff 'slab' (slab data of type 'type' and class 'rdclass')
00567  * contains an rdata identical to 'rdata'.  This does case insensitive
00568  * comparisons per DNSSEC.
00569  */
00570 static inline isc_boolean_t
00571 rdata_in_slab(unsigned char *slab, unsigned int reservelen,
00572               dns_rdataclass_t rdclass, dns_rdatatype_t type,
00573               dns_rdata_t *rdata)
00574 {
00575         unsigned int count, i;
00576         unsigned char *current;
00577         dns_rdata_t trdata = DNS_RDATA_INIT;
00578         int n;
00579 
00580         current = slab + reservelen;
00581         count = *current++ * 256;
00582         count += *current++;
00583 
00584 #if DNS_RDATASET_FIXED
00585         current += (4 * count);
00586 #endif
00587 
00588         for (i = 0; i < count; i++) {
00589                 rdata_from_slab(&current, rdclass, type, &trdata);
00590 
00591                 n = dns_rdata_compare(&trdata, rdata);
00592                 if (n == 0)
00593                         return (ISC_TRUE);
00594                 if (n > 0)      /* In DNSSEC order. */
00595                         break;
00596                 dns_rdata_reset(&trdata);
00597         }
00598         return (ISC_FALSE);
00599 }
00600 
00601 isc_result_t
00602 dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
00603                     unsigned int reservelen, isc_mem_t *mctx,
00604                     dns_rdataclass_t rdclass, dns_rdatatype_t type,
00605                     unsigned int flags, unsigned char **tslabp)
00606 {
00607         unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent, *data;
00608         unsigned int ocount, ncount, count, olength, tlength, tcount, length;
00609         dns_rdata_t ordata = DNS_RDATA_INIT;
00610         dns_rdata_t nrdata = DNS_RDATA_INIT;
00611         isc_boolean_t added_something = ISC_FALSE;
00612         unsigned int oadded = 0;
00613         unsigned int nadded = 0;
00614         unsigned int nncount = 0;
00615 #if DNS_RDATASET_FIXED
00616         unsigned int oncount;
00617         unsigned int norder = 0;
00618         unsigned int oorder = 0;
00619         unsigned char *offsetbase;
00620         unsigned int *offsettable;
00621 #endif
00622 
00623         /*
00624          * XXX  Need parameter to allow "delete rdatasets in nslab" merge,
00625          * or perhaps another merge routine for this purpose.
00626          */
00627 
00628         REQUIRE(tslabp != NULL && *tslabp == NULL);
00629         REQUIRE(oslab != NULL && nslab != NULL);
00630 
00631         ocurrent = oslab + reservelen;
00632         ocount = *ocurrent++ * 256;
00633         ocount += *ocurrent++;
00634 #if DNS_RDATASET_FIXED
00635         ocurrent += (4 * ocount);
00636 #endif
00637         ostart = ocurrent;
00638         ncurrent = nslab + reservelen;
00639         ncount = *ncurrent++ * 256;
00640         ncount += *ncurrent++;
00641 #if DNS_RDATASET_FIXED
00642         ncurrent += (4 * ncount);
00643 #endif
00644         INSIST(ocount > 0 && ncount > 0);
00645 
00646 #if DNS_RDATASET_FIXED
00647         oncount = ncount;
00648 #endif
00649 
00650         /*
00651          * Yes, this is inefficient!
00652          */
00653 
00654         /*
00655          * Figure out the length of the old slab's data.
00656          */
00657         olength = 0;
00658         for (count = 0; count < ocount; count++) {
00659                 length = *ocurrent++ * 256;
00660                 length += *ocurrent++;
00661 #if DNS_RDATASET_FIXED
00662                 olength += length + 8;
00663                 ocurrent += length + 2;
00664 #else
00665                 olength += length + 2;
00666                 ocurrent += length;
00667 #endif
00668         }
00669 
00670         /*
00671          * Start figuring out the target length and count.
00672          */
00673         tlength = reservelen + 2 + olength;
00674         tcount = ocount;
00675 
00676         /*
00677          * Add in the length of rdata in the new slab that aren't in
00678          * the old slab.
00679          */
00680         do {
00681                 dns_rdata_init(&nrdata);
00682                 rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
00683                 if (!rdata_in_slab(oslab, reservelen, rdclass, type, &nrdata))
00684                 {
00685                         /*
00686                          * This rdata isn't in the old slab.
00687                          */
00688 #if DNS_RDATASET_FIXED
00689                         tlength += nrdata.length + 8;
00690 #else
00691                         tlength += nrdata.length + 2;
00692 #endif
00693                         if (type == dns_rdatatype_rrsig)
00694                                 tlength++;
00695                         tcount++;
00696                         nncount++;
00697                         added_something = ISC_TRUE;
00698                 }
00699                 ncount--;
00700         } while (ncount > 0);
00701         ncount = nncount;
00702 
00703         if (((flags & DNS_RDATASLAB_EXACT) != 0) &&
00704             (tcount != ncount + ocount))
00705                 return (DNS_R_NOTEXACT);
00706 
00707         if (!added_something && (flags & DNS_RDATASLAB_FORCE) == 0)
00708                 return (DNS_R_UNCHANGED);
00709 
00710         /*
00711          * Ensure that singleton types are actually singletons.
00712          */
00713         if (tcount > 1 && dns_rdatatype_issingleton(type)) {
00714                 /*
00715                  * We have a singleton type, but there's more than one
00716                  * RR in the rdataset.
00717                  */
00718                 return (DNS_R_SINGLETON);
00719         }
00720 
00721         if (tcount > 0xffff)
00722                 return (ISC_R_NOSPACE);
00723 
00724         /*
00725          * Copy the reserved area from the new slab.
00726          */
00727         tstart = isc_mem_get(mctx, tlength);
00728         if (tstart == NULL)
00729                 return (ISC_R_NOMEMORY);
00730         memmove(tstart, nslab, reservelen);
00731         tcurrent = tstart + reservelen;
00732 #if DNS_RDATASET_FIXED
00733         offsetbase = tcurrent;
00734 #endif
00735 
00736         /*
00737          * Write the new count.
00738          */
00739         *tcurrent++ = (tcount & 0xff00) >> 8;
00740         *tcurrent++ = (tcount & 0x00ff);
00741 
00742 #if DNS_RDATASET_FIXED
00743         /*
00744          * Skip offset table.
00745          */
00746         tcurrent += (tcount * 4);
00747 
00748         offsettable = isc_mem_get(mctx,
00749                                   (ocount + oncount) * sizeof(unsigned int));
00750         if (offsettable == NULL) {
00751                 isc_mem_put(mctx, tstart, tlength);
00752                 return (ISC_R_NOMEMORY);
00753         }
00754         memset(offsettable, 0, (ocount + oncount) * sizeof(unsigned int));
00755 #endif
00756 
00757         /*
00758          * Merge the two slabs.
00759          */
00760         ocurrent = ostart;
00761         INSIST(ocount != 0);
00762 #if DNS_RDATASET_FIXED
00763         oorder = ocurrent[2] * 256 + ocurrent[3];
00764         INSIST(oorder < ocount);
00765 #endif
00766         rdata_from_slab(&ocurrent, rdclass, type, &ordata);
00767 
00768         ncurrent = nslab + reservelen + 2;
00769 #if DNS_RDATASET_FIXED
00770         ncurrent += (4 * oncount);
00771 #endif
00772 
00773         if (ncount > 0) {
00774                 do {
00775                         dns_rdata_reset(&nrdata);
00776 #if DNS_RDATASET_FIXED
00777                         norder = ncurrent[2] * 256 + ncurrent[3];
00778 
00779                         INSIST(norder < oncount);
00780 #endif
00781                         rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
00782                 } while (rdata_in_slab(oslab, reservelen, rdclass,
00783                                        type, &nrdata));
00784         }
00785 
00786         while (oadded < ocount || nadded < ncount) {
00787                 isc_boolean_t fromold;
00788                 if (oadded == ocount)
00789                         fromold = ISC_FALSE;
00790                 else if (nadded == ncount)
00791                         fromold = ISC_TRUE;
00792                 else
00793                         fromold = ISC_TF(compare_rdata(&ordata, &nrdata) < 0);
00794                 if (fromold) {
00795 #if DNS_RDATASET_FIXED
00796                         offsettable[oorder] = tcurrent - offsetbase;
00797 #endif
00798                         length = ordata.length;
00799                         data = ordata.data;
00800                         if (type == dns_rdatatype_rrsig) {
00801                                 length++;
00802                                 data--;
00803                         }
00804                         *tcurrent++ = (length & 0xff00) >> 8;
00805                         *tcurrent++ = (length & 0x00ff);
00806 #if DNS_RDATASET_FIXED
00807                         tcurrent += 2;  /* fill in later */
00808 #endif
00809                         memmove(tcurrent, data, length);
00810                         tcurrent += length;
00811                         oadded++;
00812                         if (oadded < ocount) {
00813                                 dns_rdata_reset(&ordata);
00814 #if DNS_RDATASET_FIXED
00815                                 oorder = ocurrent[2] * 256 + ocurrent[3];
00816                                 INSIST(oorder < ocount);
00817 #endif
00818                                 rdata_from_slab(&ocurrent, rdclass, type,
00819                                                 &ordata);
00820                         }
00821                 } else {
00822 #if DNS_RDATASET_FIXED
00823                         offsettable[ocount + norder] = tcurrent - offsetbase;
00824 #endif
00825                         length = nrdata.length;
00826                         data = nrdata.data;
00827                         if (type == dns_rdatatype_rrsig) {
00828                                 length++;
00829                                 data--;
00830                         }
00831                         *tcurrent++ = (length & 0xff00) >> 8;
00832                         *tcurrent++ = (length & 0x00ff);
00833 #if DNS_RDATASET_FIXED
00834                         tcurrent += 2;  /* fill in later */
00835 #endif
00836                         memmove(tcurrent, data, length);
00837                         tcurrent += length;
00838                         nadded++;
00839                         if (nadded < ncount) {
00840                                 do {
00841                                         dns_rdata_reset(&nrdata);
00842 #if DNS_RDATASET_FIXED
00843                                         norder = ncurrent[2] * 256 + ncurrent[3];
00844                                         INSIST(norder < oncount);
00845 #endif
00846                                         rdata_from_slab(&ncurrent, rdclass,
00847                                                         type, &nrdata);
00848                                 } while (rdata_in_slab(oslab, reservelen,
00849                                                        rdclass, type,
00850                                                        &nrdata));
00851                         }
00852                 }
00853         }
00854 
00855 #if DNS_RDATASET_FIXED
00856         fillin_offsets(offsetbase, offsettable, ocount + oncount);
00857 
00858         isc_mem_put(mctx, offsettable,
00859                     (ocount + oncount) * sizeof(unsigned int));
00860 #endif
00861 
00862         INSIST(tcurrent == tstart + tlength);
00863 
00864         *tslabp = tstart;
00865 
00866         return (ISC_R_SUCCESS);
00867 }
00868 
00869 isc_result_t
00870 dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab,
00871                        unsigned int reservelen, isc_mem_t *mctx,
00872                        dns_rdataclass_t rdclass, dns_rdatatype_t type,
00873                        unsigned int flags, unsigned char **tslabp)
00874 {
00875         unsigned char *mcurrent, *sstart, *scurrent, *tstart, *tcurrent;
00876         unsigned int mcount, scount, rcount ,count, tlength, tcount, i;
00877         dns_rdata_t srdata = DNS_RDATA_INIT;
00878         dns_rdata_t mrdata = DNS_RDATA_INIT;
00879 #if DNS_RDATASET_FIXED
00880         unsigned char *offsetbase;
00881         unsigned int *offsettable;
00882         unsigned int order;
00883 #endif
00884 
00885         REQUIRE(tslabp != NULL && *tslabp == NULL);
00886         REQUIRE(mslab != NULL && sslab != NULL);
00887 
00888         mcurrent = mslab + reservelen;
00889         mcount = *mcurrent++ * 256;
00890         mcount += *mcurrent++;
00891         scurrent = sslab + reservelen;
00892         scount = *scurrent++ * 256;
00893         scount += *scurrent++;
00894         INSIST(mcount > 0 && scount > 0);
00895 
00896         /*
00897          * Yes, this is inefficient!
00898          */
00899 
00900         /*
00901          * Start figuring out the target length and count.
00902          */
00903         tlength = reservelen + 2;
00904         tcount = 0;
00905         rcount = 0;
00906 
00907 #if DNS_RDATASET_FIXED
00908         mcurrent += 4 * mcount;
00909         scurrent += 4 * scount;
00910 #endif
00911         sstart = scurrent;
00912 
00913         /*
00914          * Add in the length of rdata in the mslab that aren't in
00915          * the sslab.
00916          */
00917         for (i = 0; i < mcount; i++) {
00918                 unsigned char *mrdatabegin = mcurrent;
00919                 rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
00920                 scurrent = sstart;
00921                 for (count = 0; count < scount; count++) {
00922                         dns_rdata_reset(&srdata);
00923                         rdata_from_slab(&scurrent, rdclass, type, &srdata);
00924                         if (dns_rdata_compare(&mrdata, &srdata) == 0)
00925                                 break;
00926                 }
00927                 if (count == scount) {
00928                         /*
00929                          * This rdata isn't in the sslab, and thus isn't
00930                          * being subtracted.
00931                          */
00932                         tlength += (unsigned int)(mcurrent - mrdatabegin);
00933                         tcount++;
00934                 } else
00935                         rcount++;
00936                 dns_rdata_reset(&mrdata);
00937         }
00938 
00939 #if DNS_RDATASET_FIXED
00940         tlength += (4 * tcount);
00941 #endif
00942 
00943         /*
00944          * Check that all the records originally existed.  The numeric
00945          * check only works as rdataslabs do not contain duplicates.
00946          */
00947         if (((flags & DNS_RDATASLAB_EXACT) != 0) && (rcount != scount))
00948                 return (DNS_R_NOTEXACT);
00949 
00950         /*
00951          * Don't continue if the new rdataslab would be empty.
00952          */
00953         if (tcount == 0)
00954                 return (DNS_R_NXRRSET);
00955 
00956         /*
00957          * If nothing is going to change, we can stop.
00958          */
00959         if (rcount == 0)
00960                 return (DNS_R_UNCHANGED);
00961 
00962         /*
00963          * Copy the reserved area from the mslab.
00964          */
00965         tstart = isc_mem_get(mctx, tlength);
00966         if (tstart == NULL)
00967                 return (ISC_R_NOMEMORY);
00968         memmove(tstart, mslab, reservelen);
00969         tcurrent = tstart + reservelen;
00970 #if DNS_RDATASET_FIXED
00971         offsetbase = tcurrent;
00972 
00973         offsettable = isc_mem_get(mctx, mcount * sizeof(unsigned int));
00974         if (offsettable == NULL) {
00975                 isc_mem_put(mctx, tstart, tlength);
00976                 return (ISC_R_NOMEMORY);
00977         }
00978         memset(offsettable, 0, mcount * sizeof(unsigned int));
00979 #endif
00980 
00981         /*
00982          * Write the new count.
00983          */
00984         *tcurrent++ = (tcount & 0xff00) >> 8;
00985         *tcurrent++ = (tcount & 0x00ff);
00986 
00987 #if DNS_RDATASET_FIXED
00988         tcurrent += (4 * tcount);
00989 #endif
00990 
00991         /*
00992          * Copy the parts of mslab not in sslab.
00993          */
00994         mcurrent = mslab + reservelen;
00995         mcount = *mcurrent++ * 256;
00996         mcount += *mcurrent++;
00997 #if DNS_RDATASET_FIXED
00998         mcurrent += (4 * mcount);
00999 #endif
01000         for (i = 0; i < mcount; i++) {
01001                 unsigned char *mrdatabegin = mcurrent;
01002 #if DNS_RDATASET_FIXED
01003                 order = mcurrent[2] * 256 + mcurrent[3];
01004                 INSIST(order < mcount);
01005 #endif
01006                 rdata_from_slab(&mcurrent, rdclass, type, &mrdata);
01007                 scurrent = sstart;
01008                 for (count = 0; count < scount; count++) {
01009                         dns_rdata_reset(&srdata);
01010                         rdata_from_slab(&scurrent, rdclass, type, &srdata);
01011                         if (dns_rdata_compare(&mrdata, &srdata) == 0)
01012                                 break;
01013                 }
01014                 if (count == scount) {
01015                         /*
01016                          * This rdata isn't in the sslab, and thus should be
01017                          * copied to the tslab.
01018                          */
01019                         unsigned int length;
01020                         length = (unsigned int)(mcurrent - mrdatabegin);
01021 #if DNS_RDATASET_FIXED
01022                         offsettable[order] = tcurrent - offsetbase;
01023 #endif
01024                         memmove(tcurrent, mrdatabegin, length);
01025                         tcurrent += length;
01026                 }
01027                 dns_rdata_reset(&mrdata);
01028         }
01029 
01030 #if DNS_RDATASET_FIXED
01031         fillin_offsets(offsetbase, offsettable, mcount);
01032 
01033         isc_mem_put(mctx, offsettable, mcount * sizeof(unsigned int));
01034 #endif
01035 
01036         INSIST(tcurrent == tstart + tlength);
01037 
01038         *tslabp = tstart;
01039 
01040         return (ISC_R_SUCCESS);
01041 }
01042 
01043 isc_boolean_t
01044 dns_rdataslab_equal(unsigned char *slab1, unsigned char *slab2,
01045                     unsigned int reservelen)
01046 {
01047         unsigned char *current1, *current2;
01048         unsigned int count1, count2;
01049         unsigned int length1, length2;
01050 
01051         current1 = slab1 + reservelen;
01052         count1 = *current1++ * 256;
01053         count1 += *current1++;
01054 
01055         current2 = slab2 + reservelen;
01056         count2 = *current2++ * 256;
01057         count2 += *current2++;
01058 
01059         if (count1 != count2)
01060                 return (ISC_FALSE);
01061 
01062 #if DNS_RDATASET_FIXED
01063         current1 += (4 * count1);
01064         current2 += (4 * count2);
01065 #endif
01066 
01067         while (count1 > 0) {
01068                 length1 = *current1++ * 256;
01069                 length1 += *current1++;
01070 
01071                 length2 = *current2++ * 256;
01072                 length2 += *current2++;
01073 
01074 #if DNS_RDATASET_FIXED
01075                 current1 += 2;
01076                 current2 += 2;
01077 #endif
01078 
01079                 if (length1 != length2 ||
01080                     memcmp(current1, current2, length1) != 0)
01081                         return (ISC_FALSE);
01082 
01083                 current1 += length1;
01084                 current2 += length1;
01085 
01086                 count1--;
01087         }
01088         return (ISC_TRUE);
01089 }
01090 
01091 isc_boolean_t
01092 dns_rdataslab_equalx(unsigned char *slab1, unsigned char *slab2,
01093                      unsigned int reservelen, dns_rdataclass_t rdclass,
01094                      dns_rdatatype_t type)
01095 {
01096         unsigned char *current1, *current2;
01097         unsigned int count1, count2;
01098         dns_rdata_t rdata1 = DNS_RDATA_INIT;
01099         dns_rdata_t rdata2 = DNS_RDATA_INIT;
01100 
01101         current1 = slab1 + reservelen;
01102         count1 = *current1++ * 256;
01103         count1 += *current1++;
01104 
01105         current2 = slab2 + reservelen;
01106         count2 = *current2++ * 256;
01107         count2 += *current2++;
01108 
01109         if (count1 != count2)
01110                 return (ISC_FALSE);
01111 
01112 #if DNS_RDATASET_FIXED
01113         current1 += (4 * count1);
01114         current2 += (4 * count2);
01115 #endif
01116 
01117         while (count1-- > 0) {
01118                 rdata_from_slab(&current1, rdclass, type, &rdata1);
01119                 rdata_from_slab(&current2, rdclass, type, &rdata2);
01120                 if (dns_rdata_compare(&rdata1, &rdata2) != 0)
01121                         return (ISC_FALSE);
01122                 dns_rdata_reset(&rdata1);
01123                 dns_rdata_reset(&rdata2);
01124         }
01125         return (ISC_TRUE);
01126 }

Generated on Tue Apr 28 17:41:00 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha