Coverage Report

Created: 2026-09-14 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/rdatavec.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 <ctype.h>
17
#include <stdbool.h>
18
#include <stddef.h>
19
#include <stdlib.h>
20
21
#include <isc/ascii.h>
22
#include <isc/atomic.h>
23
#include <isc/mem.h>
24
#include <isc/refcount.h>
25
#include <isc/region.h>
26
#include <isc/result.h>
27
#include <isc/string.h>
28
#include <isc/util.h>
29
30
#include <dns/db.h>
31
#include <dns/rdata.h>
32
#include <dns/rdataset.h>
33
#include <dns/rdatavec.h>
34
#include <dns/stats.h>
35
36
#include "rdatavec_p.h"
37
38
/*
39
 * The memory structure of an rdatavec is as follows:
40
 *
41
 *  header    (dns_vecheader_t)
42
 *  record count  (2 bytes, big endian)
43
 *  data records
44
 *    data length (2 bytes, big endian)
45
 *    meta data (1 byte for RRSIG, 0 bytes for all other types)
46
 *    data    (data length bytes)
47
 *
48
 * A "bare" rdatavec is everything after the header. The first two bytes
49
 * contain the count of rdata records in the rdatavec. For records with
50
 * the DNS_VECHEADERATTR_NONEXISTENT attribute, the record count is omitted
51
 * entirely.
52
 *
53
 * After the count, the rdata records are stored sequentially in memory.
54
 * Each record consists of a length field, optional metadata, and the actual
55
 * rdata bytes.
56
 *
57
 * The rdata format depends on the RR type and is defined by the type-specific
58
 * *_fromwire and *_towire functions (e.g., lib/dns/rdata/in_1/a_1.c for A
59
 * records). The data is typically stored in wire format.
60
 *
61
 * When a vec is created, data records are sorted into DNSSEC canonical order.
62
 */
63
64
static void
65
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG);
66
static isc_result_t
67
rdataset_first(dns_rdataset_t *rdataset);
68
static isc_result_t
69
rdataset_next(dns_rdataset_t *rdataset);
70
static void
71
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
72
static void
73
rdataset_clone(const dns_rdataset_t *source,
74
         dns_rdataset_t *target DNS__DB_FLARG);
75
static unsigned int
76
rdataset_count(dns_rdataset_t *rdataset);
77
static void
78
rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
79
static void
80
rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name);
81
82
dns_rdatasetmethods_t dns_rdatavec_rdatasetmethods = {
83
  .disassociate = rdataset_disassociate,
84
  .first = rdataset_first,
85
  .next = rdataset_next,
86
  .current = rdataset_current,
87
  .clone = rdataset_clone,
88
  .count = rdataset_count,
89
  .settrust = rdataset_settrust,
90
  .expire = NULL,
91
  .clearprefetch = NULL,
92
  .getownercase = rdataset_getownercase,
93
};
94
95
/*% Note: the "const void *" are just to make qsort happy.  */
96
static int
97
505k
compare_rdata(const void *p1, const void *p2) {
98
505k
  return dns_rdata_compare(p1, p2);
99
505k
}
100
101
static size_t
102
166M
header_size(const dns_vecheader_t *header) {
103
166M
  UNUSED(header);
104
166M
  return sizeof(dns_vecheader_t);
105
166M
}
106
107
static unsigned char *
108
53.0M
rdatavec_raw(dns_vecheader_t *header) {
109
53.0M
  unsigned char *as_char_star = (unsigned char *)header;
110
53.0M
  unsigned char *raw = as_char_star + header_size(header);
111
112
53.0M
  return raw;
113
53.0M
}
114
115
static unsigned char *
116
16.3M
rdatavec_data(dns_vecheader_t *header) {
117
16.3M
  return rdatavec_raw(header) + 2;
118
16.3M
}
119
120
static unsigned int
121
22.7M
rdatavec_count(dns_vecheader_t *header) {
122
22.7M
  unsigned char *raw = rdatavec_raw(header);
123
22.7M
  unsigned int count = get_uint16(raw);
124
125
22.7M
  return count;
126
22.7M
}
127
128
static unsigned char *
129
newvec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
130
7.30M
       size_t size) {
131
7.30M
  dns_vecheader_t *header = isc_mem_get(mctx, size);
132
133
7.30M
  *header = (dns_vecheader_t){
134
7.30M
    .next_header = ISC_SLINK_INITIALIZER,
135
7.30M
    .trust = rdataset->trust,
136
7.30M
    .ttl = rdataset->ttl,
137
7.30M
    .references = ISC_REFCOUNT_INITIALIZER(1),
138
7.30M
    .mctx = isc_mem_ref(mctx),
139
7.30M
  };
140
141
7.30M
  region->base = (unsigned char *)header;
142
7.30M
  region->length = size;
143
144
7.30M
  return (unsigned char *)header + sizeof(*header);
145
7.30M
}
146
147
static isc_result_t
148
makevec(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region,
149
7.30M
  uint32_t maxrrperset) {
150
  /*
151
   * Use &removed as a sentinel pointer for duplicate
152
   * rdata as rdata.data == NULL is valid.
153
   */
154
7.30M
  static unsigned char removed;
155
7.30M
  dns_rdata_t *rdata = NULL;
156
7.30M
  unsigned char *rawbuf = NULL;
157
7.30M
  unsigned int headerlen = sizeof(dns_vecheader_t);
158
7.30M
  uint32_t buflen = headerlen + 2;
159
7.30M
  isc_result_t result;
160
7.30M
  unsigned int nitems;
161
7.30M
  unsigned int nalloc;
162
7.30M
  unsigned int length;
163
7.30M
  size_t i;
164
7.30M
  size_t rdatasize;
165
166
  /*
167
   * If the source rdataset is also a vec, we don't need
168
   * to do anything special, just copy the whole vec to a
169
   * new buffer.
170
   */
171
7.30M
  if (rdataset->methods == &dns_rdatavec_rdatasetmethods) {
172
0
    dns_vecheader_t *header = dns_vecheader_getheader(rdataset);
173
0
    buflen = dns_rdatavec_size(header);
174
175
0
    rawbuf = newvec(rdataset, mctx, region, buflen);
176
177
0
    INSIST(headerlen <= buflen);
178
0
    memmove(rawbuf, (unsigned char *)header + headerlen,
179
0
      buflen - headerlen);
180
0
    return ISC_R_SUCCESS;
181
0
  }
182
183
  /*
184
   * If there are no rdata then we just need to allocate a header
185
   * with a zero record count.
186
   */
187
7.30M
  nitems = dns_rdataset_count(rdataset);
188
7.30M
  if (nitems == 0) {
189
0
    if (rdataset->type != 0) {
190
0
      return ISC_R_FAILURE;
191
0
    }
192
0
    rawbuf = newvec(rdataset, mctx, region, buflen);
193
0
    put_uint16(rawbuf, 0);
194
0
    return ISC_R_SUCCESS;
195
0
  }
196
197
7.30M
  if (maxrrperset > 0 && nitems > maxrrperset) {
198
0
    return DNS_R_TOOMANYRECORDS;
199
0
  }
200
201
7.30M
  if (nitems > 0xffff) {
202
0
    return ISC_R_NOSPACE;
203
0
  }
204
205
  /*
206
   * Remember the original number of items.
207
   */
208
7.30M
  nalloc = nitems;
209
210
7.30M
  RUNTIME_CHECK(!ckd_mul(&rdatasize, nalloc, sizeof(rdata[0])));
211
7.30M
  rdata = isc_mem_get(mctx, rdatasize);
212
213
  /*
214
   * Save all of the rdata members into an array.
215
   */
216
7.30M
  result = dns_rdataset_first(rdataset);
217
7.30M
  if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) {
218
0
    goto free_rdatas;
219
0
  }
