2 * Copyright (C) 2004, 2005, 2007, 2008, 2010 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.334.2 2010/02/25 10:57:11 tbox 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:
44 * rdata length These two occur 'rdata count'
49 static inline isc_result_t
50 copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
54 dns_rdata_t rdata = DNS_RDATA_INIT;
57 * Copy the rdataset count to the buffer.
59 isc_buffer_availableregion(buffer, &ar);
61 return (ISC_R_NOSPACE);
62 count = dns_rdataset_count(rdataset);
63 INSIST(count <= 65535);
64 isc_buffer_putuint16(buffer, (isc_uint16_t)count);
66 result = dns_rdataset_first(rdataset);
67 while (result == ISC_R_SUCCESS) {
68 dns_rdataset_current(rdataset, &rdata);
69 dns_rdata_toregion(&rdata, &r);
70 INSIST(r.length <= 65535);
71 isc_buffer_availableregion(buffer, &ar);
73 return (ISC_R_NOSPACE);
75 * Copy the rdata length to the buffer.
77 isc_buffer_putuint16(buffer, (isc_uint16_t)r.length);
79 * Copy the rdata to the buffer.
81 result = isc_buffer_copyregion(buffer, &r);
82 if (result != ISC_R_SUCCESS)
84 dns_rdata_reset(&rdata);
85 result = dns_rdataset_next(rdataset);
87 if (result != ISC_R_NOMORE)
90 return (ISC_R_SUCCESS);
94 dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
95 dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
96 dns_rdataset_t *addedrdataset)
98 return (dns_ncache_addoptout(message, cache, node, covers, now, maxttl,
99 ISC_FALSE, addedrdataset));
103 dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache,
104 dns_dbnode_t *node, dns_rdatatype_t covers,
105 isc_stdtime_t now, dns_ttl_t maxttl,
106 isc_boolean_t optout, dns_rdataset_t *addedrdataset)
111 dns_rdataset_t *rdataset;
112 dns_rdatatype_t type;
116 dns_rdata_t rdata[DNS_NCACHE_RDATA];
117 dns_rdataset_t ncrdataset;
118 dns_rdatalist_t ncrdatalist;
119 unsigned char data[4096];
120 unsigned int next = 0;
123 * Convert the authority data from 'message' into a negative cache
124 * rdataset, and store it in 'cache' at 'node'.
127 REQUIRE(message != NULL);
130 * We assume that all data in the authority section has been
131 * validated by the caller.
135 * Initialize the list.
137 ncrdatalist.rdclass = dns_db_class(cache);
138 ncrdatalist.type = 0;
139 ncrdatalist.covers = covers;
140 ncrdatalist.ttl = maxttl;
141 ISC_LIST_INIT(ncrdatalist.rdata);
142 ISC_LINK_INIT(&ncrdatalist, link);
145 * Build an ncache rdatas into buffer.
149 isc_buffer_init(&buffer, data, sizeof(data));
150 if (message->counts[DNS_SECTION_AUTHORITY])
151 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
153 result = ISC_R_NOMORE;
154 while (result == ISC_R_SUCCESS) {
156 dns_message_currentname(message, DNS_SECTION_AUTHORITY,
158 if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
159 for (rdataset = ISC_LIST_HEAD(name->list);
161 rdataset = ISC_LIST_NEXT(rdataset, link)) {
162 if ((rdataset->attributes &
163 DNS_RDATASETATTR_NCACHE) == 0)
165 type = rdataset->type;
166 if (type == dns_rdatatype_rrsig)
167 type = rdataset->covers;
168 if (type == dns_rdatatype_soa ||
169 type == dns_rdatatype_nsec ||
170 type == dns_rdatatype_nsec3) {
171 if (ttl > rdataset->ttl)
173 if (trust > rdataset->trust)
174 trust = rdataset->trust;
176 * Copy the owner name to the buffer.
178 dns_name_toregion(name, &r);
179 result = isc_buffer_copyregion(&buffer,
181 if (result != ISC_R_SUCCESS)
184 * Copy the type to the buffer.
186 isc_buffer_availableregion(&buffer,
189 return (ISC_R_NOSPACE);
190 isc_buffer_putuint16(&buffer,
193 * Copy the rdataset into the buffer.
195 result = copy_rdataset(rdataset,
197 if (result != ISC_R_SUCCESS)
200 if (next >= DNS_NCACHE_RDATA)
201 return (ISC_R_NOSPACE);
202 dns_rdata_init(&rdata[next]);
203 isc_buffer_remainingregion(&buffer, &r);
204 rdata[next].data = r.base;
205 rdata[next].length = r.length;
206 rdata[next].rdclass =
208 rdata[next].type = 0;
209 rdata[next].flags = 0;
210 ISC_LIST_APPEND(ncrdatalist.rdata,
212 isc_buffer_forward(&buffer, r.length);
217 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
219 if (result != ISC_R_NOMORE)
222 if (trust == 0xffff) {
224 * We didn't find any authority data from which to create a
225 * negative cache rdataset. In particular, we have no SOA.
227 * We trust that the caller wants negative caching, so this
228 * means we have a "type 3 nxdomain" or "type 3 nodata"
229 * response (see RFC2308 for details).
231 * We will now build a suitable negative cache rdataset that
232 * will cause zero bytes to be emitted when converted to
237 * The ownername must exist, but it doesn't matter what value
238 * it has. We use the root name.
240 dns_name_toregion(dns_rootname, &r);
241 result = isc_buffer_copyregion(&buffer, &r);
242 if (result != ISC_R_SUCCESS)
245 * Copy the type and a zero rdata count to the buffer.
247 isc_buffer_availableregion(&buffer, &r);
249 return (ISC_R_NOSPACE);
250 isc_buffer_putuint16(&buffer, 0);
251 isc_buffer_putuint16(&buffer, 0);
253 * RFC2308, section 5, says that negative answers without
254 * SOAs should not be cached.
260 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
261 message->counts[DNS_SECTION_ANSWER] == 0) {
263 * The response has aa set and we haven't followed
264 * any CNAME or DNAME chains.
266 trust = dns_trust_authauthority;
268 trust = dns_trust_additional;
270 * Now add it to the cache.
272 if (next >= DNS_NCACHE_RDATA)
273 return (ISC_R_NOSPACE);
274 dns_rdata_init(&rdata[next]);
275 isc_buffer_remainingregion(&buffer, &r);
276 rdata[next].data = r.base;
277 rdata[next].length = r.length;
278 rdata[next].rdclass = ncrdatalist.rdclass;
279 rdata[next].type = 0;
280 rdata[next].flags = 0;
281 ISC_LIST_APPEND(ncrdatalist.rdata, &rdata[next], link);
284 INSIST(trust != 0xffff);
286 ncrdatalist.ttl = ttl;
288 dns_rdataset_init(&ncrdataset);
289 RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
291 ncrdataset.trust = trust;
292 if (message->rcode == dns_rcode_nxdomain)
293 ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
295 ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT;
297 return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
302 dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
303 isc_buffer_t *target, unsigned int options,
304 unsigned int *countp)
306 dns_rdata_t rdata = DNS_RDATA_INIT;
308 isc_region_t remaining, tavailable;
309 isc_buffer_t source, savedbuffer, rdlen;
311 dns_rdatatype_t type;
312 unsigned int i, rcount, count;
315 * Convert the negative caching rdataset 'rdataset' to wire format,
316 * compressing names as specified in 'cctx', and storing the result in
320 REQUIRE(rdataset != NULL);
321 REQUIRE(rdataset->type == 0);
323 savedbuffer = *target;
326 result = dns_rdataset_first(rdataset);
327 while (result == ISC_R_SUCCESS) {
328 dns_rdataset_current(rdataset, &rdata);
329 isc_buffer_init(&source, rdata.data, rdata.length);
330 isc_buffer_add(&source, rdata.length);
331 dns_name_init(&name, NULL);
332 isc_buffer_remainingregion(&source, &remaining);
333 dns_name_fromregion(&name, &remaining);
334 INSIST(remaining.length >= name.length);
335 isc_buffer_forward(&source, name.length);
336 remaining.length -= name.length;
338 INSIST(remaining.length >= 4);
339 type = isc_buffer_getuint16(&source);
340 rcount = isc_buffer_getuint16(&source);
342 for (i = 0; i < rcount; i++) {
344 * Get the length of this rdata and set up an
345 * rdata structure for it.
347 isc_buffer_remainingregion(&source, &remaining);
348 INSIST(remaining.length >= 2);
349 dns_rdata_reset(&rdata);
350 rdata.length = isc_buffer_getuint16(&source);
351 isc_buffer_remainingregion(&source, &remaining);
352 rdata.data = remaining.base;
354 rdata.rdclass = rdataset->rdclass;
355 INSIST(remaining.length >= rdata.length);
356 isc_buffer_forward(&source, rdata.length);
358 if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
359 dns_rdatatype_isdnssec(type))
365 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
366 result = dns_name_towire(&name, cctx, target);
367 if (result != ISC_R_SUCCESS)
371 * See if we have space for type, class, ttl, and
372 * rdata length. Write the type, class, and ttl.
374 isc_buffer_availableregion(target, &tavailable);
375 if (tavailable.length < 10) {
376 result = ISC_R_NOSPACE;
379 isc_buffer_putuint16(target, type);
380 isc_buffer_putuint16(target, rdataset->rdclass);
381 isc_buffer_putuint32(target, rdataset->ttl);
384 * Save space for rdata length.
387 isc_buffer_add(target, 2);
392 result = dns_rdata_towire(&rdata, cctx, target);
393 if (result != ISC_R_SUCCESS)
397 * Set the rdata length field to the compressed
400 INSIST((target->used >= rdlen.used + 2) &&
401 (target->used - rdlen.used - 2 < 65536));
402 isc_buffer_putuint16(&rdlen,
403 (isc_uint16_t)(target->used -
408 INSIST(isc_buffer_remaininglength(&source) == 0);
409 result = dns_rdataset_next(rdataset);
410 dns_rdata_reset(&rdata);
412 if (result != ISC_R_NOMORE)
417 return (ISC_R_SUCCESS);
420 INSIST(savedbuffer.used < 65536);
421 dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
423 *target = savedbuffer;
429 rdataset_disassociate(dns_rdataset_t *rdataset) {
434 rdataset_first(dns_rdataset_t *rdataset) {
435 unsigned char *raw = rdataset->private3;
438 count = raw[0] * 256 + raw[1];
440 rdataset->private5 = NULL;
441 return (ISC_R_NOMORE);
445 * The privateuint4 field is the number of rdata beyond the cursor
446 * position, so we decrement the total count by one before storing
450 rdataset->privateuint4 = count;
451 rdataset->private5 = raw;
453 return (ISC_R_SUCCESS);
457 rdataset_next(dns_rdataset_t *rdataset) {
462 count = rdataset->privateuint4;
464 return (ISC_R_NOMORE);
466 rdataset->privateuint4 = count;
467 raw = rdataset->private5;
468 length = raw[0] * 256 + raw[1];
470 rdataset->private5 = raw;
472 return (ISC_R_SUCCESS);
476 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
477 unsigned char *raw = rdataset->private5;
480 REQUIRE(raw != NULL);
482 r.length = raw[0] * 256 + raw[1];
485 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
489 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
493 * Reset iterator state.
495 target->privateuint4 = 0;
496 target->private5 = NULL;
500 rdataset_count(dns_rdataset_t *rdataset) {
501 unsigned char *raw = rdataset->private3;
504 count = raw[0] * 256 + raw[1];
509 static dns_rdatasetmethods_t rdataset_methods = {
510 rdataset_disassociate,
528 dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
529 dns_rdatatype_t type, dns_rdataset_t *rdataset)
532 dns_rdata_t rdata = DNS_RDATA_INIT;
533 isc_region_t remaining;
536 dns_rdatatype_t ttype;
538 REQUIRE(ncacherdataset != NULL);
539 REQUIRE(ncacherdataset->type == 0);
540 REQUIRE(name != NULL);
541 REQUIRE(!dns_rdataset_isassociated(rdataset));
542 REQUIRE(type != dns_rdatatype_rrsig);
544 result = dns_rdataset_first(ncacherdataset);
545 while (result == ISC_R_SUCCESS) {
546 dns_rdataset_current(ncacherdataset, &rdata);
547 isc_buffer_init(&source, rdata.data, rdata.length);
548 isc_buffer_add(&source, rdata.length);
549 dns_name_init(&tname, NULL);
550 isc_buffer_remainingregion(&source, &remaining);
551 dns_name_fromregion(&tname, &remaining);
552 INSIST(remaining.length >= tname.length);
553 isc_buffer_forward(&source, tname.length);
554 remaining.length -= tname.length;
556 INSIST(remaining.length >= 4);
557 ttype = isc_buffer_getuint16(&source);
559 if (ttype == type && dns_name_equal(&tname, name)) {
560 isc_buffer_remainingregion(&source, &remaining);
563 result = dns_rdataset_next(ncacherdataset);
564 dns_rdata_reset(&rdata);
566 if (result == ISC_R_NOMORE)
567 return (ISC_R_NOTFOUND);
568 if (result != ISC_R_SUCCESS)
571 INSIST(remaining.length != 0);
573 rdataset->methods = &rdataset_methods;
574 rdataset->rdclass = ncacherdataset->rdclass;
575 rdataset->type = type;
576 rdataset->covers = 0;
577 rdataset->ttl = ncacherdataset->ttl;
578 rdataset->trust = ncacherdataset->trust;
579 rdataset->private1 = NULL;
580 rdataset->private2 = NULL;
582 rdataset->private3 = remaining.base;
585 * Reset iterator state.
587 rdataset->privateuint4 = 0;
588 rdataset->private5 = NULL;
589 rdataset->private6 = NULL;
590 return (ISC_R_SUCCESS);
594 dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
595 dns_rdataset_t *rdataset)
597 dns_rdata_t rdata = DNS_RDATA_INIT;
598 isc_region_t remaining, sigregion;
601 dns_rdatatype_t type;
603 dns_rdata_rrsig_t rrsig;
606 REQUIRE(ncacherdataset != NULL);
607 REQUIRE(ncacherdataset->type == 0);
608 REQUIRE(found != NULL);
609 REQUIRE(!dns_rdataset_isassociated(rdataset));
611 dns_rdataset_current(ncacherdataset, &rdata);
612 isc_buffer_init(&source, rdata.data, rdata.length);
613 isc_buffer_add(&source, rdata.length);
615 dns_name_init(&tname, NULL);
616 isc_buffer_remainingregion(&source, &remaining);
617 dns_name_fromregion(found, &remaining);
618 INSIST(remaining.length >= found->length);
619 isc_buffer_forward(&source, found->length);
620 remaining.length -= found->length;
622 INSIST(remaining.length >= 4);
623 type = isc_buffer_getuint16(&source);
624 isc_buffer_remainingregion(&source, &remaining);
626 rdataset->methods = &rdataset_methods;
627 rdataset->rdclass = ncacherdataset->rdclass;
628 rdataset->type = type;
629 if (type == dns_rdatatype_rrsig) {
631 * Extract covers from RRSIG.
633 raw = remaining.base;
634 count = raw[0] * 256 + raw[1];
637 sigregion.length = raw[0] * 256 + raw[1];
639 sigregion.base = raw;
640 dns_rdata_reset(&rdata);
641 dns_rdata_fromregion(&rdata, rdataset->rdclass,
642 rdataset->type, &sigregion);
643 (void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
644 rdataset->covers = rrsig.covered;
646 rdataset->covers = 0;
647 rdataset->ttl = ncacherdataset->ttl;
648 rdataset->trust = ncacherdataset->trust;
649 rdataset->private1 = NULL;
650 rdataset->private2 = NULL;
652 rdataset->private3 = remaining.base;
655 * Reset iterator state.
657 rdataset->privateuint4 = 0;
658 rdataset->private5 = NULL;
659 rdataset->private6 = NULL;