Coverage Report

Created: 2025-08-26 06:59

/src/bind9/lib/dns/rdataslab.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <ctype.h>
17
#include <stdbool.h>
18
#include <stdlib.h>
19
20
#include <isc/ascii.h>
21
#include <isc/atomic.h>
22
#include <isc/mem.h>
23
#include <isc/region.h>
24
#include <isc/result.h>
25
#include <isc/string.h>
26
#include <isc/util.h>
27
28
#include <dns/db.h>
29
#include <dns/rdata.h>
30
#include <dns/rdataset.h>
31
#include <dns/rdataslab.h>
32
#include <dns/stats.h>
33
34
#include "rdataslab_p.h"
35
36
/*
37
 * The memory structure of an rdataslab is as follows:
38
 *
39
 *  header    (dns_slabheader_t)
40
 *  record count  (2 bytes)
41
 *  data records
42
 *    data length (2 bytes)
43
 *    order   (2 bytes)
44
 *    meta data (1 byte for RRSIG, 0 for all other types)
45
 *    data    (data length bytes)
46
 *
47
 * A "bare" rdataslab is everything after "header".
48
 *
49
 * When a slab is created, data records are sorted into DNSSEC order.
50
 */
51
52
static void
53
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
54
static isc_result_t
55
rdataset_first(dns_rdataset_t *rdataset);
56
static isc_result_t
57
rdataset_next(dns_rdataset_t *rdataset);
58
static void
59
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
60
static void
61
rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG);
62
static unsigned int
63
rdataset_count(dns_rdataset_t *rdataset);
64
static isc_result_t
65
rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
66
        dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG);
67
static isc_result_t
68
rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
69
        dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG);
70
static void
71
rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
72
static void
73
rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG);
74
static void
75
rdataset_clearprefetch(dns_rdataset_t *rdataset);
76
static void
77
rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name);
78
static void
79
rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name);
80
static dns_slabheader_t *
81
rdataset_getheader(const dns_rdataset_t *rdataset);
82
static bool
83
rdataset_equals(const dns_rdataset_t *rdataset1,
84
    const dns_rdataset_t *rdataset2);
85
86
dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods = {
87
  .disassociate = rdataset_disassociate,
88
  .first = rdataset_first,
89
  .next = rdataset_next,
90
  .current = rdataset_current,
91
  .clone = rdataset_clone,
92
  .count = rdataset_count,
93
  .getnoqname = rdataset_getnoqname,
94
  .getclosest = rdataset_getclosest,
95
  .settrust = rdataset_settrust,
96
  .expire = rdataset_expire,
97
  .clearprefetch = rdataset_clearprefetch,
98
  .setownercase = rdataset_setownercase,
99
  .getownercase = rdataset_getownercase,
100
  .getheader = rdataset_getheader,
101
  .equals = rdataset_equals,
102
};
103
104
/*% Note: the "const void *" are just to make qsort happy.  */
105
static int
106
908k
compare_rdata(const void *p1, const void *p2) {
107
908k
  return dns_rdata_compare(p1, p2);
108
908k
}
109
110
static isc_result_t
111
makeslab(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
112
8.51M
   uint32_t maxrrperset) {
113
  /*
114
   * Use &removed as a sentinel pointer for duplicate
115
   * rdata as rdata.data == NULL is valid.
116
   */
117
8.51M
  static unsigned char removed;
118
8.51M
  dns_rdata_t *rdata = NULL;
119
8.51M
  unsigned char *rawbuf = NULL;
120
8.51M
  unsigned int headerlen = sizeof(dns_slabheader_t);
121
8.51M
  unsigned int buflen = headerlen + 2;
122
8.51M
  isc_result_t result;
123
8.51M
  unsigned int nitems;
124
8.51M
  unsigned int nalloc;
125
8.51M
  unsigned int length;
126
8.51M
  size_t i;
127
8.51M
  size_t rdatasize;
128
129
  /*
130
   * If the source rdataset is also a slab, we don't need
131
   * to do anything special, just copy the whole slab to a
132
   * new buffer.
133
   */
134
8.51M
  if (rdataset->methods == &dns_rdataslab_rdatasetmethods) {
135
0
    dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
136
0
    buflen = dns_rdataslab_size(header);
137
138
0
    rawbuf = isc_mem_get(mctx, buflen);
139
0
    region->base = rawbuf;
140
0
    region->length = buflen;
141
142
0
    memmove(rawbuf, header, buflen);
143
0
    return ISC_R_SUCCESS;
144
0
  }
145
146
  /*
147
   * If there are no rdata then we just need to allocate a header
148
   * with a zero record count.
149
   */
150
8.51M
  nitems = dns_rdataset_count(rdataset);
151
8.51M
  if (nitems == 0) {
152
0
    if (rdataset->type != 0) {
153
0
      return ISC_R_FAILURE;
154
0
    }
155
0
    rawbuf = isc_mem_get(mctx, buflen);
156
0
    region->base = rawbuf;
157
0
    region->length = buflen;
158
0
    rawbuf += headerlen;
159
0
    put_uint16(rawbuf, 0);
160
0
    return ISC_R_SUCCESS;
161
0
  }
162
163
8.51M
  if (maxrrperset > 0 && nitems > maxrrperset) {
164
0
    return DNS_R_TOOMANYRECORDS;
165
0
  }
166
167
8.51M
  if (nitems > 0xffff) {
168
0
    return ISC_R_NOSPACE;
169
0
  }
170
171
  /*
172
   * Remember the original number of items.
173
   */
174
8.51M
  nalloc = nitems;
175
176
8.51M
  RUNTIME_CHECK(!ISC_OVERFLOW_MUL(nalloc, sizeof(rdata[0]), &rdatasize));
177
8.51M
  rdata = isc_mem_get(mctx, rdatasize);
178
179
  /*
180
   * Save all of the rdata members into an array.
181
   */
182
8.51M
  result = dns_rdataset_first(rdataset);
183
8.51M
  if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) {
184
0
    goto free_rdatas;
185
0
  }