220
14.7M
  for (i = 0; i < nalloc && result == ISC_R_SUCCESS; i++) {
221
7.39M
    INSIST(result == ISC_R_SUCCESS);
222
7.39M
    dns_rdata_init(&rdata[i]);
223
7.39M
    dns_rdataset_current(rdataset, &rdata[i]);
224
7.39M
    INSIST(rdata[i].data != &removed);
225
7.39M
    result = dns_rdataset_next(rdataset);
226
7.39M
  }
227
7.30M
  if (i != nalloc || result != ISC_R_NOMORE) {
228
    /*
229
     * Somehow we iterated over fewer rdatas than
230
     * dns_rdataset_count() said there were or there
231
     * were more items than dns_rdataset_count said
232
     * there were.
233
     */
234
0
    result = ISC_R_FAILURE;
235
0
    goto free_rdatas;
236
0
  }
237
238
  /*
239
   * Put into DNSSEC order.
240
   */
241
7.30M
  if (nalloc > 1U) {
242
7.55k
    qsort(rdata, nalloc, sizeof(rdata[0]), compare_rdata);
243
7.55k
  }
244
245
  /*
246
   * Remove duplicates and compute the total storage required.
247
   *
248
   * If an rdata is not a duplicate, accumulate the storage size
249
   * required for the rdata.  We do not store the class, type, etc,
250
   * just the rdata, so our overhead is 2 bytes for the number of
251
   * records, and 2 bytes for the length of each rdata, plus the
252
   * rdata itself.
253
   */
254
7.39M
  for (i = 1; i < nalloc; i++) {
255
86.0k
    if (compare_rdata(&rdata[i - 1], &rdata[i]) == 0) {
256
77.1k
      rdata[i - 1].data = &removed;
257
77.1k
      nitems--;
258
77.1k
    } else {
259
8.93k
      buflen += 2 + rdata[i - 1].length;
260
      /*
261
       * Provide space to store the per RR meta data.
262
       */
263
8.93k
      if (rdataset->type == dns_rdatatype_rrsig) {
264
722
        buflen++;
265
722
      }
266
8.93k
      if (buflen - headerlen - 2 > DNS_RDATA_MAXLENGTH) {
267
12
        result = ISC_R_NOSPACE;
268
12
        goto free_rdatas;
269
12
      }
270
8.93k
    }
271
86.0k
  }
272
273
  /*
274
   * Don't forget the last item!
275
   */
276
7.30M
  buflen += 2 + rdata[i - 1].length;
277
278
  /*
279
   * Provide space to store the per RR meta data.
280
   */
281
7.30M
  if (rdataset->type == dns_rdatatype_rrsig) {
282
1.89k
    buflen++;
283
1.89k
  }
284
7.30M
  if (buflen - headerlen - 2 > DNS_RDATA_MAXLENGTH) {
285
6
    result = ISC_R_NOSPACE;
286
6
    goto free_rdatas;
287
6
  }
