]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add regression tests using the yaml configuration
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 24 Dec 2024 16:13:05 +0000 (17:13 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 16 Jan 2025 08:50:32 +0000 (09:50 +0100)
regression-tests.dnsdist/dnsdisttests.py
regression-tests.dnsdist/test_CDB.py
regression-tests.dnsdist/test_DOH.py
regression-tests.dnsdist/test_DOH3.py
regression-tests.dnsdist/test_DOQ.py
regression-tests.dnsdist/test_LMDB.py
regression-tests.dnsdist/test_OutgoingDOH.py
regression-tests.dnsdist/test_OutgoingTLS.py
regression-tests.dnsdist/test_Protobuf.py
regression-tests.dnsdist/test_TLS.py
regression-tests.dnsdist/test_Yaml.py [new file with mode: 0644]

index 70e5be984cd0d5573c97efba3a16e80767a08613..5797d4bb2c1f3b53672bb62365d47b9470e03273 100644 (file)
@@ -81,6 +81,8 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
     _config_template = """
     """
     _config_params = ['_testServerPort']
+    _yaml_config_template = None
+    _yaml_config_params = []
     _acl = ['127.0.0.1/32']
     _consoleKey = None
     _healthCheckName = 'a.root-servers.net.'
@@ -134,13 +136,24 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase):
         cls._consolePort = pickAvailablePort()
 
         print("Launching dnsdist..")
-        confFile = os.path.join('configs', 'dnsdist_%s.conf' % (cls.__name__))
+        if cls._yaml_config_template:
+            if 'SKIP_YAML_TESTS' in os.environ:
+                raise unittest.SkipTest('YAML tests are disabled')
+
+            params = tuple([getattr(cls, param) for param in cls._yaml_config_params])
+            confFile = os.path.join('configs', 'dnsdist_%s.yml' % (cls.__name__))
+            with open(confFile, 'w') as conf:
+                conf.write(cls._yaml_config_template % params)
+
         params = tuple([getattr(cls, param) for param in cls._config_params])
         print(params)
+        extension = 'lua' if cls._yaml_config_template else 'conf'
+        confFile = os.path.join('configs', 'dnsdist_%s.%s' % (cls.__name__, extension))
         with open(confFile, 'w') as conf:
             conf.write("-- Autogenerated by dnsdisttests.py\n")
-            conf.write(f"-- dnsdist will listen on {cls._dnsDistPort}")
+            conf.write(f"-- dnsdist will listen on {cls._dnsDistPort}\n")
             conf.write(cls._config_template % params)
+            conf.write("\n")
             conf.write("setSecurityPollSuffix('')")
 
         if cls._skipListeningOnCL:
index 2b4f0a06ad98416272af2bcc58d89da41b074571..50f8474c548545e4bc8c9b875038539fcbeb166e 100644 (file)
@@ -26,6 +26,9 @@ class CDBTest(DNSDistTest):
     newServer{address="127.0.0.1:%d"}
 
     kvs = newCDBKVStore('%s', %d)
+    kvs:reload()
+    kvs:lookup('does not exist, just testing that the lookup binding exists')
+    kvs:lookupSuffix(newDNSName('dummy'))
 
     -- KVS lookups follow
     -- does a lookup in the CDB database using the source IP as key, and store the result into the 'kvs-sourceip-result' tag
index c9554846ea86f52ea6140720d7b03de1c5249f2f..5e73a10d30500abbc723bd1d31f656ddf17cd650 100644 (file)
@@ -761,6 +761,149 @@ class TestDoHNGHTTP2(DOHTests, DNSDistDOHTest):
 class TestDoHH2O(DOHTests, DNSDistDOHTest):
     _dohLibrary = 'h2o'
 
