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 --
From: Brian Haley <brian.haley@hp.com> 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. --
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
--
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 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
--
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 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
--
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 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
--
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 | 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 ...
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. --
From: Jarek Poplawski <jarkao2@gmail.com> 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? --
On Wed, Mar 18, 2009 at 02:36:35PM -0700, David Miller wrote: Only if sb. is looking for advice; otherwise it's not very nice, especially if repeated many times. Jarek P. --
From: Jarek Poplawski <jarkao2@gmail.com> 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. --