288
289
  /*
290
   * Ensure that singleton types are actually singletons.
291
   */
292
7.30M
  if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) {
293
    /*
294
     * We have a singleton type, but there's more than one
295
     * RR in the rdataset.
296
     */
297
49
    result = DNS_R_SINGLETON;
298
49
    goto free_rdatas;
299
49
  }
300
301
  /*
302
   * Allocate the memory, set up a buffer, start copying in
303
   * data.
304
   */
305
7.30M
  rawbuf = newvec(rdataset, mctx, region, buflen);
306
7.30M
  put_uint16(rawbuf, nitems);
307
308
14.7M
  for (i = 0; i < nalloc; i++) {
309
7.39M
    if (rdata[i].data == &removed) {
310
76.4k
      continue;
311
76.4k
    }
312
7.31M
    length = rdata[i].length;
313
7.31M
    if (rdataset->type == dns_rdatatype_rrsig) {
314
2.61k
      length++;
315
2.61k
    }
316
7.31M
    INSIST(length <= 0xffff);
317
318
7.31M
    put_uint16(rawbuf, length);
319
320
    /*
321
     * Store the per RR meta data.
322
     */
323
7.31M
    if (rdataset->type == dns_rdatatype_rrsig) {
324
2.61k
      *rawbuf++ = (rdata[i].flags & DNS_RDATA_OFFLINE)
325
2.61k
              ? DNS_RDATAVEC_OFFLINE
326
2.61k
              : 0;
327
2.61k
    }
328
7.31M
    if (rdata[i].length != 0) {
329
7.31M
      memmove(rawbuf, rdata[i].data, rdata[i].length);
330
7.31M
    }
331
7.31M
    rawbuf += rdata[i].length;
332
7.31M
  }
333
334
7.30M
  result = ISC_R_SUCCESS;
335
336
7.30M
free_rdatas:
337
7.30M
  isc_mem_put(mctx, rdata, rdatasize);
338
7.30M
  return result;
339
7.30M
}
340
341
isc_result_t
342
dns_rdatavec_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
343
7.30M
        isc_region_t *region, uint32_t maxrrperset) {
344
7.30M
  isc_result_t result;
345
346
7.30M
  if (rdataset->type == dns_rdatatype_none &&
347
0
      rdataset->covers == dns_rdatatype_none)
348
0
  {
349
0
    return DNS_R_DISALLOWED;
350
0
  }
351
352
7.30M
  result = makevec(rdataset, mctx, region, maxrrperset);
353
7.30M
  if (result == ISC_R_SUCCESS) {
354
7.30M
    dns_vecheader_t *new = (dns_vecheader_t *)region->base;
355
356
7.30M
    INSIST(!rdataset->attributes.negative);
357
7.30M
    INSIST(rdataset->type != dns_rdatatype_none);
358
7.30M
    INSIST(dns_rdatatype_issig(rdataset->type) ||
359
7.30M
           rdataset->covers == dns_rdatatype_none);
360
361
    /*
362
     * Reset the vecheader content, but keep the refcount and mctx.
363
     */
364
7.30M
    *new = (dns_vecheader_t){
365
7.30M
      .next_header = ISC_SLINK_INITIALIZER,
366
7.30M
      .typepair = DNS_TYPEPAIR_VALUE(rdataset->type,
367
7.30M
                   rdataset->covers),
368
7.30M
      .trust = rdataset->trust,
369
7.30M
      .ttl = rdataset->ttl,
370
7.30M
      .references = atomic_load_acquire(&new->references),
371
7.30M
      .mctx = new->mctx,
372
7.30M
    };
373
7.30M
  }
374
375
7.30M
  return result;
376
7.30M
}
377
378
unsigned int
379
14.0M
dns_rdatavec_size(dns_vecheader_t *header) {
380
14.0M
  REQUIRE(header != NULL);
381
382
14.0M
  unsigned char *vec = rdatavec_raw(header);
383
14.0M
  INSIST(vec != NULL);
384
385
14.0M
  unsigned char *current = rdatavec_data(header);
386
14.0M
  uint16_t count = rdatavec_count(header);
387
388
320M
  while (count-- > 0) {
389
306M
    uint16_t length = get_uint16(current);
390
306M
    current += length;
391
306M
  }
392
393
14.0M
  return (unsigned int)(current - vec) + header_size(header);
394
14.0M
}
395
396
unsigned int
397
6.57M
dns_rdatavec_count(dns_vecheader_t *header) {
398
6.57M
  REQUIRE(header != NULL);
399
400
6.57M
  return rdatavec_count(header);
401
6.57M
}
402
403
/*
404
 * Make the dns_rdata_t 'rdata' refer to the vec item
405
 * beginning at '*current' (which is part of a vec of type
406
 * 'type' and class 'rdclass') and advance '*current' to
407
 * point to the next item in the vec.
408
 */