+class TestDoHNGHTTP2Yaml(DOHTests, DNSDistDOHTest):
+    _dohLibrary = 'nghttp2'
+    _yaml_config_template = """---
+console:
+  key: "%s"
+  listen-address: "127.0.0.1:%d"
+  acl:
+    - 127.0.0.0/8
+backends:
+  - address: "127.0.0.1:%d"
+    protocol: "Do53"
+binds:
+  - listen-address: "127.0.0.1:%d"
+    reuseport: true
+    protocol: "DoH"
+    tls:
+      certificates:
+        - certificate: "%s"
+          key: "%s"
+    doh:
+      provider: "%s"
+      paths:
+        - "/"
+        - "/coffee"
+        - "/PowerDNS"
+        - "/PowerDNS2"
+        - "/PowerDNS-999"
+      custom-response-headers:
+        - key: "access-control-allow-origin"
+          value: "*"
+        - key: "user-agent"
+          value: "derp"
+        - key: "UPPERCASE"
+          value: "VaLuE"
+      keep-incoming-headers: true
+      responses-map:
+        - expression: "^/coffee$"
+          status: 418
+          content: 'C0FFEE'
+          headers:
+           - key: "FoO"
+             value: "bar"
+query-rules:
+  - name: "Drop"
+    selector:
+      type: "QName"
+      qname: "drop.doh.tests.powerdns.com."
+    action:
+      type: "Drop"
+  - name: "Refused"
+    selector:
+      type: "QName"
+      qname: "refused.doh.tests.powerdns.com."
+    action:
+      type: "RCode"
+      rcode: 5
+  - name: "Spoof"
+    selector:
+      type: "QName"
+      qname: "spoof.doh.tests.powerdns.com."
+    action:
+      type: "Spoof"
+      ips:
+        - "1.2.3.4"
+  - name: "HTTP header"
+    selector:
+      type: "HTTPHeader"
+      header: "X-PowerDNS"
+      expression: "^[a]{5}$"
+    action:
+      type: "Spoof"
+      ips:
+        - "2.3.4.5"
+  - name: "HTTP path"
+    selector:
+      type: "HTTPPath"
+      path: "/PowerDNS"
+    action:
+      type: "Spoof"
+      ips:
+        - "3.4.5.6"
+  - name: "HTTP regex"
+    selector:
+      type: "HTTPPathRegex"
+      expression: "^/PowerDNS-[0-9]"
+    action:
+      type: "Spoof"
+      ips:
+        - "6.7.8.9"
+  - name: "HTTP status"
+    selector:
+      type: "QName"
+      qname: "http-status-action.doh.tests.powerdns.com."
+    action:
+      type: "HTTPStatus"
+      status: 200
+      body: "Plaintext answer"
+      content-type: "text/plain"
+  - name: "HTTP status redirect"
+    selector:
+      type: "QName"
+      qname: "http-status-action-redirect.doh.tests.powerdns.com."
+    action:
+      type: "HTTPStatus"
+      status: 307
+      body: "https://doh.powerdns.org"
+  - name: "No backend"
+    selector:
+      type: "QName"
+      qname: "no-backend.doh.tests.powerdns.com."
+    action:
+      type: "Pool"
+      pool-name: "this-pool-has-no-backend"
+  - name: "HTTP Lua"
+    selector:
+      type: "QName"
+      qname: "http-lua.doh.tests.powerdns.com."
+    action:
+      type: "Lua"
+      function: "dohHandler"
+"""
+    _yaml_config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+    _config_template = """
+    function dohHandler(dq)
+      if dq:getHTTPScheme() == 'https' and dq:getHTTPHost() == '%s:%d' and dq:getHTTPPath() == '/' and dq:getHTTPQueryString() == '' then
+        local foundct = false
+        for key,value in pairs(dq:getHTTPHeaders()) do
+          if key == 'content-type' and value == 'application/dns-message' then
+            foundct = true
+            break
+          end
+        end
+        if foundct then
+          dq:setHTTPResponse(200, 'It works!', 'text/plain')
+          dq.dh:setQR(true)
+          return DNSAction.HeaderModify
+        end
+      end
+      return DNSAction.None
+    end
+    """
+    _config_params = ['_serverName', '_dohServerPort']
+
 class DOHSubPathsTests(object):
     _serverKey = 'server.key'
     _serverCert = 'server.chain'
