]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Fix an iterator out-of-bound read when removing a TCP-only server 15471/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 25 Apr 2025 10:14:04 +0000 (12:14 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 25 Apr 2025 10:15:29 +0000 (12:15 +0200)
Introduced in https://github.com/PowerDNS/pdns/pull/15418

pdns/dnsdistdist/dnsdist-backend.cc
regression-tests.dnsdist/test_PoolManagement.py [new file with mode: 0644]

index 31e9d254cd5dd06d3627121ec91fb5afe4e53f3a..83b6fe7ba7b88c2e6441450a84ceb2b38819606f 100644 (file)
@@ -1078,6 +1078,7 @@ void ServerPool::removeServer(shared_ptr<DownstreamState>& server)
   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++;
@@ -1087,10 +1088,10 @@ void ServerPool::removeServer(shared_ptr<DownstreamState>& server)
       it = newServers->erase(it);
       found = true;
     } else {
+      tcpOnly = tcpOnly && it->second->isTCPOnly();
       idx++;
       it++;
     }
-    tcpOnly = tcpOnly && it->second->isTCPOnly();
   }
   d_tcpOnly = tcpOnly;
   *servers = std::move(newServers);
diff --git a/regression-tests.dnsdist/test_PoolManagement.py b/regression-tests.dnsdist/test_PoolManagement.py
new file mode 100644 (file)
index 0000000..9120d78
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+import dns
+from dnsdisttests import DNSDistTest, pickAvailablePort
+
+class TestPoolManagement(DNSDistTest):
+    _config_template = """
+    local backendPort = %d
+    server1 = newServer{address="127.0.0.1:"..backendPort, tcpOnly=true}
+    server2 = newServer{address="127.0.0.1:"..backendPort, tcpOnly=true}
+    server3 = newServer{address="127.0.0.1:"..backendPort, tcpOnly=true}
+    server1:addPool("new-pool")
+    server2:addPool("new-pool")
+    server3:addPool("new-pool")
+    server1:rmPool("new-pool")
+    server1:addPool("new-pool")
+    rmServer(server1)
+    rmServer(server2)
+    server3:rmPool("new-pool")
+    """
+
+    def testSimpleA(self):
+        """
+        Pool management: A query without EDNS
+        """
+        name = 'pool-mngmt.tests.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+        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)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, response)
+            self.assertTrue(receivedQuery)
+            self.assertTrue(receivedResponse)
+            receivedQuery.id = query.id
+            self.assertEqual(query, receivedQuery)
+            self.assertEqual(response, receivedResponse)