Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / dns / ncache.c
blobc9e0a49e8ff778804b5b3ff920456818226d6553
1 /*
2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.24.2.6 2004/03/09 06:11:04 marka Exp $ */
20 #include <config.h>
22 #include <isc/buffer.h>
23 #include <isc/util.h>
25 #include <dns/db.h>
26 #include <dns/message.h>
27 #include <dns/ncache.h>
28 #include <dns/rdata.h>
29 #include <dns/rdatalist.h>
30 #include <dns/rdataset.h>
33 * The format of an ncache rdata is a sequence of one or more records of
34 * the following format:
36 * owner name
37 * type
38 * rdata count
39 * rdata length These two occur 'rdata count'
40 * rdata times.
44 static inline isc_result_t
45 copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
46 isc_result_t result;
47 unsigned int count;
48 isc_region_t ar, r;
49 dns_rdata_t rdata = DNS_RDATA_INIT;
52 * Copy the rdataset count to the buffer.
54 isc_buffer_availableregion(buffer, &ar);
55 if (ar.length < 2)
56 return (ISC_R_NOSPACE);
57 count = dns_rdataset_count(rdataset);
58 INSIST(count <= 65535);
59 isc_buffer_putuint16(buffer, (isc_uint16_t)count);
61 result = dns_rdataset_first(rdataset);
62 while (result == ISC_R_SUCCESS) {
63 dns_rdataset_current(rdataset, &rdata);
64 dns_rdata_toregion(&rdata, &r);
65 INSIST(r.length <= 65535);
66 isc_buffer_availableregion(buffer, &ar);
67 if (ar.length < 2)
68 return (ISC_R_NOSPACE);
70 * Copy the rdata length to the buffer.
72 isc_buffer_putuint16(buffer, (isc_uint16_t)r.length);
74 * Copy the rdata to the buffer.
76 result = isc_buffer_copyregion(buffer, &r);
77 if (result != ISC_R_SUCCESS)
78 return (result);
79 dns_rdata_reset(&rdata);
80 result = dns_rdataset_next(rdataset);
82 if (result != ISC_R_NOMORE)
83 return (result);
85 return (ISC_R_SUCCESS);
88 isc_result_t
89 dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
90 dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
91 dns_rdataset_t *addedrdataset)
93 isc_result_t result;
94 isc_buffer_t buffer;
95 isc_region_t r;
96 dns_rdataset_t *rdataset;
97 dns_rdatatype_t type;
98 dns_name_t *name;
99 dns_ttl_t ttl;
100 dns_trust_t trust;
101 dns_rdata_t rdata = DNS_RDATA_INIT;
102 dns_rdataset_t ncrdataset;
103 dns_rdatalist_t ncrdatalist;
104 unsigned char data[4096];
107 * Convert the authority data from 'message' into a negative cache
108 * rdataset, and store it in 'cache' at 'node'.
111 REQUIRE(message != NULL);
114 * We assume that all data in the authority section has been
115 * validated by the caller.
119 * First, build an ncache rdata in buffer.
121 ttl = maxttl;
122 trust = 0xffff;
123 isc_buffer_init(&buffer, data, sizeof(data));
124 if (message->counts[DNS_SECTION_AUTHORITY])
125 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
126 else
127 result = ISC_R_NOMORE;
128 while (result == ISC_R_SUCCESS) {
129 name = NULL;
130 dns_message_currentname(message, DNS_SECTION_AUTHORITY,
131 &name);
132 if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
133 for (rdataset = ISC_LIST_HEAD(name->list);
134 rdataset != NULL;
135 rdataset = ISC_LIST_NEXT(rdataset, link)) {
136 if ((rdataset->attributes &
137 DNS_RDATASETATTR_NCACHE) == 0)
138 continue;
139 type = rdataset->type;
140 if (type == dns_rdatatype_sig)
141 type = rdataset->covers;
142 if (type == dns_rdatatype_soa ||
143 type == dns_rdatatype_nxt) {
144 if (ttl > rdataset->ttl)
145 ttl = rdataset->ttl;
146 if (trust > rdataset->trust)
147 trust = rdataset->trust;
149 * Copy the owner name to the buffer.
151 dns_name_toregion(name, &r);
152 result = isc_buffer_copyregion(&buffer,
153 &r);
154 if (result != ISC_R_SUCCESS)
155 return (result);
157 * Copy the type to the buffer.
159 isc_buffer_availableregion(&buffer,
160 &r);
161 if (r.length < 2)
162 return (ISC_R_NOSPACE);
163 isc_buffer_putuint16(&buffer,
164 rdataset->type);
166 * Copy the rdataset into the buffer.
168 result = copy_rdataset(rdataset,
169 &buffer);
170 if (result != ISC_R_SUCCESS)
171 return (result);
175 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
177 if (result != ISC_R_NOMORE)
178 return (result);
180 if (trust == 0xffff) {
182 * We didn't find any authority data from which to create a
183 * negative cache rdataset. In particular, we have no SOA.
185 * We trust that the caller wants negative caching, so this
186 * means we have a "type 3 nxdomain" or "type 3 nodata"
187 * response (see RFC 2308 for details).
189 * We will now build a suitable negative cache rdataset that
190 * will cause zero bytes to be emitted when converted to
191 * wire format.
195 * The ownername must exist, but it doesn't matter what value
196 * it has. We use the root name.
198 dns_name_toregion(dns_rootname, &r);
199 result = isc_buffer_copyregion(&buffer, &r);
200 if (result != ISC_R_SUCCESS)
201 return (result);
203 * Copy the type and a zero rdata count to the buffer.
205 isc_buffer_availableregion(&buffer, &r);
206 if (r.length < 4)
207 return (ISC_R_NOSPACE);
208 isc_buffer_putuint16(&buffer, 0);
209 isc_buffer_putuint16(&buffer, 0);
211 * RFC 2308, section 5, says that negative answers without
212 * SOAs should not be cached.
214 ttl = 0;
216 * Set trust.
218 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
219 message->counts[DNS_SECTION_ANSWER] == 0) {
221 * The response has aa set and we haven't followed
222 * any CNAME or DNAME chains.
224 trust = dns_trust_authauthority;
225 } else
226 trust = dns_trust_additional;
230 * Now add it to the cache.
232 INSIST(trust != 0xffff);
233 isc_buffer_usedregion(&buffer, &r);
234 rdata.data = r.base;
235 rdata.length = r.length;
236 rdata.rdclass = dns_db_class(cache);
237 rdata.type = 0;
238 rdata.flags = 0;
240 ncrdatalist.rdclass = rdata.rdclass;
241 ncrdatalist.type = 0;
242 ncrdatalist.covers = covers;
243 ncrdatalist.ttl = ttl;
244 ISC_LIST_INIT(ncrdatalist.rdata);
245 ISC_LINK_INIT(&ncrdatalist, link);
247 ISC_LIST_APPEND(ncrdatalist.rdata, &rdata, link);
249 dns_rdataset_init(&ncrdataset);
250 dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset);
251 ncrdataset.trust = trust;
252 if (message->rcode == dns_rcode_nxdomain)
253 ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
255 return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
256 0, addedrdataset));
259 isc_result_t
260 dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
261 isc_buffer_t *target, unsigned int *countp)
263 dns_rdata_t rdata = DNS_RDATA_INIT;
264 isc_result_t result;
265 isc_region_t remaining, tavailable;
266 isc_buffer_t source, savedbuffer, rdlen;
267 dns_name_t name;
268 dns_rdatatype_t type;
269 unsigned int i, rcount, count;
272 * Convert the negative caching rdataset 'rdataset' to wire format,
273 * compressing names as specified in 'cctx', and storing the result in
274 * 'target'.
277 REQUIRE(rdataset != NULL);
278 REQUIRE(rdataset->type == 0);
280 result = dns_rdataset_first(rdataset);
281 if (result != ISC_R_SUCCESS)
282 return (result);
283 dns_rdataset_current(rdataset, &rdata);
284 INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
285 isc_buffer_init(&source, rdata.data, rdata.length);
286 isc_buffer_add(&source, rdata.length);
288 savedbuffer = *target;
290 count = 0;
291 do {
292 dns_name_init(&name, NULL);
293 isc_buffer_remainingregion(&source, &remaining);
294 dns_name_fromregion(&name, &remaining);
295 INSIST(remaining.length >= name.length);
296 isc_buffer_forward(&source, name.length);
297 remaining.length -= name.length;
299 INSIST(remaining.length >= 4);
300 type = isc_buffer_getuint16(&source);
301 rcount = isc_buffer_getuint16(&source);
303 for (i = 0; i < rcount; i++) {
305 * Get the length of this rdata and set up an
306 * rdata structure for it.
308 isc_buffer_remainingregion(&source, &remaining);
309 INSIST(remaining.length >= 2);
310 dns_rdata_reset(&rdata);
311 rdata.length = isc_buffer_getuint16(&source);
312 isc_buffer_remainingregion(&source, &remaining);
313 rdata.data = remaining.base;
314 rdata.type = type;
315 rdata.rdclass = rdataset->rdclass;
316 INSIST(remaining.length >= rdata.length);
317 isc_buffer_forward(&source, rdata.length);
320 * Write the name.
322 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
323 result = dns_name_towire(&name, cctx, target);
324 if (result != ISC_R_SUCCESS)
325 goto rollback;
328 * See if we have space for type, class, ttl, and
329 * rdata length. Write the type, class, and ttl.
331 isc_buffer_availableregion(target, &tavailable);
332 if (tavailable.length < 10) {
333 result = ISC_R_NOSPACE;
334 goto rollback;
336 isc_buffer_putuint16(target, type);
337 isc_buffer_putuint16(target, rdataset->rdclass);
338 isc_buffer_putuint32(target, rdataset->ttl);
341 * Save space for rdata length.
343 rdlen = *target;
344 isc_buffer_add(target, 2);
347 * Write the rdata.
349 result = dns_rdata_towire(&rdata, cctx, target);
350 if (result != ISC_R_SUCCESS)
351 goto rollback;
354 * Set the rdata length field to the compressed
355 * length.
357 INSIST((target->used >= rdlen.used + 2) &&
358 (target->used - rdlen.used - 2 < 65536));
359 isc_buffer_putuint16(&rdlen,
360 (isc_uint16_t)(target->used -
361 rdlen.used - 2));
363 count++;
365 isc_buffer_remainingregion(&source, &remaining);
366 } while (remaining.length > 0);
368 *countp = count;
370 return (ISC_R_SUCCESS);
372 rollback:
373 INSIST(savedbuffer.used < 65536);
374 dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
375 *countp = 0;
376 *target = savedbuffer;
378 return (result);