index 89d7e0c0169599d5b80ef95ec744691f9cfc4aba..a7eb15d474a236ec0317404222678a60205cdc2a 100644 (file)
@@ -224,6 +224,65 @@ class TestDOH3(QUICTests, DNSDistTest):
         self.assertIn(b'content-type', receivedHeaders)
         self.assertEqual(receivedHeaders[b'content-type'], b'text/plain')
 
+class TestDOH3Yaml(QUICTests, DNSDistTest):
+    _serverKey = 'server.key'
+    _serverCert = 'server.chain'
+    _serverName = 'tls.tests.dnsdist.org'
+    _caCert = 'ca.pem'
+    _doqServerPort = pickAvailablePort()
+    _dohBaseURL = ("https://%s:%d/" % (_serverName, _doqServerPort))
+    _config_template = ""
+    _config_params = []
+    _yaml_config_template = """---
+backends:
+  - address: "127.0.0.1:%d"
+    protocol: "Do53"
+binds:
+  - listen-address: "127.0.0.1:%d"
+    reuseport: true
+    protocol: "DoH3"
+    tls:
+      certificates:
+        - certificate: "%s"
+          key: "%s"
+query-rules:
+  - name: "Drop"
+    selector:
+      type: "QName"
+      qname: "drop.doq.tests.powerdns.com."
+    action:
+      type: "Drop"
+  - name: "Refused"
+    selector:
+      type: "QName"
+      qname: "refused.doq.tests.powerdns.com."
+    action:
+      type: "RCode"
+      rcode: 5
+  - name: "Spoof"
+    selector:
+      type: "QName"
+      qname: "spoof.doq.tests.powerdns.com."
+    action:
+      type: "Spoof"
+      ips:
+        - "1.2.3.4"
+  - name: "No backend"
+    selector:
+      type: "QName"
+      qname: "no-backend.doq.tests.powerdns.com."
+    action:
+      type: "Pool"
+      pool-name: "this-pool-has-no-backend"
+    """
+    _yaml_config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+
+    def getQUICConnection(self):
+        return self.getDOQConnection(self._doqServerPort, self._caCert)
+
+    def sendQUICQuery(self, query, response=None, useQueue=True, connection=None):
+        return self.sendDOH3Query(self._doqServerPort, self._dohBaseURL, query, response=response, caFile=self._caCert, useQueue=useQueue, serverName=self._serverName, connection=connection)
+
 class TestDOH3ACL(QUICACLTests, DNSDistTest):
     _serverKey = 'server.key'
     _serverCert = 'server.chain'
index 5a817747e04c2fef38cf41da730dda93b3ed8b6f..d7f6b417703edfeeedb85a93add3ee2b5d2d2ff8 100644 (file)
@@ -63,6 +63,64 @@ class TestDOQ(QUICTests, DNSDistTest):
     def sendQUICQuery(self, query, response=None, useQueue=True, connection=None):
         return self.sendDOQQuery(self._doqServerPort, query, response=response, caFile=self._caCert, useQueue=useQueue, serverName=self._serverName, connection=connection)
 
