diff --git a/CHANGES b/CHANGES index 57875233c8..9d11028159 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +4282. [func] 'dig +[no]mapped' determine whether the use of mapped + IPv4 addresses over IPv6 is permitted or not. The + default is +mapped. [RT #41307] + 4281. [bug] Teach dns_message_totext about BADCOOKIE. [RT #41257] 4280. [performance] Use optimal message sizes to improve compression diff --git a/bin/dig/dig.c b/bin/dig/dig.c index 0ae86b6022..e09cff1513 100644 --- a/bin/dig/dig.c +++ b/bin/dig/dig.c @@ -195,6 +195,7 @@ help(void) { " +[no]identify (ID responders in short answers)\n" " +[no]ignore (Don't revert to TCP for TC responses.)\n" " +[no]keepopen (Keep the TCP socket open between queries)\n" +" +[no]mapped (Allow mapped IPv4 over IPv6)\n" " +[no]multiline (Print records in an expanded format)\n" " +ndots=### (Set search NDOTS value)\n" " +[no]nsid (Request Name Server ID)\n" @@ -1061,8 +1062,18 @@ plus_option(const char *option, isc_boolean_t is_batchfile, keep_open = state; break; case 'm': /* multiline */ - FULLCHECK("multiline"); - multiline = state; + switch (cmd[1]) { + case 'a': + FULLCHECK("mapped"); + lookup->mapped = state; + break; + case 'u': + FULLCHECK("multiline"); + multiline = state; + break; + default: + goto invalid_option; + } break; case 'n': switch (cmd[1]) { @@ -1849,7 +1860,7 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only, if (is_batchfile && !config_only) { addresscount = getaddresses(lookup, &rv[0][1], &result); - if (result != ISC_R_SUCCESS) { + if (addresscount == 0) { fprintf(stderr, "couldn't get address " "for '%s': %s: skipping " "lookup\n", &rv[0][1], @@ -1860,9 +1871,13 @@ parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only, destroy_lookup(lookup); return; } - } else + } else { addresscount = getaddresses(lookup, &rv[0][1], NULL); + if (addresscount == 0) + fatal("no valid addresses for '%s'\n", + &rv[0][1]); + } } else if (rv[0][0] == '+') { plus_option(&rv[0][1], is_batchfile, lookup); diff --git a/bin/dig/dig.docbook b/bin/dig/dig.docbook index 7230935947..33c02430b5 100644 --- a/bin/dig/dig.docbook +++ b/bin/dig/dig.docbook @@ -789,6 +789,16 @@ + + + + + Allow mapped IPv4 over IPv6 addresses to be used. The + default is . + + + + diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 9785e900c1..d7586df42b 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -830,6 +830,7 @@ make_empty_lookup(void) { looknew->ednsopts = NULL; looknew->ednsoptscnt = 0; looknew->ednsneg = ISC_TRUE; + looknew->mapped = ISC_TRUE; looknew->dscp = -1; dns_fixedname_init(&looknew->fdomain); ISC_LINK_INIT(looknew, link); @@ -889,6 +890,7 @@ clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) { looknew->ednsopts = lookold->ednsopts; looknew->ednsoptscnt = lookold->ednsoptscnt; looknew->ednsneg = lookold->ednsneg; + looknew->mapped = lookold->mapped; #ifdef DIG_SIGCHASE looknew->sigchase = lookold->sigchase; #if DIG_SIGCHASE_TD @@ -2840,6 +2842,28 @@ send_tcp_connect(dig_query_t *query) { return; } + if (!l->mapped && isc_sockaddr_pf(&query->sockaddr) == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&query->sockaddr.type.sin6.sin6_addr)) { + isc_netaddr_t netaddr; + char buf[ISC_NETADDR_FORMATSIZE]; + + isc_netaddr_fromsockaddr(&netaddr, &query->sockaddr); + isc_netaddr_format(&netaddr, buf, sizeof(buf)); + printf(";; Skipping mapped address '%s'\n", buf); + + query->waiting_connect = ISC_FALSE; + next = ISC_LIST_NEXT(query, link); + l = query->lookup; + clear_query(query); + if (next == NULL) { + printf(";; No acceptable nameservers\n"); + check_next_lookup(l); + return; + } + send_tcp_connect(next); + return; + } + if (specified_source && (isc_sockaddr_pf(&query->sockaddr) != isc_sockaddr_pf(&bind_address))) { @@ -2876,6 +2900,7 @@ send_tcp_connect(dig_query_t *query) { debug("sockcount=%d", sockcount); if (query->lookup->dscp != -1) isc_socket_dscp(query->sock, query->lookup->dscp); + isc_socket_ipv6only(query->sock, ISC_TF(!query->lookup->mapped)); if (specified_source) result = isc_socket_bind(query->sock, &bind_address, ISC_SOCKET_REUSEADDRESS); @@ -2929,6 +2954,7 @@ send_udp(dig_query_t *query) { dig_lookup_t *l = NULL; isc_result_t result; isc_buffer_t *sendbuf; + dig_query_t *next; debug("send_udp(%p)", query); @@ -2946,6 +2972,25 @@ send_udp(dig_query_t *query) { return; } + if (!l->mapped && + isc_sockaddr_pf(&query->sockaddr) == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&query->sockaddr.type.sin6.sin6_addr)) { + isc_netaddr_t netaddr; + char buf[ISC_NETADDR_FORMATSIZE]; + + isc_netaddr_fromsockaddr(&netaddr, &query->sockaddr); + isc_netaddr_format(&netaddr, buf, sizeof(buf)); + printf(";; Skipping mapped address '%s'\n", buf); + + next = ISC_LIST_NEXT(query, link); + l = query->lookup; + clear_query(query); + if (next == NULL) + printf(";; No acceptable nameservers\n"); + check_next_lookup(l); + return; + } + result = isc_socket_create(socketmgr, isc_sockaddr_pf(&query->sockaddr), isc_sockettype_udp, &query->sock); @@ -2954,6 +2999,8 @@ send_udp(dig_query_t *query) { debug("sockcount=%d", sockcount); if (query->lookup->dscp != -1) isc_socket_dscp(query->sock, query->lookup->dscp); + isc_socket_ipv6only(query->sock, + ISC_TF(!query->lookup->mapped)); if (specified_source) { result = isc_socket_bind(query->sock, &bind_address, ISC_SOCKET_REUSEADDRESS); diff --git a/bin/dig/include/dig/dig.h b/bin/dig/include/dig/dig.h index 478f8377ce..9e2094929c 100644 --- a/bin/dig/include/dig/dig.h +++ b/bin/dig/include/dig/dig.h @@ -136,7 +136,8 @@ struct dig_lookup { badcookie, nsid, /*% Name Server ID (RFC 5001) */ header_only, - ednsneg; + ednsneg, + mapped; #ifdef DIG_SIGCHASE isc_boolean_t sigchase; #if DIG_SIGCHASE_TD diff --git a/bin/tests/system/digdelv/tests.sh b/bin/tests/system/digdelv/tests.sh index 7974df0b17..3e654a6ab1 100644 --- a/bin/tests/system/digdelv/tests.sh +++ b/bin/tests/system/digdelv/tests.sh @@ -202,18 +202,46 @@ if [ -x ${DIG} ] ; then fi n=`expr $n + 1` - echo "I:checking dig @IPv4addr -6 A a.example ($n)" + echo "I:checking dig @IPv4addr -6 +mapped A a.example ($n)" if $TESTSOCK6 fd92:7065:b8e:ffff::2 then ret=0 ret=0 - $DIG $DIGOPTS +tcp @10.53.0.2 -6 A a.example > dig.out.test$n 2>&1 || ret=1 + $DIG $DIGOPTS +tcp @10.53.0.2 -6 +mapped A a.example > dig.out.test$n 2>&1 || ret=1 grep "SERVER: ::ffff:10.53.0.2#5300" < dig.out.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` else echo "I:IPv6 unavailable; skipping" fi + + n=`expr $n + 1` + echo "I:checking dig +tcp @IPv4addr -6 +nomapped A a.example ($n)" + if $TESTSOCK6 fd92:7065:b8e:ffff::2 + then + ret=0 + ret=0 + $DIG $DIGOPTS +tcp @10.53.0.2 -6 +nomapped A a.example > dig.out.test$n 2>&1 || ret=1 + grep "SERVER: ::ffff:10.53.0.2#5300" < dig.out.test$n > /dev/null && ret=1 + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` + else + echo "I:IPv6 unavailable; skipping" + fi + n=`expr $n + 1` + + echo "I:checking dig +notcp @IPv4addr -6 +nomapped A a.example ($n)" + if $TESTSOCK6 fd92:7065:b8e:ffff::2 + then + ret=0 + ret=0 + $DIG $DIGOPTS +notcp @10.53.0.2 -6 +nomapped A a.example > dig.out.test$n 2>&1 || ret=1 + grep "SERVER: ::ffff:10.53.0.2#5300" < dig.out.test$n > /dev/null && ret=1 + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` + else + echo "I:IPv6 unavailable; skipping" + fi n=`expr $n + 1` echo "I:checking dig +subnet ($n)"