On Tue, Aug 24, 2021 at 09:52 AM, Filippo Giunchedi wrote: > On Tue, Jun 08, 2021 at 10:03 AM, Filippo Giunchedi wrote: > > Package: swift-container > > Version: 2.26.0-10 > > Severity: important > > File: /usr/bin/swift-container-reconciler > > > > Dear Maintainer, > > I'm experimenting with Swift on Bullseye and came across a problem with > > container-reconciler (possibly others) when using hostnames in > > memcache_servers. Namely these errors: > > In the "possibly others" category, swift-dispersion-report is also 100% > broken in Bullseye:
I was able to get python3-eventlet to play nice with dnspython2 by integrating https://github.com/eventlet/eventlet/pull/722 from upstream. See debdiff attached for the result against Bullseye's python-eventlet
diff -Nru python-eventlet-0.26.1/debian/changelog python-eventlet-0.26.1/debian/changelog --- python-eventlet-0.26.1/debian/changelog 2021-05-11 08:03:43.000000000 +0200 +++ python-eventlet-0.26.1/debian/changelog 2021-08-24 14:04:54.000000000 +0200 @@ -1,3 +1,10 @@ +python-eventlet (0.26.1-8~wmf1) bullseye; urgency=medium + + * Fix dnspython 2 compat + ** See also https://github.com/eventlet/eventlet/pull/722 + + -- Filippo Giunchedi <[email protected]> Tue, 24 Aug 2021 14:04:54 +0200 + python-eventlet (0.26.1-7) unstable; urgency=medium * CVE-2021-21419: Malicious peer may exhaust memory on Eventlet side diff -Nru python-eventlet-0.26.1/debian/greendns.orig.py python-eventlet-0.26.1/debian/greendns.orig.py --- python-eventlet-0.26.1/debian/greendns.orig.py 2021-05-11 08:03:43.000000000 +0200 +++ python-eventlet-0.26.1/debian/greendns.orig.py 2021-08-24 14:04:54.000000000 +0200 @@ -120,12 +120,13 @@ return is_ipv4_addr(host) or is_ipv6_addr(host) -def compute_expiration(query, timeout): - # NOTE(ralonsoh): in dnspython v2.0.0, "_compute_expiration" was replaced - # by "_compute_times". - if hasattr(query, '_compute_expiration'): +# NOTE(ralonsoh): in dnspython v2.0.0, "_compute_expiration" was replaced +# by "_compute_times". +if hasattr(dns.query, '_compute_expiration'): + def compute_expiration(query, timeout): return query._compute_expiration(timeout) - else: +else: + def compute_expiration(query, timeout): return query._compute_times(timeout)[1] @@ -669,8 +670,21 @@ raise dns.exception.Timeout +# Test if raise_on_truncation is an argument we should handle. +# It was newly added in dnspython 2.0 +try: + dns.message.from_wire("", raise_on_truncation=True) +except dns.message.ShortHeader: + _handle_raise_on_truncation = True +except TypeError: + # Argument error, there is no argument "raise_on_truncation" + _handle_raise_on_truncation = False + + def udp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, - af=None, source=None, source_port=0, ignore_unexpected=False): + af=None, source=None, source_port=0, ignore_unexpected=False, + one_rr_per_rrset=False, ignore_trailing=False, + raise_on_truncation=False, sock=None): """coro friendly replacement for dns.query.udp Return the response obtained after sending a query via UDP. @@ -695,7 +709,21 @@ @type source_port: int @param ignore_unexpected: If True, ignore responses from unexpected sources. The default is False. - @type ignore_unexpected: bool""" + @type ignore_unexpected: bool + @param one_rr_per_rrset: If True, put each RR into its own + RRset. + @type one_rr_per_rrset: bool + @param ignore_trailing: If True, ignore trailing + junk at end of the received message. + @type ignore_trailing: bool + @param raise_on_truncation: If True, raise an exception if + the TC bit is set. + @type raise_on_truncation: bool + @param sock: the socket to use for the + 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. + @type sock: socket.socket | None""" wire = q.to_wire() if af is None: @@ -717,7 +745,10 @@ if source is not None: source = (source, source_port, 0, 0) - s = socket.socket(af, socket.SOCK_DGRAM) + if sock: + s = sock + else: + s = socket.socket(af, socket.SOCK_DGRAM) s.settimeout(timeout) try: expiration = compute_expiration(dns.query, timeout) @@ -765,14 +796,23 @@ finally: s.close() - r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac) + if _handle_raise_on_truncation: + r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, + one_rr_per_rrset=one_rr_per_rrset, + ignore_trailing=ignore_trailing, + raise_on_truncation=raise_on_truncation) + else: + r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, + one_rr_per_rrset=one_rr_per_rrset, + ignore_trailing=ignore_trailing) if not q.is_response(r): raise dns.query.BadResponse() return r def tcp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, - af=None, source=None, source_port=0): + af=None, source=None, source_port=0, + one_rr_per_rrset=False, ignore_trailing=False, sock=None): """coro friendly replacement for dns.query.tcp Return the response obtained after sending a query via TCP. @@ -794,7 +834,19 @@ @type source: string @param source_port: The port from which to send the message. The default is 0. - @type source_port: int""" + @type source_port: int + @type ignore_unexpected: bool + @param one_rr_per_rrset: If True, put each RR into its own + RRset. + @type one_rr_per_rrset: bool + @param ignore_trailing: If True, ignore trailing + junk at end of the received message. + @type ignore_trailing: bool + @param sock: the socket to use for the + 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. + @type sock: socket.socket | None""" wire = q.to_wire() if af is None: @@ -810,7 +862,10 @@ destination = (where, port, 0, 0) if source is not None: source = (source, source_port, 0, 0) - s = socket.socket(af, socket.SOCK_STREAM) + if sock: + s = sock + else: + s = socket.socket(af, socket.SOCK_STREAM) s.settimeout(timeout) try: expiration = compute_expiration(dns.query, timeout) @@ -838,7 +893,9 @@ wire = bytes(_net_read(s, l, expiration)) finally: s.close() - r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac) + r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, + one_rr_per_rrset=one_rr_per_rrset, + ignore_trailing=ignore_trailing) if not q.is_response(r): raise dns.query.BadResponse() return r diff -Nru python-eventlet-0.26.1/debian/greendns.py python-eventlet-0.26.1/debian/greendns.py --- python-eventlet-0.26.1/debian/greendns.py 2021-05-11 08:03:43.000000000 +0200 +++ python-eventlet-0.26.1/debian/greendns.py 2021-08-24 14:04:54.000000000 +0200 @@ -120,12 +120,13 @@ return is_ipv4_addr(host) or is_ipv6_addr(host) -def compute_expiration(query, timeout): - # NOTE(ralonsoh): in dnspython v2.0.0, "_compute_expiration" was replaced - # by "_compute_times". - if hasattr(query, '_compute_expiration'): +# NOTE(ralonsoh): in dnspython v2.0.0, "_compute_expiration" was replaced +# by "_compute_times". +if hasattr(dns.query, '_compute_expiration'): + def compute_expiration(query, timeout): return query._compute_expiration(timeout) - else: +else: + def compute_expiration(query, timeout): return query._compute_times(timeout)[1] @@ -669,8 +670,21 @@ raise dns.exception.Timeout +# Test if raise_on_truncation is an argument we should handle. +# It was newly added in dnspython 2.0 +try: + dns.message.from_wire("", raise_on_truncation=True) +except dns.message.ShortHeader: + _handle_raise_on_truncation = True +except TypeError: + # Argument error, there is no argument "raise_on_truncation" + _handle_raise_on_truncation = False + + def udp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, - af=None, source=None, source_port=0, ignore_unexpected=False): + af=None, source=None, source_port=0, ignore_unexpected=False, + one_rr_per_rrset=False, ignore_trailing=False, + raise_on_truncation=False, sock=None): """coro friendly replacement for dns.query.udp Return the response obtained after sending a query via UDP. @@ -695,7 +709,21 @@ @type source_port: int @param ignore_unexpected: If True, ignore responses from unexpected sources. The default is False. - @type ignore_unexpected: bool""" + @type ignore_unexpected: bool + @param one_rr_per_rrset: If True, put each RR into its own + RRset. + @type one_rr_per_rrset: bool + @param ignore_trailing: If True, ignore trailing + junk at end of the received message. + @type ignore_trailing: bool + @param raise_on_truncation: If True, raise an exception if + the TC bit is set. + @type raise_on_truncation: bool + @param sock: the socket to use for the + 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. + @type sock: socket.socket | None""" wire = q.to_wire() if af is None: @@ -717,7 +745,10 @@ if source is not None: source = (source, source_port, 0, 0) - s = socket.socket(af, socket.SOCK_DGRAM) + if sock: + s = sock + else: + s = socket.socket(af, socket.SOCK_DGRAM) s.settimeout(timeout) try: expiration = compute_expiration(dns.query, timeout) @@ -765,14 +796,23 @@ finally: s.close() - r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac) + if _handle_raise_on_truncation: + r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, + one_rr_per_rrset=one_rr_per_rrset, + ignore_trailing=ignore_trailing, + raise_on_truncation=raise_on_truncation) + else: + r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, + one_rr_per_rrset=one_rr_per_rrset, + ignore_trailing=ignore_trailing) if not q.is_response(r): raise dns.query.BadResponse() return r def tcp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, - af=None, source=None, source_port=0): + af=None, source=None, source_port=0, + one_rr_per_rrset=False, ignore_trailing=False, sock=None): """coro friendly replacement for dns.query.tcp Return the response obtained after sending a query via TCP. @@ -794,7 +834,19 @@ @type source: string @param source_port: The port from which to send the message. The default is 0. - @type source_port: int""" + @type source_port: int + @type ignore_unexpected: bool + @param one_rr_per_rrset: If True, put each RR into its own + RRset. + @type one_rr_per_rrset: bool + @param ignore_trailing: If True, ignore trailing + junk at end of the received message. + @type ignore_trailing: bool + @param sock: the socket to use for the + 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. + @type sock: socket.socket | None""" wire = q.to_wire() if af is None: @@ -810,7 +862,10 @@ destination = (where, port, 0, 0) if source is not None: source = (source, source_port, 0, 0) - s = socket.socket(af, socket.SOCK_STREAM) + if sock: + s = sock + else: + s = socket.socket(af, socket.SOCK_STREAM) s.settimeout(timeout) try: expiration = compute_expiration(dns.query, timeout) @@ -838,7 +893,9 @@ wire = bytes(_net_read(s, l, expiration)) finally: s.close() - r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac) + r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, + one_rr_per_rrset=one_rr_per_rrset, + ignore_trailing=ignore_trailing) if not q.is_response(r): raise dns.query.BadResponse() return r diff -Nru python-eventlet-0.26.1/debian/patches/Check_compute_expiration_at_module_level.patch python-eventlet-0.26.1/debian/patches/Check_compute_expiration_at_module_level.patch --- python-eventlet-0.26.1/debian/patches/Check_compute_expiration_at_module_level.patch 1970-01-01 01:00:00.000000000 +0100 +++ python-eventlet-0.26.1/debian/patches/Check_compute_expiration_at_module_level.patch 2021-08-24 14:04:34.000000000 +0200 @@ -0,0 +1,30 @@ +Description: check _compute_expiration at module level +Author: Felix Yan <[email protected]> +Date: Tue, 17 Aug 2021 00:46:49 +0800 +Origin: https://github.com/eventlet/eventlet/pull/722/commits/ecd55ad127ea630e45b630e45c53146bc064a65c + +--- + eventlet/support/greendns.py | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/eventlet/support/greendns.py b/eventlet/support/greendns.py +index b95790c3e..ab98e5882 100644 +--- a/eventlet/support/greendns.py ++++ b/eventlet/support/greendns.py +@@ -120,12 +120,13 @@ def is_ip_addr(host): + return is_ipv4_addr(host) or is_ipv6_addr(host) + + +-def compute_expiration(query, timeout): +- # NOTE(ralonsoh): in dnspython v2.0.0, "_compute_expiration" was replaced +- # by "_compute_times". +- if hasattr(query, '_compute_expiration'): ++# NOTE(ralonsoh): in dnspython v2.0.0, "_compute_expiration" was replaced ++# by "_compute_times". ++if hasattr(dns.query, '_compute_expiration'): ++ def compute_expiration(query, timeout): + return query._compute_expiration(timeout) +- else: ++else: ++ def compute_expiration(query, timeout): + return query._compute_times(timeout)[1] diff -Nru python-eventlet-0.26.1/debian/patches/add_handling_for_new_dnspython_arguments.patch python-eventlet-0.26.1/debian/patches/add_handling_for_new_dnspython_arguments.patch --- python-eventlet-0.26.1/debian/patches/add_handling_for_new_dnspython_arguments.patch 1970-01-01 01:00:00.000000000 +0100 +++ python-eventlet-0.26.1/debian/patches/add_handling_for_new_dnspython_arguments.patch 2021-08-24 14:04:27.000000000 +0200 @@ -0,0 +1,143 @@ +Description: Add handling for new dnspython arguments + one_rr_per_rrset and ignore_trailing are present very long ago, + raise_on_truncation and sock are added since dnspython 2.0. +Author: Felix Yan <[email protected]> +Date: Tue, 17 Aug 2021 15:42:23 +0800 +Origin: https://github.com/eventlet/eventlet/pull/722/commits/4496d99294233383250c0aa38f37b2a0751a346d + +--- + eventlet/support/greendns.py | 72 ++++++++++++++++++++++++++++++++---- + 1 file changed, 64 insertions(+), 8 deletions(-) + +diff --git a/eventlet/support/greendns.py b/eventlet/support/greendns.py +index ab98e5882..76545c7ee 100644 +--- a/eventlet/support/greendns.py ++++ b/eventlet/support/greendns.py +@@ -670,8 +670,21 @@ def _net_write(sock, data, expiration): + raise dns.exception.Timeout + + ++# Test if raise_on_truncation is an argument we should handle. ++# It was newly added in dnspython 2.0 ++try: ++ dns.message.from_wire("", raise_on_truncation=True) ++except dns.message.ShortHeader: ++ _handle_raise_on_truncation = True ++except TypeError: ++ # Argument error, there is no argument "raise_on_truncation" ++ _handle_raise_on_truncation = False ++ ++ + def udp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, +- af=None, source=None, source_port=0, ignore_unexpected=False): ++ af=None, source=None, source_port=0, ignore_unexpected=False, ++ one_rr_per_rrset=False, ignore_trailing=False, ++ raise_on_truncation=False, sock=None): + """coro friendly replacement for dns.query.udp + Return the response obtained after sending a query via UDP. + +@@ -696,7 +709,21 @@ def udp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, + @type source_port: int + @param ignore_unexpected: If True, ignore responses from unexpected + sources. The default is False. +- @type ignore_unexpected: bool""" ++ @type ignore_unexpected: bool ++ @param one_rr_per_rrset: If True, put each RR into its own ++ RRset. ++ @type one_rr_per_rrset: bool ++ @param ignore_trailing: If True, ignore trailing ++ junk at end of the received message. ++ @type ignore_trailing: bool ++ @param raise_on_truncation: If True, raise an exception if ++ the TC bit is set. ++ @type raise_on_truncation: bool ++ @param sock: the socket to use for the ++ 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. ++ @type sock: socket.socket | None""" + + wire = q.to_wire() + if af is None: +@@ -718,7 +745,10 @@ def udp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, + if source is not None: + source = (source, source_port, 0, 0) + +- s = socket.socket(af, socket.SOCK_DGRAM) ++ if sock: ++ s = sock ++ else: ++ s = socket.socket(af, socket.SOCK_DGRAM) + s.settimeout(timeout) + try: + expiration = compute_expiration(dns.query, timeout) +@@ -766,14 +796,23 @@ def udp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, + finally: + s.close() + +- r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac) ++ if _handle_raise_on_truncation: ++ r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, ++ one_rr_per_rrset=one_rr_per_rrset, ++ ignore_trailing=ignore_trailing, ++ raise_on_truncation=raise_on_truncation) ++ else: ++ r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, ++ one_rr_per_rrset=one_rr_per_rrset, ++ ignore_trailing=ignore_trailing) + if not q.is_response(r): + raise dns.query.BadResponse() + return r + + + def tcp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, +- af=None, source=None, source_port=0): ++ af=None, source=None, source_port=0, ++ one_rr_per_rrset=False, ignore_trailing=False, sock=None): + """coro friendly replacement for dns.query.tcp + Return the response obtained after sending a query via TCP. + +@@ -795,7 +834,19 @@ def tcp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, + @type source: string + @param source_port: The port from which to send the message. + The default is 0. +- @type source_port: int""" ++ @type source_port: int ++ @type ignore_unexpected: bool ++ @param one_rr_per_rrset: If True, put each RR into its own ++ RRset. ++ @type one_rr_per_rrset: bool ++ @param ignore_trailing: If True, ignore trailing ++ junk at end of the received message. ++ @type ignore_trailing: bool ++ @param sock: the socket to use for the ++ 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. ++ @type sock: socket.socket | None""" + + wire = q.to_wire() + if af is None: +@@ -811,7 +862,10 @@ def tcp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, + destination = (where, port, 0, 0) + if source is not None: + source = (source, source_port, 0, 0) +- s = socket.socket(af, socket.SOCK_STREAM) ++ if sock: ++ s = sock ++ else: ++ s = socket.socket(af, socket.SOCK_STREAM) + s.settimeout(timeout) + try: + expiration = compute_expiration(dns.query, timeout) +@@ -839,7 +893,9 @@ def tcp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, + wire = bytes(_net_read(s, l, expiration)) + finally: + s.close() +- r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac) ++ r = dns.message.from_wire(wire, keyring=q.keyring, request_mac=q.mac, ++ one_rr_per_rrset=one_rr_per_rrset, ++ ignore_trailing=ignore_trailing) + if not q.is_response(r): + raise dns.query.BadResponse() + return r diff -Nru python-eventlet-0.26.1/debian/patches/series python-eventlet-0.26.1/debian/patches/series --- python-eventlet-0.26.1/debian/patches/series 2021-05-11 08:03:43.000000000 +0200 +++ python-eventlet-0.26.1/debian/patches/series 2021-08-24 14:04:44.000000000 +0200 @@ -8,6 +8,8 @@ 0009-Removed-test_urllib-that-is-failing-in-py36.patch 0016-imp-rename.patch Replace-dnspython-_compute_expiration-by-_compute_times.patch +Check_compute_expiration_at_module_level.patch +add_handling_for_new_dnspython_arguments.patch fix-test_noraise_dns_tcp.patch remove-non-deterministic-test_communicate_with_poll.patch 0017-py39-Add-_at_fork_reinit-method-to-Semaphores.patch

