]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - contrib/bind9/lib/dns/ncache.c
Update to version 9.6-ESV-R4-P3
[FreeBSD/stable/8.git] / contrib / bind9 / lib / dns / ncache.c
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2008, 2010, 2011  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: ncache.c,v 1.43.48.7.6.3 2011-06-21 20:13:22 each Exp $ */
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 one 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                 /*
227                  * We didn't find any authority data from which to create a
228                  * negative cache rdataset.  In particular, we have no SOA.
229                  *
230                  * We trust that the caller wants negative caching, so this
231                  * means we have a "type 3 nxdomain" or "type 3 nodata"
232                  * response (see RFC2308 for details).
233                  *
234                  * We will now build a suitable negative cache rdataset that
235                  * will cause zero bytes to be emitted when converted to
236                  * wire format.
237                  */
238
239                 /*
240                  * The ownername must exist, but it doesn't matter what value
241                  * it has.  We use the root name.
242                  */
243                 dns_name_toregion(dns_rootname, &r);
244                 result = isc_buffer_copyregion(&buffer, &r);
245                 if (result != ISC_R_SUCCESS)
246                         return (result);
247                 /*
248                  * Copy the type and a zero rdata count to the buffer.
249                  */
250                 isc_buffer_availableregion(&buffer, &r);
251                 if (r.length < 5)
252                         return (ISC_R_NOSPACE);
253                 isc_buffer_putuint16(&buffer, 0);       /* type */
254                 /*
255                  * RFC2308, section 5, says that negative answers without
256                  * SOAs should not be cached.
257                  */
258                 ttl = 0;
259                 /*
260                  * Set trust.
261                  */
262                 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
263                     message->counts[DNS_SECTION_ANSWER] == 0) {
264                         /*
265                          * The response has aa set and we haven't followed
266                          * any CNAME or DNAME chains.
267                          */
268                         trust = dns_trust_authauthority;
269                 } else
270                         trust = dns_trust_additional;
271                 isc_buffer_putuint8(&buffer, (unsigned char)trust); /* trust */
272                 isc_buffer_putuint16(&buffer, 0);       /* count */
273
274                 /*
275                  * Now add it to the cache.
276                  */
277                 if (next >= DNS_NCACHE_RDATA)
278                         return (ISC_R_NOSPACE);
279                 dns_rdata_init(&rdata[next]);
280                 isc_buffer_remainingregion(&buffer, &r);
281                 rdata[next].data = r.base;
282                 rdata[next].length = r.length;
283                 rdata[next].rdclass = ncrdatalist.rdclass;
284                 rdata[next].type = 0;
285                 rdata[next].flags = 0;
286                 ISC_LIST_APPEND(ncrdatalist.rdata, &rdata[next], link);
287         }
288
289         INSIST(trust != 0xffff);
290
291         ncrdatalist.ttl = ttl;
292
293         dns_rdataset_init(&ncrdataset);
294         RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
295                       == ISC_R_SUCCESS);
296         ncrdataset.trust = trust;
297         ncrdataset.attributes |= DNS_RDATASETATTR_NEGATIVE;
298         if (message->rcode == dns_rcode_nxdomain)
299                 ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
300         if (optout)
301                 ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT;
302
303         return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
304                                    0, addedrdataset));
305 }
306
307 isc_result_t
308 dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
309                   isc_buffer_t *target, unsigned int options,
310                   unsigned int *countp)
311 {
312         dns_rdata_t rdata = DNS_RDATA_INIT;
313         isc_result_t result;
314         isc_region_t remaining, tavailable;
315         isc_buffer_t source, savedbuffer, rdlen;
316         dns_name_t name;
317         dns_rdatatype_t type;
318         unsigned int i, rcount, count;
319
320         /*
321          * Convert the negative caching rdataset 'rdataset' to wire format,
322          * compressing names as specified in 'cctx', and storing the result in
323          * 'target'.
324          */
325
326         REQUIRE(rdataset != NULL);
327         REQUIRE(rdataset->type == 0);
328         REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
329
330         savedbuffer = *target;
331         count = 0;
332
333         result = dns_rdataset_first(rdataset);
334         while (result == ISC_R_SUCCESS) {
335                 dns_rdataset_current(rdataset, &rdata);
336                 isc_buffer_init(&source, rdata.data, rdata.length);
337                 isc_buffer_add(&source, rdata.length);
338                 dns_name_init(&name, NULL);
339                 isc_buffer_remainingregion(&source, &remaining);
340                 dns_name_fromregion(&name, &remaining);
341                 INSIST(remaining.length >= name.length);
342                 isc_buffer_forward(&source, name.length);
343                 remaining.length -= name.length;
344
345                 INSIST(remaining.length >= 5);
346                 type = isc_buffer_getuint16(&source);
347                 isc_buffer_forward(&source, 1);
348                 rcount = isc_buffer_getuint16(&source);
349
350                 for (i = 0; i < rcount; i++) {
351                         /*
352                          * Get the length of this rdata and set up an
353                          * rdata structure for it.
354                          */
355                         isc_buffer_remainingregion(&source, &remaining);
356                         INSIST(remaining.length >= 2);
357                         dns_rdata_reset(&rdata);
358                         rdata.length = isc_buffer_getuint16(&source);
359                         isc_buffer_remainingregion(&source, &remaining);
360                         rdata.data = remaining.base;
361                         rdata.type = type;
362                         rdata.rdclass = rdataset->rdclass;
363                         INSIST(remaining.length >= rdata.length);
364                         isc_buffer_forward(&source, rdata.length);
365
366                         if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
367                             dns_rdatatype_isdnssec(type))
368                                 continue;
369
370                         /*
371                          * Write the name.
372                          */
373                         dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
374                         result = dns_name_towire(&name, cctx, target);
375                         if (result != ISC_R_SUCCESS)
376                                 goto rollback;
377
378                         /*
379                          * See if we have space for type, class, ttl, and
380                          * rdata length.  Write the type, class, and ttl.
381                          */
382                         isc_buffer_availableregion(target, &tavailable);
383                         if (tavailable.length < 10) {
384                                 result = ISC_R_NOSPACE;
385                                 goto rollback;
386                         }
387                         isc_buffer_putuint16(target, type);
388                         isc_buffer_putuint16(target, rdataset->rdclass);
389                         isc_buffer_putuint32(target, rdataset->ttl);
390
391                         /*
392                          * Save space for rdata length.
393                          */
394                         rdlen = *target;
395                         isc_buffer_add(target, 2);
396
397                         /*
398                          * Write the rdata.
399                          */
400                         result = dns_rdata_towire(&rdata, cctx, target);
401                         if (result != ISC_R_SUCCESS)
402                                 goto rollback;
403
404                         /*
405                          * Set the rdata length field to the compressed
406                          * length.
407                          */
408                         INSIST((target->used >= rdlen.used + 2) &&
409                                (target->used - rdlen.used - 2 < 65536));
410                         isc_buffer_putuint16(&rdlen,
411                                              (isc_uint16_t)(target->used -
412                                                             rdlen.used - 2));
413
414                         count++;
415                 }
416                 INSIST(isc_buffer_remaininglength(&source) == 0);
417                 result = dns_rdataset_next(rdataset);
418                 dns_rdata_reset(&rdata);
419         }
420         if (result != ISC_R_NOMORE)
421                 goto rollback;
422
423         *countp = count;
424
425         return (ISC_R_SUCCESS);
426
427  rollback:
428         INSIST(savedbuffer.used < 65536);
429         dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
430         *countp = 0;
431         *target = savedbuffer;
432
433         return (result);
434 }
435
436 static void
437 rdataset_disassociate(dns_rdataset_t *rdataset) {
438         UNUSED(rdataset);
439 }
440
441 static isc_result_t
442 rdataset_first(dns_rdataset_t *rdataset) {
443         unsigned char *raw = rdataset->private3;
444         unsigned int count;
445
446         count = raw[0] * 256 + raw[1];
447         if (count == 0) {
448                 rdataset->private5 = NULL;
449                 return (ISC_R_NOMORE);
450         }
451         raw += 2;
452         /*
453          * The privateuint4 field is the number of rdata beyond the cursor
454          * position, so we decrement the total count by one before storing
455          * it.
456          */
457         count--;
458         rdataset->privateuint4 = count;
459         rdataset->private5 = raw;
460
461         return (ISC_R_SUCCESS);
462 }
463
464 static isc_result_t
465 rdataset_next(dns_rdataset_t *rdataset) {
466         unsigned int count;
467         unsigned int length;
468         unsigned char *raw;
469
470         count = rdataset->privateuint4;
471         if (count == 0)
472                 return (ISC_R_NOMORE);
473         count--;
474         rdataset->privateuint4 = count;
475         raw = rdataset->private5;
476         length = raw[0] * 256 + raw[1];
477         raw += length + 2;
478         rdataset->private5 = raw;
479
480         return (ISC_R_SUCCESS);
481 }
482
483 static void
484 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
485         unsigned char *raw = rdataset->private5;
486         isc_region_t r;
487
488         REQUIRE(raw != NULL);
489
490         r.length = raw[0] * 256 + raw[1];
491         raw += 2;
492         r.base = raw;
493         dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
494 }
495
496 static void
497 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
498         *target = *source;
499
500         /*
501          * Reset iterator state.
502          */
503         target->privateuint4 = 0;
504         target->private5 = NULL;
505 }
506
507 static unsigned int
508 rdataset_count(dns_rdataset_t *rdataset) {
509         unsigned char *raw = rdataset->private3;
510         unsigned int count;
511
512         count = raw[0] * 256 + raw[1];
513
514         return (count);
515 }
516
517 static void
518 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
519         unsigned char *raw = rdataset->private3;
520
521         raw[-1] = (unsigned char)trust;
522 }
523
524 static dns_rdatasetmethods_t rdataset_methods = {
525         rdataset_disassociate,
526         rdataset_first,
527         rdataset_next,
528         rdataset_current,
529         rdataset_clone,
530         rdataset_count,
531         NULL,
532         NULL,
533         NULL,
534         NULL,
535         NULL,
536         NULL,
537         NULL,
538         rdataset_settrust,
539         NULL
540 };
541
542 isc_result_t
543 dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
544                        dns_rdatatype_t type, dns_rdataset_t *rdataset)
545 {
546         isc_result_t result;
547         dns_rdata_t rdata = DNS_RDATA_INIT;
548         isc_region_t remaining;
549         isc_buffer_t source;
550         dns_name_t tname;
551         dns_rdatatype_t ttype;
552         dns_trust_t trust = dns_trust_none;
553         dns_rdataset_t clone;
554
555         REQUIRE(ncacherdataset != NULL);
556         REQUIRE(ncacherdataset->type == 0);
557         REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
558         REQUIRE(name != NULL);
559         REQUIRE(!dns_rdataset_isassociated(rdataset));
560         REQUIRE(type != dns_rdatatype_rrsig);
561
562         dns_rdataset_init(&clone);
563         dns_rdataset_clone(ncacherdataset, &clone);
564         result = dns_rdataset_first(&clone);
565         while (result == ISC_R_SUCCESS) {
566                 dns_rdataset_current(&clone, &rdata);
567                 isc_buffer_init(&source, rdata.data, rdata.length);
568                 isc_buffer_add(&source, rdata.length);
569                 dns_name_init(&tname, NULL);
570                 isc_buffer_remainingregion(&source, &remaining);
571                 dns_name_fromregion(&tname, &remaining);
572                 INSIST(remaining.length >= tname.length);
573                 isc_buffer_forward(&source, tname.length);
574                 remaining.length -= tname.length;
575
576                 INSIST(remaining.length >= 3);
577                 ttype = isc_buffer_getuint16(&source);
578
579                 if (ttype == type && dns_name_equal(&tname, name)) {
580                         trust = isc_buffer_getuint8(&source);
581                         INSIST(trust <= dns_trust_ultimate);
582                         isc_buffer_remainingregion(&source, &remaining);
583                         break;
584                 }
585                 result = dns_rdataset_next(&clone);
586                 dns_rdata_reset(&rdata);
587         }
588         dns_rdataset_disassociate(&clone);
589         if (result == ISC_R_NOMORE)
590                 return (ISC_R_NOTFOUND);
591         if (result != ISC_R_SUCCESS)
592                 return (result);
593
594         INSIST(remaining.length != 0);
595
596         rdataset->methods = &rdataset_methods;
597         rdataset->rdclass = ncacherdataset->rdclass;
598         rdataset->type = type;
599         rdataset->covers = 0;
600         rdataset->ttl = ncacherdataset->ttl;
601         rdataset->trust = trust;
602         rdataset->private1 = NULL;
603         rdataset->private2 = NULL;
604
605         rdataset->private3 = remaining.base;
606
607         /*
608          * Reset iterator state.
609          */
610         rdataset->privateuint4 = 0;
611         rdataset->private5 = NULL;
612         rdataset->private6 = NULL;
613         return (ISC_R_SUCCESS);
614 }
615
616 isc_result_t
617 dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
618                           dns_rdatatype_t covers, dns_rdataset_t *rdataset)
619 {
620         dns_name_t tname;
621         dns_rdata_rrsig_t rrsig;
622         dns_rdata_t rdata = DNS_RDATA_INIT;
623         dns_rdataset_t clone;
624         dns_rdatatype_t type;
625         dns_trust_t trust = dns_trust_none;
626         isc_buffer_t source;
627         isc_region_t remaining, sigregion;
628         isc_result_t result;
629         unsigned char *raw;
630         unsigned int count;
631
632         REQUIRE(ncacherdataset != NULL);
633         REQUIRE(ncacherdataset->type == 0);
634         REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
635         REQUIRE(name != NULL);
636         REQUIRE(!dns_rdataset_isassociated(rdataset));
637
638         dns_rdataset_init(&clone);
639         dns_rdataset_clone(ncacherdataset, &clone);
640         result = dns_rdataset_first(&clone);
641         while (result == ISC_R_SUCCESS) {
642                 dns_rdataset_current(&clone, &rdata);
643                 isc_buffer_init(&source, rdata.data, rdata.length);
644                 isc_buffer_add(&source, rdata.length);
645                 dns_name_init(&tname, NULL);
646                 isc_buffer_remainingregion(&source, &remaining);
647                 dns_name_fromregion(&tname, &remaining);
648                 INSIST(remaining.length >= tname.length);
649                 isc_buffer_forward(&source, tname.length);
650                 remaining.length -= tname.length;
651                 remaining.base += tname.length;
652
653                 INSIST(remaining.length >= 2);
654                 type = isc_buffer_getuint16(&source);
655                 remaining.length -= 2;
656                 remaining.base += 2;
657
658                 if (type != dns_rdatatype_rrsig ||
659                     !dns_name_equal(&tname, name)) {
660                         result = dns_rdataset_next(&clone);
661                         dns_rdata_reset(&rdata);
662                         continue;
663                 }
664
665                 INSIST(remaining.length >= 1);
666                 trust = isc_buffer_getuint8(&source);
667                 INSIST(trust <= dns_trust_ultimate);
668                 remaining.length -= 1;
669                 remaining.base += 1;
670
671                 raw = remaining.base;
672                 count = raw[0] * 256 + raw[1];
673                 INSIST(count > 0);
674                 raw += 2;
675                 sigregion.length = raw[0] * 256 + raw[1];
676                 raw += 2;
677                 sigregion.base = raw;
678                 dns_rdata_reset(&rdata);
679                 dns_rdata_fromregion(&rdata, rdataset->rdclass,
680                                      dns_rdatatype_rrsig, &sigregion);
681                 (void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
682                 if (rrsig.covered == covers) {
683                         isc_buffer_remainingregion(&source, &remaining);
684                         break;
685                 }
686
687                 result = dns_rdataset_next(&clone);
688                 dns_rdata_reset(&rdata);
689         }
690         dns_rdataset_disassociate(&clone);
691         if (result == ISC_R_NOMORE)
692                 return (ISC_R_NOTFOUND);
693         if (result != ISC_R_SUCCESS)
694                 return (result);
695
696         INSIST(remaining.length != 0);
697
698         rdataset->methods = &rdataset_methods;
699         rdataset->rdclass = ncacherdataset->rdclass;
700         rdataset->type = dns_rdatatype_rrsig;
701         rdataset->covers = covers;
702         rdataset->ttl = ncacherdataset->ttl;
703         rdataset->trust = trust;
704         rdataset->private1 = NULL;
705         rdataset->private2 = NULL;
706
707         rdataset->private3 = remaining.base;
708
709         /*
710          * Reset iterator state.
711          */
712         rdataset->privateuint4 = 0;
713         rdataset->private5 = NULL;
714         rdataset->private6 = NULL;
715         return (ISC_R_SUCCESS);
716 }
717
718 void
719 dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
720                    dns_rdataset_t *rdataset)
721 {
722         dns_rdata_t rdata = DNS_RDATA_INIT;
723         dns_trust_t trust;
724         isc_region_t remaining, sigregion;
725         isc_buffer_t source;
726         dns_name_t tname;
727         dns_rdatatype_t type;
728         unsigned int count;
729         dns_rdata_rrsig_t rrsig;
730         unsigned char *raw;
731
732         REQUIRE(ncacherdataset != NULL);
733         REQUIRE(ncacherdataset->type == 0);
734         REQUIRE((ncacherdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
735         REQUIRE(found != NULL);
736         REQUIRE(!dns_rdataset_isassociated(rdataset));
737
738         dns_rdataset_current(ncacherdataset, &rdata);
739         isc_buffer_init(&source, rdata.data, rdata.length);
740         isc_buffer_add(&source, rdata.length);
741
742         dns_name_init(&tname, NULL);
743         isc_buffer_remainingregion(&source, &remaining);
744         dns_name_fromregion(found, &remaining);
745         INSIST(remaining.length >= found->length);
746         isc_buffer_forward(&source, found->length);
747         remaining.length -= found->length;
748
749         INSIST(remaining.length >= 5);
750         type = isc_buffer_getuint16(&source);
751         trust = isc_buffer_getuint8(&source);
752         INSIST(trust <= dns_trust_ultimate);
753         isc_buffer_remainingregion(&source, &remaining);
754
755         rdataset->methods = &rdataset_methods;
756         rdataset->rdclass = ncacherdataset->rdclass;
757         rdataset->type = type;
758         if (type == dns_rdatatype_rrsig) {
759                 /*
760                  * Extract covers from RRSIG.
761                  */
762                 raw = remaining.base;
763                 count = raw[0] * 256 + raw[1];
764                 INSIST(count > 0);
765                 raw += 2;
766                 sigregion.length = raw[0] * 256 + raw[1];
767                 raw += 2;
768                 sigregion.base = raw;
769                 dns_rdata_reset(&rdata);
770                 dns_rdata_fromregion(&rdata, rdataset->rdclass,
771                                      rdataset->type, &sigregion);
772                 (void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
773                 rdataset->covers = rrsig.covered;
774         } else
775                 rdataset->covers = 0;
776         rdataset->ttl = ncacherdataset->ttl;
777         rdataset->trust = trust;
778         rdataset->private1 = NULL;
779         rdataset->private2 = NULL;
780
781         rdataset->private3 = remaining.base;
782
783         /*
784          * Reset iterator state.
785          */
786         rdataset->privateuint4 = 0;
787         rdataset->private5 = NULL;
788         rdataset->private6 = NULL;
789 }