Coverage Report

Created: 2025-08-03 06:33

/src/bind9/lib/dns/rdataset.c
Line
Count
Source (jump to first uncovered line)
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 <inttypes.h>
17
#include <stdbool.h>
18
#include <stdlib.h>
19
20
#include <isc/buffer.h>
21
#include <isc/mem.h>
22
#include <isc/random.h>
23
#include <isc/serial.h>
24
#include <isc/util.h>
25
26
#include <dns/compress.h>
27
#include <dns/fixedname.h>
28
#include <dns/name.h>
29
#include <dns/ncache.h>
30
#include <dns/rdata.h>
31
#include <dns/rdataset.h>
32
#include <dns/types.h>
33
34
static const char *trustnames[] = {
35
  "none",     "pending-additional",
36
  "pending-answer", "additional",
37
  "glue",     "answer",
38
  "authauthority",  "authanswer",
39
  "secure",   "local" /* aka ultimate */
40
};
41
42
const char *
43
0
dns_trust_totext(dns_trust_t trust) {
44
0
  if (trust >= sizeof(trustnames) / sizeof(*trustnames)) {
45
0
    return "bad";
46
0
  }
47
0
  return trustnames[trust];
48
0
}
49
50
void
51
6.38M
dns_rdataset_init(dns_rdataset_t *rdataset) {
52
  /*
53
   * Make 'rdataset' a valid, disassociated rdataset.
54
   */
55
56
6.38M
  REQUIRE(rdataset != NULL);
57
58
6.38M
  *rdataset = (dns_rdataset_t){
59
6.38M
    .magic = DNS_RDATASET_MAGIC,
60
6.38M
    .link = ISC_LINK_INITIALIZER,
61
6.38M
    .count = DNS_RDATASET_COUNT_UNDEFINED,
62
6.38M
  };
63
6.38M
}
64
65
void
66
4
dns_rdataset_invalidate(dns_rdataset_t *rdataset) {
67
  /*
68
   * Invalidate 'rdataset'.
69
   */
70
71
4
  REQUIRE(DNS_RDATASET_VALID(rdataset));
72
4
  REQUIRE(rdataset->methods == NULL);
73
74
4
  *rdataset = (dns_rdataset_t){
75
4
    .magic = 0,
76
4
    .link = ISC_LINK_INITIALIZER,
77
4
    .count = DNS_RDATASET_COUNT_UNDEFINED,
78
4
  };
79
4
}
80
81
void
82
455k
dns__rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
83
  /*
84
   * Disassociate 'rdataset' from its rdata, allowing it to be reused.
85
   */
86
87
455k
  REQUIRE(DNS_RDATASET_VALID(rdataset));
88
455k
  REQUIRE(rdataset->methods != NULL);
89
90
455k
  if (rdataset->methods->disassociate != NULL) {
91
455k
    (rdataset->methods->disassociate)(rdataset DNS__DB_FLARG_PASS);
92
455k
  }
93
455k
  *rdataset = (dns_rdataset_t){
94
455k
    .magic = DNS_RDATASET_MAGIC,
95
455k
    .link = ISC_LINK_INITIALIZER,
96
455k
    .count = DNS_RDATASET_COUNT_UNDEFINED,
97
455k
  };
