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)"