]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - pdns/dnsdist-lua.cc
dnsdist: squelch unused function warning
[thirdparty/pdns.git] / pdns / dnsdist-lua.cc
index 69e5c571f67178cb8e6242c0d19a180e517382b9..f27fd87f71a3eb470ffe2cd9ec42a720d0b5d74c 100644 (file)
@@ -89,12 +89,9 @@ void resetLuaSideEffect()
 
 typedef std::unordered_map<std::string, boost::variant<bool, int, std::string, std::vector<std::pair<int,int> > > > localbind_t;
 
-static void parseLocalBindVars(boost::optional<localbind_t> vars, bool& doTCP, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus)
+static void parseLocalBindVars(boost::optional<localbind_t> vars, bool& reusePort, int& tcpFastOpenQueueSize, std::string& interface, std::set<int>& cpus)
 {
   if (vars) {
-    if (vars->count("doTCP")) {
-      doTCP = boost::get<bool>((*vars)["doTCP"]);
-    }
     if (vars->count("reusePort")) {
       reusePort = boost::get<bool>((*vars)["reusePort"]);
     }
@@ -112,40 +109,40 @@ static void parseLocalBindVars(boost::optional<localbind_t> vars, bool& doTCP, b
   }
 }
 
-#ifdef HAVE_DNS_OVER_TLS
-static bool loadTLSCertificateAndKeys(shared_ptr<TLSFrontend>& frontend, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles)
+#if defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
+static bool loadTLSCertificateAndKeys(const std::string& context, std::vector<std::pair<std::string, std::string>>& pairs, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles)
 {
   if (certFiles.type() == typeid(std::string) && keyFiles.type() == typeid(std::string)) {
     auto certFile = boost::get<std::string>(certFiles);
     auto keyFile = boost::get<std::string>(keyFiles);
-    frontend->d_certKeyPairs.clear();
-    frontend->d_certKeyPairs.push_back({certFile, keyFile});
+    pairs.clear();
+    pairs.push_back({certFile, keyFile});
   }
   else if (certFiles.type() == typeid(std::vector<std::pair<int,std::string>>) && keyFiles.type() == typeid(std::vector<std::pair<int,std::string>>))
   {
     auto certFilesVect = boost::get<std::vector<std::pair<int,std::string>>>(certFiles);
     auto keyFilesVect = boost::get<std::vector<std::pair<int,std::string>>>(keyFiles);
     if (certFilesVect.size() == keyFilesVect.size()) {
-      frontend->d_certKeyPairs.clear();
+      pairs.clear();
       for (size_t idx = 0; idx < certFilesVect.size(); idx++) {
-        frontend->d_certKeyPairs.push_back({certFilesVect.at(idx).second, keyFilesVect.at(idx).second});
+        pairs.push_back({certFilesVect.at(idx).second, keyFilesVect.at(idx).second});
       }
     }
     else {
-      errlog("Error, mismatching number of certificates and keys in call to addTLSLocal()!");
-      g_outputBuffer="Error, mismatching number of certificates and keys in call to addTLSLocal()!";
+      errlog("Error, mismatching number of certificates and keys in call to %s()!", context);
+      g_outputBuffer="Error, mismatching number of certificates and keys in call to " + context + "()!";
       return false;
     }
   }
   else {
-    errlog("Error, mismatching number of certificates and keys in call to addTLSLocal()!");
-    g_outputBuffer="Error, mismatching number of certificates and keys in call to addTLSLocal()!";
+    errlog("Error, mismatching number of certificates and keys in call to %s()!", context);
+    g_outputBuffer="Error, mismatching number of certificates and keys in call to " + context + "()!";
     return false;
   }
 
   return true;
 }
-#endif /* HAVE_DNS_OVER_TLS */
+#endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
 
 void setupLuaConfig(bool client)
 {
@@ -487,20 +484,30 @@ void setupLuaConfig(bool client)
         g_outputBuffer="setLocal cannot be used at runtime!\n";
         return;
       }
-      bool doTCP = true;
       bool reusePort = false;
       int tcpFastOpenQueueSize = 0;
       std::string interface;
       std::set<int> cpus;
 
-      parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
+      parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
 
       try {
        ComboAddress loc(addr, 53);
-       g_locals.clear();
-       g_locals.push_back(std::make_tuple(loc, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus)); /// only works pre-startup, so no sync necessary
+        for (auto it = g_frontends.begin(); it != g_frontends.end(); ) {
+          /* TLS and DNSCrypt frontends are separate */
+          if ((*it)->tlsFrontend == nullptr && (*it)->dnscryptCtx == nullptr) {
+            it = g_frontends.erase(it);
+          }
+          else {
+            ++it;
+          }
+        }
+
+        // only works pre-startup, so no sync necessary
+        g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+        g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
       }
-      catch(std::exception& e) {
+      catch(const std::exception& e) {
        g_outputBuffer="Error: "+string(e.what())+"\n";
       }
     });
@@ -513,20 +520,22 @@ void setupLuaConfig(bool client)
         g_outputBuffer="addLocal cannot be used at runtime!\n";
         return;
       }
-      bool doTCP = true;
       bool reusePort = false;
       int tcpFastOpenQueueSize = 0;
       std::string interface;
       std::set<int> cpus;
 
-      parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
+      parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
 
       try {
        ComboAddress loc(addr, 53);
-       g_locals.push_back(std::make_tuple(loc, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus)); /// only works pre-startup, so no sync necessary
+        // only works pre-startup, so no sync necessary
+        g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, false, reusePort, tcpFastOpenQueueSize, interface, cpus)));
+        g_frontends.push_back(std::unique_ptr<ClientState>(new ClientState(loc, true, reusePort, tcpFastOpenQueueSize, interface, cpus)));
       }
       catch(std::exception& e) {
-       g_outputBuffer="Error: "+string(e.what())+"\n";
+        g_outputBuffer="Error: "+string(e.what())+"\n";
+        errlog("Error while trying to listen on %s: %s\n", addr, string(e.what()));
       }
     });
 
@@ -1085,17 +1094,26 @@ void setupLuaConfig(bool client)
         return;
       }
 #ifdef HAVE_DNSCRYPT
-      bool doTCP = true;
       bool reusePort = false;
       int tcpFastOpenQueueSize = 0;
       std::string interface;
       std::set<int> cpus;
 
-      parseLocalBindVars(vars, doTCP, reusePort, tcpFastOpenQueueSize, interface, cpus);
+      parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
 
       try {
         auto ctx = std::make_shared<DNSCryptContext>(providerName, certFile, keyFile);
-        g_dnsCryptLocals.push_back(std::make_tuple(ComboAddress(addr, 443), ctx, reusePort, tcpFastOpenQueueSize, interface, cpus));
+
+        /* UDP */
+        auto cs = std::unique_ptr<ClientState>(new ClientState(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus));
+        cs->dnscryptCtx = ctx;
+        g_dnsCryptLocals.push_back(ctx);
+        g_frontends.push_back(std::move(cs));
+
+        /* TCP */
+        cs = std::unique_ptr<ClientState>(new ClientState(ComboAddress(addr, 443), true, reusePort, tcpFastOpenQueueSize, interface, cpus));
+        cs->dnscryptCtx = ctx;
+        g_frontends.push_back(std::move(cs));
       }
       catch(std::exception& e) {
         errlog(e.what());
@@ -1115,9 +1133,9 @@ void setupLuaConfig(bool client)
       ret << (fmt % "#" % "Address" % "Provider Name") << endl;
       size_t idx = 0;
 
-      for (const auto& local : g_dnsCryptLocals) {
-        const std::shared_ptr<DNSCryptContext> ctx = std::get<1>(local);
-        ret<< (fmt % idx % std::get<0>(local).toStringWithPort() % ctx->getProviderName()) << endl;
+      for (const auto& frontend : g_frontends) {
+        const std::shared_ptr<DNSCryptContext> ctx = frontend->dnscryptCtx;
+        ret<< (fmt % idx % frontend->local.toStringWithPort() % ctx->getProviderName()) << endl;
         idx++;
       }
 
@@ -1132,7 +1150,7 @@ void setupLuaConfig(bool client)
 #ifdef HAVE_DNSCRYPT
       std::shared_ptr<DNSCryptContext> ret = nullptr;
       if (idx < g_dnsCryptLocals.size()) {
-        ret = std::get<1>(g_dnsCryptLocals.at(idx));
+        ret = g_dnsCryptLocals.at(idx);
       }
       return ret;
 #else
@@ -1285,7 +1303,7 @@ void setupLuaConfig(bool client)
       setLuaNoSideEffect();
       ClientState* ret = nullptr;
       if(num < g_frontends.size()) {
-        ret=g_frontends[num];
+        ret=g_frontends[num].get();
       }
       return ret;
       });
