Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: dnsdist@packages.debian.org, team@security.debian.org
Control: affects -1 + src:dnsdist
Please unblock package dnsdist
[ Reason ]
New upstream bugfix release with fix for security issue CVE-2025-30193 #1106207
I've picked the complete upstream minor release instead of
cherry-picking the single fix, as the remaining diff is small. In
addition to the CVE fix, we get: 1) fix for newer systemd versions / socket-family sandboxing, 2) fix for newer prometheus scrapers,
3) tiny feature to get the incoming network interface in Lua
scripting.
[ Impact ]
CVE-2025-30193 will be unfixed if not uploaded.
[ Tests ]
I've reviewed the diff, did a test build and did a runtime test on a
very small setup.
[ Risks ]
IMO the security fix is the large part of the diff, the rest seems
trivial to me.
[ Checklist ]
[x] all changes are documented in the d/changelog
[x] I reviewed all changes and I approve them
[x] attach debdiff against the package in testing
[ Other info ]
Nothing I'm aware of.
unblock dnsdist/1.9.10-1
diff -Nru dnsdist-1.9.9/configure dnsdist-1.9.10/configure
--- dnsdist-1.9.9/configure 2025-04-29 11:46:28.000000000 +0200
+++ dnsdist-1.9.10/configure 2025-05-20 11:13:44.000000000 +0200
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for dnsdist 1.9.9.
+# Generated by GNU Autoconf 2.71 for dnsdist 1.9.10.
#
#
# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -618,8 +618,8 @@
# Identity of this package.
PACKAGE_NAME='dnsdist'
PACKAGE_TARNAME='dnsdist'
-PACKAGE_VERSION='1.9.9'
-PACKAGE_STRING='dnsdist 1.9.9'
+PACKAGE_VERSION='1.9.10'
+PACKAGE_STRING='dnsdist 1.9.10'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1645,7 +1645,7 @@
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures dnsdist 1.9.9 to adapt to many kinds of systems. +\`configure' configures dnsdist 1.9.10 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1716,7 +1716,7 @@
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of dnsdist 1.9.9:";;
+ short | recursive ) echo "Configuration of dnsdist 1.9.10:";;
esac
cat <<\_ACEOF
@@ -1951,7 +1951,7 @@
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-dnsdist configure 1.9.9
+dnsdist configure 1.9.10
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2440,7 +2440,7 @@
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by dnsdist $as_me 1.9.9, which was
+It was created by dnsdist $as_me 1.9.10, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -3932,7 +3932,7 @@
# Define the identity of the package.
PACKAGE='dnsdist'
- VERSION='1.9.9'
+ VERSION='1.9.10'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.hsourceItfName.empty() ? "not set" : d_config.sourceItfName, error.what());
@@ -28627,7 +28627,7 @@
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by dnsdist $as_me 1.9.9, which was
+This file was extended by dnsdist $as_me 1.9.10, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -28695,7 +28695,7 @@
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
-dnsdist config.status 1.9.9
+dnsdist config.status 1.9.10
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
diff -Nru dnsdist-1.9.9/configure.ac dnsdist-1.9.10/configure.ac
--- dnsdist-1.9.9/configure.ac 2025-04-29 11:46:19.000000000 +0200
+++ dnsdist-1.9.10/configure.ac 2025-05-20 11:13:35.000000000 +0200
@@ -1,6 +1,6 @@
AC_PREREQ([2.69])
-AC_INIT([dnsdist], [1.9.9])
+AC_INIT([dnsdist], [1.9.10])
AM_INIT_AUTOMAKE([foreign tar-ustar dist-bzip2 no-dist-gzip parallel-tests 1.11 subdir-objects])
AM_SILENT_RULES([yes])
AC_CONFIG_MACRO_DIR([m4])
diff -Nru dnsdist-1.9.9/credentials.hh dnsdist-1.9.10/credentials.hh
--- dnsdist-1.9.9/credentials.hh 2025-04-29 11:46:03.000000000 +0200
+++ dnsdist-1.9.10/credentials.hh 2025-05-20 11:13:25.000000000 +0200
@@ -21,7 +21,7 @@
*/
#pragma once
-#include <memory>
+#include <cstdint>
#include <string>
class SensitiveData
diff -Nru dnsdist-1.9.9/debian/changelog dnsdist-1.9.10/debian/changelog
--- dnsdist-1.9.9/debian/changelog 2025-04-29 14:27:45.000000000 +0200
+++ dnsdist-1.9.10/debian/changelog 2025-05-21 10:30:17.000000000 +0200
@@ -1,3 +1,10 @@
+dnsdist (1.9.10-1) unstable; urgency=medium
+
+ * New upstream version 1.9.10 including fix for CVE-2025-30193
+ (Closes: #1106207)
+
+ -- Chris Hofstaedtler <zeha@debian.org> Wed, 21 May 2025 10:30:17 +0200
+
dnsdist (1.9.9-1) unstable; urgency=medium
* New upstream version 1.9.9 including fix for CVE-2025-30194
diff -Nru dnsdist-1.9.9/dnsdist.1 dnsdist-1.9.10/dnsdist.1
--- dnsdist-1.9.9/dnsdist.1 2025-04-29 11:47:05.000000000 +0200
+++ dnsdist-1.9.10/dnsdist.1 2025-05-20 11:14:13.000000000 +0200
@@ -27,7 +27,7 @@
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "DNSDIST" "1" "Apr 29, 2025" "" "dnsdist"
+.TH "DNSDIST" "1" "May 20, 2025" "" "dnsdist"
.SH NAME
dnsdist \- A DNS and DoS aware, scriptable loadbalancer
.SH SYNOPSIS
diff -Nru dnsdist-1.9.9/dnsdist-backend.cc dnsdist-1.9.10/dnsdist-backend.cc --- dnsdist-1.9.9/dnsdist-backend.cc 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-backend.cc 2025-05-20 11:13:25.000000000 +0200
@@ -144,7 +144,12 @@
}
catch (const std::runtime_error& error) {
if (initialAttempt || g_verbose) {
- infolog("Error connecting to new server with address %s: %s", d_config.remote.toStringWithPort(), error.what());
+ if (!IsAnyAddress(d_config.sourceAddr) || !d_config.sourceItfName.empty()) {
+ infolog("Error connecting to new server with address %s (source address: %s, source interface: %s): %s", d_config.remote.toStringWithPort(), IsAnyAddress(d_config.sourceAddr) ? "not set" : d_config.sourceAddr.toString(), d_config.
+ }DownstreamState>& backend, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs)
+ else {
+ infolog("Error connecting to new server with address %s: %s", d_config.remote.toStringWithPort(), error.what());
+ }
}
connected = false;
break;
@@ -974,6 +979,13 @@
serv.first = idx++;
}
*servers = std::make_shared<const ServerPolicy::NumberedServerVector>(std::move(newServers));
+
+ if ((*servers)->size() == 1) {
+ d_tcpOnly = server->isTCPOnly();
+ }
+ else if (!server->isTCPOnly()) {
+ d_tcpOnly = false;
+ }
}
void ServerPool::removeServer(shared_ptr<DownstreamState>& server)
@@ -984,8 +996,10 @@
auto newServers = std::make_shared<ServerPolicy::NumberedServerVector>(*(*servers));
size_t idx = 1;
bool found = false;
+ bool tcpOnly = true;
for (auto it = newServers->begin(); it != newServers->end();) {
if (found) {
+ tcpOnly = tcpOnly && it->second->isTCPOnly();
/* we need to renumber the servers placed
after the removed one, for Lua (custom policies) */
it->first = idx++;
@@ -995,9 +1009,11 @@
it = newServers->erase(it);
found = true;
} else {
+ tcpOnly = tcpOnly && it->second->isTCPOnly();
idx++;
it++;
}
}
+ d_tcpOnly = tcpOnly;
*servers = std::move(newServers);
}
diff -Nru dnsdist-1.9.9/dnsdist.cc dnsdist-1.9.10/dnsdist.cc
--- dnsdist-1.9.9/dnsdist.cc 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist.cc 2025-05-20 11:13:25.000000000 +0200
@@ -1447,6 +1447,9 @@
if (selectedBackend && selectedBackend->isTCPOnly()) {
willBeForwardedOverUDP = false;
}
+ else if (!selectedBackend) {
+ willBeForwardedOverUDP = !serverPool->isTCPOnly();
+ }
uint32_t allowExpired = selectedBackend ? 0 : g_staleCacheEntriesTTL;
@@ -1693,9 +1696,13 @@
bool doh = dnsQuestion.ids.du != nullptr;
bool failed = false;
+ dnsQuestion.ids.d_proxyProtocolPayloadSize = 0;
if (downstream->d_config.useProxyProtocol) {
try {
- addProxyProtocol(dnsQuestion, &dnsQuestion.ids.d_proxyProtocolPayloadSize);
+ size_t proxyProtocolPayloadSize = 0;
+ if (addProxyProtocol(dnsQuestion, &proxyProtocolPayloadSize)) {
+ dnsQuestion.ids.d_proxyProtocolPayloadSize += proxyProtocolPayloadSize;
+ }
}
catch (const std::exception& e) {
vinfolog("Adding proxy protocol payload to %s query from %s failed: %s", (dnsQuestion.ids.du ? "DoH" : ""), dnsQuestion.ids.origDest.toStringWithPort(), e.what());
diff -Nru dnsdist-1.9.9/dnsdist.hh dnsdist-1.9.10/dnsdist.hh
--- dnsdist-1.9.9/dnsdist.hh 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist.hh 2025-05-20 11:13:25.000000000 +0200
@@ -971,7 +971,7 @@
return d_config.d_tcpOnly || d_config.d_tcpCheck || d_tlsCtx != nullptr;
}
- bool isTCPOnly() const
+ [[nodiscard]] bool isTCPOnly() const
{
return d_config.d_tcpOnly || d_tlsCtx != nullptr;
}
@@ -1071,10 +1071,15 @@
const std::shared_ptr<const ServerPolicy::NumberedServerVector> getServers();
void addServer(shared_ptr<DownstreamState>& server);
void removeServer(shared_ptr<DownstreamState>& server);
+ bool isTCPOnly() const
+ {
+ return d_tcpOnly;
+ }
private:
SharedLockGuarded<std::shared_ptr<const ServerPolicy::NumberedServerVector>> d_servers;
bool d_useECS{false};
+ bool d_tcpOnly{false};
};
enum ednsHeaderFlags {
diff -Nru dnsdist-1.9.9/dnsdist-lua-bindings.cc dnsdist-1.9.10/dnsdist-lua-bindings.cc
--- dnsdist-1.9.9/dnsdist-lua-bindings.cc 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-lua-bindings.cc 2025-05-20 11:13:25.000000000 +0200
@@ -845,7 +845,7 @@
if (client || configCheck) {
return;
}
- std::thread newThread(dnsdist::resolver::asynchronousResolver, std::move(hostname), [callback=std::move(callback)](const std::string& resolvedHostname, std::vector<ComboAddress>& ips) {
+ std::thread newThread(dnsdist::resolver::asynchronousResolver, std::move(hostname), [callback = std::move(callback)](const std::string& resolvedHostname, std::vector<ComboAddress>& ips) mutable {
LuaArray<ComboAddress> result;
result.reserve(ips.size());
for (const auto& entry : ips) {
@@ -853,7 +853,15 @@
}
{
auto lua = g_lua.lock();
- callback(resolvedHostname, result);
+ try {
+ callback(resolvedHostname, result);
+ }
+ catch (const std::exception& exp) {
+ vinfolog("Error during execution of getAddressInfo callback: %s", exp.what());
+ }
+ // this _needs_ to be done while we are holding the lock,
+ // otherwise the destructor will corrupt the stack
+ callback = nullptr;
dnsdist::handleQueuedAsynchronousEvents();
}
});
diff -Nru dnsdist-1.9.9/dnsdist-lua-bindings-dnsquestion.cc dnsdist-1.9.10/dnsdist-lua-bindings-dnsquestion.cc
--- dnsdist-1.9.9/dnsdist-lua-bindings-dnsquestion.cc 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-lua-bindings-dnsquestion.cc 2025-05-20 11:13:25.000000000 +0200
@@ -138,6 +138,13 @@
return dq.sni;
});
+ luaCtx.registerFunction<std::string (DNSQuestion::*)() const>("getIncomingInterface", [](const DNSQuestion& dnsQuestion) -> std::string {
+ if (dnsQuestion.ids.cs != nullptr) {
+ return dnsQuestion.ids.cs->interface;
+ }
+ return {};
+ });
+
luaCtx.registerFunction<std::string (DNSQuestion::*)()const>("getProtocol", [](const DNSQuestion& dq) {
return dq.getProtocol().toPrettyString();
});
@@ -458,6 +465,13 @@
return dnsResponse.ids.queryRealTime.udiff();
});
+ luaCtx.registerFunction<std::string (DNSResponse::*)() const>("getIncomingInterface", [](const DNSResponse& dnsResponse) -> std::string {
+ if (dnsResponse.ids.cs != nullptr) {
+ return dnsResponse.ids.cs->interface;
+ }
+ return {};
+ });
+
luaCtx.registerFunction<void(DNSResponse::*)(std::string)>("sendTrap", [](const DNSResponse& dr, boost::optional<std::string> reason) {
#ifdef HAVE_NET_SNMP
if (g_snmpAgent && g_snmpTrapsEnabled) {
@@ -551,6 +565,7 @@
}
dr.asynchronous = true;
dr.getMutableData() = *dr.ids.d_packet;
+ dr.ids.d_proxyProtocolPayloadSize = 0;
auto query = dnsdist::getInternalQueryFromDQ(dr, false);
return dnsdist::queueQueryResumptionEvent(std::move(query));
});
diff -Nru dnsdist-1.9.9/dnsdist-lua.cc dnsdist-1.9.10/dnsdist-lua.cc
--- dnsdist-1.9.9/dnsdist-lua.cc 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-lua.cc 2025-05-20 11:13:25.000000000 +0200
@@ -642,7 +642,7 @@
auto ret = std::make_shared<DownstreamState>(std::move(config), std::move(tlsCtx), !(client || configCheck));
#ifdef HAVE_XSK
LuaArray<std::shared_ptr<XskSocket>> luaXskSockets; - if (getOptionalValue<LuaArray<std::shared_ptr<XskSocket>>>(vars, "xskSockets", luaXskSockets) > 0 && !luaXskSockets.empty()) {
+ if (!client && !configCheck && getOptionalValue<LuaArray<std::shared_ptr<XskSocket>>>(vars, "xskSockets", luaXskSockets) > 0 && !luaXskSockets.empty()) {
if (g_configurationDone) {
throw std::runtime_error("Adding a server with xsk at runtime is not supported");
}
@@ -668,6 +668,13 @@
else if (!(client || configCheck)) {
infolog("Added downstream server %s", ret->d_config.remote.toStringWithPort());
}
+
+ if (client || configCheck) {
+ /* consume these in client or configuration check mode, to prevent warnings */
+ std::string mac;
+ getOptionalValue<std::string>(vars, "MACAddr", mac);
+ getOptionalValue<LuaArray<std::shared_ptr<XskSocket>>>(vars, "xskSockets", luaXskSockets);
+ }
#else /* HAVE_XSK */
if (!(client || configCheck)) {
infolog("Added downstream server %s", ret->d_config.remote.toStringWithPort());
diff -Nru dnsdist-1.9.9/dnsdist-lua-ffi.cc dnsdist-1.9.10/dnsdist-lua-ffi.cc --- dnsdist-1.9.9/dnsdist-lua-ffi.cc 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-lua-ffi.cc 2025-05-20 11:13:25.000000000 +0200
@@ -121,6 +121,14 @@
return dq->dq->ids.origRemote.getPort();
}
+const char* dnsdist_ffi_dnsquestion_get_incoming_interface(const dnsdist_ffi_dnsquestion_t* dnsQuestion)
+{
+ if (dnsQuestion == nullptr || dnsQuestion->dq == nullptr || dnsQuestion->dq->ids.cs == nullptr) {
+ return nullptr;
+ }
+ return dnsQuestion->dq->ids.cs->interface.c_str();
+}
+
void dnsdist_ffi_dnsquestion_get_qname_raw(const dnsdist_ffi_dnsquestion_t* dq, const char** qname, size_t* qnameSize)
{
const auto& storage = dq->dq->ids.qname.getStorage();
diff -Nru dnsdist-1.9.9/dnsdist-lua-ffi-interface.h dnsdist-1.9.10/dnsdist-lua-ffi-interface.h
--- dnsdist-1.9.9/dnsdist-lua-ffi-interface.h 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-lua-ffi-interface.h 2025-05-20 11:13:25.000000000 +0200
@@ -64,6 +64,7 @@
void dnsdist_ffi_dnsquestion_get_remoteaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize) __attribute__ ((visibility ("default")));
void dnsdist_ffi_dnsquestion_get_masked_remoteaddr(dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize, uint8_t bits) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_dnsquestion_get_remote_port(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
+const char* dnsdist_ffi_dnsquestion_get_incoming_interface(const dnsdist_ffi_dnsquestion_t* dnsQuestion) __attribute__ ((visibility ("default")));
void dnsdist_ffi_dnsquestion_get_qname_raw(const dnsdist_ffi_dnsquestion_t* dq, const char** qname, size_t* qnameSize) __attribute__ ((visibility ("default")));
size_t dnsdist_ffi_dnsquestion_get_qname_hash(const dnsdist_ffi_dnsquestion_t* dq, size_t init) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_dnsquestion_get_qtype(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
diff -Nru dnsdist-1.9.9/dnsdist-lua-ffi-interface.inc dnsdist-1.9.10/dnsdist-lua-ffi-interface.inc
--- dnsdist-1.9.9/dnsdist-lua-ffi-interface.inc 2025-04-29 11:46:38.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-lua-ffi-interface.inc 2025-05-20 11:13:53.000000000 +0200
@@ -65,6 +65,7 @@
void dnsdist_ffi_dnsquestion_get_remoteaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize) __attribute__ ((visibility ("default")));
void dnsdist_ffi_dnsquestion_get_masked_remoteaddr(dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize, uint8_t bits) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_dnsquestion_get_remote_port(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
+const char* dnsdist_ffi_dnsquestion_get_incoming_interface(const dnsdist_ffi_dnsquestion_t* dnsQuestion) __attribute__ ((visibility ("default")));
void dnsdist_ffi_dnsquestion_get_qname_raw(const dnsdist_ffi_dnsquestion_t* dq, const char** qname, size_t* qnameSize) __attribute__ ((visibility ("default")));
size_t dnsdist_ffi_dnsquestion_get_qname_hash(const dnsdist_ffi_dnsquestion_t* dq, size_t init) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_dnsquestion_get_qtype(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
diff -Nru dnsdist-1.9.9/dnsdist-proxy-protocol.cc dnsdist-1.9.10/dnsdist-proxy-protocol.cc
--- dnsdist-1.9.9/dnsdist-proxy-protocol.cc 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-proxy-protocol.cc 2025-05-20 11:13:25.000000000 +0200
@@ -42,14 +42,19 @@
return addProxyProtocol(dq.getMutableData(), payload);
}
-bool addProxyProtocol(DNSQuestion& dq, size_t* payloadSize)
+bool addProxyProtocol(DNSQuestion& dnsQuestion, size_t* proxyProtocolPayloadSize)
{
- auto payload = getProxyProtocolPayload(dq);
- if (payloadSize != nullptr) {
- *payloadSize = payload.size();
+ auto payload = getProxyProtocolPayload(dnsQuestion);
+ size_t payloadSize = payload.size();
+
+ if (!addProxyProtocol(dnsQuestion, payload)) {
+ return false;
}
- return addProxyProtocol(dq, payload);
+ if (proxyProtocolPayloadSize != nullptr) {
+ *proxyProtocolPayloadSize = payloadSize;
+ }
+ return true;
}
bool addProxyProtocol(PacketBuffer& buffer, const std::string& payload)
diff -Nru dnsdist-1.9.9/dnsdist-proxy-protocol.hh dnsdist-1.9.10/dnsdist-proxy-protocol.hh
--- dnsdist-1.9.9/dnsdist-proxy-protocol.hh 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-proxy-protocol.hh 2025-05-20 11:13:25.000000000 +0200
@@ -29,7 +29,7 @@
std::string getProxyProtocolPayload(const DNSQuestion& dq);
-bool addProxyProtocol(DNSQuestion& dq, size_t* proxyProtocolPayloadSize = nullptr);
+bool addProxyProtocol(DNSQuestion& dnsQuestion, size_t* proxyProtocolPayloadSize = nullptr);
bool addProxyProtocol(DNSQuestion& dq, const std::string& payload);
bool addProxyProtocol(PacketBuffer& buffer, const std::string& payload);
bool addProxyProtocol(PacketBuffer& buffer, bool tcp, const ComboAddress& source, const ComboAddress& destination, const std::vector<ProxyProtocolValue>& values);
diff -Nru dnsdist-1.9.9/dnsdist.service.in dnsdist-1.9.10/dnsdist.service.in --- dnsdist-1.9.9/dnsdist.service.in 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist.service.in 2025-05-20 11:13:25.000000000 +0200
@@ -44,7 +44,7 @@
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectSystem=full
-RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX AF_XDP
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
diff -Nru dnsdist-1.9.9/dnsdist-tcp.cc dnsdist-1.9.10/dnsdist-tcp.cc
--- dnsdist-1.9.9/dnsdist-tcp.cc 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-tcp.cc 2025-05-20 11:13:25.000000000 +0200
@@ -114,14 +114,46 @@
return t_downstreamTCPConnectionsManager.clear();
}
+static std::pair<std::shared_ptr<TCPConnectionToBackend>, bool> getOwnedDownstreamConnection(std::map<std::shared_ptr<DownstreamState>, std::deque<std::shared_ptr<TCPConnectionToBackend>>>& ownedConnectionsToBackend, const std::shared_ptr<
+{
+ bool tlvsMismatch = false;
+ auto connIt = ownedConnectionsToBackend.find(backend);
+ if (connIt == ownedConnectionsToBackend.end()) {
+ DEBUGLOG("no owned connection found for " << backend->getName());
+ return {nullptr, tlvsMismatch};
+ }
+
+ for (auto& conn : connIt->second) {
+ if (conn->canBeReused(true)) {
+ if (conn->matchesTLVs(tlvs)) {
+ DEBUGLOG("Got one owned connection accepting more for " << backend->getName());
+ conn->setReused();
+ ++backend->tcpReusedConnections;
+ return {conn, tlvsMismatch};
+ }
+ DEBUGLOG("Found one connection to " << backend->getName() << " but with different TLV values");
+ tlvsMismatch = true;
+ }
+ DEBUGLOG("not accepting more for " << backend->getName());
+ }
+
+ return {nullptr, tlvsMismatch};
+}
+
std::shared_ptr<TCPConnectionToBackend> IncomingTCPConnectionState::getDownstreamConnection(std::shared_ptr<DownstreamState>& backend, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs, const struct timeval& now)
{
- auto downstream = getOwnedDownstreamConnection(backend, tlvs);
+ auto [downstream, tlvsMismatch] = getOwnedDownstreamConnection(d_ownedConnectionsToBackend, backend, tlvs);
if (!downstream) {
+ if (backend->d_config.useProxyProtocol && tlvsMismatch) {
+ clearOwnedDownstreamConnections(backend);
+ }
+
/* we don't have a connection to this backend owned yet, let's get one (it might not be a fresh one, though) */
downstream = t_downstreamTCPConnectionsManager.getConnectionToDownstream(d_threadData.mplexer, backend, now, std::string());
- if (backend->d_config.useProxyProtocol) {
+ // if we had an existing connection but the TLVs are different, they are likely unique per query so do not bother keeping the connection
+ // around
+ if (backend->d_config.useProxyProtocol && !tlvsMismatch) {
registerOwnedDownstreamConnection(downstream);
}
}
@@ -272,29 +304,32 @@
d_state = State::waitingForQuery;
}
-std::shared_ptr<TCPConnectionToBackend> IncomingTCPConnectionState::getOwnedDownstreamConnection(const std::shared_ptr<DownstreamState>& backend, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs)
+void IncomingTCPConnectionState::registerOwnedDownstreamConnection(std::shared_ptr<TCPConnectionToBackend>& conn)
{
- auto connIt = d_ownedConnectionsToBackend.find(backend);
- if (connIt == d_ownedConnectionsToBackend.end()) {
- DEBUGLOG("no owned connection found for " << backend->getName());
- return nullptr;
- }
+ const auto& downstream = conn->getDS();
- for (auto& conn : connIt->second) {
- if (conn->canBeReused(true) && conn->matchesTLVs(tlvs)) {
- DEBUGLOG("Got one owned connection accepting more for " << backend->getName());
- conn->setReused();
- return conn;
- }
- DEBUGLOG("not accepting more for " << backend->getName());
- }
+ auto& queue = d_ownedConnectionsToBackend[downstream];
+ // how many proxy-protocol enabled connections do we want to keep around? + // - they are only usable for this incoming connection because of the proxy protocol header containing the source and destination addresses and ports
+ // - if we have TLV values, and they are unique per query, keeping these is useless
+ // - if there is no, or identical, TLV values, a single outgoing connection is enough if maxInFlight == 1, or if incoming maxInFlight == outgoing maxInFlight
+ // so it makes sense to keep a few of them around if incoming maxInFlight is greater than outgoing maxInFlight
- return nullptr;
+ auto incomingMaxInFlightQueriesPerConn = d_ci.cs->d_maxInFlightQueriesPerConn;
+ incomingMaxInFlightQueriesPerConn = std::max(incomingMaxInFlightQueriesPerConn, static_cast<size_t>(1U));
+ auto outgoingMaxInFlightQueriesPerConn = downstream->d_config.d_maxInFlightQueriesPerConn;
+ outgoingMaxInFlightQueriesPerConn = std::max(outgoingMaxInFlightQueriesPerConn, static_cast<size_t>(1U));
+ size_t maxCachedOutgoingConnections = std::min(static_cast<size_t>(incomingMaxInFlightQueriesPerConn / outgoingMaxInFlightQueriesPerConn), static_cast<size_t>(5U));
+
+ queue.push_front(conn);
+ if (queue.size() > maxCachedOutgoingConnections) {
+ queue.pop_back();
+ }
}
-void IncomingTCPConnectionState::registerOwnedDownstreamConnection(std::shared_ptr<TCPConnectionToBackend>& conn)
+void IncomingTCPConnectionState::clearOwnedDownstreamConnections(const std::shared_ptr<DownstreamState>& downstream)
{
- d_ownedConnectionsToBackend[conn->getDS()].push_front(conn);
+ d_ownedConnectionsToBackend.erase(downstream);
}
/* called when the buffer has been set and the rules have been processed, and only from handleIO (sometimes indirectly via handleQuery) */
@@ -1053,8 +1088,39 @@
return false;
}
+class HandlingIOGuard
+{
+public:
+ HandlingIOGuard(bool& handlingIO) :
+ d_handlingIO(handlingIO)
+ {
+ }
+ HandlingIOGuard(const HandlingIOGuard&) = delete;
+ HandlingIOGuard(HandlingIOGuard&&) = delete;
+ HandlingIOGuard& operator=(const HandlingIOGuard& rhs) = delete;
+ HandlingIOGuard& operator=(HandlingIOGuard&&) = delete;
+ ~HandlingIOGuard()
+ {
+ d_handlingIO = false;
+ }
+
+private:
+ bool& d_handlingIO;
+};
+
void IncomingTCPConnectionState::handleIO()
{
+ // let's make sure we are not already in handleIO() below in the stack:
+ // this might happen when we have a response available on the backend socket
+ // right after forwarding the query, and then a query waiting for us on the
+ // client socket right after forwarding the response, and then a response available
+ // on the backend socket right after forwarding the query.. you get the idea.
+ if (d_handlingIO) {
+ return;
+ }
+ d_handlingIO = true;
+ HandlingIOGuard reentryGuard(d_handlingIO);
+
// why do we loop? Because the TLS layer does buffering, and thus can have data ready to read
// even though the underlying socket is not ready, so we need to actually ask for the data first
IOState iostate = IOState::Done;
diff -Nru dnsdist-1.9.9/dnsdist-tcp-upstream.hh dnsdist-1.9.10/dnsdist-tcp-upstream.hh
--- dnsdist-1.9.9/dnsdist-tcp-upstream.hh 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-tcp-upstream.hh 2025-05-20 11:13:25.000000000 +0200
@@ -116,9 +116,9 @@
return false;
}
- std::shared_ptr<TCPConnectionToBackend> getOwnedDownstreamConnection(const std::shared_ptr<DownstreamState>& backend, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs);
std::shared_ptr<TCPConnectionToBackend> getDownstreamConnection(std::shared_ptr<DownstreamState>& backend, const std::unique_ptr<std::vector<ProxyProtocolValue>>& tlvs, const struct timeval& now);
void registerOwnedDownstreamConnection(std::shared_ptr<TCPConnectionToBackend>& conn);
+ void clearOwnedDownstreamConnections(const std::shared_ptr<DownstreamState>& downstream);
static size_t clearAllDownstreamConnections();
@@ -216,4 +216,5 @@
bool d_proxyProtocolPayloadHasTLV{false};
bool d_lastIOBlocked{false};
bool d_hadErrors{false};
+ bool d_handlingIO{false};
};
diff -Nru dnsdist-1.9.9/dnsdist-web.cc dnsdist-1.9.10/dnsdist-web.cc
--- dnsdist-1.9.9/dnsdist-web.cc 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/dnsdist-web.cc 2025-05-20 11:13:25.000000000 +0200
@@ -913,7 +913,7 @@
output << "dnsdist_info{version=\"" << VERSION << "\"} " << "1" << "\n";
resp.body = output.str();
- resp.headers["Content-Type"] = "text/plain";
+ resp.headers["Content-Type"] = "text/plain; version=0.0.4";
}
#endif /* DISABLE_PROMETHEUS */
diff -Nru dnsdist-1.9.9/doh3.cc dnsdist-1.9.10/doh3.cc
--- dnsdist-1.9.9/doh3.cc 2025-04-29 11:46:04.000000000 +0200
+++ dnsdist-1.9.10/doh3.cc 2025-05-20 11:13:25.000000000 +0200
@@ -912,14 +912,14 @@
if (!quiche_version_is_supported(version)) {
DEBUGLOG("Unsupported version");
++frontend.d_doh3UnsupportedVersionErrors;
- handleVersionNegociation(sock, clientConnID, serverConnID, client, localAddr, buffer);
+ handleVersionNegotiation(sock, clientConnID, serverConnID, client, localAddr, buffer, clientState.local.isUnspecified());
continue;
}
if (token_len == 0) {
/* stateless retry */
DEBUGLOG("No token received");
- handleStatelessRetry(sock, clientConnID, serverConnID, client, localAddr, version, buffer);
+ handleStatelessRetry(sock, clientConnID, serverConnID, client, localAddr, version, buffer, clientState.local.isUnspecified());
continue;
}
@@ -966,7 +966,7 @@
processH3Events(clientState, frontend, conn->get(), client, serverConnID, buffer);
- flushEgress(sock, conn->get().d_conn, client, localAddr, buffer);
+ flushEgress(sock, conn->get().d_conn, client, localAddr, buffer, clientState.local.isUnspecified());
}
else {
DEBUGLOG("Connection not established");
@@ -1011,7 +1011,7 @@
for (auto conn = frontend->d_server_config->d_connections.begin(); conn != frontend->d_server_config->d_connections.end();) {
quiche_conn_on_timeout(conn->second.d_conn.get());
- flushEgress(sock, conn->second.d_conn, conn->second.d_peer, conn->second.d_localAddr, buffer);
+ flushEgress(sock, conn->second.d_conn, conn->second.d_peer, conn->second.d_localAddr, buffer, clientState->local.isUnspecified());
if (quiche_conn_is_closed(conn->second.d_conn.get())) {
#ifdef DEBUGLOG_ENABLED
Control: tags -1 confirmed
On 2025-05-21 11:03:59 +0200, Chris Hofstädtler wrote:
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: dnsdist@packages.debian.org, team@security.debian.org
Control: affects -1 + src:dnsdist
Please unblock package dnsdist
[ Reason ]
New upstream bugfix release with fix for security issue CVE-2025-30193 #1106207
ACK, please go ahead.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 488 |
Nodes: | 16 (2 / 14) |
Uptime: | 06:44:36 |
Calls: | 9,663 |
Calls today: | 5 |
Files: | 13,711 |
Messages: | 6,167,008 |
Posted today: | 2 |