_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.'
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:
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
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'
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'
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'
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
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'
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']
_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)
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']
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)
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'
--- /dev/null
+#!/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)