From: Remi Gacogne Date: Mon, 8 Feb 2016 11:38:59 +0000 (+0100) Subject: dnsdist: Add an optional reuseport param to {add,set}Local() X-Git-Tag: rec-4.0.0-alpha2~50^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4c34246d52f3bfd12af6582c1ba661ab5ce090af;p=thirdparty%2Fpdns.git dnsdist: Add an optional reuseport param to {add,set}Local() If set to true, this parameter sets SO_REUSEPORT on platforms supporting for this option, allowing multiple servers to bind to the same port. The same parameter is also added to addDNSCryptBind(). --- diff --git a/pdns/README-dnsdist.md b/pdns/README-dnsdist.md index e601643aff..fed94ca27b 100644 --- a/pdns/README-dnsdist.md +++ b/pdns/README-dnsdist.md @@ -805,8 +805,8 @@ Here are all functions: * `setACL({netmask, netmask})`: replace the ACL set with these netmasks. Use `setACL({})` to reset the list, meaning no one can use us * `showACL()`: show our ACL set * Network related: - * `addLocal(netmask, [false])`: add to addresses we listen on. Second optional parameter sets TCP/IP or not. - * `setLocal(netmask, [false])`: reset list of addresses we listen on to this address. Second optional parameter sets TCP/IP or not. + * `addLocal(netmask, [false], [false])`: add to addresses we listen on. Second optional parameter sets TCP/IP or not. Third optional parameter sets SO_REUSEPORT when available. + * `setLocal(netmask, [false], [false])`: reset list of addresses we listen on to this address. Second optional parameter sets TCP/IP or not. Third optional parameter sets SO_REUSEPORT when available. * Blocking related: * `addDomainBlock(domain)`: block queries within this domain * Carbon/Graphite/Metronome statistics related: @@ -1008,7 +1008,7 @@ instantiate a server with additional parameters * `setMaxUDPOutstanding(n)`: set the maximum number of outstanding UDP queries to a given backend server. This can only be set at configuration time * `setCacheCleaningDelay(n)`: set the interval in seconds between two runs of the cache cleaning algorithm, removing expired entries * DNSCrypt related: - * `addDNSCryptBind("127.0.0.1:8443", "provider name", "/path/to/resolver.cert", "/path/to/resolver.key"):` listen to incoming DNSCrypt queries on 127.0.0.1 port 8443, with a provider name of "provider name", using a resolver certificate and associated key stored respectively in the `resolver.cert` and `resolver.key` files + * `addDNSCryptBind("127.0.0.1:8443", "provider name", "/path/to/resolver.cert", "/path/to/resolver.key", [false]):` listen to incoming DNSCrypt queries on 127.0.0.1 port 8443, with a provider name of "provider name", using a resolver certificate and associated key stored respectively in the `resolver.cert` and `resolver.key` files. The last optional parameter sets SO_REUSEPORT when available * `generateDNSCryptProviderKeys("/path/to/providerPublic.key", "/path/to/providerPrivate.key"):` generate a new provider keypair * `generateDNSCryptCertificate("/path/to/providerPrivate.key", "/path/to/resolver.cert", "/path/to/resolver.key", serial, validFrom, validUntil):` generate a new resolver private key and related certificate, valid from the `validFrom` timestamp until the `validUntil` one, signed with the provider private key * `printDNSCryptProviderFingerprint("/path/to/providerPublic.key")`: display the fingerprint of the provided resolver public key diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index d114634787..e71619151d 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -436,7 +436,7 @@ vector> setupLua(bool client, const std::string& confi g_ACL.modify([domain](NetmaskGroup& nmg) { nmg.addMask(domain); }); }); - g_lua.writeFunction("setLocal", [client](const std::string& addr, boost::optional doTCP) { + g_lua.writeFunction("setLocal", [client](const std::string& addr, boost::optional doTCP, boost::optional reusePort) { setLuaSideEffect(); if(client) return; @@ -447,14 +447,14 @@ vector> setupLua(bool client, const std::string& confi try { ComboAddress loc(addr, 53); g_locals.clear(); - g_locals.push_back({loc, doTCP ? *doTCP : true}); /// only works pre-startup, so no sync necessary + g_locals.push_back(std::make_tuple(loc, doTCP ? *doTCP : true, reusePort ? *reusePort : false)); /// only works pre-startup, so no sync necessary } catch(std::exception& e) { g_outputBuffer="Error: "+string(e.what())+"\n"; } }); - g_lua.writeFunction("addLocal", [client](const std::string& addr, boost::optional doTCP) { + g_lua.writeFunction("addLocal", [client](const std::string& addr, boost::optional doTCP, boost::optional reusePort) { setLuaSideEffect(); if(client) return; @@ -464,7 +464,7 @@ vector> setupLua(bool client, const std::string& confi } try { ComboAddress loc(addr, 53); - g_locals.push_back({loc, doTCP ? *doTCP : true}); /// only works pre-startup, so no sync necessary + g_locals.push_back(std::make_tuple(loc, doTCP ? *doTCP : true, reusePort ? *reusePort : false)); /// only works pre-startup, so no sync necessary } catch(std::exception& e) { g_outputBuffer="Error: "+string(e.what())+"\n"; diff --git a/pdns/dnsdist-lua2.cc b/pdns/dnsdist-lua2.cc index a78a1e5564..3360fc57b5 100644 --- a/pdns/dnsdist-lua2.cc +++ b/pdns/dnsdist-lua2.cc @@ -356,7 +356,7 @@ void moreLua(bool client) } }); - g_lua.writeFunction("addDNSCryptBind", [](const std::string& addr, const std::string& providerName, const std::string& certFile, const std::string keyFile) { + g_lua.writeFunction("addDNSCryptBind", [](const std::string& addr, const std::string& providerName, const std::string& certFile, const std::string keyFile, boost::optional reusePort) { if (g_configurationDone) { g_outputBuffer="addDNSCryptBind cannot be used at runtime!\n"; return; @@ -364,7 +364,7 @@ void moreLua(bool client) #ifdef HAVE_DNSCRYPT try { DnsCryptContext ctx(providerName, certFile, keyFile); - g_dnsCryptLocals.push_back({ComboAddress(addr, 443), ctx}); + g_dnsCryptLocals.push_back(std::make_tuple(ComboAddress(addr, 443), ctx, reusePort ? *reusePort : false)); } catch(std::exception& e) { errlog(e.what()); @@ -384,12 +384,12 @@ void moreLua(bool client) size_t idx = 0; for (const auto& local : g_dnsCryptLocals) { - const DnsCryptContext& ctx = local.second; + const DnsCryptContext& ctx = std::get<1>(local); bool const hasOldCert = ctx.hadOldCertificate(); const DnsCryptCert& cert = ctx.getCurrentCertificate(); const DnsCryptCert& oldCert = ctx.getOldCertificate(); - ret<< (fmt % idx % local.first.toStringWithPort() % ctx.getProviderName() % cert.signedData.serial % DnsCryptContext::certificateDateToStr(cert.signedData.tsEnd) % (hasOldCert ? oldCert.signedData.serial : 0) % (hasOldCert ? DnsCryptContext::certificateDateToStr(oldCert.signedData.tsEnd) : "-")) << endl; + ret<< (fmt % idx % std::get<0>(local).toStringWithPort() % ctx.getProviderName() % cert.signedData.serial % DnsCryptContext::certificateDateToStr(cert.signedData.tsEnd) % (hasOldCert ? oldCert.signedData.serial : 0) % (hasOldCert ? DnsCryptContext::certificateDateToStr(oldCert.signedData.tsEnd) : "-")) << endl; idx++; } diff --git a/pdns/dnsdist-web.cc b/pdns/dnsdist-web.cc index d5a1e47c28..007d34238a 100644 --- a/pdns/dnsdist-web.cc +++ b/pdns/dnsdist-web.cc @@ -206,7 +206,7 @@ static void connectionThread(int sock, ComboAddress remote, string password) string localaddresses; for(const auto& loc : g_locals) { if(!localaddresses.empty()) localaddresses += ", "; - localaddresses += loc.first.toStringWithPort(); + localaddresses += std::get<0>(loc).toStringWithPort(); } Json my_json = Json::object { diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index a793a15d92..c81d6373d2 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -65,9 +65,9 @@ bool g_verboseHealthChecks{false}; GlobalStateHolder g_ACL; string g_outputBuffer; -vector> g_locals; +vector> g_locals; #ifdef HAVE_DNSCRYPT -std::vector> g_dnsCryptLocals; +std::vector> g_dnsCryptLocals; #endif vector g_frontends; GlobalStateHolder g_pools; @@ -1339,11 +1339,11 @@ try if(g_cmdLine.locals.size()) { g_locals.clear(); for(auto loc : g_cmdLine.locals) - g_locals.push_back({ComboAddress(loc, 53), true}); + g_locals.push_back(std::make_tuple(ComboAddress(loc, 53), true, false)); } if(g_locals.empty()) - g_locals.push_back({ComboAddress("127.0.0.1", 53), true}); + g_locals.push_back(std::make_tuple(ComboAddress("127.0.0.1", 53), true, false)); g_configurationDone = true; @@ -1351,25 +1351,30 @@ try vector toLaunch; for(const auto& local : g_locals) { ClientState* cs = new ClientState; - cs->local= local.first; + cs->local= std::get<0>(local); cs->udpFD = SSocket(cs->local.sin4.sin_family, SOCK_DGRAM, 0); if(cs->local.sin4.sin_family == AF_INET6) { SSetsockopt(cs->udpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1); } //if(g_vm.count("bind-non-local")) - bindAny(local.first.sin4.sin_family, cs->udpFD); + bindAny(cs->local.sin4.sin_family, cs->udpFD); // if (!setSocketTimestamps(cs->udpFD)) // L<local)) { int one=1; setsockopt(cs->udpFD, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems #ifdef IPV6_RECVPKTINFO setsockopt(cs->udpFD, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); #endif } +#ifdef SO_REUSEPORT + if (std::get<2>(local)) { + SSetsockopt(cs->udpFD, SOL_SOCKET, SO_REUSEPORT, 1); + } +#endif SBind(cs->udpFD, cs->local); toLaunch.push_back(cs); @@ -1377,12 +1382,12 @@ try } for(const auto& local : g_locals) { - if(!local.second) { // no TCP/IP - warnlog("Not providing TCP/IP service on local address '%s'", local.first.toStringWithPort()); + if(!std::get<1>(local)) { // no TCP/IP + warnlog("Not providing TCP/IP service on local address '%s'", std::get<0>(local).toStringWithPort()); continue; } ClientState* cs = new ClientState; - cs->local= local.first; + cs->local= std::get<0>(local); cs->tcpFD = SSocket(cs->local.sin4.sin_family, SOCK_STREAM, 0); @@ -1393,6 +1398,11 @@ try if(cs->local.sin4.sin_family == AF_INET6) { SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1); } +#ifdef SO_REUSEPORT + if (std::get<2>(local)) { + SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEPORT, 1); + } +#endif // if(g_vm.count("bind-non-local")) bindAny(cs->local.sin4.sin_family, cs->tcpFD); SBind(cs->tcpFD, cs->local); @@ -1406,8 +1416,8 @@ try #ifdef HAVE_DNSCRYPT for(auto& dcLocal : g_dnsCryptLocals) { ClientState* cs = new ClientState; - cs->local = dcLocal.first; - cs->dnscryptCtx = &dcLocal.second; + cs->local = std::get<0>(dcLocal); + cs->dnscryptCtx = &(std::get<1>(dcLocal)); cs->udpFD = SSocket(cs->local.sin4.sin_family, SOCK_DGRAM, 0); if(cs->local.sin4.sin_family == AF_INET6) { SSetsockopt(cs->udpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1); @@ -1425,12 +1435,17 @@ try g_frontends.push_back(cs); cs = new ClientState; - cs->local = dcLocal.first; - cs->dnscryptCtx = &dcLocal.second; + cs->local = std::get<0>(dcLocal); + cs->dnscryptCtx = &(std::get<1>(dcLocal)); cs->tcpFD = SSocket(cs->local.sin4.sin_family, SOCK_STREAM, 0); SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEADDR, 1); #ifdef TCP_DEFER_ACCEPT SSetsockopt(cs->tcpFD, SOL_TCP,TCP_DEFER_ACCEPT, 1); +#endif +#ifdef SO_REUSEPORT + if (std::get<2>(dcLocal)) { + SSetsockopt(cs->tcpFD, SOL_SOCKET, SO_REUSEPORT, 1); + } #endif if(cs->local.sin4.sin_family == AF_INET6) { SSetsockopt(cs->tcpFD, IPPROTO_IPV6, IPV6_V6ONLY, 1); diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index d979d4e5eb..61ef35daf1 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -454,7 +454,7 @@ extern GlobalStateHolder g_ACL; extern ComboAddress g_serverControl; // not changed during runtime -extern std::vector> g_locals; // not changed at runtime (we hope XXX) +extern std::vector> g_locals; // not changed at runtime (we hope XXX) extern vector g_frontends; extern std::string g_key; // in theory needs locking extern bool g_truncateTC; @@ -505,7 +505,7 @@ bool getLuaNoSideEffect(); // set if there were only explicit declarations of _n void resetLuaSideEffect(); // reset to indeterminate state #ifdef HAVE_DNSCRYPT -extern std::vector> g_dnsCryptLocals; +extern std::vector> g_dnsCryptLocals; int handleDnsCryptQuery(DnsCryptContext* ctx, char* packet, uint16_t len, std::shared_ptr& query, uint16_t* decryptedQueryLen, bool tcp, std::vector& reponse); #endif