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()) {
}
#endif /* DISABLE_CARBON */
- if (!globalConfig.webserver.listen_address.empty()) {
+ if (!globalConfig.webserver.listen_addresses.empty()) {
const auto& webConfig = globalConfig.webserver;
loadWebServer(webConfig);
}
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;
}
dnsdist::configuration::updateRuntimeConfiguration([local](dnsdist::configuration::RuntimeConfiguration& config) {
- config.d_webServerAddress = local;
+ config.d_webServerAddresses.emplace(local);
});
if (dnsdist::configuration::isImmutableConfigurationDone()) {
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) {
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: ""
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)) {
namespace dnsdist::webserver
{
-void WebserverThread(Socket sock);
+void WebserverThread(ComboAddress listeningAddress, Socket sock);
void setMaxConcurrentConnections(size_t max);
void registerBuiltInWebHandlers();
void clearWebHandlers();
struct ListeningSockets
{
Socket d_consoleSocket{-1};
- Socket d_webServerSocket{-1};
+ std::vector<std::pair<ComboAddress, Socket>> d_webServerSockets;
};
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());
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();
}
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")
"""
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:
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:
_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:
_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
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):