[PATCH v2 4/4] ipv6: Fix conflict resolutions during ipv6 binding

Previous thread: Winner.........Siemens Promo by Siemens News Center on Tuesday, March 24, 2009 - 6:53 pm. (1 message)

Next thread: [PATCH] net: remove two duplicated include by Jianjun Kong on Tuesday, March 24, 2009 - 8:31 pm. (2 messages)
From: Vlad Yasevich
Date: Tuesday, March 24, 2009 - 7:24 pm

This is an updated patch series to fix up bind() conflicts between v4-mapped
and IPv6 addresses.

These patches correct the following problems:
    1) Disallow binding of a v4-mapped address on a IPV6_V6ONLY socket.
    2) Allow IPv4 wildcards to bind at the same time as a native IPv6 address.
    3) Make v4-mapped bind()s consitant with IPv4 native binds.
    4) Fix conflict resolutions between v4-mapped addresses, v4 addresses, and v6
       addresses

Thanks
-vlad
--

From: Vlad Yasevich
Date: Tuesday, March 24, 2009 - 7:24 pm

The IPv4 wildcard (0.0.0.0) address does not intersect
in any way with explicit IPv6 addresses.  These two should
be permitted, but the IPv4 conflict code checks the ipv6only
bit as part of the test.  Since binding to an explicit IPv6
address restricts the socket to only that IPv6 address, the
side-effect is that the socket behaves as v6-only.  By
explicitely setting ipv6only in this case, allows the 2 binds
to succeed.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
---
 net/ipv6/af_inet6.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 7f092fa..9b6a37d 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -346,8 +346,11 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 		goto out;
 	}
 
-	if (addr_type != IPV6_ADDR_ANY)
+	if (addr_type != IPV6_ADDR_ANY) {
 		sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
+		if (addr_type != IPV6_ADDR_MAPPED)
+			np->ipv6only = 1;
+	}
 	if (snum)
 		sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
 	inet->sport = htons(inet->num);
-- 
1.5.4.3

--

From: Vlad Yasevich
Date: Tuesday, March 24, 2009 - 7:24 pm

A socket marked v6-only, can not receive or send traffic to v4-mapped
addresses.  Thus allowing binding to v4-mapped address on such a
socket makes no sense.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
---
 net/ipv6/af_inet6.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index fbf533c..7f092fa 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -276,6 +276,13 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 
 	/* Check if the address belongs to the host. */
 	if (addr_type == IPV6_ADDR_MAPPED) {
+		/* Binding to v4-mapped address on a v6-only socket
+		 * makes no sense
+		 */
+		if (np->ipv6only) {
+			err = -EINVAL;
+			goto out;
+		}
 		v4addr = addr->sin6_addr.s6_addr32[3];
 		if (inet_addr_type(net, v4addr) != RTN_LOCAL) {
 			err = -EADDRNOTAVAIL;
-- 
1.5.4.3

--

From: Vlad Yasevich
Date: Tuesday, March 24, 2009 - 7:24 pm

The ipv6 version of bind_conflict code calls ipv6_rcv_saddr_equal()
which at times wrongly identified intersections between addresses.
It particularly broke down under a few instances and caused erroneouse
bind conflicts.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
---
 include/net/addrconf.h |    4 ++--
 include/net/udp.h      |    2 ++
 net/ipv4/udp.c         |    3 ++-
 net/ipv6/addrconf.c    |   34 ----------------------------------
 net/ipv6/udp.c         |   28 ++++++++++++++++++++++++++++
 5 files changed, 34 insertions(+), 37 deletions(-)

diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index c216de5..7b55ab2 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -88,8 +88,8 @@ extern int			ipv6_dev_get_saddr(struct net *net,
 extern int			ipv6_get_lladdr(struct net_device *dev,
 						struct in6_addr *addr,
 						unsigned char banned_flags);
-extern int			ipv6_rcv_saddr_equal(const struct sock *sk, 
-						      const struct sock *sk2);
+extern int 			ipv6_rcv_saddr_equal(const struct sock *sk,
+						    const struct sock *sk2);
 extern void			addrconf_join_solict(struct net_device *dev,
 					struct in6_addr *addr);
 extern void			addrconf_leave_solict(struct inet6_dev *idev,
diff --git a/include/net/udp.h b/include/net/udp.h
index 90e6ce5..93dbe29 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -124,6 +124,8 @@ static inline void udp_lib_close(struct sock *sk, long timeout)
 	sk_common_release(sk);
 }
 
+extern int	ipv4_rcv_saddr_equal(const struct sock *sk1,
+				    const struct sock *sk2);
 extern int	udp_lib_get_port(struct sock *sk, unsigned short snum,
 		int (*)(const struct sock*,const struct sock*));
 
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 05b7abb..ace2ac8 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -222,7 +222,7 @@ fail:
 	return error;
 }
 
-static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
+int ipv4_rcv_saddr_equal(const struct sock ...
From: Vlad Yasevich
Date: Tuesday, March 24, 2009 - 7:24 pm

Binding to a v4-mapped address on an AF_INET6 socket should
produce the same result as binding to an IPv4 address on
AF_INET socket.  The two are interchangable as v4-mapped
address is really a portability aid.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
---
 net/ipv6/af_inet6.c |   14 +++++++++++---
 1 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 9b6a37d..61f5538 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -276,6 +276,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 
 	/* Check if the address belongs to the host. */
 	if (addr_type == IPV6_ADDR_MAPPED) {
+		int chk_addr_ret;
+
 		/* Binding to v4-mapped address on a v6-only socket
 		 * makes no sense
 		 */
@@ -283,11 +285,17 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 			err = -EINVAL;
 			goto out;
 		}
+
+		/* Reproduce AF_INET checks to make the bindings consitant */
 		v4addr = addr->sin6_addr.s6_addr32[3];
-		if (inet_addr_type(net, v4addr) != RTN_LOCAL) {
-			err = -EADDRNOTAVAIL;
+		chk_addr_ret = inet_addr_type(net, v4addr);
+		if (!sysctl_ip_nonlocal_bind &&
+		    !(inet->freebind || inet->transparent) &&
+		    v4addr != htonl(INADDR_ANY) &&
+		    chk_addr_ret != RTN_LOCAL &&
+		    chk_addr_ret != RTN_MULTICAST &&
+		    chk_addr_ret != RTN_BROADCAST)
 			goto out;
-		}
 	} else {
 		if (addr_type != IPV6_ADDR_ANY) {
 			struct net_device *dev = NULL;
-- 
1.5.4.3

--

From: David Miller
Date: Tuesday, March 24, 2009 - 11:27 pm

From: Vlad Yasevich <vladislav.yasevich@hp.com>

All applied, thanks Vlad.
--

Previous thread: Winner.........Siemens Promo by Siemens News Center on Tuesday, March 24, 2009 - 6:53 pm. (1 message)

Next thread: [PATCH] net: remove two duplicated include by Jianjun Kong on Tuesday, March 24, 2009 - 8:31 pm. (2 messages)