Skip to content

Commit 138e88d

Browse files
committed
dnsdist: add opt-in fatal bind failures for console and webserver
Introduce opt-in fatal behavior when binding the webserver socket or the control socket fails, to make startup failures visible to service managers like systemd. Expose the feature in both configuration styles: - Lua: setConsoleBindFatal(bool), setWebserverBindFatal(bool) - YAML: console.bind_fatal, webserver.bind_fatal When enabled, dnsdist now exits with failure on bind exceptions for: - control socket listeners - webserver listeners Wire the new settings through runtime configuration loading, Lua configuration items, and YAML parsing, and add console completion entries for both setters. Update documentation with new config functions and behavior notes. Add regression tests in test_BindFatal.py for Lua and YAML, validating: - default/not set: bind failures are non-fatal - explicit false: bind failures are non-fatal - explicit true: bind failures are fatal at startup Signed-off-by: b.courtois <b.courtois@criteo.com>
1 parent d0c0af3 commit 138e88d

9 files changed

Lines changed: 311 additions & 0 deletions

File tree

pdns/dnsdistdist/dnsdist-configuration-yaml.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,7 @@ static void loadWebServer(const Context& context, const dnsdist::rust::settings:
915915
dnsdist::webserver::setMaxConcurrentConnections(webConfig.max_concurrent_connections);
916916
config.d_apiConfigDirectory = std::string(webConfig.api_configuration_directory);
917917
config.d_apiReadWrite = webConfig.api_read_write;
918+
config.d_webserverBindFatal = webConfig.bind_fatal;
918919
});
919920
}
920921

@@ -1037,6 +1038,7 @@ static void handleConsoleConfiguration(const dnsdist::rust::settings::ConsoleCon
10371038
config.d_consoleACL.addMask(std::string(aclEntry));
10381039
}
10391040
B64Decode(std::string(consoleConf.key), config.d_consoleKey);
1041+
config.d_consoleBindFatal = consoleConf.bind_fatal;
10401042
});
10411043
}
10421044
}

pdns/dnsdistdist/dnsdist-configuration.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ struct RuntimeConfiguration
181181
bool d_allowEmptyResponse{false};
182182
bool d_dropEmptyQueries{false};
183183
bool d_consoleEnabled{false};
184+
bool d_consoleBindFatal{false};
185+
bool d_webserverBindFatal{false};
184186
bool d_logConsoleConnections{true};
185187
bool d_addEDNSToSelfGeneratedResponses{true};
186188
bool d_applyACLToProxiedClients{false};

pdns/dnsdistdist/dnsdist-console-completion.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ static std::vector<dnsdist::console::completion::ConsoleKeyword> s_consoleKeywor
239239
{"setCacheCleaningPercentage", true, "num", "Set the percentage of the cache that the cache cleaning algorithm will try to free by removing expired entries. By default (100), all expired entries are remove"},
240240
{"setConsistentHashingBalancingFactor", true, "factor", "Set the balancing factor for bounded-load consistent hashing"},
241241
{"setConsoleACL", true, "{netmask, netmask}", "replace the console ACL set with these netmasks"},
242+
{"setConsoleBindFatal", true, "enable", "whether a failure to bind the console control socket is fatal"},
242243
{"setConsoleConnectionsLogging", true, "enabled", "whether to log the opening and closing of console connections"},
243244
{"setConsoleMaximumConcurrentConnections", true, "max", "Set the maximum number of concurrent console connections"},
244245
{"setConsoleOutputMaxMsgSize", true, "messageSize", "set console message maximum size in bytes, default is 10 MB"},
@@ -309,6 +310,7 @@ static std::vector<dnsdist::console::completion::ConsoleKeyword> s_consoleKeywor
309310
{"setVerbose", true, "bool", "set whether log messages at the verbose level will be logged"},
310311
{"setVerboseHealthChecks", true, "bool", "set whether health check errors will be logged"},
311312
{"setVerboseLogDestination", true, "destination file", "Set a destination file to write the 'verbose' log messages to, instead of sending them to syslog and/or the standard output"},
313+
{"setWebserverBindFatal", true, "enable", "whether a failure to bind a web server socket is fatal"},
312314
{"setWebserverConfig", true, "[{password=string, apiKey=string, customHeaders, statsRequireAuthentication, prometheusAddInstanceLabel=bool}]", "Updates webserver configuration"},
313315
{"setWeightedBalancingFactor", true, "factor", "Set the balancing factor for bounded-load weighted policies (whashed, wrandom)"},
314316
{"setWHashedPerturbation", true, "value", "Set the hash perturbation value to be used in the whashed policy instead of a random one, allowing to have consistent whashed results on different instance"},

pdns/dnsdistdist/dnsdist-lua-configuration-items.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ static const std::map<std::string, BooleanConfigurationItems> s_booleanConfigIte
7575
{"setRoundRobinFailOnNoServer", {[](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_roundrobinFailOnNoServer = newValue; }}},
7676
{"setDropEmptyQueries", {[](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_dropEmptyQueries = newValue; }}},
7777
{"setAllowEmptyResponse", {[](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_allowEmptyResponse = newValue; }}},
78+
{"setConsoleBindFatal", {[](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_consoleBindFatal = newValue; }}},
7879
{"setConsoleConnectionsLogging", {[](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_logConsoleConnections = newValue; }}},
80+
{"setWebserverBindFatal", {[](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_webserverBindFatal = newValue; }}},
7981
{"setProxyProtocolApplyACLToProxiedClients", {[](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_applyACLToProxiedClients = newValue; }}},
8082
{"setAddEDNSToSelfGeneratedResponses", {[](dnsdist::configuration::RuntimeConfiguration& config, bool newValue) { config.d_addEDNSToSelfGeneratedResponses = newValue; }}},
8183
};

