Coverage Report

Created: 2026-01-24 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/ncache.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
19
#include <isc/buffer.h>
20
#include <isc/result.h>
21
#include <isc/util.h>
22
23
#include <dns/db.h>
24
#include <dns/message.h>
25
#include <dns/ncache.h>
26
#include <dns/rdata.h>
27
#include <dns/rdatalist.h>
28
#include <dns/rdataset.h>
29
#include <dns/rdatastruct.h>
30
31
0
#define DNS_NCACHE_RDATA 100U
32
33
/*
34
 * The format of an ncache rdata is a sequence of zero or more records
35
 * of the following format:
36
 *
37
 *  owner name
38
 *  type
39
 *  trust
40
 *  rdata count
41
 *  rdata length      These two occur 'rdata
42
 *  rdata       count' times.
43
 *
44
 */
45
46
static uint8_t
47
0
atomic_getuint8(isc_buffer_t *b) {
48
0
  atomic_uchar *cp = isc_buffer_current(b);
49
0
  uint8_t ret = atomic_load_relaxed(cp);
50
0
  isc_buffer_forward(b, 1);
51
0
  return ret;
52
0
}
53
54
static isc_result_t
55
0
copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
56
0
  unsigned int count;
57
0
  isc_region_t ar, r;
58
59
  /*
60
   * Copy the rdataset count to the buffer.
61
   */
62
0
  isc_buffer_availableregion(buffer, &ar);
63
0
  if (ar.length < 2) {
64
0
    return ISC_R_NOSPACE;
65
0
  }
66
0
  count = dns_rdataset_count(rdataset);
67
0
  INSIST(count <= 65535);
68
0
  isc_buffer_putuint16(buffer, (uint16_t)count);
69
70
0
  DNS_RDATASET_FOREACH(rdataset) {
71
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
72
0
    dns_rdataset_current(rdataset, &rdata);
73
74
0
    dns_rdata_toregion(&rdata, &r);
75
0
    INSIST(r.length <= 65535);
76
0
    isc_buffer_availableregion(buffer, &ar);
77
0
    if (ar.length < 2) {
78
0
      return ISC_R_NOSPACE;
79
0
    }
80
    /*
81
     * Copy the rdata length to the buffer.
82
     */
83
0
    isc_buffer_putuint16(buffer, (uint16_t)r.length);
84
    /*
85
     * Copy the rdata to the buffer.
86
     */
87
0
    RETERR(isc_buffer_copyregion(buffer, &r));
88
0
  }
89
90
0
  return ISC_R_SUCCESS;
91
0
}
92
93
isc_result_t
94
dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
95
         dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t minttl,
96
         dns_ttl_t maxttl, bool optout, bool secure,
