]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: reload: determine the foreing binding status from the socket
authorWilly Tarreau <w@1wt.eu>
Wed, 26 Aug 2020 08:23:40 +0000 (10:23 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 26 Aug 2020 08:33:02 +0000 (10:33 +0200)
Let's not look at the listener options passed by the original process
and determine from the socket itself whether it is configured for
transparent mode or not. This is cleaner and safer, and doesn't rely
on flag values that could possibly change between versions.

include/haproxy/proto_tcp.h
src/haproxy.c
src/proto_tcp.c

index 50748a68fe186309db37e41895f396f178b6c495..e3eeca91c4daf15870f7b9acc8c90ecd23ca1d82 100644 (file)
@@ -33,6 +33,7 @@ int tcp_pause_listener(struct listener *l);
 int tcp_connect_server(struct connection *conn, int flags);
 int tcp_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir);
 int tcp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir);
+int tcp_is_foreign(int fd, sa_family_t family);
 
 /* Export some samples. */
 int smp_fetch_src(const struct arg *args, struct sample *smp, const char *kw, void *private);
index 028ebcda07bae22fdf592318bb1a91611eada82b..5b3252256c4f7f72840b005917f17adb8e542537 100644 (file)
 #include <haproxy/peers.h>
 #include <haproxy/pool.h>
 #include <haproxy/protocol.h>
+#include <haproxy/proto_tcp.h>
 #include <haproxy/proxy.h>
 #include <haproxy/regex.h>
 #include <haproxy/sample.h>
@@ -1298,6 +1299,11 @@ static int get_old_sockets(const char *unixsocket)
                    sizeof(xfer_sock->options));
                curoff += sizeof(xfer_sock->options);
 
+               /* determine the foreign status directly from the socket itself */
+               xfer_sock->options &= ~LI_O_FOREIGN;
+               if (tcp_is_foreign(fd, xfer_sock->addr.ss_family))
+                       xfer_sock->options |= LI_O_FOREIGN;
+
                /* keep only the v6only flag depending on what's currently
                 * active on the socket, and always drop the v4v6 one.
                 */
index 3d56cf60b568f59d7ae482c931a67529e2b631c8..2f8ec22e8ef321db2a7ce010026e535f467e9250 100644 (file)
@@ -681,6 +681,65 @@ static int compare_sockaddr(struct sockaddr_storage *a, struct sockaddr_storage
 
 }
 
+/* Returns true if the passed FD corresponds to a socket bound with LI_O_FOREIGN
+ * according to the various supported socket options. The socket's address family
+ * must be passed in <family>.
+ */
+int tcp_is_foreign(int fd, sa_family_t family)
+{
+       int val __maybe_unused;
+       socklen_t len __maybe_unused;
+
+       switch (family) {
+       case AF_INET:
+#if defined(IP_TRANSPARENT)
+               val = 0; len = sizeof(val);
+               if (getsockopt(fd, SOL_IP, IP_TRANSPARENT, &val, &len) == 0 && val)
+                       return 1;
+#endif
+#if defined(IP_FREEBIND)
+               val = 0; len = sizeof(val);
+               if (getsockopt(fd, SOL_IP, IP_FREEBIND, &val, &len) == 0 && val)
+                       return 1;
+#endif
+#if defined(IP_BINDANY)
+               val = 0; len = sizeof(val);
+               if (getsockopt(fd, IPPROTO_IP, IP_BINDANY, &val, &len) == 0 && val)
+                       return 1;
+#endif
+#if defined(SO_BINDANY)
+               val = 0; len = sizeof(val);
+               if (getsockopt(fd, SOL_SOCKET, SO_BINDANY, &val, &len) == 0 && val)
+                       return 1;
+#endif
+               break;
+
+       case AF_INET6:
+#if defined(IPV6_TRANSPARENT) && defined(SOL_IPV6)
+               val = 0; len = sizeof(val);
+               if (getsockopt(fd, SOL_IPV6, IPV6_TRANSPARENT, &val, &len) == 0 && val)
+                       return 1;
+#endif
+#if defined(IP_FREEBIND)
+               val = 0; len = sizeof(val);
+               if (getsockopt(fd, SOL_IP, IP_FREEBIND, &val, &len) == 0 && val)
+                       return 1;
+#endif
+#if defined(IPV6_BINDANY)
+               val = 0; len = sizeof(val);
+               if (getsockopt(fd, IPPROTO_IPV6, IPV6_BINDANY, &val, &len) == 0 && val)
+                       return 1;
+#endif
+#if defined(SO_BINDANY)
+               val = 0; len = sizeof(val);
+               if (getsockopt(fd, SOL_SOCKET, SO_BINDANY, &val, &len) == 0 && val)
+                       return 1;
+#endif
+               break;
+       }
+       return 0;
+}
+
 /* sets the v6only_default flag according to the OS' default settings; for
  * simplicity it's set to zero if not supported.
  */