From 9b6700f673e04a0f2a804202429f208bb2285d29 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 24 Nov 2012 11:55:28 +0100 Subject: [PATCH] MINOR: tcp: add support for the "v6only" bind option This option forces a socket to bind to IPv6 only when it uses the default address (eg: ":::80"). --- doc/configuration.txt | 6 ++++++ include/types/listener.h | 1 + src/proto_tcp.c | 24 ++++++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/doc/configuration.txt b/doc/configuration.txt index f4094079c..aa2121289 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -7156,6 +7156,12 @@ transparent kernel version. Some distribution kernels include backports of the feature, so check for support with your vendor. +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. + uid Sets the owner of the UNIX sockets to the designated system uid. It can also be set by default in the global section's "unix-bind" statement. Note that diff --git a/include/types/listener.h b/include/types/listener.h index 0f1698665..0bdde76b7 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_V6ONLY 0x0200 /* bind to IPv6 only 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 fd9b03d86..86073a41f 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -700,6 +700,11 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) } } #endif +#if defined(IPV6_V6ONLY) + if (listener->options & LI_O_V6ONLY) + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); +#endif + if (bind(fd, (struct sockaddr *)&listener->addr, listener->proto->sock_addrlen) == -1) { err |= ERR_RETRYABLE | ERR_ALERT; msg = "cannot bind socket"; @@ -1721,6 +1726,21 @@ static int val_payload_lv(struct arg *arg, char **err_msg) return 1; } +#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_INET6) + l->options |= LI_O_V6ONLY; + } + + return 0; +} +#endif + #ifdef CONFIG_HAP_LINUX_TPROXY /* parse the "transparent" bind keyword */ static int bind_parse_transparent(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) @@ -1877,12 +1897,16 @@ static struct bind_kw_list bind_kws = { "TCP", { }, { #endif #ifdef CONFIG_HAP_LINUX_TPROXY { "transparent", bind_parse_transparent, 0 }, /* transparently bind to the specified addresses */ +#endif +#ifdef IPV6_V6ONLY + { "v6only", bind_parse_v6only, 0 }, /* force socket to bind to IPv6 only */ #endif /* the versions with the NULL parse function*/ { "defer-accept", NULL, 0 }, { "interface", NULL, 1 }, { "mss", NULL, 1 }, { "transparent", NULL, 0 }, + { "v6only", NULL, 0 }, { NULL, NULL, 0 }, }};