******************************************************************************/
/**
- * This is the default DNS64 prefix that is used whent he dns64 module is listed
+ * This is the default DNS64 prefix that is used when the dns64 module is listed
* in module-config but when the dns64-prefix variable is not present.
*/
static const char DEFAULT_DNS64_PREFIX[] = "64:ff9b::/96";
# the network, unbound can use NAT64 to reach these servers with
# the following option. This is NOT needed for enabling DNS64 on a
# system that has IPv4 connectivity.
+ # Consider also enabling prefer-ip6 to prefer native IPv6 connections
+ # to nameservers.
# do-nat64: no
# NAT64 prefix. Defaults to using dns64-prefix value.
servers. It is controlled by two options in the \fBserver:\fR section:
.TP
.B do\-nat64: \fI<yes or no>\fR
-Use NAT64 to reach IPv4-only servers. Default no.
+Use NAT64 to reach IPv4-only servers.
+Consider also enabling \fBprefer\-ip6\fR to prefer native IPv6 connections to
+nameservers.
+Default no.
.TP
.B nat64\-prefix: \fI<IPv6 prefix>\fR
Use a specific NAT64 prefix to reach IPv4-only servers. Defaults to using
the prefix configured in \fBdns64\-prefix\fR, which in turn defaults to
-64:ff9b::/96. Must be /96 or shorter.
+64:ff9b::/96. The prefix length must be one of /32, /40, /48, /56, /64 or /96.
.SS "DNSCrypt Options"
.LP
The
}
nat64_prefix = cfg->nat64_prefix;
- if (!nat64_prefix)
+ if(!nat64_prefix)
nat64_prefix = cfg->dns64_prefix;
- if (!nat64_prefix)
+ if(!nat64_prefix)
nat64_prefix = DEFAULT_NAT64_PREFIX;
- if (!netblockstrtoaddr(nat64_prefix, 0, &iter_env->nat64_prefix_addr,
- &iter_env->nat64_prefix_addrlen,
- &iter_env->nat64_prefix_net)) {
+ if(!netblockstrtoaddr(nat64_prefix, 0, &iter_env->nat64_prefix_addr,
+ &iter_env->nat64_prefix_addrlen,
+ &iter_env->nat64_prefix_net)) {
log_err("cannot parse nat64-prefix netblock: %s", nat64_prefix);
return 0;
}
- if (!addr_is_ip6(&iter_env->nat64_prefix_addr,
- iter_env->nat64_prefix_addrlen)) {
- log_err("nat64_prefix is not IPv6: %s", cfg->nat64_prefix);
+ if(!addr_is_ip6(&iter_env->nat64_prefix_addr,
+ iter_env->nat64_prefix_addrlen)) {
+ log_err("nat64-prefix is not IPv6: %s", cfg->nat64_prefix);
return 0;
}
- if (iter_env->nat64_prefix_net != 32 && iter_env->nat64_prefix_net != 40 &&
- iter_env->nat64_prefix_net != 48 && iter_env->nat64_prefix_net != 56 &&
- iter_env->nat64_prefix_net != 64 && iter_env->nat64_prefix_net != 96 ) {
- log_err("dns64-prefix length it not 32, 40, 48, 56, 64 or 96: %s",
+ if(!prefixnet_is_nat64(iter_env->nat64_prefix_net)) {
+ log_err("nat64-prefix length it not 32, 40, 48, 56, 64 or 96: %s",
nat64_prefix);
return 0;
}
int
iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
- struct delegpt* dp, int supports_ipv4, int supports_ipv6, int use_nat64)
+ struct delegpt* dp, int supports_ipv4, int supports_ipv6,
+ int use_nat64)
{
struct delegpt_ns* ns;
struct delegpt_addr* a;
- if (supports_ipv6 && use_nat64)
+ if(supports_ipv6 && use_nat64)
supports_ipv4 = 1;
/* check:
* if not, then the IPv4 addresses are useless.
* @param supports_ipv6: if we support ipv6 for lookups to the target.
* if not, then the IPv6 addresses are useless.
+ * @param use_nat64: if we support NAT64 for lookups to the target.
+ * if yes, IPv4 addresses are useful even if we don't support IPv4.
* @return true if dp is useless.
*/
-int iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
+int iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
struct delegpt* dp, int supports_ipv4, int supports_ipv6,
int use_nat64);
/* see if this dp not useless.
* It is useless if:
- * o all NS items are required glue.
+ * o all NS items are required glue.
* or the query is for NS item that is required glue.
* o no addresses are provided.
* o RD qflag is on.
* Instead, go up one level, and try to get even further
- * If the root was useless, use safety belt information.
+ * If the root was useless, use safety belt information.
* Only check cache returns, because replies for servers
* could be useless but lead to loops (bumping into the
* same server reply) if useless-checked.
*/
- if(iter_dp_is_useless(&qstate->qinfo, qstate->query_flags,
+ if(iter_dp_is_useless(&qstate->qinfo, qstate->query_flags,
iq->dp, ie->supports_ipv4, ie->supports_ipv6,
ie->use_nat64)) {
struct delegpt* retdp = NULL;
break;
}
/* Send the A request. */
- if(ie->supports_ipv4 &&
+ if((ie->supports_ipv4 || ie->use_nat64) &&
((ns->lame && !ns->done_pside4) ||
(!ns->lame && !ns->got4))) {
if(!generate_target_query(qstate, iq, id,
int tf_policy;
struct delegpt_addr* target;
struct outbound_entry* outq;
+ struct sockaddr_storage real_addr;
+ socklen_t real_addrlen;
int auth_fallback = 0;
uint8_t* qout_orig = NULL;
size_t qout_orig_len = 0;
/* We have a valid target. */
if(verbosity >= VERB_QUERY) {
log_query_info(VERB_QUERY, "sending query:", &iq->qinfo_out);
- log_name_addr(VERB_QUERY, "sending to target:", iq->dp->name,
+ log_name_addr(VERB_QUERY, "sending to target:", iq->dp->name,
&target->addr, target->addrlen);
verbose(VERB_ALGO, "dnssec status: %s%s",
iq->dnssec_expected?"expected": "not expected",
iq->dnssec_lame_query?" but lame_query anyway": "");
}
- struct sockaddr_storage real_addr = target->addr;
- socklen_t real_addrlen = target->addrlen;
+ real_addr = target->addr;
+ real_addrlen = target->addrlen;
- if (ie->use_nat64 && real_addr.ss_family == AF_INET) {
- struct sockaddr_in *sin = (struct sockaddr_in *)&target->addr;
- struct sockaddr_in6 *sin6;
- int plen = ie->nat64_prefix_net;
- uint8_t *v4_byte;
-
- real_addr = ie->nat64_prefix_addr;
- real_addrlen = ie->nat64_prefix_addrlen;
-
- sin6 = (struct sockaddr_in6 *)&real_addr;
- sin6->sin6_flowinfo = 0;
- sin6->sin6_port = sin->sin_port;
-
- /* config validation enforces these prefix lengths too */
- log_assert(plen == 32 || plen == 40 || plen == 48 || plen == 56
- || plen == 64 || plen == 96);
- plen = plen / 8;
-
- v4_byte = (uint8_t *)&sin->sin_addr.s_addr;
- for (int i = 0; i < 4; i++) {
- if (plen == 8)
- /* bits 64...72 are MBZ */
- sin6->sin6_addr.s6_addr[plen++] = 0;
-
- sin6->sin6_addr.s6_addr[plen++] = *v4_byte++;
- }
-
- log_name_addr(VERB_QUERY, "applied NAT64:", iq->dp->name,
- &real_addr, real_addrlen);
+ if(ie->use_nat64 && target->addr.ss_family == AF_INET) {
+ addr_to_nat64(&target->addr, &ie->nat64_prefix_addr,
+ ie->nat64_prefix_addrlen, ie->nat64_prefix_net,
+ &real_addr, &real_addrlen);
+ log_name_addr(VERB_QUERY, "applied NAT64:",
+ iq->dp->name, &real_addr, real_addrlen);
}
fptr_ok(fptr_whitelist_modenv_send_query(qstate->env->send_query));
return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
}
log_addr(VERB_QUERY, "error sending query to auth server",
- &target->addr, target->addrlen);
+ &real_addr, real_addrlen);
if(qstate->env->cfg->qname_minimisation)
iq->minimisation_state = SKIP_MINIMISE_STATE;
return next_state(iq, QUERYTARGETS_STATE);
#define RTT_BAND 400
/**
- * Global state for the iterator.
+ * Global state for the iterator.
*/
struct iter_env {
/** A flag to indicate whether or not we have an IPv6 route */
cfg->chrootdir, cfg);
}
#endif
- /* remove chroot setting so that modules are not stripping pathnames*/
+ /* remove chroot setting so that modules are not stripping pathnames */
free(cfg->chrootdir);
cfg->chrootdir = NULL;
do-nat64: yes
nat64-prefix: 2001:db8:1234::/96
target-fetch-policy: "0 0 0 0 0"
+ do-ip4: no
stub-zone:
name: "."
free(cfg->server_cert_file);
free(cfg->control_key_file);
free(cfg->control_cert_file);
+ free(cfg->nat64_prefix);
free(cfg->dns64_prefix);
config_delstrlist(cfg->dns64_ignore_aaaa);
free(cfg->dnstap_socket_path);
return match;
}
-void
-addr_to_str(struct sockaddr_storage* addr, socklen_t addrlen,
+void
+addr_to_str(struct sockaddr_storage* addr, socklen_t addrlen,
char* buf, size_t len)
{
int af = (int)((struct sockaddr_in*)addr)->sin_family;
}
}
-int
+int
+prefixnet_is_nat64(int prefixnet)
+{
+ return (prefixnet == 32 || prefixnet == 40 ||
+ prefixnet == 48 || prefixnet == 56 ||
+ prefixnet == 64 || prefixnet == 96);
+}
+
+void
+addr_to_nat64(const struct sockaddr_storage* addr,
+ const struct sockaddr_storage* nat64_prefix,
+ socklen_t nat64_prefixlen, int nat64_prefixnet,
+ struct sockaddr_storage* nat64_addr, socklen_t* nat64_addrlen)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+ struct sockaddr_in6 *sin6;
+ uint8_t *v4_byte;
+
+ /* This needs to be checked by the caller */
+ log_assert(addr->ss_family == AF_INET);
+ /* Current usage is only from config values; prefix lengths enforced
+ * during config validation */
+ log_assert(prefixnet_is_nat64(nat64_prefixnet));
+
+ *nat64_addr = *nat64_prefix;
+ *nat64_addrlen = nat64_prefixlen;
+
+ sin6 = (struct sockaddr_in6 *)nat64_addr;
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_port = sin->sin_port;
+
+ nat64_prefixnet = nat64_prefixnet / 8;
+
+ v4_byte = (uint8_t *)&sin->sin_addr.s_addr;
+ for(int i = 0; i < 4; i++) {
+ if(nat64_prefixnet == 8) {
+ /* bits 64...71 are MBZ */
+ sin6->sin6_addr.s6_addr[nat64_prefixnet++] = 0;
+ }
+ sin6->sin6_addr.s6_addr[nat64_prefixnet++] = *v4_byte++;
+ }
+}
+
+int
addr_is_ip4mapped(struct sockaddr_storage* addr, socklen_t addrlen)
{
/* prefix for ipv4 into ipv6 mapping is ::ffff:x.x.x.x */
void addr_to_str(struct sockaddr_storage* addr, socklen_t addrlen,
char* buf, size_t len);
+/**
+ * Check if the prefix network length is one of the allowed 32, 40, 48, 56, 64,
+ * or 96.
+ * @param prefixnet: prefix network length to check.
+ * @return 1 on success, 0 on failure.
+ */
+int prefixnet_is_nat64(int prefixnet);
+
+/**
+ * Create a NAT64 address from a given address (needs to be IPv4) and a given
+ * NAT64 prefix. The NAT64 prefix net needs to be one of 32, 40, 48, 56, 64, 96.
+ * @param addr: IPv4 address.
+ * @param nat64_prefix: NAT64 prefix.
+ * @param nat64_prefixlen: NAT64 prefix len.
+ * @param nat64_prefixnet: NAT64 prefix mask.
+ * @param nat64_addr: the resulting NAT64 address.
+ * @param nat64_addrlen: the resulting NAT64 address length.
+ * @return: 1 on success, 0 on input error.
+ */
+void addr_to_nat64(const struct sockaddr_storage* addr,
+ const struct sockaddr_storage* nat64_prefix,
+ socklen_t nat64_prefixlen, int nat64_prefixnet,
+ struct sockaddr_storage* nat64_addr, socklen_t* nat64_addrlen);
+
/**
* See if sockaddr is an ipv6 mapped ipv4 address, "::ffff:0.0.0.0"
* @param addr: address