/test/test_knownservers.py

https://github.com/facebookexperimental/doh-proxy · Python · 115 lines · 80 code · 16 blank · 19 comment · 11 complexity · 76e223492d32dc76c94a2cf062632f75 MD5 · raw file

  1. #!/usr/bin/env python3
  2. #
  3. # Copyright (c) 2018-present, Facebook, Inc.
  4. # All rights reserved.
  5. #
  6. # This source code is licensed under the BSD-style license found in the
  7. # LICENSE file in the root directory of this source tree.
  8. #
  9. import asyncio
  10. import asynctest
  11. import dns
  12. import dns.message
  13. import os
  14. import unittest
  15. from dohproxy import client_protocol, utils
  16. TEST_TIMEOUT = 3.0
  17. TRAVIS_TIMEOUT = 15.0
  18. METHOD_GET = 1
  19. METHOD_POST = 2
  20. METHOD_BOTH = 3
  21. def known_servers():
  22. '''
  23. List of servers taken from
  24. https://github.com/curl/curl/wiki/DNS-over-HTTPS#publicly-available-servers
  25. '''
  26. return [
  27. # Name, Domain, endpoint
  28. ('Google', 'dns.google', '/dns-query', METHOD_BOTH),
  29. ('Cloudflare', 'cloudflare-dns.com', '/dns-query', METHOD_BOTH),
  30. (
  31. 'CleanBrowsing', 'doh.cleanbrowsing.org',
  32. '/doh/family-filter/', METHOD_BOTH
  33. ),
  34. # Currently off
  35. # ('@chantra', 'dns.dnsoverhttps.net', '/dns-query', METHOD_BOTH),
  36. ('@jedisct1', 'doh.crypto.sx', '/dns-query', METHOD_GET),
  37. # Timeout
  38. # ('SecureDNS.eu', 'doh.securedns.eu', '/dns-query', METHOD_BOTH),
  39. ('BlahDNS.com JP', 'doh-jp.blahdns.com', '/dns-query', METHOD_BOTH),
  40. ('BlahDNS.com DE', 'doh-de.blahdns.com', '/dns-query', METHOD_BOTH),
  41. (
  42. 'NekomimiRouter.com', 'dns.dns-over-https.com',
  43. '/dns-query', METHOD_BOTH
  44. ),
  45. ]
  46. def build_query(qname, qtype):
  47. dnsq = dns.message.make_query(
  48. qname=qname,
  49. rdtype=qtype,
  50. )
  51. dnsq.id = 0
  52. return dnsq
  53. class Client(client_protocol.StubServerProtocol):
  54. result = None
  55. def on_answer(self, addr, msg):
  56. self.result = dns.message.from_wire(msg)
  57. class TestKnownServers(asynctest.TestCase):
  58. def setUp(self):
  59. super().setUp()
  60. # ALPN requires >=openssl-1.0.2
  61. # NPN requires >=openssl-1.0.1
  62. self.test_timeout = TEST_TIMEOUT
  63. if os.getenv('TRAVIS'):
  64. self.test_timeout = TRAVIS_TIMEOUT
  65. for fn in ['set_alpn_protocols']:
  66. patcher = unittest.mock.patch('ssl.SSLContext.{0}'.format(fn))
  67. patcher.start()
  68. self.addCleanup(patcher.stop)
  69. async def _test_servers(self, post=False):
  70. for name, domain, uri, methods in known_servers():
  71. if post and not methods & METHOD_POST:
  72. continue
  73. if not post and not methods & METHOD_GET:
  74. continue
  75. with self.subTest(name):
  76. arglist = [
  77. '--domain',
  78. domain,
  79. '--uri',
  80. uri,
  81. ]
  82. if post:
  83. arglist.append('--post')
  84. parser = utils.client_parser_base()
  85. args = parser.parse_args(arglist)
  86. logger = utils.configure_logger('doh-integrationtest')
  87. c = Client(args=args, logger=logger)
  88. fut = c.make_request(None, build_query(
  89. qname=domain, qtype="A"))
  90. try:
  91. await asyncio.wait_for(fut, self.test_timeout)
  92. except asyncio.TimeoutError:
  93. raise unittest.SkipTest("%s Timeouted" % name)
  94. self.assertEqual(1, len(c.result.question))
  95. self.assertGreater(len(c.result.answer), 0)
  96. async def test_servers_get(self):
  97. await self._test_servers(post=False)
  98. async def test_servers_post(self):
  99. await self._test_servers(post=True)