97
0
         dns_rdataset_t *addedrdataset) {
98
0
  isc_buffer_t buffer;
99
0
  isc_region_t r;
100
0
  dns_rdatatype_t type;
101
0
  dns_ttl_t ttl;
102
0
  dns_trust_t trust;
103
0
  dns_rdata_t rdata[DNS_NCACHE_RDATA];
104
0
  dns_rdataset_t ncrdataset;
105
0
  dns_rdatalist_t ncrdatalist;
106
0
  unsigned char data[65536];
107
0
  unsigned int next = 0;
108
0
  isc_result_t result;
109
110
  /*
111
   * Convert the authority data from 'message' into a negative cache
112
   * rdataset, and store it in 'cache' at 'node'.
113
   *
114
   * We assume that all data in the authority section has been
115
   * validated by the caller.
116
   */
117
118
0
  REQUIRE(message != NULL);
119
120
  /*
121
   * If 'secure' is false, ignore 'optout'.
122
   */
123
0
  optout = optout && secure;
124
125
  /*
126
   * Initialize the list.
127
   */
128
0
  dns_rdatalist_init(&ncrdatalist);
129
0
  ncrdatalist.rdclass = dns_db_class(cache);
130
0
  ncrdatalist.covers = covers;
131
0
  ncrdatalist.ttl = maxttl;
132
133
  /*
134
   * Build an ncache rdatas into buffer.
135
   */
136
0
  ttl = maxttl;
137
0
  trust = 0xffff;
138
0
  isc_buffer_init(&buffer, data, sizeof(data));
139
140
0
  MSG_SECTION_FOREACH(message, DNS_SECTION_AUTHORITY, name) {
141
0
    if (name->attributes.ncache) {
142
0
      ISC_LIST_FOREACH(name->list, rdataset, link) {
143
0
        if (!rdataset->attributes.ncache) {
144
0
          continue;
145
0
        }
146
0
        type = rdataset->type;
147
0
        if (type == dns_rdatatype_rrsig) {
148
0
          type = rdataset->covers;
149
0
        }
150
0
        if (type == dns_rdatatype_soa ||
151
0
            dns_rdatatype_isnsec(type))
152
0
        {
153
0
          if (ttl > rdataset->ttl) {
154
0
            ttl = rdataset->ttl;
155
0
          }
156
0
          if (ttl < minttl) {
157
0
            ttl = minttl;
158
0
          }
159
0
          if (trust > rdataset->trust) {
160
0
            trust = rdataset->trust;
161
0
          }
162
          /*
163
           * Copy the owner name to the buffer.
164
           */
165
0
          dns_name_toregion(name, &r);
166
0
          RETERR(isc_buffer_copyregion(&buffer,
167
0
                     &r));
168
          /*
169
           * Copy the type to the buffer.
170
           */
171
0
          isc_buffer_availableregion(&buffer, &r);
172
0
          if (r.length < 3) {
173
0
            return ISC_R_NOSPACE;
174
0
          }
175
0
          isc_buffer_putuint16(&buffer,
176
0
                   rdataset->type);
177
0
          isc_buffer_putuint8(
178
0
            &buffer,
179
0
            (unsigned char)rdataset->trust);
180
          /*
181
           * Copy the rdataset into the buffer.
182
           */
183
0
          RETERR(copy_rdataset(rdataset,
184
0
                   &buffer));
185
186
0
          if (next >= DNS_NCACHE_RDATA) {
187
0
            return ISC_R_NOSPACE;
188
0
          }
189
0
          dns_rdata_init(&rdata[next]);
190
0
          isc_buffer_remainingregion(&buffer, &r);
191
0
          rdata[next].data = r.base;
192
0
          rdata[next].length = r.length;
193
0
          rdata[next].rdclass =
194
0
            ncrdatalist.rdclass;
195
0
          rdata[next].type = dns_rdatatype_none;
196
0
          rdata[next].flags = 0;
197
0
          ISC_LIST_APPEND(ncrdatalist.rdata,
198
0
              &rdata[next], link);
199
0
          isc_buffer_forward(&buffer, r.length);
200
0
          next++;
201
0
        }
202
0
      }
203
0
    }
204
0
  }
205
206
0
  if (trust == 0xffff) {
207
0
    if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
208
0
        message->counts[DNS_SECTION_ANSWER] == 0)
209
0
    {
210
      /*
211
       * The response has aa set and we haven't followed
212
       * any CNAME or DNAME chains.
213
       */
214
0
      trust = dns_trust_authauthority;
215
0
    } else {
216
0
      trust = dns_trust_additional;
217
0
    }
218
0
    ttl = 0;
219
0
  }
220
221
0
  INSIST(trust != 0xffff);
222
223
0
  ncrdatalist.ttl = ttl;
224
225
0
  dns_rdataset_init(&ncrdataset);
226
0
  dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset);
227
0
  if (!secure && trust > dns_trust_answer) {
228
0
    trust = dns_trust_answer;
229
0
  }
230
0
  ncrdataset.trust = trust;
231
0
  ncrdataset.attributes.negative = true;
232
0
  if (message->rcode == dns_rcode_nxdomain) {
233
0
    ncrdataset.attributes.nxdomain = true;
234
0
  }
235
0
  if (optout) {
236
0
    ncrdataset.attributes.optout = true;
237
0
  }
238
239
0
  result = dns_db_addrdataset(cache, node, NULL, now, &ncrdataset, 0,
240
0
            addedrdataset);
241
0
  if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) {
242
0
    return result;
243
0
  }
244
245
0
  return ISC_R_SUCCESS;
246
0
}
247
248
isc_result_t
249
dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
250
      isc_buffer_t *target, unsigned int options,