+class TestDOQYaml(QUICTests, DNSDistTest):
+    _serverKey = 'server.key'
+    _serverCert = 'server.chain'
+    _serverName = 'tls.tests.dnsdist.org'
+    _caCert = 'ca.pem'
+    _doqServerPort = pickAvailablePort()
+    _config_template = ""
+    _config_params = []
+    _yaml_config_template = """---
+backends:
+  - address: "127.0.0.1:%d"
+    protocol: "Do53"
+binds:
+  - listen-address: "127.0.0.1:%d"
+    reuseport: true
+    protocol: "DoQ"
+    tls:
+      certificates:
+        - certificate: "%s"
+          key: "%s"
+query-rules:
+  - name: "Drop"
+    selector:
+      type: "QName"
+      qname: "drop.doq.tests.powerdns.com."
+    action:
+      type: "Drop"
+  - name: "Refused"
+    selector:
+      type: "QName"
+      qname: "refused.doq.tests.powerdns.com."
+    action:
+      type: "RCode"
+      rcode: 5
+  - name: "Spoof"
+    selector:
+      type: "QName"
+      qname: "spoof.doq.tests.powerdns.com."
+    action:
+      type: "Spoof"
+      ips:
+        - "1.2.3.4"
+  - name: "No backend"
+    selector:
+      type: "QName"
+      qname: "no-backend.doq.tests.powerdns.com."
+    action:
+      type: "Pool"
+      pool-name: "this-pool-has-no-backend"
+    """
+    _yaml_config_params = ['_testServerPort', '_doqServerPort','_serverCert', '_serverKey']
+
+    def getQUICConnection(self):
+        return self.getDOQConnection(self._doqServerPort, self._caCert)
+
+    def sendQUICQuery(self, query, response=None, useQueue=True, connection=None):
+        return self.sendDOQQuery(self._doqServerPort, query, response=response, caFile=self._caCert, useQueue=useQueue, serverName=self._serverName, connection=connection)
+
 class TestDOQWithCache(QUICWithCacheTests, DNSDistTest):
     _serverKey = 'server.key'
     _serverCert = 'server.chain'
index 5e308d7d32bceb737829a713e38647520f602604..add797dfd4dc4dcd457f44cc961a690f66aa7d18 100644 (file)
@@ -17,6 +17,9 @@ class TestLMDB(DNSDistTest):
     newServer{address="127.0.0.1:%d"}
 
     kvs = newLMDBKVStore('%s', '%s')
+    kvs:reload()
+    kvs:lookup('does not exist, just testing that the lookup binding exists')
+    kvs:lookupSuffix(newDNSName('dummy'))
 
     -- KVS lookups follow
     -- if the qname is 'kvs-rule.lmdb.tests.powerdns.com.', does a lookup in the LMDB database using the qname as key, and spoof an answer if it matches
@@ -195,6 +198,144 @@ class TestLMDB(DNSDistTest):
             self.assertTrue(receivedResponse)
             self.assertEqual(expectedResponse, receivedResponse)
 