186
17.1M
  for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) {
187
8.67M
    INSIST(result == ISC_R_SUCCESS);
188
8.67M
    dns_rdata_init(&rdata[i]);
189
8.67M
    dns_rdataset_current(rdataset, &rdata[i]);
190
8.67M
    INSIST(rdata[i].data != &removed);
191
8.67M
    result = dns_rdataset_next(rdataset);
192
8.67M
  }
193
8.51M
  if (i != nalloc || result != ISC_R_NOMORE) {
194
    /*
195
     * Somehow we iterated over fewer rdatas than
196
     * dns_rdataset_count() said there were or there
197
     * were more items than dns_rdataset_count said
198
     * there were.
199
     */
200
0
    result = ISC_R_FAILURE;
201
0
    goto free_rdatas;
202
0
  }
203
204
  /*
205
   * Put into DNSSEC order.
206
   */
207
8.51M
  if (nalloc > 1U) {
208
12.7k
    qsort(rdata, nalloc, sizeof(rdata[0]), compare_rdata);
209
12.7k
  }
210
211
  /*
212
   * Remove duplicates and compute the total storage required.
213
   *
214
   * If an rdata is not a duplicate, accumulate the storage size
215
   * required for the rdata.  We do not store the class, type, etc,
216
   * just the rdata, so our overhead is 2 bytes for the number of
217
   * records, and 2 bytes for the length of each rdata, plus the
218
   * rdata itself.
219
   */
220
8.67M
  for (i = 1; i < nalloc; i++) {
221
164k
    if (compare_rdata(&rdata[i - 1], &rdata[i]) == 0) {
222
151k
      rdata[i - 1].data = &removed;
223
151k
      nitems--;
224
151k
    } else {
225
12.7k
      buflen += (2 + rdata[i - 1].length);
226
      /*
227
       * Provide space to store the per RR meta data.
228
       */
229
12.7k
      if (rdataset->type == dns_rdatatype_rrsig) {
230
2.11k
        buflen++;
231
2.11k
      }
232
12.7k
    }
233
164k
  }
234
235
  /*
236
   * Don't forget the last item!
237
   */
238
8.51M
  buflen += (2 + rdata[i - 1].length);
239
240
  /*
241
   * Provide space to store the per RR meta data.
242
   */
243
8.51M
  if (rdataset->type == dns_rdatatype_rrsig) {
244
9.31k
    buflen++;
245
9.31k
  }
246
247
  /*
248
   * Ensure that singleton types are actually singletons.
249
   */
250
8.51M
  if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) {
251
    /*
252
     * We have a singleton type, but there's more than one
253
     * RR in the rdataset.
254
     */
255
51
    result = DNS_R_SINGLETON;
256
51
    goto free_rdatas;
257
51
  }
258
259
  /*
260
   * Allocate the memory, set up a buffer, start copying in
261
   * data.
262
   */
263
8.51M
  rawbuf = isc_mem_get(mctx, buflen);
264
265
8.51M
  region->base = rawbuf;
266
8.51M
  region->length = buflen;
267
8.51M
  rawbuf += headerlen;
268
8.51M
  put_uint16(rawbuf, nitems);
269
270
17.1M
  for (i = 0; i < nalloc; i++) {
271
8.67M
    if (rdata[i].data == &removed) {
272
150k
      continue;
273
150k
    }
274
8.52M
    length = rdata[i].length;
275
8.52M
    if (rdataset->type == dns_rdatatype_rrsig) {
276
11.4k
      length++;
277
11.4k
    }
278
8.52M
    INSIST(length <= 0xffff);
279
280
8.52M
    put_uint16(rawbuf, length);
281
282
    /*
283
     * Store the per RR meta data.
284
     */
285
8.52M
    if (rdataset->type == dns_rdatatype_rrsig) {
286
11.4k
      *rawbuf++ = (rdata[i].flags & DNS_RDATA_OFFLINE)
287
11.4k
              ? DNS_RDATASLAB_OFFLINE
288
11.4k
              : 0;
289
11.4k
    }
290
8.52M
    if (rdata[i].length != 0) {
291
8.52M
      memmove(rawbuf, rdata[i].data, rdata[i].length);
292
8.52M
    }
293
8.52M
    rawbuf += rdata[i].length;
294
8.52M
  }
295
296
8.51M
  result = ISC_R_SUCCESS;
297
298
8.51M
free_rdatas:
299
8.51M
  isc_mem_put(mctx, rdata, rdatasize);
300
8.51M
  return result;
301
8.51M
}
302
303
isc_result_t
304
dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
305
8.51M
         isc_region_t *region, uint32_t maxrrperset) {
306
8.51M
  isc_result_t result;
307
308
8.51M
  if (rdataset->type == dns_rdatatype_none &&
309
8.51M
      rdataset->covers == dns_rdatatype_none)
310
0
  {
311
0
    return DNS_R_DISALLOWED;
312
0
  }
313
314
8.51M
  result = makeslab(rdataset, mctx, region, maxrrperset);
315
8.51M
  if (result == ISC_R_SUCCESS) {
316
8.51M
    dns_slabheader_t *new = (dns_slabheader_t *)region->base;
317
8.51M
    dns_typepair_t typepair;
318
319
8.51M
    if (rdataset->attributes.negative) {
320
0
      INSIST(rdataset->type == dns_rdatatype_none);
321
0
      INSIST(rdataset->covers != dns_rdatatype_none);
322
0
      typepair = DNS_TYPEPAIR_VALUE(rdataset->covers,
323
0
                  dns_rdatatype_none);
324
8.51M
    } else {
325
8.51M
      INSIST(rdataset->type != dns_rdatatype_none);
326
8.51M
      INSIST(dns_rdatatype_issig(rdataset->type) ||
327
8.51M
             rdataset->covers == dns_rdatatype_none);
328
8.51M
      typepair = DNS_TYPEPAIR_VALUE(rdataset->type,
329
8.51M
                  rdataset->covers);
330
8.51M
    }
331
332
8.51M
    *new = (dns_slabheader_t){
333
8.51M
      .typepair = typepair,
334
8.51M
      .trust = rdataset->trust,
335
8.51M
      .ttl = rdataset->ttl,
336
8.51M
    };
337
8.51M
  }
338
339
8.51M
  return result;
340
8.51M
}
341
342
unsigned int
343
16.2M
dns_rdataslab_size(dns_slabheader_t *header) {
344
16.2M
  REQUIRE(header != NULL);
345
346
16.2M
  unsigned char *slab = (unsigned char *)header +
347
16.2M
            sizeof(dns_slabheader_t);
348
16.2M
  INSIST(slab != NULL);
349
350
16.2M
  unsigned char *current = slab;
351
16.2M
  uint16_t count = get_uint16(current);
352
353
148M
  while (count-- > 0) {
354
132M
    uint16_t length = get_uint16(current);
355
132M
    current += length;
356
132M
  }
357
358
16.2M
  return (unsigned int)(current - slab) + sizeof(dns_slabheader_t);
359
16.2M
}
360
361
unsigned int
362
7.59M
dns_rdataslab_count(dns_slabheader_t *header) {
363
7.59M
  REQUIRE(header != NULL);
364
365
7.59M
  unsigned char *current = (unsigned char *)header + sizeof(*header);
366
7.59M
  uint16_t count = get_uint16(current);
367
368
7.59M
  return count;
369
7.59M
}
370
371
/*
372
 * Make the dns_rdata_t 'rdata' refer to the slab item
373
 * beginning at '*current' (which is part of a slab of type
374
 * 'type' and class 'rdclass') and advance '*current' to
375
 * point to the next item in the slab.
376
 */
