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 $ */
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)
36 maybe_disassociate(dns_rdataset_t
*rdataset
) {
37 if (dns_rdataset_isassociated(rdataset
))
38 dns_rdataset_disassociate(rdataset
);
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
;
49 dns_rdataset_t childsig
;
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
;
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.
71 if (prefixlen
< 128) {
72 isc_bitstring_init(&bitstring
, &r
.base
[1],
73 128 - prefixlen
, 128 - prefixlen
,
75 isc_bitstring_copy(&bitstring
, 128 - oprefixlen
,
76 &a6ctx
->bitstring
, 128 - oprefixlen
,
77 oprefixlen
- prefixlen
);
79 octets
= 16 - prefixlen
/ 8;
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
,
91 if (result
== ISC_R_SUCCESS
) {
93 * We've found a new A6 rrset.
95 if (a6ctx
->rrset
!= NULL
)
96 (a6ctx
->rrset
)(a6ctx
->arg
,
101 * Keep following the chain.
103 result
= foreach(a6ctx
, &child
, depth
,
105 dns_rdataset_disassociate(&child
);
106 maybe_disassociate(&childsig
);
107 if (result
!= ISC_R_SUCCESS
)
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
);
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'
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
141 * We do want to clean up...
143 maybe_disassociate(&child
);
144 maybe_disassociate(&childsig
);
149 * We have a complete chain.
151 if (a6ctx
->address
!= NULL
)
152 (a6ctx
->address
)(a6ctx
);
155 dns_rdata_reset(&rdata
);
156 result
= dns_rdataset_next(parent
);
157 if (result
== ISC_R_SUCCESS
) {
159 if (a6ctx
->chains
> MAX_CHAINS
)
160 return (ISC_R_QUOTA
);
163 if (result
!= ISC_R_NOMORE
)
165 return (ISC_R_SUCCESS
);
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
;
177 a6ctx
->rrset
= rrset
;
178 a6ctx
->missing
= missing
;
179 a6ctx
->address
= address
;
184 a6ctx
->expiration
= 0;
185 a6ctx
->prefixlen
= 128;
186 isc_bitstring_init(&a6ctx
->bitstring
,
187 (unsigned char *)a6ctx
->in6addr
.s6_addr
,
192 dns_a6_reset(dns_a6context_t
*a6ctx
) {
193 REQUIRE(VALID_A6CONTEXT(a6ctx
));
197 a6ctx
->expiration
= 0;
198 a6ctx
->prefixlen
= 128;
202 dns_a6_invalidate(dns_a6context_t
*a6ctx
) {
203 REQUIRE(VALID_A6CONTEXT(a6ctx
));
209 dns_a6_copy(dns_a6context_t
*source
, dns_a6context_t
*target
) {
210 REQUIRE(VALID_A6CONTEXT(source
));
211 REQUIRE(VALID_A6CONTEXT(target
));
214 isc_bitstring_init(&target
->bitstring
,
215 (unsigned char *)target
->in6addr
.s6_addr
,
220 dns_a6_foreach(dns_a6context_t
*a6ctx
, dns_rdataset_t
*rdataset
,
225 REQUIRE(VALID_A6CONTEXT(a6ctx
));
226 REQUIRE(rdataset
->type
== dns_rdatatype_a6
);
229 isc_stdtime_get(&now
);
232 result
= foreach(a6ctx
, rdataset
, a6ctx
->depth
, a6ctx
->prefixlen
);
233 if (result
== ISC_R_QUOTA
)
234 result
= ISC_R_SUCCESS
;