From 37bafdcbb12096c1291a3b5439109c91a419536a Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 28 Aug 2020 17:23:40 +0200 Subject: [PATCH] MINOR: sock_inet: move the IPv4/v6 transparent mode code to sock_inet This code was highly redundant, existing for TCP clients, TCP servers and UDP servers. Let's move it to sock_inet where it belongs. The new functions are sock_inet4_make_foreign() and sock_inet6_make_foreign(). --- include/haproxy/sock_inet.h | 2 + src/proto_tcp.c | 81 ++----------------------------------- src/proto_udp.c | 30 +------------- src/sock_inet.c | 69 +++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 105 deletions(-) diff --git a/include/haproxy/sock_inet.h b/include/haproxy/sock_inet.h index d90b41953..72b1204b2 100644 --- a/include/haproxy/sock_inet.h +++ b/include/haproxy/sock_inet.h @@ -35,5 +35,7 @@ int sock_inet4_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_s 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); int sock_inet_is_foreign(int fd, sa_family_t family); +int sock_inet4_make_foreign(int fd); +int sock_inet6_make_foreign(int fd); #endif /* _HAPROXY_SOCK_INET_H */ diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 4ae4a489f..933eced34 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -129,20 +129,7 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct so * multiple combinations of certain methods, so we try the * supported ones until one succeeds. */ - if (0 -#if defined(IP_TRANSPARENT) - || (setsockopt(fd, SOL_IP, IP_TRANSPARENT, &one, sizeof(one)) == 0) -#endif -#if defined(IP_FREEBIND) - || (setsockopt(fd, SOL_IP, IP_FREEBIND, &one, sizeof(one)) == 0) -#endif -#if defined(IP_BINDANY) - || (setsockopt(fd, IPPROTO_IP, IP_BINDANY, &one, sizeof(one)) == 0) -#endif -#if defined(SO_BINDANY) - || (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) == 0) -#endif - ) + if (sock_inet4_make_foreign(fd)) foreign_ok = 1; else ip_transp_working = 0; @@ -150,20 +137,7 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct so break; case AF_INET6: if (flags && ip6_transp_working) { - if (0 -#if defined(IPV6_TRANSPARENT) && defined(SOL_IPV6) - || (setsockopt(fd, SOL_IPV6, IPV6_TRANSPARENT, &one, sizeof(one)) == 0) -#endif -#if defined(IP_FREEBIND) - || (setsockopt(fd, SOL_IP, IP_FREEBIND, &one, sizeof(one)) == 0) -#endif -#if defined(IPV6_BINDANY) - || (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDANY, &one, sizeof(one)) == 0) -#endif -#if defined(SO_BINDANY) - || (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) == 0) -#endif - ) + if (sock_inet6_make_foreign(fd)) foreign_ok = 1; else ip6_transp_working = 0; @@ -664,39 +638,13 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) if (!ext && (listener->options & LI_O_FOREIGN)) { switch (listener->addr.ss_family) { case AF_INET: - if (1 -#if defined(IP_TRANSPARENT) - && (setsockopt(fd, SOL_IP, IP_TRANSPARENT, &one, sizeof(one)) == -1) -#endif -#if defined(IP_FREEBIND) - && (setsockopt(fd, SOL_IP, IP_FREEBIND, &one, sizeof(one)) == -1) -#endif -#if defined(IP_BINDANY) - && (setsockopt(fd, IPPROTO_IP, IP_BINDANY, &one, sizeof(one)) == -1) -#endif -#if defined(SO_BINDANY) - && (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) == -1) -#endif - ) { + if (!sock_inet4_make_foreign(fd)) { msg = "cannot make listening socket transparent"; err |= ERR_ALERT; } break; case AF_INET6: - if (1 -#if defined(IPV6_TRANSPARENT) && defined(SOL_IPV6) - && (setsockopt(fd, SOL_IPV6, IPV6_TRANSPARENT, &one, sizeof(one)) == -1) -#endif -#if defined(IP_FREEBIND) - && (setsockopt(fd, SOL_IP, IP_FREEBIND, &one, sizeof(one)) == -1) -#endif -#if defined(IPV6_BINDANY) - && (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDANY, &one, sizeof(one)) == -1) -#endif -#if defined(SO_BINDANY) - && (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) == -1) -#endif - ) { + if (!sock_inet6_make_foreign(fd)) { msg = "cannot make listening socket transparent"; err |= ERR_ALERT; } @@ -920,27 +868,6 @@ int tcp_pause_listener(struct listener *l) return 1; } -REGISTER_BUILD_OPTS("Built with transparent proxy support using:" -#if defined(IP_TRANSPARENT) - " IP_TRANSPARENT" -#endif -#if defined(IPV6_TRANSPARENT) - " IPV6_TRANSPARENT" -#endif -#if defined(IP_FREEBIND) - " IP_FREEBIND" -#endif -#if defined(IP_BINDANY) - " IP_BINDANY" -#endif -#if defined(IPV6_BINDANY) - " IPV6_BINDANY" -#endif -#if defined(SO_BINDANY) - " SO_BINDANY" -#endif - ""); - /* * Local variables: diff --git a/src/proto_udp.c b/src/proto_udp.c index 96b878a34..18e46ac91 100644 --- a/src/proto_udp.c +++ b/src/proto_udp.c @@ -241,39 +241,13 @@ int udp_bind_listener(struct listener *listener, char *errmsg, int errlen) if (listener->options & LI_O_FOREIGN) { switch (addr_inet.ss_family) { case AF_INET: - if (1 -#if defined(IP_TRANSPARENT) - && (setsockopt(fd, SOL_IP, IP_TRANSPARENT, &one, sizeof(one)) == -1) -#endif -#if defined(IP_FREEBIND) - && (setsockopt(fd, SOL_IP, IP_FREEBIND, &one, sizeof(one)) == -1) -#endif -#if defined(IP_BINDANY) - && (setsockopt(fd, IPPROTO_IP, IP_BINDANY, &one, sizeof(one)) == -1) -#endif -#if defined(SO_BINDANY) - && (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) == -1) -#endif - ) { + if (!sock_inet4_make_foreign(fd)) { msg = "cannot make listening socket transparent"; err |= ERR_ALERT; } break; case AF_INET6: - if (1 -#if defined(IPV6_TRANSPARENT) && defined(SOL_IPV6) - && (setsockopt(fd, SOL_IPV6, IPV6_TRANSPARENT, &one, sizeof(one)) == -1) -#endif -#if defined(IP_FREEBIND) - && (setsockopt(fd, SOL_IP, IP_FREEBIND, &one, sizeof(one)) == -1) -#endif -#if defined(IPV6_BINDANY) - && (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDANY, &one, sizeof(one)) == -1) -#endif -#if defined(SO_BINDANY) - && (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) == -1) -#endif - ) { + if (!sock_inet6_make_foreign(fd)) { msg = "cannot make listening socket transparent"; err |= ERR_ALERT; } diff --git a/src/sock_inet.c b/src/sock_inet.c index 29666801b..3f4edcb1d 100644 --- a/src/sock_inet.c +++ b/src/sock_inet.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -174,6 +175,52 @@ int sock_inet_is_foreign(int fd, sa_family_t family) return 0; } +/* Attempt all known socket options to prepare an AF_INET4 socket to be bound + * to a foreign address. The socket must already exist and must not be bound. + * 1 is returned on success, 0 on failure. The caller must check the address + * family before calling this function. + */ +int sock_inet4_make_foreign(int fd) +{ + return +#if defined(IP_TRANSPARENT) + setsockopt(fd, SOL_IP, IP_TRANSPARENT, &one, sizeof(one)) == 0 || +#endif +#if defined(IP_FREEBIND) + setsockopt(fd, SOL_IP, IP_FREEBIND, &one, sizeof(one)) == 0 || +#endif +#if defined(IP_BINDANY) + setsockopt(fd, IPPROTO_IP, IP_BINDANY, &one, sizeof(one)) == 0 || +#endif +#if defined(SO_BINDANY) + setsockopt(fd, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) == 0 || +#endif + 0; +} + +/* Attempt all known socket options to prepare an AF_INET6 socket to be bound + * to a foreign address. The socket must already exist and must not be bound. + * 1 is returned on success, 0 on failure. The caller must check the address + * family before calling this function. + */ +int sock_inet6_make_foreign(int fd) +{ + return +#if defined(IPV6_TRANSPARENT) && defined(SOL_IPV6) + setsockopt(fd, SOL_IPV6, IPV6_TRANSPARENT, &one, sizeof(one)) == 0 || +#endif +#if defined(IP_FREEBIND) + setsockopt(fd, SOL_IP, IP_FREEBIND, &one, sizeof(one)) == 0 || +#endif +#if defined(IPV6_BINDANY) + setsockopt(fd, IPPROTO_IPV6, IPV6_BINDANY, &one, sizeof(one)) == 0 || +#endif +#if defined(SO_BINDANY) + setsockopt(fd, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) == 0 || +#endif + 0; +} + static void sock_inet_prepare() { int fd, val; @@ -210,3 +257,25 @@ static void sock_inet_prepare() } INITCALL0(STG_PREPARE, sock_inet_prepare); + + +REGISTER_BUILD_OPTS("Built with transparent proxy support using:" +#if defined(IP_TRANSPARENT) + " IP_TRANSPARENT" +#endif +#if defined(IPV6_TRANSPARENT) + " IPV6_TRANSPARENT" +#endif +#if defined(IP_FREEBIND) + " IP_FREEBIND" +#endif +#if defined(IP_BINDANY) + " IP_BINDANY" +#endif +#if defined(IPV6_BINDANY) + " IPV6_BINDANY" +#endif +#if defined(SO_BINDANY) + " SO_BINDANY" +#endif + "");