409
static void
410
rdata_from_vecitem(unsigned char **current, dns_rdataclass_t rdclass,
411
99.6M
       dns_rdatatype_t type, dns_rdata_t *rdata) {
412
99.6M
  unsigned char *tcurrent = *current;
413
99.6M
  isc_region_t region;
414
99.6M
  bool offline = false;
415
99.6M
  uint16_t length = get_uint16(tcurrent);
416
417
99.6M
  if (type == dns_rdatatype_rrsig) {
418
7.67k
    if ((*tcurrent & DNS_RDATAVEC_OFFLINE) != 0) {
419
0
      offline = true;
420
0
    }
421
7.67k
    length--;
422
7.67k
    tcurrent++;
423
7.67k
  }
424
99.6M
  region.length = length;
425
99.6M
  region.base = tcurrent;
426
99.6M
  tcurrent += region.length;
427
99.6M
  dns_rdata_fromregion(rdata, rdclass, type, &region);
428
99.6M
  if (offline) {
429
0
    rdata->flags |= DNS_RDATA_OFFLINE;
430
0
  }
431
99.6M
  *current = tcurrent;
432
99.6M
}
433
434
static void
435
rdata_to_vecitem(unsigned char **current, dns_rdatatype_t type,
436
97.6M
     dns_rdata_t *rdata) {
437
97.6M
  unsigned int length = rdata->length;
438
97.6M
  unsigned char *data = rdata->data;
439
97.6M
  unsigned char *p = *current;
440
441
97.6M
  if (type == dns_rdatatype_rrsig) {
442
2.23k
    length++;
443
2.23k
    data--;
444
2.23k
  }
445
446
97.6M
  put_uint16(p, length);
447
97.6M
  memmove(p, data, length);
448
97.6M
  p += length;
449
450
97.6M
  *current = p;
451
97.6M
}
452
453
typedef struct vecinfo {
454
  unsigned char *pos;
455
  dns_rdata_t rdata;
456
  bool dup;
457
} vecinfo_t;
458
459
isc_result_t
460
dns_rdatavec_merge(dns_vecheader_t *oheader, dns_vecheader_t *nheader,
461
       isc_mem_t *mctx, dns_rdataclass_t rdclass,
462
       dns_rdatatype_t type, unsigned int flags,
463
1.05M
       uint32_t maxrrperset, dns_vecheader_t **theaderp) {
464
1.05M
  isc_result_t result = ISC_R_SUCCESS;
465
1.05M
  unsigned char *ocurrent = NULL, *ncurrent = NULL, *tcurrent = NULL;
466
1.05M
  unsigned int ocount, ncount, tcount = 0;
467
1.05M
  uint32_t tlength;
468
1.05M
  vecinfo_t *oinfo = NULL, *ninfo = NULL;
469
1.05M
  size_t o = 0, n = 0;
470
471
1.05M
  REQUIRE(theaderp != NULL && *theaderp == NULL);
472
1.05M
  REQUIRE(oheader != NULL && nheader != NULL);
473
474
1.05M
  ocurrent = rdatavec_data(oheader);
475
1.05M
  ocount = rdatavec_count(oheader);
476
477
1.05M
  ncurrent = rdatavec_data(nheader);
478
1.05M
  ncount = rdatavec_count(nheader);
479
480
1.05M
  INSIST(ocount > 0 && ncount > 0);
481
482
1.05M
  if (maxrrperset > 0 && ocount + ncount > maxrrperset) {
483
0
    return DNS_R_TOOMANYRECORDS;
484
0
  }
485
486
  /*
487
   * Figure out the target length. Start with the header,
488
   * plus 2 octets for the count.
489
   */
490
1.05M
  tlength = header_size(oheader) + 2;
491
492
  /*
493
   * Allocate both info arrays up front so the cleanup path is
494
   * always safe to call regardless of where we exit.
495
   */
496
1.05M
  oinfo = isc_mem_cget(mctx, ocount, sizeof(struct vecinfo));
497
1.05M
  ninfo = isc_mem_cget(mctx, ncount, sizeof(struct vecinfo));
498
499
  /*
500
   * Gather the rdatas in the old vec and add their lengths to
501
   * the larget length.
502
   */
503
99.6M
  for (size_t i = 0; i < ocount; i++) {
504
98.5M
    oinfo[i].pos = ocurrent;
505
98.5M
    dns_rdata_init(&oinfo[i].rdata);
506
98.5M
    rdata_from_vecitem(&ocurrent, rdclass, type, &oinfo[i].rdata);
507
98.5M
    tlength += (uint32_t)(ocurrent - oinfo[i].pos);
508
98.5M
    if (tlength - header_size(oheader) - 2 > DNS_RDATA_MAXLENGTH) {
509
0
      CLEANUP(ISC_R_NOSPACE);
510
0
    }
511
98.5M
  }
512
513
  /*
514
   * Then add the length of rdatas in the new vec that aren't
515
   * duplicated in the old vec.
516
   */
517
2.12M
  for (size_t i = 0; i < ncount; i++) {
518
1.06M
    ninfo[i].pos = ncurrent;
519
1.06M
    dns_rdata_init(&ninfo[i].rdata);
520
1.06M
    rdata_from_vecitem(&ncurrent, rdclass, type, &ninfo[i].rdata);
521
522
98.6M
    for (size_t j = 0; j < ocount; j++) {
523
98.5M
      if (oinfo[j].dup) {
524
        /*
525
         * This was already found to be
526
         * duplicated; no need to compare
527
         * it again.
528
         */
529
7.75k
        continue;
530
7.75k
      }
531
532
98.4M
      if (dns_rdata_compare(&oinfo[j].rdata,
533
98.4M
                &ninfo[i].rdata) == 0)
534
905k
      {
535
        /*
536
         * Found a dup. Mark the old copy as a
537
         * duplicate so we don't check it again;
538
         * mark the new copy as a duplicate so we
539
         * don't copy it to the target.
540
         */
541
905k
        oinfo[j].dup = ninfo[i].dup = true;
542
905k
        break;
543
905k
      }
544
98.4M
    }
545
546
1.06M
    if (ninfo[i].dup) {
547
905k
      continue;
548
905k
    }
549
550
    /*
551
     * We will be copying this item to the target, so
552
     * add its length to tlength and increment tcount.
553
     */
554
157k
    tlength += (uint32_t)(ncurrent - ninfo[i].pos);
555
157k
    if (tlength - header_size(oheader) - 2 > DNS_RDATA_MAXLENGTH) {
556
41
      CLEANUP(ISC_R_NOSPACE);
557
0
    }
558
157k
    tcount++;
559
157k
  }
560
561
  /*
562
   * If the EXACT flag is set, there can't be any rdata in
563
   * the new vec that was also in the old. If tcount is less
564
   * than ncount, then we found such a duplicate.
565
   */
566
1.05M
  if (((flags & DNS_RDATAVEC_EXACT) != 0) && (tcount < ncount)) {
567
0
    CLEANUP(DNS_R_NOTEXACT);
568
0
  }
569
570
  /*
571
   * If nothing's being copied in from the new vec, and the
572
   * FORCE flag isn't set, we're done.
573
   */
574
1.05M
  if (tcount == 0 && (flags & DNS_RDATAVEC_FORCE) == 0) {
575
898k
    CLEANUP(DNS_R_UNCHANGED);
576
0
  }
577
578
  /* Add to tcount the total number of items from the old vec. */
579
159k
  tcount += ocount;
580
581
  /* Resposition ncurrent at the first item. */
582
159k
  ncurrent = rdatavec_data(nheader);
583
584
  /* Single types can't have more than one RR. */
585
159k
  if (tcount > 1 && dns_rdatatype_issingleton(type)) {
586
13
    CLEANUP(DNS_R_SINGLETON);
587
0
  }
588
589
159k
  if (tcount > 0xffff) {
590
0
    CLEANUP(ISC_R_NOSPACE);
591
0
  }
592
593
  /*
594
   * Allocate the target buffer and initialize the header.
595
   * Preserve the case of the old header, but the rest from the
596
   * new header.
597
   */
598
159k
  unsigned char *tstart = isc_mem_get(mctx, tlength);
599
159k
  dns_vecheader_t *as_header = (dns_vecheader_t *)tstart;
600
159k
  uint16_t attrs = DNS_VECHEADER_GETATTR(
601
159k
    oheader,
602
159k
    DNS_VECHEADERATTR_CASESET | DNS_VECHEADERATTR_CASEFULLYLOWER);
603
159k
  if (RESIGN(nheader)) {
604
0
    attrs |= DNS_VECHEADERATTR_RESIGN;
605
0
  }
606
159k
  *as_header = (dns_vecheader_t){
607
159k
    .typepair = nheader->typepair,
608
159k
    .mctx = isc_mem_ref(mctx),
609
159k
    .serial = nheader->serial,
610
159k
    .ttl = nheader->ttl,
611
159k
    .resign = nheader->resign,
612
159k
    .next_header = ISC_SLINK_INITIALIZER,
613
159k
  };
614
159k
  isc_refcount_init(&as_header->references, 1);
615
159k
  atomic_init(&as_header->attributes, attrs);
616
159k
  atomic_init(&as_header->trust, atomic_load_acquire(&nheader->trust));
617
159k
  memmove(as_header->upper, oheader->upper, sizeof(oheader->upper));
618
619
159k
  tcurrent = tstart + header_size(nheader);
620
621
  /* Write the new count, then start merging the vecs. */
622
159k
  put_uint16(tcurrent, tcount);
623
624
  /*
625
   * Now walk the sets together, adding each item in DNSSEC order,
626
   * and skipping over any more dups in the new vec.
627
   */
628
97.8M
  while (o < ocount || n < ncount) {
629
97.6M
    bool fromold;
630
631
    /* Skip to the next non-duplicate in the new vec. */
632
97.6M
    for (; n < ncount && ninfo[n].dup; n++)
633
4.75k
      ;
634
635
97.6M
    if (o == ocount) {
636
149k
      fromold = false;
637
97.5M
    } else if (n == ncount) {
638
188k
      fromold = true;
639
97.3M
    } else {
640
97.3M
      fromold = dns_rdata_compare(&oinfo[o].rdata,
641
97.3M
                &ninfo[n].rdata) < 0;
642
97.3M
    }
643
644
97.6M
    if (fromold) {
645
97.5M
      rdata_to_vecitem(&tcurrent, type, &oinfo[o].rdata);
646
97.5M
      if (++o < ocount) {
647
        /* Skip to the next rdata in the old vec */
648
97.3M
        continue;
649
97.3M
      }
650
97.5M
    } else {
651
157k
      rdata_to_vecitem(&tcurrent, type, &ninfo[n++].rdata);
652
157k
    }
653
97.6M
  }
654
655
159k
  INSIST(tcurrent == tstart + tlength);
656
657
159k
  *theaderp = (dns_vecheader_t *)tstart;
658
659
1.05M
cleanup:
660
1.05M
  isc_mem_cput(mctx, oinfo, ocount, sizeof(struct vecinfo));
661
1.05M
  isc_mem_cput(mctx, ninfo, ncount, sizeof(struct vecinfo));
662
663
1.05M
  return result;
664
159k
}
665
666
isc_result_t
667
dns_rdatavec_subtract(dns_vecheader_t *oheader, dns_vecheader_t *sheader,
668
          isc_mem_t *mctx, dns_rdataclass_t rdclass,
669
          dns_rdatatype_t type, unsigned int flags,
670
0
          dns_vecheader_t **theaderp) {
671
0
  isc_result_t result = ISC_R_SUCCESS;
672
0
  unsigned char *ocurrent = NULL, *scurrent = NULL;
673
0
  unsigned char *tstart = NULL, *tcurrent = NULL;
674
0
  unsigned int ocount, scount;
675
0
  uint32_t tlength;
676
0
  unsigned int tcount = 0, rcount = 0;
677
0
  vecinfo_t *oinfo = NULL, *sinfo = NULL;
678
679
0
  REQUIRE(theaderp != NULL && *theaderp == NULL);
680
0
  REQUIRE(oheader != NULL && sheader != NULL);
681
682
0
  ocurrent = rdatavec_data(oheader);
683
0
  ocount = rdatavec_count(oheader);
684
685
0
  scurrent = rdatavec_data(sheader);
686
0
  scount = rdatavec_count(sheader);
687
688
0
  INSIST(ocount > 0 && scount > 0);
689
690
  /* Get info about the rdatas being subtracted */
691
0
  sinfo = isc_mem_cget(mctx, scount, sizeof(struct vecinfo));
692
0
  for (size_t i = 0; i < scount; i++) {
693
0
    sinfo[i].pos = scurrent;
694
0
    dns_rdata_init(&sinfo[i].rdata);
695
0
    rdata_from_vecitem(&scurrent, rdclass, type, &sinfo[i].rdata);
696
0
  }
697
698
  /*
699
   * Figure out the target length. Start with the header,
700
   * plus 2 octets for the count.
701
   */
702
0
  tlength = header_size(oheader) + 2;
703
704
  /*
705
   * Add the length of the rdatas in the old vec that
706
   * aren't being subtracted.
707
   */
708
0
  oinfo = isc_mem_cget(mctx, ocount, sizeof(struct vecinfo));
709
0
  for (size_t i = 0; i < ocount; i++) {
710
0
    bool matched = false;
711
712
0
    oinfo[i].pos = ocurrent;
713
0
    dns_rdata_init(&oinfo[i].rdata);
714
0
    rdata_from_vecitem(&ocurrent, rdclass, type, &oinfo[i].rdata);
715
716
0
    for (size_t j = 0; j < scount; j++) {
717
0
      if (sinfo[j].dup) {
718
0
        continue;
719
0
      } else if (dns_rdata_compare(&oinfo[i].rdata,
720
0
                 &sinfo[j].rdata) == 0)
721
0
      {
722
0
        matched = true;
723
0
        oinfo[i].dup = sinfo[j].dup = true;
724
0
        break;
725
0
      }
726
0
    }
727
728
0
    if (matched) {
729
      /* This item will be subtracted. */
730
0
      rcount++;
731
0
    } else {
732
      /*
733
       * This rdata wasn't in the vec to be subtracted,
734
       * so copy it to the target.  Add its length to
735
       * tlength and increment tcount.
736
       */
737
0
      tlength += (uint32_t)(ocurrent - oinfo[i].pos);
738
0
      if (tlength - header_size(oheader) - 2 >
739
0
          DNS_RDATA_MAXLENGTH)
740
0
      {
741
0
        CLEANUP(ISC_R_NOSPACE);
742
0
      }
743
0
      tcount++;
744
0
    }
745
0
  }
746
747
  /*
748
   * If the EXACT flag wasn't set, check that all the records that
749
   * were to be subtracted actually did exist in the original vec.
750
   * (The numeric check works here because rdatavecs do not contain
751
   * duplicates.)
752
   */
753
0
  if ((flags & DNS_RDATAVEC_EXACT) != 0 && rcount != scount) {
754
0
    CLEANUP(DNS_R_NOTEXACT);
755
0
  }
756
757
  /*
758
   * If the resulting rdatavec would be empty, don't bother to
759
   * create a new buffer, just return.
760
   */
761
0
  if (tcount == 0) {
762
0
    CLEANUP(DNS_R_NXRRSET);
763
0
  }
764
765
  /*
766
   * If nothing is going to change, stop.
767
   */
768
0
  if (rcount == 0) {
769
0
    CLEANUP(DNS_R_UNCHANGED);
770
0
  }
771
772
  /*
773
   * Allocate the target buffer and copy the old vec's header.
774
   */
775
0
  tstart = isc_mem_get(mctx, tlength);
776
0
  dns_vecheader_t *as_header = (dns_vecheader_t *)tstart;
777
0
  uint16_t attrs = RESIGN(oheader) ? DNS_VECHEADERATTR_RESIGN : 0;
778
0
  *as_header = (dns_vecheader_t){
779
0
    .typepair = oheader->typepair,
780
0
    .mctx = isc_mem_ref(mctx),
781
0
    .serial = oheader->serial,
782
0
    .ttl = oheader->ttl,
783
0
    .resign = oheader->resign,
784
0
    .next_header = ISC_SLINK_INITIALIZER,
785
0
  };
786
0
  isc_refcount_init(&as_header->references, 1);
787
0
  atomic_init(&as_header->attributes, attrs);
788
0
  atomic_init(&as_header->trust, atomic_load_acquire(&oheader->trust));
789
0
  memmove(as_header->upper, oheader->upper, sizeof(oheader->upper));
790
791
0
  tcurrent = tstart + header_size(oheader);
792
793
  /*
794
   * Write the new count.
795
   */
796
0
  put_uint16(tcurrent, tcount);
797
798
  /*
799
   * Copy the parts of the old vec that didn't have duplicates.
800
   */
801
0
  for (size_t i = 0; i < ocount; i++) {
802
0
    if (!oinfo[i].dup) {
803
0
      rdata_to_vecitem(&tcurrent, type, &oinfo[i].rdata);
804
0
    }
805
0
  }
806
807
0
  INSIST(tcurrent == tstart + tlength);
808
809
0
  *theaderp = (dns_vecheader_t *)tstart;
810
811
0
cleanup:
812
0
  isc_mem_cput(mctx, oinfo, ocount, sizeof(struct vecinfo));
813
0
  isc_mem_cput(mctx, sinfo, scount, sizeof(struct vecinfo));
814
815
0
  return result;
816
0
}
817
818
void
819
7.30M
dns_vecheader_setownercase(dns_vecheader_t *header, const dns_name_t *name) {
820
7.30M
  REQUIRE(!CASESET(header));
821
822
7.30M
  bool casefullylower = true;
823
824
  /*
825
   * We do not need to worry about label lengths as they are all
826
   * less than or equal to 63.
827
   */
828
7.30M
  memset(header->upper, 0, sizeof(header->upper));
829
82.0M
  for (size_t i = 0; i < name->length; i++) {
830
74.7M
    if (isupper(name->ndata[i])) {
831
4.78M
      header->upper[i / 8] |= 1 << (i % 8);
832
4.78M
      casefullylower = false;
833
4.78M
    }
834
74.7M
  }
835
7.30M
  if (casefullylower) {
836
5.64M
    DNS_VECHEADER_SETATTR(header, DNS_VECHEADERATTR_CASEFULLYLOWER);
837
5.64M
  }
838
7.30M
  DNS_VECHEADER_SETATTR(header, DNS_VECHEADERATTR_CASESET);
839
7.30M
}
840
841
dns_vecheader_t *
842
0
dns_vecheader_new(isc_mem_t *mctx) {
843
0
  dns_vecheader_t *h = NULL;
844
845
0
  h = isc_mem_get(mctx, sizeof(*h));
846
0
  *h = (dns_vecheader_t){
847
0
    .references = ISC_REFCOUNT_INITIALIZER(1),
848
0
    .mctx = isc_mem_ref(mctx),
849
0
  };
850
0
  return h;
851
0
}
852
853
/* Iterators for already bound rdatavec */
854
855
isc_result_t
856
vecheader_first(rdatavec_iter_t *iter, dns_vecheader_t *header,
857
187
    dns_rdataclass_t rdclass) {
858
187
  unsigned char *raw = rdatavec_data(header);
859
187
  uint16_t count = rdatavec_count(header);
860
187
  if (count == 0) {
861
0
    iter->iter_pos = NULL;
862
0
    iter->iter_count = 0;
863
0
    return ISC_R_NOMORE;
864
0
  }
865
866
  /*
867
   * iter.iter_count is the number of rdata beyond the cursor
868
   * position, so we decrement the total count by one before
869
   * storing it.
870
   *
871
   * 'raw' points to the first record.
872
   */
873
187
  iter->iter_pos = raw;
874
187
  iter->iter_count = count - 1;
875
187
  iter->iter_rdclass = rdclass;
876
187
  iter->iter_type = DNS_TYPEPAIR_TYPE(header->typepair);
877
878
187
  return ISC_R_SUCCESS;
879
187
}
880
881
isc_result_t
882
214
vecheader_next(rdatavec_iter_t *iter) {
883
214
  uint16_t count = iter->iter_count;
884
214
  if (count == 0) {
885
154
    iter->iter_pos = NULL;
886
154
    return ISC_R_NOMORE;
887
154
  }
888
60
  iter->iter_count = count - 1;
889
890
  /*
891
   * Skip forward one record (length + 4) or one offset (4).
892
   */
893
60
  unsigned char *raw = iter->iter_pos;
894
60
  uint16_t length = peek_uint16(raw);
895
60
  raw += length;
896
60
  iter->iter_pos = raw + sizeof(uint16_t);
897
898
60
  return ISC_R_SUCCESS;
899
214
}
900
901
void
902
247
vecheader_current(rdatavec_iter_t *iter, dns_rdata_t *rdata) {
903
247
  unsigned char *raw = NULL;
904
247
  unsigned int length;
905
247
  isc_region_t r;
906
247
  unsigned int flags = 0;
907
908
247
  raw = iter->iter_pos;
909
247
  REQUIRE(raw != NULL);
910
911
  /*
912
   * Find the start of the record if not already in iter_pos
913
   * then skip the length and order fields.
914
   */
915
247
  length = get_uint16(raw);
916
917
247
  if (iter->iter_type == dns_rdatatype_rrsig) {
918
0
    if (*raw & DNS_RDATAVEC_OFFLINE) {
919
0
      flags |= DNS_RDATA_OFFLINE;
920
0
    }
921
0
    length--;
922
0
    raw++;
923
0
  }
924
247
  r.length = length;
925
247
  r.base = raw;
926
247
  dns_rdata_fromregion(rdata, iter->iter_rdclass, iter->iter_type, &r);
927
247
  rdata->flags |= flags;
928
247
}
929
930
/* Fixed RRSet helper macros */
931
932
static void
933
191
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
934
191
  dns_vecheader_unref(rdataset->vec.header);
