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 /dns/asyncquery.py | |
| parent | 2fe1a285f883e4b47892e58d6e1affd5b5e95bac (diff) | |
| download | dnspython-948d5a6a2b3eb08647acaf2a67df92e9bcc2979a.tar.gz | |
Initial DoQ support.
Diffstat (limited to 'dns/asyncquery.py')
| -rw-r--r-- | dns/asyncquery.py | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/dns/asyncquery.py b/dns/asyncquery.py index 107f766..15612e5 100644 --- a/dns/asyncquery.py +++ b/dns/asyncquery.py @@ -30,6 +30,7 @@ import dns.exception import dns.inet import dns.name import dns.message +import dns.quic import dns.rcode import dns.rdataclass import dns.rdatatype @@ -45,6 +46,7 @@ from dns.query import ( _have_httpx, _have_http2, NoDOH, + NoDOQ, ) if _have_httpx: @@ -670,3 +672,62 @@ async def inbound_xfr( tsig_ctx = r.tsig_ctx if not retry and query.keyring and not r.had_tsig: raise dns.exception.FormError("missing TSIG") + + +async def quic( + q: dns.message.Message, + where: str, + timeout: Optional[float] = None, + port: int = 853, + source: Optional[str] = None, + source_port: int = 0, + one_rr_per_rrset: bool = False, + ignore_trailing: bool = False, + connection: Optional[dns.quic.AsyncQuicConnection] = None, + verify: Union[bool, str] = True, + backend: Optional[dns.asyncbackend.Backend] = None, +) -> dns.message.Message: + """Return the response obtained after sending an asynchronous query via + DNS-over-QUIC. + + *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``, + the default, then dnspython will use the default backend. + + See :py:func:`dns.query.doq()` for the documentation of the other + parameters, exceptions, and return type of this method. + """ + + if not dns.quic.have_quic: + raise NoDOQ("DNS-over-QUIC is not available.") # pragma: no cover + + q.id = 0 + wire = q.to_wire() + the_connection: dns.quic.AsyncQuicConnection + if connection: + cfactory = dns.quic.null_factory + mfactory = dns.quic.null_factory + the_connection = connection + else: + (cfactory, mfactory) = dns.quic.factories_for_backend(backend) + + async with cfactory() as context: + async with mfactory(context, verify_mode=verify) as the_manager: + if not connection: + the_connection = the_manager.connect(where, port, source, source_port) + start = time.time() + stream = await the_connection.make_stream() + async with stream: + await stream.send(wire, True) + wire = await stream.receive(timeout) + finish = time.time() + r = dns.message.from_wire( + wire, + keyring=q.keyring, + request_mac=q.request_mac, + one_rr_per_rrset=one_rr_per_rrset, + ignore_trailing=ignore_trailing, + ) + r.time = max(finish - start, 0.0) + if not q.is_response(r): + raise BadResponse + return r |
