diff options
| author | Bob Halley <halley@dnspython.org> | 2022-10-01 15:24:13 -0700 |
|---|---|---|
| committer | Bob Halley <halley@dnspython.org> | 2022-10-09 14:34:10 -0700 |
| commit | 948d5a6a2b3eb08647acaf2a67df92e9bcc2979a (patch) | |
| tree | b0a423383efbff8a314a09492d45a5de610d92b9 /tests | |
| parent | 2fe1a285f883e4b47892e58d6e1affd5b5e95bac (diff) | |
| download | dnspython-948d5a6a2b3eb08647acaf2a67df92e9bcc2979a.tar.gz | |
Initial DoQ support.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/nanoquic.py | 131 | ||||
| -rw-r--r-- | tests/test_doq.py | 56 | ||||
| -rw-r--r-- | tests/tls/ca.crt | 20 | ||||
| -rw-r--r-- | tests/tls/private.pem | 3 | ||||
| -rw-r--r-- | tests/tls/public.crt | 35 |
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----- |
