Coverage Report

Created: 2026-07-16 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/rdataslab.c
Line
Count
Source
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 <stdbool.h>
17
#include <stdlib.h>
18
19
#include <isc/ascii.h>
20
#include <isc/atomic.h>
21
#include <isc/list.h>
22
#include <isc/mem.h>
23
#include <isc/region.h>
24
#include <isc/result.h>
25
#include <isc/string.h>
26
#include <isc/urcu.h>
27
#include <isc/util.h>
28
29
#include <dns/db.h>
30
#include <dns/rdata.h>
31
#include <dns/rdataset.h>
32
#include <dns/rdataslab.h>
33
#include <dns/stats.h>
34
35
#include "rdataslab_p.h"
36
37
/*
38
 * The memory structure of an rdataslab is as follows:
39
 *
40
 *  header    (dns_slabheader_t)
41
 *  record count  (2 bytes)
42
 *  data records
43
 *    data length (2 bytes)
44
 *    order   (2 bytes)
45
 *    meta data (1 byte for RRSIG, 0 for all other types)
46
 *    data    (data length bytes)
47
 *
48
 * A "bare" rdataslab is everything after "header".
49
 *
50
 * When a slab is created, data records are sorted into DNSSEC order.
51
 */
52
53
static void
54
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
55
static isc_result_t
56
rdataset_first(dns_rdataset_t *rdataset);
57
static isc_result_t
58
rdataset_next(dns_rdataset_t *rdataset);
59
static void
60
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
61
static void
62
rdataset_clone(const dns_rdataset_t *source,
63
         dns_rdataset_t *target DNS__DB_FLARG);
64
static unsigned int
65
rdataset_count(dns_rdataset_t *rdataset);
66
static isc_result_t
67
rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
68
        dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG);
69
static isc_result_t
70
rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
71
        dns_rdataset_t *neg, dns_rdataset_t *negsig DNS__DB_FLARG);
72
static void
73
rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
74
static void
75
rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG);
76
static void
77
rdataset_clearprefetch(dns_rdataset_t *rdataset);
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
83
dns_rdatasetmethods_t dns_rdataslab_rdatasetmethods = {
84
  .disassociate = rdataset_disassociate,
85
  .first = rdataset_first,
86
  .next = rdataset_next,
87
  .current = rdataset_current,
88
  .clone = rdataset_clone,
89
  .count = rdataset_count,
90
  .getnoqname = rdataset_getnoqname,
91
  .getclosest = rdataset_getclosest,
92
  .settrust = rdataset_settrust,
93
  .expire = rdataset_expire,
94
  .clearprefetch = rdataset_clearprefetch,
95
  .getownercase = rdataset_getownercase,
96
};
97
98
static void
99
slabheader_proof_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
100
static isc_result_t
101
slabheader_proof_first(dns_rdataset_t *rdataset);
102
static isc_result_t
103
slabheader_proof_next(dns_rdataset_t *rdataset);
104
static void
105
slabheader_proof_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
106
static void
107
slabheader_proof_clone(const dns_rdataset_t *source,
108
           dns_rdataset_t *target DNS__DB_FLARG);
