]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Implementation reloading of TLS certs/keys for DoQ and DoH3
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 8 Feb 2024 13:42:04 +0000 (14:42 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 8 Feb 2024 13:42:04 +0000 (14:42 +0100)
pdns/dnsdist-console.cc
pdns/dnsdist-lua.cc
pdns/dnsdistdist/doh3.cc
pdns/dnsdistdist/doh3.hh
pdns/dnsdistdist/doq-common.hh
pdns/dnsdistdist/doq.cc
pdns/dnsdistdist/doq.hh

index 0f9e085735f9653fce618134a1a3cb870ec89de7..6444723b04b76351beb21c5faccaedf86bc5a471 100644 (file)
@@ -542,8 +542,12 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "getDynamicBlocksSMT", true, "", "returns a table of the current suffix-based dynamic blocks" },
   { "getDNSCryptBind", true, "n", "return the `DNSCryptContext` object corresponding to the bind `n`" },
   { "getDNSCryptBindCount", true, "", "returns the number of DNSCrypt listeners" },
-  { "getDOHFrontend", true, "n", "returns the DOH frontend with index n" },
+  { "getDOHFrontend", true, "n", "returns the DoH frontend with index n" },
   { "getDOHFrontendCount", true, "", "returns the number of DoH listeners" },
+  { "getDOH3Frontend", true, "n", "returns the DoH3 frontend with index n" },
+  { "getDOH3FrontendCount", true, "", "returns the number of DoH3 listeners" },
+  { "getDOQFrontend", true, "n", "returns the DoQ frontend with index n" },
+  { "getDOQFrontendCount", true, "", "returns the number of DoQ listeners" },
   { "getListOfAddressesOfNetworkInterface", true, "itf", "returns the list of addresses configured on a given network interface, as strings" },
   { "getListOfNetworkInterfaces", true, "", "returns the list of network interfaces present on the system, as strings" },
   { "getListOfRangesOfNetworkInterface", true, "itf", "returns the list of network ranges configured on a given network interface, as strings" },
index 50112a3730b0f09d52cc19c7ab5258d80932105f..6ea674a5f5b1248a410932138036653e79aadb8d 100644 (file)
@@ -2841,6 +2841,41 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #endif
   });
 
+#ifdef HAVE_DNS_OVER_QUIC
+  luaCtx.writeFunction("getDOQFrontend", [client](uint64_t index) {
+    std::shared_ptr<DOQFrontend> result = nullptr;
+    if (client) {
+      return result;
+    }
+    setLuaNoSideEffect();
+    try {
+      if (index < g_doqlocals.size()) {
+        result = g_doqlocals.at(index);
+      }
+      else {
+        errlog("Error: trying to get DOQ frontend with index %d but we only have %d frontend(s)\n", index, g_doqlocals.size());
+        g_outputBuffer = "Error: trying to get DOQ frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_doqlocals.size()) + " frontend(s)\n";
+      }
+    }
+    catch (const std::exception& e) {
+      g_outputBuffer = "Error while trying to get DOQ frontend with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
+      errlog("Error while trying to get DOQ frontend with index %d: %s\n", index, string(e.what()));
+    }
+    return result;
+  });
+
+  luaCtx.writeFunction("getDOQFrontendCount", []() {
+    setLuaNoSideEffect();
+    return g_doqlocals.size();
+  });
+
+  luaCtx.registerFunction<void (std::shared_ptr<DOQFrontend>::*)()>("reloadCertificates", [](std::shared_ptr<DOQFrontend> frontend) {
+    if (frontend != nullptr) {
+      frontend->reloadCertificates();
+    }
+  });
+#endif
+
   luaCtx.writeFunction("showDOHFrontends", []() {
 #ifdef HAVE_DNS_OVER_HTTPS
     setLuaNoSideEffect();
@@ -2887,6 +2922,41 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #endif
   });
 
