Coverage Report

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