Coverage Report

Created: 2026-02-26 06:45

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