Coverage Report

Created: 2025-08-26 06:58

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