REORG: tproxy: prepare the transparent proxy defines for accepting other OSes

This patch does not change the logic of the code, it only changes the
way OS-specific defines are tested.

At the moment the transparent proxy code heavily depends on Linux-specific
defines. This first patch introduces a new define "CONFIG_HAP_TRANSPARENT"
which is set every time the defines used by transparent proxy are present.
This also means that with an up-to-date libc, it should not be necessary
anymore to force CONFIG_HAP_LINUX_TPROXY during the build, as the flags
will automatically be detected.

The CTTPROXY flags still remain separate because this older API doesn't
work the same way.

A new line has been added in the version output for haproxy -vv to indicate
what transparent proxy support is available.
diff --git a/src/backend.c b/src/backend.c
index 9f4e635..9f23018 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -884,7 +884,7 @@
  */
 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 6f2850c..9907bfd 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1813,7 +1813,7 @@
 				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 @@
 				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 @@
 							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 @@
 						      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 @@
 		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 @@
 					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 @@
 				}
 			}
 
-#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 @@
 				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 6155ea3..d5606fa 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -313,6 +313,22 @@
 	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 97bc33b..f59c23b 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -122,15 +122,24 @@
 	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 @@
 		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 @@
 	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 @@
 }
 #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 @@
 #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