+#ifdef HAVE_DNS_OVER_HTTP3
+  luaCtx.writeFunction("getDOH3Frontend", [client](uint64_t index) {
+    std::shared_ptr<DOH3Frontend> result = nullptr;
+    if (client) {
+      return result;
+    }
+    setLuaNoSideEffect();
+    try {
+      if (index < g_doh3locals.size()) {
+        result = g_doh3locals.at(index);
+      }
+      else {
+        errlog("Error: trying to get DOH3 frontend with index %d but we only have %d frontend(s)\n", index, g_doh3locals.size());
+        g_outputBuffer = "Error: trying to get DOH3 frontend with index " + std::to_string(index) + " but we only have " + std::to_string(g_doh3locals.size()) + " frontend(s)\n";
+      }
+    }
+    catch (const std::exception& e) {
+      g_outputBuffer = "Error while trying to get DOH3 frontend with index " + std::to_string(index) + ": " + string(e.what()) + "\n";
+      errlog("Error while trying to get DOH3 frontend with index %d: %s\n", index, string(e.what()));
+    }
+    return result;
+  });
+
+  luaCtx.writeFunction("getDOH3FrontendCount", []() {
+    setLuaNoSideEffect();
+    return g_doh3locals.size();
+  });
+
+  luaCtx.registerFunction<void (std::shared_ptr<DOH3Frontend>::*)()>("reloadCertificates", [](std::shared_ptr<DOH3Frontend> frontend) {
+    if (frontend != nullptr) {
+      frontend->reloadCertificates();
+    }
+  });
+#endif
+
   luaCtx.writeFunction("showDOHResponseCodes", []() {
 #ifdef HAVE_DNS_OVER_HTTPS
     setLuaNoSideEffect();
@@ -3246,6 +3316,16 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
           frontend->dohFrontend->reloadCertificates();
         }
 #endif /* HAVE_DNS_OVER_HTTPS */
+#ifdef HAVE_DNS_OVER_QUIC
+        if (frontend->doqFrontend) {
+          frontend->doqFrontend->reloadCertificates();
+        }
+#endif /* HAVE_DNS_OVER_QUIC */
+#ifdef HAVE_DNS_OVER_HTTP3
+        if (frontend->doh3Frontend) {
+          frontend->doh3Frontend->reloadCertificates();
+        }
+#endif /* HAVE_DNS_OVER_HTTP3 */
       }
       catch (const std::exception& e) {
         errlog("Error reloading certificates for frontend %s: %s", frontend->local.toStringWithPort(), e.what());
index 4c0823ab621e669b027f20ad977af477cb20bf32..c6b6f4c2df8ecf442225de1978d1f5df7e793b01 100644 (file)
@@ -54,8 +54,8 @@ using h3_headers_t = std::map<std::string, std::string>;
 class H3Connection
 {
 public:
-  H3Connection(const ComboAddress& peer, QuicheConnection&& conn) :
-    d_peer(peer), d_conn(std::move(conn))
+  H3Connection(const ComboAddress& peer, QuicheConfig config, QuicheConnection&& conn) :
+    d_peer(peer), d_conn(std::move(conn)), d_config(std::move(config))
   {
   }
   H3Connection(const H3Connection&) = delete;
@@ -66,6 +66,7 @@ public:
 
   ComboAddress d_peer;
   QuicheConnection d_conn;
+  QuicheConfig d_config;
   QuicheHTTP3Connection d_http3{nullptr, quiche_h3_conn_free};
   // buffer request headers by streamID
   std::unordered_map<uint64_t, h3_headers_t> d_headersBuffers;
@@ -379,16 +380,22 @@ static void handleResponse(DOH3Frontend& frontend, H3Connection& conn, const uin
 void DOH3Frontend::setup()
 {
   auto config = QuicheConfig(quiche_config_new(QUICHE_PROTOCOL_VERSION), quiche_config_free);
-
   d_quicheParams.d_alpn = std::string(DOH3_ALPN.begin(), DOH3_ALPN.end());
   configureQuiche(config, d_quicheParams, true);
 
-  // quiche_h3_config_new
   auto http3config = QuicheHTTP3Config(quiche_h3_config_new(), quiche_h3_config_free);
 
   d_server_config = std::make_unique<DOH3ServerConfig>(std::move(config), std::move(http3config), d_internalPipeBufferSize);
 }
 
+void DOH3Frontend::reloadCertificates()
+{
+  auto config = QuicheConfig(quiche_config_new(QUICHE_PROTOCOL_VERSION), quiche_config_free);
+  d_quicheParams.d_alpn = std::string(DOH3_ALPN.begin(), DOH3_ALPN.end());
+  configureQuiche(config, d_quicheParams, true);
+  std::atomic_store_explicit(&d_server_config->config, std::move(config), std::memory_order_release);
+}
+
 static std::optional<std::reference_wrapper<H3Connection>> getConnection(DOH3ServerConfig::ConnectionsMap& connMap, const PacketBuffer& connID)
 {
   auto iter = connMap.find(connID);
@@ -431,7 +438,7 @@ static std::optional<std::reference_wrapper<H3Connection>> createConnection(DOH3
     quiche_conn_set_keylog_path(quicheConn.get(), config.df->d_quicheParams.d_keyLogFile.c_str());
   }
 
-  auto conn = H3Connection(peer, std::move(quicheConn));
+  auto conn = H3Connection(peer, config.config, std::move(quicheConn));
   auto pair = config.d_connections.emplace(serverSideID, std::move(conn));
   return pair.first->second;
 }
index bca7a4eb5225f3d45f4f53fdabc1ad0256e940e5..954ea4aab2ea3345670cfb2a3001258e98fd69cb 100644 (file)
@@ -48,6 +48,7 @@ struct DOH3Frontend
   ~DOH3Frontend();
 
   void setup();
+  void reloadCertificates();
 
   std::unique_ptr<DOH3ServerConfig> d_server_config;
   ComboAddress d_local;
index 92af37f25fc29ebc00f2d2506ffd4d1a50d9f579..c7a4b5c21a279f1977fb853323b3dda7d044db7e 100644 (file)
@@ -47,7 +47,7 @@ static const std::map<const std::string, int> s_available_cc_algorithms = {
 
 using QuicheConnection = std::unique_ptr<quiche_conn, decltype(&quiche_conn_free)>;
 using QuicheHTTP3Connection = std::unique_ptr<quiche_h3_conn, decltype(&quiche_h3_conn_free)>;
-using QuicheConfig = std::unique_ptr<quiche_config, decltype(&quiche_config_free)>;
+using QuicheConfig = std::shared_ptr<quiche_config>;
 using QuicheHTTP3Config = std::unique_ptr<quiche_h3_config, decltype(&quiche_h3_config_free)>;
 
 struct QuicheParams
index 277a8c5985ac1f86ffe5d88dcf225b24376cbfea..4ac7267f0bf4e56fc1aa98e49e7a5cb51d1533a7 100644 (file)
@@ -51,8 +51,8 @@ using namespace dnsdist::doq;
 class Connection
 {
 public:
-  Connection(const ComboAddress& peer, QuicheConnection&& conn) :
-    d_peer(peer), d_conn(std::move(conn))
+  Connection(const ComboAddress& peer, QuicheConfig config, QuicheConnection conn) :
+    d_peer(peer), d_conn(std::move(conn)), d_config(std::move(config))
   {
   }
   Connection(const Connection&) = delete;
@@ -63,6 +63,8 @@ public:
 
   ComboAddress d_peer;
   QuicheConnection d_conn;
+  QuicheConfig d_config;
+
   std::unordered_map<uint64_t, PacketBuffer> d_streamBuffers;
   std::unordered_map<uint64_t, PacketBuffer> d_streamOutBuffers;
 };
@@ -303,6 +305,14 @@ void DOQFrontend::setup()
   d_server_config = std::make_unique<DOQServerConfig>(std::move(config), d_internalPipeBufferSize);
 }
 
+void DOQFrontend::reloadCertificates()
+{
+  auto config = QuicheConfig(quiche_config_new(QUICHE_PROTOCOL_VERSION), quiche_config_free);
+  d_quicheParams.d_alpn = std::string(DOQ_ALPN.begin(), DOQ_ALPN.end());
+  configureQuiche(config, d_quicheParams, false);
+  std::atomic_store_explicit(&d_server_config->config, std::move(config), std::memory_order_release);
+}
+
 static std::optional<std::reference_wrapper<Connection>> getConnection(DOQServerConfig::ConnectionsMap& connMap, const PacketBuffer& connID)
 {
   auto iter = connMap.find(connID);
@@ -345,7 +355,7 @@ static std::optional<std::reference_wrapper<Connection>> createConnection(DOQSer
     quiche_conn_set_keylog_path(quicheConn.get(), config.df->d_quicheParams.d_keyLogFile.c_str());
   }
 
-  auto conn = Connection(peer, std::move(quicheConn));
+  auto conn = Connection(peer, config.config, std::move(quicheConn));
   auto pair = config.d_connections.emplace(serverSideID, std::move(conn));
   return pair.first->second;
 }
index a61af71a97c64d0ba3552e629021ce16ea822b65..258194177a6ea635299d507d6da79bee8d04c021 100644 (file)
@@ -49,6 +49,7 @@ struct DOQFrontend
   ~DOQFrontend();
 
   void setup();
+  void reloadCertificates();
 
   std::unique_ptr<DOQServerConfig> d_server_config;
   dnsdist::doq::QuicheParams d_quicheParams;