377
static void
378
rdata_from_slabitem(unsigned char **current, dns_rdataclass_t rdclass,
379
45.4M
        dns_rdatatype_t type, dns_rdata_t *rdata) {
380
45.4M
  unsigned char *tcurrent = *current;
381
45.4M
  isc_region_t region;
382
45.4M
  bool offline = false;
383
45.4M
  uint16_t length = get_uint16(tcurrent);
384
385
45.4M
  if (type == dns_rdatatype_rrsig) {
386
23.2k
    if ((*tcurrent & DNS_RDATASLAB_OFFLINE) != 0) {
387
0
      offline = true;
388
0
    }
389
23.2k
    length--;
390
23.2k
    tcurrent++;
391
23.2k
  }
392
45.4M
  region.length = length;
393
45.4M
  region.base = tcurrent;
394
45.4M
  tcurrent += region.length;
395
45.4M
  dns_rdata_fromregion(rdata, rdclass, type, &region);
396
45.4M
  if (offline) {
397
0
    rdata->flags |= DNS_RDATA_OFFLINE;
398
0
  }
399
45.4M
  *current = tcurrent;
400
45.4M
}
401
402
static void
403
rdata_to_slabitem(unsigned char **current, dns_rdatatype_t type,
404
38.7M
      dns_rdata_t *rdata) {
405
38.7M
  unsigned int length = rdata->length;
406
38.7M
  unsigned char *data = rdata->data;
407
38.7M
  unsigned char *p = *current;
408
409
38.7M
  if (type == dns_rdatatype_rrsig) {
410
4.91k
    length++;
411
4.91k
    data--;
412
4.91k
  }
413
414
38.7M
  put_uint16(p, length);
415
38.7M
  memmove(p, data, length);
416
38.7M
  p += length;
417
418
38.7M
  *current = p;
419
38.7M
}
420
421
typedef struct slabinfo {
422
  unsigned char *pos;
423
  dns_rdata_t rdata;
424
  bool dup;
425
} slabinfo_t;
426
427
isc_result_t
428
dns_rdataslab_merge(dns_slabheader_t *oheader, dns_slabheader_t *nheader,
429
        isc_mem_t *mctx, dns_rdataclass_t rdclass,
430
        dns_rdatatype_t type, unsigned int flags,
431
1.13M
        uint32_t maxrrperset, dns_slabheader_t **theaderp) {
432
1.13M
  isc_result_t result = ISC_R_SUCCESS;
433
1.13M
  unsigned char *ocurrent = NULL, *ncurrent = NULL, *tcurrent = NULL;
434
1.13M
  unsigned int ocount, ncount, tlength, tcount = 0;
435
1.13M
  slabinfo_t *oinfo = NULL, *ninfo = NULL;
436
1.13M
  size_t o = 0, n = 0;
437
438
1.13M
  REQUIRE(theaderp != NULL && *theaderp == NULL);
439
1.13M
  REQUIRE(oheader != NULL && nheader != NULL);
440
441
1.13M
  ocurrent = (unsigned char *)oheader + sizeof(dns_slabheader_t);
442
1.13M
  ocount = get_uint16(ocurrent);
443
444
1.13M
  ncurrent = (unsigned char *)nheader + sizeof(dns_slabheader_t);
445
1.13M
  ncount = get_uint16(ncurrent);
446
447
1.13M
  INSIST(ocount > 0 && ncount > 0);
448
449
1.13M
  if (maxrrperset > 0 && ocount + ncount > maxrrperset) {
450
0
    return DNS_R_TOOMANYRECORDS;
451
0
  }
452
453
  /*
454
   * Figure out the target length. Start with the header,
455
   * plus 2 octets for the count.
456
   */
457
1.13M
  tlength = sizeof(dns_slabheader_t) + 2;
458
459
  /*
460
   * Gather the rdatas in the old slab and add their lengths to
461
   * the larget length.
462
   */
463
1.13M
  oinfo = isc_mem_cget(mctx, ocount, sizeof(struct slabinfo));
464
45.4M
  for (size_t i = 0; i < ocount; i++) {
465
44.3M
    oinfo[i].pos = ocurrent;
466
44.3M
    dns_rdata_init(&oinfo[i].rdata);
467
44.3M
    rdata_from_slabitem(&ocurrent, rdclass, type, &oinfo[i].rdata);
468
44.3M
    tlength += ocurrent - oinfo[i].pos;
469
44.3M
  }
470
471
  /*
472
   * Then add the length of rdatas in the new slab that aren't
473
   * duplicated in the old slab.
474
   */
475
1.13M
  ninfo = isc_mem_cget(mctx, ncount, sizeof(struct slabinfo));
476
2.28M
  for (size_t i = 0; i < ncount; i++) {
477
1.14M
    ninfo[i].pos = ncurrent;
478
1.14M
    dns_rdata_init(&ninfo[i].rdata);
479
1.14M
    rdata_from_slabitem(&ncurrent, rdclass, type, &ninfo[i].rdata);
480
481
42.0M
    for (size_t j = 0; j < ocount; j++) {
482
41.9M
      if (oinfo[j].dup) {
483
        /*
484
         * This was already found to be
485
         * duplicated; no need to compare
486
         * it again.
487
         */
488
12.5k
        continue;
489
12.5k
      }
490
491
41.9M
      if (dns_rdata_compare(&oinfo[j].rdata,
492
41.9M
                &ninfo[i].rdata) == 0)
493
1.03M
      {
494
        /*
495
         * Found a dup. Mark the old copy as a
496
         * duplicate so we don't check it again;
497
         * mark the new copy as a duplicate so we
498
         * don't copy it to the target.
499
         */
500
1.03M
        oinfo[j].dup = ninfo[i].dup = true;
501
1.03M
        break;
502
1.03M
      }
503
41.9M
    }
504
505
1.14M
    if (ninfo[i].dup) {
506
1.03M
      continue;
507
1.03M
    }
508
509
    /*
510
     * We will be copying this item to the target, so
511
     * add its length to tlength and increment tcount.
512
     */
513
106k
    tlength += ncurrent - ninfo[i].pos;
514
106k
    tcount++;
515
106k
  }
516
517
  /*
518
   * If the EXACT flag is set, there can't be any rdata in
519
   * the new slab that was also in the old. If tcount is less
520
   * than ncount, then we found such a duplicate.
521
   */
522
1.13M
  if (((flags & DNS_RDATASLAB_EXACT) != 0) && (tcount < ncount)) {
523
0
    result = DNS_R_NOTEXACT;
524
0
    goto cleanup;
525
0
  }
526
527
  /*
528
   * If nothing's being copied in from the new slab, and the
529
   * FORCE flag isn't set, we're done.
530
   */
531
1.13M
  if (tcount == 0 && (flags & DNS_RDATASLAB_FORCE) == 0) {
532
1.02M
    result = DNS_R_UNCHANGED;
533
1.02M
    goto cleanup;
534
1.02M
  }
535
536
  /* Add to tcount the total number of items from the old slab. */
537
111k
  tcount += ocount;
538
539
  /* Resposition ncurrent at the first item. */
540
111k
  ncurrent = (unsigned char *)nheader + sizeof(dns_slabheader_t) + 2;
541
542
  /* Single types can't have more than one RR. */
543
111k
  if (tcount > 1 && dns_rdatatype_issingleton(type)) {
544
10
    result = DNS_R_SINGLETON;
545
10
    goto cleanup;
546
10
  }
547
548
111k
  if (tcount > 0xffff) {
549
0
    result = ISC_R_NOSPACE;
550
0
    goto cleanup;
551
0
  }
552
553
  /* Allocate the target buffer and copy the new slab's header */
554
111k
  unsigned char *tstart = isc_mem_get(mctx, tlength);
555
556
111k
  memmove(tstart, nheader, sizeof(dns_slabheader_t));
557
111k
  tcurrent = tstart + sizeof(dns_slabheader_t);
558
559
  /* Write the new count, then start merging the slabs. */
560
111k
  put_uint16(tcurrent, tcount);
561
562
  /*
563
   * Now walk the sets together, adding each item in DNSSEC order,
564
   * and skipping over any more dups in the new slab.
565
   */
566
38.8M
  while (o < ocount || n < ncount) {
567
38.7M
    bool fromold;
568
569
    /* Skip to the next non-duplicate in the new slab. */
570
38.7M
    for (; n < ncount && ninfo[n].dup; n++)
571
7.83k
      ;
572
573
38.7M
    if (o == ocount) {
574
90.9k
      fromold = false;
575
38.6M
    } else if (n == ncount) {
576
2.66M
      fromold = true;
577
36.0M
    } else {
578
36.0M
      fromold = dns_rdata_compare(&oinfo[o].rdata,
579
36.0M
                &ninfo[n].rdata) < 0;
580
36.0M
    }
581
582
38.7M
    if (fromold) {
583
38.6M
      rdata_to_slabitem(&tcurrent, type, &oinfo[o].rdata);
584
38.6M
      if (++o < ocount) {
585
        /* Skip to the next rdata in the old slab */
586
38.5M
        continue;
587
38.5M
      }
588
38.6M
    } else {
589
106k
      rdata_to_slabitem(&tcurrent, type, &ninfo[n++].rdata);
590
106k
    }
591
38.7M
  }
592
593
111k
  INSIST(tcurrent == tstart + tlength);
594
595
111k
  *theaderp = (dns_slabheader_t *)tstart;
596
597
1.13M
cleanup:
598
1.13M
  isc_mem_cput(mctx, oinfo, ocount, sizeof(struct slabinfo));
599
1.13M
  isc_mem_cput(mctx, ninfo, ncount, sizeof(struct slabinfo));
600
601
1.13M
  return result;
602
111k
}
603
604
isc_result_t
605
dns_rdataslab_subtract(dns_slabheader_t *oheader, dns_slabheader_t *sheader,
606
           isc_mem_t *mctx, dns_rdataclass_t rdclass,
607
           dns_rdatatype_t type, unsigned int flags,
608
0
           dns_slabheader_t **theaderp) {
609
0
  isc_result_t result = ISC_R_SUCCESS;
610
0
  unsigned char *ocurrent = NULL, *scurrent = NULL;
611
0
  unsigned char *tstart = NULL, *tcurrent = NULL;
612
0
  unsigned int ocount, scount, tlength;
613
0
  unsigned int tcount = 0, rcount = 0;
614
0
  slabinfo_t *oinfo = NULL, *sinfo = NULL;
615
616
0
  REQUIRE(theaderp != NULL && *theaderp == NULL);
617
0
  REQUIRE(oheader != NULL && sheader != NULL);
618
619
0
  ocurrent = (unsigned char *)oheader + sizeof(dns_slabheader_t);
620
0
  ocount = get_uint16(ocurrent);
621
622
0
  scurrent = (unsigned char *)sheader + sizeof(dns_slabheader_t);
623
0
  scount = get_uint16(scurrent);
624
625
0
  INSIST(ocount > 0 && scount > 0);
626
627
  /* Get info about the rdatas being subtracted */
628
0
  sinfo = isc_mem_cget(mctx, scount, sizeof(struct slabinfo));
629
0
  for (size_t i = 0; i < scount; i++) {
630
0
    sinfo[i].pos = scurrent;
631
0
    dns_rdata_init(&sinfo[i].rdata);
632
0
    rdata_from_slabitem(&scurrent, rdclass, type, &sinfo[i].rdata);
633
0
  }
634
635
  /*
636
   * Figure out the target length. Start with the header,
637
   * plus 2 octets for the count.
638
   */
639
0
  tlength = sizeof(dns_slabheader_t) + 2;
640
641
  /*
642
   * Add the length of the rdatas in the old slab that
643
   * aren't being subtracted.
644
   */
645
0
  oinfo = isc_mem_cget(mctx, ocount, sizeof(struct slabinfo));
646
0
  for (size_t i = 0; i < ocount; i++) {
647
0
    bool matched = false;
648
649
0
    oinfo[i].pos = ocurrent;
650
0
    dns_rdata_init(&oinfo[i].rdata);
651
0
    rdata_from_slabitem(&ocurrent, rdclass, type, &oinfo[i].rdata);
652
653
0
    for (size_t j = 0; j < scount; j++) {
654
0
      if (sinfo[j].dup) {
655
0
        continue;
656
0
      } else if (dns_rdata_compare(&oinfo[i].rdata,
657
0
                 &sinfo[j].rdata) == 0)
658
0
      {
659
0
        matched = true;
660
0
        oinfo[i].dup = sinfo[j].dup = true;
661
0
        break;
662
0
      }
663
0
    }
664
665
0
    if (matched) {
666
      /* This item will be subtracted. */
667
0
      rcount++;
668
0
    } else {
669
      /*
670
       * This rdata wasn't in the slab to be subtracted,
671
       * so copy it to the target.  Add its length to
672
       * tlength and increment tcount.
673
       */
674
0
      tlength += ocurrent - oinfo[i].pos;
675
0
      tcount++;
676
0
    }
677
0
  }
678
679
  /*
680
   * If the EXACT flag wasn't set, check that all the records that
681
   * were to be subtracted actually did exist in the original slab.
682
   * (The numeric check works here because rdataslabs do not contain
683
   * duplicates.)
684
   */
685
0
  if ((flags & DNS_RDATASLAB_EXACT) != 0 && rcount != scount) {
686
0
    result = DNS_R_NOTEXACT;
687
0
    goto cleanup;
688
0
  }
689
690
  /*
691
   * If the resulting rdataslab would be empty, don't bother to
692
   * create a new buffer, just return.
693
   */
694
0
  if (tcount == 0) {
695
0
    result = DNS_R_NXRRSET;
696
0
    goto cleanup;
697
0
  }
698
699
  /*
700
   * If nothing is going to change, stop.
701
   */
702
0
  if (rcount == 0) {
703
0
    result = DNS_R_UNCHANGED;
704
0
    goto cleanup;
705
0
  }
706
707
  /*
708
   * Allocate the target buffer and copy the old slab's header.
709
   */
710
0
  tstart = isc_mem_get(mctx, tlength);
711
0
  memmove(tstart, oheader, sizeof(dns_slabheader_t));
712
0
  tcurrent = tstart + sizeof(dns_slabheader_t);
713
714
  /*
715
   * Write the new count.
716
   */
717
0
  put_uint16(tcurrent, tcount);
718
719
  /*
720
   * Copy the parts of the old slab that didn't have duplicates.
721
   */
722
0
  for (size_t i = 0; i < ocount; i++) {
723
0
    if (!oinfo[i].dup) {
724
0
      rdata_to_slabitem(&tcurrent, type, &oinfo[i].rdata);
725
0
    }
726
0
  }
727
728
0
  INSIST(tcurrent == tstart + tlength);
729
730
0
  *theaderp = (dns_slabheader_t *)tstart;
731
732
0
cleanup:
733
0
  isc_mem_cput(mctx, oinfo, ocount, sizeof(struct slabinfo));
734
0
  isc_mem_cput(mctx, sinfo, scount, sizeof(struct slabinfo));
735
736
0
  return result;
737
0
}
738
739
bool
740
0
dns_rdataslab_equal(dns_slabheader_t *slab1, dns_slabheader_t *slab2) {
741
0
  unsigned char *current1 = NULL, *current2 = NULL;
742
0
  unsigned int count1, count2;
743
744
0
  current1 = (unsigned char *)slab1 + sizeof(dns_slabheader_t);
745
0
  count1 = get_uint16(current1);
746
747
0
  current2 = (unsigned char *)slab2 + sizeof(dns_slabheader_t);
748
0
  count2 = get_uint16(current2);
749
750
0
  if (count1 != count2) {
751
0
    return false;
752
0
  } else if (count1 == 0) {
753
0
    return true;
754
0
  }
755
756
0
  while (count1-- > 0) {
757
0
    unsigned int length1 = get_uint16(current1);
758
0
    unsigned int length2 = get_uint16(current2);
759
760
0
    if (length1 != length2 ||
761
0
        memcmp(current1, current2, length1) != 0)
762
0
    {
763
0
      return false;
764
0
    }
765
766
0
    current1 += length1;
767
0
    current2 += length1;
768
0
  }
769
0
  return true;
770
0
}
771
772
bool
773
dns_rdataslab_equalx(dns_slabheader_t *slab1, dns_slabheader_t *slab2,
774
0
         dns_rdataclass_t rdclass, dns_rdatatype_t type) {
775
0
  unsigned char *current1 = NULL, *current2 = NULL;
776
0
  unsigned int count1, count2;
777
778
0
  current1 = (unsigned char *)slab1 + sizeof(dns_slabheader_t);
779
0
  count1 = get_uint16(current1);
780
781
0
  current2 = (unsigned char *)slab2 + sizeof(dns_slabheader_t);
782
0
  count2 = get_uint16(current2);
783
784
0
  if (count1 != count2) {
785
0
    return false;
786
0
  } else if (count1 == 0) {
787
0
    return true;
788
0
  }
789
790
0
  while (count1-- > 0) {
791
0
    dns_rdata_t rdata1 = DNS_RDATA_INIT;
792
0
    dns_rdata_t rdata2 = DNS_RDATA_INIT;
793
794
0
    rdata_from_slabitem(&current1, rdclass, type, &rdata1);
795
0
    rdata_from_slabitem(&current2, rdclass, type, &rdata2);
796
0
    if (dns_rdata_compare(&rdata1, &rdata2) != 0) {
797
0
      return false;
798
0
    }
799
0
  }
800
0
  return true;
801
0
}
802
803
void
804
8.51M
dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name) {
805
8.51M
  REQUIRE(!CASESET(header));
806
807
8.51M
  bool casefullylower = true;
808
809
  /*
810
   * We do not need to worry about label lengths as they are all
811
   * less than or equal to 63.
812
   */
813
8.51M
  memset(header->upper, 0, sizeof(header->upper));
814
132M
  for (size_t i = 0; i < name->length; i++) {
815
123M
    if (isupper(name->ndata[i])) {
816
6.48M
      header->upper[i / 8] |= 1 << (i % 8);
817
6.48M
      casefullylower = false;
818
6.48M
    }
819
123M
  }
820
8.51M
  if (casefullylower) {
821
5.65M
    DNS_SLABHEADER_SETATTR(header,
822
5.65M
               DNS_SLABHEADERATTR_CASEFULLYLOWER);
823
5.65M
  }
824
8.51M
  DNS_SLABHEADER_SETATTR(header, DNS_SLABHEADERATTR_CASESET);
825
8.51M
}
826
827
void
828
111k
dns_slabheader_copycase(dns_slabheader_t *dest, dns_slabheader_t *src) {
829
111k
  REQUIRE(!CASESET(dest));
830
111k
  if (CASESET(src)) {
831
111k
    memmove(dest->upper, src->upper, sizeof(src->upper));
832
111k
    if (CASEFULLYLOWER(src)) {
833
59.1k
      DNS_SLABHEADER_SETATTR(
834
59.1k
        dest, DNS_SLABHEADERATTR_CASEFULLYLOWER);
835
59.1k
    }
836
111k
    DNS_SLABHEADER_SETATTR(dest, DNS_SLABHEADERATTR_CASESET);
837
111k
  }
838
111k
}
839
840
void
841
8.62M
dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node) {
842
8.62M
  h->heap_index = 0;
843
8.62M
  h->heap = NULL;
844
8.62M
  h->node = node;
845
846
8.62M
  atomic_init(&h->attributes, 0);
847
8.62M
  atomic_init(&h->last_refresh_fail_ts, 0);
848
849
8.62M
  STATIC_ASSERT(sizeof(h->attributes) == 2,
850
8.62M
          "The .attributes field of dns_slabheader_t needs to be "
851
8.62M
          "16-bit int type exactly.");
852
8.62M
}
853
854
dns_slabheader_t *
855
0
dns_slabheader_new(isc_mem_t *mctx, dns_dbnode_t *node) {
856
0
  dns_slabheader_t *h = NULL;
857
858
0
  h = isc_mem_get(mctx, sizeof(*h));
859
0
  *h = (dns_slabheader_t){
860
0
    .node = node,
861
0
  };
862
0
  return h;
863
0
}
864
865
void
866
8.62M
dns_slabheader_destroy(dns_slabheader_t **headerp) {
867
8.62M
  unsigned int size;
868
8.62M
  dns_slabheader_t *header = *headerp;
869
870
8.62M
  *headerp = NULL;
871
872
8.62M
  isc_mem_t *mctx = header->node->mctx;
873
8.62M
  dns_db_deletedata(header->node, header);
874
875
8.62M
  if (EXISTS(header)) {
876
8.62M
    size = dns_rdataslab_size(header);
877
8.62M
  } else {
878
316
    size = sizeof(*header);
879
316
  }
880
881
8.62M
  isc_mem_put(mctx, header, size);
882
8.62M
}
883
884
void
885
0
dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proofp) {
886
0
  unsigned int buflen;
887
0
  uint8_t *rawbuf;
888
0
  dns_slabheader_proof_t *proof = *proofp;
889
0
  *proofp = NULL;
890
891
0
  if (dns_name_dynamic(&proof->name)) {
892
0
    dns_name_free(&proof->name, mctx);
893
0
  }
894
0
  if (proof->neg != NULL) {
895
0
    rawbuf = proof->neg;
896
0
    rawbuf -= sizeof(dns_slabheader_t);
897
0
    buflen = dns_rdataslab_size((dns_slabheader_t *)rawbuf);
898
899
0
    isc_mem_put(mctx, rawbuf, buflen);
900
0
  }
901
0
  if (proof->negsig != NULL) {
902
0
    rawbuf = proof->negsig;
903
0
    rawbuf -= sizeof(dns_slabheader_t);
904
0
    buflen = dns_rdataslab_size((dns_slabheader_t *)rawbuf);
905
906
0
    isc_mem_put(mctx, rawbuf, buflen);
907
0
  }
908
0
  isc_mem_put(mctx, proof, sizeof(*proof));
909
0
}
910
911
/* Fixed RRSet helper macros */
912
913
static void
914
180
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
915
180
  dns_dbnode_t *node = rdataset->slab.node;
