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