]>
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 | |
cf3e149b | 186 | addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {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 | ||
9676d2a9 RG |
527 | def testHTTPPathRegex(self): |
528 | """ | |
529 | DOH: HTTPPathRegex | |
530 | """ | |
531 | name = 'http-path-regex.doh.tests.powerdns.com.' | |
532 | query = dns.message.make_query(name, 'A', 'IN') | |
533 | query.id = 0 | |
534 | query.flags &= ~dns.flags.RD | |
535 | expectedResponse = dns.message.make_response(query) | |
536 | rrset = dns.rrset.from_text(name, | |
537 | 3600, | |
538 | dns.rdataclass.IN, | |
539 | dns.rdatatype.A, | |
540 | '6.7.8.9') | |
541 | expectedResponse.answer.append(rrset) | |
542 | ||
543 | # this path should match | |
544 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + 'PowerDNS-999', caFile=self._caCert, query=query, response=None, useQueue=False) | |
545 | self.assertEquals(receivedResponse, expectedResponse) | |
546 | ||
547 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
548 | expectedQuery.id = 0 | |
549 | expectedQuery.flags &= ~dns.flags.RD | |
550 | response = dns.message.make_response(query) | |
551 | rrset = dns.rrset.from_text(name, | |
552 | 3600, | |
553 | dns.rdataclass.IN, | |
554 | dns.rdatatype.A, | |
555 | '127.0.0.1') | |
556 | response.answer.append(rrset) | |
557 | ||
558 | # this path should NOT match | |
559 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL + "PowerDNS2", query, response=response, caFile=self._caCert) | |
560 | self.assertTrue(receivedQuery) | |
561 | self.assertTrue(receivedResponse) | |
562 | receivedQuery.id = expectedQuery.id | |
563 | self.assertEquals(expectedQuery, receivedQuery) | |
564 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
565 | self.assertEquals(response, receivedResponse) | |
566 | ||
567 | def testHTTPStatusAction200(self): | |
568 | """ | |
569 | DOH: HTTPStatusAction 200 OK | |
570 | """ | |
571 | name = 'http-status-action.doh.tests.powerdns.com.' | |
572 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
573 | query.id = 0 | |
574 | ||
575 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, rawResponse=True) | |
576 | self.assertTrue(receivedResponse) | |
577 | self.assertEquals(receivedResponse, b'Plaintext answer') | |
578 | self.assertEquals(self._rcode, 200) | |
579 | self.assertTrue('content-type: text/plain' in self._response_headers.decode()) | |
580 | ||
581 | def testHTTPStatusAction307(self): | |
582 | """ | |
583 | DOH: HTTPStatusAction 307 | |
584 | """ | |
585 | name = 'http-status-action-redirect.doh.tests.powerdns.com.' | |
586 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
587 | query.id = 0 | |
588 | ||
589 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, rawResponse=True) | |
590 | self.assertTrue(receivedResponse) | |
591 | self.assertEquals(self._rcode, 307) | |
592 | self.assertTrue('location: https://doh.powerdns.org' in self._response_headers.decode()) | |
593 | ||
594 | def testHTTPLuaResponse(self): | |
595 | """ | |
596 | DOH: Lua HTTP Response | |
597 | """ | |
598 | name = 'http-lua.doh.tests.powerdns.com.' | |
599 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
600 | query.id = 0 | |
601 | ||
602 | (_, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False, rawResponse=True) | |
603 | self.assertTrue(receivedResponse) | |
604 | self.assertEquals(receivedResponse, b'It works!') | |
605 | self.assertEquals(self._rcode, 200) | |
606 | self.assertTrue('content-type: text/plain' in self._response_headers.decode()) | |
607 | ||
28b56482 RG |
608 | def testHTTPEarlyResponse(self): |
609 | """ | |
610 | DOH: HTTP Early Response | |
611 | """ | |
ded6907c | 612 | response_headers = BytesIO() |
28b56482 RG |
613 | url = self._dohBaseURL + 'coffee' |
614 | conn = self.openDOHConnection(self._dohServerPort, caFile=self._caCert, timeout=2.0) | |
615 | conn.setopt(pycurl.URL, url) | |
616 | conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)]) | |
617 | conn.setopt(pycurl.SSL_VERIFYPEER, 1) | |
618 | conn.setopt(pycurl.SSL_VERIFYHOST, 2) | |
619 | conn.setopt(pycurl.CAINFO, self._caCert) | |
ded6907c | 620 | conn.setopt(pycurl.HEADERFUNCTION, response_headers.write) |
28b56482 RG |
621 | data = conn.perform_rb() |
622 | rcode = conn.getinfo(pycurl.RESPONSE_CODE) | |
9b2ef603 | 623 | headers = response_headers.getvalue().decode() |
28b56482 RG |
624 | |
625 | self.assertEquals(rcode, 418) | |
626 | self.assertEquals(data, b'C0FFEE') | |
ded6907c RG |
627 | self.assertIn('foo: bar', headers) |
628 | self.assertNotIn(self._customResponseHeader2, headers) | |
28b56482 | 629 | |
ded6907c | 630 | response_headers = BytesIO() |
28b56482 RG |
631 | conn = self.openDOHConnection(self._dohServerPort, caFile=self._caCert, timeout=2.0) |
632 | conn.setopt(pycurl.URL, url) | |
633 | conn.setopt(pycurl.RESOLVE, ["%s:%d:127.0.0.1" % (self._serverName, self._dohServerPort)]) | |
634 | conn.setopt(pycurl.SSL_VERIFYPEER, 1) | |
635 | conn.setopt(pycurl.SSL_VERIFYHOST, 2) | |
636 | conn.setopt(pycurl.CAINFO, self._caCert) | |
ded6907c | 637 | conn.setopt(pycurl.HEADERFUNCTION, response_headers.write) |
28b56482 RG |
638 | conn.setopt(pycurl.POST, True) |
639 | data = '' | |
640 | conn.setopt(pycurl.POSTFIELDS, data) | |
641 | ||
642 | data = conn.perform_rb() | |
643 | rcode = conn.getinfo(pycurl.RESPONSE_CODE) | |
9b2ef603 | 644 | headers = response_headers.getvalue().decode() |
28b56482 RG |
645 | self.assertEquals(rcode, 418) |
646 | self.assertEquals(data, b'C0FFEE') | |
ded6907c RG |
647 | self.assertIn('foo: bar', headers) |
648 | self.assertNotIn(self._customResponseHeader2, headers) | |
28b56482 | 649 | |
10535d88 RG |
650 | class TestDOHAddingECS(DNSDistDOHTest): |
651 | ||
652 | _serverKey = 'server.key' | |
653 | _serverCert = 'server.chain' | |
654 | _serverName = 'tls.tests.dnsdist.org' | |
655 | _caCert = 'ca.pem' | |
656 | _dohServerPort = 8443 | |
10535d88 RG |
657 | _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort)) |
658 | _config_template = """ | |
659 | newServer{address="127.0.0.1:%s", useClientSubnet=true} | |
660 | addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }) | |
661 | setECSOverride(true) | |
662 | """ | |
663 | _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey'] | |
664 | ||
665 | def testDOHSimple(self): | |
666 | """ | |
667 | DOH with ECS: Simple query | |
668 | """ | |
669 | name = 'simple.doh-ecs.tests.powerdns.com.' | |
670 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
671 | query.id = 0 | |
672 | rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24) | |
673 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso]) | |
674 | response = dns.message.make_response(query) | |
675 | rrset = dns.rrset.from_text(name, | |
676 | 3600, | |
677 | dns.rdataclass.IN, | |
678 | dns.rdatatype.A, | |
679 | '127.0.0.1') | |
680 | response.answer.append(rrset) | |
681 | ||
682 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
683 | self.assertTrue(receivedQuery) | |
684 | self.assertTrue(receivedResponse) | |
685 | expectedQuery.id = receivedQuery.id | |
686 | self.assertEquals(expectedQuery, receivedQuery) | |
687 | self.checkQueryEDNSWithECS(expectedQuery, receivedQuery) | |
688 | self.assertEquals(response, receivedResponse) | |
689 | self.checkResponseNoEDNS(response, receivedResponse) | |
690 | ||
691 | def testDOHExistingEDNS(self): | |
692 | """ | |
693 | DOH with ECS: Existing EDNS | |
694 | """ | |
695 | name = 'existing-edns.doh-ecs.tests.powerdns.com.' | |
696 | query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=8192) | |
697 | query.id = 0 | |
698 | rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24) | |
699 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=8192, options=[rewrittenEcso]) | |
700 | response = dns.message.make_response(query) | |
701 | rrset = dns.rrset.from_text(name, | |
702 | 3600, | |
703 | dns.rdataclass.IN, | |
704 | dns.rdatatype.A, | |
705 | '127.0.0.1') | |
706 | response.answer.append(rrset) | |
707 | ||
708 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
709 | self.assertTrue(receivedQuery) | |
710 | self.assertTrue(receivedResponse) | |
711 | receivedQuery.id = expectedQuery.id | |
712 | self.assertEquals(expectedQuery, receivedQuery) | |
713 | self.assertEquals(response, receivedResponse) | |
714 | self.checkQueryEDNSWithECS(expectedQuery, receivedQuery) | |
715 | self.checkResponseEDNSWithoutECS(response, receivedResponse) | |
716 | ||
717 | def testDOHExistingECS(self): | |
718 | """ | |
719 | DOH with ECS: Existing EDNS Client Subnet | |
720 | """ | |
721 | name = 'existing-ecs.doh-ecs.tests.powerdns.com.' | |
722 | ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4') | |
723 | rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24) | |
724 | query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[ecso], want_dnssec=True) | |
725 | query.id = 0 | |
726 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=512, options=[rewrittenEcso]) | |
727 | response = dns.message.make_response(query) | |
728 | response.use_edns(edns=True, payload=4096, options=[rewrittenEcso]) | |
729 | rrset = dns.rrset.from_text(name, | |
730 | 3600, | |
731 | dns.rdataclass.IN, | |
732 | dns.rdatatype.A, | |
733 | '127.0.0.1') | |
734 | response.answer.append(rrset) | |
735 | ||
736 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
737 | self.assertTrue(receivedQuery) | |
738 | self.assertTrue(receivedResponse) | |
739 | receivedQuery.id = expectedQuery.id | |
740 | self.assertEquals(expectedQuery, receivedQuery) | |
741 | self.assertEquals(response, receivedResponse) | |
742 | self.checkQueryEDNSWithECS(expectedQuery, receivedQuery) | |
743 | self.checkResponseEDNSWithECS(response, receivedResponse) | |
44947230 RG |
744 | |
745 | class TestDOHOverHTTP(DNSDistDOHTest): | |
746 | ||
747 | _dohServerPort = 8480 | |
748 | _serverName = 'tls.tests.dnsdist.org' | |
749 | _dohBaseURL = ("http://%s:%d/" % (_serverName, _dohServerPort)) | |
750 | _config_template = """ | |
751 | newServer{address="127.0.0.1:%s"} | |
752 | addDOHLocal("127.0.0.1:%s") | |
753 | """ | |
754 | _config_params = ['_testServerPort', '_dohServerPort'] | |
11c22318 RG |
755 | _checkConfigExpectedOutput = b"""No certificate provided for DoH endpoint 127.0.0.1:8480, running in DNS over HTTP mode instead of DNS over HTTPS |
756 | Configuration 'configs/dnsdist_TestDOHOverHTTP.conf' OK! | |
757 | """ | |
44947230 RG |
758 | |
759 | def testDOHSimple(self): | |
760 | """ | |
761 | DOH over HTTP: Simple query | |
762 | """ | |
763 | name = 'simple.doh-over-http.tests.powerdns.com.' | |
764 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
765 | query.id = 0 | |
766 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
767 | response = dns.message.make_response(query) | |
768 | rrset = dns.rrset.from_text(name, | |
769 | 3600, | |
770 | dns.rdataclass.IN, | |
771 | dns.rdatatype.A, | |
772 | '127.0.0.1') | |
773 | response.answer.append(rrset) | |
774 | ||
775 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, useHTTPS=False) | |
776 | self.assertTrue(receivedQuery) | |
777 | self.assertTrue(receivedResponse) | |
778 | expectedQuery.id = receivedQuery.id | |
779 | self.assertEquals(expectedQuery, receivedQuery) | |
780 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
781 | self.assertEquals(response, receivedResponse) | |
782 | self.checkResponseNoEDNS(response, receivedResponse) | |
783 | ||
784 | def testDOHSimplePOST(self): | |
785 | """ | |
786 | DOH over HTTP: Simple POST query | |
787 | """ | |
788 | name = 'simple-post.doh-over-http.tests.powerdns.com.' | |
789 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
790 | query.id = 0 | |
791 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
792 | expectedQuery.id = 0 | |
793 | response = dns.message.make_response(query) | |
794 | rrset = dns.rrset.from_text(name, | |
795 | 3600, | |
796 | dns.rdataclass.IN, | |
797 | dns.rdatatype.A, | |
798 | '127.0.0.1') | |
799 | response.answer.append(rrset) | |
800 | ||
801 | (receivedQuery, receivedResponse) = self.sendDOHPostQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, useHTTPS=False) | |
802 | self.assertTrue(receivedQuery) | |
803 | self.assertTrue(receivedResponse) | |
804 | receivedQuery.id = expectedQuery.id | |
805 | self.assertEquals(expectedQuery, receivedQuery) | |
806 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
807 | self.assertEquals(response, receivedResponse) | |
808 | self.checkResponseNoEDNS(response, receivedResponse) | |
d27309a9 RG |
809 | |
810 | class TestDOHWithCache(DNSDistDOHTest): | |
811 | ||
812 | _serverKey = 'server.key' | |
813 | _serverCert = 'server.chain' | |
814 | _serverName = 'tls.tests.dnsdist.org' | |
815 | _caCert = 'ca.pem' | |
816 | _dohServerPort = 8443 | |
817 | _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort)) | |
818 | _config_template = """ | |
819 | newServer{address="127.0.0.1:%s"} | |
820 | ||
821 | addDOHLocal("127.0.0.1:%s", "%s", "%s") | |
822 | ||
823 | pc = newPacketCache(100, {maxTTL=86400, minTTL=1}) | |
824 | getPool(""):setCache(pc) | |
825 | """ | |
826 | _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey'] | |
827 | ||
828 | def testDOHCacheLargeAnswer(self): | |
829 | """ | |
830 | DOH with cache: Check that we can cache (and retrieve) large answers | |
831 | """ | |
832 | numberOfQueries = 10 | |
833 | name = 'large.doh-with-cache.tests.powerdns.com.' | |
834 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
835 | query.id = 0 | |
836 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
837 | expectedQuery.id = 0 | |
838 | response = dns.message.make_response(query) | |
839 | # we prepare a large answer | |
840 | content = "" | |
841 | for i in range(44): | |
842 | if len(content) > 0: | |
843 | content = content + ', ' | |
844 | content = content + (str(i)*50) | |
845 | # pad up to 4096 | |
846 | content = content + 'A'*40 | |
847 | ||
848 | rrset = dns.rrset.from_text(name, | |
849 | 3600, | |
850 | dns.rdataclass.IN, | |
851 | dns.rdatatype.TXT, | |
852 | content) | |
853 | response.answer.append(rrset) | |
854 | self.assertEquals(len(response.to_wire()), 4096) | |
855 | ||
856 | # first query to fill the cache | |
857 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
858 | self.assertTrue(receivedQuery) | |
859 | self.assertTrue(receivedResponse) | |
860 | receivedQuery.id = expectedQuery.id | |
861 | self.assertEquals(expectedQuery, receivedQuery) | |
862 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
863 | self.assertEquals(response, receivedResponse) | |
0026abf9 | 864 | self.checkHasHeader('cache-control', 'max-age=3600') |
d27309a9 RG |
865 | |
866 | for _ in range(numberOfQueries): | |
867 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False) | |
868 | self.assertEquals(receivedResponse, response) | |
0026abf9 RG |
869 | self.checkHasHeader('cache-control', 'max-age=' + str(receivedResponse.answer[0].ttl)) |
870 | ||
871 | time.sleep(1) | |
872 | ||
873 | (_, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, caFile=self._caCert, useQueue=False) | |
874 | self.assertEquals(receivedResponse, response) | |
875 | self.checkHasHeader('cache-control', 'max-age=' + str(receivedResponse.answer[0].ttl)) | |
876 | ||
877 | class TestDOHWithoutCacheControl(DNSDistDOHTest): | |
878 | ||
879 | _serverKey = 'server.key' | |
880 | _serverCert = 'server.chain' | |
881 | _serverName = 'tls.tests.dnsdist.org' | |
882 | _caCert = 'ca.pem' | |
883 | _dohServerPort = 8443 | |
884 | _dohBaseURL = ("https://%s:%d/" % (_serverName, _dohServerPort)) | |
885 | _config_template = """ | |
886 | newServer{address="127.0.0.1:%s"} | |
887 | ||
888 | addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, {sendCacheControlHeaders=false}) | |
889 | """ | |
890 | _config_params = ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey'] | |
891 | ||
892 | def testDOHSimple(self): | |
893 | """ | |
894 | DOH without cache-control | |
895 | """ | |
896 | name = 'simple.doh.tests.powerdns.com.' | |
897 | query = dns.message.make_query(name, 'A', 'IN', use_edns=False) | |
898 | query.id = 0 | |
899 | expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096) | |
900 | expectedQuery.id = 0 | |
901 | response = dns.message.make_response(query) | |
902 | rrset = dns.rrset.from_text(name, | |
903 | 3600, | |
904 | dns.rdataclass.IN, | |
905 | dns.rdatatype.A, | |
906 | '127.0.0.1') | |
907 | response.answer.append(rrset) | |
908 | ||
909 | (receivedQuery, receivedResponse) = self.sendDOHQuery(self._dohServerPort, self._serverName, self._dohBaseURL, query, response=response, caFile=self._caCert) | |
910 | self.assertTrue(receivedQuery) | |
911 | self.assertTrue(receivedResponse) | |
912 | receivedQuery.id = expectedQuery.id | |
913 | self.assertEquals(expectedQuery, receivedQuery) | |
914 | self.checkNoHeader('cache-control') | |
915 | self.checkQueryEDNSWithoutECS(expectedQuery, receivedQuery) | |
916 | self.assertEquals(response, receivedResponse) |