2010-12-08 02:46:17 +00:00
|
|
|
/*
|
2018-02-23 09:53:12 +01:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2010-12-08 23:51:56 +00:00
|
|
|
*
|
2016-06-27 14:56:38 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
2010-12-08 02:46:17 +00:00
|
|
|
*/
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <string.h>
|
2018-04-17 08:29:14 -07:00
|
|
|
|
2010-12-08 02:46:17 +00:00
|
|
|
#include <isc/list.h>
|
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/netaddr.h>
|
|
|
|
#include <isc/string.h>
|
|
|
|
#include <isc/util.h>
|
|
|
|
|
|
|
|
#include <dns/acl.h>
|
|
|
|
#include <dns/dns64.h>
|
|
|
|
#include <dns/rdata.h>
|
|
|
|
#include <dns/rdataset.h>
|
|
|
|
#include <dns/result.h>
|
|
|
|
|
|
|
|
struct dns_dns64 {
|
2020-02-12 13:59:18 +01:00
|
|
|
unsigned char bits[16]; /*
|
|
|
|
* Prefix + suffix bits.
|
|
|
|
*/
|
|
|
|
dns_acl_t *clients; /*
|
|
|
|
* Which clients get mapped
|
|
|
|
* addresses.
|
|
|
|
*/
|
|
|
|
dns_acl_t *mapped; /*
|
|
|
|
* IPv4 addresses to be mapped.
|
|
|
|
*/
|
|
|
|
dns_acl_t *excluded; /*
|
|
|
|
* IPv6 addresses that are
|
|
|
|
* treated as not existing.
|
|
|
|
*/
|
|
|
|
unsigned int prefixlen; /*
|
|
|
|
* Start of mapped address.
|
|
|
|
*/
|
|
|
|
unsigned int flags;
|
|
|
|
isc_mem_t * mctx;
|
|
|
|
ISC_LINK(dns_dns64_t) link;
|
2010-12-08 02:46:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
isc_result_t
|
2016-12-30 15:45:08 +11:00
|
|
|
dns_dns64_create(isc_mem_t *mctx, const isc_netaddr_t *prefix,
|
|
|
|
unsigned int prefixlen, const isc_netaddr_t *suffix,
|
2010-12-08 02:46:17 +00:00
|
|
|
dns_acl_t *clients, dns_acl_t *mapped, dns_acl_t *excluded,
|
2017-07-21 11:52:24 +10:00
|
|
|
unsigned int flags, dns_dns64_t **dns64p)
|
2010-12-08 02:46:17 +00:00
|
|
|
{
|
2017-07-21 11:52:24 +10:00
|
|
|
dns_dns64_t *dns64;
|
2010-12-08 02:46:17 +00:00
|
|
|
unsigned int nbytes = 16;
|
|
|
|
|
|
|
|
REQUIRE(prefix != NULL && prefix->family == AF_INET6);
|
2014-02-14 08:53:06 -08:00
|
|
|
/* Legal prefix lengths from rfc6052.txt. */
|
2010-12-08 02:46:17 +00:00
|
|
|
REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
|
|
|
|
prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
|
|
|
|
REQUIRE(isc_netaddr_prefixok(prefix, prefixlen) == ISC_R_SUCCESS);
|
2017-07-21 11:52:24 +10:00
|
|
|
REQUIRE(dns64p != NULL && *dns64p == NULL);
|
2010-12-08 02:46:17 +00:00
|
|
|
|
|
|
|
if (suffix != NULL) {
|
|
|
|
static const unsigned char zeros[16];
|
|
|
|
REQUIRE(prefix->family == AF_INET6);
|
|
|
|
nbytes = prefixlen / 8 + 4;
|
2014-02-14 08:53:06 -08:00
|
|
|
/* Bits 64-71 are zeros. rfc6052.txt */
|
2010-12-08 02:46:17 +00:00
|
|
|
if (prefixlen >= 32 && prefixlen <= 64)
|
|
|
|
nbytes++;
|
|
|
|
REQUIRE(memcmp(suffix->type.in6.s6_addr, zeros, nbytes) == 0);
|
|
|
|
}
|
|
|
|
|
2017-07-21 11:52:24 +10:00
|
|
|
dns64 = isc_mem_get(mctx, sizeof(dns_dns64_t));
|
|
|
|
memset(dns64->bits, 0, sizeof(dns64->bits));
|
|
|
|
memmove(dns64->bits, prefix->type.in6.s6_addr, prefixlen / 8);
|
2010-12-08 02:46:17 +00:00
|
|
|
if (suffix != NULL)
|
2017-07-21 11:52:24 +10:00
|
|
|
memmove(dns64->bits + nbytes, suffix->type.in6.s6_addr + nbytes,
|
2014-01-08 16:27:10 -08:00
|
|
|
16 - nbytes);
|
2017-07-21 11:52:24 +10:00
|
|
|
dns64->clients = NULL;
|
2010-12-08 02:46:17 +00:00
|
|
|
if (clients != NULL)
|
2017-07-21 11:52:24 +10:00
|
|
|
dns_acl_attach(clients, &dns64->clients);
|
|
|
|
dns64->mapped = NULL;
|
2010-12-08 02:46:17 +00:00
|
|
|
if (mapped != NULL)
|
2017-07-21 11:52:24 +10:00
|
|
|
dns_acl_attach(mapped, &dns64->mapped);
|
|
|
|
dns64->excluded = NULL;
|
2010-12-08 02:46:17 +00:00
|
|
|
if (excluded != NULL)
|
2017-07-21 11:52:24 +10:00
|
|
|
dns_acl_attach(excluded, &dns64->excluded);
|
|
|
|
dns64->prefixlen = prefixlen;
|
|
|
|
dns64->flags = flags;
|
|
|
|
ISC_LINK_INIT(dns64, link);
|
|
|
|
dns64->mctx = NULL;
|
|
|
|
isc_mem_attach(mctx, &dns64->mctx);
|
|
|
|
*dns64p = dns64;
|
2010-12-08 02:46:17 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
2010-12-09 04:59:09 +00:00
|
|
|
}
|
2010-12-08 02:46:17 +00:00
|
|
|
|
|
|
|
void
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_dns64_destroy(dns_dns64_t **dns64p)
|
|
|
|
{
|
2010-12-08 02:46:17 +00:00
|
|
|
dns_dns64_t *dns64;
|
|
|
|
|
|
|
|
REQUIRE(dns64p != NULL && *dns64p != NULL);
|
|
|
|
|
|
|
|
dns64 = *dns64p;
|
|
|
|
*dns64p = NULL;
|
|
|
|
|
|
|
|
REQUIRE(!ISC_LINK_LINKED(dns64, link));
|
|
|
|
|
|
|
|
if (dns64->clients != NULL)
|
|
|
|
dns_acl_detach(&dns64->clients);
|
|
|
|
if (dns64->mapped != NULL)
|
|
|
|
dns_acl_detach(&dns64->mapped);
|
|
|
|
if (dns64->excluded != NULL)
|
|
|
|
dns_acl_detach(&dns64->excluded);
|
|
|
|
isc_mem_putanddetach(&dns64->mctx, dns64, sizeof(*dns64));
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
|
|
|
dns_dns64_aaaafroma(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
|
|
|
|
const dns_name_t *reqsigner, const dns_aclenv_t *env,
|
|
|
|
unsigned int flags, unsigned char *a, unsigned char *aaaa)
|
|
|
|
{
|
|
|
|
unsigned int nbytes, i;
|
|
|
|
isc_result_t result;
|
2020-02-12 13:59:18 +01:00
|
|
|
int match;
|
2010-12-08 02:46:17 +00:00
|
|
|
|
|
|
|
if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
|
|
|
|
(flags & DNS_DNS64_RECURSIVE) == 0)
|
|
|
|
return (DNS_R_DISALLOWED);
|
|
|
|
|
|
|
|
if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
|
|
|
|
(flags & DNS_DNS64_DNSSEC) != 0)
|
|
|
|
return (DNS_R_DISALLOWED);
|
|
|
|
|
|
|
|
if (dns64->clients != NULL) {
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_acl_match(reqaddr, reqsigner, dns64->clients, env,
|
|
|
|
&match, NULL);
|
2010-12-08 02:46:17 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
if (match <= 0)
|
|
|
|
return (DNS_R_DISALLOWED);
|
|
|
|
}
|
2010-12-08 23:51:56 +00:00
|
|
|
|
2010-12-08 02:46:17 +00:00
|
|
|
if (dns64->mapped != NULL) {
|
|
|
|
struct in_addr ina;
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_netaddr_t netaddr;
|
2010-12-08 02:46:17 +00:00
|
|
|
|
2014-01-08 16:27:10 -08:00
|
|
|
memmove(&ina.s_addr, a, 4);
|
2010-12-08 02:46:17 +00:00
|
|
|
isc_netaddr_fromin(&netaddr, &ina);
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_acl_match(&netaddr, NULL, dns64->mapped, env,
|
|
|
|
&match, NULL);
|
2010-12-08 02:46:17 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
if (match <= 0)
|
|
|
|
return (DNS_R_DISALLOWED);
|
|
|
|
}
|
|
|
|
|
|
|
|
nbytes = dns64->prefixlen / 8;
|
|
|
|
INSIST(nbytes <= 12);
|
|
|
|
/* Copy prefix. */
|
2014-01-08 16:27:10 -08:00
|
|
|
memmove(aaaa, dns64->bits, nbytes);
|
2014-02-14 08:53:06 -08:00
|
|
|
/* Bits 64-71 are zeros. rfc6052.txt */
|
2010-12-09 04:01:43 +00:00
|
|
|
if (nbytes == 8)
|
|
|
|
aaaa[nbytes++] = 0;
|
2010-12-08 02:46:17 +00:00
|
|
|
/* Copy mapped address. */
|
|
|
|
for (i = 0; i < 4U; i++) {
|
|
|
|
aaaa[nbytes++] = a[i];
|
2014-02-14 08:53:06 -08:00
|
|
|
/* Bits 64-71 are zeros. rfc6052.txt */
|
2010-12-08 02:46:17 +00:00
|
|
|
if (nbytes == 8)
|
|
|
|
aaaa[nbytes++] = 0;
|
|
|
|
}
|
|
|
|
/* Copy suffix. */
|
2014-01-08 16:27:10 -08:00
|
|
|
memmove(aaaa + nbytes, dns64->bits + nbytes, 16 - nbytes);
|
2010-12-08 02:46:17 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_dns64_t *
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_dns64_next(dns_dns64_t *dns64)
|
|
|
|
{
|
2010-12-08 02:46:17 +00:00
|
|
|
dns64 = ISC_LIST_NEXT(dns64, link);
|
|
|
|
return (dns64);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_dns64_append(dns_dns64list_t *list, dns_dns64_t *dns64)
|
|
|
|
{
|
2010-12-08 02:46:17 +00:00
|
|
|
ISC_LIST_APPEND(*list, dns64, link);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_dns64_unlink(dns_dns64list_t *list, dns_dns64_t *dns64)
|
|
|
|
{
|
2010-12-08 02:46:17 +00:00
|
|
|
ISC_LIST_UNLINK(*list, dns64, link);
|
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2010-12-08 02:46:17 +00:00
|
|
|
dns_dns64_aaaaok(const dns_dns64_t *dns64, const isc_netaddr_t *reqaddr,
|
2010-12-08 23:51:56 +00:00
|
|
|
const dns_name_t *reqsigner, const dns_aclenv_t *env,
|
2020-02-12 13:59:18 +01:00
|
|
|
unsigned int flags, dns_rdataset_t *rdataset, bool *aaaaok,
|
|
|
|
size_t aaaaoklen)
|
2010-12-08 02:46:17 +00:00
|
|
|
{
|
|
|
|
struct in6_addr in6;
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
isc_result_t result;
|
|
|
|
int match;
|
|
|
|
bool answer = false;
|
|
|
|
bool found = false;
|
|
|
|
unsigned int i, ok;
|
2010-12-08 02:46:17 +00:00
|
|
|
|
|
|
|
REQUIRE(rdataset != NULL);
|
|
|
|
REQUIRE(rdataset->type == dns_rdatatype_aaaa);
|
|
|
|
REQUIRE(rdataset->rdclass == dns_rdataclass_in);
|
|
|
|
if (aaaaok != NULL)
|
|
|
|
REQUIRE(aaaaoklen == dns_rdataset_count(rdataset));
|
2010-12-08 23:51:56 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
for (; dns64 != NULL; dns64 = ISC_LIST_NEXT(dns64, link)) {
|
2010-12-08 02:46:17 +00:00
|
|
|
if ((dns64->flags & DNS_DNS64_RECURSIVE_ONLY) != 0 &&
|
|
|
|
(flags & DNS_DNS64_RECURSIVE) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((dns64->flags & DNS_DNS64_BREAK_DNSSEC) == 0 &&
|
|
|
|
(flags & DNS_DNS64_DNSSEC) != 0)
|
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* Work out if this dns64 structure applies to this client.
|
|
|
|
*/
|
|
|
|
if (dns64->clients != NULL) {
|
2018-04-26 20:57:41 -07:00
|
|
|
result = dns_acl_match(reqaddr, reqsigner,
|
2020-02-12 13:59:18 +01:00
|
|
|
dns64->clients, env, &match,
|
|
|
|
NULL);
|
2010-12-08 02:46:17 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
continue;
|
|
|
|
if (match <= 0)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found && aaaaok != NULL) {
|
|
|
|
for (i = 0; i < aaaaoklen; i++)
|
2018-04-17 08:29:14 -07:00
|
|
|
aaaaok[i] = false;
|
2010-12-08 02:46:17 +00:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
found = true;
|
2010-12-08 02:46:17 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are not excluding any addresses then any AAAA
|
|
|
|
* will do.
|
|
|
|
*/
|
|
|
|
if (dns64->excluded == NULL) {
|
2018-04-17 08:29:14 -07:00
|
|
|
answer = true;
|
2011-03-11 13:02:33 +00:00
|
|
|
if (aaaaok == NULL)
|
|
|
|
goto done;
|
2010-12-08 02:46:17 +00:00
|
|
|
for (i = 0; i < aaaaoklen; i++)
|
2018-04-17 08:29:14 -07:00
|
|
|
aaaaok[i] = true;
|
2010-12-08 02:46:17 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
i = 0;
|
|
|
|
ok = 0;
|
2010-12-08 02:46:17 +00:00
|
|
|
for (result = dns_rdataset_first(rdataset);
|
|
|
|
result == ISC_R_SUCCESS;
|
|
|
|
result = dns_rdataset_next(rdataset)) {
|
|
|
|
dns_rdata_t rdata = DNS_RDATA_INIT;
|
|
|
|
if (aaaaok == NULL || !aaaaok[i]) {
|
|
|
|
dns_rdataset_current(rdataset, &rdata);
|
2014-01-08 16:27:10 -08:00
|
|
|
memmove(&in6.s6_addr, rdata.data, 16);
|
2010-12-08 02:46:17 +00:00
|
|
|
isc_netaddr_fromin6(&netaddr, &in6);
|
|
|
|
|
2018-04-26 20:57:41 -07:00
|
|
|
result = dns_acl_match(&netaddr, NULL,
|
2018-04-03 13:09:45 +02:00
|
|
|
dns64->excluded, env,
|
|
|
|
&match, NULL);
|
2010-12-08 02:46:17 +00:00
|
|
|
if (result == ISC_R_SUCCESS && match <= 0) {
|
2018-04-17 08:29:14 -07:00
|
|
|
answer = true;
|
2010-12-08 02:46:17 +00:00
|
|
|
if (aaaaok == NULL)
|
|
|
|
goto done;
|
2018-04-17 08:29:14 -07:00
|
|
|
aaaaok[i] = true;
|
2010-12-08 02:46:17 +00:00
|
|
|
ok++;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
ok++;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Are all addresses ok?
|
|
|
|
*/
|
|
|
|
if (aaaaok != NULL && ok == aaaaoklen)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
done:
|
2010-12-08 02:46:17 +00:00
|
|
|
if (!found && aaaaok != NULL) {
|
|
|
|
for (i = 0; i < aaaaoklen; i++)
|
2018-04-17 08:29:14 -07:00
|
|
|
aaaaok[i] = true;
|
2010-12-08 02:46:17 +00:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
return (found ? answer : true);
|
2010-12-08 02:46:17 +00:00
|
|
|
}
|