]>
Commit | Line | Data |
---|---|---|
10535d88 RG |
1 | #!/usr/bin/env python |
2 | import base64 | |
3 | import dns | |
13291274 | 4 | import os |
0026abf9 RG |
5 | import re |
6 | import time | |
13291274 | 7 | import unittest |
10535d88 RG |
8 | import clientsubnetoption |
9 | from dnsdisttests import DNSDistTest | |
10 | ||
11 | import pycurl | |
811872fb | 12 | from io import BytesIO |
10535d88 RG |
13 | #from hyper import HTTP20Connection |
14 | #from hyper.ssl_compat import SSLContext, PROTOCOL_TLSv1_2 | |
15 | ||
13291274 | 16 | @unittest.skipIf('SKIP_DOH_TESTS' in os.environ, 'DNS over HTTPS tests are disabled') |
10535d88 RG |
17 | class DNSDistDOHTest(DNSDistTest): |
18 | ||
19 | @classmethod | |
47225117 RG |
20 | def getDOHGetURL(cls, baseurl, query, rawQuery=False): |
21 | if rawQuery: | |
22 | wire = query | |
23 | else: | |
24 | wire = query.to_wire() | |
10535d88 RG |
25 | param = base64.urlsafe_b64encode(wire).decode('UTF8').rstrip('=') |
26 | return baseurl + "?dns=" + param | |
27 | ||
28 | @classmethod | |
29 | def openDOHConnection(cls, port, caFile, timeout=2.0): | |
30 | conn = pycurl.Curl() | |
31 | conn.setopt(pycurl.HTTP_VERSION, pycurl.CURL_HTTP_VERSION_2) | |
32 | ||
33 | conn.setopt(pycurl.HTTPHEADER, ["Content-type: application/dns-message", | |
34 | "Accept: application/dns-message"]) | |
35 | return conn | |
36 | ||
37 | @classmethod | |
44947230 | 38 | def sendDOHQuery(cls, port, servername, baseurl, query, response=None, timeout=2.0, caFile=None, useQueue=True, rawQuery=False, rawResponse=False, customHeaders=[], useHTTPS=True): |
47225117 | 39 | url = cls.getDOHGetURL(baseurl, query, rawQuery) |
10535d88 | 40 | conn = cls.openDOHConnection(port, caFile=caFile, timeout=timeout) |
811872fb | 41 | response_headers = BytesIO() |
10535d88 RG |
42 | #conn.setopt(pycurl.VERBOSE, True) |
43 | conn.setopt(pycurl.URL, url) | |
44 | conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (servername, port)]) | |
44947230 RG |
45 | if useHTTPS: |
46 | conn.setopt(pycurl.SSL_VERIFYPEER, 1) | |
47 | conn.setopt(pycurl.SSL_VERIFYHOST, 2) | |
48 | if caFile: | |
49 | conn.setopt(pycurl.CAINFO, caFile) | |
50 | ||
9ba32868 | 51 | conn.setopt(pycurl.HTTPHEADER, customHeaders) |
ee01507f | 52 | conn.setopt(pycurl.HEADERFUNCTION, response_headers.write) |
10535d88 RG |
53 | |
54 | if response: | |
55 | cls._toResponderQueue.put(response, True, timeout) | |
56 | ||
57 | receivedQuery = None | |
58 | message = None | |
ee01507f | 59 | cls._response_headers = '' |
10535d88 | 60 | data = conn.perform_rb() |
9676d2a9 RG |
61 | cls._rcode = conn.getinfo(pycurl.RESPONSE_CODE) |
62 | if cls._rcode == 200 and not rawResponse: | |
10535d88 | 63 | message = dns.message.from_wire(data) |
9676d2a9 RG |
64 | elif rawResponse: |
65 | message = data | |
10535d88 RG |
66 | |
67 | if useQueue and not cls._fromResponderQueue.empty(): | |
68 | receivedQuery = cls._fromResponderQueue.get(True, timeout) | |
69 | ||
ee01507f | 70 | cls._response_headers = response_headers.getvalue() |
10535d88 RG |
71 | return (receivedQuery, message) |
72 | ||
b1e527ad | 73 | @classmethod |
44947230 | 74 | def sendDOHPostQuery(cls, port, servername, baseurl, query, response=None, timeout=2.0, caFile=None, useQueue=True, rawQuery=False, rawResponse=False, customHeaders=[], useHTTPS=True): |
b1e527ad RG |
75 | url = baseurl |
76 | conn = cls.openDOHConnection(port, caFile=caFile, timeout=timeout) | |
9676d2a9 | 77 | response_headers = BytesIO() |
b1e527ad RG |
78 | #conn.setopt(pycurl.VERBOSE, True) |
79 | conn.setopt(pycurl.URL, url) | |
80 | conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (servername, port)]) | |
44947230 RG |
81 | if useHTTPS: |
82 | conn.setopt(pycurl.SSL_VERIFYPEER, 1) | |
83 | conn.setopt(pycurl.SSL_VERIFYHOST, 2) | |
84 | if caFile: | |
85 | conn.setopt(pycurl.CAINFO, caFile) | |
86 | ||
9676d2a9 RG |
87 | conn.setopt(pycurl.HTTPHEADER, customHeaders) |
88 | conn.setopt(pycurl.HEADERFUNCTION, response_headers.write) | |
b1e527ad RG |
89 | conn.setopt(pycurl.POST, True) |
90 | data = query | |
91 | if not rawQuery: | |
92 | data = data.to_wire() | |
93 | ||
94 | conn.setopt(pycurl.POSTFIELDS, data) | |
95 | ||
b1e527ad RG |
96 | if response: |
97 | cls._toResponderQueue.put(response, True, timeout) | |
98 | ||
99 | receivedQuery = None | |
100 | message = None | |
9676d2a9 | 101 | cls._response_headers = '' |
b1e527ad | 102 | data = conn.perform_rb() |
9676d2a9 RG |
103 | cls._rcode = conn.getinfo(pycurl.RESPONSE_CODE) |
104 | if cls._rcode == 200 and not rawResponse: | |
b1e527ad | 105 | message = dns.message.from_wire(data) |
9676d2a9 RG |
106 | elif rawResponse: |
107 | message = data | |
b1e527ad RG |
108 | |
109 | if useQueue and not cls._fromResponderQueue.empty(): | |
110 | receivedQuery = cls._fromResponderQueue.get(True, timeout) | |
111 | ||
9676d2a9 | 112 | cls._response_headers = response_headers.getvalue() |
b1e527ad RG |
113 | return (receivedQuery, message) |
114 | ||
0026abf9 RG |
115 | def getHeaderValue(self, name): |
116 | for header in self._response_headers.decode().splitlines(False): | |
117 | values = header.split(':') | |
118 | key = values[0] | |
119 | if key.lower() == name.lower(): | |
120 | return values[1].strip() | |
121 | return None | |
122 | ||
123 | def checkHasHeader(self, name, value): | |
124 | got = self.getHeaderValue(name) | |
125 | self.assertEquals(got, value) | |
126 | ||
127 | def checkNoHeader(self, name): | |
128 | self.checkHasHeader(name, None) | |
129 | ||
13291274 RG |
130 | @classmethod |
131 | def setUpClass(cls): | |
132 | ||
133 | # for some reason, @unittest.skipIf() is not applied to derived classes with some versions of Python | |
134 | if 'SKIP_DOH_TESTS' in os.environ: | |
135 | raise unittest.SkipTest('DNS over HTTPS tests are disabled') | |
136 | ||
137 | cls.startResponders() | |
138 | cls.startDNSDist() | |
139 | cls.setUpSockets() | |
140 | ||
141 | print("Launching tests..") | |
142 | ||
10535d88 RG |
143 | # @classmethod |
144 | # def openDOHConnection(cls, port, caFile, timeout=2.0): | |
145 | # sslctx = SSLContext(PROTOCOL_TLSv1_2) | |
146 | # sslctx.load_verify_locations(caFile) | |
147 | # return HTTP20Connection('127.0.0.1', port=port, secure=True, timeout=timeout, ssl_context=sslctx, force_proto='h2') | |
148 | ||
149 | # @classmethod | |
150 | # def sendDOHQueryOverConnection(cls, conn, baseurl, query, response=None, timeout=2.0): | |
151 | # url = cls.getDOHGetURL(baseurl, query) | |
152 | ||
153 | # if response: | |
154 | # cls._toResponderQueue.put(response, True, timeout) | |
155 | ||
156 | # conn.request('GET', url) | |
157 | ||
158 | # @classmethod | |
159 | # def recvDOHResponseOverConnection(cls, conn, useQueue=False, timeout=2.0): | |
160 | # message = None | |
161 | # data = conn.get_response() | |
162 | # if data: | |
163 | # data = data.read() | |
164 | # if data: | |
165 | # message = dns.message.from_wire(data) | |
166 | ||
167 | # if useQueue and not cls._fromResponderQueue.empty(): | |
168 | # receivedQuery = cls._fromResponderQueue.get(True, timeout) | |
169 | # return (receivedQuery, message) | |
170 | # else: | |
171 | # return message | |
172 | ||
173 | class TestDOH(DNSDistDOHTest): | |
174 | ||
175 | _serverKey = 'server.key' | |
176 | _serverCert = 'server.chain' | |
177 | _serverName = 'tls.tests.dnsdist.org' | |
178 | _caCert = 'ca.pem' | |
179 | _dohServerPort = 8443 | |
ee01507f CR |
180 | _customResponseHeader1 = 'access-control-allow-origin: *' |
181 | _customResponseHeader2 = 'user-agent: derp' | |
10535d88 RG |
182 | _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort)) |
183 | _config_template = """ | |
184 | newServer{address="127.0.0.1:%s"} | |
ee01507f | 185 | |
767fbba3 | 186 | addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/", "/coffee", "/PowerDNS", "/PowerDNS2", "/PowerDNS-999" }, {customResponseHeaders={["access-control-allow-origin"]="*",["user-agent"]="derp",["UPPERCASE"]="VaLuE"}}) |
28b56482 | 187 | dohFE = getDOHFrontend(0) |
e1b72559 | 188 | dohFE:setResponsesMap({newDOHResponseMapEntry('^/coffee$', 418, 'C0FFEE', {['FoO']='bar'})}) |
10535d88 RG |
189 | |
190 | addAction("drop.doh.tests.powerdns.com.", DropAction()) | |
191 | addAction("refused.doh.tests.powerdns.com.", RCodeAction(DNSRCode.REFUSED)) | |
192 | addAction("spoof.doh.tests.powerdns.com.", SpoofAction("1.2.3.4")) | |
9ba32868 RG |
193 | addAction(HTTPHeaderRule("X-PowerDNS", "^[a]{5}$"), SpoofAction("2.3.4.5")) |
194 | addAction(HTTPPathRule("/PowerDNS"), SpoofAction("3.4.5.6")) | |
9676d2a9 RG |
195 | addAction(HTTPPathRegexRule("^/PowerDNS-[0-9]"), SpoofAction("6.7.8.9")) |
196 | addAction("http-status-action.doh.tests.powerdns.com.", HTTPStatusAction(200, "Plaintext answer", "text/plain")) | |
197 | addAction("http-status-action-redirect.doh.tests.powerdns.com.", HTTPStatusAction(307, "https://doh.powerdns.org")) | |
198 | ||
199 | function dohHandler(dq) | |
200 | if dq:getHTTPScheme() == 'https' and dq:getHTTPHost() == '%s:%d' and dq:getHTTPPath() == '/' and dq:getHTTPQueryString() == '' then | |
201 | local foundct = false | |
202 | for key,value in pairs(dq:getHTTPHeaders()) do | |
203 | if key == 'content-type' and value == 'application/dns-message' then | |
204 | foundct = true | |
205 | break | |
206 | end | |
207 | end | |
208 | if foundct then | |
209 | dq:setHTTPResponse(200, 'It works!', 'text/plain') | |
210 | dq.dh:setQR(true) | |
211 | return DNSAction.HeaderModify | |
212 | end | |
213 | end | |
214 | return DNSAction.None | |
215 | end | |
216 | addAction("http-lua.doh.tests.powerdns.com.", LuaAction(dohHandler)) | |
10535d88 | 217 | """ |
9676d2a9 | 218 | _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_serverName', '_dohServerPort'] |
10535d88 RG |
219 | |
220 | def testDOHSimple(self): | |
221 | """ | |
222 | DOH: Simple query | |
223 | """ | |
224 | name = 'simple.doh.tests.powerdns.com.' | |
225 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
226 | query.id = 0 | |
227 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
228 | expectedQuery.id = 0 | |
229 | response = dns.message.make_response(query) | |
230 | rrset = dns.rrset.from_text(name, | |
231 | 3600, | |
232 | dns.rdataclass.IN, | |
233 | dns.rdatatype.A, | |
234 | '127.0.0.1') | |
235 | response.answer.append(rrset) | |
236 | ||
237 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
238 | self.assertTrue(receivedQuery) | |
239 | self.assertTrue(receivedResponse) | |
240 | receivedQuery.id = expectedQuery.id | |
241 | self.assertEquals(expectedQuery, receivedQuery) | |
811872fb RG |
242 | self.assertTrue((self._customResponseHeader1) in self._response_headers.decode()) |
243 | self.assertTrue((self._customResponseHeader2) in self._response_headers.decode()) | |
cf3e149b RG |
244 | self.assertFalse(('UPPERCASE: VaLuE' in self._response_headers.decode())) |
245 | self.assertTrue(('uppercase: VaLuE' in self._response_headers.decode())) | |
0026abf9 | 246 | self.assertTrue(('cache-control: max-age=3600' in self._response_headers.decode())) |
10535d88 RG |
247 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) |
248 | self.assertEquals(response, receivedResponse) | |
0026abf9 | 249 | self.checkHasHeader('cache-control', 'max-age=3600') |
10535d88 | 250 | |
b1e527ad RG |
251 | def testDOHSimplePOST(self): |
252 | """ | |
253 | DOH: Simple POST query | |
254 | """ | |
255 | name = 'simple-post.doh.tests.powerdns.com.' | |
256 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
257 | query.id = 0 | |
258 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
259 | expectedQuery.id = 0 | |
260 | response = dns.message.make_response(query) | |
261 | rrset = dns.rrset.from_text(name, | |
262 | 3600, | |
263 | dns.rdataclass.IN, | |
264 | dns.rdatatype.A, | |
265 | '127.0.0.1') | |
266 | response.answer.append(rrset) | |
267 | ||
268 | (receivedQuery, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
269 | self.assertTrue(receivedQuery) | |
270 | self.assertTrue(receivedResponse) | |
271 | receivedQuery.id = expectedQuery.id | |
272 | self.assertEquals(expectedQuery, receivedQuery) | |
273 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
274 | self.assertEquals(response, receivedResponse) | |
275 | ||
10535d88 RG |
276 | def testDOHExistingEDNS(self): |
277 | """ | |
278 | DOH: Existing EDNS | |
279 | """ | |
280 | name = 'existing-edns.doh.tests.powerdns.com.' | |
281 | query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=8192) | |
282 | query.id = 0 | |
283 | response = dns.message.make_response(query) | |
284 | rrset = dns.rrset.from_text(name, | |
285 | 3600, | |
286 | dns.rdataclass.IN, | |
287 | dns.rdatatype.A, | |
288 | '127.0.0.1') | |
289 | response.answer.append(rrset) | |
290 | ||
291 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
292 | self.assertTrue(receivedQuery) | |
293 | self.assertTrue(receivedResponse) | |
294 | receivedQuery.id = query.id | |
295 | self.assertEquals(query, receivedQuery) | |
296 | self.assertEquals(response, receivedResponse) | |
297 | self.checkQueryEDNSWithoutECS(query, receivedQuery) | |
298 | self.checkResponseEDNSWithoutECS(response, receivedResponse) | |
299 | ||
300 | def testDOHExistingECS(self): | |
301 | """ | |
302 | DOH: Existing EDNS Client Subnet | |
303 | """ | |
304 | name = 'existing-ecs.doh.tests.powerdns.com.' | |
305 | ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4') | |
306 | rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24) | |
307 | query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[ecso], want_dnssec=True) | |
308 | query.id = 0 | |
309 | response = dns.message.make_response(query) | |
310 | response.use_edns(edns=True, payload=4096, options=[rewrittenEcso]) | |
311 | rrset = dns.rrset.from_text(name, | |
312 | 3600, | |
313 | dns.rdataclass.IN, | |
314 | dns.rdatatype.A, | |
315 | '127.0.0.1') | |
316 | response.answer.append(rrset) | |
317 | ||
318 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
319 | self.assertTrue(receivedQuery) | |
320 | self.assertTrue(receivedResponse) | |
321 | receivedQuery.id = query.id | |
322 | self.assertEquals(query, receivedQuery) | |
323 | self.assertEquals(response, receivedResponse) | |
324 | self.checkQueryEDNSWithECS(query, receivedQuery) | |
325 | self.checkResponseEDNSWithECS(response, receivedResponse) | |
326 | ||
327 | def testDropped(self): | |
328 | """ | |
329 | DOH: Dropped query | |
330 | """ | |
331 | name = 'drop.doh.tests.powerdns.com.' | |
332 | query = dns.message.make_query(name, 'A', 'IN') | |
333 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=query, response=None, useQueue=False) | |
10535d88 RG |
334 | self.assertEquals(receivedResponse, None) |
335 | ||
336 | def testRefused(self): | |
337 | """ | |
338 | DOH: Refused | |
339 | """ | |
340 | name = 'refused.doh.tests.powerdns.com.' | |
341 | query = dns.message.make_query(name, 'A', 'IN') | |
342 | query.id = 0 | |
7af22479 | 343 | query.flags &= ~dns.flags.RD |
10535d88 RG |
344 | expectedResponse = dns.message.make_response(query) |
345 | expectedResponse.set_rcode(dns.rcode.REFUSED) | |
346 | ||
347 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=query, response=None, useQueue=False) | |
348 | self.assertEquals(receivedResponse, expectedResponse) | |
349 | ||
350 | def testSpoof(self): | |
351 | """ | |
352 | DOH: Spoofed | |
353 | """ | |
354 | name = 'spoof.doh.tests.powerdns.com.' | |
355 | query = dns.message.make_query(name, 'A', 'IN') | |
356 | query.id = 0 | |
357 | query.flags &= ~dns.flags.RD | |
358 | expectedResponse = dns.message.make_response(query) | |
359 | rrset = dns.rrset.from_text(name, | |
360 | 3600, | |
361 | dns.rdataclass.IN, | |
362 | dns.rdatatype.A, | |
363 | '1.2.3.4') | |
364 | expectedResponse.answer.append(rrset) | |
365 | ||
366 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=query, response=None, useQueue=False) | |
367 | self.assertEquals(receivedResponse, expectedResponse) | |
368 | ||
47225117 RG |
369 | def testDOHInvalid(self): |
370 | """ | |
371 | DOH: Invalid query | |
372 | """ | |
373 | name = 'invalid.doh.tests.powerdns.com.' | |
374 | invalidQuery = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
375 | invalidQuery.id = 0 | |
376 | # first an invalid query | |
377 | invalidQuery = invalidQuery.to_wire() | |
378 | invalidQuery = invalidQuery[:-5] | |
379 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=invalidQuery, response=None, useQueue=False, rawQuery=True) | |
380 | self.assertEquals(receivedResponse, None) | |
381 | ||
382 | # and now a valid one | |
383 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
384 | query.id = 0 | |
385 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
386 | expectedQuery.id = 0 | |
387 | response = dns.message.make_response(query) | |
388 | rrset = dns.rrset.from_text(name, | |
389 | 3600, | |
390 | dns.rdataclass.IN, | |
391 | dns.rdatatype.A, | |
392 | '127.0.0.1') | |
393 | response.answer.append(rrset) | |
394 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
395 | self.assertTrue(receivedQuery) | |
396 | self.assertTrue(receivedResponse) | |
397 | receivedQuery.id = expectedQuery.id | |
398 | self.assertEquals(expectedQuery, receivedQuery) | |
399 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
400 | self.assertEquals(response, receivedResponse) | |
10535d88 | 401 | |
2cb8efb1 RG |
402 | def testDOHWithoutQuery(self): |
403 | """ | |
404 | DOH: Empty GET query | |
405 | """ | |
406 | name = 'empty-get.doh.tests.powerdns.com.' | |
407 | url = self._dohBaseURL | |
408 | conn = self.openDOHConnection(self._dohServerPort, self._caCert, timeout=2.0) | |
409 | conn.setopt(pycurl.URL, url) | |
410 | conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)]) | |
411 | conn.setopt(pycurl.SSL_VERIFYPEER, 1) | |
412 | conn.setopt(pycurl.SSL_VERIFYHOST, 2) | |
413 | conn.setopt(pycurl.CAINFO, self._caCert) | |
414 | data = conn.perform_rb() | |
415 | rcode = conn.getinfo(pycurl.RESPONSE_CODE) | |
416 | self.assertEquals(rcode, 400) | |
417 | ||
b1e527ad RG |
418 | def testDOHEmptyPOST(self): |
419 | """ | |
420 | DOH: Empty POST query | |
421 | """ | |
422 | name = 'empty-post.doh.tests.powerdns.com.' | |
423 | ||
424 | (_, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query="", rawQuery=True, response=None, caFile=self._caCert) | |
425 | self.assertEquals(receivedResponse, None) | |
426 | ||
427 | # and now a valid one | |
428 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
429 | query.id = 0 | |
430 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
431 | expectedQuery.id = 0 | |
432 | response = dns.message.make_response(query) | |
433 | rrset = dns.rrset.from_text(name, | |
434 | 3600, | |
435 | dns.rdataclass.IN, | |
436 | dns.rdatatype.A, | |
437 | '127.0.0.1') | |
438 | response.answer.append(rrset) | |
439 | (receivedQuery, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
440 | self.assertTrue(receivedQuery) | |
441 | self.assertTrue(receivedResponse) | |
442 | receivedQuery.id = expectedQuery.id | |
443 | self.assertEquals(expectedQuery, receivedQuery) | |
444 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
445 | self.assertEquals(response, receivedResponse) | |
446 | ||
9ba32868 RG |
447 | def testHeaderRule(self): |
448 | """ | |
449 | DOH: HeaderRule | |
450 | """ | |
451 | name = 'header-rule.doh.tests.powerdns.com.' | |
452 | query = dns.message.make_query(name, 'A', 'IN') | |
453 | query.id = 0 | |
454 | query.flags &= ~dns.flags.RD | |
455 | expectedResponse = dns.message.make_response(query) | |
456 | rrset = dns.rrset.from_text(name, | |
457 | 3600, | |
458 | dns.rdataclass.IN, | |
459 | dns.rdatatype.A, | |
460 | '2.3.4.5') | |
461 | expectedResponse.answer.append(rrset) | |
462 | ||
463 | # this header should match | |
464 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, caFile=self._caCert, query=query, response=None, useQueue=False, customHeaders=['x-powerdnS: aaaaa']) | |
465 | self.assertEquals(receivedResponse, expectedResponse) | |
466 | ||
467 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
468 | expectedQuery.flags &= ~dns.flags.RD | |
469 | expectedQuery.id = 0 | |
470 | response = dns.message.make_response(query) | |
471 | rrset = dns.rrset.from_text(name, | |
472 | 3600, | |
473 | dns.rdataclass.IN, | |
474 | dns.rdatatype.A, | |
475 | '127.0.0.1') | |
476 | response.answer.append(rrset) | |
477 | ||
478 | # this content of the header should NOT match | |
479 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert, customHeaders=['x-powerdnS: bbbbb']) | |
480 | self.assertTrue(receivedQuery) | |
481 | self.assertTrue(receivedResponse) | |
482 | receivedQuery.id = expectedQuery.id | |
483 | self.assertEquals(expectedQuery, receivedQuery) | |
484 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
485 | self.assertEquals(response, receivedResponse) | |
486 | ||
487 | def testHTTPPath(self): | |
488 | """ | |
489 | DOH: HTTPPath | |
490 | """ | |
491 | name = 'http-path.doh.tests.powerdns.com.' | |
492 | query = dns.message.make_query(name, 'A', 'IN') | |
493 | query.id = 0 | |
494 | query.flags &= ~dns.flags.RD | |
495 | expectedResponse = dns.message.make_response(query) | |
496 | rrset = dns.rrset.from_text(name, | |
497 | 3600, | |
498 | dns.rdataclass.IN, | |
499 | dns.rdatatype.A, | |
500 | '3.4.5.6') | |
501 | expectedResponse.answer.append(rrset) | |
502 | ||
503 | # this path should match | |
504 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + 'PowerDNS', caFile=self._caCert, query=query, response=None, useQueue=False) | |
505 | self.assertEquals(receivedResponse, expectedResponse) | |
506 | ||
507 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
508 | expectedQuery.id = 0 | |
509 | expectedQuery.flags &= ~dns.flags.RD | |
510 | response = dns.message.make_response(query) | |
511 | rrset = dns.rrset.from_text(name, | |
512 | 3600, | |
513 | dns.rdataclass.IN, | |
514 | dns.rdatatype.A, | |
515 | '127.0.0.1') | |
516 | response.answer.append(rrset) | |
517 | ||
518 | # this path should NOT match | |
519 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + "PowerDNS2", query, response=response, caFile=self._caCert) | |
520 | self.assertTrue(receivedQuery) | |
521 | self.assertTrue(receivedResponse) | |
522 | receivedQuery.id = expectedQuery.id | |
523 | self.assertEquals(expectedQuery, receivedQuery) | |
524 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
525 | self.assertEquals(response, receivedResponse) | |
526 | ||
767fbba3 RG |
527 | # this path is not in the URLs map and should lead to a 404 |
528 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + "PowerDNS/something", query, caFile=self._caCert, useQueue=False, rawResponse=True) | |
529 | self.assertTrue(receivedResponse) | |
530 | self.assertEquals(receivedResponse, b'there is no endpoint configured for this path') | |
531 | self.assertEquals(self._rcode, 404) | |
532 | ||
9676d2a9 RG |
533 | def testHTTPPathRegex(self): |
534 | """ | |
535 | DOH: HTTPPathRegex | |
536 | """ | |
537 | name = 'http-path-regex.doh.tests.powerdns.com.' | |
538 | query = dns.message.make_query(name, 'A', 'IN') | |
539 | query.id = 0 | |
540 | query.flags &= ~dns.flags.RD | |
541 | expectedResponse = dns.message.make_response(query) | |
542 | rrset = dns.rrset.from_text(name, | |
543 | 3600, | |
544 | dns.rdataclass.IN, | |
545 | dns.rdatatype.A, | |
546 | '6.7.8.9') | |
547 | expectedResponse.answer.append(rrset) | |
548 | ||
549 | # this path should match | |
550 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + 'PowerDNS-999', caFile=self._caCert, query=query, response=None, useQueue=False) | |
551 | self.assertEquals(receivedResponse, expectedResponse) | |
552 | ||
553 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
554 | expectedQuery.id = 0 | |
555 | expectedQuery.flags &= ~dns.flags.RD | |
556 | response = dns.message.make_response(query) | |
557 | rrset = dns.rrset.from_text(name, | |
558 | 3600, | |
559 | dns.rdataclass.IN, | |
560 | dns.rdatatype.A, | |
561 | '127.0.0.1') | |
562 | response.answer.append(rrset) | |
563 | ||
564 | # this path should NOT match | |
565 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + "PowerDNS2", query, response=response, caFile=self._caCert) | |
566 | self.assertTrue(receivedQuery) | |
567 | self.assertTrue(receivedResponse) | |
568 | receivedQuery.id = expectedQuery.id | |
569 | self.assertEquals(expectedQuery, receivedQuery) | |
570 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
571 | self.assertEquals(response, receivedResponse) | |
572 | ||
573 | def testHTTPStatusAction200(self): | |
574 | """ | |
575 | DOH: HTTPStatusAction 200 OK | |
576 | """ | |
577 | name = 'http-status-action.doh.tests.powerdns.com.' | |
578 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
579 | query.id = 0 | |
580 | ||
581 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, rawResponse=True) | |
582 | self.assertTrue(receivedResponse) | |
583 | self.assertEquals(receivedResponse, b'Plaintext answer') | |
584 | self.assertEquals(self._rcode, 200) | |
585 | self.assertTrue('content-type: text/plain' in self._response_headers.decode()) | |
586 | ||
587 | def testHTTPStatusAction307(self): | |
588 | """ | |
589 | DOH: HTTPStatusAction 307 | |
590 | """ | |
591 | name = 'http-status-action-redirect.doh.tests.powerdns.com.' | |
592 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
593 | query.id = 0 | |
594 | ||
595 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, rawResponse=True) | |
596 | self.assertTrue(receivedResponse) | |
597 | self.assertEquals(self._rcode, 307) | |
598 | self.assertTrue('location: https://doh.powerdns.org' in self._response_headers.decode()) | |
599 | ||
600 | def testHTTPLuaResponse(self): | |
601 | """ | |
602 | DOH: Lua HTTP Response | |
603 | """ | |
604 | name = 'http-lua.doh.tests.powerdns.com.' | |
605 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
606 | query.id = 0 | |
607 | ||
608 | (_, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, rawResponse=True) | |
609 | self.assertTrue(receivedResponse) | |
610 | self.assertEquals(receivedResponse, b'It works!') | |
611 | self.assertEquals(self._rcode, 200) | |
612 | self.assertTrue('content-type: text/plain' in self._response_headers.decode()) | |
613 | ||
28b56482 RG |
614 | def testHTTPEarlyResponse(self): |
615 | """ | |
616 | DOH: HTTP Early Response | |
617 | """ | |
ded6907c | 618 | response_headers = BytesIO() |
28b56482 RG |
619 | url = self._dohBaseURL + 'coffee' |
620 | conn = self.openDOHConnection(self._dohServerPort, caFile=self._caCert, timeout=2.0) | |
621 | conn.setopt(pycurl.URL, url) | |
622 | conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)]) | |
623 | conn.setopt(pycurl.SSL_VERIFYPEER, 1) | |
624 | conn.setopt(pycurl.SSL_VERIFYHOST, 2) | |
625 | conn.setopt(pycurl.CAINFO, self._caCert) | |
ded6907c | 626 | conn.setopt(pycurl.HEADERFUNCTION, response_headers.write) |
28b56482 RG |
627 | data = conn.perform_rb() |
628 | rcode = conn.getinfo(pycurl.RESPONSE_CODE) | |
9b2ef603 | 629 | headers = response_headers.getvalue().decode() |
28b56482 RG |
630 | |
631 | self.assertEquals(rcode, 418) | |
632 | self.assertEquals(data, b'C0FFEE') | |
ded6907c RG |
633 | self.assertIn('foo: bar', headers) |
634 | self.assertNotIn(self._customResponseHeader2, headers) | |
28b56482 | 635 | |
ded6907c | 636 | response_headers = BytesIO() |
28b56482 RG |
637 | conn = self.openDOHConnection(self._dohServerPort, caFile=self._caCert, timeout=2.0) |
638 | conn.setopt(pycurl.URL, url) | |
639 | conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)]) | |
640 | conn.setopt(pycurl.SSL_VERIFYPEER, 1) | |
641 | conn.setopt(pycurl.SSL_VERIFYHOST, 2) | |
642 | conn.setopt(pycurl.CAINFO, self._caCert) | |
ded6907c | 643 | conn.setopt(pycurl.HEADERFUNCTION, response_headers.write) |
28b56482 RG |
644 | conn.setopt(pycurl.POST, True) |
645 | data = '' | |
646 | conn.setopt(pycurl.POSTFIELDS, data) | |
647 | ||
648 | data = conn.perform_rb() | |
649 | rcode = conn.getinfo(pycurl.RESPONSE_CODE) | |
9b2ef603 | 650 | headers = response_headers.getvalue().decode() |
28b56482 RG |
651 | self.assertEquals(rcode, 418) |
652 | self.assertEquals(data, b'C0FFEE') | |
ded6907c RG |
653 | self.assertIn('foo: bar', headers) |
654 | self.assertNotIn(self._customResponseHeader2, headers) | |
28b56482 | 655 | |
10535d88 RG |
656 | class TestDOHAddingECS(DNSDistDOHTest): |
657 | ||
658 | _serverKey = 'server.key' | |
659 | _serverCert = 'server.chain' | |
660 | _serverName = 'tls.tests.dnsdist.org' | |
661 | _caCert = 'ca.pem' | |
662 | _dohServerPort = 8443 | |
10535d88 RG |
663 | _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort)) |
664 | _config_template = """ | |
665 | newServer{address="127.0.0.1:%s", useClientSubnet=true} | |
666 | addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }) | |
667 | setECSOverride(true) | |
668 | """ | |
669 | _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey'] | |
670 | ||
671 | def testDOHSimple(self): | |
672 | """ | |
673 | DOH with ECS: Simple query | |
674 | """ | |
675 | name = 'simple.doh-ecs.tests.powerdns.com.' | |
676 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
677 | query.id = 0 | |
678 | rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24) | |
679 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso]) | |
680 | response = dns.message.make_response(query) | |
681 | rrset = dns.rrset.from_text(name, | |
682 | 3600, | |
683 | dns.rdataclass.IN, | |
684 | dns.rdatatype.A, | |
685 | '127.0.0.1') | |
686 | response.answer.append(rrset) | |
687 | ||
688 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
689 | self.assertTrue(receivedQuery) | |
690 | self.assertTrue(receivedResponse) | |
691 | expectedQuery.id = receivedQuery.id | |
692 | self.assertEquals(expectedQuery, receivedQuery) | |
693 | self.checkQueryEDNSWithECS(expectedQuery, receivedQuery) | |
694 | self.assertEquals(response, receivedResponse) | |
695 | self.checkResponseNoEDNS(response, receivedResponse) | |
696 | ||
697 | def testDOHExistingEDNS(self): | |
698 | """ | |
699 | DOH with ECS: Existing EDNS | |
700 | """ | |
701 | name = 'existing-edns.doh-ecs.tests.powerdns.com.' | |
702 | query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=8192) | |
703 | query.id = 0 | |
704 | rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24) | |
705 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=8192, options=[rewrittenEcso]) | |
706 | response = dns.message.make_response(query) | |
707 | rrset = dns.rrset.from_text(name, | |
708 | 3600, | |
709 | dns.rdataclass.IN, | |
710 | dns.rdatatype.A, | |
711 | '127.0.0.1') | |
712 | response.answer.append(rrset) | |
713 | ||
714 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
715 | self.assertTrue(receivedQuery) | |
716 | self.assertTrue(receivedResponse) | |
717 | receivedQuery.id = expectedQuery.id | |
718 | self.assertEquals(expectedQuery, receivedQuery) | |
719 | self.assertEquals(response, receivedResponse) | |
720 | self.checkQueryEDNSWithECS(expectedQuery, receivedQuery) | |
721 | self.checkResponseEDNSWithoutECS(response, receivedResponse) | |
722 | ||
723 | def testDOHExistingECS(self): | |
724 | """ | |
725 | DOH with ECS: Existing EDNS Client Subnet | |
726 | """ | |
727 | name = 'existing-ecs.doh-ecs.tests.powerdns.com.' | |
728 | ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4') | |
729 | rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24) | |
730 | query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[ecso], want_dnssec=True) | |
731 | query.id = 0 | |
732 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[rewrittenEcso]) | |
733 | response = dns.message.make_response(query) | |
734 | response.use_edns(edns=True, payload=4096, options=[rewrittenEcso]) | |
735 | rrset = dns.rrset.from_text(name, | |
736 | 3600, | |
737 | dns.rdataclass.IN, | |
738 | dns.rdatatype.A, | |
739 | '127.0.0.1') | |
740 | response.answer.append(rrset) | |
741 | ||
742 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
743 | self.assertTrue(receivedQuery) | |
744 | self.assertTrue(receivedResponse) | |
745 | receivedQuery.id = expectedQuery.id | |
746 | self.assertEquals(expectedQuery, receivedQuery) | |
747 | self.assertEquals(response, receivedResponse) | |
748 | self.checkQueryEDNSWithECS(expectedQuery, receivedQuery) | |
749 | self.checkResponseEDNSWithECS(response, receivedResponse) | |
44947230 RG |
750 | |
751 | class TestDOHOverHTTP(DNSDistDOHTest): | |
752 | ||
753 | _dohServerPort = 8480 | |
754 | _serverName = 'tls.tests.dnsdist.org' | |
755 | _dohBaseURL = ("http://%s:%d/" % (_serverName, _dohServerPort)) | |
756 | _config_template = """ | |
757 | newServer{address="127.0.0.1:%s"} | |
758 | addDOHLocal("127.0.0.1:%s") | |
759 | """ | |
760 | _config_params = ['_testServerPort', '_dohServerPort'] | |
11c22318 RG |
761 | _checkConfigExpectedOutput = b"""No certificate provided for DoH endpoint 127.0.0.1:8480, running in DNS over HTTP mode instead of DNS over HTTPS |
762 | Configuration 'configs/dnsdist_TestDOHOverHTTP.conf' OK! | |
763 | """ | |
44947230 RG |
764 | |
765 | def testDOHSimple(self): | |
766 | """ | |
767 | DOH over HTTP: Simple query | |
768 | """ | |
769 | name = 'simple.doh-over-http.tests.powerdns.com.' | |
770 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
771 | query.id = 0 | |
772 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
773 | response = dns.message.make_response(query) | |
774 | rrset = dns.rrset.from_text(name, | |
775 | 3600, | |
776 | dns.rdataclass.IN, | |
777 | dns.rdatatype.A, | |
778 | '127.0.0.1') | |
779 | response.answer.append(rrset) | |
780 | ||
781 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, useHTTPS=False) | |
782 | self.assertTrue(receivedQuery) | |
783 | self.assertTrue(receivedResponse) | |
784 | expectedQuery.id = receivedQuery.id | |
785 | self.assertEquals(expectedQuery, receivedQuery) | |
786 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
787 | self.assertEquals(response, receivedResponse) | |
788 | self.checkResponseNoEDNS(response, receivedResponse) | |
789 | ||
790 | def testDOHSimplePOST(self): | |
791 | """ | |
792 | DOH over HTTP: Simple POST query | |
793 | """ | |
794 | name = 'simple-post.doh-over-http.tests.powerdns.com.' | |
795 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
796 | query.id = 0 | |
797 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
798 | expectedQuery.id = 0 | |
799 | response = dns.message.make_response(query) | |
800 | rrset = dns.rrset.from_text(name, | |
801 | 3600, | |
802 | dns.rdataclass.IN, | |
803 | dns.rdatatype.A, | |
804 | '127.0.0.1') | |
805 | response.answer.append(rrset) | |
806 | ||
807 | (receivedQuery, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, useHTTPS=False) | |
808 | self.assertTrue(receivedQuery) | |
809 | self.assertTrue(receivedResponse) | |
810 | receivedQuery.id = expectedQuery.id | |
811 | self.assertEquals(expectedQuery, receivedQuery) | |
812 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
813 | self.assertEquals(response, receivedResponse) | |
814 | self.checkResponseNoEDNS(response, receivedResponse) | |
d27309a9 RG |
815 | |
816 | class TestDOHWithCache(DNSDistDOHTest): | |
817 | ||
818 | _serverKey = 'server.key' | |
819 | _serverCert = 'server.chain' | |
820 | _serverName = 'tls.tests.dnsdist.org' | |
821 | _caCert = 'ca.pem' | |
822 | _dohServerPort = 8443 | |
823 | _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort)) | |
824 | _config_template = """ | |
825 | newServer{address="127.0.0.1:%s"} | |
826 | ||
827 | addDOHLocal("127.0.0.1:%s", "%s", "%s") | |
828 | ||
829 | pc = newPacketCache(100, {maxTTL=86400, minTTL=1}) | |
830 | getPool(""):setCache(pc) | |
831 | """ | |
832 | _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey'] | |
833 | ||
834 | def testDOHCacheLargeAnswer(self): | |
835 | """ | |
836 | DOH with cache: Check that we can cache (and retrieve) large answers | |
837 | """ | |
838 | numberOfQueries = 10 | |
839 | name = 'large.doh-with-cache.tests.powerdns.com.' | |
840 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
841 | query.id = 0 | |
842 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
843 | expectedQuery.id = 0 | |
844 | response = dns.message.make_response(query) | |
845 | # we prepare a large answer | |
846 | content = "" | |
847 | for i in range(44): | |
848 | if len(content) > 0: | |
849 | content = content + ', ' | |
850 | content = content + (str(i)*50) | |
851 | # pad up to 4096 | |
852 | content = content + 'A'*40 | |
853 | ||
854 | rrset = dns.rrset.from_text(name, | |
855 | 3600, | |
856 | dns.rdataclass.IN, | |
857 | dns.rdatatype.TXT, | |
858 | content) | |
859 | response.answer.append(rrset) | |
860 | self.assertEquals(len(response.to_wire()), 4096) | |
861 | ||
862 | # first query to fill the cache | |
863 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
864 | self.assertTrue(receivedQuery) | |
865 | self.assertTrue(receivedResponse) | |
866 | receivedQuery.id = expectedQuery.id | |
867 | self.assertEquals(expectedQuery, receivedQuery) | |
868 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
869 | self.assertEquals(response, receivedResponse) | |
0026abf9 | 870 | self.checkHasHeader('cache-control', 'max-age=3600') |
d27309a9 RG |
871 | |
872 | for _ in range(numberOfQueries): | |
873 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False) | |
874 | self.assertEquals(receivedResponse, response) | |
0026abf9 RG |
875 | self.checkHasHeader('cache-control', 'max-age=' + str(receivedResponse.answer[0].ttl)) |
876 | ||
877 | time.sleep(1) | |
878 | ||
879 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False) | |
880 | self.assertEquals(receivedResponse, response) | |
881 | self.checkHasHeader('cache-control', 'max-age=' + str(receivedResponse.answer[0].ttl)) | |
882 | ||
883 | class TestDOHWithoutCacheControl(DNSDistDOHTest): | |
884 | ||
885 | _serverKey = 'server.key' | |
886 | _serverCert = 'server.chain' | |
887 | _serverName = 'tls.tests.dnsdist.org' | |
888 | _caCert = 'ca.pem' | |
889 | _dohServerPort = 8443 | |
890 | _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort)) | |
891 | _config_template = """ | |
892 | newServer{address="127.0.0.1:%s"} | |
893 | ||
894 | addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {sendCacheControlHeaders=false}) | |
895 | """ | |
896 | _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey'] | |
897 | ||
898 | def testDOHSimple(self): | |
899 | """ | |
900 | DOH without cache-control | |
901 | """ | |
902 | name = 'simple.doh.tests.powerdns.com.' | |
903 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
904 | query.id = 0 | |
905 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
906 | expectedQuery.id = 0 | |
907 | response = dns.message.make_response(query) | |
908 | rrset = dns.rrset.from_text(name, | |
909 | 3600, | |
910 | dns.rdataclass.IN, | |
911 | dns.rdatatype.A, | |
912 | '127.0.0.1') | |
913 | response.answer.append(rrset) | |
914 | ||
915 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
916 | self.assertTrue(receivedQuery) | |
917 | self.assertTrue(receivedResponse) | |
918 | receivedQuery.id = expectedQuery.id | |
919 | self.assertEquals(expectedQuery, receivedQuery) | |
920 | self.checkNoHeader('cache-control') | |
921 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
922 | self.assertEquals(response, receivedResponse) |