916
917
180
  dns__db_detachnode(&node DNS__DB_FLARG_PASS);
918
180
}
919
920
static isc_result_t
921
174
rdataset_first(dns_rdataset_t *rdataset) {
922
174
  unsigned char *raw = rdataset->slab.raw;
923
174
  uint16_t count = peek_uint16(raw);
924
174
  if (count == 0) {
925
0
    rdataset->slab.iter_pos = NULL;
926
0
    rdataset->slab.iter_count = 0;
927
0
    return ISC_R_NOMORE;
928
0
  }
929
930
  /*
931
   * iter_count is the number of rdata beyond the cursor
932
   * position, so we decrement the total count by one before
933
   * storing it.
934
   *
935
   * 'raw' points to the first record.
936
   */
937
174
  rdataset->slab.iter_pos = raw + sizeof(uint16_t);
938
174
  rdataset->slab.iter_count = count - 1;
939
940
174
  return ISC_R_SUCCESS;
941
174
}
942
943
static isc_result_t
944
196
rdataset_next(dns_rdataset_t *rdataset) {
945
196
  uint16_t count = rdataset->slab.iter_count;
946
196
  if (count == 0) {
947
148
    rdataset->slab.iter_pos = NULL;
948
148
    return ISC_R_NOMORE;
949
148
  }
950
48
  rdataset->slab.iter_count = count - 1;
951
952
  /*
953
   * Skip forward one record (length + 4) or one offset (4).
954
   */
955
48
  unsigned char *raw = rdataset->slab.iter_pos;
956
48
  uint16_t length = peek_uint16(raw);
957
48
  raw += length;
958
48
  rdataset->slab.iter_pos = raw + sizeof(uint16_t);
959
960
48
  return ISC_R_SUCCESS;
961
196
}
962
963
static void
964
222
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
965
222
  unsigned char *raw = NULL;