251
0
      unsigned int *countp) {
252
0
  isc_result_t result;
253
0
  isc_region_t remaining, tavailable;
254
0
  isc_buffer_t source, savedbuffer, rdlen;
255
0
  dns_name_t name;
256
0
  dns_rdatatype_t type;
257
0
  unsigned int i, rcount, count;
258
259
  /*
260
   * Convert the negative caching rdataset 'rdataset' to wire format,
261
   * compressing names as specified in 'cctx', and storing the result in
262
   * 'target'.
263
   */
264
265
0
  REQUIRE(rdataset != NULL);
266
0
  REQUIRE(rdataset->type == dns_rdatatype_none);
267
0
  REQUIRE(rdataset->attributes.negative);
268
269
0
  savedbuffer = *target;
270
0
  count = 0;
271
272
0
  DNS_RDATASET_FOREACH(rdataset) {
273
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
274
0
    dns_rdataset_current(rdataset, &rdata);
275
276
0
    isc_buffer_init(&source, rdata.data, rdata.length);
277
0
    isc_buffer_add(&source, rdata.length);
278
0
    dns_name_init(&name);
279
0
    isc_buffer_remainingregion(&source, &remaining);
280
0
    dns_name_fromregion(&name, &remaining);
281
0
    INSIST(remaining.length >= name.length);
282
0
    isc_buffer_forward(&source, name.length);
283
0
    remaining.length -= name.length;
284
285
0
    INSIST(remaining.length >= 5);
286
0
    type = isc_buffer_getuint16(&source);
287
0
    isc_buffer_forward(&source, 1);
288
0
    rcount = isc_buffer_getuint16(&source);
289
290
0
    for (i = 0; i < rcount; i++) {
291
      /*
292
       * Get the length of this rdata and set up an
293
       * rdata structure for it.
294
       */
295
0
      isc_buffer_remainingregion(&source, &remaining);
296
0
      INSIST(remaining.length >= 2);
297
0
      dns_rdata_reset(&rdata);
298
0
      rdata.length = isc_buffer_getuint16(&source);
299
0
      isc_buffer_remainingregion(&source, &remaining);
300
0
      rdata.data = remaining.base;
301
0
      rdata.type = type;
302
0
      rdata.rdclass = rdataset->rdclass;
303
0
      INSIST(remaining.length >= rdata.length);
304
0
      isc_buffer_forward(&source, rdata.length);
305
306
0
      if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
307
0
          dns_rdatatype_isdnssec(type))
308
0
      {
309
0
        continue;
310
0
      }
311
312
      /*
313
       * Write the name.
314
       */
315
0
      dns_compress_setpermitted(cctx, true);
316
0
      result = dns_name_towire(&name, cctx, target);
317
0
      if (result != ISC_R_SUCCESS) {
318
0
        goto rollback;
319
0
      }
320
321
      /*
322
       * See if we have space for type, class, ttl, and
323
       * rdata length.  Write the type, class, and ttl.
324
       */
325
0
      isc_buffer_availableregion(target, &tavailable);
326
0
      if (tavailable.length < 10) {
327
0
        result = ISC_R_NOSPACE;
328
0
        goto rollback;
329
0
      }
330
0
      isc_buffer_putuint16(target, type);
331
0
      isc_buffer_putuint16(target, rdataset->rdclass);
332
0
      isc_buffer_putuint32(target, rdataset->ttl);
333
334
      /*
335
       * Save space for rdata length.
336
       */
337
0
      rdlen = *target;
338
0
      isc_buffer_add(target, 2);
339
340
      /*
341
       * Write the rdata.
342
       */
343
0
      result = dns_rdata_towire(&rdata, cctx, target);
344
0
      if (result != ISC_R_SUCCESS) {
345
0
        goto rollback;
346
0
      }
347
348
      /*
349
       * Set the rdata length field to the compressed
350
       * length.
351
       */
352
0
      INSIST((target->used >= rdlen.used + 2) &&
353
0
             (target->used - rdlen.used - 2 < 65536));
354
0
      isc_buffer_putuint16(
355
0
        &rdlen,
356
0
        (uint16_t)(target->used - rdlen.used - 2));
357
358
0
      count++;
359
0
    }
360
0
    INSIST(isc_buffer_remaininglength(&source) == 0);
361
0
  }
362
363
0
  *countp = count;
364
365
0
  return ISC_R_SUCCESS;
366
367
0
rollback:
368
0
  dns_compress_rollback(cctx, savedbuffer.used);
369
0
  *countp = 0;
370
0
  *target = savedbuffer;
371
372
0
  return result;
