]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Bring back listening on multiple web server addresses
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 11 Jul 2025 08:47:26 +0000 (10:47 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 11 Jul 2025 08:47:26 +0000 (10:47 +0200)
This was broken during the refactoring of the configuration between
1.9.x and 2.0.x.

Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
12 files changed:
pdns/dnsdistdist/dnsdist-configuration-yaml.cc
pdns/dnsdistdist/dnsdist-configuration.hh
pdns/dnsdistdist/dnsdist-lua.cc
pdns/dnsdistdist/dnsdist-settings-definitions.yml
pdns/dnsdistdist/dnsdist-web.cc
pdns/dnsdistdist/dnsdist-web.hh
pdns/dnsdistdist/dnsdist.cc
regression-tests.dnsdist/test_API.py
regression-tests.dnsdist/test_OutgoingDOH.py
regression-tests.dnsdist/test_OutgoingTLS.py
regression-tests.dnsdist/test_TLSSessionResumption.py
regression-tests.dnsdist/test_Yaml.py

index 5c9b59ad9178f805ca4a87876e6d5ab11929246c..d0be262901e9556545493671e65a86fa156a164b 100644 (file)
@@ -792,15 +792,15 @@ static void loadBinds(const ::rust::Vec<dnsdist::rust::settings::BindConfigurati
 
 static void loadWebServer(const dnsdist::rust::settings::WebserverConfiguration& webConfig)
 {
-  ComboAddress local;
-  try {
-    local = ComboAddress{std::string(webConfig.listen_address)};
-  }
-  catch (const PDNSException& e) {
-    throw std::runtime_error(std::string("Error parsing the bind address for the webserver: ") + e.reason);
-  }
-  dnsdist::configuration::updateRuntimeConfiguration([local, &webConfig](dnsdist::configuration::RuntimeConfiguration& config) {
-    config.d_webServerAddress = local;
+  dnsdist::configuration::updateRuntimeConfiguration([&webConfig](dnsdist::configuration::RuntimeConfiguration& config) {
+    for (const auto& address : webConfig.listen_addresses) {
+      try {
+        config.d_webServerAddresses.emplace(ComboAddress(std::string(address)));
+      }
+      catch (const PDNSException& exp) {
+        throw std::runtime_error(std::string("Error parsing bind address for the webserver: ") + exp.reason);
+      }
+    }
     if (!webConfig.password.empty()) {
       auto holder = std::make_shared<CredentialsHolder>(std::string(webConfig.password), webConfig.hash_plaintext_credentials);
       if (!holder->wasHashed() && holder->isHashingAvailable()) {
@@ -1077,7 +1077,7 @@ bool loadConfigurationFromFile(const std::string& fileName, [[maybe_unused]] boo
     }
 #endif /* DISABLE_CARBON */
 
-    if (!globalConfig.webserver.listen_address.empty()) {
+    if (!globalConfig.webserver.listen_addresses.empty()) {
       const auto& webConfig = globalConfig.webserver;
       loadWebServer(webConfig);
     }
index 29903199d26bed3b993792948d6f19b470184210..75702e6fd668d6ef058bd711e80c6fad1ef30688 100644 (file)
@@ -127,7 +127,7 @@ struct RuntimeConfiguration
   NetmaskGroup d_proxyProtocolACL;
   NetmaskGroup d_consoleACL;
   NetmaskGroup d_webServerACL;
-  std::optional<ComboAddress> d_webServerAddress{std::nullopt};
+  std::set<ComboAddress> d_webServerAddresses;
   dnsdist::QueryCount::Configuration d_queryCountConfig;
   ComboAddress d_consoleServerAddress{"127.0.0.1:5199"};
   std::string d_consoleKey;
index 3dc3592ef67b34a6630ed62d0c82116e976fc522..7c0a23d1b9ff6b217ab9b77fe13a42bf94fc8c39 100644 (file)
@@ -1069,7 +1069,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
     }
 
     dnsdist::configuration::updateRuntimeConfiguration([local](dnsdist::configuration::RuntimeConfiguration& config) {
-      config.d_webServerAddress = local;
+      config.d_webServerAddresses.emplace(local);
     });
 
     if (dnsdist::configuration::isImmutableConfigurationDone()) {
@@ -1077,7 +1077,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
         auto sock = Socket(local.sin4.sin_family, SOCK_STREAM, 0);
         sock.bind(local, true);
         sock.listen(5);
-        thread thr(dnsdist::webserver::WebserverThread, std::move(sock));
+        thread thr(dnsdist::webserver::WebserverThread, local, std::move(sock));
         thr.detach();
       }
       catch (const std::exception& e) {
index b6d4711cbacac8f853d8418c768d3ae4d3165a45..a82bc4132210b2caef36a92f08762ee24ae3c722 100644 (file)
@@ -403,10 +403,10 @@ key_value_stores:
 
 webserver:
   parameters:
-    - name: "listen_address"
-      type: "String"
+    - name: "listen_addresses"
+      type: "Vec<String>"
       default: ""
-      description: "IP address and port to listen on"
+      description: "IP addresses and ports to listen on"
     - name: "password"
       type: "String"
       default: ""
index 2cba82f5e0340bf96ce5007b2f4102e9a6bcb1f2..de657f3ee0667ef2eb7d77e87da96fd1a8deec09 100644 (file)
@@ -1914,23 +1914,22 @@ void setMaxConcurrentConnections(size_t max)
   s_connManager.setMaxConcurrentConnections(max);
 }
 
-void WebserverThread(Socket sock)
+void WebserverThread(ComboAddress listeningAddress, Socket sock)
 {
   setThreadName("dnsdist/webserv");
   // coverity[auto_causes_copy]
-  const auto local = *dnsdist::configuration::getCurrentRuntimeConfiguration().d_webServerAddress;
-  infolog("Webserver launched on %s", local.toStringWithPort());
+  infolog("Webserver launched on %s", listeningAddress.toStringWithPort());
 
   {
     const auto& config = dnsdist::configuration::getCurrentRuntimeConfiguration();
     if (!config.d_webPassword && config.d_dashboardRequiresAuthentication) {
-      warnlog("Webserver launched on %s without a password set!", local.toStringWithPort());
+      warnlog("Webserver launched on %s without a password set!", listeningAddress.toStringWithPort());
     }
   }
 
   for (;;) {
     try {
-      ComboAddress remote(local);
+      ComboAddress remote(listeningAddress);
       int fileDesc = SAccept(sock.getHandle(), remote);
 
       if (!isClientAllowedByACL(remote)) {
index 9acff20f9807cd0a7893d0242edddcabd2e8d553..bd6e9e1eee2d1fd092a8e481c511e9794b90d5e2 100644 (file)
@@ -6,7 +6,7 @@
 
 namespace dnsdist::webserver
 {
-void WebserverThread(Socket sock);
+void WebserverThread(ComboAddress listeningAddress, Socket sock);
 void setMaxConcurrentConnections(size_t max);
 void registerBuiltInWebHandlers();
 void clearWebHandlers();
index 9d760f842dfe4cf9fbedb509a802267fdf875465..4b69356e1423adead33460f89587376ad1d95a91 100644 (file)
@@ -3317,7 +3317,7 @@ static void startFrontends()
 struct ListeningSockets
 {
   Socket d_consoleSocket{-1};
-  Socket d_webServerSocket{-1};
+  std::vector<std::pair<ComboAddress, Socket>> d_webServerSockets;
 };
 
 static ListeningSockets initListeningSockets()
@@ -3337,12 +3337,12 @@ static ListeningSockets initListeningSockets()
     }
   }
 
-  if (currentConfig.d_webServerAddress) {
-    const auto& local = *currentConfig.d_webServerAddress;
+  for (const auto& local : currentConfig.d_webServerAddresses) {
     try {
-      result.d_webServerSocket = Socket(local.sin4.sin_family, SOCK_STREAM, 0);
-      result.d_webServerSocket.bind(local, true);
-      result.d_webServerSocket.listen(5);
+      auto webServerSocket = Socket(local.sin4.sin_family, SOCK_STREAM, 0);
+      webServerSocket.bind(local, true);
+      webServerSocket.listen(5);
+      result.d_webServerSockets.emplace_back(local, std::move(webServerSocket));
     }
     catch (const std::exception& exp) {
       errlog("Unable to bind to web server socket on %s: %s", local.toStringWithPort(), exp.what());
@@ -3615,8 +3615,8 @@ int main(int argc, char** argv)
       std::thread consoleControlThread(dnsdist::console::controlThread, std::move(listeningSockets.d_consoleSocket));
       consoleControlThread.detach();
     }
-    if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_webServerAddress) {
-      std::thread webServerThread(dnsdist::webserver::WebserverThread, std::move(listeningSockets.d_webServerSocket));
+    for (auto& [listeningAddress, socket] : listeningSockets.d_webServerSockets) {
+      std::thread webServerThread(dnsdist::webserver::WebserverThread, std::move(listeningAddress), std::move(socket));
       webServerThread.detach();
     }
 
index dfdda817f8a3313beb91f5867c33922325dba714..9afc1f4f5fe39211bf6db50c6ab9156cf375af4e 100644 (file)
@@ -434,11 +434,12 @@ class TestAPIServerDown(APITestsBase):
 class TestAPIWritable(APITestsBase):
     __test__ = True
     _APIWriteDir = '/tmp'
-    _config_params = ['_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed', '_APIWriteDir']
+    _config_params = ['_testServerPort', '_webServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed', '_APIWriteDir']
     _config_template = """
     setACL({"127.0.0.1/32", "::1/128"})
-    newServer{address="127.0.0.1:%s"}
-    webserver("127.0.0.1:%s")
+    newServer{address="127.0.0.1:%d"}
+    webserver("127.0.0.1:%d")
+    webserver("127.0.0.2:%d")
     setWebserverConfig({password="%s", apiKey="%s"})
     setAPIWritable(true, "%s")
     """
index d5e8faffb56c7055c5c6c157258a32e3b1374525..8e6cd41c41ec74a6b5c0cc5055869745bd8cfa53 100644 (file)
@@ -370,7 +370,8 @@ backends:
     health_checks:
       mode: "UP"
 webserver:
-  listen_address: "127.0.0.1:%d"
+  listen_addresses:
+    - "127.0.0.1:%d"
   password: "%s"
   api_key: "%s"
   acl:
index d701b2712fdc2599dce6586ef772cf98d6b2d2c7..159436b85bd5c184c9c81c39d3d8acbec7874930 100644 (file)
@@ -184,7 +184,8 @@ backends:
       ca_store: "ca.pem"
       subject_name: "powerdns.com"
 webserver:
-  listen_address: "127.0.0.1:%d"
+  listen_addresses:
+    - "127.0.0.1:%d"
   password: "%s"
   api_key: "%s"
   acl:
index b46eded2cb899e642af0898d7c8f60705d795e02..8760c2b45186bf9bdadfed67160e48c03b399708 100644 (file)
@@ -320,7 +320,8 @@ class TestTLSSessionResumptionDOTIdenticalFrontends(DNSDistTest):
     _config_params = []
     _yaml_config_template = """---
 webserver:
-  listen_address: "127.0.0.1:%d"
+  listen_addresses:
+    - "127.0.0.1:%d"
   password: "%s"
   api_key: "%s"
   acl:
index 1abed07c2f87bf0d6661e08d7d0c38a35458929f..bf756abcf3021de40109c713a3885ea1319e759c 100644 (file)
@@ -7,7 +7,9 @@ class TestYaml(DNSDistTest):
 
     _yaml_config_template = """---
 webserver:
-  listen_address: "127.0.0.1:%d"
+  listen_addresses:
+    - "127.0.0.2:%d"
+    - "127.0.0.1:%d"
   acl:
     - 127.0.0.0/8
 
@@ -113,12 +115,13 @@ response_rules:
       type: "TC"
 """
     _webServerPort = pickAvailablePort()
+    _webServerPort2 = pickAvailablePort()
     _dnsDistPort = pickAvailablePort()
     _consoleKey = DNSDistTest.generateConsoleKey()
     _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
     _consolePort = pickAvailablePort()
     _testServerPort = pickAvailablePort()
-    _yaml_config_params = ['_webServerPort', '_consolePort', '_consoleKeyB64', '_dnsDistPort', '_testServerPort']
+    _yaml_config_params = ['_webServerPort', '_webServerPort2', '_consolePort', '_consoleKeyB64', '_dnsDistPort', '_testServerPort']
     _config_params = []
 
     def testForwarded(self):