@@ -1458,6 +1476,11 @@ void setupLuaConfig(bool client)
       g_servFailOnNoPolicy = servfail;
     });
 
+  g_lua.writeFunction("setRoundRobinFailOnNoServer", [](bool fail) {
+      setLuaSideEffect();
+      g_roundrobinFailOnNoServer = fail;
+    });
+
   g_lua.writeFunction("setRingBuffersSize", [](size_t capacity, boost::optional<size_t> numberOfShards) {
       setLuaSideEffect();
       if (g_configurationDone) {
@@ -1618,10 +1641,124 @@ void setupLuaConfig(bool client)
     setSyslogFacility(facility);
   });
 
+  g_lua.writeFunction("addDOHLocal", [client](const std::string& addr, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles, boost::optional<boost::variant<std::string, vector<pair<int, std::string> > > > urls, boost::optional<localbind_t> vars) {
+#ifdef HAVE_DNS_OVER_HTTPS
+    if (client) {
+      return;
+    }
+    setLuaSideEffect();
+    if (g_configurationDone) {
+      g_outputBuffer="addDOHLocal cannot be used at runtime!\n";
+      return;
+    }
+    auto frontend = std::make_shared<DOHFrontend>();
+
+    if (!loadTLSCertificateAndKeys("addDOHLocal", frontend->d_certKeyPairs, certFiles, keyFiles)) {
+      return;
+    }
+
+    frontend->d_local = ComboAddress(addr, 443);
+    if (urls) {
+      if (urls->type() == typeid(std::string)) {
+        frontend->d_urls.push_back(boost::get<std::string>(*urls));
+      }
+      else if (urls->type() == typeid(std::vector<std::pair<int,std::string>>)) {
+        auto urlsVect = boost::get<std::vector<std::pair<int,std::string>>>(*urls);
+        for(const auto& p : urlsVect) {
+          frontend->d_urls.push_back(p.second);
+        }
+      }
+    }
+    else {
+      frontend->d_urls = {"/"};
+    }
+
+    bool reusePort = false;
+    int tcpFastOpenQueueSize = 0;
+    std::string interface;
+    std::set<int> cpus;
+
+    if(vars) {
+      parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
+
+      if (vars->count("idleTimeout")) {
+        frontend->d_idleTimeout = boost::get<int>((*vars)["idleTimeout"]);
+      }
+      if (vars->count("ciphers")) {
+        frontend->d_ciphers = boost::get<const string>((*vars)["ciphers"]);
+      }
+      if (vars->count("ciphersTLS13")) {
+        frontend->d_ciphers13 = boost::get<const string>((*vars)["ciphersTLS13"]);
+      }
+      if (vars->count("serverTokens")) {
+        frontend->d_serverTokens = boost::get<const string>((*vars)["serverTokens"]);
+      }
+    }
+    g_dohlocals.push_back(frontend);
+    auto cs = std::unique_ptr<ClientState>(new ClientState(frontend->d_local, true, reusePort, tcpFastOpenQueueSize, interface, cpus));
+    cs->dohFrontend = frontend;
+    g_frontends.push_back(std::move(cs));
+#else
+    throw std::runtime_error("addDOHLocal() called but DNS over HTTPS support is not present!");
+#endif
+  });
+
+  g_lua.writeFunction("showDOHFrontends", []() {
+#ifdef HAVE_DNS_OVER_HTTPS
+        setLuaNoSideEffect();
+        try {
+          ostringstream ret;
+          boost::format fmt("%-3d %-20.20s %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d %-15d");
+          ret << (fmt % "#" % "Address" % "HTTP" % "HTTP/1" % "HTTP/2" % "TLS 1.0" % "TLS 1.1" % "TLS 1.2" % "TLS 1.3" % "TLS other" % "GET" % "POST" % "Bad" % "Errors" % "Valid") << endl;
+          size_t counter = 0;
+          for (const auto& ctx : g_dohlocals) {
+            ret << (fmt % counter % ctx->d_local.toStringWithPort() % ctx->d_httpconnects % ctx->d_http1queries % ctx->d_http2queries % ctx->d_tls10queries % ctx->d_tls11queries % ctx->d_tls12queries % ctx->d_tls13queries % ctx->d_tlsUnknownqueries % ctx->d_getqueries % ctx->d_postqueries % ctx->d_badrequests % ctx->d_errorresponses % ctx->d_validresponses) << endl;
+            counter++;
+          }
+          g_outputBuffer = ret.str();
+        }
+        catch(const std::exception& e) {
+          g_outputBuffer = e.what();
+          throw;
+        }
+#else
+        g_outputBuffer="DNS over HTTPS support is not present!\n";
+#endif
+      });
+
+    g_lua.writeFunction("getDOHFrontend", [](size_t index) {
+        std::shared_ptr<DOHFrontend> result = nullptr;
+#ifdef HAVE_DNS_OVER_HTTPS
+        setLuaNoSideEffect();
+        try {
+          if (index < g_dohlocals.size()) {
+            result = g_dohlocals.at(index);
+          }
+          else {
+            errlog("Error: trying to get DOH frontend with index %zu but we only have %zu frontend(s)\n", index, g_dohlocals.size());
+            g_outputBuffer="Error: trying to get DOH frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_dohlocals.size()) + " frontend(s)\n";
+          }
+        }
+        catch(const std::exception& e) {
+          g_outputBuffer="Error while trying to get DOH frontend with index " + std::to_string(index) + ": "+string(e.what())+"\n";
+          errlog("Error while trying to get DOH frontend with index %zu: %s\n", index, string(e.what()));
+        }
+#else
+        g_outputBuffer="DNS over HTTPS support is not present!\n";
+#endif
+        return result;
+      });
+
+    g_lua.registerFunction<void(std::shared_ptr<DOHFrontend>::*)()>("reloadCertificates", [](std::shared_ptr<DOHFrontend> frontend) {
+        if (frontend != nullptr) {
+          frontend->reloadCertificates();
+        }
+      });
+
   g_lua.writeFunction("addTLSLocal", [client](const std::string& addr, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles, boost::optional<localbind_t> vars) {
+#ifdef HAVE_DNS_OVER_TLS
         if (client)
           return;
-#ifdef HAVE_DNS_OVER_TLS
         setLuaSideEffect();
         if (g_configurationDone) {
           g_outputBuffer="addTLSLocal cannot be used at runtime!\n";
@@ -1629,13 +1766,17 @@ void setupLuaConfig(bool client)
         }
         shared_ptr<TLSFrontend> frontend = std::make_shared<TLSFrontend>();
 
-        if (!loadTLSCertificateAndKeys(frontend, certFiles, keyFiles)) {
+        if (!loadTLSCertificateAndKeys("addTLSLocal", frontend->d_certKeyPairs, certFiles, keyFiles)) {
           return;
         }
 
+        bool reusePort = false;
+        int tcpFastOpenQueueSize = 0;
+        std::string interface;
+        std::set<int> cpus;
+
         if (vars) {
-          bool doTCP = true;
-          parseLocalBindVars(vars, doTCP, frontend->d_reusePort, frontend->d_tcpFastOpenQueueSize, frontend->d_interface, frontend->d_cpus);
+          parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
 
           if (vars->count("provider")) {
             frontend->d_provider = boost::get<const string>((*vars)["provider"]);
@@ -1645,6 +1786,10 @@ void setupLuaConfig(bool client)
             frontend->d_ciphers = boost::get<const string>((*vars)["ciphers"]);
           }
 
+          if (vars->count("ciphersTLS13")) {
+            frontend->d_ciphers13 = boost::get<const string>((*vars)["ciphersTLS13"]);
+          }
+
           if (vars->count("ticketKeyFile")) {
             frontend->d_ticketKeyFile = boost::get<const string>((*vars)["ticketKeyFile"]);
           }
@@ -1675,13 +1820,17 @@ void setupLuaConfig(bool client)
         try {
           frontend->d_addr = ComboAddress(addr, 853);
           vinfolog("Loading TLS provider %s", frontend->d_provider);
-          g_tlslocals.push_back(frontend); /// only works pre-startup, so no sync necessary
+          // only works pre-startup, so no sync necessary
+          auto cs = std::unique_ptr<ClientState>(new ClientState(frontend->d_addr, true, reusePort, tcpFastOpenQueueSize, interface, cpus));
+          cs->tlsFrontend = frontend;
+          g_tlslocals.push_back(cs->tlsFrontend);
+          g_frontends.push_back(std::move(cs));
         }
         catch(const std::exception& e) {
           g_outputBuffer="Error: "+string(e.what())+"\n";
         }
 #else
-        g_outputBuffer="DNS over TLS support is not present!\n";
+        throw std::runtime_error("addTLSLocal() called but DNS over TLS support is not present!");
 #endif
       });
 
@@ -1718,13 +1867,13 @@ void setupLuaConfig(bool client)
             result = g_tlslocals.at(index)->getContext();
           }
           else {
-            errlog("Error: trying to get TLS context with index %zu but we only have %zu\n", index, g_tlslocals.size());
-            g_outputBuffer="Error: trying to get TLS context with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + "\n";
+            errlog("Error: trying to get TLS context with index %zu but we only have %zu context(s)\n", index, g_tlslocals.size());
+            g_outputBuffer="Error: trying to get TLS context with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " context(s)\n";
           }
         }
         catch(const std::exception& e) {
-          g_outputBuffer="Error: "+string(e.what())+"\n";
-          errlog("Error: %s\n", string(e.what()));
+          g_outputBuffer="Error while trying to get TLS context with index " + std::to_string(index) + ": "+string(e.what())+"\n";
+          errlog("Error while trying to get TLS context with index %zu: %s\n", index, string(e.what()));
         }
 #else
         g_outputBuffer="DNS over TLS support is not present!\n";
@@ -1741,13 +1890,13 @@ void setupLuaConfig(bool client)
             result = g_tlslocals.at(index);
           }
           else {
-            errlog("Error: trying to get TLS frontend with index %zu but we only have %zu\n", index, g_tlslocals.size());
-            g_outputBuffer="Error: trying to get TLS frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + "\n";
+            errlog("Error: trying to get TLS frontend with index %zu but we only have %zu frontends\n", index, g_tlslocals.size());
+            g_outputBuffer="Error: trying to get TLS frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_tlslocals.size()) + " frontend(s)\n";
           }
         }
         catch(const std::exception& e) {
-          g_outputBuffer="Error: "+string(e.what())+"\n";
-          errlog("Error: %s\n", string(e.what()));
+          g_outputBuffer="Error while trying to get TLS frontend with index " + std::to_string(index) + ": "+string(e.what())+"\n";
+          errlog("Error while trying to get TLS frontend with index %zu: %s\n", index, string(e.what()));
         }
 #else
         g_outputBuffer="DNS over TLS support is not present!\n";
