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

Reply via email to