]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Separate the check-config and client modes
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 23 Oct 2019 14:41:49 +0000 (16:41 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 12 Nov 2019 09:19:19 +0000 (10:19 +0100)
In client (and single command) mode we do not care too much about
parsing the syntax of commands that do not relate to the console
itself, and we do not want to create sockets and touch files on the
local filesystem while parsing the configuration.
In check-config mode, however, we want to parse as much configuration
directives as possible, and we to generate some files that might be
required to validate the rest of the configuration (DNSCrypt
certificates and keys, OCSP responses..).

This PR separates the two modes and tries to skip only the following
parts when in check-config mode, compared to 'normal' configuration
parsing:
- we still parse and create objects when processing 'add*Local()'
  and 'set*Local()' directives, since the actual binding is delayed
  anyway ;
- we do not connect the outgoing sockets toward our backends ;
- we do not create Protocol Buffer or DNSTap outgoing connections ;
- we do not start the console, SNMP or webserver threads.

pdns/dnsdist-lua.cc
pdns/dnsdist-lua.hh
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/dnsdistdist/dnsdist-lua-bindings-protobuf.cc
pdns/dnsdistdist/docs/reference/config.rst

index 39ef2da24d2fa76a17cb827abf458326042b4b68..33e1426b3016fca8c8afd449717e3c6804ef8e3e 100644 (file)
@@ -206,15 +206,19 @@ static void parseTLSConfig(TLSConfig& config, const std::string& context, boost:
 
 #endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
 
-void setupLuaConfig(bool client)
+void setupLuaConfig(bool client, bool configCheck)
 {
   typedef std::unordered_map<std::string, boost::variant<bool, std::string, vector<pair<int, std::string> >, DownstreamState::checkfunc_t > > newserver_t;
   g_lua.writeFunction("inClientStartup", [client]() {
         return client && !g_configurationDone;
   });
 
+  g_lua.writeFunction("inConfigCheck", [client, configCheck]() {
+        return !configCheck;
+  });
+
   g_lua.writeFunction("newServer",
-      [client](boost::variant<string,newserver_t> pvars, boost::optional<int> qps) {
+                      [client, configCheck](boost::variant<string,newserver_t> pvars, boost::optional<int> qps) {
       setLuaSideEffect();
 
       std::shared_ptr<DownstreamState> ret = std::make_shared<DownstreamState>(ComboAddress());
@@ -316,11 +320,8 @@ void setupLuaConfig(bool client)
         }
       }
 
-      if(client) {
-        // do not construct DownstreamState now, it would try binding sockets.
-        return ret;
-      }
-      ret=std::make_shared<DownstreamState>(serverAddr, sourceAddr, sourceItf, sourceItfName, numberOfSockets);
+      // create but don't connect the socket in client or check-config modes
+      ret=std::make_shared<DownstreamState>(serverAddr, sourceAddr, sourceItf, sourceItfName, numberOfSockets, !(client || configCheck));
 
       if(vars.count("qps")) {
         int qpsVal=std::stoi(boost::get<string>(vars["qps"]));
@@ -746,7 +747,7 @@ void setupLuaConfig(bool client)
       g_carbon.setState(ours);
   });
 
-  g_lua.writeFunction("webserver", [client](const std::string& address, const std::string& password, const boost::optional<std::string> apiKey, const boost::optional<std::map<std::string, std::string> > customHeaders) {
+  g_lua.writeFunction("webserver", [client,configCheck](const std::string& address, const std::string& password, const boost::optional<std::string> apiKey, const boost::optional<std::map<std::string, std::string> > customHeaders) {
       setLuaSideEffect();
       ComboAddress local;
       try {
@@ -756,7 +757,7 @@ void setupLuaConfig(bool client)
         throw std::runtime_error(std::string("Error parsing the bind address for the webserver: ") + e.reason);
       }
 
-      if (client) {
+      if (client || configCheck) {
         return;
       }
 
@@ -809,11 +810,11 @@ void setupLuaConfig(bool client)
       }
     });
 
-  g_lua.writeFunction("controlSocket", [client](const std::string& str) {
+  g_lua.writeFunction("controlSocket", [client,configCheck](const std::string& str) {
       setLuaSideEffect();
       ComboAddress local(str, 5199);
 
-      if(client) {
+      if(client || configCheck) {
        g_serverControl = local;
        return;
       }
@@ -1267,9 +1268,12 @@ void setupLuaConfig(bool client)
 #endif
     });
 
-  g_lua.writeFunction("generateDNSCryptProviderKeys", [](const std::string& publicKeyFile, const std::string privateKeyFile) {
+  g_lua.writeFunction("generateDNSCryptProviderKeys", [client](const std::string& publicKeyFile, const std::string privateKeyFile) {
       setLuaNoSideEffect();
 #ifdef HAVE_DNSCRYPT
+      if (client) {
+        return;
+      }
       unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
       unsigned char privateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
       sodium_mlock(privateKey, sizeof(privateKey));
@@ -1324,8 +1328,11 @@ void setupLuaConfig(bool client)
     });
 
 #ifdef HAVE_DNSCRYPT
-  g_lua.writeFunction("generateDNSCryptCertificate", [](const std::string& providerPrivateKeyFile, const std::string& certificateFile, const std::string privateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version) {
+  g_lua.writeFunction("generateDNSCryptCertificate", [client](const std::string& providerPrivateKeyFile, const std::string& certificateFile, const std::string privateKeyFile, uint32_t serial, time_t begin, time_t end, boost::optional<DNSCryptExchangeVersion> version) {
       setLuaNoSideEffect();
+      if (client) {
+        return;
+      }
       DNSCryptPrivateKey privateKey;
       DNSCryptCert cert;
 
@@ -1619,8 +1626,8 @@ void setupLuaConfig(bool client)
       g_useTCPSinglePipe = flag;
     });
 
-  g_lua.writeFunction("snmpAgent", [client](bool enableTraps, boost::optional<std::string> masterSocket) {
-      if(client)
+  g_lua.writeFunction("snmpAgent", [client,configCheck](bool enableTraps, boost::optional<std::string> masterSocket) {
+      if(client || configCheck)
         return;
 #ifdef HAVE_NET_SNMP
       if (g_configurationDone) {
@@ -2105,24 +2112,28 @@ void setupLuaConfig(bool client)
     g_lua.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse=allow; });
 
 #if defined(HAVE_LIBSSL) && defined(HAVE_OCSP_BASIC_SIGN)
-    g_lua.writeFunction("generateOCSPResponse", [](const std::string& certFile, const std::string& caCert, const std::string& caKey, const std::string& outFile, int ndays, int nmin) {
-      return libssl_generate_ocsp_response(certFile, caCert, caKey, outFile, ndays, nmin);
+    g_lua.writeFunction("generateOCSPResponse", [client](const std::string& certFile, const std::string& caCert, const std::string& caKey, const std::string& outFile, int ndays, int nmin) {
+      if (client) {
+        return;
+      }
+
+      libssl_generate_ocsp_response(certFile, caCert, caKey, outFile, ndays, nmin);
     });
 #endif /* HAVE_LIBSSL && HAVE_OCSP_BASIC_SIGN*/
 }
 
-vector<std::function<void(void)>> setupLua(bool client, const std::string& config)
+vector<std::function<void(void)>> setupLua(bool client, bool configCheck, const std::string& config)
 {
   g_launchWork= new vector<std::function<void(void)>>();
 
   setupLuaActions();
-  setupLuaConfig(client);
+  setupLuaConfig(client, configCheck);
   setupLuaBindings(client);
   setupLuaBindingsDNSCrypt();
   setupLuaBindingsDNSQuestion();
   setupLuaBindingsKVS(client);
   setupLuaBindingsPacketCache();
-  setupLuaBindingsProtoBuf(client);
+  setupLuaBindingsProtoBuf(client, configCheck);
   setupLuaInspection();
   setupLuaRules();
   setupLuaVars();
index 9bd33266de0eb43eee257ed0f155a9e73990e00b..827d6e1cfb99c78df7ce96b168e1406e1ca56dcb 100644 (file)
@@ -84,13 +84,14 @@ void parseRuleParams(boost::optional<luaruleparams_t> params, boost::uuids::uuid
 
 typedef NetmaskTree<DynBlock> nmts_t;
 
+vector<std::function<void(void)>> setupLua(bool client, bool configCheck, const std::string& config);
 void setupLuaActions();
 void setupLuaBindings(bool client);
 void setupLuaBindingsDNSCrypt();
 void setupLuaBindingsDNSQuestion();
 void setupLuaBindingsKVS(bool client);
 void setupLuaBindingsPacketCache();
-void setupLuaBindingsProtoBuf(bool client);
+void setupLuaBindingsProtoBuf(bool client, bool configCheck);
 void setupLuaRules();
 void setupLuaInspection();
 void setupLuaVars();
index 1674e9fc853d730a1bed7537eae336ece0341942..8e143d924030a010e408c941ebc91898c0298fee 100644 (file)
@@ -788,7 +788,7 @@ void DownstreamState::setWeight(int newWeight)
   }
 }
 
-DownstreamState::DownstreamState(const ComboAddress& remote_, const ComboAddress& sourceAddr_, unsigned int sourceItf_, const std::string& sourceItfName_, size_t numberOfSockets): sourceItfName(sourceItfName_), remote(remote_), sourceAddr(sourceAddr_), sourceItf(sourceItf_)
+DownstreamState::DownstreamState(const ComboAddress& remote_, const ComboAddress& sourceAddr_, unsigned int sourceItf_, const std::string& sourceItfName_, size_t numberOfSockets, bool connect=true): sourceItfName(sourceItfName_), remote(remote_), sourceAddr(sourceAddr_), sourceItf(sourceItf_)
 {
   pthread_rwlock_init(&d_lock, nullptr);
   id = getUniqueID();
@@ -801,7 +801,7 @@ DownstreamState::DownstreamState(const ComboAddress& remote_, const ComboAddress
     fd = -1;
   }
 
-  if (!IsAnyAddress(remote)) {
+  if (connect && !IsAnyAddress(remote)) {
     reconnect();
     idStates.resize(g_maxOutstanding);
     sw.start();
@@ -2613,7 +2613,7 @@ try
 
   g_policy.setState(leastOutstandingPol);
   if(g_cmdLine.beClient || !g_cmdLine.command.empty()) {
-    setupLua(true, g_cmdLine.config);
+    setupLua(true, false, g_cmdLine.config);
     if (clientAddress != ComboAddress())
       g_serverControl = clientAddress;
     doClient(g_serverControl, g_cmdLine.command);
@@ -2634,13 +2634,13 @@ try
   g_consoleACL.setState(consoleACL);
 
   if (g_cmdLine.checkConfig) {
-    setupLua(true, g_cmdLine.config);
+    setupLua(false, true, g_cmdLine.config);
     // No exception was thrown
     infolog("Configuration '%s' OK!", g_cmdLine.config);
     _exit(EXIT_SUCCESS);
   }
 
-  auto todo=setupLua(false, g_cmdLine.config);
+  auto todo=setupLua(false, false, g_cmdLine.config);
 
   auto localPools = g_pools.getCopy();
   {
index 69bc7833627e162db964debde7fd4d04d2ac0200..6a7c9c3192df84822d43ee30aa83453be31c34ff 100644 (file)
@@ -835,8 +835,8 @@ struct DownstreamState
 {
    typedef std::function<std::tuple<DNSName, uint16_t, uint16_t>(const DNSName&, uint16_t, uint16_t, dnsheader*)> checkfunc_t;
 
-  DownstreamState(const ComboAddress& remote_, const ComboAddress& sourceAddr_, unsigned int sourceItf, const std::string& sourceItfName, size_t numberOfSockets);
-  DownstreamState(const ComboAddress& remote_): DownstreamState(remote_, ComboAddress(), 0, std::string(), 1) {}
+  DownstreamState(const ComboAddress& remote_, const ComboAddress& sourceAddr_, unsigned int sourceItf, const std::string& sourceItfName, size_t numberOfSockets, bool connect);
+  DownstreamState(const ComboAddress& remote_): DownstreamState(remote_, ComboAddress(), 0, std::string(), 1, true) {}
   ~DownstreamState()
   {
     for (auto& fd : sockets) {
@@ -1187,7 +1187,6 @@ struct LocalHolders
 struct dnsheader;
 
 void controlThread(int fd, ComboAddress local);
-vector<std::function<void(void)>> setupLua(bool client, const std::string& config);
 std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poolName);
 std::shared_ptr<ServerPool> createPoolIfNotExists(pools_t& pools, const string& poolName);
 NumberedServerVector getDownstreamCandidates(const pools_t& pools, const std::string& poolName);
index 876c8124ddf715a5e0e8c987c8be2ed11b1ce842..0375e1ea45eaba2d7c3a02dfe6e1fcc14400c3b6 100644 (file)
@@ -32,7 +32,7 @@
 #include "ipcipher.hh"
 #endif /* HAVE_LIBCRYPTO */
 
-void setupLuaBindingsProtoBuf(bool client)
+void setupLuaBindingsProtoBuf(bool client, bool configCheck)
 {
 #ifdef HAVE_LIBCRYPTO
   g_lua.registerFunction<ComboAddress(ComboAddress::*)(const std::string& key)>("ipencrypt", [](const ComboAddress& ca, const std::string& key) {
@@ -94,16 +94,16 @@ void setupLuaBindingsProtoBuf(bool client)
     });
 
   /* RemoteLogger */
-  g_lua.writeFunction("newRemoteLogger", [client](const std::string& remote, boost::optional<uint16_t> timeout, boost::optional<uint64_t> maxQueuedEntries, boost::optional<uint8_t> reconnectWaitTime) {
-      if (client) {
+  g_lua.writeFunction("newRemoteLogger", [client,configCheck](const std::string& remote, boost::optional<uint16_t> timeout, boost::optional<uint64_t> maxQueuedEntries, boost::optional<uint8_t> reconnectWaitTime) {
+      if (client || configCheck) {
         return std::shared_ptr<RemoteLoggerInterface>(nullptr);
       }
       return std::shared_ptr<RemoteLoggerInterface>(new RemoteLogger(ComboAddress(remote), timeout ? *timeout : 2, maxQueuedEntries ? (*maxQueuedEntries*100) : 10000, reconnectWaitTime ? *reconnectWaitTime : 1, client));
     });
 
-  g_lua.writeFunction("newFrameStreamUnixLogger", [client](const std::string& address) {
+  g_lua.writeFunction("newFrameStreamUnixLogger", [client,configCheck](const std::string& address) {
 #ifdef HAVE_FSTRM
-      if (client) {
+      if (client || configCheck) {
         return std::shared_ptr<RemoteLoggerInterface>(nullptr);
       }
       return std::shared_ptr<RemoteLoggerInterface>(new FrameStreamLogger(AF_UNIX, address, !client));
@@ -112,9 +112,9 @@ void setupLuaBindingsProtoBuf(bool client)
 #endif /* HAVE_FSTRM */
     });
 
-  g_lua.writeFunction("newFrameStreamTcpLogger", [client](const std::string& address) {
+  g_lua.writeFunction("newFrameStreamTcpLogger", [client,configCheck](const std::string& address) {
 #if defined(HAVE_FSTRM) && defined(HAVE_FSTRM_TCP_WRITER_INIT)
-      if (client) {
+      if (client || configCheck) {
         return std::shared_ptr<RemoteLoggerInterface>(nullptr);
       }
       return std::shared_ptr<RemoteLoggerInterface>(new FrameStreamLogger(AF_INET, address, !client));
index 8dcb9a70c64a710bdc95c6d153be0c9a5361cc2e..9a3a0deaf05d38cd1d3fb6a65d5a7aa62d21ab79 100644 (file)
@@ -227,6 +227,12 @@ Control Socket, Console and Webserver
 
   Returns true while the console client is parsing the configuration.
 
+.. function:: inConfigCheck()
+
+  .. versionadded:: 1.5.0
+
+  Returns true while the configuration is being checked, ie when run with ``--check-config``.
+
 .. function:: makeKey()
 
   Generate and print an encryption key.