@@ -1769,13 +1918,41 @@ void setupLuaConfig(bool client)
 
     g_lua.registerFunction<void(std::shared_ptr<TLSFrontend>::*)(boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles)>("loadNewCertificatesAndKeys", [](std::shared_ptr<TLSFrontend>& frontend, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles) {
 #ifdef HAVE_DNS_OVER_TLS
-        if (loadTLSCertificateAndKeys(frontend, certFiles, keyFiles)) {
+        if (loadTLSCertificateAndKeys("loadNewCertificatesAndKeys", frontend->d_certKeyPairs, certFiles, keyFiles)) {
           frontend->setupTLS();
         }
 #endif
       });
 
-  g_lua.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse=allow; });
+    g_lua.writeFunction("reloadAllCertificates", []() {
+        for (auto& frontend : g_frontends) {
+          if (!frontend) {
+            continue;
+          }
+          try {
+#ifdef HAVE_DNSCRYPT
+            if (frontend->dnscryptCtx) {
+              frontend->dnscryptCtx->reloadCertificate();
+            }
+#endif /* HAVE_DNSCRYPT */
+#ifdef HAVE_DNS_OVER_TLS
+            if (frontend->tlsFrontend) {
+              frontend->tlsFrontend->setupTLS();
+            }
+#endif /* HAVE_DNS_OVER_TLS */
+#ifdef HAVE_DNS_OVER_HTTPS
+            if (frontend->dohFrontend) {
+              frontend->dohFrontend->reloadCertificates();
+            }
+#endif /* HAVE_DNS_OVER_HTTPS */
+          }
+          catch(const std::exception& e) {
+            errlog("Error reloading certificates for frontend %s: %s", frontend->local.toStringWithPort(), e.what());
+          }
+        }
+      });
+
+    g_lua.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse=allow; });
 }
 
 vector<std::function<void(void)>> setupLua(bool client, const std::string& config)