2 * Copyright (C) 2004, 2005, 2007, 2008, 2010, 2011 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
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.
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.
18 /* $Id: ncache.c,v 1.43.48.7.6.3 2011-06-21 20:13:22 each Exp $ */
24 #include <isc/buffer.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>
35 #define DNS_NCACHE_RDATA 20U
38 * The format of an ncache rdata is a sequence of one or more records of
39 * the following format:
45 * rdata length These two occur 'rdata count'
50 static inline isc_result_t
51 copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
55 dns_rdata_t rdata = DNS_RDATA_INIT;
58 * Copy the rdataset count to the buffer.
60 isc_buffer_availableregion(buffer, &ar);
62 return (ISC_R_NOSPACE);
63 count = dns_rdataset_count(rdataset);
64 INSIST(count <= 65535);
65 isc_buffer_putuint16(buffer, (isc_uint16_t)count);
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);
74 return (ISC_R_NOSPACE);
76 * Copy the rdata length to the buffer.
78 isc_buffer_putuint16(buffer, (isc_uint16_t)r.length);
80 * Copy the rdata to the buffer.
82 result = isc_buffer_copyregion(buffer, &r);
83 if (result != ISC_R_SUCCESS)
85 dns_rdata_reset(&rdata);
86 result = dns_rdataset_next(rdataset);
88 if (result != ISC_R_NOMORE)
91 return (ISC_R_SUCCESS);
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)
99 return (dns_ncache_addoptout(message, cache, node, covers, now, maxttl,
100 ISC_FALSE, addedrdataset));
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)
112 dns_rdataset_t *rdataset;
113 dns_rdatatype_t type;
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;
124 * Convert the authority data from 'message' into a negative cache
125 * rdataset, and store it in 'cache' at 'node'.
128 REQUIRE(message != NULL);
131 * We assume that all data in the authority section has been
132 * validated by the caller.
136 * Initialize the list.
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);
146 * Build an ncache rdatas into buffer.
150 isc_buffer_init(&buffer, data, sizeof(data));
151 if (message->counts[DNS_SECTION_AUTHORITY])
152 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
154 result = ISC_R_NOMORE;
155 while (result == ISC_R_SUCCESS) {
157 dns_message_currentname(message, DNS_SECTION_AUTHORITY,
159 if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
160 for (rdataset = ISC_LIST_HEAD(name->list);
162 rdataset = ISC_LIST_NEXT(rdataset, link)) {
163 if ((rdataset->attributes &
164 DNS_RDATASETATTR_NCACHE) == 0)
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)
174 if (trust > rdataset->trust)
175 trust = rdataset->trust;
177 * Copy the owner name to the buffer.
179 dns_name_toregion(name, &r);
180 result = isc_buffer_copyregion(&buffer,
182 if (result != ISC_R_SUCCESS)
185 * Copy the type to the buffer.
187 isc_buffer_availableregion(&buffer,
190 return (ISC_R_NOSPACE);
191 isc_buffer_putuint16(&buffer,
193 isc_buffer_putuint8(&buffer,
194 (unsigned char)rdataset->trust);
196 * Copy the rdataset into the buffer.
198 result = copy_rdataset(rdataset,
200 if (result != ISC_R_SUCCESS)
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 =
211 rdata[next].type = 0;
212 rdata[next].flags = 0;
213 ISC_LIST_APPEND(ncrdatalist.rdata,
215 isc_buffer_forward(&buffer, r.length);
220 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
222 if (result != ISC_R_NOMORE)
225 if (trust == 0xffff) {
227 * We didn't find any authority data from which to create a
228 * negative cache rdataset. In particular, we have no SOA.
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).
234 * We will now build a suitable negative cache rdataset that
235 * will cause zero bytes to be emitted when converted to
240 * The ownername must exist, but it doesn't matter what value
241 * it has. We use the root name.
243 dns_name_toregion(dns_rootname, &r);
244 result = isc_buffer_copyregion(&buffer, &r);
245 if (result != ISC_R_SUCCESS)
248 * Copy the type and a zero rdata count to the buffer.
250 isc_buffer_availableregion(&buffer, &r);
252 return (ISC_R_NOSPACE);
253 isc_buffer_putuint16(&buffer, 0); /* type */
255 * RFC2308, section 5, says that negative answers without
256 * SOAs should not be cached.
262 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
263 message->counts[DNS_SECTION_ANSWER] == 0) {
265 * The response has aa set and we haven't followed
266 * any CNAME or DNAME chains.
268 trust = dns_trust_authauthority;
270 trust = dns_trust_additional;
271 isc_buffer_putuint8(&buffer, (unsigned char)trust); /* trust */
272 isc_buffer_putuint16(&buffer, 0); /* count */
275 * Now add it to the cache.
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);
289 INSIST(trust != 0xffff);
291 ncrdatalist.ttl = ttl;
293 dns_rdataset_init(&ncrdataset);
294 RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
296 ncrdataset.trust = trust;
297 ncrdataset.attributes |= DNS_RDATASETATTR_NEGATIVE;
298 if (message->rcode == dns_rcode_nxdomain)
299 ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
301 ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT;
303 return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
308 dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
309 isc_buffer_t *target, unsigned int options,
310 unsigned int *countp)
312 dns_rdata_t rdata = DNS_RDATA_INIT;
314 isc_region_t remaining, tavailable;
315 isc_buffer_t source, savedbuffer, rdlen;
317 dns_rdatatype_t type;
318 unsigned int i, rcount, count;
321 * Convert the negative caching rdataset 'rdataset' to wire format,
322 * compressing names as specified in 'cctx', and storing the result in
326 REQUIRE(rdataset != NULL);
327 REQUIRE(rdataset->type == 0);
328 REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
330 savedbuffer = *target;
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;
345 INSIST(remaining.length >= 5);
346 type = isc_buffer_getuint16(&source);
347 isc_buffer_forward(&source, 1);
348 rcount = isc_buffer_getuint16(&source);
350 for (i = 0; i < rcount; i++) {
352 * Get the length of this rdata and set up an
353 * rdata structure for it.
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;
362 rdata.rdclass = rdataset->rdclass;
363 INSIST(remaining.length >= rdata.length);
364 isc_buffer_forward(&source, rdata.length);
366 if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
367 dns_rdatatype_isdnssec(type))
373 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
374 result = dns_name_towire(&name, cctx, target);
375 if (result != ISC_R_SUCCESS)
379 * See if we have space for type, class, ttl, and
380 * rdata length. Write the type, class, and ttl.
382 isc_buffer_availableregion(target, &tavailable);
383 if (tavailable.length < 10) {
384 result = ISC_R_NOSPACE;
387 isc_buffer_putuint16(target, type);
388 isc_buffer_putuint16(target, rdataset->rdclass);
389 isc_buffer_putuint32(target, rdataset->ttl);
392 * Save space for rdata length.
395 isc_buffer_add(target, 2);
400 result = dns_rdata_towire(&rdata, cctx, target);
401 if (result != ISC_R_SUCCESS)
405 * Set the rdata length field to the compressed
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 -
416 INSIST(isc_buffer_remaininglength(&source) == 0);
417 result = dns_rdataset_next(rdataset);
418 dns_rdata_reset(&rdata);
420 if (result != ISC_R_NOMORE)
425 return (ISC_R_SUCCESS);
428 INSIST(savedbuffer.used < 65536);
429 dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
431 *target = savedbuffer;
437 rdataset_disassociate(dns_rdataset_t *rdataset) {
442 rdataset_first(dns_rdataset_t *rdataset) {
443 unsigned char *raw = rdataset->private3;
446 count = raw[0] * 256 + raw[1];
448 rdataset->private5 = NULL;
449 return (ISC_R_NOMORE);
453 * The privateuint4 field is the number of rdata beyond the cursor
454 * position, so we decrement the total count by one before storing
458 rdataset->privateuint4 = count;
459 rdataset->private5 = raw;
461 return (ISC_R_SUCCESS);
465 rdataset_next(dns_rdataset_t *rdataset) {
470 count = rdataset->privateuint4;
472 return (ISC_R_NOMORE);
474 rdataset->privateuint4 = count;
475 raw = rdataset->private5;
476 length = raw[0] * 256 + raw[1];
478 rdataset->private5 = raw;
480 return (ISC_R_SUCCESS);
484 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
485 unsigned char *raw = rdataset->private5;
488 REQUIRE(raw != NULL);
490 r.length = raw[0] * 256 + raw[1];
493 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
497 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
501 * Reset iterator state.
503 target->privateuint4 = 0;
504 target->private5 = NULL;
508 rdataset_count(dns_rdataset_t *rdataset) {
509 unsigned char *raw = rdataset->private3;
512 count = raw[0] * 256 + raw[1];
518 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
519 unsigned char *raw = rdataset->private3;
521 raw[-1] = (unsigned char)trust;
524 static dns_rdatasetmethods_t rdataset_methods = {
525 rdataset_disassociate,
543 dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
544 dns_rdatatype_t type, dns_rdataset_t *rdataset)
547 dns_rdata_t rdata = DNS_RDATA_INIT;
548 isc_region_t remaining;
551 dns_rdatatype_t ttype;
552 dns_trust_t trust = dns_trust_none;
553 dns_rdataset_t clone;
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);
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;
576 INSIST(remaining.length >= 3);
577 ttype = isc_buffer_getuint16(&source);
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);
585 result = dns_rdataset_next(&clone);
586 dns_rdata_reset(&rdata);
588 dns_rdataset_disassociate(&clone);
589 if (result == ISC_R_NOMORE)
590 return (ISC_R_NOTFOUND);
591 if (result != ISC_R_SUCCESS)
594 INSIST(remaining.length != 0);
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;
605 rdataset->private3 = remaining.base;
608 * Reset iterator state.
610 rdataset->privateuint4 = 0;
611 rdataset->private5 = NULL;
612 rdataset->private6 = NULL;
613 return (ISC_R_SUCCESS);
617 dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
618 dns_rdatatype_t covers, dns_rdataset_t *rdataset)
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;
627 isc_region_t remaining, sigregion;
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));
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;
653 INSIST(remaining.length >= 2);
654 type = isc_buffer_getuint16(&source);
655 remaining.length -= 2;
658 if (type != dns_rdatatype_rrsig ||
659 !dns_name_equal(&tname, name)) {
660 result = dns_rdataset_next(&clone);
661 dns_rdata_reset(&rdata);
665 INSIST(remaining.length >= 1);
666 trust = isc_buffer_getuint8(&source);
667 INSIST(trust <= dns_trust_ultimate);
668 remaining.length -= 1;
671 raw = remaining.base;
672 count = raw[0] * 256 + raw[1];
675 sigregion.length = raw[0] * 256 + raw[1];
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);
687 result = dns_rdataset_next(&clone);
688 dns_rdata_reset(&rdata);
690 dns_rdataset_disassociate(&clone);
691 if (result == ISC_R_NOMORE)
692 return (ISC_R_NOTFOUND);
693 if (result != ISC_R_SUCCESS)
696 INSIST(remaining.length != 0);
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;
707 rdataset->private3 = remaining.base;
710 * Reset iterator state.
712 rdataset->privateuint4 = 0;
713 rdataset->private5 = NULL;
714 rdataset->private6 = NULL;
715 return (ISC_R_SUCCESS);
719 dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
720 dns_rdataset_t *rdataset)
722 dns_rdata_t rdata = DNS_RDATA_INIT;
724 isc_region_t remaining, sigregion;
727 dns_rdatatype_t type;
729 dns_rdata_rrsig_t rrsig;
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));
738 dns_rdataset_current(ncacherdataset, &rdata);
739 isc_buffer_init(&source, rdata.data, rdata.length);
740 isc_buffer_add(&source, rdata.length);
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;
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);
755 rdataset->methods = &rdataset_methods;
756 rdataset->rdclass = ncacherdataset->rdclass;
757 rdataset->type = type;
758 if (type == dns_rdatatype_rrsig) {
760 * Extract covers from RRSIG.
762 raw = remaining.base;
763 count = raw[0] * 256 + raw[1];
766 sigregion.length = raw[0] * 256 + raw[1];
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;
775 rdataset->covers = 0;
776 rdataset->ttl = ncacherdataset->ttl;
777 rdataset->trust = trust;
778 rdataset->private1 = NULL;
779 rdataset->private2 = NULL;
781 rdataset->private3 = remaining.base;
784 * Reset iterator state.
786 rdataset->privateuint4 = 0;
787 rdataset->private5 = NULL;
788 rdataset->private6 = NULL;