109
static unsigned int
110
slabheader_proof_count(dns_rdataset_t *rdataset);
111
static dns_slabheader_t *
112
slabheader_proof_getheader(const dns_rdataset_t *rdataset);
113
114
dns_rdatasetmethods_t dns_rdataslab_proof_rdatasetmethods = {
115
  .disassociate = slabheader_proof_disassociate,
116
  .first = slabheader_proof_first,
117
  .next = slabheader_proof_next,
118
  .current = slabheader_proof_current,
119
  .clone = slabheader_proof_clone,
120
  .count = slabheader_proof_count,
121
  .getnoqname = NULL,
122
  .getclosest = NULL,
123
  .settrust = NULL,
124
  .expire = NULL,
125
  .clearprefetch = NULL,
126
  .getownercase = NULL,
127
};
128
129
/*% Note: the "const void *" are just to make qsort happy.  */
130
static int
131
0
compare_rdata(const void *p1, const void *p2) {
132
0
  return dns_rdata_compare(p1, p2);
133
0
}
134
135
static unsigned char *
136
newslab(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
137
  uint16_t nitems, size_t size, const char *func, const char *file,
138
0
  const unsigned int line) {
139
0
  dns_slabheader_t *header = isc_mem_get(mctx, size);
140
141
0
  *header = (dns_slabheader_t){
142
0
    .headers_link = CDS_LIST_HEAD_INIT(header->headers_link),
143
0
    .trust = rdataset->trust,
144
0
    .nitems = nitems,
145
0
    .references = ISC_REFCOUNT_INITIALIZER(1),
146
0
    .mctx = isc_mem_ref(mctx),
147
0
    .lrulink = ISC_LINK_INITIALIZER,
148
0
  };
149
150
#if DNS_SLABHEADER_TRACE
151
  fprintf(stderr,
152
    "%s:%s:%s:%u:t%" PRItid ":%p->references = %" PRIuFAST32 "\n",
153
    __func__, func, file, line, isc_tid(), header,
154
    header->references);
155
#else
156
0
  UNUSED(func);
157
0
  UNUSED(file);
158
0
  UNUSED(line);
159
0
#endif
160
161
0
  region->base = (unsigned char *)header;
162
0
  region->length = size;
163
164
0
  return (unsigned char *)header + sizeof(*header);
165
0
}
166
167
static isc_result_t
168
makeslab(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
169
   uint32_t maxrrperset, const char *func, const char *file,
170
0
   const unsigned int line) {
171
  /*
172
   * Use &removed as a sentinel pointer for duplicate
173
   * rdata as rdata.data == NULL is valid.
174
   */
175
0
  static unsigned char removed;
176
0
  dns_rdata_t *rdata = NULL;
177
0
  unsigned char *rawbuf = NULL;
178
0
  unsigned int headerlen = sizeof(dns_slabheader_t);
179
0
  uint32_t buflen = headerlen;
180
0
  isc_result_t result;
181
0
  unsigned int nitems;
182
0
  unsigned int nalloc;
183
0
  unsigned int length;
184
0
  size_t i;
185
0
  size_t rdatasize;
186
187
  /*
188
   * If the source rdataset is also a slab, we don't need
189
   * to do anything special, just copy the whole slab to a
190
   * new buffer.
191
   */
192
0
  if (rdataset->methods == &dns_rdataslab_rdatasetmethods) {
193
0
    dns_slabheader_t *header = rdataset_getheader(rdataset);
194
0
    buflen = dns_rdataslab_size(header);
195
196
0
    rawbuf = newslab(rdataset, mctx, region, header->nitems, buflen,
197
0
         func, file, line);
198
199
0
    INSIST(headerlen <= buflen);
200
0
    memmove(rawbuf, (unsigned char *)header + headerlen,
201
0
      buflen - headerlen);
202
0
    return ISC_R_SUCCESS;
203
0
  }
204
205
  /*
206
   * If there are no rdata then we just need to allocate a header
207
   * with a zero record count.
208
   */
209
0
  nitems = dns_rdataset_count(rdataset);
210
0
  if (nitems == 0) {
211
0
    if (rdataset->type != 0) {
212
0
      return ISC_R_FAILURE;
213
0
    }
214
0
    (void)newslab(rdataset, mctx, region, 0, buflen, func, file,
215
0
            line);
216
0
    return ISC_R_SUCCESS;
217
0
  }
218
219
0
  if (maxrrperset > 0 && nitems > maxrrperset) {
220
0
    return DNS_R_TOOMANYRECORDS;
221
0
  }
222
223
0
  if (nitems > 0xffff) {
224
0
    return ISC_R_NOSPACE;
225
0
  }
226
227
  /*
228
   * Remember the original number of items.
229
   */
230
0
  nalloc = nitems;
231
232
0
  RUNTIME_CHECK(!ckd_mul(&rdatasize, nalloc, sizeof(rdata[0])));
233
0
  rdata = isc_mem_get(mctx, rdatasize);
234
235
  /*
236
   * Save all of the rdata members into an array.
237
   */
238
0
  result = dns_rdataset_first(rdataset);
239
0
  if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) {
240
0
    goto free_rdatas;
241
0
  }
242
0
  for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) {
243
0
    INSIST(result == ISC_R_SUCCESS);
244
0
    dns_rdata_init(&rdata[i]);
245
0
    dns_rdataset_current(rdataset, &rdata[i]);
246
0
    INSIST(rdata[i].data != &removed);
247
0
    result = dns_rdataset_next(rdataset);
248
0
  }
249
0
  if (i != nalloc || result != ISC_R_NOMORE) {
250
    /*
251
     * Somehow we iterated over fewer rdatas than
252
     * dns_rdataset_count() said there were or there
253
     * were more items than dns_rdataset_count said
254
     * there were.
255
     */
256
0
    result = ISC_R_FAILURE;
257
0
    goto free_rdatas;
258
0
  }
259
260
  /*
261
   * Put into DNSSEC order.
262
   */
263
0
  if (nalloc > 1U) {
264
0
    qsort(rdata, nalloc, sizeof(rdata[0]), compare_rdata);
265
0
  }
266
267
  /*
268
   * Remove duplicates and compute the total storage required.
269
   *
270
   * If an rdata is not a duplicate, accumulate the storage size
271
   * required for the rdata.  We do not store the class, type, etc,
272
   * just the rdata, so our overhead is 2 bytes for the number of
273
   * records, and 2 bytes for the length of each rdata, plus the
274
   * rdata itself.
275
   */
