Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / dns / a6.c
blob850cc4b075e2cc6dc3271b8590ae0f3d8be07621
1 /*
2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001 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: a6.c,v 1.20.2.1 2004/03/09 06:10:59 marka Exp $ */
20 #include <config.h>
22 #include <isc/util.h>
24 #include <dns/a6.h>
25 #include <dns/name.h>
26 #include <dns/rdata.h>
27 #include <dns/rdataset.h>
29 #define A6CONTEXT_MAGIC ISC_MAGIC('A', '6', 'X', 'X')
30 #define VALID_A6CONTEXT(ac) ISC_MAGIC_VALID(ac, A6CONTEXT_MAGIC)
32 #define MAX_CHAINS 8
33 #define MAX_DEPTH 16
35 static inline void
36 maybe_disassociate(dns_rdataset_t *rdataset) {
37 if (dns_rdataset_isassociated(rdataset))
38 dns_rdataset_disassociate(rdataset);
41 static isc_result_t
42 foreach(dns_a6context_t *a6ctx, dns_rdataset_t *parent, unsigned int depth,
43 unsigned int oprefixlen)
45 dns_rdata_t rdata = DNS_RDATA_INIT;
46 isc_region_t r;
47 dns_name_t name;
48 dns_rdataset_t child;
49 dns_rdataset_t childsig;
50 isc_result_t result;
51 isc_uint8_t prefixlen, octets;
52 isc_bitstring_t bitstring;
53 isc_stdtime_t expiration;
55 expiration = a6ctx->now + parent->ttl;
56 if (expiration < a6ctx->expiration || a6ctx->expiration == 0)
57 a6ctx->expiration = expiration;
59 depth++;
60 result = dns_rdataset_first(parent);
61 while (result == ISC_R_SUCCESS) {
62 dns_rdataset_current(parent, &rdata);
63 dns_rdata_toregion(&rdata, &r);
64 prefixlen = r.base[0];
65 if (prefixlen > oprefixlen) {
67 * Trying to go to a longer prefix is illegal.
69 goto next_a6;
71 if (prefixlen < 128) {
72 isc_bitstring_init(&bitstring, &r.base[1],
73 128 - prefixlen, 128 - prefixlen,
74 ISC_TRUE);
75 isc_bitstring_copy(&bitstring, 128 - oprefixlen,
76 &a6ctx->bitstring, 128 - oprefixlen,
77 oprefixlen - prefixlen);
79 octets = 16 - prefixlen / 8;
80 if (prefixlen != 0) {
81 if (depth < MAX_DEPTH) {
82 isc_region_consume(&r, octets + 1);
83 dns_name_init(&name, NULL);
84 dns_name_fromregion(&name, &r);
85 dns_rdataset_init(&child);
86 dns_rdataset_init(&childsig);
87 result = (a6ctx->find)(a6ctx->arg, &name,
88 dns_rdatatype_a6,
89 a6ctx->now,
90 &child, &childsig);
91 if (result == ISC_R_SUCCESS) {
93 * We've found a new A6 rrset.
95 if (a6ctx->rrset != NULL)
96 (a6ctx->rrset)(a6ctx->arg,
97 &name,
98 &child,
99 &childsig);
101 * Keep following the chain.
103 result = foreach(a6ctx, &child, depth,
104 prefixlen);
105 dns_rdataset_disassociate(&child);
106 maybe_disassociate(&childsig);
107 if (result != ISC_R_SUCCESS)
108 break;
109 } else if (result == ISC_R_NOTFOUND &&
110 a6ctx->missing != NULL) {
112 * We can't follow this chain, because
113 * we don't know the next link.
115 * We update the 'depth' and
116 * 'prefixlen' values so that the
117 * missing function can make a copy
118 * of the a6context and resume
119 * processing after it has found the
120 * missing a6 context.
122 a6ctx->depth = depth;
123 a6ctx->prefixlen = prefixlen;
124 (a6ctx->missing)(a6ctx, &name);
125 } else {
127 * Either something went wrong, or
128 * we got a negative cache response.
129 * In either case, we can't follow
130 * this chain further, and we don't
131 * want to call the 'missing'
132 * function.
134 * Note that we currently require that
135 * the target of an A6 record is
136 * a canonical domain name. If the
137 * find routine returns DNS_R_CNAME or
138 * DNS_R_DNAME, we do NOT follow the
139 * chain.
141 * We do want to clean up...
143 maybe_disassociate(&child);
144 maybe_disassociate(&childsig);
147 } else {
149 * We have a complete chain.
151 if (a6ctx->address != NULL)
152 (a6ctx->address)(a6ctx);
154 next_a6:
155 dns_rdata_reset(&rdata);
156 result = dns_rdataset_next(parent);
157 if (result == ISC_R_SUCCESS) {
158 a6ctx->chains++;
159 if (a6ctx->chains > MAX_CHAINS)
160 return (ISC_R_QUOTA);
163 if (result != ISC_R_NOMORE)
164 return (result);
165 return (ISC_R_SUCCESS);
168 void
169 dns_a6_init(dns_a6context_t *a6ctx, dns_findfunc_t find, dns_rrsetfunc_t rrset,
170 dns_in6addrfunc_t address, dns_a6missingfunc_t missing, void *arg)
172 REQUIRE(a6ctx != NULL);
173 REQUIRE(find != NULL);
175 a6ctx->magic = A6CONTEXT_MAGIC;
176 a6ctx->find = find;
177 a6ctx->rrset = rrset;
178 a6ctx->missing = missing;
179 a6ctx->address = address;
180 a6ctx->arg = arg;
181 a6ctx->chains = 1;
182 a6ctx->depth = 0;
183 a6ctx->now = 0;
184 a6ctx->expiration = 0;
185 a6ctx->prefixlen = 128;
186 isc_bitstring_init(&a6ctx->bitstring,
187 (unsigned char *)a6ctx->in6addr.s6_addr,
188 128, 128, ISC_TRUE);
191 void
192 dns_a6_reset(dns_a6context_t *a6ctx) {
193 REQUIRE(VALID_A6CONTEXT(a6ctx));
195 a6ctx->chains = 1;
196 a6ctx->depth = 0;
197 a6ctx->expiration = 0;
198 a6ctx->prefixlen = 128;
201 void
202 dns_a6_invalidate(dns_a6context_t *a6ctx) {
203 REQUIRE(VALID_A6CONTEXT(a6ctx));
205 a6ctx->magic = 0;
208 void
209 dns_a6_copy(dns_a6context_t *source, dns_a6context_t *target) {
210 REQUIRE(VALID_A6CONTEXT(source));
211 REQUIRE(VALID_A6CONTEXT(target));
213 *target = *source;
214 isc_bitstring_init(&target->bitstring,
215 (unsigned char *)target->in6addr.s6_addr,
216 128, 128, ISC_TRUE);
219 isc_result_t
220 dns_a6_foreach(dns_a6context_t *a6ctx, dns_rdataset_t *rdataset,
221 isc_stdtime_t now)
223 isc_result_t result;
225 REQUIRE(VALID_A6CONTEXT(a6ctx));
226 REQUIRE(rdataset->type == dns_rdatatype_a6);
228 if (now == 0)
229 isc_stdtime_get(&now);
230 a6ctx->now = now;
232 result = foreach(a6ctx, rdataset, a6ctx->depth, a6ctx->prefixlen);
233 if (result == ISC_R_QUOTA)
234 result = ISC_R_SUCCESS;
236 return (result);