#!/usr/bin/env python
+import base64
import dns
import os
import time
import clientsubnetoption
from dnsdistdohtests import DNSDistDOHTest
+from dnsdisttests import pickAvailablePort
import pycurl
from io import BytesIO
-class TestDOH(DNSDistDOHTest):
-
+class DOHTests(object):
_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_customResponseHeader1 = 'access-control-allow-origin: *'
_customResponseHeader2 = 'user-agent: derp'
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
_config_template = """
- newServer{address="127.0.0.1:%s"}
-
- addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/", "/coffee", "/PowerDNS", "/PowerDNS2", "/PowerDNS-999" }, {customResponseHeaders={["access-control-allow-origin"]="*",["user-agent"]="derp",["UPPERCASE"]="VaLuE"}, keepIncomingHeaders=true})
- dohFE = getDOHFrontend(0)
- dohFE:setResponsesMap({newDOHResponseMapEntry('^/coffee$', 418, 'C0FFEE', {['FoO']='bar'})})
+ newServer{address="127.0.0.1:%d"}
addAction("drop.doh.tests.powerdns.com.", DropAction())
addAction("refused.doh.tests.powerdns.com.", RCodeAction(DNSRCode.REFUSED))
addAction(HTTPPathRegexRule("^/PowerDNS-[0-9]"), SpoofAction("6.7.8.9"))
addAction("http-status-action.doh.tests.powerdns.com.", HTTPStatusAction(200, "Plaintext answer", "text/plain"))
addAction("http-status-action-redirect.doh.tests.powerdns.com.", HTTPStatusAction(307, "https://doh.powerdns.org"))
+ addAction("no-backend.doh.tests.powerdns.com.", PoolAction('this-pool-has-no-backend'))
function dohHandler(dq)
if dq:getHTTPScheme() == 'https' and dq:getHTTPHost() == '%s:%d' and dq:getHTTPPath() == '/' and dq:getHTTPQueryString() == '' then
return DNSAction.None
end
addAction("http-lua.doh.tests.powerdns.com.", LuaAction(dohHandler))
+
+ addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/", "/coffee", "/PowerDNS", "/PowerDNS2", "/PowerDNS-999" }, {customResponseHeaders={["access-control-allow-origin"]="*",["user-agent"]="derp",["UPPERCASE"]="VaLuE"}, keepIncomingHeaders=true, library='%s'})
+ dohFE = getDOHFrontend(0)
+ dohFE:setResponsesMap({newDOHResponseMapEntry('^/coffee$', 418, 'C0FFEE', {['FoO']='bar'})})
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_serverName', '_dohServerPort']
+ _config_params = ['_testServerPort', '_serverName', '_dohServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
+ _verboseMode = True
def testDOHSimple(self):
"""
(_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=query, response=None, useQueue=False)
self.assertEqual(receivedResponse, expectedResponse)
+ def testDOHWithoutQuery(self):
+ """
+ DOH: Empty GET query
+ """
+ name = 'empty-get.doh.tests.powerdns.com.'
+ url = self._dohBaseURL
+ conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2.0)
+ conn.setopt(pycurl.URL, url)
+ conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
+ conn.setopt(pycurl.SSL_VERIFYPEER, 1)
+ conn.setopt(pycurl.SSL_VERIFYHOST, 2)
+ conn.setopt(pycurl.CAINFO, self._caCert)
+ data = conn.perform_rb()
+ rcode = conn.getinfo(pycurl.RESPONSE_CODE)
+ self.assertEqual(rcode, 400)
+
+ def testDOHZeroQDCount(self):
+ """
+ DOH: qdcount == 0
+ """
+ if self._dohLibrary == 'h2o':
+ raise unittest.SkipTest('h2o tries to parse the qname early, so this check will fail')
+ name = 'zero-qdcount.doh.tests.powerdns.com.'
+ query = dns.message.Message()
+ query.id = 0
+ query.flags &= ~dns.flags.RD
+ expectedResponse = dns.message.make_response(query)
+ expectedResponse.set_rcode(dns.rcode.NOTIMP)
+
+ (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=query, response=None, useQueue=False)
+ self.assertEqual(receivedResponse, expectedResponse)
+
+ def testDOHShortPath(self):
+ """
+ DOH: Short path in GET query
+ """
+ name = 'short-path-get.doh.tests.powerdns.com.'
+ url = self._dohBaseURL + '/AA'
+ conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2.0)
+ conn.setopt(pycurl.URL, url)
+ conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
+ conn.setopt(pycurl.SSL_VERIFYPEER, 1)
+ conn.setopt(pycurl.SSL_VERIFYHOST, 2)
+ conn.setopt(pycurl.CAINFO, self._caCert)
+ data = conn.perform_rb()
+ rcode = conn.getinfo(pycurl.RESPONSE_CODE)
+ self.assertEqual(rcode, 404)
+
+ def testDOHQueryNoParameter(self):
+ """
+ DOH: No parameter GET query
+ """
+ name = 'no-parameter-get.doh.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+ wire = query.to_wire()
+ b64 = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=')
+ url = self._dohBaseURL + '?not-dns=' + b64
+ conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2.0)
+ conn.setopt(pycurl.URL, url)
+ conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
+ conn.setopt(pycurl.SSL_VERIFYPEER, 1)
+ conn.setopt(pycurl.SSL_VERIFYHOST, 2)
+ conn.setopt(pycurl.CAINFO, self._caCert)
+ data = conn.perform_rb()
+ rcode = conn.getinfo(pycurl.RESPONSE_CODE)
+ self.assertEqual(rcode, 400)
+
+ def testDOHQueryInvalidBase64(self):
+ """
+ DOH: Invalid Base64 GET query
+ """
+ name = 'invalid-b64-get.doh.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+ wire = query.to_wire()
+ url = self._dohBaseURL + '?dns=' + '_-~~~~-_'
+ conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2.0)
+ conn.setopt(pycurl.URL, url)
+ conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
+ conn.setopt(pycurl.SSL_VERIFYPEER, 1)
+ conn.setopt(pycurl.SSL_VERIFYHOST, 2)
+ conn.setopt(pycurl.CAINFO, self._caCert)
+ data = conn.perform_rb()
+ rcode = conn.getinfo(pycurl.RESPONSE_CODE)
+ self.assertEqual(rcode, 400)
+
+ def testDOHInvalidDNSHeaders(self):
+ """
+ DOH: Invalid DNS headers
+ """
+ name = 'invalid-dns-headers.doh.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+ query.flags |= dns.flags.QR
+ wire = query.to_wire()
+ b64 = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=')
+ url = self._dohBaseURL + '?dns=' + b64
+ conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2.0)
+ conn.setopt(pycurl.URL, url)
+ conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
+ conn.setopt(pycurl.SSL_VERIFYPEER, 1)
+ conn.setopt(pycurl.SSL_VERIFYHOST, 2)
+ conn.setopt(pycurl.CAINFO, self._caCert)
+ data = conn.perform_rb()
+ rcode = conn.getinfo(pycurl.RESPONSE_CODE)
+ self.assertEqual(rcode, 400)
+
+ def testDOHQueryInvalidMethod(self):
+ """
+ DOH: Invalid method
+ """
+ if self._dohLibrary == 'h2o':
+ raise unittest.SkipTest('h2o does not check the HTTP method')
+ name = 'invalid-method.doh.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+ wire = query.to_wire()
+ b64 = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=')
+ url = self._dohBaseURL + '?dns=' + b64
+ conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2)
+ conn.setopt(pycurl.URL, url)
+ conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
+ conn.setopt(pycurl.SSL_VERIFYPEER, 1)
+ conn.setopt(pycurl.SSL_VERIFYHOST, 2)
+ conn.setopt(pycurl.CAINFO, self._caCert)
+ conn.setopt(pycurl.CUSTOMREQUEST, 'PATCH')
+ data = conn.perform_rb()
+ rcode = conn.getinfo(pycurl.RESPONSE_CODE)
+ self.assertEqual(rcode, 400)
+
+ def testDOHQueryInvalidALPN(self):
+ """
+ DOH: Invalid ALPN
+ """
+ alpn = ['bogus-alpn']
+ conn = self.openTLSConnection(self._dohServerPort, self._serverName, self._caCert, alpn=alpn)
+ try:
+ conn.send('AAAA')
+ response = conn.recv(65535)
+ self.assertFalse(response)
+ except:
+ pass
+
+ def testDOHHTTP1(self):
+ """
+ DOH: HTTP/1.1
+ """
+ if self._dohLibrary == 'h2o':
+ raise unittest.SkipTest('h2o supports HTTP/1.1, this test is only relevant for nghttp2')
+ name = 'http11.doh.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+ wire = query.to_wire()
+ b64 = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=')
+ url = self._dohBaseURL + '?dns=' + b64
+ conn = pycurl.Curl()
+ conn.setopt(pycurl.HTTP_VERSION, pycurl.CURL_HTTP_VERSION_1_1)
+ conn.setopt(pycurl.HTTPHEADER, ["Content-type: application/dns-message",
+ "Accept: application/dns-message"])
+ conn.setopt(pycurl.URL, url)
+ conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
+ conn.setopt(pycurl.SSL_VERIFYPEER, 1)
+ conn.setopt(pycurl.SSL_VERIFYHOST, 2)
+ conn.setopt(pycurl.CAINFO, self._caCert)
+ data = conn.perform_rb()
+ rcode = conn.getinfo(pycurl.RESPONSE_CODE)
+ self.assertEqual(rcode, 400)
+ self.assertEqual(data, b'<html><body>This server implements RFC 8484 - DNS Queries over HTTP, and requires HTTP/2 in accordance with section 5.2 of the RFC.</body></html>\r\n')
+
def testDOHInvalid(self):
"""
- DOH: Invalid query
+ DOH: Invalid DNS query
"""
name = 'invalid.doh.tests.powerdns.com.'
invalidQuery = dns.message.make_query(name, 'A', 'IN', use_edns=False)
self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
self.assertEqual(response, receivedResponse)
- def testDOHWithoutQuery(self):
+ def testDOHInvalidHeaderName(self):
"""
- DOH: Empty GET query
+ DOH: Invalid HTTP header name query
"""
- name = 'empty-get.doh.tests.powerdns.com.'
- url = self._dohBaseURL
- conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2.0)
+ name = 'invalid-header-name.doh.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+ query.id = 0
+ expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
+ expectedQuery.id = 0
+ 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)
+ # this header is invalid, see rfc9113 section 8.2.1. Field Validity
+ customHeaders = ['{}: test']
+ try:
+ (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert, customHeaders=customHeaders)
+ self.assertFalse(receivedQuery)
+ self.assertFalse(receivedResponse)
+ except pycurl.error:
+ pass
+
+ def testDOHNoBackend(self):
+ """
+ DOH: No backend
+ """
+ if self._dohLibrary == 'h2o':
+ raise unittest.SkipTest('h2o does not check the HTTP method')
+ name = 'no-backend.doh.tests.powerdns.com.'
+ query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
+ wire = query.to_wire()
+ b64 = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=')
+ url = self._dohBaseURL + '?dns=' + b64
+ conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2)
conn.setopt(pycurl.URL, url)
conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)])
conn.setopt(pycurl.SSL_VERIFYPEER, 1)
conn.setopt(pycurl.CAINFO, self._caCert)
data = conn.perform_rb()
rcode = conn.getinfo(pycurl.RESPONSE_CODE)
- self.assertEqual(rcode, 400)
+ self.assertEqual(rcode, 403)
def testDOHEmptyPOST(self):
"""
self.assertIn('foo: bar', headers)
self.assertNotIn(self._customResponseHeader2, headers)
-class TestDOHSubPaths(DNSDistDOHTest):
+class TestDoHNGHTTP2(DOHTests, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+
+class TestDoHH2O(DOHTests, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
+class DOHSubPathsTests(object):
_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
_config_template = """
newServer{address="127.0.0.1:%s"}
addAction(AllRule(), SpoofAction("3.4.5.6"))
- addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/PowerDNS" }, {exactPathMatching=false})
+ addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/PowerDNS" }, {exactPathMatching=false, library='%s'})
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey']
+ _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
def testSubPath(self):
"""
# this path is not in the URLs map and should lead to a 404
(_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + "NotPowerDNS", query, caFile=self._caCert, useQueue=False, rawResponse=True)
self.assertTrue(receivedResponse)
- self.assertEqual(receivedResponse, b'not found')
+ self.assertIn(receivedResponse, [b'there is no endpoint configured for this path', b'not found'])
self.assertEqual(self._rcode, 404)
# this path is below one in the URLs map and exactPathMatching is false, so we should be good
(_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + 'PowerDNS/something', caFile=self._caCert, query=query, response=None, useQueue=False)
self.assertEqual(receivedResponse, expectedResponse)
-class TestDOHAddingECS(DNSDistDOHTest):
+class TestDoHSubPathsNGHTTP2(DOHSubPathsTests, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+
+class TestDoHSubPathsH2O(DOHSubPathsTests, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
+
+class DOHAddingECSTests(object):
_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
_config_template = """
newServer{address="127.0.0.1:%s", useClientSubnet=true}
- addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" })
+ addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {library='%s'})
setECSOverride(true)
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey']
+ _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
def testDOHSimple(self):
"""
self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
self.checkResponseEDNSWithECS(response, receivedResponse)
-class TestDOHOverHTTP(DNSDistDOHTest):
+class TestDoHAddingECSNGHTTP2(DOHAddingECSTests, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+
+class TestDoHAddingECSH2O(DOHAddingECSTests, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
- _dohServerPort = 8480
+class DOHOverHTTP(object):
+ _dohServerPort = pickAvailablePort()
_serverName = 'tls.tests.dnsdist.org'
_dohBaseURL = ("http://%s:%d/dns-query" % (_serverName, _dohServerPort))
_config_template = """
newServer{address="127.0.0.1:%s"}
- addDOHLocal("127.0.0.1:%s")
+ addDOHLocal("127.0.0.1:%s", nil, nil, '/dns-query', {library='%s'})
"""
- _config_params = ['_testServerPort', '_dohServerPort']
- _checkConfigExpectedOutput = b"""No certificate provided for DoH endpoint 127.0.0.1:8480, running in DNS over HTTP mode instead of DNS over HTTPS
-Configuration 'configs/dnsdist_TestDOHOverHTTP.conf' OK!
-"""
+ _config_params = ['_testServerPort', '_dohServerPort', '_dohLibrary']
def testDOHSimple(self):
"""
self.assertEqual(response, receivedResponse)
self.checkResponseNoEDNS(response, receivedResponse)
-class TestDOHWithCache(DNSDistDOHTest):
+class TestDOHOverHTTPNGHTTP2(DOHOverHTTP, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+ _checkConfigExpectedOutput = b"""No certificate provided for DoH endpoint 127.0.0.1:%d, running in DNS over HTTP mode instead of DNS over HTTPS
+Configuration 'configs/dnsdist_TestDOHOverHTTPNGHTTP2.conf' OK!
+""" % (DOHOverHTTP._dohServerPort)
+
+class TestDOHOverHTTPH2O(DOHOverHTTP, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
+ _checkConfigExpectedOutput = b"""No certificate provided for DoH endpoint 127.0.0.1:%d, running in DNS over HTTP mode instead of DNS over HTTPS
+Configuration 'configs/dnsdist_TestDOHOverHTTPH2O.conf' OK!
+""" % (DOHOverHTTP._dohServerPort)
+
+class DOHWithCache(object):
_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_dohBaseURL = ("https://%s:%d/dns-query" % (_serverName, _dohServerPort))
_config_template = """
newServer{address="127.0.0.1:%s"}
- addDOHLocal("127.0.0.1:%s", "%s", "%s")
+ addDOHLocal("127.0.0.1:%s", "%s", "%s", '/dns-query', {library='%s'})
pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
getPool(""):setCache(pc)
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey']
+ _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
def testDOHCacheLargeAnswer(self):
"""
(_, receivedResponse) = self.sendUDPQuery(expectedQuery, response=None, useQueue=False)
self.assertEqual(response, receivedResponse)
-class TestDOHWithoutCacheControl(DNSDistDOHTest):
+class TestDOHWithCacheNGHTTP2(DOHWithCache, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+ _verboseMode = True
+
+class TestDOHWithCacheH2O(DOHWithCache, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
+
+class DOHWithoutCacheControl(object):
_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
_config_template = """
newServer{address="127.0.0.1:%s"}
- addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {sendCacheControlHeaders=false})
+ addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {sendCacheControlHeaders=false, library='%s'})
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey']
+ _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
def testDOHSimple(self):
"""
self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
self.assertEqual(response, receivedResponse)
-class TestDOHFFI(DNSDistDOHTest):
+class TestDOHWithoutCacheControlNGHTTP2(DOHWithoutCacheControl, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+
+class TestDOHWithoutCacheControlH2O(DOHWithoutCacheControl, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
+class DOHFFI(object):
_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_customResponseHeader1 = 'access-control-allow-origin: *'
_customResponseHeader2 = 'user-agent: derp'
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
_config_template = """
newServer{address="127.0.0.1:%s"}
- addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {customResponseHeaders={["access-control-allow-origin"]="*",["user-agent"]="derp",["UPPERCASE"]="VaLuE"}, keepIncomingHeaders=true})
+ addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {customResponseHeaders={["access-control-allow-origin"]="*",["user-agent"]="derp",["UPPERCASE"]="VaLuE"}, keepIncomingHeaders=true, library='%s'})
local ffi = require("ffi")
end
addAction("http-lua-ffi.doh.tests.powerdns.com.", LuaFFIAction(dohHandler))
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_serverName', '_dohServerPort']
+ _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary', '_serverName', '_dohServerPort']
def testHTTPLuaFFIResponse(self):
"""
self.assertEqual(self._rcode, 200)
self.assertTrue('content-type: text/plain' in self._response_headers.decode())
-class TestDOHForwardedFor(DNSDistDOHTest):
+class TestDOHFFINGHTTP2(DOHFFI, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+class TestDOHFFIH2O(DOHFFI, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
+
+class DOHForwardedFor(object):
_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
_config_template = """
newServer{address="127.0.0.1:%s"}
setACL('192.0.2.1/32')
- addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {trustForwardedForHeader=true})
+ addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {trustForwardedForHeader=true, library='%s'})
+ -- Set a maximum number of TCP connections per client, to exercise
+ -- that code along with X-Forwarded-For support
+ setMaxTCPConnectionsPerClient(2)
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey']
+ _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
def testDOHAllowedForwarded(self):
"""
(receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert, useQueue=False, rawResponse=True, customHeaders=['x-forwarded-for: 127.0.0.1:42, 127.0.0.1'])
self.assertEqual(self._rcode, 403)
- self.assertEqual(receivedResponse, b'dns query not allowed because of ACL')
+ self.assertEqual(receivedResponse, b'DoH query not allowed because of ACL')
+
+class TestDOHForwardedForNGHTTP2(DOHForwardedFor, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+
+class TestDOHForwardedForH2O(DOHForwardedFor, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
-class TestDOHForwardedForNoTrusted(DNSDistDOHTest):
+class DOHForwardedForNoTrusted(object):
_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
_config_template = """
newServer{address="127.0.0.1:%s"}
setACL('192.0.2.1/32')
- addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" })
+ addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {earlyACLDrop=true, library='%s'})
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey']
+ _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
def testDOHForwardedUntrusted(self):
"""
'127.0.0.1')
response.answer.append(rrset)
- (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert, useQueue=False, rawResponse=True, customHeaders=['x-forwarded-for: 192.0.2.1:4200'])
+ dropped = False
+ try:
+ (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert, useQueue=False, rawResponse=True, customHeaders=['x-forwarded-for: 192.0.2.1:4200'])
+ self.assertEqual(self._rcode, 403)
+ self.assertEqual(receivedResponse, b'DoH query not allowed because of ACL')
+ except pycurl.error as e:
+ dropped = True
- self.assertEqual(self._rcode, 403)
- self.assertEqual(receivedResponse, b'dns query not allowed because of ACL')
+ self.assertTrue(dropped)
+
+class TestDOHForwardedForNoTrustedNGHTTP2(DOHForwardedForNoTrusted, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
-class TestDOHFrontendLimits(DNSDistDOHTest):
+class TestDOHForwardedForNoTrustedH2O(DOHForwardedForNoTrusted, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
+
+class DOHFrontendLimits(object):
# this test suite uses a different responder port
# because it uses a different health check configuration
- _testServerPort = 5395
+ _testServerPort = pickAvailablePort()
_answerUnexpected = True
_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
-
_skipListeningOnCL = True
_maxTCPConnsPerDOHFrontend = 5
_config_template = """
newServer{address="127.0.0.1:%s"}
- addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, { maxConcurrentTCPConnections=%d })
+ addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, { maxConcurrentTCPConnections=%d, library='%s' })
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_maxTCPConnsPerDOHFrontend']
+ _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_maxTCPConnsPerDOHFrontend', '_dohLibrary']
_alternateListeningAddr = '127.0.0.1'
_alternateListeningPort = _dohServerPort
for idx in range(self._maxTCPConnsPerDOHFrontend + 1):
try:
- conns.append(self.openTLSConnection(self._dohServerPort, self._serverName, self._caCert))
+ alpn = []
+ if self._dohLibrary != 'h2o':
+ alpn.append('h2')
+ conns.append(self.openTLSConnection(self._dohServerPort, self._serverName, self._caCert, alpn=alpn))
except:
conns.append(None)
self.assertEqual(count, self._maxTCPConnsPerDOHFrontend)
self.assertEqual(failed, 1)
-class TestProtocols(DNSDistDOHTest):
+class TestDOHFrontendLimitsNGHTTP2(DOHFrontendLimits, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+
+class TestDOHFrontendLimitsH2O(DOHFrontendLimits, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
+
+class Protocols(object):
_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_customResponseHeader1 = 'access-control-allow-origin: *'
_customResponseHeader2 = 'user-agent: derp'
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
addAction("protocols.doh.tests.powerdns.com.", LuaAction(checkDOH))
newServer{address="127.0.0.1:%s"}
- addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" })
+ addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {library='%s'})
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey']
+ _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
def testProtocolDOH(self):
"""
self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery)
self.assertEqual(response, receivedResponse)
-class TestDOHWithPCKS12Cert(DNSDistDOHTest):
+class TestProtocolsNGHTTP2(Protocols, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+
+class TestProtocolsH2O(Protocols, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
+
+class DOHWithPKCS12Cert(object):
_serverCert = 'server.p12'
_pkcs12Password = 'passw0rd'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
_config_template = """
newServer{address="127.0.0.1:%s"}
cert=newTLSCertificate("%s", {password="%s"})
- addDOHLocal("127.0.0.1:%s", cert, "", { "/" })
+ addDOHLocal("127.0.0.1:%s", cert, "", { "/" }, {library='%s'})
"""
- _config_params = ['_testServerPort', '_serverCert', '_pkcs12Password', '_dohServerPort']
+ _config_params = ['_testServerPort', '_serverCert', '_pkcs12Password', '_dohServerPort', '_dohLibrary']
- def testProtocolDOH(self):
+ def testPKCS12DOH(self):
"""
- DoH: Test Simple DOH Query with a password protected PCKS12 file configured
+ DoH: Test Simple DOH Query with a password protected PKCS12 file configured
"""
name = 'simple.doh.tests.powerdns.com.'
query = dns.message.make_query(name, 'A', 'IN', use_edns=False)
receivedQuery.id = expectedQuery.id
self.assertEqual(expectedQuery, receivedQuery)
-class TestDOHForwardedToTCPOnly(DNSDistDOHTest):
+class TestDOHWithPKCS12CertNGHTTP2(DOHWithPKCS12Cert, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+
+class TestDOHWithPKCS12CertH2O(DOHWithPKCS12Cert, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
+
+class DOHForwardedToTCPOnly(object):
_serverKey = 'server.key'
_serverCert = 'server.chain'
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
_config_template = """
newServer{address="127.0.0.1:%s", tcpOnly=true}
- addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" })
+ addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {library='%s'})
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey']
+ _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary']
def testDOHTCPOnly(self):
"""
self.assertEqual(receivedQuery, query)
self.assertEqual(receivedResponse, response)
-class TestDOHLimits(DNSDistDOHTest):
+class TestDOHForwardedToTCPOnlyNGHTTP2(DOHForwardedToTCPOnly, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+
+class TestDOHForwardedToTCPOnlyH2O(DOHForwardedToTCPOnly, DNSDistDOHTest):
+ _dohLibrary = 'h2o'
+
+class DOHLimits(object):
_serverName = 'tls.tests.dnsdist.org'
_caCert = 'ca.pem'
- _dohServerPort = 8443
+ _dohServerPort = pickAvailablePort()
_dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort))
_serverKey = 'server.key'
_serverCert = 'server.chain'
_maxTCPConnsPerClient = 3
_config_template = """
- newServer{address="127.0.0.1:%s"}
- addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" })
- setMaxTCPConnectionsPerClient(%s)
+ newServer{address="127.0.0.1:%d"}
+ addDOHLocal("127.0.0.1:%d", "%s", "%s", { "/" }, {library='%s'})
+ setMaxTCPConnectionsPerClient(%d)
"""
- _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_maxTCPConnsPerClient']
+ _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_dohLibrary', '_maxTCPConnsPerClient']
def testConnsPerClient(self):
"""
self.assertEqual(count, self._maxTCPConnsPerClient)
self.assertEqual(failed, 1)
+
+class TestDOHLimitsNGHTTP2(DOHLimits, DNSDistDOHTest):
+ _dohLibrary = 'nghttp2'
+
+class TestDOHLimitsH2O(DOHLimits, DNSDistDOHTest):
+ _dohLibrary = 'h2o'