]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Protect the runtime-modifiable configuration via RCU
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 19 Mar 2024 17:24:14 +0000 (18:24 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 15 Jul 2024 09:39:34 +0000 (11:39 +0200)
53 files changed:
pdns/credentials.cc
pdns/credentials.hh
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/dnscrypt.hh
pdns/dnsdistdist/dnsdist-backend.cc
pdns/dnsdistdist/dnsdist-carbon.cc
pdns/dnsdistdist/dnsdist-concurrent-connections.hh
pdns/dnsdistdist/dnsdist-configuration.cc [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-configuration.hh [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-console.cc
pdns/dnsdistdist/dnsdist-console.hh
pdns/dnsdistdist/dnsdist-discovery.cc
pdns/dnsdistdist/dnsdist-dynblocks.cc
pdns/dnsdistdist/dnsdist-ecs.cc
pdns/dnsdistdist/dnsdist-ecs.hh
pdns/dnsdistdist/dnsdist-healthchecks.cc
pdns/dnsdistdist/dnsdist-healthchecks.hh
pdns/dnsdistdist/dnsdist-lbpolicies.cc
pdns/dnsdistdist/dnsdist-lbpolicies.hh
pdns/dnsdistdist/dnsdist-lua-actions.cc
pdns/dnsdistdist/dnsdist-lua-bindings-dnsquestion.cc
pdns/dnsdistdist/dnsdist-lua-bindings.cc
pdns/dnsdistdist/dnsdist-lua-ffi.cc
pdns/dnsdistdist/dnsdist-lua-inspection.cc
pdns/dnsdistdist/dnsdist-lua.cc
pdns/dnsdistdist/dnsdist-nghttp2-in.cc
pdns/dnsdistdist/dnsdist-nghttp2.cc
pdns/dnsdistdist/dnsdist-proxy-protocol.cc
pdns/dnsdistdist/dnsdist-proxy-protocol.hh
pdns/dnsdistdist/dnsdist-query-count.cc [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-query-count.hh [new file with mode: 0644]
pdns/dnsdistdist/dnsdist-secpoll.cc
pdns/dnsdistdist/dnsdist-secpoll.hh
pdns/dnsdistdist/dnsdist-session-cache.cc
pdns/dnsdistdist/dnsdist-session-cache.hh
pdns/dnsdistdist/dnsdist-snmp.cc
pdns/dnsdistdist/dnsdist-snmp.hh
pdns/dnsdistdist/dnsdist-svc.cc
pdns/dnsdistdist/dnsdist-tcp-upstream.hh
pdns/dnsdistdist/dnsdist-tcp.cc
pdns/dnsdistdist/dnsdist-web.cc
pdns/dnsdistdist/dnsdist.cc
pdns/dnsdistdist/dnsdist.hh
pdns/dnsdistdist/test-dnscrypt_cc.cc
pdns/dnsdistdist/test-dnsdist-lua-ffi.cc
pdns/dnsdistdist/test-dnsdist_cc.cc
pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc
pdns/dnsdistdist/test-dnsdistnghttp2-in_cc.cc
pdns/dnsdistdist/test-dnsdisttcp_cc.cc
pdns/dolog.hh
pdns/proxy-protocol.hh
pdns/tcpiohandler.cc
pdns/tcpiohandler.hh

index ec11732f246c04a5998da426becf9ab2b2e4ef3e..a1131035d128612ad2928d01babde47c07d4b1a7 100644 (file)
@@ -56,10 +56,6 @@ static std::string const pwhash_prefix = "$scrypt$";
 static size_t const pwhash_prefix_size = pwhash_prefix.size();
 #endif
 
-uint64_t const CredentialsHolder::s_defaultWorkFactor{1024U}; /* N */
-uint64_t const CredentialsHolder::s_defaultParallelFactor{1U}; /* p */
-uint64_t const CredentialsHolder::s_defaultBlockSize{8U}; /* r */
-
 SensitiveData::SensitiveData(std::string&& data) :
   d_data(std::move(data))
 {
index 6762b1a845116d6247bfb9daa835b1083f0c8bda..1cadc14b8b99b527a9d57c3f7a04dde3c9777195 100644 (file)
@@ -81,9 +81,9 @@ public:
   static bool isHashingAvailable();
   static SensitiveData readFromTerminal();
 
-  static uint64_t const s_defaultWorkFactor;
-  static uint64_t const s_defaultParallelFactor;
-  static uint64_t const s_defaultBlockSize;
+  static uint64_t constexpr s_defaultWorkFactor{1024U}; /* N */;
+  static uint64_t constexpr s_defaultParallelFactor{1U}; /* p */;
+  static uint64_t constexpr s_defaultBlockSize{8U}; /* r */;
 
 private:
   SensitiveData d_credentials;
index 2ca88419c7898733914adb5f204c81762341258a..98267217f8a2315da8f3327c691e5fd467ab2d35 100644 (file)
@@ -150,6 +150,7 @@ dnsdist_SOURCES = \
        dnsdist-cache.cc dnsdist-cache.hh \
        dnsdist-carbon.cc dnsdist-carbon.hh \
        dnsdist-concurrent-connections.hh \
+       dnsdist-configuration.cc dnsdist-configuration.hh \
        dnsdist-console.cc dnsdist-console.hh \
        dnsdist-crypto.cc dnsdist-crypto.hh \
        dnsdist-discovery.cc dnsdist-discovery.hh \
@@ -194,6 +195,7 @@ dnsdist_SOURCES = \
        dnsdist-protobuf.cc dnsdist-protobuf.hh \
        dnsdist-protocols.cc dnsdist-protocols.hh \
        dnsdist-proxy-protocol.cc dnsdist-proxy-protocol.hh \
+       dnsdist-query-count.hh dnsdist-query-count.cc \
        dnsdist-random.cc dnsdist-random.hh \
        dnsdist-resolver.cc dnsdist-resolver.hh \
        dnsdist-rings.cc dnsdist-rings.hh \
@@ -274,6 +276,7 @@ testrunner_SOURCES = \
        dnsdist-backoff.hh \
        dnsdist-cache.cc dnsdist-cache.hh \
        dnsdist-concurrent-connections.hh \
+       dnsdist-configuration.cc dnsdist-configuration.hh \
        dnsdist-crypto.cc dnsdist-crypto.hh \
        dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
        dnsdist-doh-common.cc dnsdist-doh-common.hh \
@@ -547,6 +550,7 @@ fuzz_target_dnsdistcache_SOURCES = \
        channel.hh channel.cc \
        dns.cc dns.hh \
        dnsdist-cache.cc dnsdist-cache.hh \
+       dnsdist-configuration.cc dnsdist-configuration.hh \
        dnsdist-dnsparser.cc dnsdist-dnsparser.hh \
        dnsdist-ecs.cc dnsdist-ecs.hh \
        dnsdist-idstate.hh \
index ff5e40bbdfba62eae21a89bd8545448c61dfba13..516848f9a05dfad3211908cb4ef0e242b949c05d 100644 (file)
@@ -259,7 +259,7 @@ public:
   void getCertificateResponse(time_t now, PacketBuffer& response) const;
   int encryptResponse(PacketBuffer& response, size_t maxResponseSize, bool tcp);
 
-  static const size_t s_minUDPLength = 256;
+  static constexpr size_t s_minUDPLength = 256;
 
 private:
   static void fillServerNonce(DNSCryptNonceType& nonce);
index c4ea77d1cb7e678b69524461ff6119af5ff85f37..a3e8edf95b43f7809f67d4406bb226a0e67e3bee 100644 (file)
@@ -26,6 +26,7 @@
 #include "dnsdist-nghttp2.hh"
 #include "dnsdist-random.hh"
 #include "dnsdist-rings.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsdist-tcp.hh"
 #include "dnsdist-xsk.hh"
 #include "dolog.hh"
@@ -143,7 +144,7 @@ bool DownstreamState::reconnect(bool initialAttempt)
       connected = true;
     }
     catch (const std::runtime_error& error) {
-      if (initialAttempt || g_verbose) {
+      if (initialAttempt || dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
         infolog("Error connecting to new server with address %s: %s", d_config.remote.toStringWithPort(), error.what());
       }
       connected = false;
@@ -236,6 +237,7 @@ void DownstreamState::stop()
 void DownstreamState::hash()
 {
   vinfolog("Computing hashes for id=%s and weight=%d", *d_config.id, d_config.d_weight);
+  const auto hashPerturbation = dnsdist::configuration::getImmutableConfiguration().d_hashPerturbation;
   auto w = d_config.d_weight;
   auto idStr = boost::str(boost::format("%s") % *d_config.id);
   auto lockedHashes = hashes.write_lock();
@@ -243,7 +245,8 @@ void DownstreamState::hash()
   lockedHashes->reserve(w);
   while (w > 0) {
     std::string uuid = boost::str(boost::format("%s-%d") % idStr % w);
-    unsigned int wshash = burtleCI(reinterpret_cast<const unsigned char*>(uuid.c_str()), uuid.size(), g_hashperturb);
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast): sorry, it's the burtle API
+    unsigned int wshash = burtleCI(reinterpret_cast<const unsigned char*>(uuid.c_str()), uuid.size(), hashPerturbation);
     lockedHashes->push_back(wshash);
     --w;
   }
@@ -305,7 +308,7 @@ DownstreamState::DownstreamState(DownstreamState::Config&& config, std::shared_p
 #ifdef HAVE_NGHTTP2
       setupDoHClientProtocolNegotiation(d_tlsCtx);
 
-      if (g_configurationDone && g_outgoingDoHWorkerThreads && *g_outgoingDoHWorkerThreads == 0) {
+      if (dnsdist::configuration::isConfigurationDone() && g_outgoingDoHWorkerThreads && *g_outgoingDoHWorkerThreads == 0) {
         throw std::runtime_error("Error: setOutgoingDoHWorkerThreads() is set to 0 so no outgoing DoH worker thread is available to serve queries");
       }
 
@@ -352,11 +355,12 @@ void DownstreamState::start()
 
 void DownstreamState::connectUDPSockets()
 {
-  if (s_randomizeIDs) {
+  const auto& config = dnsdist::configuration::getImmutableConfiguration();
+  if (config.d_randomizeIDsToBackend) {
     idStates.clear();
   }
   else {
-    idStates.resize(g_maxOutstanding);
+    idStates.resize(config.d_maxUDPOutstanding);
   }
   sockets.resize(d_config.d_numberOfSockets);
 
@@ -396,8 +400,8 @@ int DownstreamState::pickSocketForSending()
     return sockets[0];
   }
 
-  size_t idx;
-  if (s_randomizeSockets) {
+  size_t idx{0};
+  if (dnsdist::configuration::getImmutableConfiguration().d_randomizeUDPSocketsToBackend) {
     idx = dnsdist::getRandomValue(numberOfSockets);
   }
   else {
@@ -419,14 +423,10 @@ void DownstreamState::pickSocketsReadyForReceiving(std::vector<int>& ready)
   (*mplexer.lock())->getAvailableFDs(ready, 1000);
 }
 
-bool DownstreamState::s_randomizeSockets{false};
-bool DownstreamState::s_randomizeIDs{false};
-int DownstreamState::s_udpTimeout{2};
-
-static bool isIDSExpired(const IDState& ids)
+static bool isIDSExpired(const IDState& ids, uint8_t udpTimeout)
 {
   auto age = ids.age.load();
-  return age > DownstreamState::s_udpTimeout;
+  return age > udpTimeout;
 }
 
 void DownstreamState::handleUDPTimeout(IDState& ids)
@@ -478,11 +478,13 @@ void DownstreamState::handleUDPTimeouts()
     return;
   }
 
-  if (s_randomizeIDs) {
+  const auto& config = dnsdist::configuration::getImmutableConfiguration();
+  const auto udpTimeout = config.d_udpTimeout;
+  if (config.d_randomizeIDsToBackend) {
     auto map = d_idStatesMap.lock();
     for (auto it = map->begin(); it != map->end(); ) {
       auto& ids = it->second;
-      if (isIDSExpired(ids)) {
+      if (isIDSExpired(ids, udpTimeout)) {
         handleUDPTimeout(ids);
         it = map->erase(it);
         continue;
@@ -497,7 +499,7 @@ void DownstreamState::handleUDPTimeouts()
         if (!ids.isInUse()) {
           continue;
         }
-        if (!isIDSExpired(ids)) {
+        if (!isIDSExpired(ids, udpTimeout)) {
           ++ids.age;
           continue;
         }
@@ -506,7 +508,7 @@ void DownstreamState::handleUDPTimeouts()
           continue;
         }
         /* check again, now that we have locked this state */
-        if (ids.isInUse() && isIDSExpired(ids)) {
+        if (ids.isInUse() && isIDSExpired(ids, udpTimeout)) {
           handleUDPTimeout(ids);
         }
       }
@@ -516,7 +518,8 @@ void DownstreamState::handleUDPTimeouts()
 
 uint16_t DownstreamState::saveState(InternalQueryState&& state)
 {
-  if (s_randomizeIDs) {
+  const auto& config = dnsdist::configuration::getImmutableConfiguration();
+  if (config.d_randomizeIDsToBackend) {
     /* if the state is already in use we will retry,
        up to 5 five times. The last selected one is used
        even if it was already in use */
@@ -578,7 +581,8 @@ uint16_t DownstreamState::saveState(InternalQueryState&& state)
 
 void DownstreamState::restoreState(uint16_t id, InternalQueryState&& state)
 {
-  if (s_randomizeIDs) {
+  const auto& config = dnsdist::configuration::getImmutableConfiguration();
+  if (config.d_randomizeIDsToBackend) {
     auto map = d_idStatesMap.lock();
 
     auto [it, inserted] = map->emplace(id, IDState());
@@ -619,8 +623,8 @@ void DownstreamState::restoreState(uint16_t id, InternalQueryState&& state)
 std::optional<InternalQueryState> DownstreamState::getState(uint16_t id)
 {
   std::optional<InternalQueryState> result = std::nullopt;
-
-  if (s_randomizeIDs) {
+  const auto& config = dnsdist::configuration::getImmutableConfiguration();
+  if (config.d_randomizeIDsToBackend) {
     auto map = d_idStatesMap.lock();
 
     auto it = map->find(id);
@@ -864,7 +868,7 @@ void DownstreamState::submitHealthCheckResult(bool initial, bool newResult)
     }
 
     setUpStatus(newState);
-    if (g_snmpAgent && g_snmpTrapsEnabled) {
+    if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
       g_snmpAgent->sendBackendStatusChangeTrap(*this);
     }
   }
index 2be36ed3827b7accdaf1e6f25fa6ff8f737ff0e4..5ffe257e0b59ffb1242a888680afce2501ad5ba2 100644 (file)
@@ -26,6 +26,7 @@
 #include "dnsdist-carbon.hh"
 #include "dnsdist.hh"
 #include "dnsdist-backoff.hh"
+#include "dnsdist-configuration.hh"
 #include "dnsdist-metrics.hh"
 
 #ifndef DISABLE_CARBON
@@ -270,7 +271,7 @@ static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
 
     {
       std::string qname;
-      auto records = g_qcount.records.write_lock();
+      auto records = dnsdist::QueryCount::g_queryCountRecords.write_lock();
       for (const auto& record : *records) {
         qname = record.first;
         boost::replace_all(qname, ".", "_");
index 3cf55d5a414d469793f338877a831d59b43a8c7a..9827bbc33fecc90b65e5b8d6252f8234946ddd53 100644 (file)
@@ -24,6 +24,7 @@
 #include <map>
 #include "iputils.hh"
 #include "lock.hh"
+#include "dnsdist-configuration.hh"
 
 namespace dnsdist
 {
@@ -32,12 +33,13 @@ class IncomingConcurrentTCPConnectionsManager
 public:
   static bool accountNewTCPConnection(const ComboAddress& from)
   {
-    if (s_maxTCPConnectionsPerClient == 0) {
+    const auto maxConnsPerClient = dnsdist::configuration::getImmutableConfiguration().d_maxTCPConnectionsPerClient;
+    if (maxConnsPerClient == 0) {
       return true;
     }
     auto db = s_tcpClientsConcurrentConnectionsCount.lock();
     auto& count = (*db)[from];
-    if (count >= s_maxTCPConnectionsPerClient) {
+    if (count >= maxConnsPerClient) {
       return false;
     }
     ++count;
@@ -46,7 +48,8 @@ public:
 
   static void accountClosedTCPConnection(const ComboAddress& from)
   {
-    if (s_maxTCPConnectionsPerClient == 0) {
+    const auto maxConnsPerClient = dnsdist::configuration::getImmutableConfiguration().d_maxTCPConnectionsPerClient;
+    if (maxConnsPerClient == 0) {
       return;
     }
     auto db = s_tcpClientsConcurrentConnectionsCount.lock();
@@ -57,14 +60,8 @@ public:
     }
   }
 
-  static void setMaxTCPConnectionsPerClient(size_t max)
-  {
-    s_maxTCPConnectionsPerClient = max;
-  }
-
 private:
   static LockGuarded<std::map<ComboAddress, size_t, ComboAddress::addressOnlyLessThan>> s_tcpClientsConcurrentConnectionsCount;
-  static size_t s_maxTCPConnectionsPerClient;
 };
 
 }
diff --git a/pdns/dnsdistdist/dnsdist-configuration.cc b/pdns/dnsdistdist/dnsdist-configuration.cc
new file mode 100644 (file)
index 0000000..24689ea
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-configuration.hh"
+#include "sholder.hh"
+
+namespace dnsdist::configuration
+{
+static GlobalStateHolder<RuntimeConfiguration> s_currentRuntimeConfiguration;
+static Configuration s_configuration;
+static std::atomic<bool> s_configurationDone{false};
+
+const RuntimeConfiguration& getCurrentRuntimeConfiguration()
+{
+  static thread_local auto t_threadLocalConfiguration = s_currentRuntimeConfiguration.getLocal();
+  return *t_threadLocalConfiguration;
+}
+
+void updateRuntimeConfiguration(const std::function<void(RuntimeConfiguration&)>& mutator)
+{
+  s_currentRuntimeConfiguration.modify(mutator);
+}
+
+void updateImmutableConfiguration(const std::function<void(Configuration&)>& mutator)
+{
+  if (isConfigurationDone()) {
+    throw std::runtime_error("Trying to update an immutable setting at runtime!");
+  }
+
+  mutator(s_configuration);
+}
+
+const Configuration& getImmutableConfiguration()
+{
+  return s_configuration;
+}
+
+bool isConfigurationDone()
+{
+  return s_configurationDone.load();
+}
+
+void setConfigurationDone()
+{
+  s_configurationDone.store(true);
+}
+}
diff --git a/pdns/dnsdistdist/dnsdist-configuration.hh b/pdns/dnsdistdist/dnsdist-configuration.hh
new file mode 100644 (file)
index 0000000..01c3dd4
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <functional>
+#include <map>
+#include <string>
+
+#include "dnsdist-query-count.hh"
+#include "iputils.hh"
+
+/* so what could you do:
+   drop,
+   fake up nxdomain,
+   provide actual answer,
+   allow & and stop processing,
+   continue processing,
+   modify header:    (servfail|refused|notimp), set TC=1,
+   send to pool */
+
+struct DNSQuestion;
+struct DNSResponse;
+
+class DNSAction
+{
+public:
+  enum class Action : uint8_t
+  {
+    Drop,
+    Nxdomain,
+    Refused,
+    Spoof,
+    Allow,
+    HeaderModify,
+    Pool,
+    Delay,
+    Truncate,
+    ServFail,
+    None,
+    NoOp,
+    NoRecurse,
+    SpoofRaw,
+    SpoofPacket,
+    SetTag,
+  };
+  static std::string typeToString(const Action& action)
+  {
+    switch (action) {
+    case Action::Drop:
+      return "Drop";
+    case Action::Nxdomain:
+      return "Send NXDomain";
+    case Action::Refused:
+      return "Send Refused";
+    case Action::Spoof:
+      return "Spoof an answer";
+    case Action::SpoofPacket:
+      return "Spoof a raw answer from bytes";
+    case Action::SpoofRaw:
+      return "Spoof an answer from raw bytes";
+    case Action::Allow:
+      return "Allow";
+    case Action::HeaderModify:
+      return "Modify the header";
+    case Action::Pool:
+      return "Route to a pool";
+    case Action::Delay:
+      return "Delay";
+    case Action::Truncate:
+      return "Truncate over UDP";
+    case Action::ServFail:
+      return "Send ServFail";
+    case Action::SetTag:
+      return "Set Tag";
+    case Action::None:
+    case Action::NoOp:
+      return "Do nothing";
+    case Action::NoRecurse:
+      return "Set rd=0";
+    }
+
+    return "Unknown";
+  }
+
+  virtual Action operator()(DNSQuestion*, std::string* ruleresult) const = 0;
+  virtual ~DNSAction() = default;
+  virtual std::string toString() const = 0;
+  virtual std::map<std::string, double> getStats() const
+  {
+    return {{}};
+  }
+  virtual void reload()
+  {
+  }
+};
+
+class DNSResponseAction
+{
+public:
+  enum class Action : uint8_t
+  {
+    Allow,
+    Delay,
+    Drop,
+    HeaderModify,
+    ServFail,
+    Truncate,
+    None
+  };
+  virtual Action operator()(DNSResponse*, std::string* ruleresult) const = 0;
+  virtual ~DNSResponseAction() = default;
+  virtual std::string toString() const = 0;
+  virtual void reload()
+  {
+  }
+};
+
+namespace dnsdist::configuration
+{
+/* when we add EDNS to a query, we don't want to advertise
+   a large buffer size */
+static constexpr size_t s_EdnsUDPPayloadSize{512};
+static constexpr uint16_t s_defaultPayloadSizeSelfGenAnswers = 1232;
+static constexpr uint16_t s_udpIncomingBufferSize{1500}; // don't accept UDP queries larger than this value
+static_assert(s_defaultPayloadSizeSelfGenAnswers < s_udpIncomingBufferSize, "The UDP responder's payload size should be smaller or equal to our incoming buffer size");
+
+struct Configuration
+{
+  std::string d_consoleKey;
+#ifdef __linux__
+  // On Linux this gives us 128k pending queries (default is 8192 queries),
+  // which should be enough to deal with huge spikes
+  uint64_t d_maxTCPQueuedConnections{10000};
+  size_t d_tcpInternalPipeBufferSize{1048576U};
+#else
+  uint64_t d_maxTCPQueuedConnections{1000};
+  size_t d_tcpInternalPipeBufferSize{0};
+#endif
+  double d_weightedBalancingFactor{0};
+  double d_consistentHashBalancingFactor{0};
+  uint64_t d_maxTCPClientThreads{0};
+  size_t d_maxTCPConnectionsPerClient{0};
+  size_t d_udpVectorSize{1};
+  uint32_t d_socketUDPSendBuffer{0};
+  uint32_t d_socketUDPRecvBuffer{0};
+  uint32_t d_hashPerturbation{0};
+  uint16_t d_maxUDPOutstanding{std::numeric_limits<uint16_t>::max()};
+  uint8_t d_udpTimeout{2};
+  bool d_randomizeUDPSocketsToBackend{false};
+  bool d_randomizeIDsToBackend{false};
+};
+
+struct RuntimeConfiguration
+{
+  NetmaskGroup d_proxyProtocolACL;
+  NetmaskGroup d_consoleACL;
+  dnsdist::QueryCount::Configuration d_queryCountConfig;
+  std::string d_secPollSuffix{"secpoll.powerdns.com."};
+  std::string d_apiConfigDirectory;
+  size_t d_maxTCPQueriesPerConn{0};
+  size_t d_maxTCPConnectionDuration{0};
+  size_t d_proxyProtocolMaximumSize{512};
+  uint32_t d_staleCacheEntriesTTL{0};
+  uint32_t d_secPollInterval{3600};
+  uint32_t d_consoleOutputMsgMaxSize{10000000};
+  uint16_t d_payloadSizeSelfGenAnswers{s_defaultPayloadSizeSelfGenAnswers};
+  uint16_t d_tcpRecvTimeout{2};
+  uint16_t d_tcpSendTimeout{2};
+  /* rfc7871: "11.1. Privacy" */
+  uint16_t d_ECSSourcePrefixV4{24};
+  uint16_t d_ECSSourcePrefixV6{56};
+  uint16_t d_cacheCleaningDelay{60};
+  uint16_t d_cacheCleaningPercentage{100};
+  uint16_t d_tlsSessionCacheCleanupDelay{60};
+  uint16_t d_tlsSessionCacheSessionValidity{600};
+  uint16_t d_tlsSessionCacheMaxSessionsPerBackend{20};
+  DNSAction::Action d_dynBlockAction{DNSAction::Action::Drop};
+  bool d_truncateTC{false};
+  bool d_fixupCase{false};
+  bool d_queryCountEnabled{false};
+  bool d_ecsOverride{false};
+  bool d_verbose{false};
+  bool d_verboseHealthChecks{false};
+  bool d_apiReadWrite{false};
+  bool d_roundrobinFailOnNoServer{false};
+  bool d_servFailOnNoPolicy{false};
+  bool d_allowEmptyResponse{false};
+  bool d_dropEmptyQueries{false};
+  bool d_snmpEnabled{false};
+  bool d_snmpTrapsEnabled{false};
+  bool d_consoleEnabled{false};
+  bool d_logConsoleConnections{true};
+  bool d_addEDNSToSelfGeneratedResponses{true};
+  bool d_applyACLToProxiedClients{false};
+};
+
+const RuntimeConfiguration& getCurrentRuntimeConfiguration();
+const Configuration& getImmutableConfiguration();
+void updateImmutableConfiguration(const std::function<void(Configuration&)>& mutator);
+void updateRuntimeConfiguration(const std::function<void(RuntimeConfiguration&)>& mutator);
+bool isConfigurationDone();
+void setConfigurationDone();
+}
index 6696843fd91e1ff743d3c56df1855faebd4c6e3d..77dee4e812b4206a55f796a32f661303b47f8b57 100644 (file)
 #include "dnsdist-crypto.hh"
 #include "threadname.hh"
 
-GlobalStateHolder<NetmaskGroup> g_consoleACL;
-vector<pair<struct timeval, string>> g_confDelta;
-std::string g_consoleKey;
-bool g_logConsoleConnections{true};
-bool g_consoleEnabled{false};
-uint32_t g_consoleOutputMsgMaxSize{10000000};
+static LockGuarded<std::vector<pair<timeval, string>>> s_confDelta;
 
 static ConcurrentConnectionManager s_connManager(100);
 
@@ -101,7 +96,6 @@ void setConsoleMaximumConcurrentConnections(size_t max)
   s_connManager.setMaxConcurrentConnections(max);
 }
 
-// MUST BE CALLED UNDER A LOCK - right now the LuaLock
 static void feedConfigDelta(const std::string& line)
 {
   if (line.empty()) {
@@ -109,7 +103,15 @@ static void feedConfigDelta(const std::string& line)
   }
   timeval now{};
   gettimeofday(&now, nullptr);
-  g_confDelta.emplace_back(now, line);
+  s_confDelta.lock()->emplace_back(now, line);
+}
+
+namespace dnsdist::console
+{
+const std::vector<std::pair<timeval, std::string>>& getConfigurationDelta()
+{
+  return *(s_confDelta.lock());
+}
 }
 
 #ifdef HAVE_LIBEDIT
@@ -156,7 +158,7 @@ static ConsoleCommandResult getMsgLen32(int fileDesc, uint32_t* len)
     }
 
     *len = ntohl(raw);
-    if (*len > g_consoleOutputMsgMaxSize) {
+    if (*len > dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleOutputMsgMaxSize) {
       return ConsoleCommandResult::TooLarge;
     }
 
@@ -181,7 +183,8 @@ static bool putMsgLen32(int fileDesc, uint32_t len)
 
 static ConsoleCommandResult sendMessageToServer(int fileDesc, const std::string& line, dnsdist::crypto::authenticated::Nonce& readingNonce, dnsdist::crypto::authenticated::Nonce& writingNonce, const bool outputEmptyLine)
 {
-  string msg = dnsdist::crypto::authenticated::encryptSym(line, g_consoleKey, writingNonce);
+  const auto& consoleKey = dnsdist::configuration::getImmutableConfiguration().d_consoleKey;
+  string msg = dnsdist::crypto::authenticated::encryptSym(line, consoleKey, writingNonce);
   const auto msgLen = msg.length();
   if (msgLen > std::numeric_limits<uint32_t>::max()) {
     cerr << "Encrypted message is too long to be sent to the server, " << std::to_string(msgLen) << " > " << std::numeric_limits<uint32_t>::max() << endl;
@@ -201,7 +204,7 @@ static ConsoleCommandResult sendMessageToServer(int fileDesc, const std::string&
     return commandResult;
   }
   if (commandResult == ConsoleCommandResult::TooLarge) {
-    cerr << "Received a console message whose length (" << len << ") is exceeding the allowed one (" << g_consoleOutputMsgMaxSize << "), closing that connection" << endl;
+    cerr << "Received a console message whose length (" << len << ") is exceeding the allowed one (" << dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleOutputMsgMaxSize << "), closing that connection" << endl;
     return commandResult;
   }
 
@@ -216,7 +219,7 @@ static ConsoleCommandResult sendMessageToServer(int fileDesc, const std::string&
   msg.clear();
   msg.resize(len);
   readn2(fileDesc, msg.data(), len);
-  msg = dnsdist::crypto::authenticated::decryptSym(msg, g_consoleKey, readingNonce);
+  msg = dnsdist::crypto::authenticated::decryptSym(msg, consoleKey, readingNonce);
   cout << msg;
   cout.flush();
 
@@ -225,12 +228,13 @@ static ConsoleCommandResult sendMessageToServer(int fileDesc, const std::string&
 
 void doClient(ComboAddress server, const std::string& command)
 {
-  if (!dnsdist::crypto::authenticated::isValidKey(g_consoleKey)) {
+  const auto& consoleKey = dnsdist::configuration::getImmutableConfiguration().d_consoleKey;
+  if (!dnsdist::crypto::authenticated::isValidKey(consoleKey)) {
     cerr << "The currently configured console key is not valid, please configure a valid key using the setKey() directive" << endl;
     return;
   }
 
-  if (g_verbose) {
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
     cout << "Connecting to " << server.toStringWithPort() << endl;
   }
 
@@ -902,6 +906,7 @@ static void controlClientThread(ConsoleConnection&& conn)
 
     setTCPNoDelay(conn.getFD());
 
+    const auto& consoleKey = dnsdist::configuration::getImmutableConfiguration().d_consoleKey;
     dnsdist::crypto::authenticated::Nonce theirs;
     dnsdist::crypto::authenticated::Nonce ours;
     dnsdist::crypto::authenticated::Nonce readingNonce;
@@ -929,7 +934,7 @@ static void controlClientThread(ConsoleConnection&& conn)
       line.resize(len);
       readn2(conn.getFD(), line.data(), len);
 
-      line = dnsdist::crypto::authenticated::decryptSym(line, g_consoleKey, readingNonce);
+      line = dnsdist::crypto::authenticated::decryptSym(line, consoleKey, readingNonce);
 
       string response;
       try {
@@ -1021,11 +1026,11 @@ static void controlClientThread(ConsoleConnection&& conn)
       catch (const LuaContext::SyntaxErrorException& e) {
         response = "Error: " + string(e.what()) + ": ";
       }
-      response = dnsdist::crypto::authenticated::encryptSym(response, g_consoleKey, writingNonce);
+      response = dnsdist::crypto::authenticated::encryptSym(response, consoleKey, writingNonce);
       putMsgLen32(conn.getFD(), response.length());
       writen2(conn.getFD(), response.c_str(), response.length());
     }
-    if (g_logConsoleConnections) {
+    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_logConsoleConnections) {
       infolog("Closed control connection from %s", conn.getClient().toStringWithPort());
     }
   }
@@ -1046,25 +1051,25 @@ void controlThread(std::shared_ptr<Socket> acceptFD, ComboAddress local)
     client.sin4.sin_family = local.sin4.sin_family;
 
     int sock{-1};
-    auto localACL = g_consoleACL.getLocal();
     infolog("Accepting control connections on %s", local.toStringWithPort());
 
     while ((sock = SAccept(acceptFD->getHandle(), client)) >= 0) {
-
+      const auto& consoleKey = dnsdist::configuration::getImmutableConfiguration().d_consoleKey;
       FDWrapper socket(sock);
-      if (!dnsdist::crypto::authenticated::isValidKey(g_consoleKey)) {
+      if (!dnsdist::crypto::authenticated::isValidKey(consoleKey)) {
         vinfolog("Control connection from %s dropped because we don't have a valid key configured, please configure one using setKey()", client.toStringWithPort());
         continue;
       }
 
-      if (!localACL->match(client)) {
+      const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+      if (!runtimeConfig.d_consoleACL.match(client)) {
         vinfolog("Control connection from %s dropped because of ACL", client.toStringWithPort());
         continue;
       }
 
       try {
         ConsoleConnection conn(client, std::move(socket));
-        if (g_logConsoleConnections) {
+        if (runtimeConfig.d_logConsoleConnections) {
           warnlog("Got control connection from %s", client.toStringWithPort());
         }
 
@@ -1086,5 +1091,5 @@ void clearConsoleHistory()
 #ifdef HAVE_LIBEDIT
   clear_history();
 #endif /* HAVE_LIBEDIT */
-  g_confDelta.clear();
+  s_confDelta.lock()->clear();
 }
index dd833c49e473f3346beac57c1b0cdc392f0c9959..077fc2609ce6762d687ec4501ed1a4dd08c0ec98 100644 (file)
@@ -21,6 +21,9 @@
  */
 #pragma once
 
+#include <vector>
+#include <string>
+
 #include "config.h"
 #include "sstuff.hh"
 
@@ -50,15 +53,14 @@ extern "C"
 
 #endif /* DISABLE_COMPLETION */
 
-extern GlobalStateHolder<NetmaskGroup> g_consoleACL;
-extern std::string g_consoleKey; // in theory needs locking
-extern bool g_logConsoleConnections;
-extern bool g_consoleEnabled;
-extern uint32_t g_consoleOutputMsgMaxSize;
-
 void doClient(ComboAddress server, const std::string& command);
 void doConsole();
 void controlThread(std::shared_ptr<Socket> acceptFD, ComboAddress local);
 void clearConsoleHistory();
 
 void setConsoleMaximumConcurrentConnections(size_t max);
+
+namespace dnsdist::console
+{
+const std::vector<std::pair<timeval, std::string>>& getConfigurationDelta();
+}
index bba713bb6f43170689c860cc4649c75f9837a7b7..ed2a766538349ccf8ea854fbc80932410c2f9208 100644 (file)
@@ -235,6 +235,7 @@ static bool handleSVCResult(const PacketBuffer& answer, const ComboAddress& exis
 
 bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeableBackend, ServiceDiscovery::DiscoveredResolverConfig& config)
 {
+  const auto verbose = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
   const auto& backend = upgradeableBackend.d_ds;
   const auto& addr = backend->d_config.remote;
   try {
@@ -276,7 +277,7 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     uint16_t responseSize = 0;
     auto got = readn2WithTimeout(sock.getHandle(), &responseSize, sizeof(responseSize), remainingTime);
     if (got != sizeof(responseSize)) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Error while waiting for the ADD upgrade response size from backend %s: %d", addr.toStringWithPort(), got);
       }
       return false;
@@ -286,14 +287,14 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
 
     got = readn2WithTimeout(sock.getHandle(), packet.data(), packet.size(), remainingTime);
     if (got != packet.size()) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Error while waiting for the ADD upgrade response from backend %s: %d", addr.toStringWithPort(), got);
       }
       return false;
     }
 
     if (packet.size() <= sizeof(struct dnsheader)) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Too short answer of size %d received from the backend %s", packet.size(), addr.toStringWithPort());
       }
       return false;
@@ -302,14 +303,14 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     struct dnsheader d;
     memcpy(&d, packet.data(), sizeof(d));
     if (d.id != id) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid ID (%d / %d) received from the backend %s", d.id, id, addr.toStringWithPort());
       }
       return false;
     }
 
     if (d.rcode != RCode::NoError) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Response code '%s' received from the backend %s for '%s'", RCode::to_s(d.rcode), addr.toStringWithPort(), s_discoveryDomain);
       }
 
@@ -317,7 +318,7 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     }
 
     if (ntohs(d.qdcount) != 1) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid answer (qdcount %d) received from the backend %s", ntohs(d.qdcount), addr.toStringWithPort());
       }
       return false;
@@ -328,7 +329,7 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     DNSName receivedName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &receivedType, &receivedClass);
 
     if (receivedName != s_discoveryDomain || receivedType != s_discoveryType || receivedClass != QClass::IN) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid answer, either the qname (%s / %s), qtype (%s / %s) or qclass (%s / %s) does not match, received from the backend %s", receivedName, s_discoveryDomain, QType(receivedType).toString(), s_discoveryType.toString(), QClass(receivedClass).toString(), QClass::IN.toString(), addr.toStringWithPort());
       }
       return false;
index ec9362d58729e4d2433225501b4e33fe86740704..1b276003b1f64be3d1d99b50aa571574d05e42be 100644 (file)
@@ -5,7 +5,6 @@
 
 GlobalStateHolder<NetmaskTree<DynBlock, AddressAndPortRange>> g_dynblockNMG;
 GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
-DNSAction::Action g_dynBlockAction = DNSAction::Action::Drop;
 
 #ifndef DISABLE_DYNBLOCKS
 void DynBlockRulesGroup::apply(const timespec& now)
@@ -202,14 +201,14 @@ bool DynBlockRulesGroup::checkIfResponseCodeMatches(const Rings::Response& respo
 
 /* return the actual action that will be taken by that block:
    - either the one set on that block, if any
-   - or the one set with setDynBlocksAction in g_dynBlockAction
+   - or the one set with setDynBlocksAction
 */
 static DNSAction::Action getActualAction(const DynBlock& block)
 {
   if (block.action != DNSAction::Action::None) {
     return block.action;
   }
-  return g_dynBlockAction;
+  return dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
 }
 
 namespace dnsdist::DynamicBlocks
index 988345640745df06b77b93ea0912671543d73d61..c3fe0bccc2ce9fe9d7e8748b45882de32e8f490d 100644 (file)
 #include "ednsoptions.hh"
 #include "ednssubnet.hh"
 
-/* when we add EDNS to a query, we don't want to advertise
-   a large buffer size */
-size_t g_EdnsUDPPayloadSize = 512;
-static const uint16_t defaultPayloadSizeSelfGenAnswers = 1232;
-static_assert(defaultPayloadSizeSelfGenAnswers < s_udpIncomingBufferSize, "The UDP responder's payload size should be smaller or equal to our incoming buffer size");
-uint16_t g_PayloadSizeSelfGenAnswers{defaultPayloadSizeSelfGenAnswers};
-
-/* draft-ietf-dnsop-edns-client-subnet-04 "11.1.  Privacy" */
-uint16_t g_ECSSourcePrefixV4 = 24;
-uint16_t g_ECSSourcePrefixV6 = 56;
-
-bool g_ECSOverride{false};
-bool g_addEDNSToSelfGeneratedResponses{true};
-
 int rewriteResponseWithoutEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent)
 {
   if (initialPacket.size() < sizeof(dnsheader)) {
@@ -261,7 +247,7 @@ bool slowRewriteEDNSOptionInQueryWithRecords(const PacketBuffer& initialPacket,
   }
 
   if (ednsAdded) {
-    packetWriter.addOpt(g_EdnsUDPPayloadSize, 0, 0, {{optionToReplace, std::string(&newOptionContent.at(EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE), newOptionContent.size() - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE))}}, 0);
+    packetWriter.addOpt(dnsdist::configuration::s_EdnsUDPPayloadSize, 0, 0, {{optionToReplace, std::string(&newOptionContent.at(EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE), newOptionContent.size() - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE))}}, 0);
     optionAdded = true;
   }
 
@@ -585,7 +571,7 @@ static bool addECSToExistingOPT(PacketBuffer& packet, size_t maximumSize, const
 
 static bool addEDNSWithECS(PacketBuffer& packet, size_t maximumSize, const string& newECSOption, bool& ednsAdded, bool& ecsAdded)
 {
-  if (!generateOptRR(newECSOption, packet, maximumSize, g_EdnsUDPPayloadSize, 0, false)) {
+  if (!generateOptRR(newECSOption, packet, maximumSize, dnsdist::configuration::s_EdnsUDPPayloadSize, 0, false)) {
     return false;
   }
 
@@ -918,7 +904,7 @@ bool setNegativeAndAdditionalSOA(DNSQuestion& dnsQuestion, bool nxd, const DNSNa
   bool hadEDNS = false;
   bool dnssecOK = false;
 
-  if (g_addEDNSToSelfGeneratedResponses) {
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses) {
     uint16_t payloadSize = 0;
     uint16_t zValue = 0;
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
@@ -997,7 +983,7 @@ bool setNegativeAndAdditionalSOA(DNSQuestion& dnsQuestion, bool nxd, const DNSNa
 
   if (hadEDNS) {
     /* now we need to add a new OPT record */
-    return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
+    return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
   }
 
   return true;
@@ -1036,9 +1022,9 @@ bool addEDNSToQueryTurnedResponse(DNSQuestion& dnsQuestion)
     return true;
   });
 
-  if (g_addEDNSToSelfGeneratedResponses) {
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses) {
     /* now we need to add a new OPT record */
-    return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
+    return addEDNS(packet, dnsQuestion.getMaximumSize(), dnssecOK, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, dnsQuestion.ednsRCode);
   }
 
   /* otherwise we are just fine */
@@ -1150,7 +1136,7 @@ bool setEDNSOption(DNSQuestion& dnsQuestion, uint16_t ednsCode, const std::strin
   }
 
   auto& data = dnsQuestion.getMutableData();
-  if (generateOptRR(optRData, data, dnsQuestion.getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
+  if (generateOptRR(optRData, data, dnsQuestion.getMaximumSize(), dnsdist::configuration::s_EdnsUDPPayloadSize, 0, false)) {
     dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [](dnsheader& header) {
       header.arcount = htons(1);
       return true;
@@ -1196,7 +1182,7 @@ bool setInternalQueryRCode(InternalQueryState& state, PacketBuffer& buffer, uint
     buffer.resize(sizeof(dnsheader) + qnameLength + sizeof(uint16_t) + sizeof(uint16_t));
     if (hadEDNS) {
       DNSQuestion dnsQuestion(state, buffer);
-      if (!addEDNS(buffer, dnsQuestion.getMaximumSize(), (edns0.extFlags & htons(EDNS_HEADER_FLAG_DO)) != 0, g_PayloadSizeSelfGenAnswers, 0)) {
+      if (!addEDNS(buffer, dnsQuestion.getMaximumSize(), (edns0.extFlags & htons(EDNS_HEADER_FLAG_DO)) != 0, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers, 0)) {
         return false;
       }
     }
index 94eccc1a1d7b9a953a9f5017326c95826c0a69b8..ee901bee97b6ff9019224dd5f1c98c18da2e13e4 100644 (file)
@@ -31,9 +31,6 @@ struct DNSQuestion;
 // root label (1), type (2), class (2), ttl (4) + rdlen (2)
 static const size_t optRecordMinimumSize = 11;
 
-extern size_t g_EdnsUDPPayloadSize;
-extern uint16_t g_PayloadSizeSelfGenAnswers;
-
 int rewriteResponseWithoutEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent);
 bool slowRewriteEDNSOptionInQueryWithRecords(const PacketBuffer& initialPacket, PacketBuffer& newContent, bool& ednsAdded, uint16_t optionToReplace, bool& optionAdded, bool overrideExisting, const string& newOptionContent);
 int locateEDNSOptRR(const PacketBuffer& packet, uint16_t* optStart, size_t* optLen, bool* last);
index 36805573e7842624ecefe7ecc223e7270f92250a..02c08037461a520c3ce4c8b6aed563fd35df3bac 100644 (file)
@@ -29,8 +29,6 @@
 #include "dnsdist-nghttp2.hh"
 #include "dnsdist-session-cache.hh"
 
-bool g_verboseHealthChecks{false};
-
 struct HealthCheckData
 {
   enum class TCPState : uint8_t
@@ -66,11 +64,12 @@ struct HealthCheckData
 
 static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
 {
+  const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
   const auto& downstream = data->d_ds;
   try {
     if (data->d_buffer.size() < sizeof(dnsheader)) {
       ++data->d_ds->d_healthCheckMetrics.d_parseErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Invalid health check response of size %d from backend %s, expecting at least %d", data->d_buffer.size(), downstream->getNameWithAddr(), sizeof(dnsheader));
       }
       return false;
@@ -79,7 +78,7 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
     dnsheader_aligned responseHeader(data->d_buffer.data());
     if (responseHeader.get()->id != data->d_queryID) {
       ++data->d_ds->d_healthCheckMetrics.d_mismatchErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Invalid health check response id %d from backend %s, expecting %d", responseHeader.get()->id, downstream->getNameWithAddr(), data->d_queryID);
       }
       return false;
@@ -87,7 +86,7 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
 
     if (!responseHeader.get()->qr) {
       ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Invalid health check response from backend %s, expecting QR to be set", downstream->getNameWithAddr());
       }
       return false;
@@ -95,7 +94,7 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
 
     if (responseHeader.get()->rcode == RCode::ServFail) {
       ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Backend %s responded to health check with ServFail", downstream->getNameWithAddr());
       }
       return false;
@@ -103,7 +102,7 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
 
     if (downstream->d_config.mustResolve && (responseHeader.get()->rcode == RCode::NXDomain || responseHeader.get()->rcode == RCode::Refused)) {
       ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Backend %s responded to health check with %s while mustResolve is set", downstream->getNameWithAddr(), responseHeader.get()->rcode == RCode::NXDomain ? "NXDomain" : "Refused");
       }
       return false;
@@ -116,7 +115,7 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
 
     if (receivedName != data->d_checkName || receivedType != data->d_checkType || receivedClass != data->d_checkClass) {
       ++data->d_ds->d_healthCheckMetrics.d_mismatchErrors;
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Backend %s responded to health check with an invalid qname (%s vs %s), qtype (%s vs %s) or qclass (%d vs %d)", downstream->getNameWithAddr(), receivedName.toLogString(), data->d_checkName.toLogString(), QType(receivedType).toString(), QType(data->d_checkType).toString(), receivedClass, data->d_checkClass);
       }
       return false;
@@ -124,13 +123,13 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
   }
   catch (const std::exception& e) {
     ++data->d_ds->d_healthCheckMetrics.d_parseErrors;
-    if (g_verboseHealthChecks) {
+    if (verboseHealthChecks) {
       infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what());
     }
     return false;
   }
   catch (...) {
-    if (g_verboseHealthChecks) {
+    if (verboseHealthChecks) {
       infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr());
     }
     return false;
@@ -181,6 +180,7 @@ private:
 static void healthCheckUDPCallback(int descriptor, FDMultiplexer::funcparam_t& param)
 {
   auto data = boost::any_cast<std::shared_ptr<HealthCheckData>>(param);
+  const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
 
   ssize_t got = 0;
   ComboAddress from;
@@ -202,7 +202,7 @@ static void healthCheckUDPCallback(int descriptor, FDMultiplexer::funcparam_t& p
         return;
       }
 
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Error receiving health check response from %s: %s", data->d_ds->d_config.remote.toStringWithPort(), stringerror(savederrno));
       }
       ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
@@ -216,7 +216,7 @@ static void healthCheckUDPCallback(int descriptor, FDMultiplexer::funcparam_t& p
 
   /* we are using a connected socket but hey.. */
   if (from != data->d_ds->d_config.remote) {
-    if (g_verboseHealthChecks) {
+    if (verboseHealthChecks) {
       infolog("Invalid health check response received from %s, expecting one from %s", from.toStringWithPort(), data->d_ds->d_config.remote.toStringWithPort());
     }
     ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
@@ -288,13 +288,15 @@ static void healthCheckTCPCallback(int descriptor, FDMultiplexer::funcparam_t& p
   catch (const std::exception& e) {
     ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
     data->d_ds->submitHealthCheckResult(data->d_initial, false);
-    if (g_verboseHealthChecks) {
+    const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
+    if (verboseHealthChecks) {
       infolog("Error checking the health of backend %s: %s", data->d_ds->getNameWithAddr(), e.what());
     }
   }
   catch (...) {
     data->d_ds->submitHealthCheckResult(data->d_initial, false);
-    if (g_verboseHealthChecks) {
+    const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
+    if (verboseHealthChecks) {
       infolog("Unknown exception while checking the health of backend %s", data->d_ds->getNameWithAddr());
     }
   }
@@ -302,6 +304,7 @@ static void healthCheckTCPCallback(int descriptor, FDMultiplexer::funcparam_t& p
 
 bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared_ptr<DownstreamState>& downstream, bool initialCheck)
 {
+  const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
   try {
     uint16_t queryID = dnsdist::getRandomDNSID();
     DNSName checkName = downstream->d_config.checkName;
@@ -350,7 +353,7 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
 #ifdef SO_BINDTODEVICE
     if (!downstream->d_config.sourceItfName.empty()) {
       int res = setsockopt(sock.getHandle(), SOL_SOCKET, SO_BINDTODEVICE, downstream->d_config.sourceItfName.c_str(), downstream->d_config.sourceItfName.length());
-      if (res != 0 && g_verboseHealthChecks) {
+      if (res != 0 && verboseHealthChecks) {
         infolog("Error setting SO_BINDTODEVICE on the health check socket for backend '%s': %s", downstream->getNameWithAddr(), stringerror());
       }
     }
@@ -382,7 +385,7 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
       ssize_t sent = udpClientSendRequestToBackend(downstream, data->d_udpSocket.getHandle(), packet, true);
       if (sent < 0) {
         int ret = errno;
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Error while sending a health check query (ID %d) to backend %s: %d", queryID, downstream->getNameWithAddr(), ret);
         }
         return false;
@@ -435,13 +438,13 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
     return true;
   }
   catch (const std::exception& e) {
-    if (g_verboseHealthChecks) {
+    if (verboseHealthChecks) {
       infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what());
     }
     return false;
   }
   catch (...) {
-    if (g_verboseHealthChecks) {
+    if (verboseHealthChecks) {
       infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr());
     }
     return false;
@@ -450,13 +453,14 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
 
 void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
 {
+  const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
   while (mplexer.getWatchedFDCount(false) > 0 || mplexer.getWatchedFDCount(true) > 0) {
     struct timeval now
     {
     };
     int ret = mplexer.run(&now, 100);
     if (ret == -1) {
-      if (g_verboseHealthChecks) {
+      if (verboseHealthChecks) {
         infolog("Error while waiting for the health check response from backends: %d", ret);
       }
       break;
@@ -485,7 +489,7 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
         else {
           mplexer.removeReadFD(timeout.first);
         }
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
         }
 
@@ -496,13 +500,13 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
         /* this is not supposed to happen as the file descriptor has to be
            there for us to reach that code, and the submission code should not throw,
            but let's provide a nice error message if it ever does. */
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what());
         }
       }
       catch (...) {
         /* this is even less likely to happen */
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
         }
       }
@@ -517,7 +521,7 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
       try {
         /* UDP does not block while writing, H2 is handled separately */
         data->d_ioState.reset();
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
         }
 
@@ -527,13 +531,13 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
       catch (const std::exception& e) {
         /* this is not supposed to happen as the submission code should not throw,
            but let's provide a nice error message if it ever does. */
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what());
         }
       }
       catch (...) {
         /* this is even less likely to happen */
-        if (g_verboseHealthChecks) {
+        if (verboseHealthChecks) {
           infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
         }
       }
index e9da6c66de8b0eb56baadb0c0fc57e78461822d0..fa3cf57aa81849b0b79650b40582307ceee2bca8 100644 (file)
@@ -25,7 +25,5 @@
 #include "mplexer.hh"
 #include "sstuff.hh"
 
-extern bool g_verboseHealthChecks;
-
 bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared_ptr<DownstreamState>& downstream, bool initial = false);
 void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial = false);
index b4e3532619acba185df68dec0242143f25803425..99d1f9036b185adb96048963ed0b9bd5ff19c044 100644 (file)
@@ -28,7 +28,6 @@
 #include "dns_random.hh"
 
 GlobalStateHolder<ServerPolicy> g_policy;
-bool g_roundrobinFailOnNoServer{false};
 
 static constexpr size_t s_staticArrayCutOff = 16;
 template <typename T> using DynamicIndexArray = std::vector<std::pair<T, size_t>>;
@@ -84,16 +83,15 @@ shared_ptr<DownstreamState> firstAvailable(const ServerPolicy::NumberedServerVec
   return leastOutstanding(servers, dq);
 }
 
-double g_weightedBalancingFactor = 0;
-
 template <class T> static std::shared_ptr<DownstreamState> getValRandom(const ServerPolicy::NumberedServerVector& servers, T& poss, const unsigned int val, const double targetLoad)
 {
   constexpr int max = std::numeric_limits<int>::max();
   int sum = 0;
 
   size_t usableServers = 0;
+  const auto weightedBalancingFactor = dnsdist::configuration::getImmutableConfiguration().d_consistentHashBalancingFactor;
   for (const auto& d : servers) {      // w=1, w=10 -> 1, 11
-    if (d.second->isUp() && (g_weightedBalancingFactor == 0 || (d.second->outstanding <= (targetLoad * d.second->d_config.d_weight)))) {
+    if (d.second->isUp() && (weightedBalancingFactor == 0 || (static_cast<double>(d.second->outstanding.load()) <= (targetLoad * d.second->d_config.d_weight)))) {
       // Don't overflow sum when adding high weights
       if (d.second->d_config.d_weight > max - sum) {
         sum = max;
@@ -125,8 +123,8 @@ static shared_ptr<DownstreamState> valrandom(const unsigned int val, const Serve
 {
   using ValRandomType = int;
   double targetLoad = std::numeric_limits<double>::max();
-
-  if (g_weightedBalancingFactor > 0) {
+  const auto weightedBalancingFactor = dnsdist::configuration::getImmutableConfiguration().d_consistentHashBalancingFactor;
+  if (weightedBalancingFactor > 0) {
     /* we start with one, representing the query we are currently handling */
     double currentLoad = 1;
     size_t totalWeight = 0;
@@ -138,7 +136,7 @@ static shared_ptr<DownstreamState> valrandom(const unsigned int val, const Serve
     }
 
     if (totalWeight > 0) {
-      targetLoad = (currentLoad / totalWeight) * g_weightedBalancingFactor;
+      targetLoad = (currentLoad / static_cast<double>(totalWeight)) * weightedBalancingFactor;
     }
   }
 
@@ -157,9 +155,6 @@ shared_ptr<DownstreamState> wrandom(const ServerPolicy::NumberedServerVector& se
   return valrandom(dns_random_uint32(), servers);
 }
 
-uint32_t g_hashperturb;
-double g_consistentHashBalancingFactor = 0;
-
 shared_ptr<DownstreamState> whashedFromHash(const ServerPolicy::NumberedServerVector& servers, size_t hash)
 {
   return valrandom(hash, servers);
@@ -167,7 +162,8 @@ shared_ptr<DownstreamState> whashedFromHash(const ServerPolicy::NumberedServerVe
 
 shared_ptr<DownstreamState> whashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
 {
-  return whashedFromHash(servers, dq->ids.qname.hash(g_hashperturb));
+  const auto hashPerturbation = dnsdist::configuration::getImmutableConfiguration().d_hashPerturbation;
+  return whashedFromHash(servers, dq->ids.qname.hash(hashPerturbation));
 }
 
 shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVector& servers, size_t qhash)
@@ -177,7 +173,8 @@ shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVe
   shared_ptr<DownstreamState> ret = nullptr, first = nullptr;
 
   double targetLoad = std::numeric_limits<double>::max();
-  if (g_consistentHashBalancingFactor > 0) {
+  const auto consistentHashBalancingFactor = dnsdist::configuration::getImmutableConfiguration().d_consistentHashBalancingFactor;
+  if (consistentHashBalancingFactor > 0) {
     /* we start with one, representing the query we are currently handling */
     double currentLoad = 1;
     size_t totalWeight = 0;
@@ -189,12 +186,12 @@ shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVe
     }
 
     if (totalWeight > 0) {
-      targetLoad = (currentLoad / totalWeight) * g_consistentHashBalancingFactor;
+      targetLoad = (currentLoad / totalWeight) * consistentHashBalancingFactor;
     }
   }
 
   for (const auto& d: servers) {
-    if (d.second->isUp() && (g_consistentHashBalancingFactor == 0 || d.second->outstanding <= (targetLoad * d.second->d_config.d_weight))) {
+    if (d.second->isUp() && (consistentHashBalancingFactor == 0 || static_cast<double>(d.second->outstanding.load()) <= (targetLoad * d.second->d_config.d_weight))) {
       // make sure hashes have been computed
       if (!d.second->hashesComputed) {
         d.second->hash();
@@ -229,7 +226,8 @@ shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVe
 
 shared_ptr<DownstreamState> chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
 {
-  return chashedFromHash(servers, dq->ids.qname.hash(g_hashperturb));
+  const auto hashPerturbation = dnsdist::configuration::getImmutableConfiguration().d_hashPerturbation;
+  return chashedFromHash(servers, dq->ids.qname.hash(hashPerturbation));
 }
 
 shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
@@ -248,7 +246,7 @@ shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector&
   }
 
   if (candidates.empty()) {
-    if (g_roundrobinFailOnNoServer) {
+    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_roundrobinFailOnNoServer) {
       return shared_ptr<DownstreamState>();
     }
     for (auto& d : servers) {
index 78fcb22016b2cc29ea059dd354f21aa5fe8461c0..fd943b2498211ead31f94d524d45b0f1f9e88ebf 100644 (file)
@@ -110,8 +110,3 @@ std::shared_ptr<DownstreamState> whashedFromHash(const ServerPolicy::NumberedSer
 std::shared_ptr<DownstreamState> chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
 std::shared_ptr<DownstreamState> chashedFromHash(const ServerPolicy::NumberedServerVector& servers, size_t hash);
 std::shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
-
-extern double g_consistentHashBalancingFactor;
-extern double g_weightedBalancingFactor;
-extern uint32_t g_hashperturb;
-extern bool g_roundrobinFailOnNoServer;
index ebb82507a4b5658e0967e523d1ff10644e1c1698..760715ede198b08a598c7226e036dc3544b773e6 100644 (file)
@@ -33,6 +33,7 @@
 #include "dnsdist-proxy-protocol.hh"
 #include "dnsdist-kvs.hh"
 #include "dnsdist-rule-chains.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsdist-svc.hh"
 
 #include "dnstap.hh"
@@ -254,7 +255,7 @@ std::map<std::string, double> TeeAction::getStats() const
 void TeeAction::worker()
 {
   setThreadName("dnsdist/TeeWork");
-  std::array<char, s_udpIncomingBufferSize> packet{};
+  std::array<char, dnsdist::configuration::s_udpIncomingBufferSize> packet{};
   ssize_t res = 0;
   const dnsheader_aligned dnsheader(packet.data());
   for (;;) {
@@ -453,6 +454,7 @@ public:
     if (!dnsdist::svc::generateSVCResponse(*dnsquestion, d_payloads, d_additionals4, d_additionals6, d_responseConfig)) {
       return Action::None;
     }
+
     return Action::HeaderModify;
   }
 
@@ -905,7 +907,8 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dnsquestion, std::string*
 
   bool dnssecOK = false;
   bool hadEDNS = false;
-  if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) {
+  const auto& runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (runtimeConfiguration.d_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dnsquestion)) {
     hadEDNS = true;
     dnssecOK = ((getEDNSZ(*dnsquestion) & EDNS_HEADER_FLAG_DO) != 0);
   }
@@ -1008,7 +1011,7 @@ DNSAction::Action SpoofAction::operator()(DNSQuestion* dnsquestion, std::string*
   });
 
   if (hadEDNS && !raw) {
-    addEDNS(dnsquestion->getMutableData(), dnsquestion->getMaximumSize(), dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
+    addEDNS(dnsquestion->getMutableData(), dnsquestion->getMaximumSize(), dnssecOK, runtimeConfiguration.d_payloadSizeSelfGenAnswers, 0);
   }
 
   return Action::HeaderModify;
@@ -1058,7 +1061,7 @@ public:
     }
 
     auto& data = dnsquestion->getMutableData();
-    if (generateOptRR(optRData, data, dnsquestion->getMaximumSize(), g_EdnsUDPPayloadSize, 0, false)) {
+    if (generateOptRR(optRData, data, dnsquestion->getMaximumSize(), dnsdist::configuration::s_EdnsUDPPayloadSize, 0, false)) {
       dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsquestion->getMutableData(), [](dnsheader& header) {
         header.arcount = htons(1);
         return true;
@@ -1143,7 +1146,7 @@ public:
   {
     auto filepointer = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
     if (!filepointer) {
-      if (!d_verboseOnly || g_verbose) {
+      if (!d_verboseOnly || dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
         if (d_includeTimestamp) {
           infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast<unsigned long long>(dnsquestion->getQueryRealTime().tv_sec), static_cast<unsigned long>(dnsquestion->getQueryRealTime().tv_nsec), dnsquestion->ids.origRemote.toStringWithPort(), dnsquestion->ids.qname.toString(), QType(dnsquestion->ids.qtype).toString(), dnsquestion->getHeader()->id);
         }
@@ -1255,7 +1258,7 @@ public:
   {
     auto filepointer = std::atomic_load_explicit(&d_fp, std::memory_order_acquire);
     if (!filepointer) {
-      if (!d_verboseOnly || g_verbose) {
+      if (!d_verboseOnly || dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) {
         if (d_includeTimestamp) {
           infolog("[%u.%u] Answer to %s for %s %s (%s) with id %u", static_cast<unsigned long long>(response->getQueryRealTime().tv_sec), static_cast<unsigned long>(response->getQueryRealTime().tv_nsec), response->ids.origRemote.toStringWithPort(), response->ids.qname.toString(), QType(response->ids.qtype).toString(), RCode::to_s(response->getHeader()->rcode), response->getHeader()->id);
         }
@@ -1712,7 +1715,7 @@ public:
   }
   DNSAction::Action operator()(DNSQuestion* dnsquestion, std::string* ruleresult) const override
   {
-    if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+    if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
       g_snmpAgent->sendDNSTrap(*dnsquestion, d_reason);
     }
 
@@ -1919,7 +1922,7 @@ public:
   }
   DNSResponseAction::Action operator()(DNSResponse* response, std::string* ruleresult) const override
   {
-    if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+    if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
       g_snmpAgent->sendDNSTrap(*response, d_reason);
     }
 
index 9297dbccad81d75d9524170d0e86c09e3f91d87f..8889fea674588d76576234daa3cb3692fe1a941b 100644 (file)
@@ -25,6 +25,7 @@
 #include "dnsdist-ecs.hh"
 #include "dnsdist-internal-queries.hh"
 #include "dnsdist-lua.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsparser.hh"
 
 // NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
@@ -169,7 +170,7 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
 
   luaCtx.registerFunction<void (DNSQuestion::*)(std::string)>("sendTrap", [](const DNSQuestion& dnsQuestion, boost::optional<std::string> reason) {
 #ifdef HAVE_NET_SNMP
-    if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+    if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
       g_snmpAgent->sendDNSTrap(dnsQuestion, reason ? *reason : "");
     }
 #endif /* HAVE_NET_SNMP */
@@ -496,7 +497,7 @@ void setupLuaBindingsDNSQuestion(LuaContext& luaCtx)
 
   luaCtx.registerFunction<void (DNSResponse::*)(std::string)>("sendTrap", [](const DNSResponse& dnsResponse, boost::optional<std::string> reason) {
 #ifdef HAVE_NET_SNMP
-    if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+    if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
       g_snmpAgent->sendDNSTrap(dnsResponse, reason ? *reason : "");
     }
 #endif /* HAVE_NET_SNMP */
index 86cef5be2ba311b42d9e1e4d05917fdab7807e89..7681f7024870bd57ecc14b79ca1683930fd5c5f2 100644 (file)
@@ -672,7 +672,7 @@ void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
 
   luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)()>("attachToAllBinds", [](std::shared_ptr<BPFFilter>& bpf) {
     std::string res;
-    if (!g_configurationDone) {
+    if (!dnsdist::configuration::isConfigurationDone()) {
       throw std::runtime_error("attachToAllBinds() cannot be used at configuration time!");
       return;
     }
@@ -740,7 +740,7 @@ void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
 #ifdef HAVE_XSK
   using xskopt_t = LuaAssociativeTable<boost::variant<uint32_t, std::string>>;
   luaCtx.writeFunction("newXsk", [client](xskopt_t opts) {
-    if (g_configurationDone) {
+    if (dnsdist::configuration::isConfigurationDone()) {
       throw std::runtime_error("newXsk() only can be used at configuration time!");
     }
     if (client) {
index 1fb9e631af03bb4a0c638e911815e64e5fddba22..1b849cefb627508507628472c870e0b7170fc1d0 100644 (file)
@@ -32,6 +32,7 @@
 #include "dnsdist-ecs.hh"
 #include "dnsdist-rings.hh"
 #include "dnsdist-svc.hh"
+#include "dnsdist-snmp.hh"
 #include "dolog.hh"
 
 uint16_t dnsdist_ffi_dnsquestion_get_qtype(const dnsdist_ffi_dnsquestion_t* dq)
@@ -585,7 +586,7 @@ bool dnsdist_ffi_dnsquestion_set_trailing_data(dnsdist_ffi_dnsquestion_t* dq, co
 
 void dnsdist_ffi_dnsquestion_send_trap(dnsdist_ffi_dnsquestion_t* dq, const char* reason, size_t reasonLen)
 {
-  if (g_snmpAgent && g_snmpTrapsEnabled) {
+  if (g_snmpAgent != nullptr && dnsdist::configuration::getCurrentRuntimeConfiguration().d_snmpTrapsEnabled) {
     g_snmpAgent->sendDNSTrap(*dq->dq, std::string(reason, reasonLen));
   }
 }
@@ -1963,7 +1964,7 @@ size_t dnsdist_ffi_dynamic_blocks_get_entries(dnsdist_ffi_dynamic_blocks_list_t*
     if (g_defaultBPFFilter && details.bpf) {
       counter += g_defaultBPFFilter->getHits(client.getNetwork());
     }
-    list->d_entries.push_back({strdup(client.toString().c_str()), strdup(details.reason.c_str()), counter, static_cast<uint64_t>(details.until.tv_sec - now.tv_sec), static_cast<uint8_t>(details.action != DNSAction::Action::None ? details.action : g_dynBlockAction), g_defaultBPFFilter && details.bpf, details.warning});
+    list->d_entries.push_back({strdup(client.toString().c_str()), strdup(details.reason.c_str()), counter, static_cast<uint64_t>(details.until.tv_sec - now.tv_sec), static_cast<uint8_t>(details.action != DNSAction::Action::None ? details.action : dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction), g_defaultBPFFilter && details.bpf, details.warning});
   }
 
   auto count = list->d_entries.size();
@@ -1984,8 +1985,9 @@ size_t dnsdist_ffi_dynamic_blocks_smt_get_entries(dnsdist_ffi_dynamic_blocks_lis
   };
   gettime(&now);
 
+  const auto defaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
   auto fullCopy = g_dynblockSMT.getCopy();
-  fullCopy.visit([&now, &list](const SuffixMatchTree<DynBlock>& node) {
+  fullCopy.visit([&now, &list, defaultAction](const SuffixMatchTree<DynBlock>& node) {
     if (!(now < node.d_value.until)) {
       return;
     }
@@ -1995,7 +1997,7 @@ size_t dnsdist_ffi_dynamic_blocks_smt_get_entries(dnsdist_ffi_dynamic_blocks_lis
       key = entry.domain.toString();
     }
     if (entry.action == DNSAction::Action::None) {
-      entry.action = g_dynBlockAction;
+      entry.action = defaultAction;
     }
     list->d_entries.push_back({strdup(key.c_str()), strdup(entry.reason.c_str()), entry.blocks, static_cast<uint64_t>(entry.until.tv_sec - now.tv_sec), static_cast<uint8_t>(entry.action), entry.bpf, entry.warning});
   });
index d9ac137f45c69c01c69e41965e63810fac095db1..eb8440a3d8de438a67dd767440ce51120afcd4bd 100644 (file)
@@ -22,8 +22,9 @@
 #include <fcntl.h>
 
 #include "dnsdist.hh"
-#include "dnsdist-lua.hh"
+#include "dnsdist-console.hh"
 #include "dnsdist-dynblocks.hh"
+#include "dnsdist-lua.hh"
 #include "dnsdist-nghttp2.hh"
 #include "dnsdist-rings.hh"
 #include "dnsdist-tcp.hh"
@@ -533,7 +534,7 @@ void setupLuaInspection(LuaContext& luaCtx)
   luaCtx.writeFunction("delta", []() {
     setLuaNoSideEffect();
     // we hold the lua lock already!
-    for (const auto& entry : g_confDelta) {
+    for (const auto& entry : dnsdist::console::getConfigurationDelta()) {
       tm entryTime{};
       localtime_r(&entry.first.tv_sec, &entryTime);
       std::array<char, 80> date{};
@@ -719,10 +720,11 @@ void setupLuaInspection(LuaContext& luaCtx)
 
   luaCtx.writeFunction("showTCPStats", [] {
     setLuaNoSideEffect();
+    const auto& immutableConfig = dnsdist::configuration::getImmutableConfiguration();
     ostringstream ret;
     boost::format fmt("%-12d %-12d %-12d %-12d");
     ret << (fmt % "Workers" % "Max Workers" % "Queued" % "Max Queued") << endl;
-    ret << (fmt % g_tcpclientthreads->getThreadsCount() % (g_maxTCPClientThreads ? *g_maxTCPClientThreads : 0) % g_tcpclientthreads->getQueuedCount() % g_maxTCPQueuedConnections) << endl;
+    ret << (fmt % g_tcpclientthreads->getThreadsCount() % immutableConfig.d_maxTCPClientThreads % g_tcpclientthreads->getQueuedCount() % immutableConfig.d_maxTCPQueuedConnections) << endl;
     ret << endl;
 
     ret << "Frontends:" << endl;
index f139efcf0363c09570755eab3b7c27ec27f6bee7..cb7fcf9e5af3dac86ee2488d8235d30654113a84 100644 (file)
@@ -39,6 +39,7 @@
 #include "dnsdist.hh"
 #include "dnsdist-carbon.hh"
 #include "dnsdist-concurrent-connections.hh"
+#include "dnsdist-configuration.hh"
 #include "dnsdist-console.hh"
 #include "dnsdist-crypto.hh"
 #include "dnsdist-dynblocks.hh"
@@ -57,6 +58,7 @@
 #include "dnsdist-rings.hh"
 #include "dnsdist-secpoll.hh"
 #include "dnsdist-session-cache.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsdist-tcp-downstream.hh"
 #include "dnsdist-web.hh"
 
@@ -82,29 +84,28 @@ using std::thread;
 
 static boost::optional<std::vector<std::function<void(void)>>> g_launchWork = boost::none;
 
-boost::tribool g_noLuaSideEffect;
-static bool g_included{false};
+static boost::tribool s_noLuaSideEffect;
 
 /* this is a best effort way to prevent logging calls with no side-effects in the output of delta()
    Functions can declare setLuaNoSideEffect() and if nothing else does declare a side effect, or nothing
    has done so before on this invocation, this call won't be part of delta() output */
 void setLuaNoSideEffect()
 {
-  if (g_noLuaSideEffect == false) {
+  if (s_noLuaSideEffect == false) {
     // there has been a side effect already
     return;
   }
-  g_noLuaSideEffect = true;
+  s_noLuaSideEffect = true;
 }
 
 void setLuaSideEffect()
 {
-  g_noLuaSideEffect = false;
+  s_noLuaSideEffect = false;
 }
 
 bool getLuaNoSideEffect()
 {
-  if (g_noLuaSideEffect) {
+  if (s_noLuaSideEffect) {
     // NOLINTNEXTLINE(readability-simplify-boolean-expr): it's a tribool, not a boolean
     return true;
   }
@@ -113,7 +114,7 @@ bool getLuaNoSideEffect()
 
 void resetLuaSideEffect()
 {
-  g_noLuaSideEffect = boost::logic::indeterminate;
+  s_noLuaSideEffect = boost::logic::indeterminate;
 }
 
 using localbind_t = LuaAssociativeTable<boost::variant<bool, int, std::string, LuaArray<int>, LuaArray<std::string>, LuaAssociativeTable<std::string>, std::shared_ptr<XskSocket>>>;
@@ -303,7 +304,7 @@ static void LuaThread(const std::string& code)
 
 static bool checkConfigurationTime(const std::string& name)
 {
-  if (!g_configurationDone) {
+  if (!dnsdist::configuration::isConfigurationDone()) {
     return true;
   }
   g_outputBuffer = name + " cannot be used at runtime!\n";
@@ -456,7 +457,7 @@ static void handleNewServerSourceParameter(boost::optional<newserver_t>& vars, D
 static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 {
   luaCtx.writeFunction("inClientStartup", [client]() {
-    return client && !g_configurationDone;
+    return client && !dnsdist::configuration::isConfigurationDone();
   });
 
   luaCtx.writeFunction("inConfigCheck", [configCheck]() {
@@ -649,7 +650,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #ifdef HAVE_XSK
                          LuaArray<std::shared_ptr<XskSocket>> luaXskSockets;
                          if (getOptionalValue<LuaArray<std::shared_ptr<XskSocket>>>(vars, "xskSockets", luaXskSockets) > 0 && !luaXskSockets.empty()) {
-                           if (g_configurationDone) {
+                           if (dnsdist::configuration::isConfigurationDone()) {
                              throw std::runtime_error("Adding a server with xsk at runtime is not supported");
                            }
                            std::vector<std::shared_ptr<XskSocket>> xskSockets;
@@ -753,8 +754,193 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
                          server->stop();
                        });
 
-  luaCtx.writeFunction("truncateTC", [](bool value) { setLuaSideEffect(); g_truncateTC = value; });
-  luaCtx.writeFunction("fixupCase", [](bool value) { setLuaSideEffect(); g_fixupCase = value; });
+  struct BooleanConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::RuntimeConfiguration& config, bool newValue)> mutator;
+  };
+  static const std::vector<BooleanConfigurationItems> booleanConfigItems{
+    {"truncateTC", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_truncateTC = newValue; }},
+    {"fixupCase", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_fixupCase = newValue; }},
+    {"setECSOverride", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_ecsOverride = newValue; }},
+    {"setQueryCount", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_queryCountConfig.d_enabled = newValue; }},
+    {"setVerbose", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_verbose = newValue; }},
+    {"setVerboseHealthChecks", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_verboseHealthChecks = newValue; }},
+    {"setServFailWhenNoServer", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_servFailOnNoPolicy = newValue; }},
+    {"setRoundRobinFailOnNoServer", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_roundrobinFailOnNoServer = newValue; }},
+    {"setDropEmptyQueries", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_dropEmptyQueries = newValue; }},
+    {"setAllowEmptyResponse", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_allowEmptyResponse = newValue; }},
+    {"setConsoleConnectionsLogging", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_logConsoleConnections = newValue; }},
+    {"setProxyProtocolApplyACLToProxiedClients", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_applyACLToProxiedClients = newValue; }},
+    {"setAddEDNSToSelfGeneratedResponses", [](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_addEDNSToSelfGeneratedResponses = newValue; }},
+  };
+  struct UnsignedIntegerConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::RuntimeConfiguration& config, uint64_t value)> mutator;
+    const size_t maximumValue{std::numeric_limits<uint64_t>::max()};
+  };
+  static const std::vector<UnsignedIntegerConfigurationItems> unsignedIntegerConfigItems{
+    {"setCacheCleaningDelay", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_cacheCleaningDelay = newValue; }, std::numeric_limits<uint32_t>::max()},
+    {"setCacheCleaningPercentage", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_cacheCleaningPercentage = newValue; }, 100U},
+    {"setOutgoingTLSSessionsCacheMaxTicketsPerBackend", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tlsSessionCacheMaxSessionsPerBackend = newValue; }, std::numeric_limits<uint16_t>::max() },
+    {"setOutgoingTLSSessionsCacheCleanupDelay", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tlsSessionCacheCleanupDelay = newValue; }, std::numeric_limits<uint16_t>::max() },
+    {"setOutgoingTLSSessionsCacheMaxTicketValidity", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tlsSessionCacheSessionValidity = newValue; }, std::numeric_limits<uint16_t>::max() },
+    {"setECSSourcePrefixV4", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_ECSSourcePrefixV4 = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setECSSourcePrefixV6", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_ECSSourcePrefixV6 = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setTCPRecvTimeout", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tcpRecvTimeout = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setTCPSendTimeout", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_tcpSendTimeout = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setMaxTCPQueriesPerConnection", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_maxTCPQueriesPerConn = newValue; }, std::numeric_limits<uint64_t>::max()},
+    {"setMaxTCPConnectionDuration", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_maxTCPConnectionDuration = newValue; }, std::numeric_limits<uint32_t>::max()},
+    {"setStaleCacheEntriesTTL", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_staleCacheEntriesTTL = newValue; }, std::numeric_limits<uint32_t>::max()},
+    {"setConsoleOutputMaxMsgSize", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_consoleOutputMsgMaxSize = newValue; }, std::numeric_limits<uint32_t>::max()},
+#ifndef DISABLE_SECPOLL
+    {"setSecurityPollInterval", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_secPollInterval = newValue; }, std::numeric_limits<uint32_t>::max()},
+#endif /* DISABLE_SECPOLL */
+    {"setProxyProtocolMaximumPayloadSize", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) { config.d_proxyProtocolMaximumSize = std::max(static_cast<uint64_t>(16), newValue); }, std::numeric_limits<uint32_t>::max()},
+    {"setPayloadSizeOnSelfGeneratedAnswers", [](dnsdist::configuration::RuntimeConfiguration& config, uint64_t newValue) {
+       if (newValue < 512) {
+         warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!");
+         g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!";
+         newValue = 512;
+       }
+       if (newValue > dnsdist::configuration::s_udpIncomingBufferSize) {
+         warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to %d instead!", dnsdist::configuration::s_udpIncomingBufferSize);
+         g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to " + std::to_string(dnsdist::configuration::s_udpIncomingBufferSize) + " instead";
+         newValue = dnsdist::configuration::s_udpIncomingBufferSize;
+       }
+       config.d_payloadSizeSelfGenAnswers = newValue;
+     },
+     std::numeric_limits<uint64_t>::max()},
+  };
+
+  struct StringConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::RuntimeConfiguration& config, const std::string& value)> mutator;
+  };
+  static const std::vector<StringConfigurationItems> stringConfigItems{
+#ifndef DISABLE_SECPOLL
+    {"setSecurityPollSuffix", [](dnsdist::configuration::RuntimeConfiguration& config, const std::string& newValue) { config.d_secPollSuffix = newValue; }},
+#endif /* DISABLE_SECPOLL */
+  };
+
+  for (const auto& item : booleanConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](bool value) {
+      setLuaSideEffect();
+      dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+        item.mutator(config, value);
+      });
+    });
+  }
+
+  for (const auto& item : unsignedIntegerConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](uint64_t value) {
+      setLuaSideEffect();
+      checkParameterBound(item.name, value, item.maximumValue);
+      dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+        item.mutator(config, value);
+      });
+    });
+  }
+
+  for (const auto& item : stringConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](const std::string& value) {
+      setLuaSideEffect();
+      dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+        item.mutator(config, value);
+      });
+    });
+  }
+
+  struct BooleanImmutableConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::Configuration& config, bool newValue)> mutator;
+  };
+  static const std::vector<BooleanImmutableConfigurationItems> booleanImmutableConfigItems{
+    {"setRandomizedOutgoingSockets", [](dnsdist::configuration::Configuration& config, bool newValue) { config.d_randomizeUDPSocketsToBackend = newValue; }},
+    {"setRandomizedIdsOverUDP", [](dnsdist::configuration::Configuration& config, bool newValue) { config.d_randomizeIDsToBackend = newValue; }},
+  };
+  struct UnsignedIntegerImmutableConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::Configuration& config, uint64_t value)> mutator;
+    const size_t maximumValue{std::numeric_limits<uint64_t>::max()};
+  };
+  static const std::vector<UnsignedIntegerImmutableConfigurationItems> unsignedIntegerImmutableConfigItems{
+    {"setMaxTCPQueuedConnections", [](dnsdist::configuration::Configuration& config, uint64_t newValue) { config.d_maxTCPQueuedConnections = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setMaxTCPClientThreads", [](dnsdist::configuration::Configuration& config, uint64_t newValue) { config.d_maxTCPClientThreads = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setMaxTCPConnectionsPerClient", [](dnsdist::configuration::Configuration& config, uint64_t newValue) { config.d_maxTCPConnectionsPerClient = newValue; }, std::numeric_limits<uint64_t>::max()},
+    {"setTCPInternalPipeBufferSize", [](dnsdist::configuration::Configuration& config, uint64_t newValue) { config.d_tcpInternalPipeBufferSize = newValue; }, std::numeric_limits<uint64_t>::max()},
+    {"setMaxUDPOutstanding", [](dnsdist::configuration::Configuration& config, uint64_t newValue) { config.d_maxUDPOutstanding = newValue; }, std::numeric_limits<uint16_t>::max()},
+    {"setWHashedPertubation", [](dnsdist::configuration::Configuration& config, uint64_t newValue) { config.d_hashPerturbation = newValue; }, std::numeric_limits<uint32_t>::max()},
+#ifndef DISABLE_RECVMMSG
+    {"setUDPMultipleMessagesVectorSize", [](dnsdist::configuration::Configuration& config, uint64_t newValue) { config.d_udpVectorSize = newValue; }, std::numeric_limits<uint32_t>::max()},
+#endif /* DISABLE_RECVMMSG */
+    {"setUDPTimeout", [](dnsdist::configuration::Configuration& config, uint64_t newValue) { config.d_udpTimeout = newValue; }, std::numeric_limits<uint8_t>::max()},
+  };
+  struct DoubleImmutableConfigurationItems
+  {
+    const std::string name;
+    const std::function<void(dnsdist::configuration::Configuration& config, double value)> mutator;
+    const double maximumValue{1.0};
+  };
+  static const std::vector<DoubleImmutableConfigurationItems> doubleImmutableConfigItems{
+    {"setConsistentHashingBalancingFactor", [](dnsdist::configuration::Configuration& config, double newValue) { config.d_consistentHashBalancingFactor = newValue; }, 1.0},
+    {"setWeightedBalancingFactor", [](dnsdist::configuration::Configuration& config, double newValue) { config.d_weightedBalancingFactor = newValue; }, 1.0},
+  };
+
+  for (const auto& item : booleanConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](bool value) {
+      try {
+        dnsdist::configuration::updateRuntimeConfiguration([value, &item](dnsdist::configuration::RuntimeConfiguration& config) {
+          item.mutator(config, value);
+        });
+      }
+      catch (const std::exception& exp) {
+        g_outputBuffer = item.name + " cannot be used at runtime!\n";
+        errlog("%s cannot be used at runtime!", item.name);
+      }
+    });
+  }
+
+  for (const auto& item : unsignedIntegerImmutableConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](uint64_t value) {
+      checkParameterBound(item.name, value, item.maximumValue);
+      try {
+        dnsdist::configuration::updateImmutableConfiguration([value, &item](dnsdist::configuration::Configuration& config) {
+          item.mutator(config, value);
+        });
+      }
+      catch (const std::exception& exp) {
+        g_outputBuffer = item.name + " cannot be used at runtime!\n";
+        errlog("%s cannot be used at runtime!", item.name);
+      }
+    });
+  }
+  for (const auto& item : doubleImmutableConfigItems) {
+    luaCtx.writeFunction(item.name, [&item](double value) {
+      if (value > item.maximumValue) {
+        g_outputBuffer = "Invalid value passed to " + item.name + "()!\n";
+        errlog("Invalid value passed to %s()!", item.name);
+        return;
+      }
+
+      try {
+        dnsdist::configuration::updateImmutableConfiguration([value, &item](dnsdist::configuration::Configuration& config) {
+          item.mutator(config, value);
+        });
+      }
+      catch (const std::exception& exp) {
+        g_outputBuffer = item.name + " cannot be used at runtime!\n";
+        errlog("%s cannot be used at runtime!", item.name);
+      }
+      setLuaSideEffect();
+    });
+  }
+
+  luaCtx.writeFunction("getVerbose", []() { return dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose; });
 
   luaCtx.writeFunction("addACL", [](const std::string& domain) {
     setLuaSideEffect();
@@ -1196,9 +1382,11 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       return;
     }
 
-    g_consoleEnabled = true;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_consoleEnabled = true;
+    });
 #if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
-    if (g_configurationDone && g_consoleKey.empty()) {
+    if (dnsdist::configuration::isConfigurationDone() && dnsdist::configuration::getImmutableConfiguration().d_consoleKey.empty()) {
       warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set");
     }
 #endif
@@ -1230,7 +1418,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     warnlog("Allowing remote access to the console while neither libsodium not libcrypto support has been enabled is not secure, and will result in cleartext communications");
 #endif
 
-    g_consoleACL.modify([netmask](NetmaskGroup& nmg) { nmg.addMask(netmask); });
+    dnsdist::configuration::updateRuntimeConfiguration([&netmask](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_consoleACL.addMask(netmask);
+    });
   });
 
   luaCtx.writeFunction("setConsoleACL", [](LuaTypeOrArrayOf<std::string> inp) {
@@ -1249,7 +1439,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         nmg.addMask(entry.second);
       }
     }
-    g_consoleACL.setState(nmg);
+    dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_consoleACL = std::move(nmg);
+    });
   });
 
   luaCtx.writeFunction("showConsoleACL", []() {
@@ -1259,7 +1451,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     warnlog("Allowing remote access to the console while neither libsodium nor libcrypto support has not been enabled is not secure, and will result in cleartext communications");
 #endif
 
-    auto aclEntries = g_consoleACL.getLocal()->toStringVector();
+    auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleACL.toStringVector();
 
     for (const auto& entry : aclEntries) {
       g_outputBuffer += entry + "\n";
@@ -1274,7 +1466,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
   luaCtx.writeFunction("clearQueryCounters", []() {
     unsigned int size{0};
     {
-      auto records = g_qcount.records.write_lock();
+      auto records = dnsdist::QueryCount::g_queryCountRecords.write_lock();
       size = records->size();
       records->clear();
     }
@@ -1285,9 +1477,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
   luaCtx.writeFunction("getQueryCounters", [](boost::optional<uint64_t> optMax) {
     setLuaNoSideEffect();
-    auto records = g_qcount.records.read_lock();
+    auto records = dnsdist::QueryCount::g_queryCountRecords.read_lock();
     g_outputBuffer = "query counting is currently: ";
-    g_outputBuffer += g_qcount.enabled ? "enabled" : "disabled";
+    g_outputBuffer += dnsdist::configuration::getCurrentRuntimeConfiguration().d_queryCountConfig.d_enabled ? "enabled" : "disabled";
     g_outputBuffer += (boost::format(" (%d records in buffer)\n") % records->size()).str();
 
     boost::format fmt("%-3d %s: %d request(s)\n");
@@ -1298,10 +1490,10 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     }
   });
 
-  luaCtx.writeFunction("setQueryCount", [](bool enabled) { g_qcount.enabled = enabled; });
-
-  luaCtx.writeFunction("setQueryCountFilter", [](QueryCountFilter func) {
-    g_qcount.filter = std::move(func);
+  luaCtx.writeFunction("setQueryCountFilter", [](dnsdist::QueryCount::Configuration::Filter func) {
+    dnsdist::configuration::updateRuntimeConfiguration([&func](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_queryCountConfig.d_filter = std::move(func);
+    });
   });
 
   luaCtx.writeFunction("makeKey", []() {
@@ -1310,7 +1502,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
   });
 
   luaCtx.writeFunction("setKey", [](const std::string& key) {
-    if (!g_configurationDone && !g_consoleKey.empty()) { // this makes sure the commandline -k key prevails over dnsdist.conf
+    if (!dnsdist::configuration::isConfigurationDone() && !dnsdist::configuration::getImmutableConfiguration().d_consoleKey.empty()) { // this makes sure the commandline -k key prevails over dnsdist.conf
       return; // but later setKeys() trump the -k value again
     }
 #if !defined(HAVE_LIBSODIUM) && !defined(HAVE_LIBCRYPTO)
@@ -1318,14 +1510,16 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #endif
 
     setLuaSideEffect();
-    string newkey;
-    if (B64Decode(key, newkey) < 0) {
+    string newKey;
+    if (B64Decode(key, newKey) < 0) {
       g_outputBuffer = string("Unable to decode ") + key + " as Base64";
       errlog("%s", g_outputBuffer);
+      return;
     }
-    else {
-      g_consoleKey = std::move(newkey);
-    }
+
+    dnsdist::configuration::updateImmutableConfiguration([&newKey](dnsdist::configuration::Configuration& config) {
+      config.d_consoleKey = std::move(newKey);
+    });
   });
 
   luaCtx.writeFunction("clearConsoleHistory", []() {
@@ -1336,6 +1530,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     setLuaNoSideEffect();
 #if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
     try {
+      const auto& consoleKey = dnsdist::configuration::getImmutableConfiguration().d_consoleKey;
       string testmsg;
 
       if (optTestMsg) {
@@ -1349,14 +1544,14 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       dnsdist::crypto::authenticated::Nonce nonce2;
       nonce1.init();
       nonce2 = nonce1;
-      string encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, g_consoleKey, nonce1);
-      string decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, g_consoleKey, nonce2);
+      string encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, consoleKey, nonce1);
+      string decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, consoleKey, nonce2);
 
       nonce1.increment();
       nonce2.increment();
 
-      encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, g_consoleKey, nonce1);
-      decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, g_consoleKey, nonce2);
+      encrypted = dnsdist::crypto::authenticated::encryptSym(testmsg, consoleKey, nonce1);
+      decrypted = dnsdist::crypto::authenticated::decryptSym(encrypted, consoleKey, nonce2);
 
       if (testmsg == decrypted) {
         g_outputBuffer = "Everything is ok!\n";
@@ -1376,56 +1571,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 #endif
   });
 
-  luaCtx.writeFunction("setTCPRecvTimeout", [](int timeout) { g_tcpRecvTimeout = timeout; });
-
-  luaCtx.writeFunction("setTCPSendTimeout", [](int timeout) { g_tcpSendTimeout = timeout; });
-
-  luaCtx.writeFunction("setUDPTimeout", [](int timeout) { DownstreamState::s_udpTimeout = timeout; });
-
-  luaCtx.writeFunction("setMaxUDPOutstanding", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxUDPOutstanding")) {
-      return;
-    }
-
-    checkParameterBound("setMaxUDPOutstanding", max);
-    g_maxOutstanding = max;
-  });
-
-  luaCtx.writeFunction("setMaxTCPClientThreads", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxTCPClientThreads")) {
-      return;
-    }
-    g_maxTCPClientThreads = max;
-  });
-
-  luaCtx.writeFunction("setMaxTCPQueuedConnections", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxTCPQueuedConnections")) {
-      return;
-    }
-    g_maxTCPQueuedConnections = max;
-  });
-
-  luaCtx.writeFunction("setMaxTCPQueriesPerConnection", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxTCPQueriesPerConnection")) {
-      return;
-    }
-    g_maxTCPQueriesPerConn = max;
-  });
-
-  luaCtx.writeFunction("setMaxTCPConnectionsPerClient", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxTCPConnectionsPerClient")) {
-      return;
-    }
-    dnsdist::IncomingConcurrentTCPConnectionsManager::setMaxTCPConnectionsPerClient(max);
-  });
-
-  luaCtx.writeFunction("setMaxTCPConnectionDuration", [](uint64_t max) {
-    if (!checkConfigurationTime("setMaxTCPConnectionDuration")) {
-      return;
-    }
-    g_maxTCPConnectionDuration = max;
-  });
-
   luaCtx.writeFunction("setMaxCachedTCPConnectionsPerDownstream", [](uint64_t max) {
     setTCPDownstreamMaxIdleConnectionsPerBackend(max);
   });
@@ -1443,61 +1588,15 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
   });
 #endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
 
-  luaCtx.writeFunction("setOutgoingTLSSessionsCacheMaxTicketsPerBackend", [](uint64_t max) {
-    if (!checkConfigurationTime("setOutgoingTLSSessionsCacheMaxTicketsPerBackend")) {
-      return;
-    }
-    TLSSessionCache::setMaxTicketsPerBackend(max);
-  });
-
-  luaCtx.writeFunction("setOutgoingTLSSessionsCacheCleanupDelay", [](time_t delay) {
-    if (!checkConfigurationTime("setOutgoingTLSSessionsCacheCleanupDelay")) {
-      return;
-    }
-    TLSSessionCache::setCleanupDelay(delay);
-  });
-
-  luaCtx.writeFunction("setOutgoingTLSSessionsCacheMaxTicketValidity", [](time_t validity) {
-    if (!checkConfigurationTime("setOutgoingTLSSessionsCacheMaxTicketValidity")) {
-      return;
-    }
-    TLSSessionCache::setSessionValidity(validity);
-  });
-
   luaCtx.writeFunction("getOutgoingTLSSessionCacheSize", []() {
     setLuaNoSideEffect();
     return g_sessionCache.getSize();
   });
 
-  luaCtx.writeFunction("setCacheCleaningDelay", [](uint64_t delay) {
-    checkParameterBound("setCacheCleaningDelay", delay, std::numeric_limits<uint32_t>::max());
-    g_cacheCleaningDelay = delay;
-  });
-
-  luaCtx.writeFunction("setCacheCleaningPercentage", [](uint64_t percentage) {
-    if (percentage < 100) {
-      g_cacheCleaningPercentage = percentage;
-    }
-    else {
-      g_cacheCleaningPercentage = 100;
-    }
-  });
-
-  luaCtx.writeFunction("setECSSourcePrefixV4", [](uint64_t prefix) {
-    checkParameterBound("setECSSourcePrefixV4", prefix, std::numeric_limits<uint16_t>::max());
-    g_ECSSourcePrefixV4 = prefix;
-  });
-
-  luaCtx.writeFunction("setECSSourcePrefixV6", [](uint64_t prefix) {
-    checkParameterBound("setECSSourcePrefixV6", prefix, std::numeric_limits<uint16_t>::max());
-    g_ECSSourcePrefixV6 = prefix;
-  });
-
-  luaCtx.writeFunction("setECSOverride", [](bool override) { g_ECSOverride = override; });
-
 #ifndef DISABLE_DYNBLOCKS
   luaCtx.writeFunction("showDynBlocks", []() {
     setLuaNoSideEffect();
+    const auto runtimeConf = dnsdist::configuration::getCurrentRuntimeConfiguration();
     auto slow = g_dynblockNMG.getCopy();
     timespec now{};
     gettime(&now);
@@ -1509,17 +1608,17 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         if (g_defaultBPFFilter && entry.second.bpf) {
           counter += g_defaultBPFFilter->getHits(entry.first.getNetwork());
         }
-        g_outputBuffer += (fmt % entry.first.toString() % (entry.second.until.tv_sec - now.tv_sec) % counter % (entry.second.warning ? "true" : "false") % DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : g_dynBlockAction) % (g_defaultBPFFilter && entry.second.bpf ? "*" : "") % entry.second.reason).str();
+        g_outputBuffer += (fmt % entry.first.toString() % (entry.second.until.tv_sec - now.tv_sec) % counter % (entry.second.warning ? "true" : "false") % DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : runtimeConf.d_dynBlockAction) % (g_defaultBPFFilter && entry.second.bpf ? "*" : "") % entry.second.reason).str();
       }
     }
     auto slow2 = g_dynblockSMT.getCopy();
-    slow2.visit([&now, &fmt](const SuffixMatchTree<DynBlock>& node) {
+    slow2.visit([&now, &fmt, &runtimeConf](const SuffixMatchTree<DynBlock>& node) {
       if (now < node.d_value.until) {
         string dom("empty");
         if (!node.d_value.domain.empty()) {
           dom = node.d_value.domain.toString();
         }
-        g_outputBuffer += (fmt % dom % (node.d_value.until.tv_sec - now.tv_sec) % node.d_value.blocks % (node.d_value.warning ? "true" : "false") % DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : g_dynBlockAction) % "" % node.d_value.reason).str();
+        g_outputBuffer += (fmt % dom % (node.d_value.until.tv_sec - now.tv_sec) % node.d_value.blocks % (node.d_value.warning ? "true" : "false") % DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : runtimeConf.d_dynBlockAction) % "" % node.d_value.reason).str();
       }
     });
   });
@@ -1530,6 +1629,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     gettime(&now);
 
     LuaAssociativeTable<DynBlock> entries;
+    const auto defaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
     auto fullCopy = g_dynblockNMG.getCopy();
     for (const auto& blockPair : fullCopy) {
       const auto& requestor = blockPair.first;
@@ -1541,7 +1641,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         entry.blocks += g_defaultBPFFilter->getHits(requestor.getNetwork());
       }
       if (entry.action == DNSAction::Action::None) {
-        entry.action = g_dynBlockAction;
+        entry.action = defaultAction;
       }
       entries.emplace(requestor.toString(), std::move(entry));
     }
@@ -1554,8 +1654,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     gettime(&now);
 
     LuaAssociativeTable<DynBlock> entries;
+    const auto defaultAction = dnsdist::configuration::getCurrentRuntimeConfiguration().d_dynBlockAction;
     auto fullCopy = g_dynblockSMT.getCopy();
-    fullCopy.visit([&now, &entries](const SuffixMatchTree<DynBlock>& node) {
+    fullCopy.visit([&now, &entries, defaultAction](const SuffixMatchTree<DynBlock>& node) {
       if (!(now < node.d_value.until)) {
         return;
       }
@@ -1565,7 +1666,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         key = entry.domain.toString();
       }
       if (entry.action == DNSAction::Action::None) {
-        entry.action = g_dynBlockAction;
+        entry.action = defaultAction;
       }
       entries.emplace(std::move(key), std::move(entry));
     });
@@ -1623,11 +1724,10 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
                        });
 
   luaCtx.writeFunction("setDynBlocksAction", [](DNSAction::Action action) {
-    if (!checkConfigurationTime("setDynBlocksAction")) {
-      return;
-    }
     if (action == DNSAction::Action::Drop || action == DNSAction::Action::NoOp || action == DNSAction::Action::Nxdomain || action == DNSAction::Action::Refused || action == DNSAction::Action::Truncate || action == DNSAction::Action::NoRecurse) {
-      g_dynBlockAction = action;
+      dnsdist::configuration::updateRuntimeConfiguration([action](dnsdist::configuration::RuntimeConfiguration& config) {
+        config.d_dynBlockAction = action;
+      });
     }
     else {
       errlog("Dynamic blocks action can only be Drop, NoOp, NXDomain, Refused, Truncate or NoRecurse!");
@@ -1813,9 +1913,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     return pool;
   });
 
-  luaCtx.writeFunction("setVerbose", [](bool verbose) { g_verbose = verbose; });
-  luaCtx.writeFunction("getVerbose", []() { return g_verbose; });
-  luaCtx.writeFunction("setVerboseHealthChecks", [](bool verbose) { g_verboseHealthChecks = verbose; });
   luaCtx.writeFunction("setVerboseLogDestination", [](const std::string& dest) {
     if (!checkConfigurationTime("setVerboseLogDestination")) {
       return;
@@ -1850,11 +1947,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     dnsdist::logging::LoggingConfiguration::setStructuredLogging(enable, levelPrefix);
   });
 
-  luaCtx.writeFunction("setStaleCacheEntriesTTL", [](uint64_t ttl) {
-    checkParameterBound("setStaleCacheEntriesTTL", ttl, std::numeric_limits<uint32_t>::max());
-    g_staleCacheEntriesTTL = ttl;
-  });
-
   luaCtx.writeFunction("showBinds", []() {
     setLuaNoSideEffect();
     try {
@@ -1981,7 +2073,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     if (!checkConfigurationTime("includeDirectory")) {
       return;
     }
-    if (g_included) {
+    static bool s_included{false};
+
+    if (s_included) {
       errlog("includeDirectory() cannot be used recursively!");
       g_outputBuffer = "includeDirectory() cannot be used recursively!\n";
       return;
@@ -2028,7 +2122,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
 
     std::sort(files.begin(), files.end());
 
-    g_included = true;
+    s_included = true;
 
     for (const auto& file : files) {
       std::ifstream ifs(file);
@@ -2043,62 +2137,29 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         luaCtx.executeCode(ifs);
       }
       catch (...) {
-        g_included = false;
+        s_included = false;
         throw;
       }
 
       luaCtx.executeCode(ifs);
     }
 
-    g_included = false;
+    s_included = false;
   });
 
   luaCtx.writeFunction("setAPIWritable", [](bool writable, boost::optional<std::string> apiConfigDir) {
-    setLuaSideEffect();
-    g_apiReadWrite = writable;
-    if (apiConfigDir) {
-      if (!(*apiConfigDir).empty()) {
-        g_apiConfigDirectory = *apiConfigDir;
-      }
-      else {
-        errlog("The API configuration directory value cannot be empty!");
-        g_outputBuffer = "The API configuration directory value cannot be empty!";
-      }
-    }
-  });
-
-  luaCtx.writeFunction("setServFailWhenNoServer", [](bool servfail) {
-    setLuaSideEffect();
-    g_servFailOnNoPolicy = servfail;
-  });
-
-  luaCtx.writeFunction("setRoundRobinFailOnNoServer", [](bool fail) {
-    setLuaSideEffect();
-    g_roundrobinFailOnNoServer = fail;
-  });
-
-  luaCtx.writeFunction("setConsistentHashingBalancingFactor", [](double factor) {
-    setLuaSideEffect();
-    if (factor >= 1.0) {
-      g_consistentHashBalancingFactor = factor;
-    }
-    else {
-      errlog("Invalid value passed to setConsistentHashingBalancingFactor()!");
-      g_outputBuffer = "Invalid value passed to setConsistentHashingBalancingFactor()!\n";
+    if (apiConfigDir && (*apiConfigDir).empty()) {
+      errlog("The API configuration directory value cannot be empty!");
+      g_outputBuffer = "The API configuration directory value cannot be empty!";
       return;
     }
-  });
-
-  luaCtx.writeFunction("setWeightedBalancingFactor", [](double factor) {
+    dnsdist::configuration::updateRuntimeConfiguration([writable, &apiConfigDir](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_apiReadWrite = writable;
+      if (!(*apiConfigDir).empty()) {
+        config.d_apiConfigDirectory = *apiConfigDir;
+      }
+    });
     setLuaSideEffect();
-    if (factor >= 1.0) {
-      g_weightedBalancingFactor = factor;
-    }
-    else {
-      errlog("Invalid value passed to setWeightedBalancingFactor()!");
-      g_outputBuffer = "Invalid value passed to setWeightedBalancingFactor()!\n";
-      return;
-    }
   });
 
   luaCtx.writeFunction("setRingBuffersSize", [client](uint64_t capacity, boost::optional<uint64_t> numberOfShards) {
@@ -2138,13 +2199,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     }
   });
 
-  luaCtx.writeFunction("setWHashedPertubation", [](uint64_t perturb) {
-    setLuaSideEffect();
-    checkParameterBound("setWHashedPertubation", perturb, std::numeric_limits<uint32_t>::max());
-    g_hashperturb = perturb;
-  });
-
-  luaCtx.writeFunction("setTCPInternalPipeBufferSize", [](uint64_t size) { g_tcpInternalPipeBufferSize = size; });
   luaCtx.writeFunction("setTCPFastOpenKey", [](const std::string& keyString) {
     setLuaSideEffect();
     std::array<uint32_t, 4> key{};
@@ -2168,19 +2222,27 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     if (!checkConfigurationTime("snmpAgent")) {
       return;
     }
-    if (g_snmpEnabled) {
-      errlog("snmpAgent() cannot be used twice!");
-      g_outputBuffer = "snmpAgent() cannot be used twice!\n";
-      return;
+
+    {
+      const auto runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+      if (runtimeConfiguration.d_snmpEnabled) {
+        errlog("snmpAgent() cannot be used twice!");
+        g_outputBuffer = "snmpAgent() cannot be used twice!\n";
+        return;
+      }
     }
 
-    g_snmpEnabled = true;
-    g_snmpTrapsEnabled = enableTraps;
+    dnsdist::configuration::updateRuntimeConfiguration([enableTraps](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_snmpEnabled = true;
+      config.d_snmpTrapsEnabled = enableTraps;
+    });
+
     g_snmpAgent = std::make_unique<DNSDistSNMPAgent>("dnsdist", daemonSocket ? *daemonSocket : std::string());
   });
 
   luaCtx.writeFunction("sendCustomTrap", [](const std::string& str) {
-    if (g_snmpAgent != nullptr && g_snmpTrapsEnabled) {
+    const auto runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+    if (g_snmpAgent != nullptr && runtimeConfiguration.d_snmpTrapsEnabled) {
       g_snmpAgent->sendCustomTrap(str);
     }
   });
@@ -2283,15 +2345,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
   });
 #endif /* HAVE_DNS_OVER_HTTPS && HAVE_NGHTTP2 */
 
-  luaCtx.writeFunction("setConsoleConnectionsLogging", [](bool enabled) {
-    g_logConsoleConnections = enabled;
-  });
-
-  luaCtx.writeFunction("setConsoleOutputMaxMsgSize", [](uint64_t size) {
-    checkParameterBound("setConsoleOutputMaxMsgSize", size, std::numeric_limits<uint32_t>::max());
-    g_consoleOutputMsgMaxSize = size;
-  });
-
   luaCtx.writeFunction("setProxyProtocolACL", [](LuaTypeOrArrayOf<std::string> inp) {
     if (!checkConfigurationTime("setProxyProtocolACL")) {
       return;
@@ -2306,56 +2359,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         nmg.addMask(entry.second);
       }
     }
-    g_proxyProtocolACL = std::move(nmg);
-  });
-
-  luaCtx.writeFunction("setProxyProtocolApplyACLToProxiedClients", [](bool apply) {
-    if (!checkConfigurationTime("setProxyProtocolApplyACLToProxiedClients")) {
-      return;
-    }
-    setLuaSideEffect();
-    g_applyACLToProxiedClients = apply;
-  });
-
-  luaCtx.writeFunction("setProxyProtocolMaximumPayloadSize", [](uint64_t size) {
-    if (!checkConfigurationTime("setProxyProtocolMaximumPayloadSize")) {
-      return;
-    }
-    setLuaSideEffect();
-    g_proxyProtocolMaximumSize = std::max(static_cast<uint64_t>(16), size);
-  });
-
-#ifndef DISABLE_RECVMMSG
-  luaCtx.writeFunction("setUDPMultipleMessagesVectorSize", [](uint64_t vSize) {
-    if (!checkConfigurationTime("setUDPMultipleMessagesVectorSize")) {
-      return;
-    }
-#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
-    setLuaSideEffect();
-    g_udpVectorSize = vSize;
-#else
-      errlog("recvmmsg() support is not available!");
-      g_outputBuffer = "recvmmsg support is not available!\n";
-#endif
-  });
-#endif /* DISABLE_RECVMMSG */
-
-  luaCtx.writeFunction("setAddEDNSToSelfGeneratedResponses", [](bool add) {
-    g_addEDNSToSelfGeneratedResponses = add;
-  });
-
-  luaCtx.writeFunction("setPayloadSizeOnSelfGeneratedAnswers", [](uint64_t payloadSize) {
-    if (payloadSize < 512) {
-      warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!");
-      g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too low, using 512 instead!";
-      payloadSize = 512;
-    }
-    if (payloadSize > s_udpIncomingBufferSize) {
-      warnlog("setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to %d instead!", s_udpIncomingBufferSize);
-      g_outputBuffer = "setPayloadSizeOnSelfGeneratedAnswers() is set too high, capping to " + std::to_string(s_udpIncomingBufferSize) + " instead";
-      payloadSize = s_udpIncomingBufferSize;
-    }
-    g_PayloadSizeSelfGenAnswers = payloadSize;
+    dnsdist::configuration::updateRuntimeConfiguration([&nmg](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_proxyProtocolACL = std::move(nmg);
+    });
   });
 
 #ifndef DISABLE_SECPOLL
@@ -2363,22 +2369,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     setLuaNoSideEffect();
     g_outputBuffer = std::to_string(dnsdist::metrics::g_stats.securityStatus) + "\n";
   });
-
-  luaCtx.writeFunction("setSecurityPollSuffix", [](const std::string& suffix) {
-    if (!checkConfigurationTime("setSecurityPollSuffix")) {
-      return;
-    }
-    g_secPollSuffix = suffix;
-  });
-
-  luaCtx.writeFunction("setSecurityPollInterval", [](time_t newInterval) {
-    if (newInterval <= 0) {
-      warnlog("setSecurityPollInterval() should be > 0, skipping");
-      g_outputBuffer = "setSecurityPollInterval() should be > 0, skipping";
-    }
-
-    g_secPollInterval = newInterval;
-  });
 #endif /* DISABLE_SECPOLL */
 
   luaCtx.writeFunction("setSyslogFacility", [](boost::variant<int, std::string> facility) {
@@ -3296,9 +3286,6 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     }
   });
 
-  luaCtx.writeFunction("setAllowEmptyResponse", [](bool allow) { g_allowEmptyResponse = allow; });
-  luaCtx.writeFunction("setDropEmptyQueries", [](bool drop) { extern bool g_dropEmptyQueries; g_dropEmptyQueries = drop; });
-
 #if defined(HAVE_LIBSSL) && defined(HAVE_OCSP_BASIC_SIGN) && !defined(DISABLE_OCSP_STAPLING)
   luaCtx.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) {
@@ -3328,23 +3315,20 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     if (client) {
       return;
     }
-    if (!checkConfigurationTime("setUDPSocketBufferSizes")) {
-      return;
-    }
     checkParameterBound("setUDPSocketBufferSizes", recv, std::numeric_limits<uint32_t>::max());
     checkParameterBound("setUDPSocketBufferSizes", snd, std::numeric_limits<uint32_t>::max());
-    setLuaSideEffect();
-
-    g_socketUDPSendBuffer = snd;
-    g_socketUDPRecvBuffer = recv;
-  });
 
-  luaCtx.writeFunction("setRandomizedOutgoingSockets", [](bool randomized) {
-    DownstreamState::s_randomizeSockets = randomized;
-  });
-
-  luaCtx.writeFunction("setRandomizedIdsOverUDP", [](bool randomized) {
-    DownstreamState::s_randomizeIDs = randomized;
+    try {
+      dnsdist::configuration::updateImmutableConfiguration([snd, recv](dnsdist::configuration::Configuration& config) {
+        config.d_socketUDPSendBuffer = snd;
+        config.d_socketUDPRecvBuffer = recv;
+      });
+      setLuaSideEffect();
+    }
+    catch (const std::exception& exp) {
+      g_outputBuffer = "setUDPSocketBufferSizes cannot be used at runtime!\n";
+      errlog("setUDPSocketBufferSizes cannot be used at runtime!");
+    }
   });
 
 #if defined(HAVE_LIBSSL) && !defined(HAVE_TLS_PROVIDERS)
index 797def327e56104f3febed829418aa9703dbcc88..089deb52ea58b3981159caa4327ed95d471a4637 100644 (file)
@@ -362,7 +362,8 @@ void IncomingHTTP2Connection::handleIO()
   gettimeofday(&now, nullptr);
 
   try {
-    if (maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
+    const auto& currentConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+    if (maxConnectionDurationReached(currentConfig.d_maxTCPConnectionDuration, now)) {
       vinfolog("Terminating DoH connection from %s because it reached the maximum TCP connection duration", d_ci.remote.toStringWithPort());
       stopIO();
       d_connectionClosing = true;
@@ -1154,17 +1155,18 @@ uint32_t IncomingHTTP2Connection::getConcurrentStreamsCount() const
 
 boost::optional<struct timeval> IncomingHTTP2Connection::getIdleClientReadTTD(struct timeval now) const
 {
+  const auto& currentConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
   auto idleTimeout = d_ci.cs->dohFrontend->d_idleTimeout;
-  if (g_maxTCPConnectionDuration == 0 && idleTimeout == 0) {
+  if (currentConfig.d_maxTCPConnectionDuration == 0 && idleTimeout == 0) {
     return boost::none;
   }
 
-  if (g_maxTCPConnectionDuration > 0) {
+  if (currentConfig.d_maxTCPConnectionDuration > 0) {
     auto elapsed = now.tv_sec - d_connectionStartTime.tv_sec;
-    if (elapsed < 0 || (static_cast<size_t>(elapsed) >= g_maxTCPConnectionDuration)) {
+    if (elapsed < 0 || (static_cast<size_t>(elapsed) >= currentConfig.d_maxTCPConnectionDuration)) {
       return now;
     }
-    auto remaining = g_maxTCPConnectionDuration - elapsed;
+    auto remaining = currentConfig.d_maxTCPConnectionDuration - elapsed;
     if (idleTimeout == 0 || remaining <= static_cast<size_t>(idleTimeout)) {
       now.tv_sec += static_cast<time_t>(remaining);
       return now;
index 68d4f92962e2fbfb016997fb5b3b0b7ba73e35f5..ffacf9a19ce4ca4b07059b39d8dd0d329a03ba85 100644 (file)
@@ -987,7 +987,8 @@ void DoHClientCollection::addThread()
 {
 #if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
   try {
-    auto [sender, receiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+    const auto internalPipeBufferSize = dnsdist::configuration::getImmutableConfiguration().d_tcpInternalPipeBufferSize;
+    auto [sender, receiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
 
     vinfolog("Adding DoH Client thread");
     std::lock_guard<std::mutex> lock(d_mutex);
index d19e87206e2f47249a97f4ec6e6a3efda17d2a5e..01056b1d5a4398d5f7db8f73c02fde39540a7636 100644 (file)
  */
 
 #include "dnsdist-proxy-protocol.hh"
+
+#include "dnsdist.hh"
 #include "dnsdist-metrics.hh"
 #include "dolog.hh"
 
-NetmaskGroup g_proxyProtocolACL;
-size_t g_proxyProtocolMaximumSize = 512;
-bool g_applyACLToProxiedClients = false;
-
 std::string getProxyProtocolPayload(const DNSQuestion& dq)
 {
   return makeProxyHeader(dq.overTCP(), dq.ids.origRemote, dq.ids.origDest, dq.proxyProtocolValues ? *dq.proxyProtocolValues : std::vector<ProxyProtocolValue>());
@@ -72,7 +70,7 @@ bool addProxyProtocol(PacketBuffer& buffer, bool tcp, const ComboAddress& source
 
 bool expectProxyProtocolFrom(const ComboAddress& remote)
 {
-  return g_proxyProtocolACL.match(remote);
+  return dnsdist::configuration::getCurrentRuntimeConfiguration().d_proxyProtocolACL.match(remote);
 }
 
 bool handleProxyProtocol(const ComboAddress& remote, bool isTCP, const NetmaskGroup& acl, PacketBuffer& query, ComboAddress& realRemote, ComboAddress& realDestination, std::vector<ProxyProtocolValue>& values)
@@ -86,7 +84,7 @@ bool handleProxyProtocol(const ComboAddress& remote, bool isTCP, const NetmaskGr
     vinfolog("Ignoring invalid proxy protocol (%d, %d) query over %s from %s", query.size(), used, (isTCP ? "TCP" : "UDP"), remote.toStringWithPort());
     return false;
   }
-  else if (static_cast<size_t>(used) > g_proxyProtocolMaximumSize) {
+  if (static_cast<size_t>(used) > dnsdist::configuration::getCurrentRuntimeConfiguration().d_proxyProtocolMaximumSize) {
     vinfolog("Proxy protocol header in %s packet from %s is larger than proxy-protocol-maximum-size (%d), dropping", (isTCP ? "TCP" : "UDP"), remote.toStringWithPort(), used);
     ++dnsdist::metrics::g_stats.proxyProtocolInvalid;
     return false;
@@ -100,7 +98,7 @@ bool handleProxyProtocol(const ComboAddress& remote, bool isTCP, const NetmaskGr
     return false;
   }
 
-  if (proxyProto && g_applyACLToProxiedClients) {
+  if (proxyProto && dnsdist::configuration::getCurrentRuntimeConfiguration().d_applyACLToProxiedClients) {
     if (!acl.match(realRemote)) {
       vinfolog("Query from %s dropped because of ACL", realRemote.toStringWithPort());
       ++dnsdist::metrics::g_stats.aclDrops;
index de7674a2dbaa27069bf0f79b32db85f62d6f3fd4..6e4234d6be531c2a62161ae8060978a7d095aa80 100644 (file)
  */
 #pragma once
 
-#include "dnsdist.hh"
+#include <string>
 
-extern NetmaskGroup g_proxyProtocolACL;
-extern size_t g_proxyProtocolMaximumSize;
-extern bool g_applyACLToProxiedClients;
+#include "iputils.hh"
+#include "noinitvector.hh"
+#include "proxy-protocol.hh"
+
+struct DNSQuestion;
 
 std::string getProxyProtocolPayload(const DNSQuestion& dq);
 
diff --git a/pdns/dnsdistdist/dnsdist-query-count.cc b/pdns/dnsdistdist/dnsdist-query-count.cc
new file mode 100644 (file)
index 0000000..8387f28
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-query-count.hh"
+
+namespace dnsdist::QueryCount
+{
+SharedLockGuarded<Records> g_queryCountRecords;
+}
diff --git a/pdns/dnsdistdist/dnsdist-query-count.hh b/pdns/dnsdistdist/dnsdist-query-count.hh
new file mode 100644 (file)
index 0000000..bb9d589
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+
+#include <functional>
+#include <unordered_map>
+#include <string>
+#include <tuple>
+
+#include "lock.hh"
+
+struct DNSQuestion;
+
+namespace dnsdist::QueryCount
+{
+struct Configuration
+{
+  using Filter = std::function<std::tuple<bool, std::string>(const DNSQuestion* dq)>;
+  Configuration() = default;
+  Filter d_filter;
+  bool d_enabled{false};
+};
+
+using Records = std::unordered_map<std::string, unsigned int>;
+extern SharedLockGuarded<Records> g_queryCountRecords;
+}
index 26c48ba90194dccd33bef8471c89fd1cd8271381..213b43f436843910ad4166c660cf1e1ad7e0b146 100644 (file)
@@ -91,6 +91,8 @@ static std::string getFirstTXTAnswer(const std::string& answer)
 
 static std::string getSecPollStatus(const std::string& queriedName, int timeout=2)
 {
+  const auto verbose = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
+
   const DNSName sentName(queriedName);
   std::vector<uint8_t> packet;
   DNSPacketWriter pw(packet, sentName, QType::TXT);
@@ -108,13 +110,13 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
     string reply;
     int ret = waitForData(sock.getHandle(), timeout, 0);
     if (ret < 0) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Error while waiting for the secpoll response from stub resolver %s: %d", dest.toString(), ret);
       }
       continue;
     }
     else if (ret == 0) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Timeout while waiting for the secpoll response from stub resolver %s", dest.toString());
       }
       continue;
@@ -124,14 +126,14 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
       sock.read(reply);
     }
     catch(const std::exception& e) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Error while reading for the secpoll response from stub resolver %s: %s", dest.toString(), e.what());
       }
       continue;
     }
 
     if (reply.size() <= sizeof(struct dnsheader)) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Too short answer of size %d received from the secpoll stub resolver %s", reply.size(), dest.toString());
       }
       continue;
@@ -140,14 +142,14 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
     struct dnsheader d;
     memcpy(&d, reply.c_str(), sizeof(d));
     if (d.id != pw.getHeader()->id) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid ID (%d / %d) received from the secpoll stub resolver %s", d.id, pw.getHeader()->id, dest.toString());
       }
       continue;
     }
 
     if (d.rcode != RCode::NoError) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Response code '%s' received from the secpoll stub resolver %s for '%s'", RCode::to_s(d.rcode), dest.toString(), queriedName);
       }
 
@@ -159,7 +161,7 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
     }
 
     if (ntohs(d.qdcount) != 1 || ntohs(d.ancount) != 1) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid answer (qdcount %d / ancount %d) received from the secpoll stub resolver %s", ntohs(d.qdcount), ntohs(d.ancount), dest.toString());
       }
       continue;
@@ -170,7 +172,7 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
     DNSName receivedName(reply.c_str(), reply.size(), sizeof(dnsheader), false, &receivedType, &receivedClass);
 
     if (receivedName != sentName || receivedType != QType::TXT || receivedClass != QClass::IN) {
-      if (g_verbose) {
+      if (verbose) {
         warnlog("Invalid answer, either the qname (%s / %s), qtype (%s / %s) or qclass (%s / %s) does not match, received from the secpoll stub resolver %s", receivedName, sentName, QType(receivedType).toString(), QType(QType::TXT).toString(), QClass(receivedClass).toString(), QClass::IN.toString(), dest.toString());
       }
       continue;
@@ -182,12 +184,12 @@ static std::string getSecPollStatus(const std::string& queriedName, int timeout=
   throw std::runtime_error("Unable to get a valid Security Status update");
 }
 
-static bool g_secPollDone{false};
-std::string g_secPollSuffix{"secpoll.powerdns.com."};
-time_t g_secPollInterval{3600};
-
+namespace dnsdist::secpoll
+{
 void doSecPoll(const std::string& suffix)
 {
+  static bool s_secPollDone{false};
+
   if (suffix.empty()) {
     return;
   }
@@ -211,7 +213,7 @@ void doSecPoll(const std::string& suffix)
     int securityStatus = std::stoi(split.first);
     std::string securityMessage = split.second;
 
-    if (securityStatus == 1 && !g_secPollDone) {
+    if (securityStatus == 1 && !s_secPollDone) {
       infolog("Polled security status of version %s at startup, no known issues reported: %s", std::string(VERSION), securityMessage);
     }
     if (securityStatus == 2) {
@@ -222,14 +224,14 @@ void doSecPoll(const std::string& suffix)
     }
 
     dnsdist::metrics::g_stats.securityStatus = securityStatus;
-    g_secPollDone = true;
+    s_secPollDone = true;
     return;
   }
   catch (const std::exception& e) {
     if (releaseVersion) {
       warnlog("Error while retrieving the security update for version %s: %s", version, e.what());
     }
-    else if (!g_secPollDone) {
+    else if (!s_secPollDone) {
       infolog("Error while retrieving the security update for version %s: %s", version, e.what());
     }
   }
@@ -237,13 +239,14 @@ void doSecPoll(const std::string& suffix)
   if (releaseVersion) {
     warnlog("Failed to retrieve security status update for '%s' on %s", pkgv, queriedName);
   }
-  else if (!g_secPollDone) {
+  else if (!s_secPollDone) {
     infolog("Not validating response for security status update, this is a non-release version.");
 
     /* for non-released versions, there is no use sending the same message several times,
        let's just accept that there will be no security polling for this exact version */
-    g_secPollDone = true;
+    s_secPollDone = true;
   }
 }
+}
 
 #endif /* DISABLE_SECPOLL */
index 1a376a8eada1d8956556cab041a2fdc9e9c4512d..f2977081edcbead50041755b8e2fa79bd6000685 100644 (file)
 
 #ifndef DISABLE_SECPOLL
 #include <string>
-#include <ctime>
-
-extern std::string g_secPollSuffix;
-extern time_t g_secPollInterval;
 
+namespace dnsdist::secpoll
+{
 void doSecPoll(const std::string& suffix);
+}
 #endif /* DISABLE_SECPOLL */
index 42ba272ed4b75885148ef7546c17de8da8fe8d92..de4e6c3639a9b93349aa674286040181d2f85fa3 100644 (file)
  */
 #include "dnsdist-session-cache.hh"
 
-TLSSessionCache g_sessionCache;
+#include "dnsdist-configuration.hh"
 
-time_t TLSSessionCache::s_cleanupDelay{60};
-time_t TLSSessionCache::s_sessionValidity{600};
-uint16_t TLSSessionCache::s_maxSessionsPerBackend{20};
+TLSSessionCache g_sessionCache;
 
 void TLSSessionCache::cleanup(time_t now, LockGuardedHolder<TLSSessionCache::CacheData>& data)
 {
-  time_t cutOff = now + s_sessionValidity;
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  time_t cutOff = now + runtimeConfig.d_tlsSessionCacheSessionValidity;
 
   for (auto it = data->d_sessions.begin(); it != data->d_sessions.end();) {
     if (it->second.d_lastUsed > cutOff || it->second.d_sessions.size() == 0) {
@@ -40,7 +39,7 @@ void TLSSessionCache::cleanup(time_t now, LockGuardedHolder<TLSSessionCache::Cac
     }
   }
 
-  data->d_nextCleanup = now + s_cleanupDelay;
+  data->d_nextCleanup = now + runtimeConfig.d_tlsSessionCacheCleanupDelay;
 }
 
 void TLSSessionCache::putSessions(const boost::uuids::uuid& backendID, time_t now, std::vector<std::unique_ptr<TLSSession>>&& sessions)
@@ -50,9 +49,10 @@ void TLSSessionCache::putSessions(const boost::uuids::uuid& backendID, time_t no
     cleanup(now, data);
   }
 
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
   for (auto& session : sessions) {
     auto& entry = data->d_sessions[backendID];
-    if (entry.d_sessions.size() >= s_maxSessionsPerBackend) {
+    if (entry.d_sessions.size() >= runtimeConfig.d_tlsSessionCacheMaxSessionsPerBackend) {
       entry.d_sessions.pop_back();
     }
     entry.d_sessions.push_front(std::move(session));
index 1881fb1af5e5bd6f433545b818d3a13a8788c861..f4e4cdbaad266843ecc6f15215738ff6754aab27 100644 (file)
@@ -38,28 +38,9 @@ public:
   void putSessions(const boost::uuids::uuid& backendID, time_t now, std::vector<std::unique_ptr<TLSSession>>&& sessions);
   std::unique_ptr<TLSSession> getSession(const boost::uuids::uuid& backendID, time_t now);
 
-  static void setCleanupDelay(time_t delay)
-  {
-    s_cleanupDelay = delay;
-  }
-
-  static void setSessionValidity(time_t validity)
-  {
-    s_sessionValidity = validity;
-  }
-
-  static void setMaxTicketsPerBackend(uint16_t max)
-  {
-    s_maxSessionsPerBackend = max;
-  }
-
   size_t getSize();
 
 private:
-  static time_t s_cleanupDelay;
-  static time_t s_sessionValidity;
-  static uint16_t s_maxSessionsPerBackend;
-
   struct BackendEntry
   {
     std::deque<std::unique_ptr<TLSSession>> d_sessions;
index ab6a0f2a09021cadb559b5671aeafe895d8f0d77..a1a2cbdd342c9c46195163e3427674082e511f9b 100644 (file)
@@ -3,8 +3,6 @@
 #include "dnsdist-metrics.hh"
 #include "dolog.hh"
 
-bool g_snmpEnabled{false};
-bool g_snmpTrapsEnabled{false};
 std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent{nullptr};
 
 #ifdef HAVE_NET_SNMP
index 7c1deff9b321586c9e8953ebfc03973e0b81857f..13a83bf8695de1f540eae3df45f005fde71c8f39 100644 (file)
@@ -35,3 +35,5 @@ public:
   bool sendCustomTrap(const std::string& reason);
   bool sendDNSTrap(const DNSQuestion&, const std::string& reason = "");
 };
+
+extern std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent;
index 5393f400d63fa5b1e8b938e768ceadc3831e3428..d09d8d7bf02f85324312c70eed14c5b31110071f 100644 (file)
@@ -175,9 +175,11 @@ bool generateSVCResponse(DNSQuestion& dnsQuestion, const std::vector<std::vector
     }
   }
 
-  if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(dnsQuestion)) {
+
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (runtimeConfig.d_addEDNSToSelfGeneratedResponses && queryHasEDNS(dnsQuestion)) {
     bool dnssecOK = ((getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO) != 0);
-    packetWriter.addOpt(g_PayloadSizeSelfGenAnswers, 0, dnssecOK ? EDNS_HEADER_FLAG_DO : 0);
+    packetWriter.addOpt(runtimeConfig.d_payloadSizeSelfGenAnswers, 0, dnssecOK ? EDNS_HEADER_FLAG_DO : 0);
     packetWriter.commit();
   }
 
index 0cbd806c1164ad59cca8ecc370ee2e7708c7fb98..e03646d4560ff9a02107ed10dc20671072463cec 100644 (file)
@@ -31,7 +31,7 @@ public:
   enum class QueryProcessingResult : uint8_t { Forwarded, TooSmall, InvalidHeaders, Dropped, SelfAnswered, NoBackend, Asynchronous };
   enum class ProxyProtocolResult : uint8_t { Reading, Done, Error };
 
-  IncomingTCPConnectionState(ConnectionInfo&& ci, TCPClientThreadData& threadData, const struct timeval& now): d_buffer(sizeof(uint16_t)), d_ci(std::move(ci)), d_handler(d_ci.fd, timeval{g_tcpRecvTimeout,0}, d_ci.cs->tlsFrontend ? d_ci.cs->tlsFrontend->getContext() : (d_ci.cs->dohFrontend ? d_ci.cs->dohFrontend->d_tlsContext.getContext() : nullptr), now.tv_sec), d_connectionStartTime(now), d_ioState(make_unique<IOStateHandler>(*threadData.mplexer, d_ci.fd)), d_threadData(threadData), d_creatorThreadID(std::this_thread::get_id())
+  IncomingTCPConnectionState(ConnectionInfo&& ci, TCPClientThreadData& threadData, const struct timeval& now): d_buffer(sizeof(uint16_t)), d_ci(std::move(ci)), d_handler(d_ci.fd, timeval{dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout,0}, d_ci.cs->tlsFrontend ? d_ci.cs->tlsFrontend->getContext() : (d_ci.cs->dohFrontend ? d_ci.cs->dohFrontend->d_tlsContext.getContext() : nullptr), now.tv_sec), d_connectionStartTime(now), d_ioState(make_unique<IOStateHandler>(*threadData.mplexer, d_ci.fd)), d_threadData(threadData), d_creatorThreadID(std::this_thread::get_id())
   {
     d_origDest.reset();
     d_origDest.sin4.sin_family = d_ci.remote.sin4.sin_family;
@@ -57,47 +57,49 @@ public:
 
   boost::optional<struct timeval> getClientReadTTD(struct timeval now) const
   {
-    if (g_maxTCPConnectionDuration == 0 && g_tcpRecvTimeout == 0) {
+    const auto& runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+    if (runtimeConfiguration.d_maxTCPConnectionDuration == 0 && runtimeConfiguration.d_tcpRecvTimeout == 0) {
       return boost::none;
     }
 
-    if (g_maxTCPConnectionDuration > 0) {
+    if (runtimeConfiguration.d_maxTCPConnectionDuration > 0) {
       auto elapsed = now.tv_sec - d_connectionStartTime.tv_sec;
-      if (elapsed < 0 || (static_cast<size_t>(elapsed) >= g_maxTCPConnectionDuration)) {
+      if (elapsed < 0 || (static_cast<size_t>(elapsed) >= runtimeConfiguration.d_maxTCPConnectionDuration)) {
         return now;
       }
-      auto remaining = g_maxTCPConnectionDuration - elapsed;
-      if (g_tcpRecvTimeout == 0 || remaining <= static_cast<size_t>(g_tcpRecvTimeout)) {
+      auto remaining = runtimeConfiguration.d_maxTCPConnectionDuration - elapsed;
+      if (runtimeConfiguration.d_tcpRecvTimeout == 0 || remaining <= static_cast<size_t>(runtimeConfiguration.d_tcpRecvTimeout)) {
         now.tv_sec += remaining;
         return now;
       }
     }
 
-    now.tv_sec += g_tcpRecvTimeout;
+    now.tv_sec += runtimeConfiguration.d_tcpRecvTimeout;
     return now;
   }
 
   boost::optional<struct timeval> getClientWriteTTD(const struct timeval& now) const
   {
-    if (g_maxTCPConnectionDuration == 0 && g_tcpSendTimeout == 0) {
+    const auto& runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+    if (runtimeConfiguration.d_maxTCPConnectionDuration == 0 && runtimeConfiguration.d_tcpSendTimeout == 0) {
       return boost::none;
     }
 
-    struct timeval res = now;
+    timeval res(now);
 
-    if (g_maxTCPConnectionDuration > 0) {
+    if (runtimeConfiguration.d_maxTCPConnectionDuration > 0) {
       auto elapsed = res.tv_sec - d_connectionStartTime.tv_sec;
-      if (elapsed < 0 || static_cast<size_t>(elapsed) >= g_maxTCPConnectionDuration) {
+      if (elapsed < 0 || static_cast<size_t>(elapsed) >= runtimeConfiguration.d_maxTCPConnectionDuration) {
         return res;
       }
-      auto remaining = g_maxTCPConnectionDuration - elapsed;
-      if (g_tcpSendTimeout == 0 || remaining <= static_cast<size_t>(g_tcpSendTimeout)) {
+      auto remaining = runtimeConfiguration.d_maxTCPConnectionDuration - elapsed;
+      if (runtimeConfiguration.d_tcpSendTimeout == 0 || remaining <= static_cast<size_t>(runtimeConfiguration.d_tcpSendTimeout)) {
         res.tv_sec += remaining;
         return res;
       }
     }
 
-    res.tv_sec += g_tcpSendTimeout;
+    res.tv_sec += runtimeConfiguration.d_tcpSendTimeout;
     return res;
   }
 
index b7ca45a6f9c291778ec44018c7ec92f334266535..09be1441d24629f4a7a33ae2e95b188bcf7ca4ee 100644 (file)
    Let's start naively.
 */
 
-size_t g_maxTCPQueriesPerConn{0};
-size_t g_maxTCPConnectionDuration{0};
-
-#ifdef __linux__
-// On Linux this gives us 128k pending queries (default is 8192 queries),
-// which should be enough to deal with huge spikes
-size_t g_tcpInternalPipeBufferSize{1048576U};
-uint64_t g_maxTCPQueuedConnections{10000};
-#else
-size_t g_tcpInternalPipeBufferSize{0};
-uint64_t g_maxTCPQueuedConnections{1000};
-#endif
-
-int g_tcpRecvTimeout{2};
-int g_tcpSendTimeout{2};
 std::atomic<uint64_t> g_tcpStatesDumpRequested{0};
 
 LockGuarded<std::map<ComboAddress, size_t, ComboAddress::addressOnlyLessThan>> dnsdist::IncomingConcurrentTCPConnectionsManager::s_tcpClientsConcurrentConnectionsCount;
-size_t dnsdist::IncomingConcurrentTCPConnectionsManager::s_maxTCPConnectionsPerClient = 0;
 
 IncomingTCPConnectionState::~IncomingTCPConnectionState()
 {
@@ -142,11 +126,13 @@ TCPClientCollection::TCPClientCollection(size_t maxThreads, std::vector<ClientSt
 void TCPClientCollection::addTCPClientThread(std::vector<ClientState*>& tcpAcceptStates)
 {
   try {
-    auto [queryChannelSender, queryChannelReceiver] = pdns::channel::createObjectQueue<ConnectionInfo>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+    const auto internalPipeBufferSize = dnsdist::configuration::getImmutableConfiguration().d_tcpInternalPipeBufferSize;
+
+    auto [queryChannelSender, queryChannelReceiver] = pdns::channel::createObjectQueue<ConnectionInfo>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
 
-    auto [crossProtocolQueryChannelSender, crossProtocolQueryChannelReceiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+    auto [crossProtocolQueryChannelSender, crossProtocolQueryChannelReceiver] = pdns::channel::createObjectQueue<CrossProtocolQuery>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
 
-    auto [crossProtocolResponseChannelSender, crossProtocolResponseChannelReceiver] = pdns::channel::createObjectQueue<TCPCrossProtocolResponse>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, g_tcpInternalPipeBufferSize);
+    auto [crossProtocolResponseChannelSender, crossProtocolResponseChannelReceiver] = pdns::channel::createObjectQueue<TCPCrossProtocolResponse>(pdns::channel::SenderBlockingMode::SenderNonBlocking, pdns::channel::ReceiverBlockingMode::ReceiverNonBlocking, internalPipeBufferSize);
 
     vinfolog("Adding TCP Client thread");
 
@@ -251,12 +237,13 @@ bool IncomingTCPConnectionState::canAcceptNewQueries(const struct timeval& now)
     return false;
   }
 
-  if (g_maxTCPQueriesPerConn != 0 && d_queriesCount > g_maxTCPQueriesPerConn) {
-    vinfolog("not accepting new queries from %s because it reached the maximum number of queries per conn (%d / %d)", d_ci.remote.toStringWithPort(), d_queriesCount, g_maxTCPQueriesPerConn);
+  const auto& currentConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (currentConfig.d_maxTCPQueriesPerConn != 0 && d_queriesCount > currentConfig.d_maxTCPQueriesPerConn) {
+    vinfolog("not accepting new queries from %s because it reached the maximum number of queries per conn (%d / %d)", d_ci.remote.toStringWithPort(), d_queriesCount, currentConfig.d_maxTCPQueriesPerConn);
     return false;
   }
 
-  if (maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
+  if (maxConnectionDurationReached(currentConfig.d_maxTCPConnectionDuration, now)) {
     vinfolog("not accepting new queries from %s because it reached the maximum TCP connection duration", d_ci.remote.toStringWithPort());
     return false;
   }
@@ -498,11 +485,12 @@ void IncomingTCPConnectionState::handleResponse(const struct timeval& now, TCPRe
     return;
   }
 
+  const auto config = dnsdist::configuration::getCurrentRuntimeConfiguration();
   if (!response.isAsync()) {
     try {
       auto& ids = response.d_idstate;
       std::shared_ptr<DownstreamState> backend = response.d_ds ? response.d_ds : (response.d_connection ? response.d_connection->getDS() : nullptr);
-      if (backend == nullptr || !responseContentMatches(response.d_buffer, ids.qname, ids.qtype, ids.qclass, backend)) {
+      if (backend == nullptr || !responseContentMatches(response.d_buffer, ids.qname, ids.qtype, ids.qclass, backend, config.d_allowEmptyResponse)) {
         state->terminateClientConnection();
         return;
       }
@@ -1068,7 +1056,8 @@ void IncomingTCPConnectionState::handleIO()
     iostate = IOState::Done;
     IOStateGuard ioGuard(d_ioState);
 
-    if (maxConnectionDurationReached(g_maxTCPConnectionDuration, now)) {
+    const auto& currentConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+    if (maxConnectionDurationReached(currentConfig.d_maxTCPConnectionDuration, now)) {
       vinfolog("Terminating TCP connection from %s because it reached the maximum TCP connection duration", d_ci.remote.toStringWithPort());
       // will be handled by the ioGuard
       // handleNewIOState(state, IOState::Done, fd, handleIOCallback);
@@ -1608,7 +1597,8 @@ static void acceptNewConnection(const TCPAcceptorParam& param, TCPClientThreadDa
 
     setTCPNoDelay(connInfo.fd); // disable NAGLE
 
-    if (g_maxTCPQueuedConnections > 0 && g_tcpclientthreads->getQueuedCount() >= g_maxTCPQueuedConnections) {
+    const auto maxTCPQueuedConnections = dnsdist::configuration::getImmutableConfiguration().d_maxTCPQueuedConnections;
+    if (maxTCPQueuedConnections > 0 && g_tcpclientthreads->getQueuedCount() >= maxTCPQueuedConnections) {
       vinfolog("Dropping TCP connection from %s because we have too many queued already", remote.toStringWithPort());
       return;
     }
index 368ee9e75a638d0effdb3a0c5d59cbfd89d253df..24395fdb0a03095f28fe08c7c6ffc0cdcad7b7ac 100644 (file)
@@ -32,6 +32,7 @@
 #include "base64.hh"
 #include "connection-management.hh"
 #include "dnsdist.hh"
+#include "dnsdist-configuration.hh"
 #include "dnsdist-dynblocks.hh"
 #include "dnsdist-healthchecks.hh"
 #include "dnsdist-metrics.hh"
@@ -60,9 +61,7 @@ struct WebserverConfig
   bool statsRequireAuthentication{true};
 };
 
-bool g_apiReadWrite{false};
 LockGuarded<WebserverConfig> g_webserverConfig;
-std::string g_apiConfigDirectory;
 
 static ConcurrentConnectionManager s_connManager(100);
 
@@ -90,9 +89,12 @@ std::string getWebserverConfig()
     out << "Password: " << (config->password ? "set" : "unset") << endl;
     out << "API key: " << (config->apiKey ? "set" : "unset") << endl;
   }
-  out << "API writable: " << (g_apiReadWrite ? "yes" : "no") << endl;
-  out << "API configuration directory: " << g_apiConfigDirectory << endl;
-  out << "Maximum concurrent connections: " << s_connManager.getMaxConcurrentConnections() << endl;
+  {
+    const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
+    out << "API writable: " << (config.d_apiReadWrite ? "yes" : "no") << endl;
+    out << "API configuration directory: " << config.d_apiConfigDirectory << endl;
+    out << "Maximum concurrent connections: " << s_connManager.getMaxConcurrentConnections() << endl;
+  }
 
   return out.str();
 }
@@ -238,17 +240,18 @@ bool addMetricDefinition(const dnsdist::prometheus::PrometheusMetricDefinition&
 #ifndef DISABLE_WEB_CONFIG
 static bool apiWriteConfigFile(const string& filebasename, const string& content)
 {
-  if (!g_apiReadWrite) {
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (!runtimeConfig.d_apiReadWrite) {
     warnlog("Not writing content to %s since the API is read-only", filebasename);
     return false;
   }
 
-  if (g_apiConfigDirectory.empty()) {
+  if (runtimeConfig.d_apiConfigDirectory.empty()) {
     vinfolog("Not writing content to %s since the API configuration directory is not set", filebasename);
     return false;
   }
 
-  string filename = g_apiConfigDirectory + "/" + filebasename + ".conf";
+  string filename = runtimeConfig.d_apiConfigDirectory + "/" + filebasename + ".conf";
   ofstream ofconf(filename.c_str());
   if (!ofconf) {
     errlog("Could not open configuration fragment file '%s' for writing: %s", filename, stringerror());
@@ -365,7 +368,7 @@ static bool isMethodAllowed(const YaHTTP::Request& req)
   if (req.method == "GET") {
     return true;
   }
-  if (req.method == "PUT" && g_apiReadWrite) {
+  if (req.method == "PUT" && dnsdist::configuration::getCurrentRuntimeConfiguration().d_apiReadWrite) {
     if (req.url.path == "/api/v1/servers/localhost/config/allow-from") {
       return true;
     }
@@ -391,7 +394,7 @@ static void handleCORS(const YaHTTP::Request& req, YaHTTP::Response& resp)
   if (origin != req.headers.end()) {
     if (req.method == "OPTIONS") {
       /* Pre-flight request */
-      if (g_apiReadWrite) {
+      if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_apiReadWrite) {
         resp.headers["Access-Control-Allow-Methods"] = "GET, PUT";
       }
       else {
@@ -969,6 +972,7 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
   }
 
   const string& command = req.getvars.at("command");
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
 
   if (command == "stats") {
     auto obj = Json::object{
@@ -1002,14 +1006,14 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
         {"reason", entry.second.reason},
         {"seconds", static_cast<double>(entry.second.until.tv_sec - now.tv_sec)},
         {"blocks", static_cast<double>(counter)},
-        {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : g_dynBlockAction)},
+        {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : runtimeConfig.d_dynBlockAction)},
         {"warning", entry.second.warning},
         {"ebpf", entry.second.bpf}};
       obj.emplace(entry.first.toString(), thing);
     }
 
     auto smt = g_dynblockSMT.getLocal();
-    smt->visit([&now, &obj](const SuffixMatchTree<DynBlock>& node) {
+    smt->visit([&now, &obj, &runtimeConfig](const SuffixMatchTree<DynBlock>& node) {
       if (!(now < node.d_value.until)) {
         return;
       }
@@ -1021,7 +1025,7 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
         {"reason", node.d_value.reason},
         {"seconds", static_cast<double>(node.d_value.until.tv_sec - now.tv_sec)},
         {"blocks", static_cast<double>(node.d_value.blocks)},
-        {"action", DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : g_dynBlockAction)},
+        {"action", DNSAction::typeToString(node.d_value.action != DNSAction::Action::None ? node.d_value.action : runtimeConfig.d_dynBlockAction)},
         {"ebpf", node.d_value.bpf}};
       obj.emplace(dom, thing);
     });
@@ -1055,7 +1059,7 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
           {"reason", entry.second.reason},
           {"seconds", static_cast<double>(entry.second.until.tv_sec - now.tv_sec)},
           {"blocks", static_cast<double>(counter)},
-          {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : g_dynBlockAction)},
+          {"action", DNSAction::typeToString(entry.second.action != DNSAction::Action::None ? entry.second.action : runtimeConfig.d_dynBlockAction)},
           {"warning", entry.second.warning},
         };
         obj.emplace(entry.first.toString(), thing);
@@ -1442,23 +1446,25 @@ static void handleConfigDump(const YaHTTP::Request& req, YaHTTP::Response& resp)
   resp.status = 200;
 
   Json::array doc;
-  typedef boost::variant<bool, double, std::string> configentry_t;
+  const auto runtimeConfiguration = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  const auto immutableConfig = dnsdist::configuration::getImmutableConfiguration();
+  using configentry_t = boost::variant<bool, double, std::string>;
   std::vector<std::pair<std::string, configentry_t>> configEntries{
     {"acl", g_ACL.getLocal()->toString()},
-    {"allow-empty-response", g_allowEmptyResponse},
+    {"allow-empty-response", runtimeConfiguration.d_allowEmptyResponse},
     {"control-socket", g_serverControl.toStringWithPort()},
-    {"ecs-override", g_ECSOverride},
-    {"ecs-source-prefix-v4", (double)g_ECSSourcePrefixV4},
-    {"ecs-source-prefix-v6", (double)g_ECSSourcePrefixV6},
-    {"fixup-case", g_fixupCase},
-    {"max-outstanding", (double)g_maxOutstanding},
+    {"ecs-override", runtimeConfiguration.d_ecsOverride},
+    {"ecs-source-prefix-v4", static_cast<double>(runtimeConfiguration.d_ECSSourcePrefixV4)},
+    {"ecs-source-prefix-v6", static_cast<double>(runtimeConfiguration.d_ECSSourcePrefixV6)},
+    {"fixup-case", runtimeConfiguration.d_fixupCase},
+    {"max-outstanding", static_cast<double>(immutableConfig.d_maxUDPOutstanding)},
     {"server-policy", g_policy.getLocal()->getName()},
-    {"stale-cache-entries-ttl", (double)g_staleCacheEntriesTTL},
-    {"tcp-recv-timeout", (double)g_tcpRecvTimeout},
-    {"tcp-send-timeout", (double)g_tcpSendTimeout},
-    {"truncate-tc", g_truncateTC},
-    {"verbose", g_verbose},
-    {"verbose-health-checks", g_verboseHealthChecks}};
+    {"stale-cache-entries-ttl", static_cast<double>(runtimeConfiguration.d_staleCacheEntriesTTL)},
+    {"tcp-recv-timeout", static_cast<double>(runtimeConfiguration.d_tcpRecvTimeout)},
+    {"tcp-send-timeout", static_cast<double>(runtimeConfiguration.d_tcpSendTimeout)},
+    {"truncate-tc", runtimeConfiguration.d_truncateTC},
+    {"verbose", runtimeConfiguration.d_verbose},
+    {"verbose-health-checks", runtimeConfiguration.d_verboseHealthChecks}};
   for (const auto& item : configEntries) {
     if (const auto& bval = boost::get<bool>(&item.second)) {
       doc.emplace_back(Json::object{
index 0336904f5390f0930e4472193773cb4b19b7582d..df237bfe64fe5bdebdc8cfbe9adcfdb88add89ed 100644 (file)
@@ -52,6 +52,7 @@
 #include "dnsdist-async.hh"
 #include "dnsdist-cache.hh"
 #include "dnsdist-carbon.hh"
+#include "dnsdist-configuration.hh"
 #include "dnsdist-console.hh"
 #include "dnsdist-crypto.hh"
 #include "dnsdist-discovery.hh"
@@ -67,6 +68,7 @@
 #include "dnsdist-random.hh"
 #include "dnsdist-rings.hh"
 #include "dnsdist-secpoll.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsdist-tcp.hh"
 #include "dnsdist-web.hh"
 #include "dnsdist-xsk.hh"
    on the Lua side we can't do that. */
 
 using std::thread;
-bool g_verbose;
-
-uint16_t g_maxOutstanding{std::numeric_limits<uint16_t>::max()};
-uint32_t g_staleCacheEntriesTTL{0};
-bool g_allowEmptyResponse{false};
 
 GlobalStateHolder<NetmaskGroup> g_ACL;
 string g_outputBuffer;
@@ -120,7 +117,6 @@ std::vector<std::shared_ptr<DynBPFFilter>> g_dynBPFFilters;
 
 std::vector<std::unique_ptr<ClientState>> g_frontends;
 GlobalStateHolder<pools_t> g_pools;
-size_t g_udpVectorSize{1};
 std::vector<uint32_t> g_TCPFastOpenKey;
 /* UDP: the grand design. Per socket we listen on for incoming queries there is one thread.
    Then we have a bunch of connected sockets for talking to downstream servers.
@@ -138,17 +134,9 @@ std::vector<uint32_t> g_TCPFastOpenKey;
  */
 
 Rings g_rings;
-QueryCount g_qcount;
 
 GlobalStateHolder<servers_t> g_dstates;
 
-bool g_servFailOnNoPolicy{false};
-bool g_truncateTC{false};
-bool g_fixupCase{false};
-bool g_dropEmptyQueries{false};
-uint32_t g_socketUDPSendBuffer{0};
-uint32_t g_socketUDPRecvBuffer{0};
-
 std::set<std::string> g_capabilitiesToRetain;
 
 // we are not willing to receive a bigger UDP response than that, no matter what
@@ -177,14 +165,14 @@ static void sendfromto(int sock, const PacketBuffer& buffer, const ComboAddress&
   }
 }
 
-static void truncateTC(PacketBuffer& packet, size_t maximumSize, unsigned int qnameWireLength)
+static void truncateTC(PacketBuffer& packet, size_t maximumSize, unsigned int qnameWireLength, bool addEDNSToSelfGeneratedResponses)
 {
   try {
     bool hadEDNS = false;
     uint16_t payloadSize = 0;
     uint16_t zValue = 0;
 
-    if (g_addEDNSToSelfGeneratedResponses) {
+    if (addEDNSToSelfGeneratedResponses) {
       // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
       hadEDNS = getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(packet.data()), packet.size(), &payloadSize, &zValue);
     }
@@ -320,7 +308,7 @@ static void doLatencyStats(dnsdist::Protocol protocol, double udiff)
   }
 }
 
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote)
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, bool allowEmptyResponse)
 {
   if (response.size() < sizeof(dnsheader)) {
     return false;
@@ -336,7 +324,7 @@ bool responseContentMatches(const PacketBuffer& response, const DNSName& qname,
   }
 
   if (dnsHeader->qdcount == 0) {
-    if ((dnsHeader->rcode != RCode::NoError && dnsHeader->rcode != RCode::NXDomain) || g_allowEmptyResponse) {
+    if ((dnsHeader->rcode != RCode::NoError && dnsHeader->rcode != RCode::NXDomain) || allowEmptyResponse) {
       return true;
     }
 
@@ -407,7 +395,7 @@ static bool fixUpResponse(PacketBuffer& response, const DNSName& qname, uint16_t
     return true;
   }
 
-  if (g_fixupCase) {
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_fixupCase) {
     const auto& realname = qname.getStorage();
     if (response.size() >= (sizeof(dnsheader) + realname.length())) {
       memcpy(&response.at(sizeof(dnsheader)), realname.c_str(), realname.length());
@@ -532,7 +520,7 @@ bool applyRulesToResponse(const std::vector<dnsdist::rules::ResponseRuleAction>&
             header.qr = true;
             return true;
           });
-          truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength());
+          truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength(), dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses);
           ++dnsdist::metrics::g_stats.ruleTruncated;
           return true;
         }
@@ -621,13 +609,14 @@ bool processResponse(PacketBuffer& response, const std::vector<dnsdist::rules::R
 
 static size_t getInitialUDPPacketBufferSize(bool expectProxyProtocol)
 {
-  static_assert(s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "The incoming buffer size should not be larger than s_initialUDPPacketBufferSize");
+  static_assert(dnsdist::configuration::s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "The incoming buffer size should not be larger than s_initialUDPPacketBufferSize");
 
-  if (!expectProxyProtocol || g_proxyProtocolACL.empty()) {
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (!expectProxyProtocol || runtimeConfig.d_proxyProtocolACL.empty()) {
     return s_initialUDPPacketBufferSize;
   }
 
-  return s_initialUDPPacketBufferSize + g_proxyProtocolMaximumSize;
+  return s_initialUDPPacketBufferSize + runtimeConfig.d_proxyProtocolMaximumSize;
 }
 
 static size_t getMaximumIncomingPacketSize(const ClientState& clientState)
@@ -636,11 +625,12 @@ static size_t getMaximumIncomingPacketSize(const ClientState& clientState)
     return getInitialUDPPacketBufferSize(clientState.d_enableProxyProtocol);
   }
 
-  if (!clientState.d_enableProxyProtocol || g_proxyProtocolACL.empty()) {
-    return s_udpIncomingBufferSize;
+  const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (!clientState.d_enableProxyProtocol || runtimeConfig.d_proxyProtocolACL.empty()) {
+    return dnsdist::configuration::s_udpIncomingBufferSize;
   }
 
-  return s_udpIncomingBufferSize + g_proxyProtocolMaximumSize;
+  return dnsdist::configuration::s_udpIncomingBufferSize + runtimeConfig.d_proxyProtocolMaximumSize;
 }
 
 bool sendUDPResponse(int origFD, const PacketBuffer& response, const int delayMsec, const ComboAddress& origDest, const ComboAddress& origRemote)
@@ -694,14 +684,14 @@ static void handleResponseForUDPClient(InternalQueryState& ids, PacketBuffer& re
 
   if (ids.udpPayloadSize > 0 && response.size() > ids.udpPayloadSize) {
     vinfolog("Got a response of size %d while the initial UDP payload size was %d, truncating", response.size(), ids.udpPayloadSize);
-    truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength());
+    truncateTC(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength(), dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses);
     dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsResponse.getMutableData(), [](dnsheader& header) {
       header.tc = true;
       return true;
     });
   }
-  else if (dnsResponse.getHeader()->tc && g_truncateTC) {
-    truncateTC(response, dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength());
+  else if (dnsResponse.getHeader()->tc && dnsdist::configuration::getCurrentRuntimeConfiguration().d_truncateTC) {
+    truncateTC(response, dnsResponse.getMaximumSize(), dnsResponse.ids.qname.wirelength(), dnsdist::configuration::getCurrentRuntimeConfiguration().d_addEDNSToSelfGeneratedResponses);
   }
 
   /* when the answer is encrypted in place, we need to get a copy
@@ -757,7 +747,7 @@ bool processResponderPacket(std::shared_ptr<DownstreamState>& dss, PacketBuffer&
   const dnsheader_aligned dnsHeader(response.data());
   auto queryId = dnsHeader->id;
 
-  if (!responseContentMatches(response, ids.qname, ids.qtype, ids.qclass, dss)) {
+  if (!responseContentMatches(response, ids.qname, ids.qtype, ids.qclass, dss, dnsdist::configuration::getCurrentRuntimeConfiguration().d_allowEmptyResponse)) {
     dss->restoreState(queryId, std::move(ids));
     return false;
   }
@@ -1060,16 +1050,17 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, c
     g_rings.insertQuery(now, dnsQuestion.ids.origRemote, dnsQuestion.ids.qname, dnsQuestion.ids.qtype, dnsQuestion.getData().size(), *dnsQuestion.getHeader(), dnsQuestion.getProtocol());
   }
 
-  if (g_qcount.enabled) {
+  const auto runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+  if (runtimeConfig.d_queryCountConfig.d_enabled) {
     string qname = dnsQuestion.ids.qname.toLogString();
     bool countQuery{true};
-    if (g_qcount.filter) {
+    if (runtimeConfig.d_queryCountConfig.d_filter) {
       auto lock = g_lua.lock();
-      std::tie(countQuery, qname) = g_qcount.filter(&dnsQuestion);
+      std::tie(countQuery, qname) = runtimeConfig.d_queryCountConfig.d_filter(&dnsQuestion);
     }
 
     if (countQuery) {
-      auto records = g_qcount.records.write_lock();
+      auto records = dnsdist::QueryCount::g_queryCountRecords.write_lock();
       if (records->count(qname) == 0) {
         (*records)[qname] = 0;
       }
@@ -1096,7 +1087,7 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, c
     if (now < got->second.until) {
       DNSAction::Action action = got->second.action;
       if (action == DNSAction::Action::None) {
-        action = g_dynBlockAction;
+        action = runtimeConfig.d_dynBlockAction;
       }
 
       switch (action) {
@@ -1173,7 +1164,7 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, c
     if (now < got->until) {
       DNSAction::Action action = got->action;
       if (action == DNSAction::Action::None) {
-        action = g_dynBlockAction;
+        action = runtimeConfig.d_dynBlockAction;
       }
       switch (action) {
       case DNSAction::Action::NoOp:
@@ -1356,7 +1347,7 @@ bool checkQueryHeaders(const struct dnsheader& dnsHeader, ClientState& clientSta
 
   if (dnsHeader.qdcount == 0) {
     ++dnsdist::metrics::g_stats.emptyQueries;
-    if (g_dropEmptyQueries) {
+    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_dropEmptyQueries) {
       return false;
     }
   }
@@ -1475,7 +1466,7 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders
     dnsQuestion.ids.packetCache = serverPool->packetCache;
     selectBackendForOutgoingQuery(dnsQuestion, serverPool, holders, selectedBackend);
 
-    uint32_t allowExpired = selectedBackend ? 0 : g_staleCacheEntriesTTL;
+    uint32_t allowExpired = selectedBackend ? 0 : dnsdist::configuration::getCurrentRuntimeConfiguration().d_staleCacheEntriesTTL;
 
     if (dnsQuestion.ids.packetCache && !dnsQuestion.ids.skipCache) {
       dnsQuestion.ids.dnssecOK = (getEDNSZ(dnsQuestion) & EDNS_HEADER_FLAG_DO) != 0;
@@ -1570,10 +1561,11 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders
     }
 
     if (!selectedBackend) {
+      auto servFailOnNoPolicy = dnsdist::configuration::getCurrentRuntimeConfiguration().d_servFailOnNoPolicy;
       ++dnsdist::metrics::g_stats.noPolicy;
 
-      vinfolog("%s query for %s|%s from %s, no downstream server available", g_servFailOnNoPolicy ? "ServFailed" : "Dropped", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort());
-      if (g_servFailOnNoPolicy) {
+      vinfolog("%s query for %s|%s from %s, no downstream server available", servFailOnNoPolicy ? "ServFailed" : "Dropped", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort());
+      if (servFailOnNoPolicy) {
         dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [](dnsheader& header) {
           header.rcode = RCode::ServFail;
           header.qr = true;
@@ -2070,7 +2062,7 @@ static void MultipleMessagesUDPClientThread(ClientState* clientState, LocalHolde
     /* used by HarvestDestinationAddress */
     cmsgbuf_aligned cbuf{};
   };
-  const size_t vectSize = g_udpVectorSize;
+  const size_t vectSize = dnsdist::configuration::getImmutableConfiguration().d_udpVectorSize;
 
   if (vectSize > std::numeric_limits<uint16_t>::max()) {
     throw std::runtime_error("The value of setUDPMultipleMessagesVectorSize is too high, the maximum value is " + std::to_string(std::numeric_limits<uint16_t>::max()));
@@ -2157,7 +2149,7 @@ static void udpClientThread(std::vector<ClientState*> states)
     LocalHolders holders;
 #ifndef DISABLE_RECVMMSG
 #if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
-    if (g_udpVectorSize > 1) {
+    if (dnsdist::configuration::getImmutableConfiguration().d_udpVectorSize > 1) {
       MultipleMessagesUDPClientThread(states.at(0), holders);
     }
     else
@@ -2268,10 +2260,6 @@ static void udpClientThread(std::vector<ClientState*> states)
   }
 }
 
-boost::optional<uint64_t> g_maxTCPClientThreads{boost::none};
-pdns::stat16_t g_cacheCleaningDelay{60};
-pdns::stat16_t g_cacheCleaningPercentage{100};
-
 static void maintThread()
 {
   setThreadName("dnsdist/main");
@@ -2281,6 +2269,7 @@ static void maintThread()
 
   for (;;) {
     std::this_thread::sleep_for(std::chrono::seconds(interval));
+    const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
 
     {
       auto lua = g_lua.lock();
@@ -2302,7 +2291,7 @@ static void maintThread()
     }
 
     counter++;
-    if (counter >= g_cacheCleaningDelay) {
+    if (counter >= config.d_cacheCleaningDelay) {
       /* keep track, for each cache, of whether we should keep
        expired entries */
       std::map<std::shared_ptr<DNSDistPacketCache>, bool> caches;
@@ -2338,7 +2327,7 @@ static void maintThread()
           continue;
         }
         const auto& packetCache = pair.first;
-        size_t upTo = (packetCache->getMaxEntries() * (100 - g_cacheCleaningPercentage)) / 100;
+        size_t upTo = (packetCache->getMaxEntries() * (100 - config.d_cacheCleaningPercentage)) / 100;
         packetCache->purgeExpired(upTo, now);
       }
       counter = 0;
@@ -2361,13 +2350,15 @@ static void secPollThread()
   setThreadName("dnsdist/secpoll");
 
   for (;;) {
+    const auto& runtimeConfig = dnsdist::configuration::getCurrentRuntimeConfiguration();
+
     try {
-      doSecPoll(g_secPollSuffix);
+      dnsdist::secpoll::doSecPoll(runtimeConfig.d_secPollSuffix);
     }
     catch (...) {
     }
     // coverity[store_truncates_time_t]
-    std::this_thread::sleep_for(std::chrono::seconds(g_secPollInterval));
+    std::this_thread::sleep_for(std::chrono::seconds(runtimeConfig.d_secPollInterval));
   }
 }
 #endif /* DISABLE_SECPOLL */
@@ -2477,6 +2468,7 @@ static void dropUserPrivs(uid_t uid)
 
 static void checkFileDescriptorsLimits(size_t udpBindsCount, size_t tcpBindsCount)
 {
+  const auto immutableConfig = dnsdist::configuration::getImmutableConfiguration();
   /* stdin, stdout, stderr */
   rlim_t requiredFDsCount = 3;
   auto backends = g_dstates.getLocal();
@@ -2487,20 +2479,20 @@ static void checkFileDescriptorsLimits(size_t udpBindsCount, size_t tcpBindsCoun
   }
   requiredFDsCount += backendUDPSocketsCount;
   /* TCP sockets to backends */
-  if (g_maxTCPClientThreads) {
-    requiredFDsCount += (backends->size() * (*g_maxTCPClientThreads));
+  if (immutableConfig.d_maxTCPClientThreads > 0) {
+    requiredFDsCount += (backends->size() * immutableConfig.d_maxTCPClientThreads);
   }
   /* listening sockets */
   requiredFDsCount += udpBindsCount;
   requiredFDsCount += tcpBindsCount;
   /* number of TCP connections currently served, assuming 1 connection per worker thread which is of course not right */
-  if (g_maxTCPClientThreads) {
-    requiredFDsCount += *g_maxTCPClientThreads;
+  if (immutableConfig.d_maxTCPClientThreads > 0) {
+    requiredFDsCount += immutableConfig.d_maxTCPClientThreads;
     /* max pipes for communicating between TCP acceptors and client threads */
-    requiredFDsCount += (*g_maxTCPClientThreads * 2);
+    requiredFDsCount += (immutableConfig.d_maxTCPClientThreads * 2);
   }
   /* max TCP queued connections */
-  requiredFDsCount += g_maxTCPQueuedConnections;
+  requiredFDsCount += immutableConfig.d_maxTCPQueuedConnections;
   /* DelayPipe pipe */
   requiredFDsCount += 2;
   /* syslog socket */
@@ -2525,10 +2517,10 @@ static void checkFileDescriptorsLimits(size_t udpBindsCount, size_t tcpBindsCoun
   }
 }
 
-static bool g_warned_ipv6_recvpktinfo = false;
-
 static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr, int& socket, bool tcp, bool warn)
 {
+  const auto immutableConfig = dnsdist::configuration::getImmutableConfiguration();
+  static bool s_warned_ipv6_recvpktinfo = false;
   (void)warn;
   socket = SSocket(addr.sin4.sin_family, !tcp ? SOCK_DGRAM : SOCK_STREAM, 0);
 
@@ -2566,9 +2558,9 @@ static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr,
     int one = 1;
     (void)setsockopt(socket, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
 #ifdef IPV6_RECVPKTINFO
-    if (addr.isIPv6() && setsockopt(socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)) < 0 && !g_warned_ipv6_recvpktinfo) {
+    if (addr.isIPv6() && setsockopt(socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)) < 0 && !s_warned_ipv6_recvpktinfo) {
       warnlog("Warning: IPV6_RECVPKTINFO setsockopt failed: %s", stringerror());
-      g_warned_ipv6_recvpktinfo = true;
+      s_warned_ipv6_recvpktinfo = true;
     }
 #endif
   }
@@ -2605,9 +2597,9 @@ static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr,
   }
 
   if (!tcp) {
-    if (g_socketUDPSendBuffer > 0) {
+    if (immutableConfig.d_socketUDPSendBuffer > 0) {
       try {
-        setSocketSendBuffer(socket, g_socketUDPSendBuffer);
+        setSocketSendBuffer(socket, immutableConfig.d_socketUDPSendBuffer);
       }
       catch (const std::exception& e) {
         warnlog(e.what());
@@ -2625,9 +2617,9 @@ static void setupLocalSocket(ClientState& clientState, const ComboAddress& addr,
       }
     }
 
-    if (g_socketUDPRecvBuffer > 0) {
+    if (immutableConfig.d_socketUDPRecvBuffer > 0) {
       try {
-        setSocketReceiveBuffer(socket, g_socketUDPRecvBuffer);
+        setSocketReceiveBuffer(socket, immutableConfig.d_socketUDPRecvBuffer);
       }
       catch (const std::exception& e) {
         warnlog(e.what());
@@ -2962,6 +2954,8 @@ static void parseParameters(int argc, char** argv, ComboAddress& clientAddress)
                                                 {nullptr, 0, nullptr, 0}}};
   int longindex = 0;
   string optstring;
+  dnsdist::configuration::RuntimeConfiguration newConfig;
+
   while (true) {
     // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
     int gotChar = getopt_long(argc, argv, "a:cC:e:g:hk:l:u:vV", longopts.data(), &longindex);
@@ -3006,17 +3000,23 @@ static void parseParameters(int argc, char** argv, ComboAddress& clientAddress)
       break;
     case 'k':
 #if defined HAVE_LIBSODIUM || defined(HAVE_LIBCRYPTO)
-      if (B64Decode(string(optarg), g_consoleKey) < 0) {
+    {
+      std::string consoleKey;
+      if (B64Decode(string(optarg), consoleKey) < 0) {
         cerr << "Unable to decode key '" << optarg << "'." << endl;
         // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
         exit(EXIT_FAILURE);
       }
+      dnsdist::configuration::updateImmutableConfiguration([&consoleKey](dnsdist::configuration::Configuration& config) {
+        config.d_consoleKey = std::move(consoleKey);
+      });
+    }
 #else
       cerr << "dnsdist has been built without libsodium or libcrypto, -k/--setkey is unsupported." << endl;
       // NOLINTNEXTLINE(concurrency-mt-unsafe): only one thread at this point
       exit(EXIT_FAILURE);
 #endif
-      break;
+    break;
     case 'l':
       g_cmdLine.locals.push_back(boost::trim_copy(string(optarg)));
       break;
@@ -3024,7 +3024,7 @@ static void parseParameters(int argc, char** argv, ComboAddress& clientAddress)
       g_cmdLine.uid = optarg;
       break;
     case 'v':
-      g_verbose = true;
+      newConfig.d_verbose = true;
       break;
     case 'V':
       reportFeatures();
@@ -3052,6 +3052,10 @@ static void parseParameters(int argc, char** argv, ComboAddress& clientAddress)
       g_cmdLine.remotes.emplace_back(*ptr);
     }
   }
+
+  dnsdist::configuration::updateRuntimeConfiguration([&newConfig](dnsdist::configuration::RuntimeConfiguration& config) {
+    config = std::move(newConfig);
+  });
 }
 static void setupPools()
 {
@@ -3286,7 +3290,9 @@ int main(int argc, char** argv)
     }
 #endif
     dnsdist::initRandom();
-    g_hashperturb = dnsdist::getRandomValue(0xffffffff);
+    dnsdist::configuration::updateImmutableConfiguration([](dnsdist::configuration::Configuration& config) {
+      config.d_hashPerturbation = dnsdist::getRandomValue(0xffffffff);
+    });
 
 #ifdef HAVE_XSK
     try {
@@ -3327,11 +3333,12 @@ int main(int argc, char** argv)
       g_ACL.setState(acl);
     }
 
-    auto consoleACL = g_consoleACL.getCopy();
-    for (const auto& mask : {"127.0.0.1/8", "::1/128"}) {
-      consoleACL.addMask(mask);
-    }
-    g_consoleACL.setState(consoleACL);
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      for (const auto& mask : {"127.0.0.1/8", "::1/128"}) {
+        config.d_consoleACL.addMask(mask);
+      }
+    });
+
     registerBuiltInWebHandlers();
 
     if (g_cmdLine.checkConfig) {
@@ -3356,13 +3363,7 @@ int main(int argc, char** argv)
 
     initFrontends();
 
-    g_configurationDone = true;
-
-    g_rings.init();
-
-    for (auto& frontend : g_frontends) {
-      setUpLocalBind(frontend);
-
+    for (const auto& frontend : g_frontends) {
       if (!frontend->tcp) {
         ++udpBindsCount;
       }
@@ -3371,6 +3372,20 @@ int main(int argc, char** argv)
       }
     }
 
+    if (dnsdist::configuration::getImmutableConfiguration().d_maxTCPClientThreads == 0 && tcpBindsCount > 0) {
+      dnsdist::configuration::updateImmutableConfiguration([](dnsdist::configuration::Configuration& config) {
+        config.d_maxTCPClientThreads = static_cast<size_t>(10);
+      });
+    }
+
+    g_configurationDone = true;
+
+    g_rings.init();
+
+    for (auto& frontend : g_frontends) {
+      setUpLocalBind(frontend);
+    }
+
     {
       std::string acls;
       auto aclEntries = g_ACL.getLocal()->toStringVector();
@@ -3384,7 +3399,7 @@ int main(int argc, char** argv)
     }
     {
       std::string acls;
-      auto aclEntries = g_consoleACL.getLocal()->toStringVector();
+      auto aclEntries = dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleACL.toStringVector();
       for (const auto& entry : aclEntries) {
         if (!acls.empty()) {
           acls += ", ";
@@ -3395,7 +3410,7 @@ int main(int argc, char** argv)
     }
 
 #if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBCRYPTO)
-    if (g_consoleEnabled && g_consoleKey.empty()) {
+    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleEnabled && dnsdist::configuration::getImmutableConfiguration().d_consoleKey.empty()) {
       warnlog("Warning, the console has been enabled via 'controlSocket()' but no key has been set with 'setKey()' so all connections will fail until a key has been set");
     }
 #endif
@@ -3411,19 +3426,11 @@ int main(int argc, char** argv)
       g_snmpAgent->run();
     }
 
-    if (!g_maxTCPClientThreads) {
-      g_maxTCPClientThreads = static_cast<size_t>(10);
-    }
-    else if (*g_maxTCPClientThreads == 0 && tcpBindsCount > 0) {
-      warnlog("setMaxTCPClientThreads() has been set to 0 while we are accepting TCP connections, raising to 1");
-      g_maxTCPClientThreads = 1;
-    }
-
     /* we need to create the TCP worker threads before the
        acceptor ones, otherwise we might crash when processing
        the first TCP query */
 #ifndef USE_SINGLE_ACCEPTOR_THREAD
-    g_tcpclientthreads = std::make_unique<TCPClientCollection>(*g_maxTCPClientThreads, std::vector<ClientState*>());
+    g_tcpclientthreads = std::make_unique<TCPClientCollection>(dnsdist::configuration::getImmutableConfiguration().d_maxTCPClientThreads, std::vector<ClientState*>());
 #endif
 
 #if defined(HAVE_DNS_OVER_HTTPS) && defined(HAVE_NGHTTP2)
@@ -3495,7 +3502,7 @@ int main(int argc, char** argv)
 #endif /* DISABLE_DYNBLOCKS */
 
 #ifndef DISABLE_SECPOLL
-    if (!g_secPollSuffix.empty()) {
+    if (!dnsdist::configuration::getCurrentRuntimeConfiguration().d_secPollSuffix.empty()) {
       thread secpollthread(secPollThread);
       secpollthread.detach();
     }
index d3c02c4995a83b750a7fe58077797a9408cf605d..398a5700014e616784c3af1a7d83de43bc14fffb 100644 (file)
@@ -38,6 +38,7 @@
 #include "circular_buffer.hh"
 #include "dnscrypt.hh"
 #include "dnsdist-cache.hh"
+#include "dnsdist-configuration.hh"
 #include "dnsdist-dynbpf.hh"
 #include "dnsdist-idstate.hh"
 #include "dnsdist-lbpolicies.hh"
 
 uint64_t uptimeOfProcess(const std::string& str);
 
-extern uint16_t g_ECSSourcePrefixV4;
-extern uint16_t g_ECSSourcePrefixV6;
-extern bool g_ECSOverride;
-
 using QTag = std::unordered_map<string, string>;
 
 class IncomingTCPConnectionState;
@@ -72,7 +69,7 @@ struct ClientState;
 struct DNSQuestion
 {
   DNSQuestion(InternalQueryState& ids_, PacketBuffer& data_) :
-    data(data_), ids(ids_), ecsPrefixLength(ids.origRemote.sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6), ecsOverride(g_ECSOverride)
+    data(data_), ids(ids_), ecsPrefixLength(ids.origRemote.sin4.sin_family == AF_INET ? dnsdist::configuration::getCurrentRuntimeConfiguration().d_ECSSourcePrefixV4 : dnsdist::configuration::getCurrentRuntimeConfiguration().d_ECSSourcePrefixV6), ecsOverride(dnsdist::configuration::getCurrentRuntimeConfiguration().d_ecsOverride)
   {
   }
   DNSQuestion(const DNSQuestion&) = delete;
@@ -210,113 +207,6 @@ struct DNSResponse : DNSQuestion
   const std::shared_ptr<DownstreamState>& d_downstream;
 };
 
-/* so what could you do:
-   drop,
-   fake up nxdomain,
-   provide actual answer,
-   allow & and stop processing,
-   continue processing,
-   modify header:    (servfail|refused|notimp), set TC=1,
-   send to pool */
-
-class DNSAction
-{
-public:
-  enum class Action : uint8_t
-  {
-    Drop,
-    Nxdomain,
-    Refused,
-    Spoof,
-    Allow,
-    HeaderModify,
-    Pool,
-    Delay,
-    Truncate,
-    ServFail,
-    None,
-    NoOp,
-    NoRecurse,
-    SpoofRaw,
-    SpoofPacket,
-    SetTag,
-  };
-  static std::string typeToString(const Action& action)
-  {
-    switch (action) {
-    case Action::Drop:
-      return "Drop";
-    case Action::Nxdomain:
-      return "Send NXDomain";
-    case Action::Refused:
-      return "Send Refused";
-    case Action::Spoof:
-      return "Spoof an answer";
-    case Action::SpoofPacket:
-      return "Spoof a raw answer from bytes";
-    case Action::SpoofRaw:
-      return "Spoof an answer from raw bytes";
-    case Action::Allow:
-      return "Allow";
-    case Action::HeaderModify:
-      return "Modify the header";
-    case Action::Pool:
-      return "Route to a pool";
-    case Action::Delay:
-      return "Delay";
-    case Action::Truncate:
-      return "Truncate over UDP";
-    case Action::ServFail:
-      return "Send ServFail";
-    case Action::SetTag:
-      return "Set Tag";
-    case Action::None:
-    case Action::NoOp:
-      return "Do nothing";
-    case Action::NoRecurse:
-      return "Set rd=0";
-    }
-
-    return "Unknown";
-  }
-
-  virtual Action operator()(DNSQuestion*, string* ruleresult) const = 0;
-  virtual ~DNSAction()
-  {
-  }
-  virtual string toString() const = 0;
-  virtual std::map<string, double> getStats() const
-  {
-    return {{}};
-  }
-  virtual void reload()
-  {
-  }
-};
-
-class DNSResponseAction
-{
-public:
-  enum class Action : uint8_t
-  {
-    Allow,
-    Delay,
-    Drop,
-    HeaderModify,
-    ServFail,
-    Truncate,
-    None
-  };
-  virtual Action operator()(DNSResponse*, string* ruleresult) const = 0;
-  virtual ~DNSResponseAction()
-  {
-  }
-  virtual string toString() const = 0;
-  virtual void reload()
-  {
-  }
-};
-
 struct DynBlock
 {
   DynBlock()
@@ -386,8 +276,6 @@ struct DynBlock
 
 extern GlobalStateHolder<NetmaskTree<DynBlock, AddressAndPortRange>> g_dynblockNMG;
 
-extern vector<pair<struct timeval, std::string>> g_confDelta;
-
 using pdns::stat_t;
 
 class BasicQPSLimiter
@@ -502,23 +390,6 @@ private:
   bool d_passthrough{true};
 };
 
-typedef std::unordered_map<string, unsigned int> QueryCountRecords;
-typedef std::function<std::tuple<bool, string>(const DNSQuestion* dq)> QueryCountFilter;
-struct QueryCount
-{
-  QueryCount()
-  {
-  }
-  ~QueryCount()
-  {
-  }
-  SharedLockGuarded<QueryCountRecords> records;
-  QueryCountFilter filter;
-  bool enabled{false};
-};
-
-extern QueryCount g_qcount;
-
 class XskPacket;
 class XskSocket;
 class XskWorker;
@@ -1092,10 +963,6 @@ public:
     }
     return latencyUsec;
   }
-
-  static int s_udpTimeout;
-  static bool s_randomizeSockets;
-  static bool s_randomizeIDs;
 };
 using servers_t = vector<std::shared_ptr<DownstreamState>>;
 
@@ -1158,7 +1025,6 @@ enum ednsHeaderFlags
 };
 
 extern GlobalStateHolder<SuffixMatchTree<DynBlock>> g_dynblockSMT;
-extern DNSAction::Action g_dynBlockAction;
 
 extern GlobalStateHolder<ServerPolicy> g_policy;
 extern GlobalStateHolder<servers_t> g_dstates;
@@ -1172,27 +1038,6 @@ extern std::vector<shared_ptr<DOHFrontend>> g_dohlocals;
 extern std::vector<shared_ptr<DOQFrontend>> g_doqlocals;
 extern std::vector<shared_ptr<DOH3Frontend>> g_doh3locals;
 extern std::vector<std::unique_ptr<ClientState>> g_frontends;
-extern bool g_truncateTC;
-extern bool g_fixupCase;
-extern int g_tcpRecvTimeout;
-extern int g_tcpSendTimeout;
-extern uint16_t g_maxOutstanding;
-extern std::atomic<bool> g_configurationDone;
-extern boost::optional<uint64_t> g_maxTCPClientThreads;
-extern uint64_t g_maxTCPQueuedConnections;
-extern size_t g_maxTCPQueriesPerConn;
-extern size_t g_maxTCPConnectionDuration;
-extern size_t g_tcpInternalPipeBufferSize;
-extern pdns::stat16_t g_cacheCleaningDelay;
-extern pdns::stat16_t g_cacheCleaningPercentage;
-extern uint32_t g_staleCacheEntriesTTL;
-extern bool g_apiReadWrite;
-extern std::string g_apiConfigDirectory;
-extern bool g_servFailOnNoPolicy;
-extern size_t g_udpVectorSize;
-extern bool g_allowEmptyResponse;
-extern uint32_t g_socketUDPSendBuffer;
-extern uint32_t g_socketUDPRecvBuffer;
 
 extern shared_ptr<BPFFilter> g_defaultBPFFilter;
 extern std::vector<std::shared_ptr<DynBPFFilter>> g_dynBPFFilters;
@@ -1204,7 +1049,7 @@ void setLuaSideEffect(); // set to report a side effect, cancelling all _no_ sid
 bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect
 void resetLuaSideEffect(); // reset to indeterminate state
 
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote);
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, bool allowEmptyResponse);
 
 bool checkQueryHeaders(const struct dnsheader& dnsHeader, ClientState& clientState);
 
@@ -1212,15 +1057,7 @@ extern std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
 bool handleDNSCryptQuery(PacketBuffer& packet, DNSCryptQuery& query, bool tcp, time_t now, PacketBuffer& response);
 bool checkDNSCryptQuery(const ClientState& clientState, PacketBuffer& query, std::unique_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp);
 
-#include "dnsdist-snmp.hh"
-
-extern bool g_snmpEnabled;
-extern bool g_snmpTrapsEnabled;
-extern std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent;
-extern bool g_addEDNSToSelfGeneratedResponses;
-
 extern std::set<std::string> g_capabilitiesToRetain;
-static const uint16_t s_udpIncomingBufferSize{1500}; // don't accept UDP queries larger than this value
 
 enum class ProcessQueryResult : uint8_t
 {
index fca9fd209de6e3419761aeab2066ad7449fa2b6f..8b89539c2eb89f524a4650ba77fc7969b5a08553 100644 (file)
@@ -34,8 +34,6 @@
 #include "dolog.hh"
 #include <unistd.h>
 
-bool g_verbose{false};
-
 BOOST_AUTO_TEST_SUITE(test_dnscrypt_cc)
 
 #ifdef HAVE_DNSCRYPT
index 0429e5c560908a0ce71a00cdb8a134450e551286..6163e1aead23bae2d7cc0195f0ca1a9c0793749d 100644 (file)
@@ -236,7 +236,7 @@ BOOST_AUTO_TEST_CASE(test_Query)
   }
 
   {
-    BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_ecs_prefix_length(&lightDQ), g_ECSSourcePrefixV4);
+    BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_ecs_prefix_length(&lightDQ), dnsdist::configuration::getCurrentRuntimeConfiguration().d_ECSSourcePrefixV4);
     dnsdist_ffi_dnsquestion_set_ecs_prefix_length(&lightDQ, 65535);
     BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_ecs_prefix_length(&lightDQ), 65535U);
   }
index a6fa8ff834ce6fdf2848639229d027549010d1a4..9fbdcbfd1af09e365b8d523baa14757e27f76a11 100644 (file)
@@ -31,6 +31,7 @@
 #include "dnsdist.hh"
 #include "dnsdist-ecs.hh"
 #include "dnsdist-internal-queries.hh"
+#include "dnsdist-snmp.hh"
 #include "dnsdist-tcp.hh"
 #include "dnsdist-xsk.hh"
 
@@ -1656,7 +1657,7 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
     BOOST_CHECK_EQUAL(zValue, 0);
-    BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
   }
 
   {
@@ -1671,7 +1672,7 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
     BOOST_CHECK_EQUAL(zValue, EDNS_HEADER_FLAG_DO);
-    BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
   }
 
   {
@@ -1686,7 +1687,7 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
     BOOST_CHECK_EQUAL(zValue, 0);
-    BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
   }
 
   {
@@ -1701,7 +1702,7 @@ BOOST_AUTO_TEST_CASE(test_addEDNSToQueryTurnedResponse)
     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dnsQuestion.getData().data()), dnsQuestion.getData().size(), &udpPayloadSize, &zValue), true);
     BOOST_CHECK_EQUAL(zValue, EDNS_HEADER_FLAG_DO);
-    BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
+    BOOST_CHECK_EQUAL(udpPayloadSize, dnsdist::configuration::getCurrentRuntimeConfiguration().d_payloadSizeSelfGenAnswers);
   }
 }
 
index 7d6569073cecce09762db884fbb256b17b5cc788..a3df9eff6a1dd4a467e5121ed9127c10f51cc1a1 100644 (file)
 #include "dnsdist.hh"
 #include "dnsdist-lua.hh"
 #include "dnsdist-lua-ffi.hh"
+#include "dnsdist-snmp.hh"
 #include "dolog.hh"
 
-uint16_t g_maxOutstanding{std::numeric_limits<uint16_t>::max()};
-
 #include "ext/luawrapper/include/LuaContext.hpp"
 RecursiveLockGuarded<LuaContext> g_lua{LuaContext()};
 
-bool g_snmpEnabled{false};
-bool g_snmpTrapsEnabled{false};
 std::unique_ptr<DNSDistSNMPAgent> g_snmpAgent{nullptr};
 
 #if BENCH_POLICIES
-bool g_verbose{true};
 #include "dnsdist-rings.hh"
 Rings g_rings;
 GlobalStateHolder<NetmaskTree<DynBlock>> g_dynblockNMG;
@@ -102,9 +98,6 @@ static DNSQuestion getDQ(const DNSName* providedName = nullptr)
 static void benchPolicy(const ServerPolicy& pol)
 {
 #if BENCH_POLICIES
-  bool existingVerboseValue = g_verbose;
-  g_verbose = false;
-
   std::vector<DNSName> names;
   names.reserve(1000);
   for (size_t idx = 0; idx < 1000; idx++) {
@@ -129,8 +122,6 @@ static void benchPolicy(const ServerPolicy& pol)
     }
   }
   cerr << pol.name << " took " << std::to_string(sw.udiff()) << " us for " << names.size() << endl;
-
-  g_verbose = existingVerboseValue;
 #endif /* BENCH_POLICIES */
 }
 
@@ -223,17 +214,23 @@ BOOST_AUTO_TEST_CASE(test_roundRobin)
   ServerPolicy::NumberedServerVector servers;
 
   /* selecting a server on an empty server list */
-  g_roundrobinFailOnNoServer = false;
+  dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_roundrobinFailOnNoServer = false;
+  });
   auto server = pol.getSelectedBackend(servers, dnsQuestion);
   BOOST_CHECK(server == nullptr);
 
   servers.emplace_back(1, std::make_shared<DownstreamState>(ComboAddress("192.0.2.1:53")));
 
-  /* servers start as 'down' but the RR policy returns a server unless g_roundrobinFailOnNoServer is set */
-  g_roundrobinFailOnNoServer = true;
+  /* servers start as 'down' but the RR policy returns a server unless d_roundrobinFailOnNoServer is set */
+  dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_roundrobinFailOnNoServer = true;
+  });
   server = pol.getSelectedBackend(servers, dnsQuestion);
   BOOST_CHECK(server == nullptr);
-  g_roundrobinFailOnNoServer = false;
+  dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_roundrobinFailOnNoServer = false;
+  });
   server = pol.getSelectedBackend(servers, dnsQuestion);
   BOOST_CHECK(server != nullptr);
 
@@ -466,8 +463,10 @@ BOOST_AUTO_TEST_CASE(test_whashed)
 
 BOOST_AUTO_TEST_CASE(test_chashed)
 {
-  bool existingVerboseValue = g_verbose;
-  g_verbose = false;
+  bool existingVerboseValue = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
+  dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_verbose = false;
+  });
 
   std::vector<DNSName> names;
   names.reserve(1000);
@@ -549,7 +548,9 @@ BOOST_AUTO_TEST_CASE(test_chashed)
   BOOST_CHECK_GT(got, expected / 2);
   BOOST_CHECK_LT(got, expected * 2);
 
-  g_verbose = existingVerboseValue;
+  dnsdist::configuration::updateRuntimeConfiguration([existingVerboseValue](dnsdist::configuration::RuntimeConfiguration& config) {
+    config.d_verbose = existingVerboseValue;
+  });
 }
 
 BOOST_AUTO_TEST_CASE(test_lua)
@@ -822,9 +823,6 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_whashed)
 
 BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed)
 {
-  bool existingVerboseValue = g_verbose;
-  g_verbose = false;
-
   std::vector<DNSName> names;
   names.reserve(1000);
   for (size_t idx = 0; idx < 1000; idx++) {
@@ -880,7 +878,6 @@ BOOST_AUTO_TEST_CASE(test_lua_ffi_chashed)
 
     benchPolicy(pol);
   }
-  g_verbose = existingVerboseValue;
   resetLuaContext();
 }
 
index c3f555a2257efaef054b952112e73717c949a286..a24341f13ab6b8eab7a7a22e2096d22b0f81c7d6 100644 (file)
@@ -472,7 +472,6 @@ private:
     /* we _NEED_ to set this function to empty otherwise we might get what was set
        by the last test, and we might not like it at all */
     s_processQuery = nullptr;
-    g_proxyProtocolACL.clear();
   }
 };
 
index 2934616ff769dec7272fa9ba599c4b5159e46109..85cb05b2da8a5eaf58b7165448454ac15f584d92 100644 (file)
@@ -37,8 +37,6 @@
 GlobalStateHolder<NetmaskGroup> g_ACL;
 GlobalStateHolder<servers_t> g_dstates;
 
-QueryCount g_qcount;
-
 const bool TCPIOHandler::s_disableConnectForUnitTests = true;
 
 bool checkDNSCryptQuery(const ClientState& cs, PacketBuffer& query, std::unique_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp)
@@ -71,7 +69,7 @@ ProcessQueryResult processQuery(DNSQuestion& dq, LocalHolders& holders, std::sha
   return ProcessQueryResult::Drop;
 }
 
-bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote)
+bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr<DownstreamState>& remote, bool allowEmptyResponse)
 {
   return true;
 }
@@ -456,8 +454,9 @@ struct TestFixture
     s_backendReadBuffer.clear();
     s_backendWriteBuffer.clear();
 
-    g_proxyProtocolACL.clear();
-    g_verbose = false;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_proxyProtocolACL.clear();
+    });
     IncomingTCPConnectionState::clearAllDownstreamConnections();
 
     /* we _NEED_ to set this function to empty otherwise we might get what was set
@@ -482,6 +481,7 @@ static void testInit(const std::string& name, TCPClientThreadData& threadData)
 
 BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
 {
+  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
   auto local = getBackendAddress("1", 80);
   ClientState localCS(local, true, false, 0, "", {}, true);
   auto tlsCtx = std::make_shared<MockupTLSCtx>();
@@ -656,7 +656,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
     state->handleIO();
     BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredReadConns = threadData.mplexer->getTimeouts(later, false);
     for (const auto& cbData : expiredReadConns) {
       BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
@@ -692,7 +692,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
     state->handleIO();
     BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredWriteConns = threadData.mplexer->getTimeouts(later, true);
     for (const auto& cbData : expiredWriteConns) {
       BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
@@ -729,6 +729,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_SelfAnswered, TestFixture)
 
 BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, TestFixture)
 {
+  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
   auto local = getBackendAddress("1", 80);
   ClientState localCS(local, true, false, 0, "", {}, true);
   auto tlsCtx = std::make_shared<MockupTLSCtx>();
@@ -751,8 +752,10 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, T
   {
     TEST_INIT("=> reading PP");
 
-    g_proxyProtocolACL.addMask("0.0.0.0/0");
-    g_proxyProtocolACL.addMask("::0/0");
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_proxyProtocolACL.addMask("0.0.0.0/0");
+      config.d_proxyProtocolACL.addMask("::0/0");
+    });
 
     auto proxyPayload = makeProxyHeader(true, ComboAddress("192.0.2.1"), ComboAddress("192.0.2.2"), {});
     BOOST_REQUIRE_GT(proxyPayload.size(), s_proxyProtocolMinimumHeaderSize);
@@ -791,8 +794,11 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, T
   {
     TEST_INIT("=> Invalid PP");
 
-    g_proxyProtocolACL.addMask("0.0.0.0/0");
-    g_proxyProtocolACL.addMask("::0/0");
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_proxyProtocolACL.addMask("0.0.0.0/0");
+      config.d_proxyProtocolACL.addMask("::0/0");
+    });
+
     auto proxyPayload = std::vector<uint8_t>(s_proxyProtocolMinimumHeaderSize);
     std::fill(proxyPayload.begin(), proxyPayload.end(), 0);
 
@@ -818,8 +824,11 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, T
   {
     TEST_INIT("=> timeout while reading PP");
 
-    g_proxyProtocolACL.addMask("0.0.0.0/0");
-    g_proxyProtocolACL.addMask("::0/0");
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_proxyProtocolACL.addMask("0.0.0.0/0");
+      config.d_proxyProtocolACL.addMask("::0/0");
+    });
+
     auto proxyPayload = makeProxyHeader(true, ComboAddress("192.0.2.1"), ComboAddress("192.0.2.2"), {});
     BOOST_REQUIRE_GT(proxyPayload.size(), s_proxyProtocolMinimumHeaderSize);
     s_readBuffer = query;
@@ -843,7 +852,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionWithProxyProtocol_SelfAnswered, T
     state->handleIO();
     BOOST_CHECK_EQUAL(threadData.mplexer->run(&now), 0);
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredReadConns = threadData.mplexer->getTimeouts(later, false);
     for (const auto& cbData : expiredReadConns) {
       BOOST_CHECK_EQUAL(cbData.first, state->d_handler.getDescriptor());
@@ -1660,7 +1669,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendNoOOOR, TestFixture)
     /* 101 queries on the same connection, check that the maximum number of queries kicks in */
     TEST_INIT("=> 101 queries on the same connection");
 
-    g_maxTCPQueriesPerConn = 100;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_maxTCPQueriesPerConn = 100;
+    });
 
     size_t count = 101;
 
@@ -1714,7 +1725,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendNoOOOR, TestFixture)
     /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
     IncomingTCPConnectionState::clearAllDownstreamConnections();
 
-    g_maxTCPQueriesPerConn = 0;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_maxTCPQueriesPerConn = 0;
+    });
 #endif
   }
 
@@ -1759,6 +1772,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnection_BackendNoOOOR, TestFixture)
 
 BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
 {
+  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
   auto local = getBackendAddress("1", 80);
   ClientState localCS(local, true, false, 0, "", {}, true);
   /* enable out-of-order on the front side */
@@ -1952,7 +1966,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     TEST_INIT("=> 3 queries sent to the backend, 1 self-answered, 1 new query sent to the backend which responds to the first query right away, then to the last one, then the connection to the backend times out");
 
     // increase the client timeout for that test, we want the backend to timeout first
-    g_tcpRecvTimeout = 5;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_tcpRecvTimeout = 5;
+    });
 
     PacketBuffer expectedWriteBuffer;
     PacketBuffer expectedBackendWriteBuffer;
@@ -2092,7 +2108,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     IncomingTCPConnectionState::clearAllDownstreamConnections();
 
     // restore the client timeout
-    g_tcpRecvTimeout = 2;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_tcpRecvTimeout = 2;
+    });
   }
 
   {
@@ -2252,7 +2270,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     }
 
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredConns = threadData.mplexer->getTimeouts(later, false);
     BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
     for (const auto& cbData : expiredConns) {
@@ -2527,7 +2545,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     }
 
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredConns = threadData.mplexer->getTimeouts(later, false);
     BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
     for (const auto& cbData : expiredConns) {
@@ -2543,7 +2561,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     }
 
     later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     expiredConns = threadData.mplexer->getTimeouts(later, false);
     BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
     for (const auto& cbData : expiredConns) {
@@ -3557,7 +3575,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
 
     /* make sure that the backend's timeout is shorter than the client's */
     backend->d_config.tcpConnectTimeout = 1;
-    g_tcpRecvTimeout = 5;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_tcpRecvTimeout = 5;
+    });
 
     bool timeout = false;
     s_steps = {
@@ -3616,7 +3636,9 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
 
     /* restore */
     backend->d_config.tcpSendTimeout = 30;
-    g_tcpRecvTimeout = 2;
+    dnsdist::configuration::updateRuntimeConfiguration([](dnsdist::configuration::RuntimeConfiguration& config) {
+      config.d_tcpRecvTimeout = 2;
+    });
 
     /* we need to clear them now, otherwise we end up with dangling pointers to the steps via the TLS context, etc */
     /* we have no connection to clear, because there was a timeout! */
@@ -3876,7 +3898,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
     }
 
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredConns = threadData.mplexer->getTimeouts(later);
     BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
     for (const auto& cbData : expiredConns) {
@@ -3899,6 +3921,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR, TestFixture)
 
 BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR, TestFixture)
 {
+  const auto tcpRecvTimeout = dnsdist::configuration::getCurrentRuntimeConfiguration().d_tcpRecvTimeout;
   auto local = getBackendAddress("1", 80);
   ClientState localCS(local, true, false, 0, "", {}, true);
   /* enable out-of-order on the front side */
@@ -4160,7 +4183,7 @@ BOOST_FIXTURE_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR, TestFixture)
     }
 
     struct timeval later = now;
-    later.tv_sec += g_tcpRecvTimeout + 1;
+    later.tv_sec += tcpRecvTimeout + 1;
     auto expiredConns = threadData.mplexer->getTimeouts(later);
     BOOST_CHECK_EQUAL(expiredConns.size(), 1U);
     for (const auto& cbData : expiredConns) {
index 25c49521b7e3fe84d9041bce32ccfa58ebeebdfb..2552db568439fd92be1be17cc8f512c2234e9ec5 100644 (file)
@@ -46,7 +46,7 @@
           errlog("Unable to bind to %s: %s", ca.toStringWithPort(), strerr(errno));
 
    Will log to stdout. Will syslog in any case with LOG_INFO,
-   LOG_WARNING, LOG_ERR respectively. If g_verbose=false, vinfolog is a noop.
+   LOG_WARNING, LOG_ERR respectively. If verbose=false, vinfolog is a noop.
    More generically, dolog(someiostream, "Hello %s", stream) will log to someiostream
 
    This will happily print a string to %d! Doesn't do further format processing.
@@ -81,9 +81,6 @@ void dolog(O& outputStream, const char* formatStr, T value, const Args&... args)
 }
 
 #if !defined(RECURSOR)
-// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
-extern bool g_verbose;
-
 #ifdef DNSDIST
 namespace dnsdist::logging
 {
@@ -96,10 +93,6 @@ public:
     ISO8601
   };
 
-  static void setVerbose(bool value = true)
-  {
-    g_verbose = value;
-  }
   static void setSyslog(bool value = true)
   {
     s_syslog = value;
@@ -123,10 +116,6 @@ public:
   {
     s_verboseStream = std::move(stream);
   }
-  static bool getVerbose()
-  {
-    return g_verbose;
-  }
   static bool getSyslog()
   {
     return s_syslog;
@@ -235,9 +224,16 @@ void verboselog(const char* formatStr, const Args&... args)
 #endif /* DNSDIST */
 }
 
-#define vinfolog \
-  if (g_verbose) \
+#ifdef DNSDIST
+#include "dnsdist-configuration.hh"
+
+#define vinfolog                                                          \
+  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) \
   verboselog
+#else
+#define vinfolog \
+  infolog
+#endif
 
 template <typename... Args>
 void infolog(const char* formatStr, const Args&... args)
@@ -258,9 +254,8 @@ void errlog(const char* formatStr, const Args&... args)
 }
 
 #else // RECURSOR
-#define g_verbose 0
 #define vinfolog \
-  if (g_verbose) \
+  if (false)     \
   infolog
 
 template <typename... Args>
index a44c72110f5c74cfe79367de0f89d79d34155ece..5c20d3b9c5893edd9abd94c7fe50922d47477c47 100644 (file)
@@ -37,7 +37,7 @@ struct ProxyProtocolValue
   enum class Types : uint8_t { PP_TLV_ALPN = 0x01, PP_TLV_SSL = 0x20 };
 };
 
-static const size_t s_proxyProtocolMinimumHeaderSize = 16;
+static constexpr size_t s_proxyProtocolMinimumHeaderSize = 16;
 
 std::string makeLocalProxyHeader();
 std::string makeProxyHeader(bool tcp, const ComboAddress& source, const ComboAddress& destination, const std::vector<ProxyProtocolValue>& values);
index edee311ad078d5cc48408c30c614fee7b15933c1..81107cbc068e3a03607228ce25bd506290b5d47d 100644 (file)
@@ -7,6 +7,19 @@
 
 const bool TCPIOHandler::s_disableConnectForUnitTests = false;
 
+namespace {
+bool shouldDoVerboseLogging()
+{
+#ifdef DNSDIST
+  return dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
+#elif defined(RECURSOR)
+  return false;
+#else
+  return true;
+#endif
+}
+}
+
 #ifdef HAVE_LIBSODIUM
 #include <sodium.h>
 #endif /* HAVE_LIBSODIUM */
@@ -83,7 +96,7 @@ public:
 
     if (!d_conn) {
       vinfolog("Error creating TLS object");
-      if (g_verbose) {
+      if (shouldDoVerboseLogging()) {
         ERR_print_errors_fp(stderr);
       }
       throw std::runtime_error("Error creating TLS object");
@@ -103,7 +116,7 @@ public:
 
     if (!d_conn) {
       vinfolog("Error creating TLS object");
-      if (g_verbose) {
+      if (shouldDoVerboseLogging()) {
         ERR_print_errors_fp(stderr);
       }
       throw std::runtime_error("Error creating TLS object");
@@ -201,7 +214,7 @@ public:
     }
 #endif
     else {
-      if (g_verbose) {
+      if (shouldDoVerboseLogging()) {
         throw std::runtime_error("Error while processing TLS connection: (" + std::to_string(error) + ") " + libssl_get_error_string());
       } else {
         throw std::runtime_error("Error while processing TLS connection: " + std::to_string(error));
index 8420529811e30b22d75fdee2ec09c040f281dc5a..191a161e5c5fcb7d43f2cfaf11362683662b2362 100644 (file)
@@ -566,7 +566,7 @@ public:
     return d_conn->getAsyncFDs();
   }
 
-  const static bool s_disableConnectForUnitTests;
+  static const bool s_disableConnectForUnitTests;
 
 private:
   std::unique_ptr<TLSConnection> d_conn{nullptr};