[PATCH] MEDIUM: tcp: add a v6only option for TCP sockets

2012-11-24 Thread Vincent Bernat
With this option enabled, a TCPv6 socket will only listen for IPv6
packets. With this option absent, a TCPv6 socket will accept both IPv6
and IPv4 packets.

The system setting (net.ipv6.bindv6only) is ignored because many
people disagree with the default proposed by RFC 3493 (which is to
listen to both IPv4 and IPv6 by default) because this makes difficult
to write a server socket in a truly protocol-independent way. So, on
any system, haproxy will bind to both IPv4 and IPv6 sockets by
default, unless the v6only option is specified.
---
 doc/configuration.txt|7 +++
 include/types/listener.h |1 +
 src/proto_tcp.c  |   40 +++-
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index f409407..bd721c8 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -7170,6 +7170,13 @@ user user
   setting except that the user name is used instead of its uid. This setting is
   ignored by non UNIX sockets.
 
+v6only
+  This setting will make the socket listening for IPv6 packets. Another socket
+  or program can be configured to handle IPv4 packets on the same port. Without
+  this option, a socket will be able to handle both IPv4 and IPv6 packets,
+  whatever the default system setting is. This option is ignored if the socket
+  is configured to listen to an IPv4 address.
+
 verify [none|optional|required]
   This setting is only available when support for OpenSSL was built in. If set
   to 'none', client certificate is not requested. This is the default. In other
diff --git a/include/types/listener.h b/include/types/listener.h
index 0f16986..824956f 100644
--- a/include/types/listener.h
+++ b/include/types/listener.h
@@ -90,6 +90,7 @@ enum {
 #define LI_O_ACC_PROXY  0x0040  /* find the proxied address in the first 
request line */
 #define LI_O_UNLIMITED  0x0080  /* listener not subject to global limits 
(peers  stats socket) */
 #define LI_O_TCP_FO 0x0100  /* enable TCP Fast Open (linux = 3.6) */
+#define LI_O_IPV6_ONLY  0x0200  /* listen only on IPv6 */
 
 /* Note: if a listener uses LI_O_UNLIMITED, it is highly recommended that it 
adds its own
  * maxconn setting to the global.maxsock value so that its resources are 
reserved.
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 2b8d148..eb831f0 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -699,6 +699,26 @@ int tcp_bind_listener(struct listener *listener, char 
*errmsg, int errlen)
}
}
 #endif
+#if defined(IPV6_V6ONLY)
+   switch (listener-addr.ss_family) {
+   case AF_INET: break;
+   case AF_INET6:
+   if (listener-options  LI_O_IPV6_ONLY) {
+   int on = 1;
+   if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, on, 
sizeof(on)) == -1) {
+   msg = cannot enable IPV6_V6ONLY;
+   err |= ERR_WARN;
+   }
+   } else {
+   int off = 0;
+   if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, off, 
sizeof(off)) == -1) {
+   msg = cannot disable IPV6_V6ONLY;
+   err |= ERR_WARN;
+   }
+   }
+   break;
+   }
+#endif
if (bind(fd, (struct sockaddr *)listener-addr, 
listener-proto-sock_addrlen) == -1) {
err |= ERR_RETRYABLE | ERR_ALERT;
msg = cannot bind socket;
@@ -1751,7 +1771,7 @@ static int bind_parse_defer_accept(char **args, int 
cur_arg, struct proxy *px, s
 #endif
 
 #ifdef TCP_FASTOPEN
-/* parse the defer-accept bind keyword */
+/* parse the tfo bind keyword */
 static int bind_parse_tfo(char **args, int cur_arg, struct proxy *px, struct 
bind_conf *conf, char **err)
 {
struct listener *l;
@@ -1765,6 +1785,21 @@ static int bind_parse_tfo(char **args, int cur_arg, 
struct proxy *px, struct bin
 }
 #endif
 
+#ifdef IPV6_V6ONLY
+/* parse the v6only bind keyword */
+static int bind_parse_v6only(char **args, int cur_arg, struct proxy *px, 
struct bind_conf *conf, char **err)
+{
+   struct listener *l;
+
+   list_for_each_entry(l, conf-listeners, by_bind) {
+   if (l-addr.ss_family == AF_INET || l-addr.ss_family == 
AF_INET6)
+   l-options |= LI_O_IPV6_ONLY;
+   }
+
+   return 0;
+}
+#endif
+
 #ifdef TCP_MAXSEG
 /* parse the mss bind keyword */
 static int bind_parse_mss(char **args, int cur_arg, struct proxy *px, struct 
bind_conf *conf, char **err)
@@ -1874,6 +1909,9 @@ static struct bind_kw_list bind_kws = { TCP, { }, {
 #ifdef TCP_FASTOPEN
{ tfo,   bind_parse_tfo,  0 }, /* enable TCP_FASTOPEN 
of listening socket */
 #endif
+#ifdef IPV6_V6ONLY
+   { v6only,bind_parse_v6only,   0 }, /* enable IPV6_V6ONLY 
of listening socket */
+#endif
 #ifdef CONFIG_HAP_LINUX_TPROXY
{ transparent,   

Re: [PATCH] MEDIUM: tcp: add a v6only option for TCP sockets

2012-11-24 Thread Vincent Bernat
 ❦ 24 novembre 2012 12:01 CET, Vincent Bernat ber...@luffy.cx :

  #ifdef TCP_FASTOPEN
 -/* parse the defer-accept bind keyword */
 +/* parse the tfo bind keyword */
  static int bind_parse_tfo(char **args, int cur_arg, struct proxy *px, struct 
 bind_conf *conf, char **err)

I have embedded this change on purpose. Feel free to strip it.
-- 
Make input easy to proofread.
- The Elements of Programming Style (Kernighan  Plauger)