summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorBob Halley <halley@dnspython.org>2022-10-01 15:24:13 -0700
committerBob Halley <halley@dnspython.org>2022-10-09 14:34:10 -0700
commit948d5a6a2b3eb08647acaf2a67df92e9bcc2979a (patch)
treeb0a423383efbff8a314a09492d45a5de610d92b9 /tests
parent2fe1a285f883e4b47892e58d6e1affd5b5e95bac (diff)
downloaddnspython-948d5a6a2b3eb08647acaf2a67df92e9bcc2979a.tar.gz
Initial DoQ support.
Diffstat (limited to 'tests')
-rw-r--r--tests/nanoquic.py131
-rw-r--r--tests/test_doq.py56
-rw-r--r--tests/tls/ca.crt20
-rw-r--r--tests/tls/private.pem3
-rw-r--r--tests/tls/public.crt35
5 files changed, 245 insertions, 0 deletions
diff --git a/tests/nanoquic.py b/tests/nanoquic.py
new file mode 100644
index 0000000..0bcb12c
--- /dev/null
+++ b/tests/nanoquic.py
@@ -0,0 +1,131 @@
+# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
+
+try:
+ import asyncio
+ import socket
+ import struct
+ import threading
+
+ import aioquic.asyncio
+ import aioquic.asyncio.server
+ import aioquic.quic.configuration
+ import aioquic.quic.events
+
+ import dns.asyncquery
+ import dns.message
+ import dns.rcode
+
+ from tests.util import here
+
+ have_quic = True
+
+ class Request:
+ def __init__(self, message, wire):
+ self.message = message
+ self.wire = wire
+
+ @property
+ def question(self):
+ return self.message.question[0]
+
+ @property
+ def qname(self):
+ return self.question.name
+
+ @property
+ def qclass(self):
+ return self.question.rdclass
+
+ @property
+ def qtype(self):
+ return self.question.rdtype
+
+ class NanoQuic(aioquic.asyncio.QuicConnectionProtocol):
+ def quic_event_received(self, event):
+ # This is a bit hackish and not fully general, but this is a test server!
+ if isinstance(event, aioquic.quic.events.StreamDataReceived):
+ data = bytes(event.data)
+ (wire_len,) = struct.unpack("!H", data[:2])
+ wire = self.handle_wire(data[2 : 2 + wire_len])
+ if wire is not None:
+ self._quic.send_stream_data(event.stream_id, wire, end_stream=True)
+
+ def handle(self, request):
+ r = dns.message.make_response(request.message)
+ r.set_rcode(dns.rcode.REFUSED)
+ return r
+
+ def handle_wire(self, wire):
+ response = None
+ try:
+ q = dns.message.from_wire(wire)
+ except dns.message.ShortHeader:
+ return
+ except Exception as e:
+ try:
+ q = dns.message.from_wire(wire, question_only=True)
+ response = dns.message.make_response(q)
+ response.set_rcode(dns.rcode.FORMERR)
+ except Exception:
+ return
+ if response is None:
+ try:
+ request = Request(q, wire)
+ response = self.handle(request)
+ except Exception:
+ response = dns.message.make_response(q)
+ response.set_rcode(dns.rcode.SERVFAIL)
+ wire = response.to_wire()
+ return struct.pack("!H", len(wire)) + wire
+
+ class Server(threading.Thread):
+ def __init__(self):
+ super().__init__()
+ self.transport = None
+ self.protocol = None
+ self.left = None
+ self.right = None
+
+ def __enter__(self):
+ self.left, self.right = socket.socketpair()
+ self.start()
+
+ def __exit__(self, ex_ty, ex_va, ex_tr):
+ if self.protocol is not None:
+ self.protocol.close()
+ if self.transport is not None:
+ self.transport.close()
+ if self.left:
+ self.left.close()
+ if self.is_alive():
+ self.join()
+ if self.right:
+ self.right.close()
+
+ async def arun(self):
+ reader, _ = await asyncio.open_connection(sock=self.right)
+ conf = aioquic.quic.configuration.QuicConfiguration(
+ alpn_protocols=["doq"],
+ is_client=False,
+ )
+ conf.load_cert_chain(here("tls/public.crt"), here("tls/private.pem"))
+ loop = asyncio.get_event_loop()
+ (self.transport, self.protocol) = await loop.create_datagram_endpoint(
+ lambda: aioquic.asyncio.server.QuicServer(
+ configuration=conf, create_protocol=NanoQuic
+ ),
+ local_addr=("127.0.0.1", 8853),
+ )
+ try:
+ await reader.read(1)
+ except Exception:
+ pass
+
+ def run(self):
+ asyncio.run(self.arun())
+
+except ImportError:
+ have_quic = False
+
+ class NanoQuic:
+ pass
diff --git a/tests/test_doq.py b/tests/test_doq.py
new file mode 100644
index 0000000..571581a
--- /dev/null
+++ b/tests/test_doq.py
@@ -0,0 +1,56 @@
+# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
+
+import asyncio
+import sys
+
+import pytest
+
+import dns.asyncbackend
+import dns.asyncquery
+import dns.message
+import dns.query
+import dns.rcode
+
+from .util import here
+
+try:
+ from .nanoquic import Server
+
+ _nanoquic_available = True
+except ImportError:
+ _nanoquic_available = False
+
+ class Server(object):
+ pass
+
+
+@pytest.mark.skipif(not _nanoquic_available, reason="requires nanoquic")
+def test_basic_sync():
+ with Server() as server:
+ q = dns.message.make_query("www.example.", "A")
+ r = dns.query.quic(q, "127.0.0.1", port=8853, verify=here("tls/ca.crt"))
+ assert r.rcode() == dns.rcode.REFUSED
+
+
+async def amain():
+ q = dns.message.make_query("www.example.", "A")
+ r = await dns.asyncquery.quic(q, "127.0.0.1", port=8853, verify=here("tls/ca.crt"))
+ assert r.rcode() == dns.rcode.REFUSED
+
+
+def test_basic_asyncio():
+ dns.asyncbackend.set_default_backend("asyncio")
+ with Server() as server:
+ asyncio.run(amain())
+
+
+try:
+ import trio
+
+ def test_basic_trio():
+ dns.asyncbackend.set_default_backend("trio")
+ with Server() as server:
+ trio.run(amain)
+
+except ImportError:
+ pass
diff --git a/tests/tls/ca.crt b/tests/tls/ca.crt
new file mode 100644
index 0000000..81c7682
--- /dev/null
+++ b/tests/tls/ca.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIUUCWxpsMnzETqwNKJ38le9z7oFEEwDQYJKoZIhvcNAQEL
+BQAwHTEbMBkGA1UEAxMScXVpYy5kbnNweXRob24ub3JnMB4XDTIyMDcwOTIyMjQw
+N1oXDTMyMDcwNjIyMjQzN1owHTEbMBkGA1UEAxMScXVpYy5kbnNweXRob24ub3Jn
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0AMlXDsx/7Kis4lUhAML
+yaL4wtvhPGnqz20Gnhd/b2uAjZbtLtKDG2aRC0QtHL6N0vfBhj+KUV/unT60Mf7G
+Pm2Z8fOxiwh/UJ8oxoJe59izklrwM0PL2iR21OMCCsiYcjiOOx75RUZ/6KEGMTgd
+3wvqwEV320yd3WInkdO72n9jlQTN3VtwLwkIkSbINiuUCKgP9hy28K7HjMHvEIlf
+QZfh9wIHhbqs/JP3dirRL7MKWFAv3MlmMffb/6NBBFb6FaRjS6WjojD8qaSTr14/
+tyqrK7zL32npKm/TbzxC8hFwYdwd3HURgpWInA6CRIcyZM/k4y7dHQlI4ID7hmcC
+1QIDAQABo4GDMIGAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G
+A1UdDgQWBBQrNPKeL6rBhPV+Eb1RnvIkeax5sDAfBgNVHSMEGDAWgBQrNPKeL6rB
+hPV+Eb1RnvIkeax5sDAdBgNVHREEFjAUghJxdWljLmRuc3B5dGhvbi5vcmcwDQYJ
+KoZIhvcNAQELBQADggEBAADpAtDvceOrhn5FReYip9DlTW7KKrRDDFCo0SNdhvN3
+6mU/Hn3jNXYu9Ym3NDVL8q9UWzLRcSNLUo1qjkK3aOlgwcO6PuGKXukF7Zdd8wVb
+pPdUqooBmj6akqmNvmloZyDmQ+aXcYhR83hcEHFOK+C7pGLqSFChN1mgDT1/mgBk
+pODOZkcLtZI8YJyQ2sn3WhUJS52D6xfmPigliUcYqi6i+w1vxD45QilWbvqCwnN/
+6qmb3JQsMf+3MCtogVcSZjE9cf4CwlmKqgMxsBKz+/Qk9YPMpDuecEbd76L+Htdl
+HWuDlemBzyhd5qO5y/UGarqmuh3MgkOdFVQWAUygcCM=
+-----END CERTIFICATE-----
diff --git a/tests/tls/private.pem b/tests/tls/private.pem
new file mode 100644
index 0000000..06a01fa
--- /dev/null
+++ b/tests/tls/private.pem
@@ -0,0 +1,3 @@
+-----BEGIN PRIVATE KEY-----
+MC4CAQAwBQYDK2VwBCIEIL2OxuOo+awfhPvvm82EBZ4VA6ULQHlebxGCamZ/H5Rt
+-----END PRIVATE KEY-----
diff --git a/tests/tls/public.crt b/tests/tls/public.crt
new file mode 100644
index 0000000..96129a1
--- /dev/null
+++ b/tests/tls/public.crt
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIICZjCCAU6gAwIBAgIUBTlEzhtkXYQvZl5CYRNBxOG4GpEwDQYJKoZIhvcNAQEL
+BQAwHTEbMBkGA1UEAxMScXVpYy5kbnNweXRob24ub3JnMB4XDTIyMTAwOTE2MjYw
+OFoXDTMwMTIyNjE2MjYzOFowFDESMBAGA1UEAxMJbG9jYWxob3N0MCowBQYDK2Vw
+AyEAKpQbO2JXhCGnQs2MrWmGBK5LcmJMWPXCzM2PfWbo1TyjgaAwgZ0wDgYDVR0P
+AQH/BAQDAgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4E
+FgQUM2pZy8pH78CvP+FnuF190KEJkjUwHwYDVR0jBBgwFoAUKzTyni+qwYT1fhG9
+UZ7yJHmsebAwLAYDVR0RBCUwI4IJbG9jYWxob3N0hwR/AAABhxAAAAAAAAAAAAAA
+AAAAAAABMA0GCSqGSIb3DQEBCwUAA4IBAQA0JlNLrLz3ajCzSVfOQsUdd3a3wR7Q
+Dr28mYoDHSY9mhnJ9IQeInmGvPMLA4dgiRPFqxWsKh+lxzZObkbMjf1IAIVykfh6
+LynePm58/lnRrhdvf8vFfccuTyeb2aD0ZBA/RyhZam79J6JjRRovkSj9TyIqKfif
+6T6QWXOXwAF89rH8YHAKnRSl32pqZuDhOnM0Ien+Sa6KpCvgIDogHQxIVbe1egZl
+2Ec0LVQUaXhoICd1c6xoRoAa5UzDFJ7ujeu1XNGWKIiXESlcIo7SZjzusL2p5vv/
+frM+r43khtZ4s+F70A+B3AndcVSeKTQ5KlftN9CBuiQoYzhY29NmL93X
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIUUCWxpsMnzETqwNKJ38le9z7oFEEwDQYJKoZIhvcNAQEL
+BQAwHTEbMBkGA1UEAxMScXVpYy5kbnNweXRob24ub3JnMB4XDTIyMDcwOTIyMjQw
+N1oXDTMyMDcwNjIyMjQzN1owHTEbMBkGA1UEAxMScXVpYy5kbnNweXRob24ub3Jn
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0AMlXDsx/7Kis4lUhAML
+yaL4wtvhPGnqz20Gnhd/b2uAjZbtLtKDG2aRC0QtHL6N0vfBhj+KUV/unT60Mf7G
+Pm2Z8fOxiwh/UJ8oxoJe59izklrwM0PL2iR21OMCCsiYcjiOOx75RUZ/6KEGMTgd
+3wvqwEV320yd3WInkdO72n9jlQTN3VtwLwkIkSbINiuUCKgP9hy28K7HjMHvEIlf
+QZfh9wIHhbqs/JP3dirRL7MKWFAv3MlmMffb/6NBBFb6FaRjS6WjojD8qaSTr14/
+tyqrK7zL32npKm/TbzxC8hFwYdwd3HURgpWInA6CRIcyZM/k4y7dHQlI4ID7hmcC
+1QIDAQABo4GDMIGAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G
+A1UdDgQWBBQrNPKeL6rBhPV+Eb1RnvIkeax5sDAfBgNVHSMEGDAWgBQrNPKeL6rB
+hPV+Eb1RnvIkeax5sDAdBgNVHREEFjAUghJxdWljLmRuc3B5dGhvbi5vcmcwDQYJ
+KoZIhvcNAQELBQADggEBAADpAtDvceOrhn5FReYip9DlTW7KKrRDDFCo0SNdhvN3
+6mU/Hn3jNXYu9Ym3NDVL8q9UWzLRcSNLUo1qjkK3aOlgwcO6PuGKXukF7Zdd8wVb
+pPdUqooBmj6akqmNvmloZyDmQ+aXcYhR83hcEHFOK+C7pGLqSFChN1mgDT1/mgBk
+pODOZkcLtZI8YJyQ2sn3WhUJS52D6xfmPigliUcYqi6i+w1vxD45QilWbvqCwnN/
+6qmb3JQsMf+3MCtogVcSZjE9cf4CwlmKqgMxsBKz+/Qk9YPMpDuecEbd76L+Htdl
+HWuDlemBzyhd5qO5y/UGarqmuh3MgkOdFVQWAUygcCM=
+-----END CERTIFICATE-----