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