]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: reload proxy settings on rec_control reload-acls
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 12 Feb 2025 12:38:42 +0000 (13:38 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Fri, 14 Feb 2025 14:08:14 +0000 (15:08 +0100)
Fixes #14096

pdns/recursordist/pdns_recursor.cc
pdns/recursordist/rec-main.cc
pdns/recursordist/rec-main.hh
pdns/recursordist/rec-rust-lib/cxxsupport.cc
pdns/recursordist/rec-rust-lib/table.py

index a59ee8ab437c5a6ad52c66946df111cf6723858f..ae10b11cfe55c32953262109c40a8ecf86735cdb 100644 (file)
@@ -59,6 +59,9 @@ thread_local std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t>>> t_
 thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
 thread_local std::shared_ptr<NetmaskGroup> t_allowNotifyFrom;
 thread_local std::shared_ptr<notifyset_t> t_allowNotifyFor;
+thread_local std::shared_ptr<NetmaskGroup> t_proxyProtocolACL;
+thread_local std::shared_ptr<std::set<ComboAddress>> t_proxyProtocolExceptions;
+
 __thread struct timeval g_now; // timestamp, updated (too) frequently
 
 using listenSocketsAddresses_t = map<int, ComboAddress>; // is shared across all threads right now
@@ -2150,7 +2153,16 @@ void requestWipeCaches(const DNSName& canon)
 
 bool expectProxyProtocol(const ComboAddress& from, const ComboAddress& listenAddress)
 {
-  return g_proxyProtocolACL.match(from) && g_proxyProtocolExceptions.count(listenAddress) == 0;
+  if (!t_proxyProtocolACL) {
+    return false;
+  }
+  if (t_proxyProtocolACL->match(from)) {
+    if (!t_proxyProtocolExceptions) {
+      return true;
+    }
+    return t_proxyProtocolExceptions->count(listenAddress) == 0;
+  }
+  return false;
 }
 
 // fromaddr: the address the query is coming from
@@ -2437,7 +2449,8 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
 
 static void handleNewUDPQuestion(int fileDesc, FDMultiplexer::funcparam_t& /* var */) // NOLINT(readability-function-cognitive-complexity): https://github.com/PowerDNS/pdns/issues/12791
 {
-  static const size_t maxIncomingQuerySize = g_proxyProtocolACL.empty() ? 512 : (512 + g_proxyProtocolMaximumSize);
+  const bool proxyActive = t_proxyProtocolACL && !t_proxyProtocolACL->empty();
+  static const size_t maxIncomingQuerySize = !proxyActive ? 512 : (512 + g_proxyProtocolMaximumSize);
   static thread_local std::string data;
   ComboAddress fromaddr; // the address the query is coming from
   ComboAddress source; // the address we assume the query is coming from, might be set by proxy protocol
index 3fae0825f6ae39677a4cdd0565e55230429fd978..221d76de596fb85015cff2a7565814c10e00b02e 100644 (file)
@@ -106,8 +106,8 @@ std::unique_ptr<nod::UniqueResponseDB> g_udrDBp;
 std::atomic<bool> statsWanted;
 uint32_t g_disthashseed;
 bool g_useIncomingECS;
-NetmaskGroup g_proxyProtocolACL;
-std::set<ComboAddress> g_proxyProtocolExceptions;
+static shared_ptr<NetmaskGroup> g_initialProxyProtocolACL;
+static shared_ptr<std::set<ComboAddress>> g_initialProxyProtocolExceptions;
 boost::optional<ComboAddress> g_dns64Prefix{boost::none};
 DNSName g_dns64PrefixReverse;
 unsigned int g_maxChainLength;
@@ -1388,11 +1388,25 @@ void* pleaseSupplantAllowNotifyFor(std::shared_ptr<notifyset_t> allowNotifyFor)
   return nullptr;
 }
 
+void* pleaseSupplantProxyProtocolSettings(std::shared_ptr<NetmaskGroup> acl, std::shared_ptr<std::set<ComboAddress>> except)
+{
+  t_proxyProtocolACL = std::move(acl);
+  t_proxyProtocolExceptions = std::move(except);
+  return nullptr;
+}
+
 void parseACLs()
 {
   auto log = g_slog->withName("config");
 
   static bool l_initialized;
+  const std::array<string, 6> aclNames = {
+    "allow-from-file",
+    "allow-from",
+    "allow-notify-from-file",
+    "allow-notify-from",
+    "proxy-protocol-from",
+    "proxy-protocol-exceptions"};
 
   if (l_initialized) { // only reload configuration file on second call
 
@@ -1434,6 +1448,8 @@ void parseACLs()
         throw runtime_error("Unable to re-parse configuration file '" + configName + "'");
       }
       ::arg().preParseFile(configName, "allow-notify-from");
+      ::arg().preParseFile(configName, "proxy-protocol-from");
+      ::arg().preParseFile(configName, "proxy-protocol-exceptions");
 
       ::arg().preParseFile(configName, "include-dir");
       ::arg().preParse(g_argc, g_argv, "include-dir");
@@ -1443,28 +1459,18 @@ void parseACLs()
       ::arg().gatherIncludes(::arg()["include-dir"], ".conf", extraConfigs);
 
       for (const std::string& fileName : extraConfigs) {
-        if (!::arg().preParseFile(fileName, "allow-from-file", ::arg()["allow-from-file"])) {
-          throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'");
-        }
-        if (!::arg().preParseFile(fileName, "allow-from", ::arg()["allow-from"])) {
-          throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'");
-        }
-
-        if (!::arg().preParseFile(fileName, "allow-notify-from-file", ::arg()["allow-notify-from-file"])) {
-          throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'");
-        }
-        if (!::arg().preParseFile(fileName, "allow-notify-from", ::arg()["allow-notify-from"])) {
-          throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'");
+        for (const auto& aclName : aclNames) {
+          if (!::arg().preParseFile(fileName, aclName, ::arg()[aclName])) {
+            throw runtime_error("Unable to re-parse configuration file include '" + fileName + "'");
+          }
         }
       }
     }
   }
   // Process command line args potentially overriding settings read from file
-  ::arg().preParse(g_argc, g_argv, "allow-from-file");
-  ::arg().preParse(g_argc, g_argv, "allow-from");
-
-  ::arg().preParse(g_argc, g_argv, "allow-notify-from-file");
-  ::arg().preParse(g_argc, g_argv, "allow-notify-from");
+  for (const auto& aclName : aclNames) {
+    ::arg().preParse(g_argc, g_argv, aclName);
+  }
 
   auto allowFrom = parseACL("allow-from-file", "allow-from", log);
 
@@ -1486,6 +1492,28 @@ void parseACLs()
   // coverity[copy_constructor_call] maybe this can be avoided, but be careful as pointers get passed to other threads
   broadcastFunction([=] { return pleaseSupplantAllowNotifyFrom(allowNotifyFrom); });
 
+  std::shared_ptr<NetmaskGroup> proxyProtocolACL;
+  std::shared_ptr<std::set<ComboAddress>> proxyProtocolExceptions;
+  if (!::arg()["proxy-protocol-from"].empty()) {
+    proxyProtocolACL = std::make_shared<NetmaskGroup>();
+    proxyProtocolACL->toMasks(::arg()["proxy-protocol-from"]);
+
+    std::vector<std::string> vec;
+    stringtok(vec, ::arg()["proxy-protocol-exceptions"], ", ");
+    if (!vec.empty()) {
+      proxyProtocolExceptions = std::make_shared<std::set<ComboAddress>>();
+      for (const auto& sockAddrStr : vec) {
+        ComboAddress sockAddr(sockAddrStr, 53);
+        proxyProtocolExceptions->emplace(sockAddr);
+      }
+    }
+  }
+  g_initialProxyProtocolACL = proxyProtocolACL;
+  g_initialProxyProtocolExceptions = proxyProtocolExceptions;
+
+  // coverity[copy_constructor_call] maybe this can be avoided, but be careful as pointers get passed to other threads
+  broadcastFunction([=] { return pleaseSupplantProxyProtocolSettings(proxyProtocolACL, proxyProtocolExceptions); });
+
   l_initialized = true;
 }
 