276
0
  for (i = 1; i < nalloc; i++) {
277
0
    if (compare_rdata(&rdata[i - 1], &rdata[i]) == 0) {
278
0
      rdata[i - 1].data = &removed;
279
0
      nitems--;
280
0
    } else {
281
0
      buflen += 2 + rdata[i - 1].length;
282
      /*
283
       * Provide space to store the per RR meta data.
284
       */
285
0
      if (rdataset->type == dns_rdatatype_rrsig) {
286
0
        buflen++;
287
0
      }
288
0
      if (buflen - headerlen > DNS_RDATA_MAXLENGTH) {
289
0
        result = ISC_R_NOSPACE;
290
0
        goto free_rdatas;
291
0
      }
292
0
    }
293
0
  }
294
295
  /*
296
   * Don't forget the last item!
297
   */
298
0
  buflen += 2 + rdata[i - 1].length;
299
300
  /*
301
   * Provide space to store the per RR meta data.
302
   */
303
0
  if (rdataset->type == dns_rdatatype_rrsig) {
304
0
    buflen++;
305
0
  }
306
0
  if (buflen - headerlen > DNS_RDATA_MAXLENGTH) {
307
0
    result = ISC_R_NOSPACE;
308
0
    goto free_rdatas;
309
0
  }
310
311
  /*
312
   * Ensure that singleton types are actually singletons.
313
   */
314
0
  if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) {
315
    /*
316
     * We have a singleton type, but there's more than one
317
     * RR in the rdataset.
318
     */
319
0
    result = DNS_R_SINGLETON;
320
0
    goto free_rdatas;
321
0
  }
322
323
  /*
324
   * Allocate the memory, set up a buffer, start copying in
325
   * data.
326
   */
327
0
  rawbuf = newslab(rdataset, mctx, region, nitems, buflen, func, file,
328
0
       line);
329
330
0
  for (i = 0; i < nalloc; i++) {
331
0
    if (rdata[i].data == &removed) {
332
0
      continue;
333
0
    }
334
0
    length = rdata[i].length;
335
0
    if (rdataset->type == dns_rdatatype_rrsig) {
336
0
      length++;
337
0
    }
338
0
    INSIST(length <= 0xffff);
339
340
0
    put_uint16(rawbuf, length);
341
342
    /*
343
     * Store the per RR meta data.
344
     */
345
0
    if (rdataset->type == dns_rdatatype_rrsig) {
346
0
      *rawbuf++ = (rdata[i].flags & DNS_RDATA_OFFLINE)
347
0
              ? DNS_RDATASLAB_OFFLINE
348
0
              : 0;
349
0
    }
350
0
    if (rdata[i].length != 0) {
351
0
      memmove(rawbuf, rdata[i].data, rdata[i].length);
352
0
    }
353
0
    rawbuf += rdata[i].length;
354
0
  }
355
356
0
  result = ISC_R_SUCCESS;
357
358
0
free_rdatas:
359
0
  isc_mem_put(mctx, rdata, rdatasize);
360
0
  return result;
361
0
}
362
363
isc_result_t
364
dns_rdataslab__fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
365
          isc_region_t *region, uint32_t maxrrperset,
366
          const char *func, const char *file,
367
0
          const unsigned int line) {
368
0
  if (rdataset->type == dns_rdatatype_none &&
369
0
      rdataset->covers == dns_rdatatype_none)
370
0
  {
371
0
    return DNS_R_DISALLOWED;
372
0
  }
373
374
0
  isc_result_t result = makeslab(rdataset, mctx, region, maxrrperset,
375
0
               func, file, line);
376
0
  if (result != ISC_R_SUCCESS) {
377
0
    return result;
378
0
  }
379
380
0
  dns_slabheader_t *header = (dns_slabheader_t *)region->base;
381
0
  if (rdataset->attributes.negative) {
382
0
    INSIST(rdataset->type == dns_rdatatype_none);
383
0
    INSIST(rdataset->covers != dns_rdatatype_none);
384
0
    header->typepair = DNS_TYPEPAIR_VALUE(rdataset->covers,
385
0
                  dns_rdatatype_none);
386
0
  } else {
387
0
    INSIST(rdataset->type != dns_rdatatype_none);
388
0
    INSIST(dns_rdatatype_issig(rdataset->type) ||
389
0
           rdataset->covers == dns_rdatatype_none);
390
0
    header->typepair = DNS_TYPEPAIR_VALUE(rdataset->type,
391
0
                  rdataset->covers);
392
0
  }
393
394
0
  return ISC_R_SUCCESS;
395
0
}
396
397
unsigned int
398
0
dns_rdataslab_size(dns_slabheader_t *header) {
399
0
  REQUIRE(header != NULL);
400
401
0
  unsigned char *slab = (unsigned char *)header +
402
0
            sizeof(dns_slabheader_t);
403
0
  INSIST(slab != NULL);
404
405
0
  unsigned char *current = slab;
406
0
  uint16_t count = header->nitems;
407
408
0
  while (count-- > 0) {
409
0
    uint16_t length = get_uint16(current);
410
0
    current += length;
411
0
  }
412
413
0
  return (unsigned int)(current - slab) + sizeof(dns_slabheader_t);
414
0
}
415
416
unsigned int
417
0
dns_rdataslab_count(dns_slabheader_t *header) {
418
0
  REQUIRE(header != NULL);
419
420
0
  return header->nitems;
421
0
}
422
423
/*
424
 * Make the dns_rdata_t 'rdata' refer to the slab item
425
 * beginning at '*current' (which is part of a slab of type
426
 * 'type' and class 'rdclass') and advance '*current' to
427
 * point to the next item in the slab.
428
 */
429
static void
430
rdata_from_slabitem(unsigned char **current, dns_rdataclass_t rdclass,
431
0
        dns_rdatatype_t type, dns_rdata_t *rdata) {
432
0
  unsigned char *tcurrent = *current;
433
0
  isc_region_t region;
434
0
  bool offline = false;
435
0
  uint16_t length = get_uint16(tcurrent);
436
437
0
  if (type == dns_rdatatype_rrsig) {
438
0
    if ((*tcurrent & DNS_RDATASLAB_OFFLINE) != 0) {
439
0
      offline = true;
440
0
    }
441
0
    length--;
442
0
    tcurrent++;
443
0
  }
444
0
  region.length = length;
445
0
  region.base = tcurrent;
446
0
  tcurrent += region.length;
447
0
  dns_rdata_fromregion(rdata, rdclass, type, &region);
448
0
  if (offline) {
449
0
    rdata->flags |= DNS_RDATA_OFFLINE;
450
0
  }
451
0
  *current = tcurrent;
452
0
}
453
454
bool
455
0
dns_rdataslab_equal(dns_slabheader_t *slab1, dns_slabheader_t *slab2) {
456
0
  unsigned char *current1 = NULL, *current2 = NULL;
457
0
  unsigned int count1, count2;
458
459
0
  current1 = (unsigned char *)slab1 + sizeof(dns_slabheader_t);
460
0
  count1 = slab1->nitems;
461
462
0
  current2 = (unsigned char *)slab2 + sizeof(dns_slabheader_t);
463
0
  count2 = slab2->nitems;
464
465
0
  if (count1 != count2) {
466
0
    return false;
467
0
  } else if (count1 == 0) {
468
0
    return true;
469
0
  }
470
471
0
  while (count1-- > 0) {
472
0
    unsigned int length1 = get_uint16(current1);
473
0
    unsigned int length2 = get_uint16(current2);
474
475
0
    if (length1 != length2 ||
476
0
        memcmp(current1, current2, length1) != 0)
477
0
    {
478
0
      return false;
479
0
    }
480
481
0
    current1 += length1;
482
0
    current2 += length1;
483
0
  }
484
0
  return true;
485
0
}
486
487
bool
488
dns_rdataslab_equalx(dns_slabheader_t *slab1, dns_slabheader_t *slab2,
489
0
         dns_rdataclass_t rdclass, dns_rdatatype_t type) {
490
0
  unsigned char *current1 = NULL, *current2 = NULL;
491
0
  unsigned int count1, count2;
492
493
0
  current1 = (unsigned char *)slab1 + sizeof(dns_slabheader_t);
494
0
  count1 = slab1->nitems;
495
496
0
  current2 = (unsigned char *)slab2 + sizeof(dns_slabheader_t);
497
0
  count2 = slab2->nitems;
498
499
0
  if (count1 != count2) {
500
0
    return false;
501
0
  } else if (count1 == 0) {
502
0
    return true;
503
0
  }
504
505
0
  while (count1-- > 0) {
506
0
    dns_rdata_t rdata1 = DNS_RDATA_INIT;
507
0
    dns_rdata_t rdata2 = DNS_RDATA_INIT;
508
509
0
    rdata_from_slabitem(&current1, rdclass, type, &rdata1);
510
0
    rdata_from_slabitem(&current2, rdclass, type, &rdata2);
511
0
    if (dns_rdata_compare(&rdata1, &rdata2) != 0) {
512
0
      return false;
513
0
    }
514
0
  }
515
0
  return true;
516
0
}
517
518
void
519
dns_slabheader__reset(dns_slabheader_t *h, dns_dbnode_t *node, const char *func,
520
0
          const char *file, const unsigned int line) {
521
0
  h->node = node;
522
523
0
  atomic_init(&h->attributes, 0);
524
0
  atomic_init(&h->last_refresh_fail_ts, 0);
525
0
  isc_refcount_init(&h->references, 1);
526
527
0
  STATIC_ASSERT(sizeof(h->attributes) == 2,
528
0
          "The .attributes field of dns_slabheader_t needs to be "
529
0
          "16-bit int type exactly.");
530
531
#if DNS_SLABHEADER_TRACE
532
  fprintf(stderr,
533
    "%s:%s:%s:%u:t%" PRItid ":%p->references = %" PRIuFAST32 "\n",
534
    __func__, func, file, line, isc_tid(), h, h->references);
535
#else
536
0
  UNUSED(func);
537
0
  UNUSED(file);
538
0
  UNUSED(line);
539
0
#endif
540
0
}
541
542
dns_slabheader_t *
543
dns_slabheader__new(isc_mem_t *mctx, dns_dbnode_t *node, const char *func,
544
0
        const char *file, const unsigned int line) {
545
0
  dns_slabheader_t *h = NULL;
546
547
0
  h = isc_mem_get(mctx, sizeof(*h));
548
0
  *h = (dns_slabheader_t){
549
0
    .headers_link = CDS_LIST_HEAD_INIT(h->headers_link),
550
0
    .node = node,
551
0
    .references = ISC_REFCOUNT_INITIALIZER(1),
552
0
    .mctx = isc_mem_ref(mctx),
553
0
    .lrulink = ISC_LINK_INITIALIZER,
554
0
  };
555
556
#if DNS_SLABHEADER_TRACE
557
  fprintf(stderr,
558
    "%s:%s:%s:%u:t%" PRItid ":%p->references = %" PRIuFAST32 "\n",
559
    __func__, func, file, line, isc_tid(), h, h->references);
560
#else
561
0
  UNUSED(func);
562
0
  UNUSED(file);
563
0
  UNUSED(line);
564
0
#endif
565
566
0
  return h;
567
0
}
568
569
static void
570
0
slabheader_destroy(dns_slabheader_t *header) {
571
0
  unsigned int size;
572
573
0
  if (EXISTS(header)) {
574
0
    size = dns_rdataslab_size(header);
575
0
  } else {
576
0
    size = sizeof(*header);
577
0
  }
578
579
0
  if (header->noqname != NULL) {
580
0
    dns_slabheader_freeproof(header->mctx, &header->noqname);
581
0
  }
582
0
  if (header->closest != NULL) {
583
0
    dns_slabheader_freeproof(header->mctx, &header->closest);
584
0
  }
585
586
0
  isc_mem_putanddetach(&header->mctx, header, size);
587
0
}
588
589
void
590
0
dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proofp) {
591
0
  dns_slabheader_proof_t *proof = *proofp;
592
0
  *proofp = NULL;
593
594
0
  if (dns_name_dynamic(&proof->name)) {
595
0
    dns_name_free(&proof->name, mctx);
596
0
  }
597
0
  if (proof->neg != NULL) {
598
0
    dns_slabheader_t *header =
599
0
      (dns_slabheader_t *)((uint8_t *)proof->neg -
600
0
               sizeof(dns_slabheader_t));
601
0
    dns_slabheader_detach(&header);
602
0
  }
603
0
  if (proof->negsig != NULL) {
604
0
    dns_slabheader_t *header =
605
0
      (dns_slabheader_t *)((uint8_t *)proof->negsig -
606
0
               sizeof(dns_slabheader_t));
607
0
    dns_slabheader_detach(&header);
608
0
  }
609
0
  isc_mem_put(mctx, proof, sizeof(*proof));
610
0
}
611
612
#if DNS_SLABHEADER_TRACE
613
ISC_REFCOUNT_TRACE_IMPL(dns_slabheader, slabheader_destroy);
614
#else
615
0
ISC_REFCOUNT_IMPL(dns_slabheader, slabheader_destroy);
Unexecuted instantiation: dns_slabheader_ref
Unexecuted instantiation: dns_slabheader_unref
Unexecuted instantiation: dns_slabheader_detach
616
0
#endif
617
0
618
0
/* Fixed RRSet helper macros */
619
0
620
0
static void
621
0
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
622
0
  dns_slabheader_t *header = rdataset_getheader(rdataset);
