]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add an optional reuseport param to {add,set}Local()
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 8 Feb 2016 11:38:59 +0000 (12:38 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 26 Feb 2016 13:14:07 +0000 (14:14 +0100)
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().

pdns/README-dnsdist.md
pdns/dnsdist-lua.cc
pdns/dnsdist-lua2.cc
pdns/dnsdist-web.cc
pdns/dnsdist.cc
pdns/dnsdist.hh

index e601643aff820a34bb4fae03ac3b4495f2b5cab4..fed94ca27b68317db6b715c9b79b11ec23a85117 100644 (file)
@@ -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
index d11463478747cd19eabb370ff5ee8edab7353714..e71619151d10a4346fc1c10dfec8561c31860add 100644 (file)
@@ -436,7 +436,7 @@ vector<std::function<void(void)>> 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<bool> doTCP) {
+  g_lua.writeFunction("setLocal", [client](const std::string& addr, boost::optional<bool> doTCP, boost::optional<bool> reusePort) {
       setLuaSideEffect();
       if(client)
        return;
@@ -447,14 +447,14 @@ vector<std::function<void(void)>> 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<bool> doTCP) {
+  g_lua.writeFunction("addLocal", [client](const std::string& addr, boost::optional<bool> doTCP, boost::optional<bool> reusePort) {
       setLuaSideEffect();
       if(client)
        return;
@@ -464,7 +464,7 @@ vector<std::function<void(void)>> 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";
index a78a1e5564aa8eca7fa8f7d05178c33929ffb5b3..3360fc57b5d5c9f3d52ffd82bec4a8cc3dc76593 100644 (file)
@@ -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<bool> 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++;
       }
 
index d5a1e47c284c780b101f33bfb6ab62685f6c5e9b..007d34238a07b7c2b66b0c7d81a77f8d279347dd 100644 (file)
@@ -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 {
index a793a15d92a07cfc01bd2ba1135a6717359b6102..c81d6373d2734e542810ecbe7159ab0b29e32f0b 100644 (file)
@@ -65,9 +65,9 @@ bool g_verboseHealthChecks{false};
 
 GlobalStateHolder<NetmaskGroup> g_ACL;
 string g_outputBuffer;
-vector<std::pair<ComboAddress, bool>> g_locals;
+vector<std::tuple<ComboAddress, bool, bool>> g_locals;
 #ifdef HAVE_DNSCRYPT
-std::vector<std::pair<ComboAddress,DnsCryptContext>> g_dnsCryptLocals;
+std::vector<std::tuple<ComboAddress,DnsCryptContext,bool>> g_dnsCryptLocals;
 #endif
 vector<ClientState *> g_frontends;
 GlobalStateHolder<pools_t> 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<ClientState*> 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<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
 
 
-    if(IsAnyAddress(local.first)) {
+    if(IsAnyAddress(cs->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);
index d979d4e5eb9be6c6a3bd5f9c86e612bd6a6ec33f..61ef35daf1f9f84fbac0ce8589666dccf4732b6b 100644 (file)
@@ -454,7 +454,7 @@ extern GlobalStateHolder<NetmaskGroup> g_ACL;
 
 extern ComboAddress g_serverControl; // not changed during runtime
 
-extern std::vector<std::pair<ComboAddress, bool>> g_locals; // not changed at runtime (we hope XXX)
+extern std::vector<std::tuple<ComboAddress, bool, bool>> g_locals; // not changed at runtime (we hope XXX)
 extern vector<ClientState*> 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<std::pair<ComboAddress,DnsCryptContext>> g_dnsCryptLocals;
+extern std::vector<std::tuple<ComboAddress,DnsCryptContext,bool>> g_dnsCryptLocals;
 
 int handleDnsCryptQuery(DnsCryptContext* ctx, char* packet, uint16_t len, std::shared_ptr<DnsCryptQuery>& query, uint16_t* decryptedQueryLen, bool tcp, std::vector<uint8_t>& reponse);
 #endif