966
222
  unsigned int length;
967
222
  isc_region_t r;
968
222
  unsigned int flags = 0;
969
970
222
  raw = rdataset->slab.iter_pos;
971
222
  REQUIRE(raw != NULL);
972
973
  /*
974
   * Find the start of the record if not already in iter_pos
975
   * then skip the length and order fields.
976
   */
977
222
  length = get_uint16(raw);
978
979
222
  if (rdataset->type == dns_rdatatype_rrsig) {
980
0
    if (*raw & DNS_RDATASLAB_OFFLINE) {
981
0
      flags |= DNS_RDATA_OFFLINE;
982
0
    }
983
0
    length--;
984
0
    raw++;
985
0
  }
986
222
  r.length = length;
987
222
  r.base = raw;
988
222
  dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
989
222
  rdata->flags |= flags;
990
222
}
991
992
static void
993
0
rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) {
994
0
  dns_dbnode_t *node = source->slab.node;
995
0
  dns_dbnode_t *cloned_node = NULL;
996
997
0
  dns__db_attachnode(node, &cloned_node DNS__DB_FLARG_PASS);
998
0
  INSIST(!ISC_LINK_LINKED(target, link));
999
0
  *target = *source;
1000
0
  ISC_LINK_INIT(target, link);
1001
1002
0
  target->slab.iter_pos = NULL;
1003
0
  target->slab.iter_count = 0;
1004
0
}
1005
1006
static unsigned int
1007
0
rdataset_count(dns_rdataset_t *rdataset) {
1008
0
  unsigned char *raw = NULL;
1009
0
  unsigned int count;
1010
1011
0
  raw = rdataset->slab.raw;
1012
0
  count = get_uint16(raw);
1013
1014
0
  return count;
1015
0
}
1016
1017
static isc_result_t
1018
rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
1019
        dns_rdataset_t *nsec,
