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