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