98
455k
}
99
100
bool
101
6.84M
dns_rdataset_isassociated(dns_rdataset_t *rdataset) {
102
  /*
103
   * Is 'rdataset' associated?
104
   */
105
106
6.84M
  REQUIRE(DNS_RDATASET_VALID(rdataset));
107
108
6.84M
  if (rdataset->methods != NULL) {
109
738
    return true;
110
738
  }
111
112
6.83M
  return false;
113
6.84M
}
114
115
static isc_result_t
116
0
question_cursor(dns_rdataset_t *rdataset ISC_ATTR_UNUSED) {
117
0
  return ISC_R_NOMORE;
118
0
}
119
120
static void
121
0
question_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) {
122
0
  *target = *source;
123
0
}
124
125
static dns_rdatasetmethods_t question_methods = {
126
  .first = question_cursor,
127
  .next = question_cursor,
128
  .clone = question_clone,
129
};
130
131
void
132
dns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass,
133
0
        dns_rdatatype_t type) {
134
  /*
135
   * Make 'rdataset' a valid, associated, question rdataset, with a
136
   * question class of 'rdclass' and type 'type'.
137
   */
138
139
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
140
0
  REQUIRE(rdataset->methods == NULL);
141
142
0
  rdataset->methods = &question_methods;
143
0
  rdataset->rdclass = rdclass;
144
0
  rdataset->type = type;
145
0
  rdataset->attributes.question = true;
146
0
}
147
148
unsigned int
149
5.98M
dns_rdataset_count(dns_rdataset_t *rdataset) {
150
  /*
151
   * Return the number of records in 'rdataset'.
152
   */
153
154
5.98M
  REQUIRE(DNS_RDATASET_VALID(rdataset));
155
5.98M
  REQUIRE(rdataset->methods != NULL);
156
5.98M
  REQUIRE(rdataset->methods->count != NULL);
157
158
5.98M
  return (rdataset->methods->count)(rdataset);
159
5.98M
}
160
161
void
162
dns__rdataset_clone(dns_rdataset_t *source,
163
0
        dns_rdataset_t *target DNS__DB_FLARG) {
164
  /*
165
   * Make 'target' refer to the same rdataset as 'source'.
166
   */
167
168
0
  REQUIRE(DNS_RDATASET_VALID(source));
169
0
  REQUIRE(source->methods != NULL);
170
0
  REQUIRE(DNS_RDATASET_VALID(target));
171
0
  REQUIRE(target->methods == NULL);
172
173
0
  (source->methods->clone)(source, target DNS__DB_FLARG_PASS);
174
0
}
175
176
isc_result_t
177
6.27M
dns_rdataset_first(dns_rdataset_t *rdataset) {
178
6.27M
  REQUIRE(DNS_RDATASET_VALID(rdataset));
179
6.27M
  REQUIRE(rdataset->methods != NULL);
180
6.27M
  REQUIRE(rdataset->methods->first != NULL);
181
182
6.27M
  isc_result_t result = rdataset->methods->first(rdataset);
183
6.27M
  ENSURE(result == ISC_R_SUCCESS || result == ISC_R_NOMORE);
184
6.27M
  return result;
185
6.27M
}
186
187
isc_result_t
188
6.50M
dns_rdataset_next(dns_rdataset_t *rdataset) {
189
6.50M
  REQUIRE(DNS_RDATASET_VALID(rdataset));
190
6.50M
  REQUIRE(rdataset->methods != NULL);
191
6.50M
  REQUIRE(rdataset->methods->next != NULL);
192
193
6.50M
  isc_result_t result = rdataset->methods->next(rdataset);
194
6.50M
  ENSURE(result == ISC_R_SUCCESS || result == ISC_R_NOMORE);
195
6.50M
  return result;
196
6.50M
}
197
198
void
199
6.48M
dns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
200
  /*
201
   * Make 'rdata' refer to the current rdata.
202
   */
203
204
6.48M
  REQUIRE(DNS_RDATASET_VALID(rdataset));
205
6.48M
  REQUIRE(rdataset->methods != NULL);
206
6.48M
  REQUIRE(rdataset->methods->current != NULL);
207
208
6.48M
  (rdataset->methods->current)(rdataset, rdata);
