]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Test that the configuration is correctly reloaded 16065/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 1 Sep 2025 10:22:55 +0000 (12:22 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 1 Sep 2025 12:14:51 +0000 (14:14 +0200)
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
regression-tests.dnsdist/test_ConfigurationUpdates.py [new file with mode: 0644]

diff --git a/regression-tests.dnsdist/test_ConfigurationUpdates.py b/regression-tests.dnsdist/test_ConfigurationUpdates.py
new file mode 100644 (file)
index 0000000..d0414cc
--- /dev/null
@@ -0,0 +1,247 @@
+#!/usr/bin/env python
+import base64
+import dns
+import time
+from dnsdisttests import DNSDistTest, pickAvailablePort
+import extendederrors
+
+class TestConfigurationUpdates(DNSDistTest):
+    _yaml_config_template = """---
+console:
+  listen_address: "127.0.0.1:%d"
+  key: "%s"
+  acl:
+    - 127.0.0.0/8
+
+binds:
+  - listen_address: "127.0.0.1:%d"
+    protocol: Do53
+  - listen_address: "127.0.0.1:%d"
+    protocol: "DoT"
+    tls:
+      certificates:
+        - certificate: "%s"
+          key: "%s"
+      provider: "openssl"
+  - listen_address: "127.0.0.1:%d"
+    protocol: "DoH"
+    tls:
+      certificates:
+        - certificate: "%s"
+          key: "%s"
+    doh:
+      provider: "nghttp2"
+      paths:
+        - "/"
+  - listen_address: "127.0.0.1:%d"
+    protocol: "DoQ"
+    tls:
+      certificates:
+        - certificate: "%s"
+          key: "%s"
+  - listen_address: "127.0.0.1:%d"
+    protocol: "DoH3"
+    tls:
+      certificates:
+        - certificate: "%s"
+          key: "%s"
+
+backends:
+  - address: "127.0.0.1:%d"
+    protocol: Do53
+  - address: "127.0.0.1:%d"
+    protocol: Do53
+    tcp_only: true
+    pools:
+      - "tcp-pool"
+
+query_rules:
+  - name: "route TCP response test to the TCP-only pool"
+    selector:
+      type: "QName"
+      qname: "TCP-response.config-updates.test.powerdns.com."
+    action:
+      type: "Pool"
+      pool_name: "tcp-pool"
+"""
+    _dnsDistPort = pickAvailablePort()
+    _tlsServerPort = pickAvailablePort()
+    _dohWithNGHTTP2ServerPort = pickAvailablePort()
+    _doqServerPort = pickAvailablePort()
+    _doh3ServerPort = pickAvailablePort()
+    _serverKey = 'server.key'
+    _serverCert = 'server.chain'
+    _serverName = 'tls.tests.dnsdist.org'
+    _dohWithNGHTTP2BaseURL = ("https://%s:%d/" % (_serverName, _dohWithNGHTTP2ServerPort))
+    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort))
+    _caCert = 'ca.pem'
+    _consoleKey = DNSDistTest.generateConsoleKey()
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consolePort = pickAvailablePort()
+    _testServerPort = pickAvailablePort()
+    _yaml_config_params = ['_consolePort', '_consoleKeyB64', '_dnsDistPort', '_tlsServerPort', '_serverCert', '_serverKey', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey', '_doqServerPort','_serverCert', '_serverKey', '_doh3ServerPort', '_serverCert', '_serverKey', '_testServerPort', '_testServerPort']
+    _config_params = []
+    _checkConfigExpectedOutput = b"DNS over HTTPS configured\nConfiguration 'configs/dnsdist_TestConfigurationUpdates.yml' OK!\n"
+
+    def testRegular(self):
+        """
+        Configuration updates: regular
+        """
+        for protocol in ['UDP', 'TCP', 'DOT', 'DOH', 'DOQ', 'DOH3']:
+            name = f'regular-{protocol}.config-updates.test.powerdns.com.'
+            query = dns.message.make_query(name, 'A', 'IN')
+            query.flags &= ~dns.flags.RD
+            response = dns.message.make_response(query)
+            rrset = dns.rrset.from_text(name,
+                                        60,
+                                        dns.rdataclass.IN,
+                                        dns.rdatatype.A,
+                                       '127.0.0.1')
+
+            response.answer.append(rrset)
+
+            method = f'send{protocol}Query'
+            if not protocol in ['UDP', 'TCP']:
+                if protocol == 'DOH':
+                    method = 'sendDOHWithNGHTTP2QueryWrapper'
+                else:
+                    method += 'Wrapper'
+            sender = getattr(self, method)
+
+            (receivedQuery, receivedResponse) = sender(query, response=response)
+            receivedQuery.id = query.id
+            self.assertEqual(receivedQuery, query)
+            self.assertEqual(receivedResponse, response)
+
+            self.sendConsoleCommand(f'addAction(QNameRule("{name}"), RCodeAction(DNSRCode.REFUSED))')
+
+            # the configuration should have been updated
+            response = dns.message.make_response(query)
+            response.set_rcode(dns.rcode.REFUSED)
+            (_, receivedResponse) = sender(query, response=None, useQueue=False)
+            self.assertEqual(receivedResponse, response)
+
+    def testResponseRule(self):
+        """
+        Configuration updates: response
+        """
+        for protocol in ['UDP', 'TCP']:
+            name = f'{protocol}-response.config-updates.test.powerdns.com.'
+            query = dns.message.make_query(name, 'A', 'IN')
+            query.flags &= ~dns.flags.RD
+            response = dns.message.make_response(query)
+            rrset = dns.rrset.from_text(name,
+                                        60,
+                                        dns.rdataclass.IN,
+                                        dns.rdatatype.A,
+                                       '127.0.0.1')
+
+            response.answer.append(rrset)
+
+            method = f'send{protocol}Query'
+            sender = getattr(self, method)
+
+            (receivedQuery, receivedResponse) = sender(query, response=response)
+            receivedQuery.id = query.id
+            self.assertEqual(receivedQuery, query)
+            self.assertEqual(receivedResponse, response)
+
+            self.sendConsoleCommand(f'addResponseAction(QNameRule("{name}"), SetExtendedDNSErrorResponseAction(15))')
+            if protocol == 'TCP':
+                time.sleep(1)
+
+            # the configuration should have been updated
+            expectedResponse = dns.message.make_response(query)
+            ede = extendederrors.ExtendedErrorOption(15, b'')
+            expectedResponse.use_edns(edns=True, payload=4096, options=[ede])
+            expectedResponse.answer.append(rrset)
+            (_, receivedResponse) = sender(query, response=response)
+            self.assertEqual(receivedResponse, expectedResponse)
+
+class TestConfigurationUpdatesRecvMMSG(DNSDistTest):
+    _yaml_config_template = """---
+console:
+  listen_address: "127.0.0.1:%d"
+  key: "%s"
+  acl:
+    - 127.0.0.0/8
+
+binds:
+  - listen_address: "127.0.0.1:%d"
+    protocol: Do53
+
+backends:
+  - address: "127.0.0.1:%d"
+    protocol: Do53
+
+tuning:
+  udp:
+    messages_per_round: 10
+"""
+    _dnsDistPort = pickAvailablePort()
+    _consoleKey = DNSDistTest.generateConsoleKey()
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consolePort = pickAvailablePort()
+    _testServerPort = pickAvailablePort()
+    _yaml_config_params = ['_consolePort', '_consoleKeyB64', '_dnsDistPort', '_testServerPort']
+    _config_params = []
+
+    def testRecvMMSGUDP(self):
+        """
+        Configuration updates: recvmmsg UDP
+        """
+        name = 'recvmmsg-udp.config-updates.test.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        query.flags &= ~dns.flags.RD
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+
+        response.answer.append(rrset)
+
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=response)
+        receivedQuery.id = query.id
+        self.assertEqual(receivedQuery, query)
+        self.assertEqual(receivedResponse, response)
+
+        self.sendConsoleCommand(f'addAction(QNameRule("{name}"), RCodeAction(DNSRCode.REFUSED))')
+
+        # the configuration should have been updated
+        response = dns.message.make_response(query)
+        response.set_rcode(dns.rcode.REFUSED)
+        (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+        self.assertEqual(receivedResponse, response)
+
+    def testUDPResponseRule(self):
+        """
+        Configuration updates: UDP response
+        """
+        name = 'recvmmsg-udp-response.config-updates.test.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        query.flags &= ~dns.flags.RD
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    60,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.A,
+                                    '127.0.0.1')
+
+        response.answer.append(rrset)
+
+        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=response)
+        receivedQuery.id = query.id
+        self.assertEqual(receivedQuery, query)
+        self.assertEqual(receivedResponse, response)
+
+        self.sendConsoleCommand(f'addResponseAction(QNameRule("{name}"), SetExtendedDNSErrorResponseAction(15))')
+
+        # the configuration should have been updated
+        expectedResponse = dns.message.make_response(query)
+        ede = extendederrors.ExtendedErrorOption(15, b'')
+        expectedResponse.use_edns(edns=True, payload=4096, options=[ede])
+        expectedResponse.answer.append(rrset)
+        (_, receivedResponse) = self.sendUDPQuery(query, response=response)
+        self.assertEqual(receivedResponse, expectedResponse)