From: Karel Bilek Date: Wed, 10 Jun 2026 12:59:21 +0000 (+0200) Subject: dnsdist: TCP multiplexer: update should reset ttd X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4be0fd0fef994525c4e1d28aaf8bb07cd0dbfa0f;p=thirdparty%2Fpdns.git dnsdist: TCP multiplexer: update should reset ttd Fixes #17555 Signed-off-by: Karel Bilek --- diff --git a/pdns/dnsdistdist/tcpiohandler-mplexer.hh b/pdns/dnsdistdist/tcpiohandler-mplexer.hh index 0c174f33db..601adddfde 100644 --- a/pdns/dnsdistdist/tcpiohandler-mplexer.hh +++ b/pdns/dnsdistdist/tcpiohandler-mplexer.hh @@ -83,6 +83,9 @@ public: /* let's update the TTD ! */ d_mplexer.setReadTTD(d_fd, *ttd, /* we pass 0 here because we already have a TTD */ 0); } + else { + d_mplexer.resetReadTTD(d_fd); + } return; } @@ -96,6 +99,9 @@ public: /* let's update the TTD ! */ d_mplexer.setWriteTTD(d_fd, *ttd, /* we pass 0 here because we already have a TTD */ 0); } + else { + d_mplexer.resetWriteTTD(d_fd); + } return; } @@ -125,6 +131,9 @@ public: /* let's update the TTD ! */ d_mplexer.setReadTTD(d_fd, *ttd, /* we pass 0 here because we already have a TTD */ 0); } + else { + d_mplexer.resetReadTTD(d_fd); + } return; } @@ -146,6 +155,9 @@ public: /* let's update the TTD ! */ d_mplexer.setWriteTTD(d_fd, *ttd, /* we pass 0 here because we already have a TTD */ 0); } + else { + d_mplexer.resetWriteTTD(d_fd); + } return; } diff --git a/pdns/mplexer.hh b/pdns/mplexer.hh index df0f6ae795..f07d8639dc 100644 --- a/pdns/mplexer.hh +++ b/pdns/mplexer.hh @@ -185,6 +185,18 @@ public: d_readCallbacks.replace(it, newEntry); } + void resetReadTTD(int fd) + { + const auto& it = d_readCallbacks.find(fd); + if (it == d_readCallbacks.end()) { + throw FDMultiplexerException("attempt to timestamp fd not in the multiplexer"); + } + + auto newEntry = *it; + memset(&newEntry.d_ttd, 0, sizeof(newEntry.d_ttd)); + d_readCallbacks.replace(it, newEntry); + } + void setWriteTTD(int fd, struct timeval tv, int timeout) { const auto& it = d_writeCallbacks.find(fd); @@ -198,6 +210,18 @@ public: d_writeCallbacks.replace(it, newEntry); } + void resetWriteTTD(int fd) + { + const auto& it = d_writeCallbacks.find(fd); + if (it == d_writeCallbacks.end()) { + throw FDMultiplexerException("attempt to timestamp fd not in the multiplexer"); + } + + auto newEntry = *it; + memset(&newEntry.d_ttd, 0, sizeof(newEntry.d_ttd)); + d_writeCallbacks.replace(it, newEntry); + } + void alterFDToRead(int fd, callbackfunc_t toDo, const funcparam_t& parameter = funcparam_t(), const struct timeval* ttd = nullptr) { accountingRemoveFD(d_writeCallbacks, fd); diff --git a/regression-tests.dnsdist/test_DOH.py b/regression-tests.dnsdist/test_DOH.py index dcc1dcb7d0..924cad5e24 100644 --- a/regression-tests.dnsdist/test_DOH.py +++ b/regression-tests.dnsdist/test_DOH.py @@ -2374,3 +2374,73 @@ class DOHEDNSPadding(object): class TestDOHEDNSPadding(DOHEDNSPadding, DNSDistDOHTest): _dohLibrary = "nghttp2" + + +class TestDOHNoIdleTimeoutKeepsConnection(DNSDistDOHTest, DNSDistTest): + _serverKey = "server.key" + _serverCert = "server.chain" + _serverName = "tls.tests.dnsdist.org" + _caCert = "ca.pem" + _dohServerPort = pickAvailablePort() + _dohBaseURL = "https://%s:%d/PowerDNS" % (_serverName, _dohServerPort) + + _config_template = """ + newServer{address="127.0.0.1:%d"} + addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/PowerDNS" }, {idleTimeout = 0}) + """ + _config_params = [ + "_testServerPort", + "_dohServerPort", + "_serverCert", + "_serverKey", + ] + _verboseMode = True + + def testKeepsConnection(self): + """ + DOH: Keeps connection with idleTimeout + """ + name = "simple.doh.tests.powerdns.com." + query = dns.message.make_query(name, "A", "IN") + expectedQuery = dns.message.make_query(name, "A", "IN") + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, "127.0.0.1") + response.answer.append(rrset) + + conn = self.openDOHConnection(self._dohServerPort, caFile=self._caCert, timeout=2.0) + conn.setopt(pycurl.HTTP_VERSION, pycurl.CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) + conn.setopt(pycurl.SSL_VERIFYPEER, 1) + conn.setopt(pycurl.SSL_VERIFYHOST, 2) + conn.setopt(pycurl.CAINFO, self._caCert) + + (receivedQuery, receivedResponse) = self.sendDOHQuery( + self._dohServerPort, + self._serverName, + self._dohBaseURL, + query, + response=response, + caFile=self._caCert, + conn=conn, + ) + self.assertTrue(receivedQuery) + self.assertTrue(receivedResponse) + receivedQuery.id = expectedQuery.id + self.assertEqual(expectedQuery, receivedQuery) + + time.sleep(3) + + (receivedQuery, receivedResponse) = self.sendDOHQuery( + self._dohServerPort, + self._serverName, + self._dohBaseURL, + query, + response=response, + caFile=self._caCert, + conn=conn, + ) + self.assertTrue(receivedQuery) + self.assertTrue(receivedResponse) + receivedQuery.id = expectedQuery.id + self.assertEqual(expectedQuery, receivedQuery) + + self.assertEqual(conn.getinfo(pycurl.NUM_CONNECTS), 0)