BIND: update vendor tree to 9.5.2-P2
[dragonfly.git] / contrib / bind / lib / dns / ncache.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
4 *
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.
8 *
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.
16 */
17
18/* $Id: ncache.c,v 1.41 2007/06/19 23:47:16 tbox Exp $ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <isc/buffer.h>
25#include <isc/util.h>
26
27#include <dns/db.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
34/*
35 * The format of an ncache rdata is a sequence of one or more records of
36 * the following format:
37 *
38 * owner name
39 * type
40 * rdata count
41 * rdata length These two occur 'rdata count'
42 * rdata times.
43 *
44 */
45
46static inline isc_result_t
47copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
48 isc_result_t result;
49 unsigned int count;
50 isc_region_t ar, r;
51 dns_rdata_t rdata = DNS_RDATA_INIT;
52
53 /*
54 * Copy the rdataset count to the buffer.
55 */
56 isc_buffer_availableregion(buffer, &ar);
57 if (ar.length < 2)
58 return (ISC_R_NOSPACE);
59 count = dns_rdataset_count(rdataset);
60 INSIST(count <= 65535);
61 isc_buffer_putuint16(buffer, (isc_uint16_t)count);
62
63 result = dns_rdataset_first(rdataset);
64 while (result == ISC_R_SUCCESS) {
65 dns_rdataset_current(rdataset, &rdata);
66 dns_rdata_toregion(&rdata, &r);
67 INSIST(r.length <= 65535);
68 isc_buffer_availableregion(buffer, &ar);
69 if (ar.length < 2)
70 return (ISC_R_NOSPACE);
71 /*
72 * Copy the rdata length to the buffer.
73 */
74 isc_buffer_putuint16(buffer, (isc_uint16_t)r.length);
75 /*
76 * Copy the rdata to the buffer.
77 */
78 result = isc_buffer_copyregion(buffer, &r);
79 if (result != ISC_R_SUCCESS)
80 return (result);
81 dns_rdata_reset(&rdata);
82 result = dns_rdataset_next(rdataset);
83 }
84 if (result != ISC_R_NOMORE)
85 return (result);
86
87 return (ISC_R_SUCCESS);
88}
89
90isc_result_t
91dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node,
92 dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl,
93 dns_rdataset_t *addedrdataset)
94{
95 isc_result_t result;
96 isc_buffer_t buffer;
97 isc_region_t r;
98 dns_rdataset_t *rdataset;
99 dns_rdatatype_t type;
100 dns_name_t *name;
101 dns_ttl_t ttl;
102 dns_trust_t trust;
103 dns_rdata_t rdata = DNS_RDATA_INIT;
104 dns_rdataset_t ncrdataset;
105 dns_rdatalist_t ncrdatalist;
106 unsigned char data[4096];
107
108 /*
109 * Convert the authority data from 'message' into a negative cache
110 * rdataset, and store it in 'cache' at 'node'.
111 */
112
113 REQUIRE(message != NULL);
114
115 /*
116 * We assume that all data in the authority section has been
117 * validated by the caller.
118 */
119
120 /*
121 * First, build an ncache rdata in buffer.
122 */
123 ttl = maxttl;
124 trust = 0xffff;
125 isc_buffer_init(&buffer, data, sizeof(data));
126 if (message->counts[DNS_SECTION_AUTHORITY])
127 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
128 else
129 result = ISC_R_NOMORE;
130 while (result == ISC_R_SUCCESS) {
131 name = NULL;
132 dns_message_currentname(message, DNS_SECTION_AUTHORITY,
133 &name);
134 if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
135 for (rdataset = ISC_LIST_HEAD(name->list);
136 rdataset != NULL;
137 rdataset = ISC_LIST_NEXT(rdataset, link)) {
138 if ((rdataset->attributes &
139 DNS_RDATASETATTR_NCACHE) == 0)
140 continue;
141 type = rdataset->type;
142 if (type == dns_rdatatype_rrsig)
143 type = rdataset->covers;
144 if (type == dns_rdatatype_soa ||
145 type == dns_rdatatype_nsec) {
146 if (ttl > rdataset->ttl)
147 ttl = rdataset->ttl;
148 if (trust > rdataset->trust)
149 trust = rdataset->trust;
150 /*
151 * Copy the owner name to the buffer.
152 */
153 dns_name_toregion(name, &r);
154 result = isc_buffer_copyregion(&buffer,
155 &r);
156 if (result != ISC_R_SUCCESS)
157 return (result);
158 /*
159 * Copy the type to the buffer.
160 */
161 isc_buffer_availableregion(&buffer,
162 &r);
163 if (r.length < 2)
164 return (ISC_R_NOSPACE);
165 isc_buffer_putuint16(&buffer,
166 rdataset->type);
167 /*
168 * Copy the rdataset into the buffer.
169 */
170 result = copy_rdataset(rdataset,
171 &buffer);
172 if (result != ISC_R_SUCCESS)
173 return (result);
174 }
175 }
176 }
177 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
178 }
179 if (result != ISC_R_NOMORE)
180 return (result);
181
182 if (trust == 0xffff) {
183 /*
184 * We didn't find any authority data from which to create a
185 * negative cache rdataset. In particular, we have no SOA.
186 *
187 * We trust that the caller wants negative caching, so this
188 * means we have a "type 3 nxdomain" or "type 3 nodata"
189 * response (see RFC2308 for details).
190 *
191 * We will now build a suitable negative cache rdataset that
192 * will cause zero bytes to be emitted when converted to
193 * wire format.
194 */
195
196 /*
197 * The ownername must exist, but it doesn't matter what value
198 * it has. We use the root name.
199 */
200 dns_name_toregion(dns_rootname, &r);
201 result = isc_buffer_copyregion(&buffer, &r);
202 if (result != ISC_R_SUCCESS)
203 return (result);
204 /*
205 * Copy the type and a zero rdata count to the buffer.
206 */
207 isc_buffer_availableregion(&buffer, &r);
208 if (r.length < 4)
209 return (ISC_R_NOSPACE);
210 isc_buffer_putuint16(&buffer, 0);
211 isc_buffer_putuint16(&buffer, 0);
212 /*
213 * RFC2308, section 5, says that negative answers without
214 * SOAs should not be cached.
215 */
216 ttl = 0;
217 /*
218 * Set trust.
219 */
220 if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 &&
221 message->counts[DNS_SECTION_ANSWER] == 0) {
222 /*
223 * The response has aa set and we haven't followed
224 * any CNAME or DNAME chains.
225 */
226 trust = dns_trust_authauthority;
227 } else
228 trust = dns_trust_additional;
229 }
230
231 /*
232 * Now add it to the cache.
233 */
234 INSIST(trust != 0xffff);
235 isc_buffer_usedregion(&buffer, &r);
236 rdata.data = r.base;
237 rdata.length = r.length;
238 rdata.rdclass = dns_db_class(cache);
239 rdata.type = 0;
240 rdata.flags = 0;
241
242 ncrdatalist.rdclass = rdata.rdclass;
243 ncrdatalist.type = 0;
244 ncrdatalist.covers = covers;
245 ncrdatalist.ttl = ttl;
246 ISC_LIST_INIT(ncrdatalist.rdata);
247 ISC_LINK_INIT(&ncrdatalist, link);
248
249 ISC_LIST_APPEND(ncrdatalist.rdata, &rdata, link);
250
251 dns_rdataset_init(&ncrdataset);
252 RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
253 == ISC_R_SUCCESS);
254 ncrdataset.trust = trust;
255 if (message->rcode == dns_rcode_nxdomain)
256 ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
257
258 return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
259 0, addedrdataset));
260}
261
262isc_result_t
263dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
264 isc_buffer_t *target, unsigned int options,
265 unsigned int *countp)
266{
267 dns_rdata_t rdata = DNS_RDATA_INIT;
268 isc_result_t result;
269 isc_region_t remaining, tavailable;
270 isc_buffer_t source, savedbuffer, rdlen;
271 dns_name_t name;
272 dns_rdatatype_t type;
273 unsigned int i, rcount, count;
274
275 /*
276 * Convert the negative caching rdataset 'rdataset' to wire format,
277 * compressing names as specified in 'cctx', and storing the result in
278 * 'target'.
279 */
280
281 REQUIRE(rdataset != NULL);
282 REQUIRE(rdataset->type == 0);
283
284 result = dns_rdataset_first(rdataset);
285 if (result != ISC_R_SUCCESS)
286 return (result);
287 dns_rdataset_current(rdataset, &rdata);
288 INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
289 isc_buffer_init(&source, rdata.data, rdata.length);
290 isc_buffer_add(&source, rdata.length);
291
292 savedbuffer = *target;
293
294 count = 0;
295 do {
296 dns_name_init(&name, NULL);
297 isc_buffer_remainingregion(&source, &remaining);
298 dns_name_fromregion(&name, &remaining);
299 INSIST(remaining.length >= name.length);
300 isc_buffer_forward(&source, name.length);
301 remaining.length -= name.length;
302
303 INSIST(remaining.length >= 4);
304 type = isc_buffer_getuint16(&source);
305 rcount = isc_buffer_getuint16(&source);
306
307 for (i = 0; i < rcount; i++) {
308 /*
309 * Get the length of this rdata and set up an
310 * rdata structure for it.
311 */
312 isc_buffer_remainingregion(&source, &remaining);
313 INSIST(remaining.length >= 2);
314 dns_rdata_reset(&rdata);
315 rdata.length = isc_buffer_getuint16(&source);
316 isc_buffer_remainingregion(&source, &remaining);
317 rdata.data = remaining.base;
318 rdata.type = type;
319 rdata.rdclass = rdataset->rdclass;
320 INSIST(remaining.length >= rdata.length);
321 isc_buffer_forward(&source, rdata.length);
322
323 if ((options & DNS_NCACHETOWIRE_OMITDNSSEC) != 0 &&
324 dns_rdatatype_isdnssec(type))
325 continue;
326
327 /*
328 * Write the name.
329 */
330 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
331 result = dns_name_towire(&name, cctx, target);
332 if (result != ISC_R_SUCCESS)
333 goto rollback;
334
335 /*
336 * See if we have space for type, class, ttl, and
337 * rdata length. Write the type, class, and ttl.
338 */
339 isc_buffer_availableregion(target, &tavailable);
340 if (tavailable.length < 10) {
341 result = ISC_R_NOSPACE;
342 goto rollback;
343 }
344 isc_buffer_putuint16(target, type);
345 isc_buffer_putuint16(target, rdataset->rdclass);
346 isc_buffer_putuint32(target, rdataset->ttl);
347
348 /*
349 * Save space for rdata length.
350 */
351 rdlen = *target;
352 isc_buffer_add(target, 2);
353
354 /*
355 * Write the rdata.
356 */
357 result = dns_rdata_towire(&rdata, cctx, target);
358 if (result != ISC_R_SUCCESS)
359 goto rollback;
360
361 /*
362 * Set the rdata length field to the compressed
363 * length.
364 */
365 INSIST((target->used >= rdlen.used + 2) &&
366 (target->used - rdlen.used - 2 < 65536));
367 isc_buffer_putuint16(&rdlen,
368 (isc_uint16_t)(target->used -
369 rdlen.used - 2));
370
371 count++;
372 }
373 isc_buffer_remainingregion(&source, &remaining);
374 } while (remaining.length > 0);
375
376 *countp = count;
377
378 return (ISC_R_SUCCESS);
379
380 rollback:
381 INSIST(savedbuffer.used < 65536);
382 dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
383 *countp = 0;
384 *target = savedbuffer;
385
386 return (result);
387}
388
389static void
390rdataset_disassociate(dns_rdataset_t *rdataset) {
391 UNUSED(rdataset);
392}
393
394static isc_result_t
395rdataset_first(dns_rdataset_t *rdataset) {
396 unsigned char *raw = rdataset->private3;
397 unsigned int count;
398
399 count = raw[0] * 256 + raw[1];
400 if (count == 0) {
401 rdataset->private5 = NULL;
402 return (ISC_R_NOMORE);
403 }
404 raw += 2;
405 /*
406 * The privateuint4 field is the number of rdata beyond the cursor
407 * position, so we decrement the total count by one before storing
408 * it.
409 */
410 count--;
411 rdataset->privateuint4 = count;
412 rdataset->private5 = raw;
413
414 return (ISC_R_SUCCESS);
415}
416
417static isc_result_t
418rdataset_next(dns_rdataset_t *rdataset) {
419 unsigned int count;
420 unsigned int length;
421 unsigned char *raw;
422
423 count = rdataset->privateuint4;
424 if (count == 0)
425 return (ISC_R_NOMORE);
426 count--;
427 rdataset->privateuint4 = count;
428 raw = rdataset->private5;
429 length = raw[0] * 256 + raw[1];
430 raw += length + 2;
431 rdataset->private5 = raw;
432
433 return (ISC_R_SUCCESS);
434}
435
436static void
437rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
438 unsigned char *raw = rdataset->private5;
439 isc_region_t r;
440
441 REQUIRE(raw != NULL);
442
443 r.length = raw[0] * 256 + raw[1];
444 raw += 2;
445 r.base = raw;
446 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
447}
448
449static void
450rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
451 *target = *source;
452
453 /*
454 * Reset iterator state.
455 */
456 target->privateuint4 = 0;
457 target->private5 = NULL;
458}
459
460static unsigned int
461rdataset_count(dns_rdataset_t *rdataset) {
462 unsigned char *raw = rdataset->private3;
463 unsigned int count;
464
465 count = raw[0] * 256 + raw[1];
466
467 return (count);
468}
469
470static dns_rdatasetmethods_t rdataset_methods = {
471 rdataset_disassociate,
472 rdataset_first,
473 rdataset_next,
474 rdataset_current,
475 rdataset_clone,
476 rdataset_count,
477 NULL,
478 NULL,
479 NULL,
480 NULL,
481 NULL
482};
483
484isc_result_t
485dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
486 dns_rdatatype_t type, dns_rdataset_t *rdataset)
487{
488 isc_result_t result;
489 dns_rdata_t rdata = DNS_RDATA_INIT;
490 isc_region_t remaining;
491 isc_buffer_t source;
492 dns_name_t tname;
493 dns_rdatatype_t ttype;
494 unsigned int i, rcount;
495 isc_uint16_t length;
496
497 REQUIRE(ncacherdataset != NULL);
498 REQUIRE(ncacherdataset->type == 0);
499 REQUIRE(name != NULL);
500 REQUIRE(!dns_rdataset_isassociated(rdataset));
501 REQUIRE(type != dns_rdatatype_rrsig);
502
503 result = dns_rdataset_first(ncacherdataset);
504 if (result != ISC_R_SUCCESS)
505 return (result);
506 dns_rdataset_current(ncacherdataset, &rdata);
507 INSIST(dns_rdataset_next(ncacherdataset) == ISC_R_NOMORE);
508 isc_buffer_init(&source, rdata.data, rdata.length);
509 isc_buffer_add(&source, rdata.length);
510
511 do {
512 dns_name_init(&tname, NULL);
513 isc_buffer_remainingregion(&source, &remaining);
514 dns_name_fromregion(&tname, &remaining);
515 INSIST(remaining.length >= tname.length);
516 isc_buffer_forward(&source, tname.length);
517 remaining.length -= tname.length;
518
519 INSIST(remaining.length >= 4);
520 ttype = isc_buffer_getuint16(&source);
521
522 if (ttype == type && dns_name_equal(&tname, name)) {
523 isc_buffer_remainingregion(&source, &remaining);
524 break;
525 }
526
527 rcount = isc_buffer_getuint16(&source);
528 for (i = 0; i < rcount; i++) {
529 isc_buffer_remainingregion(&source, &remaining);
530 INSIST(remaining.length >= 2);
531 length = isc_buffer_getuint16(&source);
532 isc_buffer_remainingregion(&source, &remaining);
533 INSIST(remaining.length >= length);
534 isc_buffer_forward(&source, length);
535 }
536 isc_buffer_remainingregion(&source, &remaining);
537 } while (remaining.length > 0);
538
539 if (remaining.length == 0)
540 return (ISC_R_NOTFOUND);
541
542 rdataset->methods = &rdataset_methods;
543 rdataset->rdclass = ncacherdataset->rdclass;
544 rdataset->type = type;
545 rdataset->covers = 0;
546 rdataset->ttl = ncacherdataset->ttl;
547 rdataset->trust = ncacherdataset->trust;
548 rdataset->private1 = NULL;
549 rdataset->private2 = NULL;
550
551 rdataset->private3 = remaining.base;
552
553 /*
554 * Reset iterator state.
555 */
556 rdataset->privateuint4 = 0;
557 rdataset->private5 = NULL;
558 return (ISC_R_SUCCESS);
559}