From: Bob Halley Date: Mon, 17 Jul 2023 22:24:59 +0000 (-0700) Subject: Fix DoQ for asyncio IPv6 [#958]. X-Git-Tag: v2.5.0rc1~69 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e594c675823571e03ab10a8e3ab24d933056610c;p=thirdparty%2Fdnspython.git Fix DoQ for asyncio IPv6 [#958]. --- diff --git a/dns/quic/_asyncio.py b/dns/quic/_asyncio.py index f01ebc33..30de36ae 100644 --- a/dns/quic/_asyncio.py +++ b/dns/quic/_asyncio.py @@ -88,8 +88,10 @@ class AsyncioQuicConnection(AsyncQuicConnection): try: af = dns.inet.af_for_address(self._address) backend = dns.asyncbackend.get_backend("asyncio") + # Note that peer is a low-level address tuple, but make_socket() wants + # a high-level address tuple, so we convert. self._socket = await backend.make_socket( - af, socket.SOCK_DGRAM, 0, self._source, self._peer + af, socket.SOCK_DGRAM, 0, self._source, (self._peer[0], self._peer[1]) ) self._socket_created.set() async with self._socket: @@ -184,6 +186,9 @@ class AsyncioQuicConnection(AsyncQuicConnection): self._manager.closed(self._peer[0], self._peer[1]) self._closed = True self._connection.close() + if not self._socket_created.is_set(): + # sender might be blocked on this, so set it + self._socket_created.set() async with self._wake_timer: self._wake_timer.notify_all() try: diff --git a/tests/nanoquic.py b/tests/nanoquic.py index 7599fcc6..b4efef2f 100644 --- a/tests/nanoquic.py +++ b/tests/nanoquic.py @@ -14,7 +14,6 @@ try: import dns.asyncquery import dns.message import dns.rcode - from tests.util import here have_quic = True @@ -79,8 +78,9 @@ try: return struct.pack("!H", len(wire)) + wire class Server(threading.Thread): - def __init__(self): + def __init__(self, address="127.0.0.1"): super().__init__() + self.address = address self.transport = None self.protocol = None self.left = None @@ -91,6 +91,7 @@ try: self.left, self.right = socket.socketpair() self.start() self.ready.wait(4) + return self def __exit__(self, ex_ty, ex_va, ex_tr): if self.protocol is not None: @@ -116,7 +117,7 @@ try: lambda: aioquic.asyncio.server.QuicServer( configuration=conf, create_protocol=NanoQuic ), - local_addr=("127.0.0.1", 8853), + local_addr=(self.address, 8853), ) self.ready.set() try: diff --git a/tests/test_doq.py b/tests/test_doq.py index 7d48bc22..c43c0654 100644 --- a/tests/test_doq.py +++ b/tests/test_doq.py @@ -11,7 +11,7 @@ import dns.message import dns.query import dns.rcode -from .util import here +from .util import have_ipv4, have_ipv6, here try: from .nanoquic import Server @@ -24,25 +24,37 @@ except ImportError: pass +addresses = [] +if have_ipv4(): + addresses.append("127.0.0.1") +if have_ipv6(): + addresses.append("::1") +if len(addresses) == 0: + # no networking + _nanoquic_available = False + + @pytest.mark.skipif(not _nanoquic_available, reason="requires aioquic") 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 + q = dns.message.make_query("www.example.", "A") + for address in addresses: + with Server(address) as server: + r = dns.query.quic(q, address, port=8853, verify=here("tls/ca.crt")) + assert r.rcode() == dns.rcode.REFUSED -async def amain(): +async def amain(address): 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")) + r = await dns.asyncquery.quic(q, address, port=8853, verify=here("tls/ca.crt")) assert r.rcode() == dns.rcode.REFUSED @pytest.mark.skipif(not _nanoquic_available, reason="requires aioquic") def test_basic_asyncio(): dns.asyncbackend.set_default_backend("asyncio") - with Server() as server: - asyncio.run(amain()) + for address in addresses: + with Server(address) as server: + asyncio.run(amain(address)) try: @@ -51,8 +63,9 @@ try: @pytest.mark.skipif(not _nanoquic_available, reason="requires aioquic") def test_basic_trio(): dns.asyncbackend.set_default_backend("trio") - with Server() as server: - trio.run(amain) + for address in addresses: + with Server(address) as server: + trio.run(amain, address) except ImportError: pass