]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- For #722: Minor fixes, formatting and refactoring.
authorGeorge Thessalonikefs <george@nlnetlabs.nl>
Mon, 1 May 2023 16:23:13 +0000 (18:23 +0200)
committerGeorge Thessalonikefs <george@nlnetlabs.nl>
Mon, 1 May 2023 16:23:13 +0000 (18:23 +0200)
12 files changed:
dns64/dns64.c
doc/example.conf.in
doc/unbound.conf.5.in
iterator/iter_utils.c
iterator/iter_utils.h
iterator/iterator.c
iterator/iterator.h
smallapp/unbound-checkconf.c
testdata/iter_nat64_prefix.rpl
util/config_file.c
util/net_help.c
util/net_help.h

index 4b98b609e2d30994f714a4b2d2ae9f39c344ecbc..cd53df27883bfcf1e8e66a8c6ac1e4f8b0ea406c 100644 (file)
@@ -59,7 +59,7 @@
  ******************************************************************************/
 
 /**
- * This is the default DNS64 prefix that is used whenhe 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";
index 279bcccdd1b0706ec854bac3ebb11c14de9edb39..0980212e123dd32649b49c001e25bb9ef435b05c 100644 (file)
@@ -248,6 +248,8 @@ server:
        # 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.
index 9e2edaba6887caf8cbce183289713e45d7557d10..76ffde9bd2fdf3c2edfa6803a22d3873583f518d 100644 (file)
@@ -2318,12 +2318,15 @@ NAT64 operation allows using a NAT64 prefix for outbound requests to IPv4-only
 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
index c8c41a19657f53e077a92ea22955eea0b037bbad..961f76241eb6edc7020da970b9c160205fdad464 100644 (file)
@@ -180,25 +180,23 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
        }
 
        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;
        }
@@ -780,12 +778,13 @@ iter_mark_pside_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
 
 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:
index 48ea8316be69fa66eabd4e1f81935bd556cc1bae..fa860fa682fc3a139db0739a17467a91db48a747 100644 (file)
@@ -189,9 +189,11 @@ void iter_mark_pside_cycle_targets(struct module_qstate* qstate,
  *     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);
 
index 3e0ee035e14592b05eb35b94ab0e0b03d0dae948..e7365c566d224331202b817158c920f3b4d3f805 100644 (file)
@@ -1557,17 +1557,17 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
 
                /* 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;
@@ -1930,7 +1930,7 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
                                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, 
@@ -2257,6 +2257,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
        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;
@@ -2803,45 +2805,22 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
        /* 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));
@@ -2871,7 +2850,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
                        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);
index 9171ff60e29d80b85fce38ee0912bc4402244cba..74299e05a23710e95e2f43a9b7c0271d9b05e45f 100644 (file)
@@ -103,7 +103,7 @@ extern int BLACKLIST_PENALTY;
 #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 */
index f850469bab1b2b3f83252871335c7d4fcbc3e5f4..ff80437112e4f45e122364d68ef95ebcdadf4ac1 100644 (file)
@@ -714,7 +714,7 @@ morechecks(struct config_file* cfg)
                        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;
 
index afc317e85f2529727adeb15cf662b9239eebfa1f..ecb6508dcf55a9d218add9e9660daecfb0656093 100644 (file)
@@ -3,6 +3,7 @@ server:
        do-nat64: yes
        nat64-prefix: 2001:db8:1234::/96
        target-fetch-policy: "0 0 0 0 0"
+       do-ip4: no
 
 stub-zone:
        name: "."
index a04c8cf091f886623d4e091421994ba3590116c5..54bd5f952e8785da20845b9ae5a968026d5b0e60 100644 (file)
@@ -1648,6 +1648,7 @@ config_delete(struct config_file* cfg)
        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);
index de2d771bdc4ddb53c8b8ada345104a2962edc123..e559c9b2fa6a1a5c7ded02606831e44b387da319 100644 (file)
@@ -779,8 +779,8 @@ addr_in_common(struct sockaddr_storage* addr1, int net1,
        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;
@@ -792,7 +792,50 @@ addr_to_str(struct sockaddr_storage* addr, socklen_t addrlen,
        }
 }
 
-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 */
index f1881b3ed0ca7e007dc432dcded76eb1aab06250..e931ed8a67f2be4b3ac912b0e4a1ceee4549a1fa 100644 (file)
@@ -331,6 +331,30 @@ int addr_in_common(struct sockaddr_storage* addr1, int net1,
 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