1020
0
        dns_rdataset_t *nsecsig DNS__DB_FLARG) {
1021
0
  dns_db_t *db = rdataset->slab.db;
1022
0
  dns_dbnode_t *node = rdataset->slab.node;
1023
0
  const dns_slabheader_proof_t *noqname = rdataset->slab.noqname;
1024
1025
  /*
1026
   * Normally, rdataset->slab.raw points to the data immediately
1027
   * following a dns_slabheader in memory. Here, though, it will
1028
   * point to a bare rdataslab, a pointer to which is stored in
1029
   * the dns_slabheader's `noqname` field.
1030
   *
1031
   * The 'keepcase' attribute is set to prevent setownercase and
1032
   * getownercase methods from affecting the case of NSEC/NSEC3
1033
   * owner names.
1034
   */
1035
0
  dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1036
0
  *nsec = (dns_rdataset_t){
1037
0
    .methods = &dns_rdataslab_rdatasetmethods,
1038
0
    .rdclass = db->rdclass,
1039
0
    .type = noqname->type,
1040
0
    .ttl = rdataset->ttl,
1041
0
    .trust = rdataset->trust,
1042
0
    .slab.db = db,
1043
0
    .slab.node = node,
1044
0
    .slab.raw = noqname->neg,
1045
0
    .link = nsec->link,
1046
0
    .count = nsec->count,
1047
0
    .attributes = nsec->attributes,
1048
0
    .magic = nsec->magic,
1049
0
  };
1050
0
  nsec->attributes.keepcase = true;
1051
1052
0
  dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1053
0
  *nsecsig = (dns_rdataset_t){
1054
0
    .methods = &dns_rdataslab_rdatasetmethods,
1055
0
    .rdclass = db->rdclass,
1056
0
    .type = dns_rdatatype_rrsig,
1057
0
    .covers = noqname->type,
1058
0
    .ttl = rdataset->ttl,
1059
0
    .trust = rdataset->trust,
1060
0
    .slab.db = db,
1061
0
    .slab.node = node,
1062
0
    .slab.raw = noqname->negsig,
1063
0
    .link = nsecsig->link,
1064
0
    .count = nsecsig->count,
1065
0
    .attributes = nsecsig->attributes,
1066
0
    .magic = nsecsig->magic,
1067
0
  };
1068
0
  nsecsig->attributes.keepcase = true;
1069
1070
0
  dns_name_clone(&noqname->name, name);
1071
1072
0
  return ISC_R_SUCCESS;
1073
0
}
1074
1075
static isc_result_t
1076
rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
1077
        dns_rdataset_t *nsec,
