/contrib/bind9/lib/dns/dns64.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 301 lines · 222 code · 34 blank · 45 comment · 109 complexity · 9ba4b8eba6c0a3cbc8e6d897d88a5bdc MD5 · raw file

  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. /* $Id$ */
  17. #include <config.h>
  18. #include <isc/list.h>
  19. #include <isc/mem.h>
  20. #include <isc/netaddr.h>
  21. #include <isc/string.h>
  22. #include <isc/util.h>
  23. #include <dns/acl.h>
  24. #include <dns/dns64.h>
  25. #include <dns/rdata.h>
  26. #include <dns/rdataset.h>
  27. #include <dns/result.h>
  28. struct dns_dns64 {
  29. unsigned char bits[16]; /*
  30. * Prefix + suffix bits.
  31. */
  32. dns_acl_t * clients; /*
  33. * Which clients get mapped
  34. * addresses.
  35. */
  36. dns_acl_t * mapped; /*
  37. * IPv4 addresses to be mapped.
  38. */
  39. dns_acl_t * excluded; /*
  40. * IPv6 addresses that are
  41. * treated as not existing.
  42. */
  43. unsigned int prefixlen; /*
  44. * Start of mapped address.
  45. */
  46. unsigned int flags;
  47. isc_mem_t * mctx;
  48. ISC_LINK(dns_dns64_t) link;
  49. };
  50. isc_result_t
  51. dns_dns64_create(isc_mem_t *mctx, isc_netaddr_t *prefix,
  52. unsigned int prefixlen, isc_netaddr_t *suffix,
  53. dns_acl_t *clients, dns_acl_t *mapped, dns_acl_t *excluded,
  54. unsigned int flags, dns_dns64_t **dns64)
  55. {
  56. dns_dns64_t *new;
  57. unsigned int nbytes = 16;
  58. REQUIRE(prefix != NULL && prefix->family == AF_INET6);
  59. /* Legal prefix lengths from draft-ietf-behave-address-format-04. */
  60. REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
  61. prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
  62. REQUIRE(isc_netaddr_prefixok(prefix, prefixlen) == ISC_R_SUCCESS);
  63. REQUIRE(dns64 != NULL && *dns64 == NULL);
  64. if (suffix != NULL) {
  65. static const unsigned char zeros[16];
  66. REQUIRE(prefix->family == AF_INET6);
  67. nbytes = prefixlen / 8 + 4;
  68. /* Bits 64-71 are zeros. draft-ietf-behave-address-format-04 */
  69. if (prefixlen >= 32 && prefixlen <= 64)
  70. nbytes++;
  71. REQUIRE(memcmp(suffix->type.in6.s6_addr, zeros, nbytes) == 0);
  72. }
  73. new = isc_mem_get(mctx, sizeof(dns_dns64_t));
  74. if (new == NULL)
  75. return (ISC_R_NOMEMORY);
  76. memset(new->bits, 0, sizeof(new->bits));
  77. memcpy(new->bits, prefix->type.in6.s6_addr, prefixlen / 8);
  78. if (suffix != NULL)
  79. memcpy(new->bits + nbytes, suffix->type.in6.s6_addr + nbytes,
  80. 16 - nbytes);
  81. new->clients = NULL;
  82. if (clients != NULL)
  83. dns_acl_attach(clients, &new->clients);
  84. new->mapped = NULL;
  85. if (mapped != NULL)
  86. dns_acl_attach(mapped, &new->mapped);
  87. new->excluded = NULL;
  88. if (excluded != NULL)
  89. dns_acl_attach(excluded, &new->excluded);
  90. new->prefixlen = prefixlen;
  91. new->flags = flags;
  92. ISC_LINK_INIT(new, link);
  93. new->mctx = NULL;
  94. isc_mem_attach(mctx, &new->mctx);
  95. *dns64 = new;
  96. return (ISC_R_SUCCESS);
  97. }
  98. void
  99. dns_dns64_destroy(dns_dns64_t **dns64p) {
  100. dns_dns64_t *dns64;
  101. REQUIRE(dns64p != NULL && *dns64p != NULL);
  102. dns64 = *dns64p;
  103. *dns64p = NULL;
  104. REQUIRE(!ISC_LINK_LINKED(dns64, link));
  105. if (dns64->clients != NULL)
  106. dns_acl_detach(&dns64->clients);
  107. if (dns64->mapped != NULL)
  108. dns_acl_detach(&dns64->mapped);
  109. if (dns64->excluded != NULL)
  110. dns_acl_detach(&dns64->excluded);
  111. isc_mem_putanddetach(&dns64->mctx, dns64, sizeof(*dns64));
  112. }
  113. isc_result_t
  114. dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
  115. const dns_name_t *reqsigner, const dns_aclenv_t *env,
  116. unsigned int flags, unsigned char *a, unsigned char *aaaa)
  117. {
  118. unsigned int nbytes, i;
  119. isc_result_t result;
  120. int match;
  121. if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
  122. (flags & DNS_DNS64_RECURSIVE) == 0)
  123. return (DNS_R_DISALLOWED);
  124. if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
  125. (flags & DNS_DNS64_DNSSEC) != 0)
  126. return (DNS_R_DISALLOWED);
  127. if (dns64->clients != NULL) {
  128. result = dns_acl_match(reqaddr, reqsigner, dns64->clients, env,
  129. &match, NULL);
  130. if (result != ISC_R_SUCCESS)
  131. return (result);
  132. if (match <= 0)
  133. return (DNS_R_DISALLOWED);
  134. }
  135. if (dns64->mapped != NULL) {
  136. struct in_addr ina;
  137. isc_netaddr_t netaddr;
  138. memcpy(&ina.s_addr, a, 4);
  139. isc_netaddr_fromin(&netaddr, &ina);
  140. result = dns_acl_match(&netaddr, NULL, dns64->mapped, env,
  141. &match, NULL);
  142. if (result != ISC_R_SUCCESS)
  143. return (result);
  144. if (match <= 0)
  145. return (DNS_R_DISALLOWED);
  146. }
  147. nbytes = dns64->prefixlen / 8;
  148. INSIST(nbytes <= 12);
  149. /* Copy prefix. */
  150. memcpy(aaaa, dns64->bits, nbytes);
  151. /* Bits 64-71 are zeros. draft-ietf-behave-address-format-04 */
  152. if (nbytes == 8)
  153. aaaa[nbytes++] = 0;
  154. /* Copy mapped address. */
  155. for (i = 0; i < 4U; i++) {
  156. aaaa[nbytes++] = a[i];
  157. /* Bits 64-71 are zeros. draft-ietf-behave-address-format-04 */
  158. if (nbytes == 8)
  159. aaaa[nbytes++] = 0;
  160. }
  161. /* Copy suffix. */
  162. memcpy(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes);
  163. return (ISC_R_SUCCESS);
  164. }
  165. dns_dns64_t *
  166. dns_dns64_next(dns_dns64_t *dns64) {
  167. dns64 = ISC_LIST_NEXT(dns64, link);
  168. return (dns64);
  169. }
  170. void
  171. dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64) {
  172. ISC_LIST_APPEND(*list, dns64, link);
  173. }
  174. void
  175. dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64) {
  176. ISC_LIST_UNLINK(*list, dns64, link);
  177. }
  178. isc_boolean_t
  179. dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
  180. const dns_name_t *reqsigner, const dns_aclenv_t *env,
  181. unsigned int flags, dns_rdataset_t *rdataset,
  182. isc_boolean_t *aaaaok, size_t aaaaoklen)
  183. {
  184. struct in6_addr in6;
  185. isc_netaddr_t netaddr;
  186. isc_result_t result;
  187. int match;
  188. isc_boolean_t answer = ISC_FALSE;
  189. isc_boolean_t found = ISC_FALSE;
  190. unsigned int i, ok;
  191. REQUIRE(rdataset != NULL);
  192. REQUIRE(rdataset->type == dns_rdatatype_aaaa);
  193. REQUIRE(rdataset->rdclass == dns_rdataclass_in);
  194. if (aaaaok != NULL)
  195. REQUIRE(aaaaoklen == dns_rdataset_count(rdataset));
  196. for (;dns64 != NULL; dns64 = ISC_LIST_NEXT(dns64, link)) {
  197. if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
  198. (flags & DNS_DNS64_RECURSIVE) == 0)
  199. continue;
  200. if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
  201. (flags & DNS_DNS64_DNSSEC) != 0)
  202. continue;
  203. /*
  204. * Work out if this dns64 structure applies to this client.
  205. */
  206. if (dns64->clients != NULL) {
  207. result = dns_acl_match(reqaddr, reqsigner,
  208. dns64->clients, env,
  209. &match, NULL);
  210. if (result != ISC_R_SUCCESS)
  211. continue;
  212. if (match <= 0)
  213. continue;
  214. }
  215. if (!found && aaaaok != NULL) {
  216. for (i = 0; i < aaaaoklen; i++)
  217. aaaaok[i] = ISC_FALSE;
  218. }
  219. found = ISC_TRUE;
  220. /*
  221. * If we are not excluding any addresses then any AAAA
  222. * will do.
  223. */
  224. if (dns64->excluded == NULL) {
  225. answer = ISC_TRUE;
  226. if (aaaaok == NULL)
  227. goto done;
  228. for (i = 0; i < aaaaoklen; i++)
  229. aaaaok[i] = ISC_TRUE;
  230. goto done;
  231. }
  232. i = 0; ok = 0;
  233. for (result = dns_rdataset_first(rdataset);
  234. result == ISC_R_SUCCESS;
  235. result = dns_rdataset_next(rdataset)) {
  236. dns_rdata_t rdata = DNS_RDATA_INIT;
  237. if (aaaaok == NULL || !aaaaok[i]) {
  238. dns_rdataset_current(rdataset, &rdata);
  239. memcpy(&in6.s6_addr, rdata.data, 16);
  240. isc_netaddr_fromin6(&netaddr, &in6);
  241. result = dns_acl_match(&netaddr, NULL,
  242. dns64->excluded,
  243. env, &match, NULL);
  244. if (result == ISC_R_SUCCESS && match <= 0) {
  245. answer = ISC_TRUE;
  246. if (aaaaok == NULL)
  247. goto done;
  248. aaaaok[i] = ISC_TRUE;
  249. ok++;
  250. }
  251. } else
  252. ok++;
  253. i++;
  254. }
  255. /*
  256. * Are all addresses ok?
  257. */
  258. if (aaaaok != NULL && ok == aaaaoklen)
  259. goto done;
  260. }
  261. done:
  262. if (!found && aaaaok != NULL) {
  263. for (i = 0; i < aaaaoklen; i++)
  264. aaaaok[i] = ISC_TRUE;
  265. }
  266. return (found ? answer : ISC_TRUE);
  267. }