MINOR: tcp: add support for the "v4v6" bind option
Commit 9b6700f added "v6only". As suggested by Vincent Bernat, it is
sometimes useful to have the opposite option to force binding to the
two protocols when the system is configured to bind to v6 only by
default. This option does exactly this. v6only still has precedence.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index aa21212..223d479 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -7156,11 +7156,19 @@
kernel version. Some distribution kernels include backports of the feature,
so check for support with your vendor.
+v4v6
+ Is an optional keyword which is supported only on most recent systems
+ including Linux kernels >= 2.4.21. It is used to bind a socket to both IPv4
+ and IPv6 when it uses the default address. Doing so is sometimes necessary
+ on systems which bind to IPv6 only by default. It has no effect on non-IPv6
+ sockets, and is overriden by the "v6only" option.
+
v6only
Is an optional keyword which is supported only on most recent systems
including Linux kernels >= 2.4.21. It is used to bind a socket to IPv6 only
when it uses the default address. Doing so is sometimes preferred to doing it
- system-wide as it is per-listener. It has no effect on non-IPv6 sockets.
+ system-wide as it is per-listener. It has no effect on non-IPv6 sockets and
+ has precedence over the "v4v6" option.
uid <uid>
Sets the owner of the UNIX sockets to the designated system uid. It can also
diff --git a/include/types/listener.h b/include/types/listener.h
index 0bdde76..d5d91f4 100644
--- a/include/types/listener.h
+++ b/include/types/listener.h
@@ -91,6 +91,7 @@
#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_V6ONLY 0x0200 /* bind to IPv6 only on Linux >= 2.4.21 */
+#define LI_O_V4V6 0x0400 /* bind to IPv4/IPv6 on Linux >= 2.4.21 */
/* 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 86073a4..5516036 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -703,6 +703,8 @@
#if defined(IPV6_V6ONLY)
if (listener->options & LI_O_V6ONLY)
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
+ else if (listener->options & LI_O_V4V6)
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero));
#endif
if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) {
@@ -1727,6 +1729,19 @@
}
#ifdef IPV6_V6ONLY
+/* parse the "v4v6" bind keyword */
+static int bind_parse_v4v6(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_INET6)
+ l->options |= LI_O_V4V6;
+ }
+
+ return 0;
+}
+
/* parse the "v6only" bind keyword */
static int bind_parse_v6only(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
@@ -1899,6 +1914,7 @@
{ "transparent", bind_parse_transparent, 0 }, /* transparently bind to the specified addresses */
#endif
#ifdef IPV6_V6ONLY
+ { "v4v6", bind_parse_v4v6, 0 }, /* force socket to bind to IPv4+IPv6 */
{ "v6only", bind_parse_v6only, 0 }, /* force socket to bind to IPv6 only */
#endif
/* the versions with the NULL parse function*/
@@ -1906,6 +1922,7 @@
{ "interface", NULL, 1 },
{ "mss", NULL, 1 },
{ "transparent", NULL, 0 },
+ { "v4v6", NULL, 0 },
{ "v6only", NULL, 0 },
{ NULL, NULL, 0 },
}};