From: Karel Bilek Date: Wed, 3 Sep 2025 07:54:45 +0000 (+0200) Subject: dnsdist: add support for TCP Fast Open on macOS X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cefcfabbab3109237244acf9ad6933c6b13fef4b;p=thirdparty%2Fpdns.git dnsdist: add support for TCP Fast Open on macOS This uses Apple's connectx() API instead of UNIX connect() API. Signed-off-by: Karel Bilek --- diff --git a/pdns/dnsdistdist/dnsdist-backend.cc b/pdns/dnsdistdist/dnsdist-backend.cc index fa44589457..2bf6ff55e9 100644 --- a/pdns/dnsdistdist/dnsdist-backend.cc +++ b/pdns/dnsdistdist/dnsdist-backend.cc @@ -141,7 +141,7 @@ bool DownstreamState::reconnect(bool initialAttempt) try { setDscp(fd, d_config.remote.sin4.sin_family, d_config.dscp); - SConnect(fd, d_config.remote); + SConnect(fd, d_config.tcpFastOpen, d_config.remote); if (sockets.size() > 1) { (*mplexer.lock())->addReadFD(fd, [](int, boost::any) {}); } diff --git a/pdns/dnsdistdist/dnsdist-console.cc b/pdns/dnsdistdist/dnsdist-console.cc index db0e9735fb..9a6f36127e 100644 --- a/pdns/dnsdistdist/dnsdist-console.cc +++ b/pdns/dnsdistdist/dnsdist-console.cc @@ -245,7 +245,7 @@ void doClient(const std::string& command) cerr << "Unable to connect to " << server.toStringWithPort() << endl; return; } - SConnect(fileDesc.getHandle(), server); + SConnect(fileDesc.getHandle(), false, server); setTCPNoDelay(fileDesc.getHandle()); dnsdist::crypto::authenticated::Nonce theirs; dnsdist::crypto::authenticated::Nonce ours; diff --git a/pdns/dnsdistdist/dnsdist-lua.cc b/pdns/dnsdistdist/dnsdist-lua.cc index 151f935647..13e8f3241c 100644 --- a/pdns/dnsdistdist/dnsdist-lua.cc +++ b/pdns/dnsdistdist/dnsdist-lua.cc @@ -69,6 +69,7 @@ #include "doq-common.hh" #include "dolog.hh" #include "threadname.hh" +#include "iputils.hh" #ifdef HAVE_LIBSSL #include "libssl.hh" @@ -459,7 +460,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck) bool fastOpen{false}; if (getOptionalValue(vars, "tcpFastOpen", fastOpen) > 0) { if (fastOpen) { -#ifdef MSG_FASTOPEN +#if defined(MSG_FASTOPEN) || defined(CONNECTX_FASTOPEN) config.tcpFastOpen = true; #else warnlog("TCP Fast Open has been configured on downstream server %s but is not supported", serverAddressStr); diff --git a/pdns/dnsdistdist/test-dnsdistnghttp2_common.hh b/pdns/dnsdistdist/test-dnsdistnghttp2_common.hh index afcdc38d26..538b4c2d9e 100644 --- a/pdns/dnsdistdist/test-dnsdistnghttp2_common.hh +++ b/pdns/dnsdistdist/test-dnsdistnghttp2_common.hh @@ -144,7 +144,7 @@ static bool isIPv6Supported() ComboAddress addr("[2001:db8:53::1]:53"); auto socket = std::make_unique(addr.sin4.sin_family, SOCK_STREAM, 0); socket->setNonBlocking(); - int res = SConnectWithTimeout(socket->getHandle(), addr, timeval{0, 0}); + int res = SConnectWithTimeout(socket->getHandle(), false, addr, timeval{0, 0}); if (res == 0 || res == EINPROGRESS) { return true; } diff --git a/pdns/dnsdistdist/test-dnsdisttcp_cc.cc b/pdns/dnsdistdist/test-dnsdisttcp_cc.cc index 53c8b1110a..6bb9a36116 100644 --- a/pdns/dnsdistdist/test-dnsdisttcp_cc.cc +++ b/pdns/dnsdistdist/test-dnsdisttcp_cc.cc @@ -449,7 +449,7 @@ static bool isIPv6Supported() ComboAddress addr("[2001:db8:53::1]:53"); auto socket = std::make_unique(addr.sin4.sin_family, SOCK_STREAM, 0); socket->setNonBlocking(); - int res = SConnectWithTimeout(socket->getHandle(), addr, timeval{0, 0}); + int res = SConnectWithTimeout(socket->getHandle(), false, addr, timeval{0, 0}); if (res == 0 || res == EINPROGRESS) { return true; } diff --git a/pdns/iputils.cc b/pdns/iputils.cc index e578f0110a..74b61c9e4a 100644 --- a/pdns/iputils.cc +++ b/pdns/iputils.cc @@ -54,9 +54,29 @@ int SSocket(int family, int type, int flags) return ret; } -int SConnect(int sockfd, const ComboAddress& remote) +static int doConnect(int sockfd, [[maybe_unused]] bool fastopen, const ComboAddress& remote) { - int ret = connect(sockfd, reinterpret_cast(&remote), remote.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) +#ifdef CONNECTX_FASTOPEN + if (fastopen) { + sa_endpoints_t endpoints{}; + + endpoints.sae_dstaddr = reinterpret_cast(&remote); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + endpoints.sae_dstaddrlen = remote.getSocklen(); + + int flags = CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE; + return connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, flags, nullptr, 0, nullptr, nullptr); + } + else { +#endif + return connect(sockfd, reinterpret_cast(&remote), remote.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) +#ifdef CONNECTX_FASTOPEN + } +#endif +} + +int SConnect(int sockfd, bool fastopen, const ComboAddress& remote) +{ + int ret = doConnect(sockfd, fastopen, remote); if (ret < 0) { int savederrno = errno; RuntimeError("connecting socket to " + remote.toStringWithPort() + ": " + stringerror(savederrno)); @@ -64,9 +84,9 @@ int SConnect(int sockfd, const ComboAddress& remote) return ret; } -int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout) +int SConnectWithTimeout(int sockfd, bool fastopen, const ComboAddress& remote, const struct timeval& timeout) { - int ret = connect(sockfd, reinterpret_cast(&remote), remote.getSocklen()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast) + int ret = doConnect(sockfd, fastopen, remote); if (ret < 0) { int savederrno = errno; if (savederrno == EINPROGRESS) { diff --git a/pdns/iputils.hh b/pdns/iputils.hh index d7b3ab9aec..d472a6c264 100644 --- a/pdns/iputils.hh +++ b/pdns/iputils.hh @@ -52,6 +52,11 @@ #define htole64(x) OSSwapHostToLittleInt64(x) #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) + +#if defined(CONNECT_DATA_IDEMPOTENT) && defined(CONNECT_RESUME_ON_READ_WRITE) +#define CONNECTX_FASTOPEN 1 +#endif + #endif #ifdef __sun @@ -2040,12 +2045,12 @@ private: }; int SSocket(int family, int type, int flags); -int SConnect(int sockfd, const ComboAddress& remote); +int SConnect(int sockfd, bool fastopen, const ComboAddress& remote); /* tries to connect to remote for a maximum of timeout seconds. sockfd should be set to non-blocking beforehand. returns 0 on success (the socket is writable), throw a runtime_error otherwise */ -int SConnectWithTimeout(int sockfd, const ComboAddress& remote, const struct timeval& timeout); +int SConnectWithTimeout(int sockfd, bool fastopen, const ComboAddress& remote, const struct timeval& timeout); int SBind(int sockfd, const ComboAddress& local); int SAccept(int sockfd, ComboAddress& remote); int SListen(int sockfd, int limit); diff --git a/pdns/sstuff.hh b/pdns/sstuff.hh index 50a81622db..8dc21afdb4 100644 --- a/pdns/sstuff.hh +++ b/pdns/sstuff.hh @@ -179,7 +179,7 @@ public: //! Connect the socket to a specified endpoint void connect(const ComboAddress& address, int timeout = 0) const { - SConnectWithTimeout(d_socket, address, timeval{timeout, 0}); + SConnectWithTimeout(d_socket, false, address, timeval{timeout, 0}); } //! For datagram sockets, receive a datagram and learn where it came from diff --git a/pdns/tcpiohandler.hh b/pdns/tcpiohandler.hh index 9450b61180..2d6bd1004f 100644 --- a/pdns/tcpiohandler.hh +++ b/pdns/tcpiohandler.hh @@ -313,12 +313,12 @@ public: } else { if (!s_disableConnectForUnitTests) { - SConnectWithTimeout(d_socket, remote, /* no timeout, we will handle it ourselves */ timeval{0,0}); + SConnectWithTimeout(d_socket, fastOpen, remote, /* no timeout, we will handle it ourselves */ timeval{0,0}); } } #else if (!s_disableConnectForUnitTests) { - SConnectWithTimeout(d_socket, remote, /* no timeout, we will handle it ourselves */ timeval{0,0}); + SConnectWithTimeout(d_socket, fastOpen, remote, /* no timeout, we will handle it ourselves */ timeval{0,0}); } #endif /* MSG_FASTOPEN */ @@ -349,12 +349,12 @@ public: } else { if (!s_disableConnectForUnitTests) { - SConnectWithTimeout(d_socket, remote, timeout); + SConnectWithTimeout(d_socket, fastOpen, remote, timeout); } } #else if (!s_disableConnectForUnitTests) { - SConnectWithTimeout(d_socket, remote, timeout); + SConnectWithTimeout(d_socket, fastOpen, remote, timeout); } #endif /* MSG_FASTOPEN */