623
624
0
  dns_slabheader_detach(&header);
625
626
0
  dns__db_detachnode(&rdataset->slab.node DNS__DB_FLARG_PASS);
627
0
}
628
629
static isc_result_t
630
0
rdataset_first(dns_rdataset_t *rdataset) {
631
0
  dns_slabheader_t *header = rdataset_getheader(rdataset);
632
0
  unsigned char *raw = rdataset->slab.raw;
633
0
  uint16_t count = header->nitems;
634
635
0
  if (count == 0) {
636
0
    rdataset->slab.iter_pos = NULL;
637
0
    rdataset->slab.iter_count = 0;
638
0
    return ISC_R_NOMORE;
639
0
  }
640
641
  /*
642
   * iter_count is the number of rdata beyond the cursor
643
   * position, so we decrement the total count by one before
644
   * storing it.
645
   *
646
   * 'raw' points to the first record.
647
   */
648
0
  rdataset->slab.iter_pos = raw;
649
0
  rdataset->slab.iter_count = count - 1;
650
651
0
  return ISC_R_SUCCESS;
652
0
}
653
654
static isc_result_t
655
0
rdataset_next(dns_rdataset_t *rdataset) {
656
0
  uint16_t count = rdataset->slab.iter_count;
657
0
  if (count == 0) {
658
0
    rdataset->slab.iter_pos = NULL;
659
0
    return ISC_R_NOMORE;
660
0
  }
661
0
  rdataset->slab.iter_count = count - 1;
662
663
  /*
664
   * Skip forward one record (length + 4) or one offset (4).
665
   */
666
0
  unsigned char *raw = rdataset->slab.iter_pos;
667
0
  uint16_t length = peek_uint16(raw);
668
0
  raw += length;
669
0
  rdataset->slab.iter_pos = raw + sizeof(uint16_t);
670
671
0
  return ISC_R_SUCCESS;
672
0
}
673
674
static void
675
0
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
676
0
  unsigned char *raw = NULL;
