From d9beed455baf10811992a96f6266605ae6caeee0 Mon Sep 17 00:00:00 2001 From: Miod Vallat Date: Mon, 18 May 2026 08:38:44 +0200 Subject: [PATCH 1/4] Advise configuring webserver-password more strongly. Signed-off-by: Miod Vallat --- docs/http-api/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/http-api/index.rst b/docs/http-api/index.rst index a1a490cf88bb..0bbfb22a83c8 100644 --- a/docs/http-api/index.rst +++ b/docs/http-api/index.rst @@ -26,8 +26,9 @@ The following webserver related configuration items are available: .. warning:: - To achieve defense-in-depth, expose the webserver only to client addresses that have a real need for access. + To achieve defense-in-depth, expose the webserver only to client addresses that have a real need for access, and configure a webserver password. Network access is configured by setting :ref:`setting-webserver-address` and :ref:`setting-webserver-allow-from`. + Password protection is configured by setting :ref:`setting-webserver-password`. Metrics Endpoint From af049bb750933b434a3bab5d01ea1c53d99e4bd4 Mon Sep 17 00:00:00 2001 From: Miod Vallat Date: Mon, 18 May 2026 08:42:10 +0200 Subject: [PATCH 2/4] Sort webserver options. Signed-off-by: Miod Vallat --- docs/settings.rst | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index 00907053c83c..21987db1e310 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -2138,6 +2138,28 @@ IP Address for webserver/API to listen on. Webserver/API access is only allowed from these subnets. Ignored if ``webserver-address`` is set to a UNIX domain socket. +.. _setting-webserver-connection-timeout: + +``webserver-connection-timeout`` +-------------------------------- +.. versionadded:: 4.8.5 + +- Integer +- Default: 5 + +Request/response timeout in seconds. + +.. _setting-webserver-cross-origin-request-header: + +``webserver-cross-origin-request-header`` +----------------------------------------- +.. versionadded:: 5.1.0 + +- String +- Default: empty + +The value if the access-control-allow-origin HTTP header to include. This header is not included if the value is empty. + .. _setting-webserver-hash-plaintext-credentials: ``webserver-hash-plaintext-credentials`` @@ -2212,17 +2234,6 @@ Maximum request/response body size in megabytes. Maximum number of allowed concurrent connections to the web server. -.. _setting-webserver-connection-timeout: - -``webserver-connection-timeout`` --------------------------------- -.. versionadded:: 4.8.5 - -- Integer -- Default: 5 - -Request/response timeout in seconds. - .. _setting-webserver-password: ``webserver-password`` @@ -2255,17 +2266,6 @@ Ignored if ``webserver-address`` is set to a UNIX domain socket. If the webserver should print arguments. -.. _setting-webserver-cross-origin-request-header: - -``webserver-cross-origin-request-header`` ------------------------------------------ -.. versionadded:: 5.1.0 - -- String -- Default: empty - -The value if the access-control-allow-origin HTTP header to include. This header is not included if the value is empty. - .. _setting-write-pid: ``write-pid`` From cf956ecf14d7c6564a97addee0180e58b43d5428 Mon Sep 17 00:00:00 2001 From: Miod Vallat Date: Mon, 18 May 2026 09:31:23 +0200 Subject: [PATCH 3/4] Correctly reject a negative number of entries for search. Signed-off-by: Miod Vallat --- pdns/ws-auth.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pdns/ws-auth.cc b/pdns/ws-auth.cc index 15bab2f928b1..a0920cddd42e 100644 --- a/pdns/ws-auth.cc +++ b/pdns/ws-auth.cc @@ -2906,7 +2906,12 @@ static void apiServerSearchData(HttpRequest* req, HttpResponse* resp) throw ApiException("Query q can't be blank"); } if (!sMaxVar.empty()) { - maxEnts = std::stoi(sMaxVar); + try { + pdns::checked_stoi_into(maxEnts, sMaxVar); + } + catch (std::logic_error&) { + throw ApiException("Invalid value for maximum entries"); + } } if (maxEnts < 1) { throw ApiException("Maximum entries must be larger than 0"); From 1ff63d597d88f02a72d8f73c4fe580a2a984b36b Mon Sep 17 00:00:00 2001 From: Miod Vallat Date: Mon, 18 May 2026 09:31:47 +0200 Subject: [PATCH 4/4] Replace a bunch of std::stoi with pdns::checked_stoi. Signed-off-by: Miod Vallat --- modules/bindbackend/binddnssec.cc | 2 +- modules/pipebackend/pipebackend.cc | 2 +- pdns/backends/gsql/gsqlbackend.cc | 4 ++-- pdns/dnssecinfra.cc | 2 +- pdns/json.cc | 2 +- pdns/minicurl.cc | 6 ++---- pdns/pkcs11signers.cc | 2 +- pdns/ws-auth.cc | 2 +- 8 files changed, 10 insertions(+), 12 deletions(-) diff --git a/modules/bindbackend/binddnssec.cc b/modules/bindbackend/binddnssec.cc index 29fcd049108a..a92f936377af 100644 --- a/modules/bindbackend/binddnssec.cc +++ b/modules/bindbackend/binddnssec.cc @@ -384,7 +384,7 @@ bool Bind2Backend::addDomainKey(const ZoneName& name, const KeyData& key, int64_ SSqlStatement::row_t row; d_GetLastInsertedKeyIdQuery_stmt->nextRow(row); ASSERT_ROW_COLUMNS("get-last-inserted-key-id-query", row, 1); - keyId = std::stoi(row[0]); + pdns::checked_stoi_into(keyId, row[0]); d_GetLastInsertedKeyIdQuery_stmt->reset(); if (keyId == 0) { // No insert took place, report as error. diff --git a/modules/pipebackend/pipebackend.cc b/modules/pipebackend/pipebackend.cc index 75e6cd5555e8..274f62ea11bf 100644 --- a/modules/pipebackend/pipebackend.cc +++ b/modules/pipebackend/pipebackend.cc @@ -320,7 +320,7 @@ bool PipeBackend::get(DNSResourceRecord& r) } if (d_abiVersion >= 3) { - r.scopeMask = std::stoi(parts[1]); + pdns::checked_stoi_into(r.scopeMask, parts[1]); r.auth = (parts[2] == "1"); parts.erase(parts.begin() + 1, parts.begin() + 3); } diff --git a/pdns/backends/gsql/gsqlbackend.cc b/pdns/backends/gsql/gsqlbackend.cc index 3513eee483e2..b58d741dceca 100644 --- a/pdns/backends/gsql/gsqlbackend.cc +++ b/pdns/backends/gsql/gsqlbackend.cc @@ -1066,7 +1066,7 @@ bool GSQLBackend::addDomainKey(const ZoneName& name, const KeyData& key, int64_t if (d_AddDomainKeyQuery_stmt->hasNextRow()) { SSqlStatement::row_t row; d_AddDomainKeyQuery_stmt->nextRow(row); - keyId = std::stoi(row[0]); + pdns::checked_stoi_into(keyId, row[0]); d_AddDomainKeyQuery_stmt->reset(); return true; } else { @@ -1088,7 +1088,7 @@ bool GSQLBackend::addDomainKey(const ZoneName& name, const KeyData& key, int64_t SSqlStatement::row_t row; d_GetLastInsertedKeyIdQuery_stmt->nextRow(row); ASSERT_ROW_COLUMNS("get-last-inserted-key-id-query", row, 1); - keyId = std::stoi(row[0]); + pdns::checked_stoi_into(keyId, row[0]); d_GetLastInsertedKeyIdQuery_stmt->reset(); if (keyId == 0) { // No insert took place, report as error. diff --git a/pdns/dnssecinfra.cc b/pdns/dnssecinfra.cc index ffdea63a0837..fc0758d7c3b1 100644 --- a/pdns/dnssecinfra.cc +++ b/pdns/dnssecinfra.cc @@ -343,7 +343,7 @@ static map ISCStringtoMap(const string& argStr) continue; } if (pdns_iequals(key,"slot")) { - int slot = std::stoi(value); + auto slot = pdns::checked_stoi(value); stormap["slot"]=std::to_string(slot); continue; } diff --git a/pdns/json.cc b/pdns/json.cc index 457f09b0ba77..6a0b296139be 100644 --- a/pdns/json.cc +++ b/pdns/json.cc @@ -37,7 +37,7 @@ static inline int intFromJsonInternal(const Json& container, const std::string& if (val.is_string()) { try { - return std::stoi(val.string_value()); + return pdns::checked_stoi(val.string_value()); } catch (std::logic_error&) { throw JsonException("Key '" + string(key) + "' is not a valid number"); } diff --git a/pdns/minicurl.cc b/pdns/minicurl.cc index bc975a91591c..c1182cb126b8 100644 --- a/pdns/minicurl.cc +++ b/pdns/minicurl.cc @@ -136,10 +136,8 @@ void MiniCurl::setupURL(const std::string& str, const ComboAddress* rem, const C std::size_t found = host4.find(':'); vector ports{80, 443}; if (found != std::string::npos) { - int port = std::stoi(host4.substr(found + 1)); - if (port <= 0 || port > 65535) - throw std::overflow_error("Invalid port number"); - ports = {(uint16_t)port}; + auto port = pdns::checked_stoi(host4.substr(found + 1)); + ports = {port}; host4 = host4.substr(0, found); } diff --git a/pdns/pkcs11signers.cc b/pdns/pkcs11signers.cc index a2566b587372..d11f7f615f0f 100644 --- a/pdns/pkcs11signers.cc +++ b/pdns/pkcs11signers.cc @@ -723,7 +723,7 @@ CK_RV Pkcs11Slot::HuntSlot(Logr::log_t slog, const string& tokenId, CK_SLOT_ID & // see if we can find it with slotId try { - slotId = std::stoi(tokenId); + pdns::checked_stoi_into(slotId, tokenId); if ((err = functions->C_GetSlotInfo(slotId, info))) { SLOG(g_log<parameters.count("key_id") == 1) { - inquireKeyId = std::stoi(req->parameters["key_id"]); + pdns::checked_stoi_into(inquireKeyId, req->parameters["key_id"]); apiZoneCryptoKeysCheckKeyExists(zonename, inquireKeyId, dnsseckeeper); } return inquireKeyId;