2 * Copyright (C) 2004, 2005, 2007, 2008, 2010-2013 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.
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 zero or more records of
39 * the following format:
45 * rdata length These two occur 'rdata count'
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);
56 static inline isc_result_t
57 copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
61 dns_rdata_t rdata = DNS_RDATA_INIT;
64 * Copy the rdataset count to the buffer.
66 isc_buffer_availableregion(buffer, &ar);
68 return (ISC_R_NOSPACE);
69 count = dns_rdataset_count(rdataset);
70 INSIST(count <= 65535);
71 isc_buffer_putuint16(buffer, (isc_uint16_t)count);
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);
80 return (ISC_R_NOSPACE);
82 * Copy the rdata length to the buffer.
84 isc_buffer_putuint16(buffer, (isc_uint16_t)r.length);
86 * Copy the rdata to the buffer.
88 result = isc_buffer_copyregion(buffer, &r);
89 if (result != ISC_R_SUCCESS)
91 dns_rdata_reset(&rdata);
92 result = dns_rdataset_next(rdataset);
94 if (result != ISC_R_NOMORE)
97 return (ISC_R_SUCCESS);
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)
105 return (addoptout(message, cache, node, covers, now, maxttl,
106 ISC_FALSE, ISC_FALSE, addedrdataset));
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)
115 return (addoptout(message, cache, node, covers, now, maxttl,
116 optout, ISC_TRUE, addedrdataset));
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)
128 dns_rdataset_t *rdataset;
129 dns_rdatatype_t type;
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;
140 * Convert the authority data from 'message' into a negative cache
141 * rdataset, and store it in 'cache' at 'node'.
144 REQUIRE(message != NULL);
147 * We assume that all data in the authority section has been
148 * validated by the caller.
152 * Initialize the list.
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);
162 * Build an ncache rdatas into buffer.
166 isc_buffer_init(&buffer, data, sizeof(data));
167 if (message->counts[DNS_SECTION_AUTHORITY])
168 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
170 result = ISC_R_NOMORE;
171 while (result == ISC_R_SUCCESS) {
173 dns_message_currentname(message, DNS_SECTION_AUTHORITY,
175 if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
176 for (rdataset = ISC_LIST_HEAD(name->list);
178 rdataset = ISC_LIST_NEXT(rdataset, link)) {
179 if ((rdataset->attributes &
180 DNS_RDATASETATTR_NCACHE) == 0)
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)
190 if (trust > rdataset->trust)
191 trust = rdataset->trust;
193 * Copy the owner name to the buffer.
195 dns_name_toregion(name, &r);
196 result = isc_buffer_copyregion(&buffer,
198 if (result != ISC_R_SUCCESS)
201 * Copy the type to the buffer.
203 isc_buffer_availableregion(&buffer,
206 return (ISC_R_NOSPACE);
207 isc_buffer_putuint16(&buffer,
209 isc_buffer_putuint8(&buffer,
210 (unsigned char)rdataset->trust);
212 * Copy the rdataset into the buffer.
214 result = copy_rdataset(rdataset,
216 if (result != ISC_R_SUCCESS)
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 =
227 rdata[next].type = 0;
228 rdata[next].flags = 0;
229 ISC_LIST_APPEND(ncrdatalist.rdata,
231 isc_buffer_forward(&buffer, r.length);
236 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
238 if (result != ISC_R_NOMORE)
241 if (trust == 0xffff) {
242 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
243 message->counts[DNS_SECTION_ANSWER] == 0) {
245 * The response has aa set and we haven't followed
246 * any CNAME or DNAME chains.
248 trust = dns_trust_authauthority;
250 trust = dns_trust_additional;
254 INSIST(trust != 0xffff);
256 ncrdatalist.ttl = ttl;
258 dns_rdataset_init(&ncrdataset);
259 RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
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;
268 ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT;
270 return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
275 dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
276 isc_buffer_t *target, unsigned int options,
277 unsigned int *countp)
279 dns_rdata_t rdata = DNS_RDATA_INIT;
281 isc_region_t remaining, tavailable;
282 isc_buffer_t source, savedbuffer, rdlen;
284 dns_rdatatype_t type;
285 unsigned int i, rcount, count;
288 * Convert the negative caching rdataset 'rdataset' to wire format,
289 * compressing names as specified in 'cctx', and storing the result in
293 REQUIRE(rdataset != NULL);
294 REQUIRE(rdataset->type == 0);
295 REQUIRE((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0);
297 savedbuffer = *target;
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;
312 INSIST(remaining.length >= 5);
313 type = isc_buffer_getuint16(&source);
314 isc_buffer_forward(&source, 1);
315 rcount = isc_buffer_getuint16(&source);
317 for (i = 0; i < rcount; i++) {
319 * Get the length of this rdata and set up an
320 * rdata structure for it.
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;
329 rdata.rdclass = rdataset->rdclass;
330 INSIST(remaining.length >= rdata.length);
331 isc_buffer_forward(&source, rdata.length);
333 if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
334 dns_rdatatype_isdnssec(type))
340 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
341 result = dns_name_towire(&name, cctx, target);
342 if (result != ISC_R_SUCCESS)
346 * See if we have space for type, class, ttl, and
347 * rdata length. Write the type, class, and ttl.
349 isc_buffer_availableregion(target, &tavailable);
350 if (tavailable.length < 10) {
351 result = ISC_R_NOSPACE;
354 isc_buffer_putuint16(target, type);
355 isc_buffer_putuint16(target, rdataset->rdclass);
356 isc_buffer_putuint32(target, rdataset->ttl);
359 * Save space for rdata length.
362 isc_buffer_add(target, 2);
367 result = dns_rdata_towire(&rdata, cctx, target);
368 if (result != ISC_R_SUCCESS)
372 * Set the rdata length field to the compressed
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 -
383 INSIST(isc_buffer_remaininglength(&source) == 0);
384 result = dns_rdataset_next(rdataset);
385 dns_rdata_reset(&rdata);
387 if (result != ISC_R_NOMORE)
392 return (ISC_R_SUCCESS);
395 INSIST(savedbuffer.used < 65536);
396 dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
398 *target = savedbuffer;
404 rdataset_disassociate(dns_rdataset_t *rdataset) {
409 rdataset_first(dns_rdataset_t *rdataset) {
410 unsigned char *raw = rdataset->private3;
413 count = raw[0] * 256 + raw[1];
415 rdataset->private5 = NULL;
416 return (ISC_R_NOMORE);
420 * The privateuint4 field is the number of rdata beyond the cursor
421 * position, so we decrement the total count by one before storing
425 rdataset->privateuint4 = count;
426 rdataset->private5 = raw;
428 return (ISC_R_SUCCESS);
432 rdataset_next(dns_rdataset_t *rdataset) {
437 count = rdataset->privateuint4;
439 return (ISC_R_NOMORE);
441 rdataset->privateuint4 = count;
442 raw = rdataset->private5;
443 length = raw[0] * 256 + raw[1];
445 rdataset->private5 = raw;
447 return (ISC_R_SUCCESS);
451 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
452 unsigned char *raw = rdataset->private5;
455 REQUIRE(raw != NULL);
457 r.length = raw[0] * 256 + raw[1];
460 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
464 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
468 * Reset iterator state.
470 target->privateuint4 = 0;
471 target->private5 = NULL;
475 rdataset_count(dns_rdataset_t *rdataset) {
476 unsigned char *raw = rdataset->private3;
479 count = raw[0] * 256 + raw[1];
485 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
486 unsigned char *raw = rdataset->private3;
488 raw[-1] = (unsigned char)trust;
491 static dns_rdatasetmethods_t rdataset_methods = {
492 rdataset_disassociate,
510 dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
511 dns_rdatatype_t type, dns_rdataset_t *rdataset)
514 dns_rdata_t rdata = DNS_RDATA_INIT;
515 isc_region_t remaining;
518 dns_rdatatype_t ttype;
519 dns_trust_t trust = dns_trust_none;
520 dns_rdataset_t clone;
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);
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;
543 INSIST(remaining.length >= 3);
544 ttype = isc_buffer_getuint16(&source);
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);
552 result = dns_rdataset_next(&clone);
553 dns_rdata_reset(&rdata);
555 dns_rdataset_disassociate(&clone);
556 if (result == ISC_R_NOMORE)
557 return (ISC_R_NOTFOUND);
558 if (result != ISC_R_SUCCESS)
561 INSIST(remaining.length != 0);
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;
572 rdataset->private3 = remaining.base;
575 * Reset iterator state.
577 rdataset->privateuint4 = 0;
578 rdataset->private5 = NULL;
579 rdataset->private6 = NULL;
580 return (ISC_R_SUCCESS);
584 dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
585 dns_rdatatype_t covers, dns_rdataset_t *rdataset)
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;
594 isc_region_t remaining, sigregion;
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));
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);
619 INSIST(remaining.length >= 2);
620 type = isc_buffer_getuint16(&source);
621 isc_region_consume(&remaining, 2);
623 if (type != dns_rdatatype_rrsig ||
624 !dns_name_equal(&tname, name)) {
625 result = dns_rdataset_next(&clone);
626 dns_rdata_reset(&rdata);
630 INSIST(remaining.length >= 1);
631 trust = isc_buffer_getuint8(&source);
632 INSIST(trust <= dns_trust_ultimate);
633 isc_region_consume(&remaining, 1);
635 raw = remaining.base;
636 count = raw[0] * 256 + raw[1];
639 sigregion.length = raw[0] * 256 + raw[1];
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);
651 result = dns_rdataset_next(&clone);
652 dns_rdata_reset(&rdata);
654 dns_rdataset_disassociate(&clone);
655 if (result == ISC_R_NOMORE)
656 return (ISC_R_NOTFOUND);
657 if (result != ISC_R_SUCCESS)
660 INSIST(remaining.length != 0);
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;
671 rdataset->private3 = remaining.base;
674 * Reset iterator state.
676 rdataset->privateuint4 = 0;
677 rdataset->private5 = NULL;
678 rdataset->private6 = NULL;
679 return (ISC_R_SUCCESS);
683 dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
684 dns_rdataset_t *rdataset)
686 dns_rdata_t rdata = DNS_RDATA_INIT;
688 isc_region_t remaining, sigregion;
691 dns_rdatatype_t type;
693 dns_rdata_rrsig_t rrsig;
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));
702 dns_rdataset_current(ncacherdataset, &rdata);
703 isc_buffer_init(&source, rdata.data, rdata.length);
704 isc_buffer_add(&source, rdata.length);
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;
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);
719 rdataset->methods = &rdataset_methods;
720 rdataset->rdclass = ncacherdataset->rdclass;
721 rdataset->type = type;
722 if (type == dns_rdatatype_rrsig) {
724 * Extract covers from RRSIG.
726 raw = remaining.base;
727 count = raw[0] * 256 + raw[1];
730 sigregion.length = raw[0] * 256 + raw[1];
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;
739 rdataset->covers = 0;
740 rdataset->ttl = ncacherdataset->ttl;
741 rdataset->trust = trust;
742 rdataset->private1 = NULL;
743 rdataset->private2 = NULL;
745 rdataset->private3 = remaining.base;
748 * Reset iterator state.
750 rdataset->privateuint4 = 0;
751 rdataset->private5 = NULL;
752 rdataset->private6 = NULL;