]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: TCP multiplexer: update should reset ttd
authorKarel Bilek <kb@karelbilek.com>
Wed, 10 Jun 2026 12:59:21 +0000 (14:59 +0200)
committerKarel Bilek <kb@karelbilek.com>
Wed, 10 Jun 2026 14:02:49 +0000 (16:02 +0200)
Fixes #17555

Signed-off-by: Karel Bilek <kb@karelbilek.com>
pdns/dnsdistdist/tcpiohandler-mplexer.hh
pdns/mplexer.hh
regression-tests.dnsdist/test_DOH.py

index 0c174f33db3c09c8ef0023ab7549ea0a5d847eb3..601adddfded9715d8d4cdabe668d301ee096d83a 100644 (file)
@@ -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;
       }
 
index df0f6ae7956321c8574383ce7082477224d9a8a0..f07d8639dc8c58e28d6c4f1338da785b9302786e 100644 (file)
@@ -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);
index dcc1dcb7d0d1c2f77fc08d135d934fca24ada1f4..924cad5e249d41c9802874b22db7469ad2230466 100644 (file)
@@ -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)