mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-12 16:22:57 -07:00
Bump dnspython from 2.4.2 to 2.6.1 (#2264)
* Bump dnspython from 2.4.2 to 2.6.1 Bumps [dnspython](https://github.com/rthalley/dnspython) from 2.4.2 to 2.6.1. - [Release notes](https://github.com/rthalley/dnspython/releases) - [Changelog](https://github.com/rthalley/dnspython/blob/main/doc/whatsnew.rst) - [Commits](https://github.com/rthalley/dnspython/compare/v2.4.2...v2.6.1) --- updated-dependencies: - dependency-name: dnspython dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Update dnspython==2.6.1 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci]
This commit is contained in:
parent
aca7e72715
commit
cfefa928be
101 changed files with 1052 additions and 459 deletions
195
lib/dns/query.py
195
lib/dns/query.py
|
@ -22,12 +22,14 @@ import contextlib
|
|||
import enum
|
||||
import errno
|
||||
import os
|
||||
import os.path
|
||||
import selectors
|
||||
import socket
|
||||
import struct
|
||||
import time
|
||||
from typing import Any, Dict, Optional, Tuple, Union
|
||||
|
||||
import dns._features
|
||||
import dns.exception
|
||||
import dns.inet
|
||||
import dns.message
|
||||
|
@ -57,24 +59,14 @@ def _expiration_for_this_attempt(timeout, expiration):
|
|||
return min(time.time() + timeout, expiration)
|
||||
|
||||
|
||||
_have_httpx = False
|
||||
_have_http2 = False
|
||||
try:
|
||||
import httpcore
|
||||
_have_httpx = dns._features.have("doh")
|
||||
if _have_httpx:
|
||||
import httpcore._backends.sync
|
||||
import httpx
|
||||
|
||||
_CoreNetworkBackend = httpcore.NetworkBackend
|
||||
_CoreSyncStream = httpcore._backends.sync.SyncStream
|
||||
|
||||
_have_httpx = True
|
||||
try:
|
||||
# See if http2 support is available.
|
||||
with httpx.Client(http2=True):
|
||||
_have_http2 = True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
class _NetworkBackend(_CoreNetworkBackend):
|
||||
def __init__(self, resolver, local_port, bootstrap_address, family):
|
||||
super().__init__()
|
||||
|
@ -147,7 +139,7 @@ try:
|
|||
resolver, local_port, bootstrap_address, family
|
||||
)
|
||||
|
||||
except ImportError: # pragma: no cover
|
||||
else:
|
||||
|
||||
class _HTTPTransport: # type: ignore
|
||||
def connect_tcp(self, host, port, timeout, local_address):
|
||||
|
@ -161,6 +153,8 @@ try:
|
|||
except ImportError: # pragma: no cover
|
||||
|
||||
class ssl: # type: ignore
|
||||
CERT_NONE = 0
|
||||
|
||||
class WantReadException(Exception):
|
||||
pass
|
||||
|
||||
|
@ -459,7 +453,7 @@ def https(
|
|||
transport = _HTTPTransport(
|
||||
local_address=local_address,
|
||||
http1=True,
|
||||
http2=_have_http2,
|
||||
http2=True,
|
||||
verify=verify,
|
||||
local_port=local_port,
|
||||
bootstrap_address=bootstrap_address,
|
||||
|
@ -470,9 +464,7 @@ def https(
|
|||
if session:
|
||||
cm: contextlib.AbstractContextManager = contextlib.nullcontext(session)
|
||||
else:
|
||||
cm = httpx.Client(
|
||||
http1=True, http2=_have_http2, verify=verify, transport=transport
|
||||
)
|
||||
cm = httpx.Client(http1=True, http2=True, verify=verify, transport=transport)
|
||||
with cm as session:
|
||||
# see https://tools.ietf.org/html/rfc8484#section-4.1.1 for DoH
|
||||
# GET and POST examples
|
||||
|
@ -577,6 +569,8 @@ def receive_udp(
|
|||
request_mac: Optional[bytes] = b"",
|
||||
ignore_trailing: bool = False,
|
||||
raise_on_truncation: bool = False,
|
||||
ignore_errors: bool = False,
|
||||
query: Optional[dns.message.Message] = None,
|
||||
) -> Any:
|
||||
"""Read a DNS message from a UDP socket.
|
||||
|
||||
|
@ -617,28 +611,58 @@ def receive_udp(
|
|||
``(dns.message.Message, float, tuple)``
|
||||
tuple of the received message, the received time, and the address where
|
||||
the message arrived from.
|
||||
|
||||
*ignore_errors*, a ``bool``. If various format errors or response
|
||||
mismatches occur, ignore them and keep listening for a valid response.
|
||||
The default is ``False``.
|
||||
|
||||
*query*, a ``dns.message.Message`` or ``None``. If not ``None`` and
|
||||
*ignore_errors* is ``True``, check that the received message is a response
|
||||
to this query, and if not keep listening for a valid response.
|
||||
"""
|
||||
|
||||
wire = b""
|
||||
while True:
|
||||
(wire, from_address) = _udp_recv(sock, 65535, expiration)
|
||||
if _matches_destination(
|
||||
if not _matches_destination(
|
||||
sock.family, from_address, destination, ignore_unexpected
|
||||
):
|
||||
break
|
||||
received_time = time.time()
|
||||
r = dns.message.from_wire(
|
||||
wire,
|
||||
keyring=keyring,
|
||||
request_mac=request_mac,
|
||||
one_rr_per_rrset=one_rr_per_rrset,
|
||||
ignore_trailing=ignore_trailing,
|
||||
raise_on_truncation=raise_on_truncation,
|
||||
)
|
||||
if destination:
|
||||
return (r, received_time)
|
||||
else:
|
||||
return (r, received_time, from_address)
|
||||
continue
|
||||
received_time = time.time()
|
||||
try:
|
||||
r = dns.message.from_wire(
|
||||
wire,
|
||||
keyring=keyring,
|
||||
request_mac=request_mac,
|
||||
one_rr_per_rrset=one_rr_per_rrset,
|
||||
ignore_trailing=ignore_trailing,
|
||||
raise_on_truncation=raise_on_truncation,
|
||||
)
|
||||
except dns.message.Truncated as e:
|
||||
# If we got Truncated and not FORMERR, we at least got the header with TC
|
||||
# set, and very likely the question section, so we'll re-raise if the
|
||||
# message seems to be a response as we need to know when truncation happens.
|
||||
# We need to check that it seems to be a response as we don't want a random
|
||||
# injected message with TC set to cause us to bail out.
|
||||
if (
|
||||
ignore_errors
|
||||
and query is not None
|
||||
and not query.is_response(e.message())
|
||||
):
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
except Exception:
|
||||
if ignore_errors:
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
if ignore_errors and query is not None and not query.is_response(r):
|
||||
continue
|
||||
if destination:
|
||||
return (r, received_time)
|
||||
else:
|
||||
return (r, received_time, from_address)
|
||||
|
||||
|
||||
def udp(
|
||||
|
@ -653,6 +677,7 @@ def udp(
|
|||
ignore_trailing: bool = False,
|
||||
raise_on_truncation: bool = False,
|
||||
sock: Optional[Any] = None,
|
||||
ignore_errors: bool = False,
|
||||
) -> dns.message.Message:
|
||||
"""Return the response obtained after sending a query via UDP.
|
||||
|
||||
|
@ -689,6 +714,10 @@ def udp(
|
|||
if a socket is provided, it must be a nonblocking datagram socket,
|
||||
and the *source* and *source_port* are ignored.
|
||||
|
||||
*ignore_errors*, a ``bool``. If various format errors or response
|
||||
mismatches occur, ignore them and keep listening for a valid response.
|
||||
The default is ``False``.
|
||||
|
||||
Returns a ``dns.message.Message``.
|
||||
"""
|
||||
|
||||
|
@ -713,9 +742,13 @@ def udp(
|
|||
q.mac,
|
||||
ignore_trailing,
|
||||
raise_on_truncation,
|
||||
ignore_errors,
|
||||
q,
|
||||
)
|
||||
r.time = received_time - begin_time
|
||||
if not q.is_response(r):
|
||||
# We don't need to check q.is_response() if we are in ignore_errors mode
|
||||
# as receive_udp() will have checked it.
|
||||
if not (ignore_errors or q.is_response(r)):
|
||||
raise BadResponse
|
||||
return r
|
||||
assert (
|
||||
|
@ -735,48 +768,50 @@ def udp_with_fallback(
|
|||
ignore_trailing: bool = False,
|
||||
udp_sock: Optional[Any] = None,
|
||||
tcp_sock: Optional[Any] = None,
|
||||
ignore_errors: bool = False,
|
||||
) -> Tuple[dns.message.Message, bool]:
|
||||
"""Return the response to the query, trying UDP first and falling back
|
||||
to TCP if UDP results in a truncated response.
|
||||
|
||||
*q*, a ``dns.message.Message``, the query to send
|
||||
|
||||
*where*, a ``str`` containing an IPv4 or IPv6 address, where
|
||||
to send the message.
|
||||
*where*, a ``str`` containing an IPv4 or IPv6 address, where to send the message.
|
||||
|
||||
*timeout*, a ``float`` or ``None``, the number of seconds to wait before the
|
||||
query times out. If ``None``, the default, wait forever.
|
||||
*timeout*, a ``float`` or ``None``, the number of seconds to wait before the query
|
||||
times out. If ``None``, the default, wait forever.
|
||||
|
||||
*port*, an ``int``, the port send the message to. The default is 53.
|
||||
|
||||
*source*, a ``str`` containing an IPv4 or IPv6 address, specifying
|
||||
the source address. The default is the wildcard address.
|
||||
*source*, a ``str`` containing an IPv4 or IPv6 address, specifying the source
|
||||
address. The default is the wildcard address.
|
||||
|
||||
*source_port*, an ``int``, the port from which to send the message.
|
||||
The default is 0.
|
||||
*source_port*, an ``int``, the port from which to send the message. The default is
|
||||
0.
|
||||
|
||||
*ignore_unexpected*, a ``bool``. If ``True``, ignore responses from
|
||||
unexpected sources.
|
||||
*ignore_unexpected*, a ``bool``. If ``True``, ignore responses from unexpected
|
||||
sources.
|
||||
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
|
||||
RRset.
|
||||
*one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset.
|
||||
|
||||
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing
|
||||
junk at end of the received message.
|
||||
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the
|
||||
received message.
|
||||
|
||||
*udp_sock*, a ``socket.socket``, or ``None``, the socket to use for the
|
||||
UDP query. If ``None``, the default, a socket is created. Note that
|
||||
if a socket is provided, it must be a nonblocking datagram socket,
|
||||
and the *source* and *source_port* are ignored for the UDP query.
|
||||
*udp_sock*, a ``socket.socket``, or ``None``, the socket to use for the UDP query.
|
||||
If ``None``, the default, a socket is created. Note that if a socket is provided,
|
||||
it must be a nonblocking datagram socket, and the *source* and *source_port* are
|
||||
ignored for the UDP query.
|
||||
|
||||
*tcp_sock*, a ``socket.socket``, or ``None``, the connected socket to use for the
|
||||
TCP query. If ``None``, the default, a socket is created. Note that
|
||||
if a socket is provided, it must be a nonblocking connected stream
|
||||
socket, and *where*, *source* and *source_port* are ignored for the TCP
|
||||
query.
|
||||
TCP query. If ``None``, the default, a socket is created. Note that if a socket is
|
||||
provided, it must be a nonblocking connected stream socket, and *where*, *source*
|
||||
and *source_port* are ignored for the TCP query.
|
||||
|
||||
Returns a (``dns.message.Message``, tcp) tuple where tcp is ``True``
|
||||
if and only if TCP was used.
|
||||
*ignore_errors*, a ``bool``. If various format errors or response mismatches occur
|
||||
while listening for UDP, ignore them and keep listening for a valid response. The
|
||||
default is ``False``.
|
||||
|
||||
Returns a (``dns.message.Message``, tcp) tuple where tcp is ``True`` if and only if
|
||||
TCP was used.
|
||||
"""
|
||||
try:
|
||||
response = udp(
|
||||
|
@ -791,6 +826,7 @@ def udp_with_fallback(
|
|||
ignore_trailing,
|
||||
True,
|
||||
udp_sock,
|
||||
ignore_errors,
|
||||
)
|
||||
return (response, False)
|
||||
except dns.message.Truncated:
|
||||
|
@ -864,14 +900,12 @@ def send_tcp(
|
|||
"""
|
||||
|
||||
if isinstance(what, dns.message.Message):
|
||||
wire = what.to_wire()
|
||||
tcpmsg = what.to_wire(prepend_length=True)
|
||||
else:
|
||||
wire = what
|
||||
l = len(wire)
|
||||
# copying the wire into tcpmsg is inefficient, but lets us
|
||||
# avoid writev() or doing a short write that would get pushed
|
||||
# onto the net
|
||||
tcpmsg = struct.pack("!H", l) + wire
|
||||
# copying the wire into tcpmsg is inefficient, but lets us
|
||||
# avoid writev() or doing a short write that would get pushed
|
||||
# onto the net
|
||||
tcpmsg = len(what).to_bytes(2, "big") + what
|
||||
sent_time = time.time()
|
||||
_net_write(sock, tcpmsg, expiration)
|
||||
return (len(tcpmsg), sent_time)
|
||||
|
@ -1014,6 +1048,28 @@ def _tls_handshake(s, expiration):
|
|||
_wait_for_writable(s, expiration)
|
||||
|
||||
|
||||
def _make_dot_ssl_context(
|
||||
server_hostname: Optional[str], verify: Union[bool, str]
|
||||
) -> ssl.SSLContext:
|
||||
cafile: Optional[str] = None
|
||||
capath: Optional[str] = None
|
||||
if isinstance(verify, str):
|
||||
if os.path.isfile(verify):
|
||||
cafile = verify
|
||||
elif os.path.isdir(verify):
|
||||
capath = verify
|
||||
else:
|
||||
raise ValueError("invalid verify string")
|
||||
ssl_context = ssl.create_default_context(cafile=cafile, capath=capath)
|
||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||
if server_hostname is None:
|
||||
ssl_context.check_hostname = False
|
||||
ssl_context.set_alpn_protocols(["dot"])
|
||||
if verify is False:
|
||||
ssl_context.verify_mode = ssl.CERT_NONE
|
||||
return ssl_context
|
||||
|
||||
|
||||
def tls(
|
||||
q: dns.message.Message,
|
||||
where: str,
|
||||
|
@ -1026,6 +1082,7 @@ def tls(
|
|||
sock: Optional[ssl.SSLSocket] = None,
|
||||
ssl_context: Optional[ssl.SSLContext] = None,
|
||||
server_hostname: Optional[str] = None,
|
||||
verify: Union[bool, str] = True,
|
||||
) -> dns.message.Message:
|
||||
"""Return the response obtained after sending a query via TLS.
|
||||
|
||||
|
@ -1065,6 +1122,11 @@ def tls(
|
|||
default is ``None``, which means that no hostname is known, and if an
|
||||
SSL context is created, hostname checking will be disabled.
|
||||
|
||||
*verify*, a ``bool`` or ``str``. If a ``True``, then TLS certificate verification
|
||||
of the server is done using the default CA bundle; if ``False``, then no
|
||||
verification is done; if a `str` then it specifies the path to a certificate file or
|
||||
directory which will be used for verification.
|
||||
|
||||
Returns a ``dns.message.Message``.
|
||||
|
||||
"""
|
||||
|
@ -1091,10 +1153,7 @@ def tls(
|
|||
where, port, source, source_port
|
||||
)
|
||||
if ssl_context is None and not sock:
|
||||
ssl_context = ssl.create_default_context()
|
||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||
if server_hostname is None:
|
||||
ssl_context.check_hostname = False
|
||||
ssl_context = _make_dot_ssl_context(server_hostname, verify)
|
||||
|
||||
with _make_socket(
|
||||
af,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue