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