209
6.48M
}
210
211
0
#define MAX_SHUFFLE    32
212
92.3k
#define WANT_RANDOM(r) (((r)->attributes.order == dns_order_randomize))
213
92.3k
#define WANT_CYCLIC(r) (((r)->attributes.order == dns_order_cyclic))
214
215
struct towire_sort {
216
  int key;
217
  dns_rdata_t *rdata;
218
};
219
220
static void
221
0
swap_rdata(dns_rdata_t *in, unsigned int a, unsigned int b) {
222
0
  dns_rdata_t rdata = in[a];
223
0
  in[a] = in[b];
224
0
  in[b] = rdata;
225
0
}
226
227
static isc_result_t
228
towire(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
229
       dns_compress_t *cctx, isc_buffer_t *target, bool partial,
230
       unsigned int options, unsigned int *countp,
231
92.3k
       void **state ISC_ATTR_UNUSED) {
232
92.3k
  isc_region_t r;
233
92.3k
  isc_result_t result;
234
92.3k
  unsigned int i, count = 0, added;
235
92.3k
  isc_buffer_t savedbuffer, rdlen, rrbuffer;
236
92.3k
  unsigned int headlen;
237
92.3k
  bool question = false;
238
92.3k
  bool shuffle = false;
239
92.3k
  bool want_random, want_cyclic;
240
92.3k
  dns_rdata_t in_fixed[MAX_SHUFFLE];
241
92.3k
  dns_rdata_t *in = in_fixed;
242
92.3k
  struct towire_sort out_fixed[MAX_SHUFFLE];
243
92.3k
  struct towire_sort *out = out_fixed;
244
92.3k
  dns_fixedname_t fixed;
245
92.3k
  dns_name_t *name = NULL;
246
247
  /*
248
   * Convert 'rdataset' to wire format, compressing names as specified
249
   * in cctx, and storing the result in 'target'.
250
   */
251
252
92.3k
  REQUIRE(DNS_RDATASET_VALID(rdataset));
253
92.3k
  REQUIRE(rdataset->methods != NULL);
254
92.3k
  REQUIRE(countp != NULL);
255
92.3k
  REQUIRE(cctx != NULL && cctx->mctx != NULL);
256
257
92.3k
  want_random = WANT_RANDOM(rdataset);
258
92.3k
  want_cyclic = WANT_CYCLIC(rdataset);
259
260
92.3k
  if (rdataset->attributes.question) {
261
23.4k
    question = true;
262
23.4k
    count = 1;
263
23.4k
    result = dns_rdataset_first(rdataset);
264
23.4k
    INSIST(result == ISC_R_NOMORE);
265
68.8k
  } else if (rdataset->attributes.negative) {
266
    /*
267
     * This is a negative caching rdataset.
268
     */
269
0
    unsigned int ncache_opts = 0;
270
0
    if ((options & DNS_RDATASETTOWIRE_OMITDNSSEC) != 0) {
271
0
      ncache_opts |= DNS_NCACHETOWIRE_OMITDNSSEC;
272
0
    }
273
0
    return dns_ncache_towire(rdataset, cctx, target, ncache_opts,
274
0
           countp);
275
68.8k
  } else {
276
68.8k
    count = dns_rdataset_count(rdataset);
277
68.8k
    result = dns_rdataset_first(rdataset);
278
68.8k
    if (result == ISC_R_NOMORE) {
279
0
      return ISC_R_SUCCESS;
280
0
    }
281
68.8k
    if (result != ISC_R_SUCCESS) {
282
0
      return result;
283
0
    }
284
68.8k
  }
285
286
  /*
287
   * Do we want to shuffle this answer?
288
   */
289
92.3k
  if (!question && count > 1 && rdataset->type != dns_rdatatype_rrsig) {
290
15.9k
    if (want_random || want_cyclic) {
291
0
      shuffle = true;
292
0
    }
293
15.9k
  }
294
295
92.3k
  if (shuffle) {
296
0
    if (count > MAX_SHUFFLE) {
297
0
      in = isc_mem_cget(cctx->mctx, count, sizeof(*in));
298
0
      out = isc_mem_cget(cctx->mctx, count, sizeof(*out));
299
0
      if (in == NULL || out == NULL) {
300
0
        shuffle = false;
301
0
      }
302
0
    }
303
0
  }
304
305
92.3k
  if (shuffle) {
306
0
    uint32_t seed = 0;
307
0
    unsigned int j = 0;
308
309
    /*
310
     * First we get handles to all of the rdata.
311
     */
312
0
    i = 0;
313
0
    do {
314
0
      INSIST(i < count);
315
0
      dns_rdata_init(&in[i]);
316
0
      dns_rdataset_current(rdataset, &in[i]);
317
0
      i++;
318
0
      result = dns_rdataset_next(rdataset);
319
0
    } while (result == ISC_R_SUCCESS);
320
0
    if (result != ISC_R_NOMORE) {
321
0
      goto cleanup;
322
0
    }
323
0
    INSIST(i == count);
324
325
0
    if (want_random) {
326
0
      seed = isc_random32();
327
0
    }
328
329
0
    if (want_cyclic &&
330
0
        (rdataset->count != DNS_RDATASET_COUNT_UNDEFINED))
331
0
    {
332
0
      j = rdataset->count % count;
333
0
    }
334
335
0
    for (i = 0; i < count; i++) {
336
0
      if (want_random) {
337
0
        swap_rdata(in, j, j + seed % (count - j));
338
0
      }
339
340
0
      out[i].key = 0;
341
0
      out[i].rdata = &in[j];
342
0
      if (++j == count) {
343
0
        j = 0;
344
0
      }
345
0
    }
346
0
  }
347
348
92.3k
  savedbuffer = *target;
349
92.3k
  i = 0;
350
92.3k
  added = 0;
351
352
92.3k
  name = dns_fixedname_initname(&fixed);
353
92.3k
  dns_name_copy(owner_name, name);
354
92.3k
  dns_rdataset_getownercase(rdataset, name);
355
92.3k
  dns_compress_setmultiuse(cctx, true);
356
357
92.3k
  name->attributes.nocompress |= owner_name->attributes.nocompress;
358
359
174k
  do {
360
    /*
361
     * Copy out the name, type, class, ttl.
362
     */
363
364
174k
    rrbuffer = *target;
365
174k
    dns_compress_setpermitted(cctx, true);
366
174k
    result = dns_name_towire(name, cctx, target);
367
174k
    if (result != ISC_R_SUCCESS) {
368
37
      goto rollback;
369
37
    }
370
174k
    headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
371
174k
    if (!question) {
372
151k
      headlen += sizeof(dns_ttl_t) + 2;
373
151k
    } /* XXX 2 for rdata len */
374
174k
    isc_buffer_availableregion(target, &r);
375
174k
    if (r.length < headlen) {
376
19
      result = ISC_R_NOSPACE;
377
19
      goto rollback;
378
19
    }
379
174k
    isc_buffer_putuint16(target, rdataset->type);
380
174k
    isc_buffer_putuint16(target, rdataset->rdclass);
381
174k
    if (!question) {
382
151k
      dns_rdata_t rdata = DNS_RDATA_INIT;
383
384
151k
      isc_buffer_putuint32(target, rdataset->ttl);
385
386
      /*
387
       * Save space for rdlen.
388
       */
389
151k
      rdlen = *target;
390
151k
      isc_buffer_add(target, 2);
391
392
      /*
393
       * Copy out the rdata
394
       */
395
151k
      if (shuffle) {
396
0
        rdata = *(out[i].rdata);
397
151k
      } else {
398
151k
        dns_rdata_reset(&rdata);
399
151k
        dns_rdataset_current(rdataset, &rdata);
400
151k
      }
401
151k
      result = dns_rdata_towire(&rdata, cctx, target);
402
151k
      if (result != ISC_R_SUCCESS) {
403
156
        goto rollback;
404
156
      }
405
150k
      INSIST((target->used >= rdlen.used + 2) &&
406
150k
             (target->used - rdlen.used - 2 < 65536));
407
150k
      isc_buffer_putuint16(
408
150k
        &rdlen,
409
150k
        (uint16_t)(target->used - rdlen.used - 2));
410
150k
      added++;
411
150k
    }
412
413
174k
    if (shuffle) {
414
0
      i++;
415
0
      if (i == count) {
416
0
        result = ISC_R_NOMORE;
417
0
      } else {
418
0
        result = ISC_R_SUCCESS;
419
0
      }
420
174k
    } else {
421
174k
      result = dns_rdataset_next(rdataset);
422
174k
    }
423
174k
  } while (result == ISC_R_SUCCESS);
424
425
92.1k
  if (result != ISC_R_NOMORE) {
426
0
    goto rollback;
427
0
  }
428
429
92.1k
  *countp += count;
430
431
92.1k
  result = ISC_R_SUCCESS;
432
92.1k
  goto cleanup;
433
434
212
rollback:
435
212
  if (partial && result == ISC_R_NOSPACE) {
436
0
    dns_compress_rollback(cctx, rrbuffer.used);
437
0
    *countp += added;
438
0
    *target = rrbuffer;
439
0
    goto cleanup;
440
0
  }
441
212
  dns_compress_rollback(cctx, savedbuffer.used);
442
212
  *countp = 0;
443
212
  *target = savedbuffer;
444
445
92.3k
cleanup:
446
92.3k
  if (out != NULL && out != out_fixed) {
447
0
    isc_mem_cput(cctx->mctx, out, count, sizeof(*out));
448
0
  }
449
92.3k
  if (in != NULL && in != in_fixed) {
450
0
    isc_mem_cput(cctx->mctx, in, count, sizeof(*in));
451
0
  }
452
92.3k
  return result;
453
212
}
454
455
isc_result_t
456
dns_rdataset_towirepartial(dns_rdataset_t *rdataset,
457
         const dns_name_t *owner_name, dns_compress_t *cctx,
458
         isc_buffer_t *target, unsigned int options,
459
0
         unsigned int *countp, void **state) {
460
0
  REQUIRE(state == NULL); /* XXX remove when implemented */
461
0
  return towire(rdataset, owner_name, cctx, target, true, options, countp,
462
0
          state);
463
0
}
464
465
isc_result_t
466
dns_rdataset_towire(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
467
        dns_compress_t *cctx, isc_buffer_t *target,
468
92.3k
        unsigned int options, unsigned int *countp) {
469
92.3k
  return towire(rdataset, owner_name, cctx, target, false, options,
470
92.3k
          countp, NULL);
471
92.3k
}
472
473
isc_result_t
474
dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
475
          const dns_name_t *owner_name,
