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