diff --git a/regression-tests.dnsdist/dnsdisttests.py b/regression-tests.dnsdist/dnsdisttests.py index 994b75168ec0..2e7d83f9a2d8 100644 --- a/regression-tests.dnsdist/dnsdisttests.py +++ b/regression-tests.dnsdist/dnsdisttests.py @@ -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 @@ def startDNSDist(cls): 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: diff --git a/regression-tests.dnsdist/test_CDB.py b/regression-tests.dnsdist/test_CDB.py index 2b4f0a06ad98..50f8474c5485 100644 --- a/regression-tests.dnsdist/test_CDB.py +++ b/regression-tests.dnsdist/test_CDB.py @@ -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 diff --git a/regression-tests.dnsdist/test_DOH.py b/regression-tests.dnsdist/test_DOH.py index c9554846ea86..5e73a10d3050 100644 --- a/regression-tests.dnsdist/test_DOH.py +++ b/regression-tests.dnsdist/test_DOH.py @@ -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' diff --git a/regression-tests.dnsdist/test_DOH3.py b/regression-tests.dnsdist/test_DOH3.py index 9634c914c7d8..0661625cd765 100644 --- a/regression-tests.dnsdist/test_DOH3.py +++ b/regression-tests.dnsdist/test_DOH3.py @@ -33,6 +33,65 @@ def getQUICConnection(self): 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 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' diff --git a/regression-tests.dnsdist/test_DOQ.py b/regression-tests.dnsdist/test_DOQ.py index 5a817747e04c..d7f6b417703e 100644 --- a/regression-tests.dnsdist/test_DOQ.py +++ b/regression-tests.dnsdist/test_DOQ.py @@ -63,6 +63,64 @@ def getQUICConnection(self): 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' diff --git a/regression-tests.dnsdist/test_LMDB.py b/regression-tests.dnsdist/test_LMDB.py index 5e308d7d32bc..add797dfd4dc 100644 --- a/regression-tests.dnsdist/test_LMDB.py +++ b/regression-tests.dnsdist/test_LMDB.py @@ -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 @@ def testLMDBKeyValueStoreLookupRule(self): 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' diff --git a/regression-tests.dnsdist/test_OutgoingDOH.py b/regression-tests.dnsdist/test_OutgoingDOH.py index 7b7c31541d4b..b4e402944074 100644 --- a/regression-tests.dnsdist/test_OutgoingDOH.py +++ b/regression-tests.dnsdist/test_OutgoingDOH.py @@ -341,6 +341,80 @@ def startResponders(cls): 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'] diff --git a/regression-tests.dnsdist/test_OutgoingTLS.py b/regression-tests.dnsdist/test_OutgoingTLS.py index 534c26789e65..8e7f57c5d3e4 100644 --- a/regression-tests.dnsdist/test_OutgoingTLS.py +++ b/regression-tests.dnsdist/test_OutgoingTLS.py @@ -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 @@ def startResponders(cls): 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'] diff --git a/regression-tests.dnsdist/test_Protobuf.py b/regression-tests.dnsdist/test_Protobuf.py index a7d119512036..7f23f2828c3f 100644 --- a/regression-tests.dnsdist/test_Protobuf.py +++ b/regression-tests.dnsdist/test_Protobuf.py @@ -1001,3 +1001,77 @@ def testProtobufAXFR(self): 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) diff --git a/regression-tests.dnsdist/test_TLS.py b/regression-tests.dnsdist/test_TLS.py index c54f3dee410e..19ff1c3cb962 100644 --- a/regression-tests.dnsdist/test_TLS.py +++ b/regression-tests.dnsdist/test_TLS.py @@ -325,6 +325,58 @@ def setUpClass(cls): 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 index 000000000000..d13e6c53712e --- /dev/null +++ b/regression-tests.dnsdist/test_Yaml.py @@ -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)