From: Remi Gacogne Date: Tue, 14 Jun 2022 16:15:15 +0000 (+0200) Subject: dnsdist: Bind to the requested src interface without a src address X-Git-Tag: auth-4.8.0-alpha0~44^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5dd560067fbb23b78480d20a760693403c9b69b7;p=thirdparty%2Fpdns.git dnsdist: Bind to the requested src interface without a src address In some cases we want to bind to a specific interface when contacting a backend without specifying an exact source address, leaving the kernel select one for us. --- diff --git a/pdns/dnsdistdist/dnsdist-backend.cc b/pdns/dnsdistdist/dnsdist-backend.cc index ac655111fa..f2094606e0 100644 --- a/pdns/dnsdistdist/dnsdist-backend.cc +++ b/pdns/dnsdistdist/dnsdist-backend.cc @@ -58,17 +58,18 @@ bool DownstreamState::reconnect() } if (!IsAnyAddress(d_config.remote)) { fd = SSocket(d_config.remote.sin4.sin_family, SOCK_DGRAM, 0); - if (!IsAnyAddress(d_config.sourceAddr)) { - SSetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 1); - if (!d_config.sourceItfName.empty()) { + + if (!d_config.sourceItfName.empty()) { #ifdef SO_BINDTODEVICE - int res = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, d_config.sourceItfName.c_str(), d_config.sourceItfName.length()); - if (res != 0) { - infolog("Error setting up the interface on backend socket '%s': %s", d_config.remote.toStringWithPort(), stringerror()); - } -#endif + int res = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, d_config.sourceItfName.c_str(), d_config.sourceItfName.length()); + if (res != 0) { + infolog("Error setting up the interface on backend socket '%s': %s", d_config.remote.toStringWithPort(), stringerror()); } +#endif + } + if (!IsAnyAddress(d_config.sourceAddr)) { + SSetsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 1); SBind(fd, d_config.sourceAddr); } try { @@ -78,7 +79,7 @@ bool DownstreamState::reconnect() } connected = true; } - catch(const std::runtime_error& error) { + catch (const std::runtime_error& error) { infolog("Error connecting to new server with address %s: %s", d_config.remote.toStringWithPort(), error.what()); connected = false; break; diff --git a/pdns/dnsdistdist/dnsdist-healthchecks.cc b/pdns/dnsdistdist/dnsdist-healthchecks.cc index 64efdf5341..5430555924 100644 --- a/pdns/dnsdistdist/dnsdist-healthchecks.cc +++ b/pdns/dnsdistdist/dnsdist-healthchecks.cc @@ -368,6 +368,15 @@ bool queueHealthCheck(std::unique_ptr& mplexer, const std::shared Socket sock(ds->d_config.remote.sin4.sin_family, ds->doHealthcheckOverTCP() ? SOCK_STREAM : SOCK_DGRAM); sock.setNonBlocking(); + if (!ds->d_config.sourceItfName.empty()) { +#ifdef SO_BINDTODEVICE + int res = setsockopt(sock.getHandle(), SOL_SOCKET, SO_BINDTODEVICE, ds->d_config.sourceItfName.c_str(), ds->d_config.sourceItfName.length()); + if (res != 0 && g_verboseHealthChecks) { + infolog("Error setting SO_BINDTODEVICE on the health check socket for backend '%s': %s", ds->getNameWithAddr(), stringerror()); + } +#endif + } + if (!IsAnyAddress(ds->d_config.sourceAddr)) { sock.setReuseAddr(); #ifdef IP_BIND_ADDRESS_NO_PORT @@ -375,15 +384,6 @@ bool queueHealthCheck(std::unique_ptr& mplexer, const std::shared SSetsockopt(sock.getHandle(), SOL_IP, IP_BIND_ADDRESS_NO_PORT, 1); } #endif - - if (!ds->d_config.sourceItfName.empty()) { -#ifdef SO_BINDTODEVICE - int res = setsockopt(sock.getHandle(), SOL_SOCKET, SO_BINDTODEVICE, ds->d_config.sourceItfName.c_str(), ds->d_config.sourceItfName.length()); - if (res != 0 && g_verboseHealthChecks) { - infolog("Error setting SO_BINDTODEVICE on the health check socket for backend '%s': %s", ds->getNameWithAddr(), stringerror()); - } -#endif - } sock.bind(ds->d_config.sourceAddr); } diff --git a/pdns/dnsdistdist/dnsdist-tcp-downstream.cc b/pdns/dnsdistdist/dnsdist-tcp-downstream.cc index 1dbf7cc96c..b254c6732b 100644 --- a/pdns/dnsdistdist/dnsdist-tcp-downstream.cc +++ b/pdns/dnsdistdist/dnsdist-tcp-downstream.cc @@ -76,23 +76,25 @@ bool ConnectionToBackend::reconnect() auto socket = std::make_unique(d_ds->d_config.remote.sin4.sin_family, SOCK_STREAM, 0); DEBUGLOG("result of socket() is "<getHandle()); +#ifdef SO_BINDTODEVICE + if (!d_ds->d_config.sourceItfName.empty()) { + int res = setsockopt(socket->getHandle(), SOL_SOCKET, SO_BINDTODEVICE, d_ds->d_config.sourceItfName.c_str(), d_ds->d_config.sourceItfName.length()); + if (res != 0) { + vinfolog("Error setting up the interface on backend TCP socket '%s': %s", d_ds->getNameWithAddr(), stringerror()); + } + } +#endif + if (!IsAnyAddress(d_ds->d_config.sourceAddr)) { SSetsockopt(socket->getHandle(), SOL_SOCKET, SO_REUSEADDR, 1); #ifdef IP_BIND_ADDRESS_NO_PORT if (d_ds->d_config.ipBindAddrNoPort) { SSetsockopt(socket->getHandle(), SOL_IP, IP_BIND_ADDRESS_NO_PORT, 1); } -#endif -#ifdef SO_BINDTODEVICE - if (!d_ds->d_config.sourceItfName.empty()) { - int res = setsockopt(socket->getHandle(), SOL_SOCKET, SO_BINDTODEVICE, d_ds->d_config.sourceItfName.c_str(), d_ds->d_config.sourceItfName.length()); - if (res != 0) { - vinfolog("Error setting up the interface on backend TCP socket '%s': %s", d_ds->getNameWithAddr(), stringerror()); - } - } #endif socket->bind(d_ds->d_config.sourceAddr, false); } + socket->setNonBlocking(); gettimeofday(&d_connectionStartTime, nullptr);