This implements #721. Includes documentation and some very basic tests.
Please refer to doc for further detail.
/* 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 "
+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.
;; 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.
# 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
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<yes or no>\fR
+Use NAT64 to reach IPv4-only servers. 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.
.SS "DNSCrypt Options"
.LP
The
/** 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)
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))
}
}
+
+ 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;
}
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 */
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.
* @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
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);
* 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) {
/* 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 */
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,
}
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);
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;
+ 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);
+ }
+
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),
!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),
} 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 */
/** 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;
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);
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;
--- /dev/null
+; 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
--- /dev/null
+; 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
--- /dev/null
+; config options
+server:
+ do-nat64: yes
+ nat64-prefix: 2001:db8:2345::/48
+ target-fetch-policy: "0 0 0 0 0"
+
+stub-zone:
+ name: "."
+ stub-addr: 2001:db8::1
+CONFIG_END
+
+SCENARIO_BEGIN Test NAT64 transport, this time with /48 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:2345:c000:0002:0100::
+
+; 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
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. */
/** 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 */
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) }
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) }
%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
%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
| ;
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 |
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 |
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));
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;