From a77e0c662c6d5b8224ac1e283aee8353bcd1536e Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Mon, 22 Apr 2024 16:49:15 +0200 Subject: [PATCH] CVE-2023-29483 --- dns/query.py | 60 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/dns/query.py b/dns/query.py index 19b9fbb..2dba3cc 100644 --- a/dns/query.py +++ b/dns/query.py @@ -170,6 +170,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( + f"got a response from {from_address} instead of " f"{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(). @@ -194,7 +210,7 @@ def _destination_and_source(af, where, port, source, source_port): def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, - ignore_unexpected=False, one_rr_per_rrset=False): + ignore_unexpected=False, one_rr_per_rrset=False, ignore_errors=False): """Return the response obtained after sending a query via UDP. @param q: the query @@ -239,26 +255,32 @@ def udp(q, where, timeout=None, port=53, af=None, source=None, source_port=0, while 1: _wait_for_readable(s, expiration) (wire, from_address) = s.recvfrom(65535) - if _addresses_equal(af, from_address, destination) or \ - (dns.inet.is_multicast(where) and - from_address[1:] == destination[1:]): - break - if not ignore_unexpected: - raise UnexpectedSource('got a response from ' - '%s instead of %s' % (from_address, - destination)) - finally: - if begin_time is None: - response_time = 0 - else: + if not _matches_destination( + s.family, from_address, destination, ignore_unexpected + ): + continue + response_time = time.time() - begin_time + + try: + r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, + one_rr_per_rrset=one_rr_per_rrset) + r.time = response_time + except Exception: + if ignore_errors: + continue + else: + raise + + if q.is_response(r): + return r + else: + if ignore_errors: + continue + else: + raise BadResponse + finally: s.close() - r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, - one_rr_per_rrset=one_rr_per_rrset) - r.time = response_time - if not q.is_response(r): - raise BadResponse - return r def _net_read(sock, count, expiration): -- 2.44.0