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