diff --git a/include/common/compat.h b/include/common/compat.h index bb2d010bf6..043a56e48e 100644 --- a/include/common/compat.h +++ b/include/common/compat.h @@ -93,6 +93,12 @@ #endif /* !IPV6_TRANSPARENT */ #endif /* CONFIG_HAP_LINUX_TPROXY */ +#if defined(IP_FREEBIND) \ + || defined(IP_TRANSPARENT) \ + || defined(IPV6_TRANSPARENT) +#define CONFIG_HAP_TRANSPARENT +#endif + /* We'll try to enable SO_REUSEPORT on Linux 2.4 and 2.6 if not defined. * There are two families of values depending on the architecture. Those * are at least valid on Linux 2.4 and 2.6, reason why we'll rely on the diff --git a/include/types/connection.h b/include/types/connection.h index 255811ca64..2c7acd18bf 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -219,7 +219,7 @@ struct conn_src { char *iface_name; /* bind interface name or NULL */ struct port_range *sport_range; /* optional per-server TCP source ports */ struct sockaddr_storage source_addr; /* the address to which we want to bind for connect() */ -#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY) +#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_TRANSPARENT) struct sockaddr_storage tproxy_addr; /* non-local address we want to bind to for connect() */ char *bind_hdr_name; /* bind to this header name if defined */ int bind_hdr_len; /* length of the name of the header above */ diff --git a/src/backend.c b/src/backend.c index 9f4e635734..9f230186eb 100644 --- a/src/backend.c +++ b/src/backend.c @@ -884,7 +884,7 @@ int assign_server_and_queue(struct session *s) */ static void assign_tproxy_address(struct session *s) { -#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY) +#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_TRANSPARENT) struct server *srv = objt_server(s->target); struct conn_src *src; diff --git a/src/cfgparse.c b/src/cfgparse.c index 6f2850c73a..9907bfd04a 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1813,7 +1813,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) curproxy->conn_src.iface_name = strdup(defproxy.conn_src.iface_name); curproxy->conn_src.iface_len = defproxy.conn_src.iface_len; curproxy->conn_src.opts = defproxy.conn_src.opts; -#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY) +#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_TRANSPARENT) curproxy->conn_src.tproxy_addr = defproxy.conn_src.tproxy_addr; #endif } @@ -4558,8 +4558,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) cur_arg += 2; while (*(args[cur_arg])) { if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */ -#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY) -#if !defined(CONFIG_HAP_LINUX_TPROXY) +#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_TRANSPARENT) +#if !defined(CONFIG_HAP_TRANSPARENT) if (!is_addr(&newsrv->conn_src.source_addr)) { Alert("parsing [%s:%d] : '%s' requires an explicit '%s' address.\n", file, linenum, "usesrc", "source"); @@ -4648,7 +4648,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) newsrv->conn_src.opts |= CO_SRC_TPROXY_ADDR; } global.last_checks |= LSTCHK_NETADM; -#if !defined(CONFIG_HAP_LINUX_TPROXY) +#if !defined(CONFIG_HAP_TRANSPARENT) global.last_checks |= LSTCHK_CTTPROXY; #endif cur_arg += 2; @@ -4658,7 +4658,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) file, linenum, "usesrc"); err_code |= ERR_ALERT | ERR_FATAL; goto out; -#endif /* defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY) */ +#endif /* defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_TRANSPARENT) */ } /* "usesrc" */ if (!strcmp(args[cur_arg], "interface")) { /* specifically bind to this interface */ @@ -5046,8 +5046,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) cur_arg = 2; while (*(args[cur_arg])) { if (!strcmp(args[cur_arg], "usesrc")) { /* address to use outside */ -#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY) -#if !defined(CONFIG_HAP_LINUX_TPROXY) +#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_TRANSPARENT) +#if !defined(CONFIG_HAP_TRANSPARENT) if (!is_addr(&curproxy->conn_src.source_addr)) { Alert("parsing [%s:%d] : '%s' requires an explicit 'source' address.\n", file, linenum, "usesrc"); @@ -5136,7 +5136,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) curproxy->conn_src.opts |= CO_SRC_TPROXY_ADDR; } global.last_checks |= LSTCHK_NETADM; -#if !defined(CONFIG_HAP_LINUX_TPROXY) +#if !defined(CONFIG_HAP_TRANSPARENT) global.last_checks |= LSTCHK_CTTPROXY; #endif #else /* no TPROXY support */ @@ -6826,7 +6826,7 @@ int check_config_validity() } } -#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY) +#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_TRANSPARENT) if (curproxy->conn_src.bind_hdr_occ) { curproxy->conn_src.bind_hdr_occ = 0; Warning("config : %s '%s' : ignoring use of header %s as source IP in non-HTTP mode.\n", @@ -6853,7 +6853,7 @@ int check_config_validity() err_code |= ERR_WARN; } -#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY) +#if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_TRANSPARENT) if (curproxy->mode != PR_MODE_HTTP && newsrv->conn_src.bind_hdr_occ) { newsrv->conn_src.bind_hdr_occ = 0; Warning("config : %s '%s' : server %s cannot use header %s as source IP in non-HTTP mode.\n", diff --git a/src/haproxy.c b/src/haproxy.c index 6155ea34be..d5606faeca 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -313,6 +313,22 @@ void display_build_opts() printf("Built without PCRE support (using libc's regex instead)\n"); #endif +#if defined(CONFIG_HAP_TRANSPARENT) || defined(CONFIG_HAP_CTTPROXY) + printf("Built with transparent proxy support using:" +#if defined(CONFIG_HAP_CTTPROXY) + " CTTPROXY" +#endif +#if defined(IP_TRANSPARENT) + " IP_TRANSPARENT" +#endif +#if defined(IPV6_TRANSPARENT) + " IPV6_TRANSPARENT" +#endif +#if defined(IP_FREEBIND) + " IP_FREEBIND" +#endif + "\n"); +#endif putchar('\n'); list_pollers(stdout); diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 97bc33bd6e..f59c23b413 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -122,15 +122,24 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct so struct sockaddr_storage bind_addr; int foreign_ok = 0; int ret; - -#ifdef CONFIG_HAP_LINUX_TPROXY static int ip_transp_working = 1; static int ip6_transp_working = 1; + switch (local->ss_family) { case AF_INET: if (flags && ip_transp_working) { - if (setsockopt(fd, SOL_IP, IP_TRANSPARENT, &one, sizeof(one)) == 0 - || setsockopt(fd, SOL_IP, IP_FREEBIND, &one, sizeof(one)) == 0) + /* This deserves some explanation. Some platforms will support + * 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 + ) foreign_ok = 1; else ip_transp_working = 0; @@ -138,14 +147,18 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct so break; case AF_INET6: if (flags && ip6_transp_working) { - if (setsockopt(fd, SOL_IPV6, IPV6_TRANSPARENT, &one, sizeof(one)) == 0) + if (0 +#if defined(IPV6_TRANSPARENT) + || (setsockopt(fd, SOL_IPV6, IPV6_TRANSPARENT, &one, sizeof(one)) == 0) +#endif + ) foreign_ok = 1; else ip6_transp_working = 0; } break; } -#endif + if (flags) { memset(&bind_addr, 0, sizeof(bind_addr)); bind_addr.ss_family = remote->ss_family; @@ -621,25 +634,35 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen) if (!ext) setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)); #endif -#ifdef CONFIG_HAP_LINUX_TPROXY + if (!ext && (listener->options & LI_O_FOREIGN)) { switch (listener->addr.ss_family) { case AF_INET: - if ((setsockopt(fd, SOL_IP, IP_TRANSPARENT, &one, sizeof(one)) == -1) - && (setsockopt(fd, SOL_IP, IP_FREEBIND, &one, sizeof(one)) == -1)) { + 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 + ) { msg = "cannot make listening socket transparent"; err |= ERR_ALERT; } break; case AF_INET6: - if (setsockopt(fd, SOL_IPV6, IPV6_TRANSPARENT, &one, sizeof(one)) == -1) { + if (1 +#if defined(IPV6_TRANSPARENT) + && (setsockopt(fd, SOL_IPV6, IPV6_TRANSPARENT, &one, sizeof(one)) == -1) +#endif + ) { msg = "cannot make listening socket transparent"; err |= ERR_ALERT; } break; } } -#endif + #ifdef SO_BINDTODEVICE /* Note: this might fail if not CAP_NET_RAW */ if (!ext && listener->interface) { @@ -1546,7 +1569,7 @@ static int bind_parse_v6only(char **args, int cur_arg, struct proxy *px, struct } #endif -#ifdef CONFIG_HAP_LINUX_TPROXY +#ifdef CONFIG_HAP_TRANSPARENT /* parse the "transparent" bind keyword */ static int bind_parse_transparent(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { @@ -1695,7 +1718,7 @@ static struct bind_kw_list bind_kws = { "TCP", { }, { #ifdef TCP_FASTOPEN { "tfo", bind_parse_tfo, 0 }, /* enable TCP_FASTOPEN of listening socket */ #endif -#ifdef CONFIG_HAP_LINUX_TPROXY +#ifdef CONFIG_HAP_TRANSPARENT { "transparent", bind_parse_transparent, 0 }, /* transparently bind to the specified addresses */ #endif #ifdef IPV6_V6ONLY