1078
0
        dns_rdataset_t *nsecsig DNS__DB_FLARG) {
1079
0
  dns_db_t *db = rdataset->slab.db;
1080
0
  dns_dbnode_t *node = rdataset->slab.node;
1081
0
  const dns_slabheader_proof_t *closest = rdataset->slab.closest;
1082
1083
  /*
1084
   * Normally, rdataset->slab.raw points to the data immediately
1085
   * following a dns_slabheader in memory. Here, though, it will
1086
   * point to a bare rdataslab, a pointer to which is stored in
1087
   * the dns_slabheader's `closest` field.
1088
   *
1089
   * The 'keepcase' attribute is set to prevent setownercase and
1090
   * getownercase methods from affecting the case of NSEC/NSEC3
1091
   * owner names.
1092
   */
1093
0
  dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1094
0
  *nsec = (dns_rdataset_t){
1095
0
    .methods = &dns_rdataslab_rdatasetmethods,
1096
0
    .rdclass = db->rdclass,
1097
0
    .type = closest->type,
1098
0
    .ttl = rdataset->ttl,
1099
0
    .trust = rdataset->trust,
1100
0
    .slab.db = db,
1101
0
    .slab.node = node,
1102
0
    .slab.raw = closest->neg,
1103
0
    .link = nsec->link,
1104
0
    .count = nsec->count,
1105
0
    .attributes = nsec->attributes,
1106
0
    .magic = nsec->magic,
1107
0
  };
1108
0
  nsec->attributes.keepcase = true;
1109
1110
0
  dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS);
