Coverage Report

Created: 2026-03-07 06:55

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