diff --git a/doc/configuration.txt b/doc/configuration.txt index aa2121289..223d479b7 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -7156,11 +7156,19 @@ transparent 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 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 0bdde76b7..d5d91f43f 100644 --- a/include/types/listener.h +++ b/include/types/listener.h @@ -91,6 +91,7 @@ enum { #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 86073a41f..551603677 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -703,6 +703,8 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) #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 @@ static int val_payload_lv(struct arg *arg, char **err_msg) } #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 @@ static struct bind_kw_list bind_kws = { "TCP", { }, { { "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 @@ static struct bind_kw_list bind_kws = { "TCP", { }, { { "interface", NULL, 1 }, { "mss", NULL, 1 }, { "transparent", NULL, 0 }, + { "v4v6", NULL, 0 }, { "v6only", NULL, 0 }, { NULL, NULL, 0 }, }};