373
0
}
374
375
static void
376
0
rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) {
377
0
  UNUSED(rdataset);
378
0
}
379
380
static isc_result_t
381
0
rdataset_first(dns_rdataset_t *rdataset) {
382
0
  unsigned char *raw;
383
0
  unsigned int count;
384
385
0
  raw = rdataset->ncache.raw;
386
0
  count = raw[0] * 256 + raw[1];
387
0
  if (count == 0) {
388
0
    rdataset->ncache.iter_pos = NULL;
389
0
    return ISC_R_NOMORE;
390
0
  }
391
  /*
392
   * iter_count is the number of rdata beyond the cursor position,
393
   * so we decrement the total count by one before storing it.
394
   */
395
0
  rdataset->ncache.iter_pos = raw + 2;
396
0
  rdataset->ncache.iter_count = count - 1;
397
0
  return ISC_R_SUCCESS;
398
0
}
399
400
static isc_result_t
401
0
rdataset_next(dns_rdataset_t *rdataset) {
402
0
  unsigned int count;
403
0
  unsigned int length;
404
0
  unsigned char *raw;
405
406
0
  raw = rdataset->ncache.iter_pos;
407
0
  count = rdataset->ncache.iter_count;
408
0
  if (count == 0) {
409
0
    rdataset->ncache.iter_pos = NULL;
410
0
    return ISC_R_NOMORE;
411
0
  }
412
413
0
  length = raw[0] * 256 + raw[1];
414
0
  rdataset->ncache.iter_pos = raw + 2 + length;
415
0
  rdataset->ncache.iter_count = count - 1;
416
0
  return ISC_R_SUCCESS;
417
0
}
418
419
static void
420
0
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
421
0
  unsigned char *raw;
422
0
  isc_region_t r;
423
424
0
  raw = rdataset->ncache.iter_pos;
425
0
  REQUIRE(raw != NULL);
426
427
0
  r.length = raw[0] * 256 + raw[1];
428
0
  r.base = raw + 2;
429
0
  dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
430
0
}
431
432
static void
433
0
rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) {
434
0
  *target = *source;
435
0
  target->ncache.iter_pos = NULL;
436
0
  target->ncache.iter_count = 0;
437
0
}
438
439
static unsigned int
440
0
rdataset_count(dns_rdataset_t *rdataset) {
441
0
  unsigned char *raw;
442
0
  unsigned int count;
443
444
0
  raw = rdataset->ncache.raw;
445
0
  count = raw[0] * 256 + raw[1];
446
447
0
  return count;
448
0
}
449
450
static void
451
0
rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
452
0
  atomic_uchar *raw;
453
454
0
  raw = (atomic_uchar *)rdataset->ncache.raw;
455
0
  atomic_store_relaxed(&raw[-1], (unsigned char)trust);
456
0
  rdataset->trust = trust;
