]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add 'reloadAllCertificates()'
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 5 Apr 2019 15:12:29 +0000 (17:12 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 5 Apr 2019 15:12:29 +0000 (17:12 +0200)
pdns/dnscrypt.cc
pdns/dnscrypt.hh
pdns/dnsdist-console.cc
pdns/dnsdist-lua.cc
pdns/dnsdistdist/docs/reference/config.rst

index f81263c09fcbbb2d5445a5f582eec1b566b98aa7..4cf126ce389d6afc7f8bb979670e34c461e458e9 100644 (file)
@@ -283,13 +283,19 @@ std::string DNSCryptContext::certificateDateToStr(uint32_t date)
   return string(buf);
 }
 
-void DNSCryptContext::addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active)
+void DNSCryptContext::addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active, bool reload)
 {
   WriteLock w(&d_lock);
 
   for (auto pair : certs) {
     if (pair->cert.getSerial() == newCert.getSerial()) {
-      throw std::runtime_error("Error adding a new certificate: we already have a certificate with the same serial");
+      if (reload) {
+        /* on reload we just assume that this is the same certificate */
+        return;
+      }
+      else {
+        throw std::runtime_error("Error adding a new certificate: we already have a certificate with the same serial");
+      }
     }
   }
 
@@ -301,7 +307,7 @@ void DNSCryptContext::addNewCertificate(const DNSCryptCert& newCert, const DNSCr
   certs.push_back(pair);
 }
 
-void DNSCryptContext::loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active)
+void DNSCryptContext::loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active, bool reload)
 {
   DNSCryptCert newCert;
   DNSCryptPrivateKey newPrivateKey;
@@ -309,7 +315,14 @@ void DNSCryptContext::loadNewCertificate(const std::string& certFile, const std:
   loadCertFromFile(certFile, newCert);
   newPrivateKey.loadFromFile(keyFile);
 
-  addNewCertificate(newCert, newPrivateKey, active);
+  addNewCertificate(newCert, newPrivateKey, active, reload);
+  certificatePath = certFile;
+  keyPath = keyFile;
+}
+
+void DNSCryptContext::reloadCertificate()
+{
+  loadNewCertificate(certificatePath, keyPath, true, true);
 }
 
 void DNSCryptContext::markActive(uint32_t serial)
index 307784cb8092ee5fcaa3ca3c42d003cbba0cb382..86ddcd20159fdad28b485fd3b97bafa7dab323bc 100644 (file)
@@ -257,8 +257,9 @@ public:
   DNSCryptContext(const std::string& pName, const std::string& certFile, const std::string& keyFile);
   DNSCryptContext(const std::string& pName, const DNSCryptCert& certificate, const DNSCryptPrivateKey& pKey);
 
-  void loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active=true);
-  void addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active=true);
+  void reloadCertificate();
+  void loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active=true, bool reload=false);
+  void addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active=true, bool reload=false);
   void markActive(uint32_t serial);
   void markInactive(uint32_t serial);
   void removeInactiveCertificate(uint32_t serial);
@@ -276,6 +277,8 @@ private:
   pthread_rwlock_t d_lock;
   std::vector<std::shared_ptr<DNSCryptCertificatePair>> certs;
   DNSName providerName;
+  std::string certificatePath;
+  std::string keyPath;
 };
 
 bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DNSCryptExchangeVersion version, DNSCryptCert& certOut, DNSCryptPrivateKey& keyOut);
index 6ed2244b8399f4a3272f004e9546ee55806c8008..1ff4670cafe69b3c0abd14ede34eb40f315567a1 100644 (file)
@@ -428,6 +428,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "RCodeRule", true, "rcode", "matches responses with the specified rcode" },
   { "RegexRule", true, "regex", "matches the query name against the supplied regex" },
   { "registerDynBPFFilter", true, "DynBPFFilter", "register this dynamic BPF filter into the web interface so that its counters are displayed" },
+  { "reloadAllCertificates", true, "", "reload all DNSCrypt and TLS certificates, along with their associated keys" },
   { "RemoteLogAction", true, "RemoteLogger [, alterFunction [, serverID]]", "send the content of this query to a remote logger via Protocol Buffer. `alterFunction` is a callback, receiving a DNSQuestion and a DNSDistProtoBufMessage, that can be used to modify the Protocol Buffer content, for example for anonymization purposes. `serverID` is the server identifier." },
   { "RemoteLogResponseAction", true, "RemoteLogger [,alterFunction [,includeCNAME [, serverID]]]", "send the content of this response to a remote logger via Protocol Buffer. `alterFunction` is the same callback than the one in `RemoteLogAction` and `includeCNAME` indicates whether CNAME records inside the response should be parsed and exported. The default is to only exports A and AAAA records. `serverID` is the server identifier." },
   { "rmCacheHitResponseRule", true, "id", "remove cache hit response rule in position 'id', or whose uuid matches if 'id' is an UUID string" },
index dea393d3b318a7c0fc9451c05142038b3b0409fd..faf002e8b7a254d24eb7e499a975e27603636715 100644 (file)
@@ -1766,7 +1766,30 @@ void setupLuaConfig(bool client)
 #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 */
+          }
+          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)
index 62604d792db5f1450979f662579baa0138986189..6a366f1982416ab315a82f3e6c52c2baac4b7d02 100644 (file)
@@ -42,6 +42,12 @@ Global configuration
 
   :param str path: The directory to load configuration files from. Each file must end in ``.conf``.
 
+.. function:: reloadAllCertificates()
+
+  .. versionadded:: 1.4.0
+
+  Reload all DNSCrypt and TLS certificates, along with their associated keys.
+
 Listen Sockets
 ~~~~~~~~~~~~~~