From d88e8c06ac076d5550366aa6a283ad485948975e Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 28 Aug 2020 16:06:01 +0200 Subject: [PATCH] REORG: sock_inet: move v6only_default from proto_tcp.c to sock_inet.c The v6only_default variable is not specific to TCP but to AF_INET6, so let's move it to the right file. It's now immediately filled on startup during the PREPARE stage so that it doesn't have to be tested each time. The variable's name was changed to sock_inet6_v6only_default. --- include/haproxy/sock_inet.h | 2 ++ src/proto_tcp.c | 37 ++----------------------------------- src/sock_inet.c | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+), 35 deletions(-) diff --git a/include/haproxy/sock_inet.h b/include/haproxy/sock_inet.h index 48b23b3fd..6e3718a2d 100644 --- a/include/haproxy/sock_inet.h +++ b/include/haproxy/sock_inet.h @@ -27,6 +27,8 @@ #include +extern int sock_inet6_v6only_default; + int sock_inet4_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b); int sock_inet6_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b); int sock_inet_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir); diff --git a/src/proto_tcp.c b/src/proto_tcp.c index fba60834b..144f4bcfa 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -107,11 +107,6 @@ static THREAD_LOCAL int default_tcp_maxseg = -1; static THREAD_LOCAL int default_tcp6_maxseg = -1; #endif -/* determine if the operating system uses IPV6_V6ONLY by default. - * -1=unknown, 0=no, 1=yes. - */ -static int v6only_default = -1; - /* Binds ipv4/ipv6 address to socket , unless is set, in which * case we try to bind . is a 2-bit field consisting of : * - 0 : ignore remote address (may even be a NULL pointer) @@ -581,32 +576,6 @@ int tcp_connect_server(struct connection *conn, int flags) return SF_ERR_NONE; /* connection is OK */ } -/* sets the v6only_default flag according to the OS' default settings; for - * simplicity it's set to zero if not supported. - */ -static inline void tcp_test_v6only_default() -{ - if (v6only_default == -1) { -#if defined(IPV6_V6ONLY) - int fd, val; - socklen_t len = sizeof(val); - - v6only_default = 0; - - fd = socket(AF_INET6, SOCK_STREAM, 0); - if (fd < 0) - return; - - if (getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, &len) == 0 && val > 0) - v6only_default = 1; - - close(fd); -#else - v6only_default = 0; -#endif - } -} - #define LI_MANDATORY_FLAGS (LI_O_FOREIGN | LI_O_V6ONLY) /* When binding the listeners, check if a socket has been sent to us by the * previous process that we could reuse, instead of creating a new one. @@ -617,15 +586,13 @@ static int tcp_find_compatible_fd(struct listener *l) int options = l->options & (LI_MANDATORY_FLAGS | LI_O_V4V6); int ret = -1; - tcp_test_v6only_default(); - /* Prepare to match the v6only option against what we really want. Note * that sadly the two options are not exclusive to each other and that * v6only is stronger than v4v6. */ - if ((options & LI_O_V6ONLY) || (v6only_default && !(options & LI_O_V4V6))) + if ((options & LI_O_V6ONLY) || (sock_inet6_v6only_default && !(options & LI_O_V4V6))) options |= LI_O_V6ONLY; - else if ((options & LI_O_V4V6) || !v6only_default) + else if ((options & LI_O_V4V6) || !sock_inet6_v6only_default) options &= ~LI_O_V6ONLY; options &= ~LI_O_V4V6; diff --git a/src/sock_inet.c b/src/sock_inet.c index db1a8c00e..c5b80da1c 100644 --- a/src/sock_inet.c +++ b/src/sock_inet.c @@ -35,6 +35,10 @@ * mentioned in the comment before the function definition. */ +/* determine if the operating system uses IPV6_V6ONLY by default. 0=no, 1=yes. + * It also remains if IPv6 is not enabled/configured. + */ +int sock_inet6_v6only_default = 0; /* Compares two AF_INET sockaddr addresses. Returns 0 if they match or non-zero * if they do not match. @@ -165,3 +169,22 @@ int sock_inet_is_foreign(int fd, sa_family_t family) } return 0; } + +static void sock_inet_prepare() +{ + int fd, val; + socklen_t len; + + fd = socket(AF_INET6, SOCK_STREAM, 0); + if (fd >= 0) { +#if defined(IPV6_V6ONLY) + /* retrieve the OS' bindv6only value */ + len = sizeof(val); + if (getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, &len) == 0 && val > 0) + sock_inet6_v6only_default = 1; +#endif + close(fd); + } +} + +INITCALL0(STG_PREPARE, sock_inet_prepare);