4 * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: ncache.c,v 1.43 2008/09/25 04:02:38 tbox Exp */
26 #include <isc/buffer.h>
30 #include <dns/message.h>
31 #include <dns/ncache.h>
32 #include <dns/rdata.h>
33 #include <dns/rdatalist.h>
34 #include <dns/rdataset.h>
35 #include <dns/rdatastruct.h>
37 #define DNS_NCACHE_RDATA 20U
40 * The format of an ncache rdata is a sequence of one or more records of
41 * the following format:
46 * rdata length These two occur 'rdata count'
51 static inline isc_result_t
52 copy_rdataset(dns_rdataset_t
*rdataset
, isc_buffer_t
*buffer
) {
56 dns_rdata_t rdata
= DNS_RDATA_INIT
;
59 * Copy the rdataset count to the buffer.
61 isc_buffer_availableregion(buffer
, &ar
);
63 return (ISC_R_NOSPACE
);
64 count
= dns_rdataset_count(rdataset
);
65 INSIST(count
<= 65535);
66 isc_buffer_putuint16(buffer
, (isc_uint16_t
)count
);
68 result
= dns_rdataset_first(rdataset
);
69 while (result
== ISC_R_SUCCESS
) {
70 dns_rdataset_current(rdataset
, &rdata
);
71 dns_rdata_toregion(&rdata
, &r
);
72 INSIST(r
.length
<= 65535);
73 isc_buffer_availableregion(buffer
, &ar
);
75 return (ISC_R_NOSPACE
);
77 * Copy the rdata length to the buffer.
79 isc_buffer_putuint16(buffer
, (isc_uint16_t
)r
.length
);
81 * Copy the rdata to the buffer.
83 result
= isc_buffer_copyregion(buffer
, &r
);
84 if (result
!= ISC_R_SUCCESS
)
86 dns_rdata_reset(&rdata
);
87 result
= dns_rdataset_next(rdataset
);
89 if (result
!= ISC_R_NOMORE
)
92 return (ISC_R_SUCCESS
);
96 dns_ncache_add(dns_message_t
*message
, dns_db_t
*cache
, dns_dbnode_t
*node
,
97 dns_rdatatype_t covers
, isc_stdtime_t now
, dns_ttl_t maxttl
,
98 dns_rdataset_t
*addedrdataset
)
100 return (dns_ncache_addoptout(message
, cache
, node
, covers
, now
, maxttl
,
101 ISC_FALSE
, addedrdataset
));
105 dns_ncache_addoptout(dns_message_t
*message
, dns_db_t
*cache
,
106 dns_dbnode_t
*node
, dns_rdatatype_t covers
,
107 isc_stdtime_t now
, dns_ttl_t maxttl
,
108 isc_boolean_t optout
, dns_rdataset_t
*addedrdataset
)
113 dns_rdataset_t
*rdataset
;
114 dns_rdatatype_t type
;
118 dns_rdata_t rdata
[DNS_NCACHE_RDATA
];
119 dns_rdataset_t ncrdataset
;
120 dns_rdatalist_t ncrdatalist
;
121 unsigned char data
[4096];
122 unsigned int next
= 0;
125 * Convert the authority data from 'message' into a negative cache
126 * rdataset, and store it in 'cache' at 'node'.
129 REQUIRE(message
!= NULL
);
132 * We assume that all data in the authority section has been
133 * validated by the caller.
137 * Initialize the list.
139 ncrdatalist
.rdclass
= dns_db_class(cache
);
140 ncrdatalist
.type
= 0;
141 ncrdatalist
.covers
= covers
;
142 ncrdatalist
.ttl
= maxttl
;
143 ISC_LIST_INIT(ncrdatalist
.rdata
);
144 ISC_LINK_INIT(&ncrdatalist
, link
);
147 * Build an ncache rdatas into buffer.
151 isc_buffer_init(&buffer
, data
, sizeof(data
));
152 if (message
->counts
[DNS_SECTION_AUTHORITY
])
153 result
= dns_message_firstname(message
, DNS_SECTION_AUTHORITY
);
155 result
= ISC_R_NOMORE
;
156 while (result
== ISC_R_SUCCESS
) {
158 dns_message_currentname(message
, DNS_SECTION_AUTHORITY
,
160 if ((name
->attributes
& DNS_NAMEATTR_NCACHE
) != 0) {
161 for (rdataset
= ISC_LIST_HEAD(name
->list
);
163 rdataset
= ISC_LIST_NEXT(rdataset
, link
)) {
164 if ((rdataset
->attributes
&
165 DNS_RDATASETATTR_NCACHE
) == 0)
167 type
= rdataset
->type
;
168 if (type
== dns_rdatatype_rrsig
)
169 type
= rdataset
->covers
;
170 if (type
== dns_rdatatype_soa
||
171 type
== dns_rdatatype_nsec
||
172 type
== dns_rdatatype_nsec3
) {
173 if (ttl
> rdataset
->ttl
)
175 if (trust
> rdataset
->trust
)
176 trust
= rdataset
->trust
;
178 * Copy the owner name to the buffer.
180 dns_name_toregion(name
, &r
);
181 result
= isc_buffer_copyregion(&buffer
,
183 if (result
!= ISC_R_SUCCESS
)
186 * Copy the type to the buffer.
188 isc_buffer_availableregion(&buffer
,
191 return (ISC_R_NOSPACE
);
192 isc_buffer_putuint16(&buffer
,
195 * Copy the rdataset into the buffer.
197 result
= copy_rdataset(rdataset
,
199 if (result
!= ISC_R_SUCCESS
)
202 if (next
>= DNS_NCACHE_RDATA
)
203 return (ISC_R_NOSPACE
);
204 dns_rdata_init(&rdata
[next
]);
205 isc_buffer_remainingregion(&buffer
, &r
);
206 rdata
[next
].data
= r
.base
;
207 rdata
[next
].length
= r
.length
;
208 rdata
[next
].rdclass
=
210 rdata
[next
].type
= 0;
211 rdata
[next
].flags
= 0;
212 ISC_LIST_APPEND(ncrdatalist
.rdata
,
214 isc_buffer_forward(&buffer
, r
.length
);
219 result
= dns_message_nextname(message
, DNS_SECTION_AUTHORITY
);
221 if (result
!= ISC_R_NOMORE
)
224 if (trust
== 0xffff) {
226 * We didn't find any authority data from which to create a
227 * negative cache rdataset. In particular, we have no SOA.
229 * We trust that the caller wants negative caching, so this
230 * means we have a "type 3 nxdomain" or "type 3 nodata"
231 * response (see RFC2308 for details).
233 * We will now build a suitable negative cache rdataset that
234 * will cause zero bytes to be emitted when converted to
239 * The ownername must exist, but it doesn't matter what value
240 * it has. We use the root name.
242 dns_name_toregion(dns_rootname
, &r
);
243 result
= isc_buffer_copyregion(&buffer
, &r
);
244 if (result
!= ISC_R_SUCCESS
)
247 * Copy the type and a zero rdata count to the buffer.
249 isc_buffer_availableregion(&buffer
, &r
);
251 return (ISC_R_NOSPACE
);
252 isc_buffer_putuint16(&buffer
, 0);
253 isc_buffer_putuint16(&buffer
, 0);
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
;
272 * Now add it to the cache.
274 if (next
>= DNS_NCACHE_RDATA
)
275 return (ISC_R_NOSPACE
);
276 dns_rdata_init(&rdata
[next
]);
277 isc_buffer_remainingregion(&buffer
, &r
);
278 rdata
[next
].data
= r
.base
;
279 rdata
[next
].length
= r
.length
;
280 rdata
[next
].rdclass
= ncrdatalist
.rdclass
;
281 rdata
[next
].type
= 0;
282 rdata
[next
].flags
= 0;
283 ISC_LIST_APPEND(ncrdatalist
.rdata
, &rdata
[next
], link
);
286 INSIST(trust
!= 0xffff);
288 ncrdatalist
.ttl
= ttl
;
290 dns_rdataset_init(&ncrdataset
);
291 RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist
, &ncrdataset
)
293 ncrdataset
.trust
= trust
;
294 if (message
->rcode
== dns_rcode_nxdomain
)
295 ncrdataset
.attributes
|= DNS_RDATASETATTR_NXDOMAIN
;
297 ncrdataset
.attributes
|= DNS_RDATASETATTR_OPTOUT
;
299 return (dns_db_addrdataset(cache
, node
, NULL
, now
, &ncrdataset
,
304 dns_ncache_towire(dns_rdataset_t
*rdataset
, dns_compress_t
*cctx
,
305 isc_buffer_t
*target
, unsigned int options
,
306 unsigned int *countp
)
308 dns_rdata_t rdata
= DNS_RDATA_INIT
;
310 isc_region_t remaining
, tavailable
;
311 isc_buffer_t source
, savedbuffer
, rdlen
;
313 dns_rdatatype_t type
;
314 unsigned int i
, rcount
, count
;
317 * Convert the negative caching rdataset 'rdataset' to wire format,
318 * compressing names as specified in 'cctx', and storing the result in
322 REQUIRE(rdataset
!= NULL
);
323 REQUIRE(rdataset
->type
== 0);
325 savedbuffer
= *target
;
328 result
= dns_rdataset_first(rdataset
);
329 while (result
== ISC_R_SUCCESS
) {
330 dns_rdataset_current(rdataset
, &rdata
);
331 isc_buffer_init(&source
, rdata
.data
, rdata
.length
);
332 isc_buffer_add(&source
, rdata
.length
);
333 dns_name_init(&name
, NULL
);
334 isc_buffer_remainingregion(&source
, &remaining
);
335 dns_name_fromregion(&name
, &remaining
);
336 INSIST(remaining
.length
>= name
.length
);
337 isc_buffer_forward(&source
, name
.length
);
338 remaining
.length
-= name
.length
;
340 INSIST(remaining
.length
>= 4);
341 type
= isc_buffer_getuint16(&source
);
342 rcount
= isc_buffer_getuint16(&source
);
344 for (i
= 0; i
< rcount
; i
++) {
346 * Get the length of this rdata and set up an
347 * rdata structure for it.
349 isc_buffer_remainingregion(&source
, &remaining
);
350 INSIST(remaining
.length
>= 2);
351 dns_rdata_reset(&rdata
);
352 rdata
.length
= isc_buffer_getuint16(&source
);
353 isc_buffer_remainingregion(&source
, &remaining
);
354 rdata
.data
= remaining
.base
;
356 rdata
.rdclass
= rdataset
->rdclass
;
357 INSIST(remaining
.length
>= rdata
.length
);
358 isc_buffer_forward(&source
, rdata
.length
);
360 if ((options
& DNS_NCACHETOWIRE_OMITDNSSEC
) != 0 &&
361 dns_rdatatype_isdnssec(type
))
367 dns_compress_setmethods(cctx
, DNS_COMPRESS_GLOBAL14
);
368 result
= dns_name_towire(&name
, cctx
, target
);
369 if (result
!= ISC_R_SUCCESS
)
373 * See if we have space for type, class, ttl, and
374 * rdata length. Write the type, class, and ttl.
376 isc_buffer_availableregion(target
, &tavailable
);
377 if (tavailable
.length
< 10) {
378 result
= ISC_R_NOSPACE
;
381 isc_buffer_putuint16(target
, type
);
382 isc_buffer_putuint16(target
, rdataset
->rdclass
);
383 isc_buffer_putuint32(target
, rdataset
->ttl
);
386 * Save space for rdata length.
389 isc_buffer_add(target
, 2);
394 result
= dns_rdata_towire(&rdata
, cctx
, target
);
395 if (result
!= ISC_R_SUCCESS
)
399 * Set the rdata length field to the compressed
402 INSIST((target
->used
>= rdlen
.used
+ 2) &&
403 (target
->used
- rdlen
.used
- 2 < 65536));
404 isc_buffer_putuint16(&rdlen
,
405 (isc_uint16_t
)(target
->used
-
410 INSIST(isc_buffer_remaininglength(&source
) == 0);
411 result
= dns_rdataset_next(rdataset
);
412 dns_rdata_reset(&rdata
);
414 if (result
!= ISC_R_NOMORE
)
419 return (ISC_R_SUCCESS
);
422 INSIST(savedbuffer
.used
< 65536);
423 dns_compress_rollback(cctx
, (isc_uint16_t
)savedbuffer
.used
);
425 *target
= savedbuffer
;
431 rdataset_disassociate(dns_rdataset_t
*rdataset
) {
436 rdataset_first(dns_rdataset_t
*rdataset
) {
437 unsigned char *raw
= rdataset
->private3
;
440 count
= raw
[0] * 256 + raw
[1];
442 rdataset
->private5
= NULL
;
443 return (ISC_R_NOMORE
);
447 * The privateuint4 field is the number of rdata beyond the cursor
448 * position, so we decrement the total count by one before storing
452 rdataset
->privateuint4
= count
;
453 rdataset
->private5
= raw
;
455 return (ISC_R_SUCCESS
);
459 rdataset_next(dns_rdataset_t
*rdataset
) {
464 count
= rdataset
->privateuint4
;
466 return (ISC_R_NOMORE
);
468 rdataset
->privateuint4
= count
;
469 raw
= rdataset
->private5
;
470 length
= raw
[0] * 256 + raw
[1];
472 rdataset
->private5
= raw
;
474 return (ISC_R_SUCCESS
);
478 rdataset_current(dns_rdataset_t
*rdataset
, dns_rdata_t
*rdata
) {
479 unsigned char *raw
= rdataset
->private5
;
482 REQUIRE(raw
!= NULL
);
484 r
.length
= raw
[0] * 256 + raw
[1];
487 dns_rdata_fromregion(rdata
, rdataset
->rdclass
, rdataset
->type
, &r
);
491 rdataset_clone(dns_rdataset_t
*source
, dns_rdataset_t
*target
) {
495 * Reset iterator state.
497 target
->privateuint4
= 0;
498 target
->private5
= NULL
;
502 rdataset_count(dns_rdataset_t
*rdataset
) {
503 unsigned char *raw
= rdataset
->private3
;
506 count
= raw
[0] * 256 + raw
[1];
511 static dns_rdatasetmethods_t rdataset_methods
= {
512 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
;