457
0
}
458
459
static dns_rdatasetmethods_t rdataset_methods = {
460
  .disassociate = rdataset_disassociate,
461
  .first = rdataset_first,
462
  .next = rdataset_next,
463
  .current = rdataset_current,
464
  .clone = rdataset_clone,
465
  .count = rdataset_count,
466
  .settrust = rdataset_settrust,
467
};
468
469
isc_result_t
470
dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
471
0
           dns_rdatatype_t type, dns_rdataset_t *rdataset) {
472
0
  isc_result_t result = ISC_R_NOTFOUND;
473
0
  isc_region_t remaining;
474
0
  isc_buffer_t source;
475
0
  dns_name_t tname;
476
0
  dns_rdatatype_t ttype;
477
0
  dns_trust_t trust = dns_trust_none;
478
0
  dns_rdataset_t rclone;
479
480
0
  REQUIRE(ncacherdataset != NULL);
481
0
  REQUIRE(DNS_RDATASET_VALID(ncacherdataset));
482
0
  REQUIRE(ncacherdataset->type == dns_rdatatype_none);
483
0
  REQUIRE(ncacherdataset->attributes.negative);
484
0
  REQUIRE(name != NULL);
485
0
  REQUIRE(!dns_rdataset_isassociated(rdataset));
486
0
  REQUIRE(type != dns_rdatatype_rrsig);
487
488
0
  dns_rdataset_init(&rclone);
489
0
  dns_rdataset_clone(ncacherdataset, &rclone);
490
0
  DNS_RDATASET_FOREACH(&rclone) {
491
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
492
0
    dns_rdataset_current(&rclone, &rdata);
493
494
0
    isc_buffer_init(&source, rdata.data, rdata.length);
495
0
    isc_buffer_add(&source, rdata.length);
496
0
    dns_name_init(&tname);
497
0
    isc_buffer_remainingregion(&source, &remaining);
498
0
    dns_name_fromregion(&tname, &remaining);
499
0
    INSIST(remaining.length >= tname.length);
500
0
    isc_buffer_forward(&source, tname.length);
501
0
    remaining.length -= tname.length;
502
503
0
    INSIST(remaining.length >= 3);
504
0
    ttype = isc_buffer_getuint16(&source);
505
506
0
    if (ttype == type && dns_name_equal(&tname, name)) {
507
0
      trust = atomic_getuint8(&source);
508
0
      INSIST(trust <= dns_trust_ultimate);
509
0
      isc_buffer_remainingregion(&source, &remaining);
510
0
      result = ISC_R_SUCCESS;
511
0
      break;
512
0
    }
513
0
  }
514
0
  dns_rdataset_disassociate(&rclone);
515
516
0
  if (result == ISC_R_SUCCESS) {
517
0
    INSIST(remaining.length != 0);
518
519
0
    rdataset->methods = &rdataset_methods;
520
0
    rdataset->rdclass = ncacherdataset->rdclass;
521
0
    rdataset->type = type;
522
0
    rdataset->covers = dns_rdatatype_none;
523
0
    rdataset->ttl = ncacherdataset->ttl;
524
0
    rdataset->trust = trust;
525
0
    rdataset->ncache.raw = remaining.base;
526
0
    rdataset->ncache.iter_pos = NULL;
527
0
    rdataset->ncache.iter_count = 0;
528
0
  }
529
530
0
  return result;
531
0
}
532
533
isc_result_t
534
dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
535
0
        dns_rdatatype_t covers, dns_rdataset_t *rdataset) {
536
0
  isc_result_t result = ISC_R_NOTFOUND;
537
0
  dns_name_t tname;
538
0
  dns_rdata_rrsig_t rrsig;
539
0
  dns_rdataset_t rclone;
540
0
  dns_rdatatype_t type;
541
0
  dns_trust_t trust = dns_trust_none;
542
0
  isc_buffer_t source;
543
0
  isc_region_t remaining, sigregion;
544
0
  unsigned char *raw = NULL;
545
0
  unsigned int count;
546
547
0
  REQUIRE(ncacherdataset != NULL);
548
0
  REQUIRE(ncacherdataset->type == dns_rdatatype_none);
549
0
  REQUIRE(ncacherdataset->attributes.negative);
550
0
  REQUIRE(name != NULL);
551
0
  REQUIRE(!dns_rdataset_isassociated(rdataset));
552
553
0
  dns_rdataset_init(&rclone);
554
0
  dns_rdataset_clone(ncacherdataset, &rclone);
555
0
  DNS_RDATASET_FOREACH(&rclone) {
556
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
557
0
    dns_rdataset_current(&rclone, &rdata);
558
559
0
    isc_buffer_init(&source, rdata.data, rdata.length);
560
0
    isc_buffer_add(&source, rdata.length);
561
0
    dns_name_init(&tname);
562
0
    isc_buffer_remainingregion(&source, &remaining);
563
0
    dns_name_fromregion(&tname, &remaining);
564
0
    INSIST(remaining.length >= tname.length);
565
0
    isc_buffer_forward(&source, tname.length);
566
0
    isc_region_consume(&remaining, tname.length);
567
568
0
    INSIST(remaining.length >= 2);
569
0
    type = isc_buffer_getuint16(&source);
570
0
    isc_region_consume(&remaining, 2);
571
572
0
    if (type != dns_rdatatype_rrsig ||
573
0
        !dns_name_equal(&tname, name))
574
0
    {
575
0
      continue;
576
0
    }
577
578
0
    INSIST(remaining.length >= 1);
579
0
    trust = atomic_getuint8(&source);
580
0
    INSIST(trust <= dns_trust_ultimate);
581
0
    isc_region_consume(&remaining, 1);
582
583
0
    raw = remaining.base;
584
0
    count = raw[0] * 256 + raw[1];
585
0
    INSIST(count > 0);
586
0
    raw += 2;
587
0
    sigregion.length = raw[0] * 256 + raw[1];
588
0
    raw += 2;
589
0
    sigregion.base = raw;
590
0
    dns_rdata_reset(&rdata);
591
0
    dns_rdata_fromregion(&rdata, rdataset->rdclass,
592
0
             dns_rdatatype_rrsig, &sigregion);
593
0
    (void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
594
0
    if (rrsig.covered == covers) {
595
0
      isc_buffer_remainingregion(&source, &remaining);
596
0
      result = ISC_R_SUCCESS;
597
0
      break;
598
0
    }
599
0
  }
600
0
  dns_rdataset_disassociate(&rclone);
601
602
0
  if (result == ISC_R_SUCCESS) {
603
0
    INSIST(remaining.length != 0);
604
605
0
    rdataset->methods = &rdataset_methods;
606
0
    rdataset->rdclass = ncacherdataset->rdclass;
607
0
    rdataset->type = dns_rdatatype_rrsig;
608
0
    rdataset->covers = covers;
609
0
    rdataset->ttl = ncacherdataset->ttl;
610
0
    rdataset->trust = trust;
611
0
    rdataset->ncache.raw = remaining.base;
612
0
    rdataset->ncache.iter_pos = NULL;
613
0
    rdataset->ncache.iter_count = 0;
614
0
  }
615
616
0
  return result;
617
0
}
618
619
void
620
dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
621
0
       dns_rdataset_t *rdataset) {
622
0
  dns_rdata_t rdata = DNS_RDATA_INIT;
623
0
  dns_trust_t trust;
624
0
  isc_region_t remaining, sigregion;
625
0
  isc_buffer_t source;
626
0
  dns_name_t tname;
627
0
  dns_rdatatype_t type, covers;
628
0
  unsigned int count;
629
0
  dns_rdata_rrsig_t rrsig;
630
0
  unsigned char *raw;
631
632
0
  REQUIRE(ncacherdataset != NULL);
633
0
  REQUIRE(ncacherdataset->type == dns_rdatatype_none);
634
0
  REQUIRE(ncacherdataset->attributes.negative);
635
0
  REQUIRE(found != NULL);
636
0
  REQUIRE(!dns_rdataset_isassociated(rdataset));
637
638
0
  dns_rdataset_current(ncacherdataset, &rdata);
639
0
  isc_buffer_init(&source, rdata.data, rdata.length);
640
0
  isc_buffer_add(&source, rdata.length);
641
642
0
  dns_name_init(&tname);
643
0
  isc_buffer_remainingregion(&source, &remaining);
644
0
  dns_name_fromregion(found, &remaining);
645
0
  INSIST(remaining.length >= found->length);
646
0
  isc_buffer_forward(&source, found->length);
647
0
  remaining.length -= found->length;
648
649
0
  INSIST(remaining.length >= 5);
650
0
  type = isc_buffer_getuint16(&source);
651
0
  trust = atomic_getuint8(&source);
652
0
  INSIST(trust <= dns_trust_ultimate);
653
0
  isc_buffer_remainingregion(&source, &remaining);
654
655
0
  if (type == dns_rdatatype_rrsig) {
656
    /*
657
     * Extract covers from RRSIG.
658
     */
659
0
    raw = remaining.base;
660
0
    count = raw[0] * 256 + raw[1];
661
0
    INSIST(count > 0);
662
0
    raw += 2;
663
0
    sigregion.length = raw[0] * 256 + raw[1];
664
0
    raw += 2;
665
0
    sigregion.base = raw;
666
0
    dns_rdata_reset(&rdata);
667
0
    dns_rdata_fromregion(&rdata, ncacherdataset->rdclass, type,
668
0
             &sigregion);
669
0
    (void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
670
0
    covers = rrsig.covered;
671
0
  } else {
672
0
    covers = dns_rdatatype_none;
673
0
  }
674
675
0
  rdataset->methods = &rdataset_methods;
676
0
  rdataset->rdclass = ncacherdataset->rdclass;
677
0
  rdataset->type = type;
678
0
  rdataset->covers = covers;
679
0
  rdataset->ttl = ncacherdataset->ttl;
680
0
  rdataset->trust = trust;
681
0
  rdataset->ncache.raw = remaining.base;
682
  rdataset->ncache.iter_pos = NULL;
683
0
  rdataset->ncache.iter_count = 0;
684
0
}