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);
#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>
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.
*/
}
+/* 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.
*/