@@ -2216,13 +2244,18 @@ static int serviceMain(Logr::log_t log)
     return ret;
   }
 
-  g_proxyProtocolACL.toMasks(::arg()["proxy-protocol-from"]);
-  {
+  if (!::arg()["proxy-protocol-from"].empty()) {
+    g_initialProxyProtocolACL = std::make_shared<NetmaskGroup>();
+    g_initialProxyProtocolACL->toMasks(::arg()["proxy-protocol-from"]);
+
     std::vector<std::string> vec;
     stringtok(vec, ::arg()["proxy-protocol-exceptions"], ", ");
-    for (const auto& sockAddrStr : vec) {
-      ComboAddress sockAddr(sockAddrStr, 53);
-      g_proxyProtocolExceptions.emplace(sockAddr);
+    if (!vec.empty()) {
+      g_initialProxyProtocolExceptions = std::make_shared<std::set<ComboAddress>>();
+      for (const auto& sockAddrStr : vec) {
+        ComboAddress sockAddr(sockAddrStr, 53);
+        g_initialProxyProtocolExceptions->emplace(sockAddr);
+      }
     }
   }
   g_proxyProtocolMaximumSize = ::arg().asNum("proxy-protocol-maximum-size");
@@ -2834,6 +2867,8 @@ static void recursorThread()
       t_allowFrom = *g_initialAllowFrom.lock();
       t_allowNotifyFrom = *g_initialAllowNotifyFrom.lock();
       t_allowNotifyFor = *g_initialAllowNotifyFor.lock();
+      t_proxyProtocolACL = g_initialProxyProtocolACL;
+      t_proxyProtocolExceptions = g_initialProxyProtocolExceptions;
       t_udpclientsocks = std::make_unique<UDPClientSocks>();
       t_tcpClientCounts = std::make_unique<tcpClientCounts_t>();
       if (g_proxyMapping) {
index d18afcb3aeb4c21575405c39f4d046efcd785016..0a31cba49e3bc4e51306b1b8c2c69609000bb360 100644 (file)
@@ -224,12 +224,12 @@ extern thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
 extern thread_local std::shared_ptr<NetmaskGroup> t_allowNotifyFrom;
 extern thread_local std::shared_ptr<notifyset_t> t_allowNotifyFor;
 extern thread_local std::unique_ptr<UDPClientSocks> t_udpclientsocks;
+extern thread_local std::shared_ptr<NetmaskGroup> t_proxyProtocolACL;
+extern thread_local std::shared_ptr<std::set<ComboAddress>> t_proxyProtocolExceptions;
 extern bool g_useIncomingECS;
 extern boost::optional<ComboAddress> g_dns64Prefix;
 extern DNSName g_dns64PrefixReverse;
 extern uint64_t g_latencyStatSize;
-extern NetmaskGroup g_proxyProtocolACL;
-extern std::set<ComboAddress> g_proxyProtocolExceptions;
 extern std::atomic<bool> g_statsWanted;
 extern uint32_t g_disthashseed;
 extern int g_argc;
index 89845cb26ce332a5362dee9b346aa46bfbb2cf75..772d21edbe694d729655f6f8b4be10c6453af764 100644 (file)
@@ -448,6 +448,8 @@ void pdns::settings::rec::setArgsForACLRelatedSettings(Recursorsettings& setting
   ::arg().set("allow-from-file") = to_arg(settings.incoming.allow_from_file);
   ::arg().set("allow-notify-from") = to_arg(settings.incoming.allow_notify_from);
   ::arg().set("allow-notify-from-file") = to_arg(settings.incoming.allow_notify_from_file);
+  ::arg().set("proxy-protocol-from") = to_arg(settings.incoming.proxy_protocol_from);
+  ::arg().set("proxy-protocol-exceptions") = to_arg(settings.incoming.proxy_protocol_exceptions);
 }
 
 void pdns::settings::rec::to_yaml(uint64_t& field, const std::string& val)
index e07e176a65f3e2b4b19cf435e6f1c71b9c5e38c1..33007c2a27186f71809552f3e8ec23f1866f65c6 100644 (file)
@@ -2196,7 +2196,9 @@ Note that once a Proxy Protocol header has been received, the source address fro
 The dnsdist docs have `more information about the PROXY protocol <https://dnsdist.org/advanced/passing-source-address.html#proxy-protocol>`_.
  ''',
         'versionadded' : '4.4.0',
-        'versionchanged' : ('5.0.5', 'YAML settings only: previously this was defined as a string instead of a sequence')
+        'versionchanged' : [('5.0.5', 'YAML settings only: previously this was defined as a string instead of a sequence'),
+                            ('5.3.0', '``rec_control reload-acls`` reloads this setting')],
+        'runtime': ['reload-acls (since 5.3.0)'],
     },
     {
         'name' : 'proxy_protocol_exceptions',
@@ -2210,6 +2212,8 @@ If no port is specified, port 53 is assumed.
 This is typically used to provide an easy to use address and port to send debug queries to.
  ''',
         'versionadded' : '5.1.0',
+        'versionchanged' : ('5.3.0', '``rec_control reload-acls`` reloads this setting'),
+        'runtime': ['reload-acls (since 5.3.0)'],
     },
     {
         'name' : 'proxy_protocol_maximum_size',