677
0
  unsigned int length;
678
0
  isc_region_t r;
679
0
  unsigned int flags = 0;
680
681
0
  raw = rdataset->slab.iter_pos;
682
0
  REQUIRE(raw != NULL);
683
684
  /*
685
   * Find the start of the record if not already in iter_pos
686
   * then skip the length and order fields.
687
   */
688
0
  length = get_uint16(raw);
689
690
0
  if (rdataset->type == dns_rdatatype_rrsig) {
691
0
    if (*raw & DNS_RDATASLAB_OFFLINE) {
692
0
      flags |= DNS_RDATA_OFFLINE;
693
0
    }
694
0
    length--;
695
0
    raw++;
696
0
  }
697
0
  r.length = length;
698
0
  r.base = raw;
699
0
  dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
700
0
  rdata->flags |= flags;
701
0
}
702
703
static void
704
rdataset_clone(const dns_rdataset_t *source,
705
0
         dns_rdataset_t *target DNS__DB_FLARG) {
706
0
  dns_slabheader_t *header = rdataset_getheader(source);
707
708
0
  INSIST(target->slab.node == NULL);
709
0
  INSIST(!ISC_LINK_LINKED(target, link));
710
0
  *target = *source;
711
0
  ISC_LINK_INIT(target, link);
712
0
  target->slab.node = NULL;
713
0
  dns__db_attachnode(source->slab.node,
714
0
         &target->slab.node DNS__DB_FLARG_PASS);
715
716
0
  target->slab.iter_pos = NULL;
717
0
  target->slab.iter_count = 0;
718
719
0
  dns_slabheader_ref(header);
720
0
}
721
722
static unsigned int
723
0
rdataset_count(dns_rdataset_t *rdataset) {
724
0
  dns_slabheader_t *header = rdataset_getheader(rdataset);
725
726
0
  return header->nitems;
727
0
}
728
729
static isc_result_t
730
rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
731
        dns_rdataset_t *nsec,
732
0
        dns_rdataset_t *nsecsig DNS__DB_FLARG) {
733
0
  dns_dbnode_t *node = rdataset->slab.node;
734
0
  dns_slabheader_t *header = rdataset_getheader(rdataset);
735
0
  const dns_slabheader_proof_t *noqname = rdataset->slab.noqname;
736
737
  /*
738
   * Normally, rdataset->slab.raw points to the data immediately
739
   * following a dns_slabheader in memory. Here, though, it will
740
   * point to a bare rdataslab, a pointer to which is stored in
741
   * the dns_slabheader's `noqname` field.
742
   *
743
   * The 'keepcase' attribute is set to prevent setownercase and
744
   * getownercase methods from affecting the case of NSEC/NSEC3
745
   * owner names.
746
   */
747
0
  *nsec = (dns_rdataset_t){
748
0
    .methods = &dns_rdataslab_proof_rdatasetmethods,
749
0
    .rdclass = rdataset->rdclass,
750
0
    .type = noqname->type,
751
0
    .ttl = rdataset->ttl,
752
0
    .trust = rdataset->trust,
753
0
    .proof.header = dns_slabheader_ref(header),
754
0
    .proof.raw = noqname->neg,
755
0
    .link = nsec->link,
756
0
    .attributes = nsec->attributes,
757
0
    .magic = nsec->magic,
758
0
  };
759
0
  nsec->attributes.keepcase = true;
760
0
  dns__db_attachnode(node, &nsec->proof.node DNS__DB_FLARG_PASS);
761
762
0
  *nsecsig = (dns_rdataset_t){
763
0
    .methods = &dns_rdataslab_proof_rdatasetmethods,
764
0
    .rdclass = rdataset->rdclass,
765
0
    .type = dns_rdatatype_rrsig,
766
0
    .covers = noqname->type,
767
0
    .ttl = rdataset->ttl,
768
0
    .trust = rdataset->trust,
769
0
    .proof.header = dns_slabheader_ref(header),
770
0
    .proof.raw = noqname->negsig,
771
0
    .link = nsecsig->link,
772
0
    .attributes = nsecsig->attributes,
773
0
    .magic = nsecsig->magic,
774
0
  };
775
0
  nsecsig->attributes.keepcase = true;
776
0
  dns__db_attachnode(node, &nsecsig->proof.node DNS__DB_FLARG_PASS);
777
778
0
  dns_name_clone(&noqname->name, name);
779
780
0
  return ISC_R_SUCCESS;
781
0
}
782
783
static isc_result_t
784
rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
785
        dns_rdataset_t *nsec,