1111
0
  *nsecsig = (dns_rdataset_t){
1112
0
    .methods = &dns_rdataslab_rdatasetmethods,
1113
0
    .rdclass = db->rdclass,
1114
0
    .type = dns_rdatatype_rrsig,
1115
0
    .covers = closest->type,
1116
0
    .ttl = rdataset->ttl,
1117
0
    .trust = rdataset->trust,
1118
0
    .slab.db = db,
1119
0
    .slab.node = node,
1120
0
    .slab.raw = closest->negsig,
1121
0
    .link = nsecsig->link,
1122
0
    .count = nsecsig->count,
1123
0
    .attributes = nsecsig->attributes,
1124
0
    .magic = nsecsig->magic,
1125
0
  };
1126
0
  nsecsig->attributes.keepcase = true;
1127
1128
0
  dns_name_clone(&closest->name, name);
1129
1130
0
  return ISC_R_SUCCESS;
1131
0
}
1132
1133
static void
1134
0
rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
1135
0
  dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
1136
1137
0
  dns_db_locknode(header->node, isc_rwlocktype_write);
1138
0
  header->trust = rdataset->trust = trust;
1139
0
  dns_db_unlocknode(header->node, isc_rwlocktype_write);
1140
0
}
1141
1142
static void
1143
0
rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG) {
1144
0
  dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
1145
1146
0
  dns_db_expiredata(header->node, header);
1147
0
}
1148
1149
static void
1150
0
rdataset_clearprefetch(dns_rdataset_t *rdataset) {
1151
0
  dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
1152
1153
0
  dns_db_locknode(header->node, isc_rwlocktype_write);
1154
0
  DNS_SLABHEADER_CLRATTR(header, DNS_SLABHEADERATTR_PREFETCH);
1155
0
  dns_db_unlocknode(header->node, isc_rwlocktype_write);
1156
0
}
1157
1158
static void
1159
0
rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) {
1160
0
  dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
1161
1162
  /* The case could be set just once for the same header */
1163
0
  if (CASESET(header)) {
1164
0
    return;
1165
0
  }
1166
1167
0
  dns_db_locknode(header->node, isc_rwlocktype_write);
1168
0
  dns_slabheader_setownercase(header, name);
1169
0
  dns_db_unlocknode(header->node, isc_rwlocktype_write);
1170
0
}
1171
1172
static void
1173
0
rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
1174
0
  dns_slabheader_t *header = dns_rdataset_getheader(rdataset);
1175
0
  uint8_t mask = (1 << 7);
1176
0
  uint8_t bits = 0;
1177
1178
0
  if (!CASESET(header)) {
1179
0
    return;
1180
0
  }
1181
1182
0
  if (CASEFULLYLOWER(header)) {
1183
0
    isc_ascii_lowercopy(name->ndata, name->ndata, name->length);
1184
0
    return;
1185
0
  }
1186
1187
0
  uint8_t *nd = name->ndata;
1188
0
  for (size_t i = 0; i < name->length; i++) {
1189
0
    if (mask == (1 << 7)) {
1190
0
      bits = header->upper[i / 8];
1191
0
      mask = 1;
1192
0
    } else {
1193
0
      mask <<= 1;
1194
0
    }
1195
0
    nd[i] = (bits & mask) ? isc_ascii_toupper(nd[i])
1196
0
              : isc_ascii_tolower(nd[i]);
1197
0
  }
1198
0
}
1199
1200
static dns_slabheader_t *
1201
0
rdataset_getheader(const dns_rdataset_t *rdataset) {
1202
0
  dns_slabheader_t *header = (dns_slabheader_t *)rdataset->slab.raw;
1203
0
  return header - 1;
1204
0
}
1205
1206
static bool
1207
rdataset_equals(const dns_rdataset_t *rdataset1,
1208
0
    const dns_rdataset_t *rdataset2) {
1209
0
  if (rdataset1->rdclass != rdataset2->rdclass ||
1210
0
      rdataset1->type != rdataset2->type)
1211
0
  {
1212
0
    return false;
1213
0
  }
1214
1215
0
  dns_slabheader_t *header1 = (dns_slabheader_t *)rdataset1->slab.raw - 1;
1216
0
  dns_slabheader_t *header2 = (dns_slabheader_t *)rdataset2->slab.raw - 1;
1217
1218
0
  return dns_rdataslab_equalx(header1, header2, rdataset1->rdclass,
1219
0
            rdataset2->type);
1220
0
}
1221
1222
dns_slabtop_t *
1223
7.37M
dns_slabtop_new(isc_mem_t *mctx, dns_typepair_t typepair) {
1224
7.37M
  dns_slabtop_t *top = isc_mem_get(mctx, sizeof(*top));
1225
7.37M
  *top = (dns_slabtop_t){
1226
7.37M
    .typepair = typepair,
1227
7.37M
    .link = ISC_LINK_INITIALIZER,
1228
7.37M
  };
1229
1230
7.37M
  return top;
1231
7.37M
}
1232
1233
void
1234
7.37M
dns_slabtop_destroy(isc_mem_t *mctx, dns_slabtop_t **topp) {
1235
7.37M
  REQUIRE(topp != NULL && *topp != NULL);
1236
7.37M
  dns_slabtop_t *top = *topp;
1237
7.37M
  *topp = NULL;
1238
7.37M
  isc_mem_put(mctx, top, sizeof(*top));
1239
7.37M
}