+class TestLMDBYaml(TestLMDB):
+
+    _lmdbFileName = '/tmp/test-lmdb-db'
+    _lmdbDBName = 'db-name'
+    _config_template = ""
+    _config_params = []
+    _yaml_config_template = """---
+backends:
+  - address: "127.0.0.1:%d"
+    protocol: Do53
+key-value-stores:
+  lmdb:
+    - name: "lmdb-kvs"
+      file-name: "%s"
+      database-name: "%s"
+  lookup-keys:
+    source-ip-keys:
+      - name: "lookup-source-ip"
+    qname-keys:
+      - name: "lookup-qname"
+      - name: "lookup-qname-plaintext"
+        wire-format: false
+    suffix-keys:
+      - name: "lookup-suffix"
+    tag-keys:
+      - name: "lookup-tag-qname-result"
+        tag: "kvs-qname-result"
+
+query-rules:
+  - name: "qname as key"
+    selector:
+      type: "And"
+      selectors:
+        - type: "QName"
+          qname: "kvs-rule.lmdb.tests.powerdns.com."
+        - type: "KeyValueStoreLookup"
+          kvs-name: "lmdb-kvs"
+          lookup-key-name: "lookup-qname-plaintext"
+    action:
+      type: "Spoof"
+      ips:
+        - "13.14.15.16"
+  - name: "source IP as key"
+    selector:
+      type: "All"
+    action:
+      type: "KeyValueStoreLookup"
+      kvs-name: "lmdb-kvs"
+      lookup-key-name: "lookup-source-ip"
+      destination-tag: "kvs-sourceip-result"
+  - name: "plaintext qname as key"
+    selector:
+      type: "All"
+    action:
+      type: "KeyValueStoreLookup"
+      kvs-name: "lmdb-kvs"
+      lookup-key-name: "lookup-qname-plaintext"
+      destination-tag: "kvs-plain-text-result"
+  - name: "plaintext qname tag check"
+    selector:
+      type: "Tag"
+      tag: "kvs-plain-text-result"
+      value: "this is the value of the plaintext tag"
+    action:
+      type: "Spoof"
+      ips:
+        - "9.10.11.12"
+  - name: "wire qname as key"
+    selector:
+      type: "All"
+    action:
+      type: "KeyValueStoreLookup"
+      kvs-name: "lmdb-kvs"
+      lookup-key-name: "lookup-qname"
+      destination-tag: "kvs-qname-result"
+  - name: "wire qname tag check"
+    selector:
+      type: "Tag"
+      tag: "kvs-qname-result"
+      value: "this is the value of the qname tag"
+    action:
+      type: "KeyValueStoreLookup"
+      kvs-name: "lmdb-kvs"
+      lookup-key-name: "lookup-tag-qname-result"
+      destination-tag: "kvs-tag-result"
+  - name: "source IP as key"
+    selector:
+      type: "All"
+    action:
+      type: "KeyValueStoreLookup"
+      kvs-name: "lmdb-kvs"
+      lookup-key-name: "lookup-source-ip"
+      destination-tag: "kvs-sourceip-result"
+  - name: "qname suffix as key"
+    selector:
+      type: "All"
+    action:
+      type: "KeyValueStoreLookup"
+      kvs-name: "lmdb-kvs"
+      lookup-key-name: "lookup-suffix"
+      destination-tag: "kvs-suffix-result"
+  - name: "tag check"
+    selector:
+      type: "Tag"
+      tag: "kvs-tag-result"
+      value: "this is the value of the second tag"
+    action:
+      type: "Spoof"
+      ips:
+        - "1.2.3.4"
+  - name: "suffix tag check"
+    selector:
+      type: "Tag"
+      tag: "kvs-suffix-result"
+      value: "this is the value of the suffix tag"
+    action:
+      type: "Spoof"
+      ips:
+        - "42.42.42.42"
+  - name: "source IP tag check"
+    selector:
+      type: "Tag"
+      tag: "kvs-sourceip-result"
+      value: "this is the value of the source address tag"
+    action:
+      type: "Spoof"
+      ips:
+        - "5.6.7.8"
+  - name: "otherwise"
+    selector:
+      type: "All"
+    action:
+      type: "Spoof"
+      ips:
+        - "9.9.9.9"
+    """
+    _yaml_config_params = ['_testServerPort', '_lmdbFileName', '_lmdbDBName']
+
 class TestLMDBIPInRange(DNSDistTest):
 
     _lmdbFileName = '/tmp/test-lmdb-range-1-db'
index 7b7c31541d4b0d3414f4a370aea8f5d9c51e8a94..b4e402944074e03c5a27f8db5eff5359a841fb15 100644 (file)
@@ -341,6 +341,80 @@ class TestOutgoingDOHGnuTLS(DNSDistTest, OutgoingDOHTests):
         cls._DOHResponder.daemon = True
         cls._DOHResponder.start()
 