786
0
        dns_rdataset_t *nsecsig DNS__DB_FLARG) {
787
0
  dns_dbnode_t *node = rdataset->slab.node;
788
0
  dns_slabheader_t *header = rdataset_getheader(rdataset);
789
0
  const dns_slabheader_proof_t *closest = rdataset->slab.closest;
790
791
  /*
792
   * Normally, rdataset->slab.raw points to the data immediately
793
   * following a dns_slabheader in memory. Here, though, it will
794
   * point to a bare rdataslab, a pointer to which is stored in
795
   * the dns_slabheader's `closest` field.
796
   *
797
   * The 'keepcase' attribute is set to prevent setownercase and
798
   * getownercase methods from affecting the case of NSEC/NSEC3
799
   * owner names.
800
   */
801
0
  *nsec = (dns_rdataset_t){
802
0
    .methods = &dns_rdataslab_proof_rdatasetmethods,
803
0
    .rdclass = rdataset->rdclass,
804
0
    .type = closest->type,
805
0
    .ttl = rdataset->ttl,
806
0
    .trust = rdataset->trust,
807
0
    .proof.header = dns_slabheader_ref(header),
808
0
    .proof.raw = closest->neg,
809
0
    .link = nsec->link,
810
0
    .attributes = nsec->attributes,
811
0
    .magic = nsec->magic,
812
0
  };
813
0
  nsec->attributes.keepcase = true;
814
0
  dns__db_attachnode(node, &nsec->proof.node DNS__DB_FLARG_PASS);
815
816
0
  *nsecsig = (dns_rdataset_t){
817
0
    .methods = &dns_rdataslab_proof_rdatasetmethods,
818
0
    .rdclass = rdataset->rdclass,
819
0
    .type = dns_rdatatype_rrsig,
820
0
    .covers = closest->type,
821
0
    .ttl = rdataset->ttl,
822
0
    .trust = rdataset->trust,
823
0
    .proof.header = dns_slabheader_ref(header),
824
0
    .proof.raw = closest->negsig,
825
0
    .link = nsecsig->link,
826
0
    .attributes = nsecsig->attributes,
827
0
    .magic = nsecsig->magic,
828
0
  };
829
0
  nsecsig->attributes.keepcase = true;
830
0
  dns__db_attachnode(node, &nsecsig->proof.node DNS__DB_FLARG_PASS);
831
832
0
  dns_name_clone(&closest->name, name);
833
834
0
  return ISC_R_SUCCESS;
835
0
}
836
837
static void
838
0
rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
839
0
  dns_slabheader_t *header = rdataset_getheader(rdataset);
840
841
0
  rdataset->trust = trust;
842
0
  atomic_store_release(&header->trust, trust);
843
0
}
844
845
static void
846
0
rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG) {
847
0
  dns_slabheader_t *header = rdataset_getheader(rdataset);
848
849
0
  dns_db_expiredata(rdataset->slab.node, header);
850
0
}
851
852
static void
853
0
rdataset_clearprefetch(dns_rdataset_t *rdataset) {
854
0
  dns_slabheader_t *header = rdataset_getheader(rdataset);
855
856
0
  DNS_SLABHEADER_CLRATTR(header, DNS_SLABHEADERATTR_PREFETCH);
857
0
}
858
859
static void
860
0
rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
861
0
  dns_slabheader_t *header = rdataset_getheader(rdataset);
862
0
  uint8_t mask = (1 << 7);
863
0
  uint8_t bits = 0;
864
865
0
  if (!CASESET(header)) {
866
0
    return;
867
0
  }
868
869
0
  if (CASEFULLYLOWER(header)) {
870
0
    isc_ascii_lowercopy(name->ndata, name->ndata, name->length);
871
0
    return;
872
0
  }
873
874
0
  uint8_t *nd = name->ndata;