pdns/dnsdistdist/dnsdist-lua.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
11231123
g_outputBuffer = "Unable to bind to webserver socket on " + local.toStringWithPort() + ": " + e.what();
11241124
SLOG(errlog("Unable to bind to webserver socket on %s: %s", local.toStringWithPort(), e.what()),
11251125
getLogger("webserver")->error(Logr::Error, e.what(), "Error while trying to bind the web server socket", "network.local.address", Logging::Loggable(local)));
1126+
if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_webserverBindFatal) {
1127+
_exit(EXIT_FAILURE);
1128+
}
11261129
}
11271130
}
11281131
});
@@ -1243,6 +1246,9 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
12431246
g_outputBuffer = "Unable to bind to control socket on " + local.toStringWithPort() + ": " + exp.what();
12441247
SLOG(errlog("Unable to bind to control socket on %s: %s", local.toStringWithPort(), exp.what()),
12451248
getLogger("controlSocket")->error(Logr::Error, exp.what(), "Unable to bind to console's control socket", "network.local.address", Logging::Loggable(local)));
1249+
if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_consoleBindFatal) {
1250+
_exit(EXIT_FAILURE);
1251+
}
12461252
}
12471253
}
12481254
});

pdns/dnsdistdist/dnsdist-settings-definitions.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,13 @@ webserver:
466466
type: "bool"
467467
default: "false"
468468
description: "Allow modifications via the API. Optionally saving these changes to disk. Modifications done via the API will not be written to the configuration by default and will not persist after a reload"
469+
- name: "bind_fatal"
470+
type: "bool"
471+
default: "false"
472+
lua-name: "setWebserverBindFatal"
473+
internal-field-name: "d_webserverBindFatal"
474+
runtime-configurable: true
475+
description: "Whether a failure to bind a web server socket should be fatal"
469476

470477
console:
471478
description: "Console-related settings"
@@ -503,6 +510,13 @@ console:
503510
internal-field-name: "d_consoleMaxConcurrentConnections"
504511
runtime-configurable: false
505512
description: "Set the maximum number of concurrent console connection"
513+
- name: "bind_fatal"
514+
type: "bool"
515+
default: "false"
516+
lua-name: "setConsoleBindFatal"
517+
internal-field-name: "d_consoleBindFatal"
518+
runtime-configurable: true
519+
description: "Whether a failure to bind the console control socket should be fatal"
506520

507521
ebpf_map:
508522
description: "An ``eBPF`` map that is used to share data with kernel-land ``AF_XDP``/``XSK``, ``socket filter`` or ``XDP`` programs. Maps can be pinned to a filesystem path, which makes their content persistent across restarts and allows external programs to read their content and to add new entries. :program:`dnsdist` will try to load maps that are pinned to a filesystem path on startups, inheriting any existing entries, and fall back to creating them if they do not exist yet. Note that the user :program`dnsdist` is running under must have the right privileges to read and write to the given file, and to go through all the directories in the path leading to that file. The pinned path must be on a filesystem of type ``BPF``, usually below ``/sys/fs/bpf/``"

pdns/dnsdistdist/dnsdist.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3553,6 +3553,9 @@ static ListeningSockets initListeningSockets()
35533553
catch (const std::exception& exp) {
35543554
SLOG(errlog("Unable to bind to control socket on %s: %s", local.toStringWithPort(), exp.what()),
35553555
dnsdist::logging::getTopLogger("setup")->error(Logr::Error, exp.what(), "Unable to bind to console control socket", "network.local.address", Logging::Loggable(local)));
3556+
if (currentConfig.d_consoleBindFatal) {
3557+
_exit(EXIT_FAILURE);
3558+
}
35563559
}
35573560
}
35583561

@@ -3566,6 +3569,9 @@ static ListeningSockets initListeningSockets()
35663569
catch (const std::exception& exp) {
35673570
SLOG(errlog("Unable to bind to web server socket on %s: %s", local.toStringWithPort(), exp.what()),
35683571
dnsdist::logging::getTopLogger("setup")->error(Logr::Error, exp.what(), "Unable to bind to web server socket", "network.local.address", Logging::Loggable(local)));
3572+
if (currentConfig.d_webserverBindFatal) {
3573+
_exit(EXIT_FAILURE);
3574+
}
35693575
}
35703576
}
35713577

pdns/dnsdistdist/docs/reference/config.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,14 @@ Control Socket, Console and Webserver
361361

362362
Generate and print an encryption key.
363363

364+
.. function:: setConsoleBindFatal(enable)
365+
366+
.. versionadded:: 2.2.0
367+
368+
Whether a failure to bind a console control socket is fatal.
369+
370+
:param bool enabled: Default to false.
371+
364372
.. function:: setConsoleConnectionsLogging(enabled)
365373

366374
Whether to log the opening and closing of console connections.
@@ -458,6 +466,14 @@ Webserver configuration
458466
:param bool allow: Set to true to allow modification through the API
459467
:param str dir: A valid directory where the configuration files will be written by the API.
460468

469+
.. function:: setWebserverBindFatal(enable)
470+
471+
.. versionadded:: 2.2.0
472+
473+
Whether a failure to bind a web server socket is fatal.
474+
475+
:param bool enabled: Default to false.
476+
461477
.. function:: setWebserverConfig(options)
462478

463479
.. versionchanged:: 1.5.0

0 commit comments

Comments
 (0)