Coverage Report

Created: 2026-01-17 06:14

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