476
          dns_additionaldatafunc_t add, void *arg,
477
0
          size_t limit) {
478
  /*
479
   * For each rdata in rdataset, call 'add' for each name and type in the
480
   * rdata which is subject to additional section processing.
481
   */
482
483
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
484
0
  REQUIRE(!rdataset->attributes.question);
485
486
0
  if (limit != 0 && dns_rdataset_count(rdataset) > limit) {
487
0
    return DNS_R_TOOMANYRECORDS;
488
0
  }
489
490
0
  DNS_RDATASET_FOREACH (rdataset) {
491
0
    isc_result_t result;
492
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
493
0
    dns_rdataset_current(rdataset, &rdata);
494
0
    result = dns_rdata_additionaldata(&rdata, owner_name, add, arg);
495
0
    if (result != ISC_R_SUCCESS) {
496
0
      return result;
497
0
    }
498
0
  }
499
500
0
  return ISC_R_SUCCESS;
501
0
}
502
503
isc_result_t
504
0
dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
505
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
506
0
  REQUIRE(rdataset->methods != NULL);
507
0
  if (rdataset->methods->addnoqname == NULL) {
508
0
    return ISC_R_NOTIMPLEMENTED;
509
0
  }
510
0
  return (rdataset->methods->addnoqname)(rdataset, name);
