dns64.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010, 2011, 2014  Internet Systems Consortium, Inc. ("ISC")
00003  *
00004  * Permission to use, copy, modify, and/or distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00009  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00010  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00011  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00012  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00013  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00014  * PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 /* $Id: dns64.c,v 1.8 2011/03/12 04:59:47 tbox Exp $ */
00018 
00019 #include <config.h>
00020 
00021 #include <isc/list.h>
00022 #include <isc/mem.h>
00023 #include <isc/netaddr.h>
00024 #include <isc/string.h>
00025 #include <isc/util.h>
00026 
00027 #include <dns/acl.h>
00028 #include <dns/dns64.h>
00029 #include <dns/rdata.h>
00030 #include <dns/rdataset.h>
00031 #include <dns/result.h>
00032 
00033 struct dns_dns64 {
00034         unsigned char           bits[16];       /*
00035                                                  * Prefix + suffix bits.
00036                                                  */
00037         dns_acl_t *             clients;        /*
00038                                                  * Which clients get mapped
00039                                                  * addresses.
00040                                                  */
00041         dns_acl_t *             mapped;         /*
00042                                                  * IPv4 addresses to be mapped.
00043                                                  */
00044         dns_acl_t *             excluded;       /*
00045                                                  * IPv6 addresses that are
00046                                                  * treated as not existing.
00047                                                  */
00048         unsigned int            prefixlen;      /*
00049                                                  * Start of mapped address.
00050                                                  */
00051         unsigned int            flags;
00052         isc_mem_t *             mctx;
00053         ISC_LINK(dns_dns64_t)   link;
00054 };
00055 
00056 isc_result_t
00057 dns_dns64_create(isc_mem_t *mctx, isc_netaddr_t *prefix,
00058                  unsigned int prefixlen, isc_netaddr_t *suffix,
00059                  dns_acl_t *clients, dns_acl_t *mapped, dns_acl_t *excluded,
00060                  unsigned int flags, dns_dns64_t **dns64)
00061 {
00062         dns_dns64_t *new;
00063         unsigned int nbytes = 16;
00064 
00065         REQUIRE(prefix != NULL && prefix->family == AF_INET6);
00066         /* Legal prefix lengths from rfc6052.txt. */
00067         REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
00068                 prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
00069         REQUIRE(isc_netaddr_prefixok(prefix, prefixlen) == ISC_R_SUCCESS);
00070         REQUIRE(dns64 != NULL && *dns64 == NULL);
00071 
00072         if (suffix != NULL) {
00073                 static const unsigned char zeros[16];
00074                 REQUIRE(prefix->family == AF_INET6);
00075                 nbytes = prefixlen / 8 + 4;
00076                 /* Bits 64-71 are zeros. rfc6052.txt */
00077                 if (prefixlen >= 32 && prefixlen <= 64)
00078                         nbytes++;
00079                 REQUIRE(memcmp(suffix->type.in6.s6_addr, zeros, nbytes) == 0);
00080         }
00081 
00082         new = isc_mem_get(mctx, sizeof(dns_dns64_t));
00083         if (new == NULL)
00084                 return (ISC_R_NOMEMORY);
00085         memset(new->bits, 0, sizeof(new->bits));
00086         memmove(new->bits, prefix->type.in6.s6_addr, prefixlen / 8);
00087         if (suffix != NULL)
00088                 memmove(new->bits + nbytes, suffix->type.in6.s6_addr + nbytes,
00089                         16 - nbytes);
00090         new->clients = NULL;
00091         if (clients != NULL)
00092                 dns_acl_attach(clients, &new->clients);
00093         new->mapped = NULL;
00094         if (mapped != NULL)
00095                 dns_acl_attach(mapped, &new->mapped);
00096         new->excluded = NULL;
00097         if (excluded != NULL)
00098                 dns_acl_attach(excluded, &new->excluded);
00099         new->prefixlen = prefixlen;
00100         new->flags = flags;
00101         ISC_LINK_INIT(new, link);
00102         new->mctx = NULL;
00103         isc_mem_attach(mctx, &new->mctx);
00104         *dns64 = new;
00105         return (ISC_R_SUCCESS);
00106 }
00107 
00108 void
00109 dns_dns64_destroy(dns_dns64_t **dns64p) {
00110         dns_dns64_t *dns64;
00111 
00112         REQUIRE(dns64p != NULL && *dns64p != NULL);
00113 
00114         dns64 = *dns64p;
00115         *dns64p = NULL;
00116 
00117         REQUIRE(!ISC_LINK_LINKED(dns64, link));
00118 
00119         if (dns64->clients != NULL)
00120                 dns_acl_detach(&dns64->clients);
00121         if (dns64->mapped != NULL)
00122                 dns_acl_detach(&dns64->mapped);
00123         if (dns64->excluded != NULL)
00124                 dns_acl_detach(&dns64->excluded);
00125         isc_mem_putanddetach(&dns64->mctx, dns64, sizeof(*dns64));
00126 }
00127 
00128 isc_result_t
00129 dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
00130                     const dns_name_t *reqsigner, const dns_aclenv_t *env,
00131                     unsigned int flags, unsigned char *a, unsigned char *aaaa)
00132 {
00133         unsigned int nbytes, i;
00134         isc_result_t result;
00135         int match;
00136 
00137         if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
00138             (flags & DNS_DNS64_RECURSIVE) == 0)
00139                 return (DNS_R_DISALLOWED);
00140 
00141         if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
00142             (flags & DNS_DNS64_DNSSEC) != 0)
00143                 return (DNS_R_DISALLOWED);
00144 
00145         if (dns64->clients != NULL) {
00146                 result = dns_acl_match(reqaddr, reqsigner, dns64->clients, env,
00147                                        &match, NULL);
00148                 if (result != ISC_R_SUCCESS)
00149                         return (result);
00150                 if (match <= 0)
00151                         return (DNS_R_DISALLOWED);
00152         }
00153 
00154         if (dns64->mapped != NULL) {
00155                 struct in_addr ina;
00156                 isc_netaddr_t netaddr;
00157 
00158                 memmove(&ina.s_addr, a, 4);
00159                 isc_netaddr_fromin(&netaddr, &ina);
00160                 result = dns_acl_match(&netaddr, NULL, dns64->mapped, env,
00161                                        &match, NULL);
00162                 if (result != ISC_R_SUCCESS)
00163                         return (result);
00164                 if (match <= 0)
00165                         return (DNS_R_DISALLOWED);
00166         }
00167 
00168         nbytes = dns64->prefixlen / 8;
00169         INSIST(nbytes <= 12);
00170         /* Copy prefix. */
00171         memmove(aaaa, dns64->bits, nbytes);
00172         /* Bits 64-71 are zeros. rfc6052.txt */
00173         if (nbytes == 8)
00174                 aaaa[nbytes++] = 0;
00175         /* Copy mapped address. */
00176         for (i = 0; i < 4U; i++) {
00177                 aaaa[nbytes++] = a[i];
00178                 /* Bits 64-71 are zeros. rfc6052.txt */
00179                 if (nbytes == 8)
00180                         aaaa[nbytes++] = 0;
00181         }
00182         /* Copy suffix. */
00183         memmove(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes);
00184         return (ISC_R_SUCCESS);
00185 }
00186 
00187 dns_dns64_t *
00188 dns_dns64_next(dns_dns64_t *dns64) {
00189         dns64 = ISC_LIST_NEXT(dns64, link);
00190         return (dns64);
00191 }
00192 
00193 void
00194 dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64) {
00195         ISC_LIST_APPEND(*list, dns64, link);
00196 }
00197 
00198 void
00199 dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64) {
00200         ISC_LIST_UNLINK(*list, dns64, link);
00201 }
00202 
00203 isc_boolean_t
00204 dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
00205                  const dns_name_t *reqsigner, const dns_aclenv_t *env,
00206                  unsigned int flags, dns_rdataset_t *rdataset,
00207                  isc_boolean_t *aaaaok, size_t aaaaoklen)
00208 {
00209         struct in6_addr in6;
00210         isc_netaddr_t netaddr;
00211         isc_result_t result;
00212         int match;
00213         isc_boolean_t answer = ISC_FALSE;
00214         isc_boolean_t found = ISC_FALSE;
00215         unsigned int i, ok;
00216 
00217         REQUIRE(rdataset != NULL);
00218         REQUIRE(rdataset->type == dns_rdatatype_aaaa);
00219         REQUIRE(rdataset->rdclass == dns_rdataclass_in);
00220         if (aaaaok != NULL)
00221                 REQUIRE(aaaaoklen == dns_rdataset_count(rdataset));
00222 
00223         for (;dns64 != NULL; dns64 = ISC_LIST_NEXT(dns64, link)) {
00224                 if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
00225                     (flags & DNS_DNS64_RECURSIVE) == 0)
00226                         continue;
00227 
00228                 if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
00229                     (flags & DNS_DNS64_DNSSEC) != 0)
00230                         continue;
00231                 /*
00232                  * Work out if this dns64 structure applies to this client.
00233                  */
00234                 if (dns64->clients != NULL) {
00235                         result = dns_acl_match(reqaddr, reqsigner,
00236                                                dns64->clients, env,
00237                                                &match, NULL);
00238                         if (result != ISC_R_SUCCESS)
00239                                 continue;
00240                         if (match <= 0)
00241                                 continue;
00242                 }
00243 
00244                 if (!found && aaaaok != NULL) {
00245                         for (i = 0; i < aaaaoklen; i++)
00246                                 aaaaok[i] = ISC_FALSE;
00247                 }
00248                 found = ISC_TRUE;
00249 
00250                 /*
00251                  * If we are not excluding any addresses then any AAAA
00252                  * will do.
00253                  */
00254                 if (dns64->excluded == NULL) {
00255                         answer = ISC_TRUE;
00256                         if (aaaaok == NULL)
00257                                 goto done;
00258                         for (i = 0; i < aaaaoklen; i++)
00259                                 aaaaok[i] = ISC_TRUE;
00260                         goto done;
00261                 }
00262 
00263                 i = 0; ok = 0;
00264                 for (result = dns_rdataset_first(rdataset);
00265                      result == ISC_R_SUCCESS;
00266                      result = dns_rdataset_next(rdataset)) {
00267                         dns_rdata_t rdata = DNS_RDATA_INIT;
00268                         if (aaaaok == NULL || !aaaaok[i]) {
00269 
00270                                 dns_rdataset_current(rdataset, &rdata);
00271                                 memmove(&in6.s6_addr, rdata.data, 16);
00272                                 isc_netaddr_fromin6(&netaddr, &in6);
00273 
00274                                 result = dns_acl_match(&netaddr, NULL,
00275                                                        dns64->excluded,
00276                                                        env, &match, NULL);
00277                                 if (result == ISC_R_SUCCESS && match <= 0) {
00278                                         answer = ISC_TRUE;
00279                                         if (aaaaok == NULL)
00280                                                 goto done;
00281                                         aaaaok[i] = ISC_TRUE;
00282                                         ok++;
00283                                 }
00284                         } else
00285                                 ok++;
00286                         i++;
00287                 }
00288                 /*
00289                  * Are all addresses ok?
00290                  */
00291                 if (aaaaok != NULL && ok == aaaaoklen)
00292                         goto done;
00293         }
00294 
00295  done:
00296         if (!found && aaaaok != NULL) {
00297                 for (i = 0; i < aaaaoklen; i++)
00298                         aaaaok[i] = ISC_TRUE;
00299         }
00300         return (found ? answer : ISC_TRUE);
00301 }

Generated on Tue Apr 28 17:40:56 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha