Re: socket api problem: can't bind an ipv6 socket to ::ffff:0.0.0.0

11 messages, 4 authors, 2009-03-19 · open the first message on its own page

Re: socket api problem: can't bind an ipv6 socket to ::ffff:0.0.0.0

From: Brian Haley <hidden>
Date: 2009-03-17 19:21:56

Top-posting so others can see your off-list rant in full.  I see no reason to
help you any further, even though I did have a patch that would change this
behavior for you.  Good luck with your "biggest noncommercial Internet messaging
infrastructure" in the world.

-Brian

Felix von Leitner wrote:
quoted
Please show me a porting guide that even mentions supporting IPv4-only mode
through an IPv6 socket by using this method.  There is none that I know of.
Are you kidding me?
A _porting guide_?!?

If you are trying to troll me, you just succeeded.

Now please make room so the adults can talk about the issue at hand
while you are putting up straw men.
quoted
quoted
Did I mention *BSD and OSX allow this?
That was their decision, and it doesn't mean it's the right thing to do.
Riiiight.

There is an old joke.  The Joneses are driving on the freeway, when the
radio sounds a warning.  "Warning!  There is a car driving the wrong way
on the freeway!"  Says grandpa (who is driving the car) "what do you
mean, one guy?  Hundreds!!"

Sometimes, if there are two ways to read something, and your users tell
you which way they want it, and the competition does it the way the
users want, and you don't, sometimes, in that case, YOU ARE WRONG.

It's that easy.

Hey, you have an hp.com email address.  Why don't you check out how
HP-UX handles this.
quoted
Compare your bittorrent server to Apache, which is probably the most widely-used
server application in the world.  It doesn't do what you're trying to do.  See
http://httpd.apache.org/docs/2.2/bind.html and/or browse the source code.
What is this supposed to be?  Name dropping?

I'm not impressed.

And Apache never won any speed or scalability records.  Just because
many people use Apache does not mean it's a good piece of software.  You
know, many more people use Windows than Linux.  That does not make
Windows the standard to follow.  Hey, many people use sendmail!  And
BIND!

Felix

Re: socket api problem: can't bind an ipv6 socket to ::ffff:0.0.0.0

From: David Miller <davem@davemloft.net>
Date: 2009-03-17 19:32:00

From: Brian Haley <redacted>
Date: Tue, 17 Mar 2009 15:21:52 -0400
Top-posting so others can see your off-list rant in full.  I see no
reason to help you any further, even though I did have a patch that
would change this behavior for you.  Good luck with your "biggest
noncommercial Internet messaging infrastructure" in the world.
What a jerk.  Brian, don't help him any more, you were being
very reasonable in your email to him.  His response was way
out of line.

[RFC PATCH 1/4] ipv6: Disallow binding to v4-mapped address on v6-only socket.

From: Vlad Yasevich <hidden>
Date: 2009-03-17 21:06:08

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 <redacted>
---
 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 3e2ddfa..07b9f3c 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

[RFC PATCH 2/4] ipv6: Allow ipv4 wildcard binds after ipv6 address binds

From: Vlad Yasevich <hidden>
Date: 2009-03-17 21:06:08

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 <redacted>
---
 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 07b9f3c..0adce8e 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

Re: socket api problem: can't bind an ipv6 socket to ::ffff:0.0.0.0

From: Vlad Yasevich <hidden>
Date: 2009-03-17 21:06:08

Hi David

Regardless of how we may feel about this thread, it did make me run
the BSD bindtest utility and look at the results.  What I found was
rather surprising.

There were multiple tests that one would exptect to succeed, but they
were failing.

Things that I consider broken:
  1) We can bind to a v4-mapped IPv6 address on a v6-only socket.
  2) We conflict IPv4 wildcrads with explicit IPv6 addresses and vice-versa
  3) We inconsitently treat V4 address and v4-mapped addresses.  As an example,
     try binging to 0.1.2.3. (This also kind of goes to binding
     ::ffff:0.0.0.0).

The following 4 RFC patches attempt to fix this.  I've run bindtest tool and
am currently analizing the results.  They look a heck of a lot better.

Thanks
-vlad

[RFC PATCH 3/4] ipv6: Make v4-mapped bindings consitant with IPv4

From: Vlad Yasevich <hidden>
Date: 2009-03-17 21:06:08

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 <redacted>
---
 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 0adce8e..274cc89 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

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

From: Vlad Yasevich <hidden>
Date: 2009-03-17 21:06:10

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 <redacted>
---
 include/net/addrconf.h |    4 ++--
 include/net/udp.h      |    2 ++
 net/ipv4/udp.c         |    3 ++-
 net/ipv6/addrconf.c    |   34 ----------------------------------
 net/ipv6/udp.c         |   30 ++++++++++++++++++++++++++++++
 5 files changed, 36 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 4bd178a..ce64e4d 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 *sk1, const struct sock *sk2)
 {
 	struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
 
@@ -1819,6 +1819,7 @@ EXPORT_SYMBOL(udp_lib_getsockopt);
 EXPORT_SYMBOL(udp_lib_setsockopt);
 EXPORT_SYMBOL(udp_poll);
 EXPORT_SYMBOL(udp_lib_get_port);
+EXPORT_SYMBOL(ipv4_rcv_saddr_equal);
 
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(udp_proc_register);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e83852a..00a37c1 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1367,40 +1367,6 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add
 	return ifp;
 }
 
-int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
-{
-	const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
-	const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2);
-	__be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;
-	__be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
-	int sk_ipv6only = ipv6_only_sock(sk);
-	int sk2_ipv6only = inet_v6_ipv6only(sk2);
-	int addr_type = ipv6_addr_type(sk_rcv_saddr6);
-	int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED;
-
-	if (!sk2_rcv_saddr && !sk_ipv6only)
-		return 1;
-
-	if (addr_type2 == IPV6_ADDR_ANY &&
-	    !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED))
-		return 1;
-
-	if (addr_type == IPV6_ADDR_ANY &&
-	    !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED))
-		return 1;
-
-	if (sk2_rcv_saddr6 &&
-	    ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6))
-		return 1;
-
-	if (addr_type == IPV6_ADDR_MAPPED &&
-	    !sk2_ipv6only &&
-	    (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr))
-		return 1;
-
-	return 0;
-}
-
 /* Gets referenced address, destroys ifaddr */
 
 static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 84b1a29..7e45761 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -49,6 +49,36 @@
 #include <linux/seq_file.h>
 #include "udp_impl.h"
 
+int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
+{
+	const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
+	const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2);
+	__be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;
+	__be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
+	int sk_ipv6only = ipv6_only_sock(sk);
+	int sk2_ipv6only = inet_v6_ipv6only(sk2);
+	int addr_type = ipv6_addr_type(sk_rcv_saddr6);
+	int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED;
+
+	/* if both are mapped, treat as IPv4 */
+	if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED)
+		return ipv4_rcv_saddr_equal(sk, sk2);
+
+	if (addr_type2 == IPV6_ADDR_ANY &&
+	    !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED))
+		return 1;
+
+	if (addr_type == IPV6_ADDR_ANY &&
+	    !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED))
+		return 1;
+
+	if (sk2_rcv_saddr6 &&
+	    ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6))
+		return 1;
+
+	return 0;
+}
+
 int udp_v6_get_port(struct sock *sk, unsigned short snum)
 {
 	return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal);
-- 
1.5.4.3

Re: socket api problem: can't bind an ipv6 socket to ::ffff:0.0.0.0

From: Jarek Poplawski <hidden>
Date: 2009-03-18 09:13:16

On 17-03-2009 20:31, David Miller wrote:
From: Brian Haley <redacted>
Date: Tue, 17 Mar 2009 15:21:52 -0400
quoted
Top-posting so others can see your off-list rant in full.  I see no
reason to help you any further, even though I did have a patch that
would change this behavior for you.  Good luck with your "biggest
noncommercial Internet messaging infrastructure" in the world.
What a jerk.  Brian, don't help him any more, you were being
very reasonable in your email to him.  His response was way
out of line.
Do you mean he got that joke wrong? Otherwise I think he is right. We
shouln't advise him how to do the things right, but, since what he
wants looks like legal and acceptable elsewhere, try to do this the
least invasive way.

Jarek P.

Re: socket api problem: can't bind an ipv6 socket to ::ffff:0.0.0.0

From: David Miller <davem@davemloft.net>
Date: 2009-03-18 21:36:49

From: Jarek Poplawski <redacted>
Date: Wed, 18 Mar 2009 09:13:07 +0000
On 17-03-2009 20:31, David Miller wrote:
quoted
From: Brian Haley <redacted>
Date: Tue, 17 Mar 2009 15:21:52 -0400
quoted
Top-posting so others can see your off-list rant in full.  I see no
reason to help you any further, even though I did have a patch that
would change this behavior for you.  Good luck with your "biggest
noncommercial Internet messaging infrastructure" in the world.
What a jerk.  Brian, don't help him any more, you were being
very reasonable in your email to him.  His response was way
out of line.
Do you mean he got that joke wrong? Otherwise I think he is right. We
shouln't advise him how to do the things right, but, since what he
wants looks like legal and acceptable elsewhere, try to do this the
least invasive way.
First of all, no matter if we allow that kind of bind() he wants or
not, he cannot use it in his application unless he wants his
application to be useless of most people's machines for at least a
year.

That's why the "make Linux be compatible with X other systems" is
always a joke argument.  Application wise, one still has to be
compatible with all existing Linux systems which is a much larger
issue.

And yes we should advise people what is an appropriate way to
accomplish some task.  If we aren't the experts on such a topic,
then who the hell is?

Re: socket api problem: can't bind an ipv6 socket to ::ffff:0.0.0.0

From: Jarek Poplawski <hidden>
Date: 2009-03-18 21:54:12

On Wed, Mar 18, 2009 at 02:36:35PM -0700, David Miller wrote:
...
And yes we should advise people what is an appropriate way to
accomplish some task.  If we aren't the experts on such a topic,
then who the hell is?
Only if sb. is looking for advice; otherwise it's not very nice,
especially if repeated many times.

Jarek P.

Re: socket api problem: can't bind an ipv6 socket to ::ffff:0.0.0.0

From: David Miller <davem@davemloft.net>
Date: 2009-03-19 00:32:33

From: Jarek Poplawski <redacted>
Date: Wed, 18 Mar 2009 22:53:00 +0100
On Wed, Mar 18, 2009 at 02:36:35PM -0700, David Miller wrote:
...
quoted
And yes we should advise people what is an appropriate way to
accomplish some task.  If we aren't the experts on such a topic,
then who the hell is?
Only if sb. is looking for advice; otherwise it's not very nice,
especially if repeated many times.
If the purpose of the query was to suggest that Linux should behave a
certain way, it should be no surprise to anyone that if we should
disagree with that suggestion we would suggest what we consider more
desriable alternatives for the application developer.

I don't even think this is worth the time we are spending to discuss
it, it seems so straightforward.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help