511
0
}
512
513
isc_result_t
514
dns__rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
515
       dns_rdataset_t *neg,
516
0
       dns_rdataset_t *negsig DNS__DB_FLARG) {
517
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
518
0
  REQUIRE(rdataset->methods != NULL);
519
520
0
  if (rdataset->methods->getnoqname == NULL) {
521
0
    return ISC_R_NOTIMPLEMENTED;
522
0
  }
523
0
  return (rdataset->methods->getnoqname)(rdataset, name, neg,
524
0
                 negsig DNS__DB_FLARG_PASS);
525
0
}
526
527
isc_result_t
528
0
dns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) {
529
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
530
0
  REQUIRE(rdataset->methods != NULL);
531
0
  if (rdataset->methods->addclosest == NULL) {
532
0
    return ISC_R_NOTIMPLEMENTED;
533
0
  }
534
0
  return (rdataset->methods->addclosest)(rdataset, name);
535
0
}
536
537
isc_result_t
538
dns__rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
539
       dns_rdataset_t *neg,
540
0
       dns_rdataset_t *negsig DNS__DB_FLARG) {
541
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
542
0
  REQUIRE(rdataset->methods != NULL);
543
544
0
  if (rdataset->methods->getclosest == NULL) {
545
0
    return ISC_R_NOTIMPLEMENTED;
546
0
  }
547
0
  return (rdataset->methods->getclosest)(rdataset, name, neg,
548
0
                 negsig DNS__DB_FLARG_PASS);
549
0
}
550
551
void
552
0
dns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
553
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
554
0
  REQUIRE(rdataset->methods != NULL);