935
191
}
936
937
static isc_result_t
938
179
rdataset_first(dns_rdataset_t *rdataset) {
939
179
  return vecheader_first(&rdataset->vec.iter, rdataset->vec.header,
940
179
             rdataset->rdclass);
941
179
}
942
943
static isc_result_t
944
197
rdataset_next(dns_rdataset_t *rdataset) {
945
197
  return vecheader_next(&rdataset->vec.iter);
946
197
}
947
948
static void
949
229
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
950
229
  vecheader_current(&rdataset->vec.iter, rdata);
951
229
}
952
953
static void
954
rdataset_clone(const dns_rdataset_t *source,
955
0
         dns_rdataset_t *target DNS__DB_FLARG) {
956
0
  INSIST(!ISC_LINK_LINKED(target, link));
957
0
  *target = *source;
958
0
  ISC_LINK_INIT(target, link);
959
960
0
  target->vec.iter.iter_pos = NULL;
961
0
  target->vec.iter.iter_count = 0;
962
963
0
  dns_vecheader_ref(target->vec.header);
964
0
}
965
966
static unsigned int
967
0
rdataset_count(dns_rdataset_t *rdataset) {
968
0
  return rdatavec_count(rdataset->vec.header);
969
0
}
970
971
static void
972
0
rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
973
0
  dns_vecheader_t *header = dns_vecheader_getheader(rdataset);
974
975
0
  rdataset->trust = trust;
976
0
  atomic_store_release(&header->trust, trust);
977
0
}
978
979
static void
980
0
rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
981
0
  dns_vecheader_t *header = dns_vecheader_getheader(rdataset);
982
0
  uint8_t mask = (1 << 7);
983
0
  uint8_t bits = 0;
984
985
0
  if (!CASESET(header)) {
986
0
    return;
987
0
  }
988
989
0
  if (CASEFULLYLOWER(header)) {
990
0
    isc_ascii_lowercopy(name->ndata, name->ndata, name->length);
991
0
    return;
992
0
  }
993
994
0
  uint8_t *nd = name->ndata;
995
0
  for (size_t i = 0; i < name->length; i++) {
996
0
    if (mask == (1 << 7)) {
997
0
      bits = header->upper[i / 8];
998
0
      mask = 1;
999
0
    } else {
1000
0
      mask <<= 1;
1001
0
    }
1002
0
    nd[i] = (bits & mask) ? isc_ascii_toupper(nd[i])
1003
0
              : isc_ascii_tolower(nd[i]);
1004
0
  }
1005
0
}
1006
1007
dns_vecheader_t *
1008
0
dns_vecheader_getheader(const dns_rdataset_t *rdataset) {
1009
0
  return rdataset->vec.header;
1010
0
}
1011
1012
dns_vecheader_t *
1013
0
dns_vecheader_moveheader(dns_rdataset_t *rdataset) {
1014
0
  dns_vecheader_t *header = MOVE_OWNERSHIP(rdataset->vec.header);
1015
  /*
1016
   * We stole the header, it is safe to reset the rdataset.
1017
   */
1018
0
  dns_rdataset_init(rdataset);
1019
0
  return header;
1020
0
}
1021
1022
dns_vectop_t *
1023
6.25M
dns_vectop_new(isc_mem_t *mctx, dns_typepair_t typepair) {
1024
6.25M
  dns_vectop_t *top = isc_mem_get(mctx, sizeof(*top));
1025
6.25M
  *top = (dns_vectop_t){
1026
6.25M
    .next_type = ISC_SLINK_INITIALIZER,
1027
6.25M
    .headers = ISC_SLIST_INITIALIZER,
1028
6.25M
    .typepair = typepair,
1029
6.25M
  };
1030
1031
6.25M
  return top;
1032
6.25M
}
1033
1034
void
1035
6.25M
dns_vectop_destroy(isc_mem_t *mctx, dns_vectop_t **topp) {
1036
6.25M
  REQUIRE(topp != NULL && *topp != NULL);
1037
6.25M
  dns_vectop_t *top = *topp;
1038
6.25M
  *topp = NULL;
1039
6.25M
  isc_mem_put(mctx, top, sizeof(*top));
1040
6.25M
}
1041
1042
static void
1043
7.46M
vecheader_destroy(dns_vecheader_t *header) {
1044
7.46M
  unsigned int size = EXISTS(header) ? dns_rdatavec_size(header)
1045
18.4E
             : sizeof(*header);
1046
1047
7.46M
  isc_mem_putanddetach(&header->mctx, header, size);
1048
7.46M
}
1049
1050
/*
1051
 * Reference counting implementation for dns_vecheader_t
1052
 */
1053
ISC_REFCOUNT_IMPL(dns_vecheader, vecheader_destroy);
dns_vecheader_ref
Line
Count
Source
1053
ISC_REFCOUNT_IMPL(dns_vecheader, vecheader_destroy);
dns_vecheader_unref
Line
Count
Source
1053
ISC_REFCOUNT_IMPL(dns_vecheader, vecheader_destroy);
Unexecuted instantiation: dns_vecheader_detach