Skip to content

Commit

Permalink
NAT64 support
Browse files Browse the repository at this point in the history
This implements NLnetLabs#721.  It's not really polished but does work.

TODO:
- clean up code formatting
- make NAT64 prefix configurable instead of hardcoding it
  • Loading branch information
eqvinox committed Jul 23, 2022
1 parent f993ffb commit 7fa39d6
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 17 deletions.
3 changes: 2 additions & 1 deletion daemon/cachedump.c
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,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 "
Expand Down
10 changes: 8 additions & 2 deletions iterator/iter_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
}
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;
}
Expand Down Expand Up @@ -238,7 +239,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 */
Expand Down Expand Up @@ -745,10 +747,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.
Expand Down
3 changes: 2 additions & 1 deletion iterator/iter_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,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
Expand Down
38 changes: 30 additions & 8 deletions iterator/iterator.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
}
delegpt_mark_neg(dpns, qstate->qinfo.qtype);
dpns->resolved = 1; /* mark as failed */
if((dpns->got4 == 2 || !ie->supports_ipv4) &&
if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->use_nat64)) &&
(dpns->got6 == 2 || !ie->supports_ipv6)) {
target_count_increase_nx(super_iq, 1);
}
Expand Down Expand Up @@ -1559,7 +1559,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) {
Expand Down Expand Up @@ -2061,14 +2062,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 */
Expand All @@ -2084,7 +2085,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
ns->done_pside6 = 1;
query_count++;
}
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,
Expand Down Expand Up @@ -2351,7 +2352,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);

Expand Down Expand Up @@ -2742,6 +2743,27 @@ 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 = (struct sockaddr_in6 *)&real_addr;

sin6->sin6_family = AF_INET6;
sin6->sin6_flowinfo = 0;
sin6->sin6_port = sin->sin_port;
sin6->sin6_addr.s6_addr32[0] = htonl(0x0064ff9b);
sin6->sin6_addr.s6_addr32[1] = 0;
sin6->sin6_addr.s6_addr32[2] = 0;
sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
real_addrlen = sizeof(*sin6);

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),
Expand All @@ -2752,7 +2774,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),
Expand Down Expand Up @@ -3490,7 +3512,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
verbose(VERB_ALGO, "iterator TargetResponse failed");
delegpt_mark_neg(dpns, qstate->qinfo.qtype);
dpns->resolved = 1; /* fail the target */
if((dpns->got4 == 2 || !ie->supports_ipv4) &&
if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->use_nat64)) &&
(dpns->got6 == 2 || !ie->supports_ipv6) &&
/* do not count cached answers */
(qstate->reply_origin && qstate->reply_origin->len != 0)) {
Expand Down
3 changes: 3 additions & 0 deletions iterator/iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ 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;

/** A set of inetaddrs that should never be queried. */
struct iter_donotq* donotq;

Expand Down
5 changes: 3 additions & 2 deletions pythonmod/interface.i
Original file line number Diff line number Diff line change
Expand Up @@ -1377,7 +1377,7 @@ struct delegpt* dns_cache_find_delegation(struct module_env* env,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
struct regional* region, struct dns_msg** msg, uint32_t timenow);
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);

Expand Down Expand Up @@ -1408,7 +1408,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;
Expand Down
2 changes: 2 additions & 0 deletions util/config_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
1 change: 1 addition & 0 deletions util/configlexer.lex
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down
15 changes: 12 additions & 3 deletions util/configparser.y
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,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
Expand Down Expand Up @@ -216,8 +216,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 |
Expand Down Expand Up @@ -827,6 +827,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));
Expand Down

0 comments on commit 7fa39d6

Please sign in to comment.