diff --git a/daemon/cachedump.c b/daemon/cachedump.c index baf8008ea8..3c5f976742 100644 --- a/daemon/cachedump.c +++ b/daemon/cachedump.c @@ -859,7 +859,8 @@ int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm, /* go up? */ if(iter_dp_is_useless(&qinfo, BIT_RD, dp, (worker->env.cfg->do_ip4 && worker->back->num_ip4 != 0), - (worker->env.cfg->do_ip6 && worker->back->num_ip6 != 0))) { + (worker->env.cfg->do_ip6 && worker->back->num_ip6 != 0), + worker->env.cfg->do_nat64)) { print_dp_main(ssl, dp, msg); print_dp_details(ssl, worker, dp); if(!ssl_printf(ssl, "cache delegation was " diff --git a/doc/Changelog b/doc/Changelog index 32e7ae8ae9..2a8bf55305 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,6 @@ +5 November 2022: equinox (David Lamparter) + - Implemented NAT64 support + 21 October 2022: George - Merge #767 from jonathangray: consistently use IPv4/IPv6 in unbound.conf.5. diff --git a/doc/README.DNS64 b/doc/README.DNS64 index 49446ac575..71e2310ed9 100644 --- a/doc/README.DNS64 +++ b/doc/README.DNS64 @@ -28,3 +28,23 @@ prefix. For example: ;; ANSWER SECTION: jazz-v4.viagenie.ca. 86400 IN AAAA 64:ff9b::ce7b:1f02 + +NAT64 support was added by David Lamparter in 2022; license(s) of the +surrounding code apply. Note that NAT64 is closely related but functionally +orthogonal to DNS64; it allows Unbound to send outgoing queries to IPv4-only +servers over IPv6 through the configured NAT64 prefix. This allows running +an Unbound instance on an IPv6-only host without breaking every single domain +that only has IPv4 servers. Whether that Unbound instance also does DNS64 is +an independent choice. + +To enable NAT64 in Unbound, add to unbound.conf's "server" section: + + do-nat64: yes + +The NAT64 prefix defaults to the DNS64 prefix, which in turn defaults to the +standard 64:FF9B::/96 prefix. You can reconfigure it with: + + nat64-prefix: 64:FF9B::/96 + +To test NAT64 operation, pick a domain that only has IPv4 reachability for its +nameservers and try resolving any names in that domain. diff --git a/doc/example.conf.in b/doc/example.conf.in index c21246e4c3..e45f497bb3 100644 --- a/doc/example.conf.in +++ b/doc/example.conf.in @@ -229,6 +229,16 @@ server: # Enable IPv6, "yes" or "no". # do-ip6: yes + # If running unbound on an IPv6-only host, domains that only have + # IPv4 servers would become unresolveable. If NAT64 is available in + # 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. + # do-nat64: no + + # NAT64 prefix. Defaults to using dns64-prefix value. + # nat64-prefix: 64:ff9b::0/96 + # Enable UDP, "yes" or "no". # do-udp: yes diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in index d829008a71..2f02c2640e 100644 --- a/doc/unbound.conf.5.in +++ b/doc/unbound.conf.5.in @@ -2268,6 +2268,18 @@ List domain for which the AAAA records are ignored and the A record is used by dns64 processing instead. Can be entered multiple times, list a new domain for which it applies, one per line. Applies also to names underneath the name given. +.SS "NAT64 Operation" +.LP +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\fR +Use NAT64 to reach IPv4-only servers. Default no. +.TP +.B nat64\-prefix: \fI\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. .SS "DNSCrypt Options" .LP The diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 56b184a02f..98fac8186a 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -71,6 +71,11 @@ /** time when nameserver glue is said to be 'recent' */ #define SUSPICION_RECENT_EXPIRY 86400 +/** if NAT64 is enabled and no NAT64 prefix is configured, first fall back to + * DNS64 prefix. If that is not configured, fall back to this default value. + */ +static const char DEFAULT_NAT64_PREFIX[] = "64:ff9b::/96"; + /** fillup fetch policy array */ static void fetch_fill(struct iter_env* ie, const char* str) @@ -142,6 +147,7 @@ caps_white_apply_cfg(rbtree_type* ntree, struct config_file* cfg) int iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg) { + const char *nat64_prefix; int i; /* target fetch policy */ if(!read_fetch_policy(iter_env, cfg->target_fetch_policy)) @@ -172,8 +178,34 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg) } } + + nat64_prefix = cfg->nat64_prefix; + if (!nat64_prefix) + nat64_prefix = cfg->dns64_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)) { + 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); + 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", + nat64_prefix); + return 0; + } + iter_env->supports_ipv6 = cfg->do_ip6; iter_env->supports_ipv4 = cfg->do_ip4; + iter_env->use_nat64 = cfg->do_nat64; iter_env->outbound_msg_retry = cfg->outbound_msg_retry; return 1; } @@ -238,7 +270,8 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env, if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr, a->addrlen)) { return -1; /* there is no ip6 available */ } - if(!iter_env->supports_ipv4 && !addr_is_ip6(&a->addr, a->addrlen)) { + if(!iter_env->supports_ipv4 && !iter_env->use_nat64 && + !addr_is_ip6(&a->addr, a->addrlen)) { return -1; /* there is no ip4 available */ } /* check lameness - need zone , class info */ @@ -745,10 +778,14 @@ 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) + 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) + supports_ipv4 = 1; + /* check: * o RD qflag is on. * o no addresses are provided. diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index 850be96a6e..48ea8316be 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -192,7 +192,8 @@ void iter_mark_pside_cycle_targets(struct module_qstate* qstate, * @return true if dp is useless. */ int iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags, - struct delegpt* dp, int supports_ipv4, int supports_ipv6); + struct delegpt* dp, int supports_ipv4, int supports_ipv6, + int use_nat64); /** * See if qname has DNSSEC needs. This is true if there is a trust anchor above diff --git a/iterator/iterator.c b/iterator/iterator.c index 9c8d256d36..c4aeeb05f0 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -255,7 +255,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super) log_err("out of memory adding missing"); } delegpt_mark_neg(dpns, qstate->qinfo.qtype); - if((dpns->got4 == 2 || !ie->supports_ipv4) && + if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->use_nat64)) && (dpns->got6 == 2 || !ie->supports_ipv6)) { dpns->resolved = 1; /* mark as failed */ target_count_increase_nx(super_iq, 1); @@ -1571,7 +1571,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, * same server reply) if useless-checked. */ if(iter_dp_is_useless(&qstate->qinfo, qstate->query_flags, - iq->dp, ie->supports_ipv4, ie->supports_ipv6)) { + iq->dp, ie->supports_ipv4, ie->supports_ipv6, + ie->use_nat64)) { struct delegpt* retdp = NULL; if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, iq->qchase.qclass, &retdp)) { if(retdp) { @@ -2085,14 +2086,14 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, /* if this nameserver is at a delegation point, but that * delegation point is a stub and we cannot go higher, skip*/ if( ((ie->supports_ipv6 && !ns->done_pside6) || - (ie->supports_ipv4 && !ns->done_pside4)) && + ((ie->supports_ipv4 || ie->use_nat64) && !ns->done_pside4)) && !can_have_last_resort(qstate->env, ns->name, ns->namelen, iq->qchase.qclass, NULL)) { log_nametypeclass(VERB_ALGO, "cannot pside lookup ns " "because it is also a stub/forward,", ns->name, LDNS_RR_TYPE_NS, iq->qchase.qclass); if(ie->supports_ipv6) ns->done_pside6 = 1; - if(ie->supports_ipv4) ns->done_pside4 = 1; + if(ie->supports_ipv4 || ie->use_nat64) ns->done_pside4 = 1; continue; } /* query for parent-side A and AAAA for nameservers */ @@ -2117,7 +2118,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, return 0; } } - if(ie->supports_ipv4 && !ns->done_pside4) { + if((ie->supports_ipv4 || ie->use_nat64) && !ns->done_pside4) { /* Send the A request. */ if(!generate_parentside_target_query(qstate, iq, id, ns->name, ns->namelen, @@ -2384,7 +2385,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, } if(!ie->supports_ipv6) delegpt_no_ipv6(iq->dp); - if(!ie->supports_ipv4) + if(!ie->supports_ipv4 && !ie->use_nat64) delegpt_no_ipv4(iq->dp); delegpt_log(VERB_ALGO, iq->dp); @@ -2811,6 +2812,32 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, 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; + + if (ie->use_nat64 && real_addr.ss_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)&target->addr; + struct sockaddr_in6 *sin6; + + real_addr = ie->nat64_prefix_addr; + real_addrlen = ie->nat64_prefix_addrlen; + + /* - NAT64 prefix length really doesn't matter at all, + * it's just a bunch of zero padding + * - config validation requires the NAT64 prefix to be /96 + * or shorter/larget, so s6_addr32[3] won't ever overwrite + * any prefix bits + */ + sin6 = (struct sockaddr_in6 *)&real_addr; + sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; + sin6->sin6_flowinfo = 0; + sin6->sin6_port = sin->sin_port; + + 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)); outq = (*qstate->env->send_query)(&iq->qinfo_out, iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), @@ -2821,7 +2848,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, !qstate->blacklist&&(!iter_qname_indicates_dnssec(qstate->env, &iq->qinfo_out)||target->attempts==1)?0:BIT_CD), iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted( - ie, iq), sq_check_ratelimit, &target->addr, target->addrlen, + ie, iq), sq_check_ratelimit, &real_addr, real_addrlen, iq->dp->name, iq->dp->namelen, (iq->dp->tcp_upstream || qstate->env->cfg->tcp_upstream), (iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream), @@ -3564,7 +3591,7 @@ processTargetResponse(struct module_qstate* qstate, int id, } else { verbose(VERB_ALGO, "iterator TargetResponse failed"); delegpt_mark_neg(dpns, qstate->qinfo.qtype); - if((dpns->got4 == 2 || !ie->supports_ipv4) && + if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->use_nat64)) && (dpns->got6 == 2 || !ie->supports_ipv6)) { dpns->resolved = 1; /* fail the target */ /* do not count cached answers */ diff --git a/iterator/iterator.h b/iterator/iterator.h index 18d3270a0c..3f078cfe58 100644 --- a/iterator/iterator.h +++ b/iterator/iterator.h @@ -117,6 +117,18 @@ struct iter_env { /** A flag to indicate whether or not we have an IPv4 route */ int supports_ipv4; + /** A flag to locally apply NAT64 to make IPv4 addrs into IPv6 */ + int use_nat64; + + /** NAT64 prefix address, cf. dns64_env->prefix_addr */ + struct sockaddr_storage nat64_prefix_addr; + + /** sizeof(sockaddr_in6) */ + socklen_t nat64_prefix_addrlen; + + /** CIDR mask length of NAT64 prefix */ + int nat64_prefix_net; + /** A set of inetaddrs that should never be queried. */ struct iter_donotq* donotq; diff --git a/pythonmod/interface.i b/pythonmod/interface.i index df8514b479..17bf022739 100644 --- a/pythonmod/interface.i +++ b/pythonmod/interface.i @@ -1378,7 +1378,7 @@ struct delegpt* dns_cache_find_delegation(struct module_env* env, struct regional* region, struct dns_msg** msg, uint32_t timenow, int noexpiredabove, uint8_t* expiretop, size_t expiretoplen); int iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags, - struct delegpt* dp, int supports_ipv4, int supports_ipv6); + struct delegpt* dp, int supports_ipv4, int supports_ipv6, int use_nat64); struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints, uint8_t* qname, uint16_t qclass, struct delegpt* dp); @@ -1409,7 +1409,8 @@ struct delegpt* find_delegation(struct module_qstate* qstate, char *nm, size_t n if(!dp) return NULL; if(iter_dp_is_useless(&qinfo, BIT_RD, dp, - qstate->env->cfg->do_ip4, qstate->env->cfg->do_ip6)) { + qstate->env->cfg->do_ip4, qstate->env->cfg->do_ip6, + qstate->env->cfg->do_nat64)) { if (dname_is_root((uint8_t*)nm)) return NULL; nm = (char*)dp->name; diff --git a/testdata/iter_nat64.rpl b/testdata/iter_nat64.rpl new file mode 100644 index 0000000000..dde0a25596 --- /dev/null +++ b/testdata/iter_nat64.rpl @@ -0,0 +1,117 @@ +; config options +server: + do-nat64: yes + target-fetch-policy: "0 0 0 0 0" + +stub-zone: + name: "." + stub-addr: 2001:db8::1 +CONFIG_END + +SCENARIO_BEGIN Test NAT64 transport for a v4-only server. + +RANGE_BEGIN 0 100 + ADDRESS 2001:db8::1 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS FAKE.ROOT. +SECTION ADDITIONAL +FAKE.ROOT. IN AAAA 2001:db8::1 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +v4only. IN NS +SECTION AUTHORITY +v4only. IN NS ns.v4only. +SECTION ADDITIONAL +ns.v4only. IN A 192.0.2.1 +ENTRY_END + +RANGE_END + +; replies from NS over "NAT64" + +RANGE_BEGIN 0 100 + ADDRESS 64:ff9b::c000:0201 + +; A over NAT64 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +ns.v4only. IN A +SECTION ANSWER +ns.v4only. IN A 192.0.2.1 +SECTION AUTHORITY +v4only. IN NS ns.v4only. +ENTRY_END + +; no AAAA +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +ns.v4only. IN AAAA +SECTION AUTHORITY +v4only. IN NS ns.v4only. +SECTION ADDITIONAL +ns.v4only. IN A 192.0.2.1 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +v4only. IN NS +SECTION ANSWER +v4only. IN NS ns.v4only. +SECTION ADDITIONAL +ns.v4only. IN A 192.0.2.1 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +test.v4only. IN A +SECTION ANSWER +test.v4only. IN A 192.0.2.2 +SECTION AUTHORITY +v4only. IN NS ns.v4only. +SECTION ADDITIONAL +ns.v4only. IN A 192.0.2.1 +ENTRY_END + +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +test.v4only. IN A +ENTRY_END + +STEP 20 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +test.v4only. IN A +SECTION ANSWER +test.v4only. IN A 192.0.2.2 +ENTRY_END + +SCENARIO_END diff --git a/testdata/iter_nat64_prefix.rpl b/testdata/iter_nat64_prefix.rpl new file mode 100644 index 0000000000..afc317e85f --- /dev/null +++ b/testdata/iter_nat64_prefix.rpl @@ -0,0 +1,118 @@ +; config options +server: + do-nat64: yes + nat64-prefix: 2001:db8:1234::/96 + target-fetch-policy: "0 0 0 0 0" + +stub-zone: + name: "." + stub-addr: 2001:db8::1 +CONFIG_END + +SCENARIO_BEGIN Test NAT64 transport for a v4-only server, custom NAT64 prefix. + +RANGE_BEGIN 0 100 + ADDRESS 2001:db8::1 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS FAKE.ROOT. +SECTION ADDITIONAL +FAKE.ROOT. IN AAAA 2001:db8::1 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +v4only. IN NS +SECTION AUTHORITY +v4only. IN NS ns.v4only. +SECTION ADDITIONAL +ns.v4only. IN A 192.0.2.1 +ENTRY_END + +RANGE_END + +; replies from NS over "NAT64" + +RANGE_BEGIN 0 100 + ADDRESS 2001:db8:1234::c000:0201 + +; A over NAT64 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +ns.v4only. IN A +SECTION ANSWER +ns.v4only. IN A 192.0.2.1 +SECTION AUTHORITY +v4only. IN NS ns.v4only. +ENTRY_END + +; no AAAA +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +ns.v4only. IN AAAA +SECTION AUTHORITY +v4only. IN NS ns.v4only. +SECTION ADDITIONAL +ns.v4only. IN A 192.0.2.1 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +v4only. IN NS +SECTION ANSWER +v4only. IN NS ns.v4only. +SECTION ADDITIONAL +ns.v4only. IN A 192.0.2.1 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY AA QR NOERROR +SECTION QUESTION +test.v4only. IN A +SECTION ANSWER +test.v4only. IN A 192.0.2.2 +SECTION AUTHORITY +v4only. IN NS ns.v4only. +SECTION ADDITIONAL +ns.v4only. IN A 192.0.2.1 +ENTRY_END + +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +test.v4only. IN A +ENTRY_END + +STEP 20 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA NOERROR +SECTION QUESTION +test.v4only. IN A +SECTION ANSWER +test.v4only. IN A 192.0.2.2 +ENTRY_END + +SCENARIO_END diff --git a/util/config_file.h b/util/config_file.h index b1406913a8..7f24ddc108 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -86,6 +86,8 @@ struct config_file { int do_ip4; /** do ip6 query support. */ int do_ip6; + /** do nat64 on queries */ + int do_nat64; /** prefer ip4 upstream queries. */ int prefer_ip4; /** prefer ip6 upstream queries. */ @@ -533,6 +535,9 @@ struct config_file { /** ignore AAAAs for these domain names and use A record anyway */ struct config_strlist* dns64_ignore_aaaa; + /* NAT64 prefix; if unset defaults to dns64_prefix */ + char* nat64_prefix; + /** true to enable dnstap support */ int dnstap; /** using bidirectional frame streams if true */ diff --git a/util/configlexer.lex b/util/configlexer.lex index 09e314b211..e71ffa7ca6 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -227,6 +227,7 @@ outgoing-num-tcp{COLON} { YDVAR(1, VAR_OUTGOING_NUM_TCP) } incoming-num-tcp{COLON} { YDVAR(1, VAR_INCOMING_NUM_TCP) } do-ip4{COLON} { YDVAR(1, VAR_DO_IP4) } do-ip6{COLON} { YDVAR(1, VAR_DO_IP6) } +do-nat64{COLON} { YDVAR(1, VAR_DO_NAT64) } prefer-ip4{COLON} { YDVAR(1, VAR_PREFER_IP4) } prefer-ip6{COLON} { YDVAR(1, VAR_PREFER_IP6) } do-udp{COLON} { YDVAR(1, VAR_DO_UDP) } @@ -461,6 +462,7 @@ max-udp-size{COLON} { YDVAR(1, VAR_MAX_UDP_SIZE) } dns64-prefix{COLON} { YDVAR(1, VAR_DNS64_PREFIX) } dns64-synthall{COLON} { YDVAR(1, VAR_DNS64_SYNTHALL) } dns64-ignore-aaaa{COLON} { YDVAR(1, VAR_DNS64_IGNORE_AAAA) } +nat64-prefix{COLON} { YDVAR(1, VAR_NAT64_PREFIX) } define-tag{COLON} { YDVAR(1, VAR_DEFINE_TAG) } local-zone-tag{COLON} { YDVAR(2, VAR_LOCAL_ZONE_TAG) } access-control-tag{COLON} { YDVAR(2, VAR_ACCESS_CONTROL_TAG) } diff --git a/util/configparser.y b/util/configparser.y index 3ecdad2ad2..91f8af0a7f 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -73,7 +73,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_FORCE_TOPLEVEL %token VAR_SERVER VAR_VERBOSITY VAR_NUM_THREADS VAR_PORT %token VAR_OUTGOING_RANGE VAR_INTERFACE VAR_PREFER_IP4 -%token VAR_DO_IP4 VAR_DO_IP6 VAR_PREFER_IP6 VAR_DO_UDP VAR_DO_TCP +%token VAR_DO_IP4 VAR_DO_IP6 VAR_DO_NAT64 VAR_PREFER_IP6 VAR_DO_UDP VAR_DO_TCP %token VAR_TCP_MSS VAR_OUTGOING_TCP_MSS VAR_TCP_IDLE_TIMEOUT %token VAR_EDNS_TCP_KEEPALIVE VAR_EDNS_TCP_KEEPALIVE_TIMEOUT %token VAR_CHROOT VAR_USERNAME VAR_DIRECTORY VAR_LOGFILE VAR_PIDFILE @@ -123,6 +123,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_UNBLOCK_LAN_ZONES VAR_INSECURE_LAN_ZONES %token VAR_INFRA_CACHE_MIN_RTT VAR_INFRA_CACHE_MAX_RTT VAR_INFRA_KEEP_PROBING %token VAR_DNS64_PREFIX VAR_DNS64_SYNTHALL VAR_DNS64_IGNORE_AAAA +%token VAR_NAT64_PREFIX %token VAR_DNSTAP VAR_DNSTAP_ENABLE VAR_DNSTAP_SOCKET_PATH VAR_DNSTAP_IP %token VAR_DNSTAP_TLS VAR_DNSTAP_TLS_SERVER_NAME VAR_DNSTAP_TLS_CERT_BUNDLE %token VAR_DNSTAP_TLS_CLIENT_KEY_FILE VAR_DNSTAP_TLS_CLIENT_CERT_FILE @@ -222,8 +223,8 @@ contents_server: contents_server content_server | ; content_server: server_num_threads | server_verbosity | server_port | server_outgoing_range | server_do_ip4 | - server_do_ip6 | server_prefer_ip4 | server_prefer_ip6 | - server_do_udp | server_do_tcp | + server_do_ip6 | server_do_nat64 | server_prefer_ip4 | + server_prefer_ip6 | server_do_udp | server_do_tcp | server_tcp_mss | server_outgoing_tcp_mss | server_tcp_idle_timeout | server_tcp_keepalive | server_tcp_keepalive_timeout | server_interface | server_chroot | server_username | @@ -273,6 +274,7 @@ content_server: server_num_threads | server_verbosity | server_port | server_so_reuseport | server_delay_close | server_udp_connect | server_unblock_lan_zones | server_insecure_lan_zones | server_dns64_prefix | server_dns64_synthall | server_dns64_ignore_aaaa | + server_nat64_prefix | server_infra_cache_min_rtt | server_infra_cache_max_rtt | server_harden_algo_downgrade | server_ip_transparent | server_ip_ratelimit | server_ratelimit | server_ip_dscp | server_infra_keep_probing | @@ -840,6 +842,15 @@ server_do_ip6: VAR_DO_IP6 STRING_ARG free($2); } ; +server_do_nat64: VAR_DO_NAT64 STRING_ARG + { + OUTYY(("P(server_do_nat64:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->do_nat64 = (strcmp($2, "yes")==0); + free($2); + } + ; server_do_udp: VAR_DO_UDP STRING_ARG { OUTYY(("P(server_do_udp:%s)\n", $2)); @@ -2323,6 +2334,13 @@ server_dns64_ignore_aaaa: VAR_DNS64_IGNORE_AAAA STRING_ARG fatal_exit("out of memory adding dns64-ignore-aaaa"); } ; +server_nat64_prefix: VAR_NAT64_PREFIX STRING_ARG + { + OUTYY(("P(nat64_prefix:%s)\n", $2)); + free(cfg_parser->cfg->nat64_prefix); + cfg_parser->cfg->nat64_prefix = $2; + } + ; server_define_tag: VAR_DEFINE_TAG STRING_ARG { char* p, *s = $2;