555
556
0
  if (rdataset->methods->settrust != NULL) {
557
0
    (rdataset->methods->settrust)(rdataset, trust);
558
0
  } else {
559
0
    rdataset->trust = trust;
560
0
  }
561
0
}
562
563
void
564
0
dns__rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG) {
565
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
566
0
  REQUIRE(rdataset->methods != NULL);
567
568
0
  if (rdataset->methods->expire != NULL) {
569
0
    (rdataset->methods->expire)(rdataset DNS__DB_FLARG_PASS);
570
0
  }
571
0
}
572
573
void
574
0
dns_rdataset_clearprefetch(dns_rdataset_t *rdataset) {
575
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
576
0
  REQUIRE(rdataset->methods != NULL);
577
578
0
  if (rdataset->methods->clearprefetch != NULL) {
579
0
    (rdataset->methods->clearprefetch)(rdataset);
580
0
  }
581
0
}
582
583
void
584
324k
dns_rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) {
585
324k
  REQUIRE(DNS_RDATASET_VALID(rdataset));
586
324k
  REQUIRE(rdataset->methods != NULL);
587
588
324k
  if (rdataset->methods->setownercase != NULL &&
589
324k
      !rdataset->attributes.keepcase)
590
324k
  {
591
324k
    (rdataset->methods->setownercase)(rdataset, name);
592
324k
  }
593
324k
}
594
595
void
596
222k
dns_rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) {
597
222k
  REQUIRE(DNS_RDATASET_VALID(rdataset));
598
222k
  REQUIRE(rdataset->methods != NULL);
599
600
222k
  if (rdataset->methods->getownercase != NULL &&
601
222k
      !rdataset->attributes.keepcase)
602
222k
  {
603
222k
    (rdataset->methods->getownercase)(rdataset, name);
604
222k
  }
605
222k
}
606
607
void
608
dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
609
         dns_rdata_rrsig_t *rrsig, isc_stdtime_t now,
610
0
         bool acceptexpired) {
611
0
  uint32_t ttl = 0;
612
613
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
614
0
  REQUIRE(DNS_RDATASET_VALID(sigrdataset));
615
0
  REQUIRE(rrsig != NULL);
616
617
  /*
618
   * If we accept expired RRsets keep them for no more than 120 seconds.
619
   */
620
0
  if (acceptexpired &&
621
0
      (isc_serial_le(rrsig->timeexpire, (now + 120) & 0xffffffff) ||
622
0
       isc_serial_le(rrsig->timeexpire, now)))
623
0
  {
624
0
    ttl = 120;
625
0
  } else if (isc_serial_ge(rrsig->timeexpire, now)) {
626
0
    ttl = rrsig->timeexpire - now;
627
0
  }
628
629
0
  ttl = ISC_MIN(ISC_MIN(rdataset->ttl, sigrdataset->ttl),
630
0
          ISC_MIN(rrsig->originalttl, ttl));
631
0
  rdataset->ttl = ttl;
632
0
  sigrdataset->ttl = ttl;
633
0
}
634
635
dns_slabheader_t *
636
0
dns_rdataset_getheader(const dns_rdataset_t *rdataset) {
637
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
638
639
0
  if (rdataset->methods->getheader != NULL) {
640
0
    return (rdataset->methods->getheader)(rdataset);
641
0
  }
642
643
0
  return NULL;
644
0
}
645
646
bool
647
dns_rdataset_equals(const dns_rdataset_t *rdataset1,
648
0
        const dns_rdataset_t *rdataset2) {
649
0
  REQUIRE(DNS_RDATASET_VALID(rdataset1));
650
0
  REQUIRE(DNS_RDATASET_VALID(rdataset2));
651
652
0
  if (rdataset1->methods->equals != NULL &&
653
0
      rdataset1->methods->equals == rdataset2->methods->equals)
654
0
  {
655
0
    return (rdataset1->methods->equals)(rdataset1, rdataset2);
656
0
  }
657
658
0
  return false;
659
0
}