]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/lib/dns/dns64.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / lib / dns / dns64.c
1 /*
2  * Copyright (C) 2010-2012  Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 /* $Id$ */
18
19 #include <config.h>
20
21 #include <isc/list.h>
22 #include <isc/mem.h>
23 #include <isc/netaddr.h>
24 #include <isc/string.h>
25 #include <isc/util.h>
26
27 #include <dns/acl.h>
28 #include <dns/dns64.h>
29 #include <dns/rdata.h>
30 #include <dns/rdataset.h>
31 #include <dns/result.h>
32
33 struct dns_dns64 {
34         unsigned char           bits[16];       /*
35                                                  * Prefix + suffix bits.
36                                                  */
37         dns_acl_t *             clients;        /*
38                                                  * Which clients get mapped
39                                                  * addresses.
40                                                  */
41         dns_acl_t *             mapped;         /*
42                                                  * IPv4 addresses to be mapped.
43                                                  */
44         dns_acl_t *             excluded;       /*
45                                                  * IPv6 addresses that are
46                                                  * treated as not existing.
47                                                  */
48         unsigned int            prefixlen;      /*
49                                                  * Start of mapped address.
50                                                  */
51         unsigned int            flags;
52         isc_mem_t *             mctx;
53         ISC_LINK(dns_dns64_t)   link;
54 };
55
56 isc_result_t
57 dns_dns64_create(isc_mem_t *mctx, isc_netaddr_t *prefix,
58                  unsigned int prefixlen, isc_netaddr_t *suffix,
59                  dns_acl_t *clients, dns_acl_t *mapped, dns_acl_t *excluded,
60                  unsigned int flags, dns_dns64_t **dns64)
61 {
62         dns_dns64_t *new;
63         unsigned int nbytes = 16;
64
65         REQUIRE(prefix != NULL && prefix->family == AF_INET6);
66         /* Legal prefix lengths from draft-ietf-behave-address-format-04. */
67         REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
68                 prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
69         REQUIRE(isc_netaddr_prefixok(prefix, prefixlen) == ISC_R_SUCCESS);
70         REQUIRE(dns64 != NULL && *dns64 == NULL);
71
72         if (suffix != NULL) {
73                 static const unsigned char zeros[16];
74                 REQUIRE(prefix->family == AF_INET6);
75                 nbytes = prefixlen / 8 + 4;
76                 /* Bits 64-71 are zeros. draft-ietf-behave-address-format-04 */
77                 if (prefixlen >= 32 && prefixlen <= 64)
78                         nbytes++;
79                 REQUIRE(memcmp(suffix->type.in6.s6_addr, zeros, nbytes) == 0);
80         }
81
82         new = isc_mem_get(mctx, sizeof(dns_dns64_t));
83         if (new == NULL)
84                 return (ISC_R_NOMEMORY);
85         memset(new->bits, 0, sizeof(new->bits));
86         memcpy(new->bits, prefix->type.in6.s6_addr, prefixlen / 8);
87         if (suffix != NULL)
88                 memcpy(new->bits + nbytes, suffix->type.in6.s6_addr + nbytes,
89                        16 - nbytes);
90         new->clients = NULL;
91         if (clients != NULL)
92                 dns_acl_attach(clients, &new->clients);
93         new->mapped = NULL;
94         if (mapped != NULL)
95                 dns_acl_attach(mapped, &new->mapped);
96         new->excluded = NULL;
97         if (excluded != NULL)
98                 dns_acl_attach(excluded, &new->excluded);
99         new->prefixlen = prefixlen;
100         new->flags = flags;
101         ISC_LINK_INIT(new, link);
102         new->mctx = NULL;
103         isc_mem_attach(mctx, &new->mctx);
104         *dns64 = new;
105         return (ISC_R_SUCCESS);
106 }
107
108 void
109 dns_dns64_destroy(dns_dns64_t **dns64p) {
110         dns_dns64_t *dns64;
111
112         REQUIRE(dns64p != NULL && *dns64p != NULL);
113
114         dns64 = *dns64p;
115         *dns64p = NULL;
116
117         REQUIRE(!ISC_LINK_LINKED(dns64, link));
118
119         if (dns64->clients != NULL)
120                 dns_acl_detach(&dns64->clients);
121         if (dns64->mapped != NULL)
122                 dns_acl_detach(&dns64->mapped);
123         if (dns64->excluded != NULL)
124                 dns_acl_detach(&dns64->excluded);
125         isc_mem_putanddetach(&dns64->mctx, dns64, sizeof(*dns64));
126 }
127
128 isc_result_t
129 dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
130                     const dns_name_t *reqsigner, const dns_aclenv_t *env,
131                     unsigned int flags, unsigned char *a, unsigned char *aaaa)
132 {
133         unsigned int nbytes, i;
134         isc_result_t result;
135         int match;
136
137         if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
138             (flags & DNS_DNS64_RECURSIVE) == 0)
139                 return (DNS_R_DISALLOWED);
140
141         if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
142             (flags & DNS_DNS64_DNSSEC) != 0)
143                 return (DNS_R_DISALLOWED);
144
145         if (dns64->clients != NULL) {
146                 result = dns_acl_match(reqaddr, reqsigner, dns64->clients, env,
147                                        &match, NULL);
148                 if (result != ISC_R_SUCCESS)
149                         return (result);
150                 if (match <= 0)
151                         return (DNS_R_DISALLOWED);
152         }
153
154         if (dns64->mapped != NULL) {
155                 struct in_addr ina;
156                 isc_netaddr_t netaddr;
157
158                 memcpy(&ina.s_addr, a, 4);
159                 isc_netaddr_fromin(&netaddr, &ina);
160                 result = dns_acl_match(&netaddr, NULL, dns64->mapped, env,
161                                        &match, NULL);
162                 if (result != ISC_R_SUCCESS)
163                         return (result);
164                 if (match <= 0)
165                         return (DNS_R_DISALLOWED);
166         }
167
168         nbytes = dns64->prefixlen / 8;
169         INSIST(nbytes <= 12);
170         /* Copy prefix. */
171         memcpy(aaaa, dns64->bits, nbytes);
172         /* Bits 64-71 are zeros. draft-ietf-behave-address-format-04 */
173         if (nbytes == 8)
174                 aaaa[nbytes++] = 0;
175         /* Copy mapped address. */
176         for (i = 0; i < 4U; i++) {
177                 aaaa[nbytes++] = a[i];
178                 /* Bits 64-71 are zeros. draft-ietf-behave-address-format-04 */
179                 if (nbytes == 8)
180                         aaaa[nbytes++] = 0;
181         }
182         /* Copy suffix. */
183         memcpy(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes);
184         return (ISC_R_SUCCESS);
185 }
186
187 dns_dns64_t *
188 dns_dns64_next(dns_dns64_t *dns64) {
189         dns64 = ISC_LIST_NEXT(dns64, link);
190         return (dns64);
191 }
192
193 void
194 dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64) {
195         ISC_LIST_APPEND(*list, dns64, link);
196 }
197
198 void
199 dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64) {
200         ISC_LIST_UNLINK(*list, dns64, link);
201 }
202
203 isc_boolean_t
204 dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
205                  const dns_name_t *reqsigner, const dns_aclenv_t *env,
206                  unsigned int flags, dns_rdataset_t *rdataset,
207                  isc_boolean_t *aaaaok, size_t aaaaoklen)
208 {
209         struct in6_addr in6;
210         isc_netaddr_t netaddr;
211         isc_result_t result;
212         int match;
213         isc_boolean_t answer = ISC_FALSE;
214         isc_boolean_t found = ISC_FALSE;
215         unsigned int i, ok;
216
217         REQUIRE(rdataset != NULL);
218         REQUIRE(rdataset->type == dns_rdatatype_aaaa);
219         REQUIRE(rdataset->rdclass == dns_rdataclass_in);
220         if (aaaaok != NULL)
221                 REQUIRE(aaaaoklen == dns_rdataset_count(rdataset));
222
223         for (;dns64 != NULL; dns64 = ISC_LIST_NEXT(dns64, link)) {
224                 if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
225                     (flags & DNS_DNS64_RECURSIVE) == 0)
226                         continue;
227
228                 if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
229                     (flags & DNS_DNS64_DNSSEC) != 0)
230                         continue;
231                 /*
232                  * Work out if this dns64 structure applies to this client.
233                  */
234                 if (dns64->clients != NULL) {
235                         result = dns_acl_match(reqaddr, reqsigner,
236                                                dns64->clients, env,
237                                                &match, NULL);
238                         if (result != ISC_R_SUCCESS)
239                                 continue;
240                         if (match <= 0)
241                                 continue;
242                 }
243
244                 if (!found && aaaaok != NULL) {
245                         for (i = 0; i < aaaaoklen; i++)
246                                 aaaaok[i] = ISC_FALSE;
247                 }
248                 found = ISC_TRUE;
249
250                 /*
251                  * If we are not excluding any addresses then any AAAA
252                  * will do.
253                  */
254                 if (dns64->excluded == NULL) {
255                         answer = ISC_TRUE;
256                         if (aaaaok == NULL)
257                                 goto done;
258                         for (i = 0; i < aaaaoklen; i++)
259                                 aaaaok[i] = ISC_TRUE;
260                         goto done;
261                 }
262
263                 i = 0; ok = 0;
264                 for (result = dns_rdataset_first(rdataset);
265                      result == ISC_R_SUCCESS;
266                      result = dns_rdataset_next(rdataset)) {
267                         dns_rdata_t rdata = DNS_RDATA_INIT;
268                         if (aaaaok == NULL || !aaaaok[i]) {
269
270                                 dns_rdataset_current(rdataset, &rdata);
271                                 memcpy(&in6.s6_addr, rdata.data, 16);
272                                 isc_netaddr_fromin6(&netaddr, &in6);
273
274                                 result = dns_acl_match(&netaddr, NULL,
275                                                        dns64->excluded,
276                                                        env, &match, NULL);
277                                 if (result == ISC_R_SUCCESS && match <= 0) {
278                                         answer = ISC_TRUE;
279                                         if (aaaaok == NULL)
280                                                 goto done;
281                                         aaaaok[i] = ISC_TRUE;
282                                         ok++;
283                                 }
284                         } else
285                                 ok++;
286                         i++;
287                 }
288                 /*
289                  * Are all addresses ok?
290                  */
291                 if (aaaaok != NULL && ok == aaaaoklen)
292                         goto done;
293         }
294
295  done:
296         if (!found && aaaaok != NULL) {
297                 for (i = 0; i < aaaaoklen; i++)
298                         aaaaok[i] = ISC_TRUE;
299         }
300         return (found ? answer : ISC_TRUE);
301 }