875
0
  for (size_t i = 0; i < name->length; i++) {
876
0
    if (mask == (1 << 7)) {
877
0
      bits = header->upper[i / 8];
878
0
      mask = 1;
879
0
    } else {
880
0
      mask <<= 1;
881
0
    }
882
0
    nd[i] = (bits & mask) ? isc_ascii_toupper(nd[i])
883
0
              : isc_ascii_tolower(nd[i]);
884
0
  }
885
0
}
886
887
static dns_slabheader_t *
888
0
rdataset_getheader(const dns_rdataset_t *rdataset) {
889
0
  uint8_t *rawbuf = rdataset->slab.raw;
890
0
  return (dns_slabheader_t *)(rawbuf - offsetof(dns_slabheader_t, raw));
891
0
}
892
893
/* Fixed Proof helper macros */
894
895
static void
896
0
slabheader_proof_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
897
0
  dns_slabheader_detach(&rdataset->proof.header);
898
0
  dns__db_detachnode(&rdataset->proof.node DNS__DB_FLARG_PASS);
899
0
}
900
901
static isc_result_t
902
0
slabheader_proof_first(dns_rdataset_t *rdataset) {
903
0
  unsigned char *raw = rdataset->proof.raw;
904
0
  uint16_t count = slabheader_proof_count(rdataset);
905
906
0
  if (count == 0) {
907
0
    rdataset->proof.iter_pos = NULL;
908
0
    rdataset->proof.iter_count = 0;
909
0
    return ISC_R_NOMORE;
910
0
  }
911
912
  /*
913
   * iter_count is the number of rdata beyond the cursor
914
   * position, so we decrement the total count by one before
915
   * storing it.
916
   *
917
   * 'raw' points to the first record.
918
   */
919
0
  rdataset->proof.iter_pos = raw;
920
0
  rdataset->proof.iter_count = count - 1;
921
922
0
  return ISC_R_SUCCESS;
923
0
}
924
925
static isc_result_t
926
0
slabheader_proof_next(dns_rdataset_t *rdataset) {
927
0
  uint16_t count = rdataset->proof.iter_count;
928
0
  if (count == 0) {
929
0
    rdataset->proof.iter_pos = NULL;
930
0
    return ISC_R_NOMORE;
931
0
  }
932
0
  rdataset->proof.iter_count = count - 1;
933
934
  /*
935
   * Skip forward one record (length + 4) or one offset (4).
936
   */
937
0
  unsigned char *raw = rdataset->proof.iter_pos;
938
0
  uint16_t length = peek_uint16(raw);
939
0
  raw += length;
940
0
  rdataset->proof.iter_pos = raw + sizeof(uint16_t);
941
942
0
  return ISC_R_SUCCESS;
943
0
}
944
945
static void
946
0
slabheader_proof_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
947
0
  unsigned char *raw = NULL;
948
0
  unsigned int length;
949
0
  isc_region_t r;
950
0
  unsigned int flags = 0;
951
952
0
  raw = rdataset->proof.iter_pos;
953
0
  REQUIRE(raw != NULL);
954
955
  /*
956
   * Find the start of the record if not already in iter_pos
957
   * then skip the length and order fields.
958
   */
959
0
  length = get_uint16(raw);
960
961
0
  if (rdataset->type == dns_rdatatype_rrsig) {
962
0
    if (*raw & DNS_RDATASLAB_OFFLINE) {
963
0
      flags |= DNS_RDATA_OFFLINE;
964
0
    }
965
0
    length--;
966
0
    raw++;
967
0
  }
968
0
  r.length = length;
969
0
  r.base = raw;
970
0
  dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
971
0
  rdata->flags |= flags;
972
0
}
973
974
static void
975
slabheader_proof_clone(const dns_rdataset_t *source,
976
0
           dns_rdataset_t *target DNS__DB_FLARG) {
977
0
  INSIST(!ISC_LINK_LINKED(target, link));
978
0
  INSIST(target->proof.node == NULL);
979
0
  INSIST(target->proof.header == NULL);
980
981
0
  *target = *source;
982
983
0
  ISC_LINK_INIT(target, link);
984
0
  target->proof.node = NULL;
985
0
  dns__db_attachnode(source->proof.node,
986
0
         &target->proof.node DNS__DB_FLARG_PASS);
987
0
  dns_slabheader_ref(target->proof.header);
988
989
0
  target->proof.iter_pos = NULL;
990
0
  target->proof.iter_count = 0;
991
0
}
992
993
static unsigned int
994
0
slabheader_proof_count(dns_rdataset_t *rdataset) {
995
0
  dns_slabheader_t *header = slabheader_proof_getheader(rdataset);
996
997
0
  return header->nitems;
998
0
}
999
1000
static dns_slabheader_t *
1001
0
slabheader_proof_getheader(const dns_rdataset_t *rdataset) {
1002
0
  uint8_t *rawbuf = rdataset->proof.raw;
1003
  return (dns_slabheader_t *)(rawbuf - offsetof(dns_slabheader_t, raw));
1004
0
}