Commit 19708236 authored by Jonathan T. Leighton's avatar Jonathan T. Leighton Committed by Sasha Levin

ipv6: Handle IPv4-mapped src to in6addr_any dst.

[ Upstream commit 052d2369 ]

This patch adds a check on the type of the source address for the case
where the destination address is in6addr_any. If the source is an
IPv4-mapped IPv6 source address, the destination is changed to
::ffff:127.0.0.1, and otherwise the destination is changed to ::1. This
is done in three locations to handle UDP calls to either connect() or
sendmsg() and TCP calls to connect(). Note that udpv6_sendmsg() delays
handling an in6addr_any destination until very late, so the patch only
needs to handle the case where the source is an IPv4-mapped IPv6
address.
Signed-off-by: default avatarJonathan T. Leighton <jtleight@udel.edu>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
parent dd4d061c
...@@ -76,18 +76,22 @@ static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int a ...@@ -76,18 +76,22 @@ static int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int a
} }
} }
addr_type = ipv6_addr_type(&usin->sin6_addr); if (ipv6_addr_any(&usin->sin6_addr)) {
if (addr_type == IPV6_ADDR_ANY) {
/* /*
* connect to self * connect to self
*/ */
usin->sin6_addr.s6_addr[15] = 0x01; if (ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr))
ipv6_addr_set_v4mapped(htonl(INADDR_LOOPBACK),
&usin->sin6_addr);
else
usin->sin6_addr = in6addr_loopback;
} }
addr_type = ipv6_addr_type(&usin->sin6_addr);
daddr = &usin->sin6_addr; daddr = &usin->sin6_addr;
if (addr_type == IPV6_ADDR_MAPPED) { if (addr_type & IPV6_ADDR_MAPPED) {
struct sockaddr_in sin; struct sockaddr_in sin;
if (__ipv6_only_sock(sk)) { if (__ipv6_only_sock(sk)) {
......
...@@ -151,8 +151,13 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -151,8 +151,13 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
* connect() to INADDR_ANY means loopback (BSD'ism). * connect() to INADDR_ANY means loopback (BSD'ism).
*/ */
if (ipv6_addr_any(&usin->sin6_addr)) if (ipv6_addr_any(&usin->sin6_addr)) {
usin->sin6_addr.s6_addr[15] = 0x1; if (ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr))
ipv6_addr_set_v4mapped(htonl(INADDR_LOOPBACK),
&usin->sin6_addr);
else
usin->sin6_addr = in6addr_loopback;
}
addr_type = ipv6_addr_type(&usin->sin6_addr); addr_type = ipv6_addr_type(&usin->sin6_addr);
...@@ -191,7 +196,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -191,7 +196,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
* TCP over IPv4 * TCP over IPv4
*/ */
if (addr_type == IPV6_ADDR_MAPPED) { if (addr_type & IPV6_ADDR_MAPPED) {
u32 exthdrlen = icsk->icsk_ext_hdr_len; u32 exthdrlen = icsk->icsk_ext_hdr_len;
struct sockaddr_in sin; struct sockaddr_in sin;
......
...@@ -1132,6 +1132,10 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) ...@@ -1132,6 +1132,10 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
if (addr_len < SIN6_LEN_RFC2133) if (addr_len < SIN6_LEN_RFC2133)
return -EINVAL; return -EINVAL;
daddr = &sin6->sin6_addr; daddr = &sin6->sin6_addr;
if (ipv6_addr_any(daddr) &&
ipv6_addr_v4mapped(&np->saddr))
ipv6_addr_set_v4mapped(htonl(INADDR_LOOPBACK),
daddr);
break; break;
case AF_INET: case AF_INET:
goto do_udp_sendmsg; goto do_udp_sendmsg;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment