Skip to content

Commit

Permalink
[ext-py][dnspython] Address DoS via the Tudoor mechanism (CVE-2023-29483
Browse files Browse the repository at this point in the history
)

Based on the dnspython upstream commits

1. rthalley/dnspython@f66e25b
Upstream PR: rthalley/dnspython#1044

2. rthalley/dnspython@0ea5ad0
Upstream PR: rthalley/dnspython#1054
  • Loading branch information
amitsrivastava committed Jul 22, 2024
1 parent ce2894e commit 3d7bad3
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 18 deletions.
90 changes: 73 additions & 17 deletions desktop/core/ext-py3/dnspython-1.16.0/dns/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,22 @@ def _addresses_equal(af, a1, a2):
return n1 == n2 and a1[1:] == a2[1:]


def _matches_destination(af, from_address, destination, ignore_unexpected):
# Check that from_address is appropriate for a response to a query
# sent to destination.
if not destination:
return True
if _addresses_equal(af, from_address, destination) or (
dns.inet.is_multicast(destination[0]) and from_address[1:] == destination[1:]
):
return True
elif ignore_unexpected:
return False
raise UnexpectedSource('got a response from '
'%s instead of %s' % (from_address,
destination))


def _destination_and_source(af, where, port, source, source_port):
# Apply defaults and compute destination and source tuples
# suitable for use in connect(), sendto(), or bind().
Expand Down Expand Up @@ -222,7 +238,9 @@ def send_udp(sock, what, destination, expiration=None):

def receive_udp(sock, destination, expiration=None,
ignore_unexpected=False, one_rr_per_rrset=False,
keyring=None, request_mac=b'', ignore_trailing=False):
keyring=None, request_mac=b'', ignore_trailing=False,
ignore_errors=False,
query=None):
"""Read a DNS message from a UDP socket.
*sock*, a ``socket``.
Expand All @@ -247,6 +265,14 @@ def receive_udp(sock, destination, expiration=None,
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing
junk at end of the received message.
*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.
Raises if the message is malformed, if network errors occur, of if
there is a timeout.
Expand All @@ -257,22 +283,45 @@ def receive_udp(sock, destination, expiration=None,
while 1:
_wait_for_readable(sock, expiration)
(wire, from_address) = sock.recvfrom(65535)
if _addresses_equal(sock.family, from_address, destination) or \
(dns.inet.is_multicast(destination[0]) and
from_address[1:] == destination[1:]):
break
if not ignore_unexpected:
raise UnexpectedSource('got a response from '
'%s instead of %s' % (from_address,
destination))
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)
return (r, received_time)
if not _matches_destination(
sock.family, from_address, destination, ignore_unexpected
):
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)
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(q, where, timeout=None, port=53, af=None, source=None, source_port=0,
ignore_unexpected=False, one_rr_per_rrset=False, ignore_trailing=False):
ignore_unexpected=False, one_rr_per_rrset=False, ignore_trailing=False,
ignore_errors=False):
"""Return the response obtained after sending a query via UDP.
*q*, a ``dns.message.Message``, the query to send
Expand Down Expand Up @@ -305,6 +354,10 @@ def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0,
*ignore_trailing*, a ``bool``. If ``True``, ignore trailing
junk at end of the received message.
*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``.
"""

Expand All @@ -322,15 +375,18 @@ def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0,
(_, sent_time) = send_udp(s, wire, destination, expiration)
(r, received_time) = receive_udp(s, destination, expiration,
ignore_unexpected, one_rr_per_rrset,
q.keyring, q.mac, ignore_trailing)
q.keyring, q.mac, ignore_trailing,
ignore_errors, q)
finally:
if sent_time is None or received_time is None:
response_time = 0
else:
response_time = received_time - sent_time
s.close()
r.time = response_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

Expand Down
3 changes: 2 additions & 1 deletion desktop/core/ext-py3/dnspython-1.16.0/dns/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,8 @@ def query(self, qname, rdtype=dns.rdatatype.A, rdclass=dns.rdataclass.IN,
response = dns.query.udp(request, nameserver,
timeout, port,
source=source,
source_port=source_port)
source_port=source_port,
ignore_errors=True)
if response.flags & dns.flags.TC:
# Response truncated; retry with TCP.
tcp_attempt = True
Expand Down

0 comments on commit 3d7bad3

Please sign in to comment.