Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / dns / ncache.c
blob4809aa92e2cbd639ea6ce64e724b983f62e7a5b5
1 /* $NetBSD$ */
3 /*
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 */
22 /*! \file */
24 #include <config.h>
26 #include <isc/buffer.h>
27 #include <isc/util.h>
29 #include <dns/db.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:
43 * owner name
44 * type
45 * rdata count
46 * rdata length These two occur 'rdata count'
47 * rdata times.
51 static inline isc_result_t
52 copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) {
53 isc_result_t result;
54 unsigned int count;
55 isc_region_t ar, r;
56 dns_rdata_t rdata = DNS_RDATA_INIT;
59 * Copy the rdataset count to the buffer.
61 isc_buffer_availableregion(buffer, &ar);
62 if (ar.length < 2)
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);
74 if (ar.length < 2)
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)
85 return (result);
86 dns_rdata_reset(&rdata);
87 result = dns_rdataset_next(rdataset);
89 if (result != ISC_R_NOMORE)
90 return (result);
92 return (ISC_R_SUCCESS);
95 isc_result_t
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));
104 isc_result_t
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)
110 isc_result_t result;
111 isc_buffer_t buffer;
112 isc_region_t r;
113 dns_rdataset_t *rdataset;
114 dns_rdatatype_t type;
115 dns_name_t *name;
116 dns_ttl_t ttl;
117 dns_trust_t trust;
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.
149 ttl = maxttl;
150 trust = 0xffff;
151 isc_buffer_init(&buffer, data, sizeof(data));
152 if (message->counts[DNS_SECTION_AUTHORITY])
153 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
154 else
155 result = ISC_R_NOMORE;
156 while (result == ISC_R_SUCCESS) {
157 name = NULL;
158 dns_message_currentname(message, DNS_SECTION_AUTHORITY,
159 &name);
160 if ((name->attributes & DNS_NAMEATTR_NCACHE) != 0) {
161 for (rdataset = ISC_LIST_HEAD(name->list);
162 rdataset != NULL;
163 rdataset = ISC_LIST_NEXT(rdataset, link)) {
164 if ((rdataset->attributes &
165 DNS_RDATASETATTR_NCACHE) == 0)
166 continue;
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)
174 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,
182 &r);
183 if (result != ISC_R_SUCCESS)
184 return (result);
186 * Copy the type to the buffer.
188 isc_buffer_availableregion(&buffer,
189 &r);
190 if (r.length < 2)
191 return (ISC_R_NOSPACE);
192 isc_buffer_putuint16(&buffer,
193 rdataset->type);
195 * Copy the rdataset into the buffer.
197 result = copy_rdataset(rdataset,
198 &buffer);
199 if (result != ISC_R_SUCCESS)
200 return (result);
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 =
209 ncrdatalist.rdclass;
210 rdata[next].type = 0;
211 rdata[next].flags = 0;
212 ISC_LIST_APPEND(ncrdatalist.rdata,
213 &rdata[next], link);
214 isc_buffer_forward(&buffer, r.length);
215 next++;
219 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY);
221 if (result != ISC_R_NOMORE)
222 return (result);
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
235 * wire format.
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)
245 return (result);
247 * Copy the type and a zero rdata count to the buffer.
249 isc_buffer_availableregion(&buffer, &r);
250 if (r.length < 4)
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.
258 ttl = 0;
260 * Set trust.
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;
269 } else
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)
292 == ISC_R_SUCCESS);
293 ncrdataset.trust = trust;
294 if (message->rcode == dns_rcode_nxdomain)
295 ncrdataset.attributes |= DNS_RDATASETATTR_NXDOMAIN;
296 if (optout)
297 ncrdataset.attributes |= DNS_RDATASETATTR_OPTOUT;
299 return (dns_db_addrdataset(cache, node, NULL, now, &ncrdataset,
300 0, addedrdataset));
303 isc_result_t
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;
309 isc_result_t result;
310 isc_region_t remaining, tavailable;
311 isc_buffer_t source, savedbuffer, rdlen;
312 dns_name_t name;
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
319 * 'target'.
322 REQUIRE(rdataset != NULL);
323 REQUIRE(rdataset->type == 0);
325 savedbuffer = *target;
326 count = 0;
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;
355 rdata.type = type;
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))
362 continue;
365 * Write the name.
367 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
368 result = dns_name_towire(&name, cctx, target);
369 if (result != ISC_R_SUCCESS)
370 goto rollback;
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;
379 goto rollback;
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.
388 rdlen = *target;
389 isc_buffer_add(target, 2);
392 * Write the rdata.
394 result = dns_rdata_towire(&rdata, cctx, target);
395 if (result != ISC_R_SUCCESS)
396 goto rollback;
399 * Set the rdata length field to the compressed
400 * length.
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 -
406 rdlen.used - 2));
408 count++;
410 INSIST(isc_buffer_remaininglength(&source) == 0);
411 result = dns_rdataset_next(rdataset);
412 dns_rdata_reset(&rdata);
414 if (result != ISC_R_NOMORE)
415 goto rollback;
417 *countp = count;
419 return (ISC_R_SUCCESS);
421 rollback:
422 INSIST(savedbuffer.used < 65536);
423 dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
424 *countp = 0;
425 *target = savedbuffer;
427 return (result);
430 static void
431 rdataset_disassociate(dns_rdataset_t *rdataset) {
432 UNUSED(rdataset);
435 static isc_result_t
436 rdataset_first(dns_rdataset_t *rdataset) {
437 unsigned char *raw = rdataset->private3;
438 unsigned int count;
440 count = raw[0] * 256 + raw[1];
441 if (count == 0) {
442 rdataset->private5 = NULL;
443 return (ISC_R_NOMORE);
445 raw += 2;
447 * The privateuint4 field is the number of rdata beyond the cursor
448 * position, so we decrement the total count by one before storing
449 * it.
451 count--;
452 rdataset->privateuint4 = count;
453 rdataset->private5 = raw;
455 return (ISC_R_SUCCESS);
458 static isc_result_t
459 rdataset_next(dns_rdataset_t *rdataset) {
460 unsigned int count;
461 unsigned int length;
462 unsigned char *raw;
464 count = rdataset->privateuint4;
465 if (count == 0)
466 return (ISC_R_NOMORE);
467 count--;
468 rdataset->privateuint4 = count;
469 raw = rdataset->private5;
470 length = raw[0] * 256 + raw[1];
471 raw += length + 2;
472 rdataset->private5 = raw;
474 return (ISC_R_SUCCESS);
477 static void
478 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
479 unsigned char *raw = rdataset->private5;
480 isc_region_t r;
482 REQUIRE(raw != NULL);
484 r.length = raw[0] * 256 + raw[1];
485 raw += 2;
486 r.base = raw;
487 dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
490 static void
491 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
492 *target = *source;
495 * Reset iterator state.
497 target->privateuint4 = 0;
498 target->private5 = NULL;
501 static unsigned int
502 rdataset_count(dns_rdataset_t *rdataset) {
503 unsigned char *raw = rdataset->private3;
504 unsigned int count;
506 count = raw[0] * 256 + raw[1];
508 return (count);
511 static dns_rdatasetmethods_t rdataset_methods = {
512 rdataset_disassociate,
513 rdataset_first,
514 rdataset_next,
515 rdataset_current,
516 rdataset_clone,
517 rdataset_count,
518 NULL,
519 NULL,
520 NULL,
521 NULL,
522 NULL,
523 NULL,
524 NULL
527 isc_result_t
528 dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
529 dns_rdatatype_t type, dns_rdataset_t *rdataset)
531 isc_result_t result;
532 dns_rdata_t rdata = DNS_RDATA_INIT;
533 isc_region_t remaining;
534 isc_buffer_t source;
535 dns_name_t tname;
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);
561 break;
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)
569 return (result);
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);
593 void
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;
599 isc_buffer_t source;
600 dns_name_t tname;
601 dns_rdatatype_t type;
602 unsigned int count;
603 dns_rdata_rrsig_t rrsig;
604 unsigned char *raw;
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];
635 INSIST(count > 0);
636 raw += 2;
637 sigregion.length = raw[0] * 256 + raw[1];
638 raw += 2;
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;
645 } else
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;