+class TestOutgoingDOHOpenSSLYaml(DNSDistTest, OutgoingDOHTests):
+    _tlsBackendPort = pickAvailablePort()
+    _tlsProvider = 'openssl'
+    _consoleKey = DNSDistTest.generateConsoleKey()
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _config_params = []
+    _config_template = ""
+    _yaml_config_template = """---
+console:
+  key: "%s"
+  listen-address: "127.0.0.1:%d"
+  acl:
+    - 127.0.0.0/8
+backends:
+  - address: "127.0.0.1:%d"
+    protocol: "DoH"
+    pools:
+      - ""
+      - "cache"
+    tls:
+      provider: "%s"
+      validate-certificate: true
+      ca-store: "ca.pem"
+      subject-name: "powerdns.com"
+    doh:
+      path: "/dns-query"
+    health-checks:
+      mode: "UP"
+webserver:
+  listen-address: "127.0.0.1:%d"
+  password: "%s"
+  api-key: "%s"
+  acl:
+    - 127.0.0.0/8
+tuning:
+  tcp:
+    worker-threads: 1
+pools:
+  - name: "cache"
+    packet-cache: "pc"
+packet-caches:
+  - name: "pc"
+    size: 100
+query-rules:
+  - name: "suffix to pool"
+    selector:
+      type: "QNameSuffix"
+      suffixes:
+        - "cached.outgoing-doh.test.powerdns.com."
+    action:
+      type: "Pool"
+      pool-name: "cache"
+"""
+    _yaml_config_params = ['_consoleKeyB64', '_consolePort', '_tlsBackendPort', '_tlsProvider', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+
+    @staticmethod
+    def sniCallback(sslSocket, sni, sslContext):
+        assert(sni == 'powerdns.com')
+        return None
+
+    @classmethod
+    def startResponders(cls):
+        tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+        tlsContext.set_alpn_protocols(["h2"])
+        tlsContext.load_cert_chain('server.chain', 'server.key')
+        # requires Python 3.7+
+        if hasattr(tlsContext, 'sni_callback'):
+            tlsContext.sni_callback = cls.sniCallback
+
+        print("Launching DOH responder..")
+        cls._DOHResponder = threading.Thread(name='DOH Responder', target=cls.DOHResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._DOHResponder.daemon = True
+        cls._DOHResponder.start()
+
 class TestOutgoingDOHOpenSSLWrongCertName(DNSDistTest, BrokenOutgoingDOHTests):
     _tlsBackendPort = pickAvailablePort()
     _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
index 534c26789e65aef35f9c93f83aed383700a7aaf9..8e7f57c5d3e480c9fad42504574c2c893def6d47 100644 (file)
@@ -16,7 +16,6 @@ class OutgoingTLSTests(object):
     _webServerAPIKey = 'apisecret'
     _webServerBasicAuthPasswordHashed = '$scrypt$ln=10,p=1,r=8$6DKLnvUYEeXWh3JNOd3iwg==$kSrhdHaRbZ7R74q3lGBqO1xetgxRxhmWzYJ2Qvfm7JM='
     _webServerAPIKeyHashed = '$scrypt$ln=10,p=1,r=8$9v8JxDfzQVyTpBkTbkUqYg==$bDQzAOHeK1G9UvTPypNhrX48w974ZXbFPtRKS34+aso='
-    _verboseMode = True
 
     def checkOnlyTLSResponderHit(self, numberOfTLSQueries=1):
         self.assertNotIn('UDP Responder', self._responsesCounter)
@@ -171,6 +170,49 @@ class TestOutgoingTLSOpenSSL(DNSDistTest, OutgoingTLSTests):
         cls._TLSResponder.daemon = True
         cls._TLSResponder.start()
 
+class TestOutgoingTLSOpenSSLYaml(DNSDistTest, OutgoingTLSTests):
+    _tlsBackendPort = pickAvailablePort()
+    _config_params = []
+    _config_template = ""
+    _yaml_config_template = """---
+backends:
+  - address: "127.0.0.1:%d"
+    protocol: "DoT"
+    tls:
+      provider: "openssl"
+      validate-certificate: true
+      ca-store: "ca.pem"
+      subject-name: "powerdns.com"
+webserver:
+  listen-address: "127.0.0.1:%d"
+  password: "%s"
+  api-key: "%s"
+  acl:
+    - 127.0.0.0/8
+tuning:
+  tcp:
+    worker-threads: 1
+    """
+    _yaml_config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
+
+    @staticmethod
+    def sniCallback(sslSocket, sni, sslContext):
+        assert(sni == 'powerdns.com')
+        return None
+
+    @classmethod
+    def startResponders(cls):
+        tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+        tlsContext.load_cert_chain('server.chain', 'server.key')
+        # requires Python 3.7+
+        if hasattr(tlsContext, 'sni_callback'):
+            tlsContext.sni_callback = cls.sniCallback
+
+        print("Launching TLS responder..")
+        cls._TLSResponder = threading.Thread(name='TLS Responder', target=cls.TCPResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
+        cls._TLSResponder.daemon = True
+        cls._TLSResponder.start()
+
 class TestOutgoingTLSGnuTLS(DNSDistTest, OutgoingTLSTests):
     _tlsBackendPort = pickAvailablePort()
     _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed']
index a7d11951203622900d4092f45ba0bd9f7eca2b28..7f23f2828c3f723bad139b2798a313386c0dc959 100644 (file)
@@ -1001,3 +1001,77 @@ class TestProtobufAXFR(DNSDistProtobufTest):
                     self.assertEqual(socket.inet_ntop(socket.AF_INET6, rr.rdata), '2001:db8::1')
 
         self.assertEqual(count, len(responses))
+
+class TestYamlProtobuf(DNSDistProtobufTest):
+
+    _yaml_config_template = """---
+binds:
+  - listen-address: "127.0.0.1:%d"
+    reuseport: true
+    protocol: Do53
+    threads: 2
+
+backends:
+  - address: "127.0.0.1:%d"
+    protocol: Do53
+
+remote-logging:
+  protobuf-loggers:
+    - name: "my-logger"
+      address: "127.0.0.1:%d"
+      timeout: 1
+
+query-rules:
+  - name: "my-rule"
+    selector:
+      type: "All"
+    action:
+      type: "RemoteLog"
+      logger-name: "my-logger"
+      server-id: "%s"
+      export-tags:
+        - "tag-1"
+        - "tag-2"
+"""
+    _dnsDistPort = pickAvailablePort()
+    _testServerPort = pickAvailablePort()
+    _yaml_config_params = ['_dnsDistPort', '_testServerPort', '_protobufServerPort', '_protobufServerID']
+    _config_params = []
+
+    def testProtobuf(self):
+        """
+        Yaml: Remote logging via protobuf
+        """
+        name = 'remote-logging.protobuf.yaml.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)
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            (receivedQuery, receivedResponse) = sender(query, response=response)
+            receivedQuery.id = query.id
+            self.assertEqual(receivedQuery, query)
+            self.assertEqual(receivedResponse, response)
+
+
+        if self._protobufQueue.empty():
+            # let the protobuf messages the time to get there
+            time.sleep(1)
+        # check the protobuf message corresponding to the UDP query
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.UDP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
+
+        if self._protobufQueue.empty():
+            # let the protobuf messages the time to get there
+            time.sleep(1)
+        # TCP query
+        msg = self.getFirstProtobufMessage()
+        self.checkProtobufQuery(msg, dnsmessage_pb2.PBDNSMessage.TCP, query, dns.rdataclass.IN, dns.rdatatype.A, name)
index c54f3dee410ec6260965a315ee11d58d02b78b69..19ff1c3cb962f4c05bb3e6fb7a30c294a711be55 100644 (file)
@@ -325,6 +325,58 @@ class TestGnuTLS(DNSDistTest, TLSTests):
     def testProvider(self):
         self.assertEqual(self.getTLSProvider(), "gnutls")
 
+class TestOpenSSLYaml(DNSDistTest, TLSTests):
+
+    _extraStartupSleep = 1
+    _consoleKey = DNSDistTest.generateConsoleKey()
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _serverKey = 'server-tls.key'
+    _serverCert = 'server-tls.chain'
+    _serverName = 'tls.tests.dnsdist.org'
+    _caCert = 'ca.pem'
+    _tlsServerPort = pickAvailablePort()
+    _config_template = ""
+    _config_params = []
+    _yaml_config_template = """---
+console:
+  key: "%s"
+  listen-address: "127.0.0.1:%d"
+  acl:
+    - 127.0.0.0/8
+backends:
+  - address: "127.0.0.1:%d"
+    protocol: "Do53"
+binds:
+  - listen-address: "127.0.0.1:%d"
+    reuseport: true
+    protocol: "DoT"
+    tls:
+      certificates:
+        - certificate: "%s"
+          key: "%s"
+      provider: "openssl"
+query-rules:
+  - name: "SNI"
+    selector:
+      type: "SNI"
+      server-name: "powerdns.com"
+    action:
+      type: "Spoof"
+      ips:
+        - "1.2.3.4"
+    """
+    _yaml_config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey']
+
+    @classmethod
+    def setUpClass(cls):
+        cls.generateNewCertificateAndKey('server-tls')
+        cls.startResponders()
+        cls.startDNSDist()
+        cls.setUpSockets()
+
+    def testProvider(self):
+        self.assertEqual(self.getTLSProvider(), "openssl")
+
 class TestDOTWithCache(DNSDistTest):
     _serverKey = 'server.key'
     _serverCert = 'server.chain'
diff --git a/regression-tests.dnsdist/test_Yaml.py b/regression-tests.dnsdist/test_Yaml.py
new file mode 100644 (file)
index 0000000..d13e6c5
--- /dev/null
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+import base64
+import dns
+from dnsdisttests import DNSDistTest, pickAvailablePort
+
+class TestYaml(DNSDistTest):
+
+    _yaml_config_template = """---
+webserver:
+  listen-address: "127.0.0.1:%d"
+  acl:
+    - 127.0.0.0/8
+
+console:
+  listen-address: "127.0.0.1:%d"
+  key: "%s"
+  acl:
+    - 127.0.0.0/8
+
+edns-client-subnet:
+  override-existing: true
+  source-prefix-v4: 32
+  source-prefix-v6: 48
+
+acl:
+  - 127.0.0.1/32
+  - ::1/128
+
+ring-buffers:
+  size: 2000
+  shards: 2
+
+binds:
+  - listen-address: "127.0.0.1:%d"
+    reuseport: true
+    protocol: Do53
+    threads: 2
+
+backends:
+  - address: "127.0.0.1:%d"
+    protocol: Do53
+    pools:
+      - "tcp-pool"
+
+pools:
+  - name: "tcp-pool"
+    policy: "leastoutstanding"
+
+selectors:
+  - type: "TCP"
+    name: "is-tcp"
+    tcp: true
+
+query-rules:
+  - name: "my-rule"
+    selector:
+      type: "And"
+      selectors:
+        - type: "ByName"
+          selector-name: "is-tcp"
+        - type: "Not"
+          selector:
+            type: "RD"
+    action:
+      type: "Pool"
+      pool-name: "tcp-pool"
+"""
+    _webServerPort = pickAvailablePort()
+    _dnsDistPort = pickAvailablePort()
+    _consoleKey = DNSDistTest.generateConsoleKey()
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+    _consolePort = pickAvailablePort()
+    _testServerPort = pickAvailablePort()
+    _yaml_config_params = ['_webServerPort', '_consolePort', '_consoleKeyB64', '_dnsDistPort', '_testServerPort']
+    _config_params = []
+
+    def testForwarded(self):
+        """
+        Yaml: Forwarded query
+        """
+        name = 'forwarded.yaml.test.powerdns.com.'
+        query = dns.message.make_query(name, 'A', 'IN')
+        query.flags &= ~dns.flags.RD
+        # UDP query should be dropped
+        (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
+        self.assertEqual(receivedResponse, None)
+        # TCP query should be forwarded
+        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.sendTCPQuery(query, response=response)
+        receivedQuery.id = query.id
+        self.assertEqual(receivedQuery, query)
+        self.assertEqual(receivedResponse, response)