From 22b51696a45dcf73ec67139151b35c48d8e37ca6 Mon Sep 17 00:00:00 2001 From: John Vandenberg Date: Sat, 15 Aug 2020 23:36:45 +0700 Subject: [PATCH 1/8] setup.py: Unpin --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index cf5150a71..3a446e763 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ url='http://eventlet.net', packages=setuptools.find_packages(exclude=['benchmarks', 'tests', 'tests.*']), install_requires=( - 'dnspython >= 1.15.0, < 2.0.0', + 'dnspython >= 1.15.0', 'greenlet >= 0.3', 'monotonic >= 1.4;python_version<"3.5"', 'six >= 1.10.0', From 51569f347671ab1ca9b5d585a1a17dc12e7e22c9 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Mon, 20 Jul 2020 17:21:30 +0000 Subject: [PATCH 2/8] Replace dnspython "_compute_expiration" by "_compute_times". In dnspython v2.0.0, "_compute_expiration" was replaced by "_compute_times". Once the minimum version of dnspython is v2.0.0, we can remove this wrapping method. Related to #629 --- eventlet/support/greendns.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/eventlet/support/greendns.py b/eventlet/support/greendns.py index 10dd04b68..b95790c3e 100644 --- a/eventlet/support/greendns.py +++ b/eventlet/support/greendns.py @@ -120,6 +120,15 @@ 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'): + return query._compute_expiration(timeout) + else: + return query._compute_times(timeout)[1] + + class HostsAnswer(dns.resolver.Answer): """Answer class for HostsResolver object""" @@ -711,7 +720,7 @@ def udp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, s = socket.socket(af, socket.SOCK_DGRAM) s.settimeout(timeout) try: - expiration = dns.query._compute_expiration(timeout) + expiration = compute_expiration(dns.query, timeout) if source is not None: s.bind(source) while True: @@ -804,7 +813,7 @@ def tcp(q, where, timeout=DNS_QUERY_TIMEOUT, port=53, s = socket.socket(af, socket.SOCK_STREAM) s.settimeout(timeout) try: - expiration = dns.query._compute_expiration(timeout) + expiration = compute_expiration(dns.query, timeout) if source is not None: s.bind(source) while True: From 2eb6ea8240cbae7f9863592034c46542e674e9a0 Mon Sep 17 00:00:00 2001 From: John Vandenberg Date: Sat, 15 Aug 2020 22:31:21 +0700 Subject: [PATCH 3/8] tox.ini: Add dnspython1 --- .github/workflows/test.yaml | 6 ++++++ tox.ini | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index d5b7c459b..ee80d3236 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -32,22 +32,28 @@ jobs: - { py: 2.7, toxenv: py27-epolls, ignore-error: false } - { py: 2.7, toxenv: py27-poll, ignore-error: false } - { py: 2.7, toxenv: py27-selects, ignore-error: false } + - { py: 2.7, toxenv: py27-dnspython1, ignore-error: false } - { py: 3.5, toxenv: py35-epolls, ignore-error: false } - { py: 3.5, toxenv: py35-poll, ignore-error: false } - { py: 3.5, toxenv: py35-selects, ignore-error: false } + - { py: 3.5, toxenv: py35-dnspython1, ignore-error: false } - { py: 3.6, toxenv: py36-epolls, ignore-error: false } - { py: 3.6, toxenv: py36-poll, ignore-error: false } - { py: 3.6, toxenv: py36-selects, ignore-error: false } + - { py: 3.6, toxenv: py36-dnspython1, ignore-error: false } - { py: 3.7, toxenv: py37-epolls, ignore-error: false } - { py: 3.7, toxenv: py37-poll, ignore-error: false } - { py: 3.7, toxenv: py37-selects, ignore-error: false } + - { py: 3.7, toxenv: py37-dnspython1, ignore-error: false } - { py: 3.8, toxenv: py38-epolls, ignore-error: false } - { py: 3.8, toxenv: py38-openssl, ignore-error: false } - { py: 3.8, toxenv: py38-poll, ignore-error: false } - { py: 3.8, toxenv: py38-selects, ignore-error: false } + - { py: 3.8, toxenv: py38-dnspython1, ignore-error: false } - { py: 3.9, toxenv: py39-epolls, ignore-error: false } - { py: 3.9, toxenv: py39-poll, ignore-error: false } - { py: 3.9, toxenv: py39-selects, ignore-error: false } + - { py: 3.9, toxenv: py39-dnspython1, ignore-error: false } - { py: 3.x, toxenv: ipv6, ignore-error: false } - { py: pypy2, toxenv: pypy2-epolls, ignore-error: true } - { py: pypy3, toxenv: pypy3-epolls, ignore-error: true } diff --git a/tox.ini b/tox.ini index 59fd833b8..9617fd0fc 100644 --- a/tox.ini +++ b/tox.ini @@ -16,7 +16,7 @@ statistics = 1 [tox] minversion=2.5 envlist = - ipv6, pep8, py{27,35,36,37,38,39,py2,py3}-{selects,poll,epolls}, py38-openssl + ipv6, pep8, py{27,35,36,37,38,39,py2,py3}-{selects,poll,epolls,dnspython1}, py38-openssl skipsdist = True [testenv:ipv6] @@ -74,6 +74,7 @@ deps = py{38,39}: psycopg2-binary==2.8.4 setuptools==38.5.1 {selects,poll,epolls}: pyzmq==19.0.2 + dnspython1: dnspython<2 usedevelop = True commands = nosetests --verbose {env:tox_cover_args} {posargs:tests/} From f5424dcb4b2e7bda662965f7228fea131df13351 Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Mon, 16 Aug 2021 23:27:15 +0800 Subject: [PATCH 4/8] Resolve the remaining test failure (changed from list to set) --- tests/greendns_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/greendns_test.py b/tests/greendns_test.py index a6faae599..7419b358a 100644 --- a/tests/greendns_test.py +++ b/tests/greendns_test.py @@ -901,7 +901,7 @@ def test_noraise_dns_tcp(self): resolver.nameserver_ports[dnsaddr[0]] = dnsaddr[1] response = resolver.query('host.example.com', 'a', tcp=True) self.assertIsInstance(response, Answer) - self.assertEqual(response.rrset.items[0].address, expected_ip) + self.assertEqual(list(response.rrset.items)[0].address, expected_ip) def test_reverse_name(): From b712f19b6a0dec4e81d6c403268c7f4c625737f7 Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Tue, 17 Aug 2021 00:02:46 +0800 Subject: [PATCH 5/8] Test dnspython1 on only py27 & py39 as suggested --- .github/workflows/test.yaml | 4 ---- tox.ini | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ee80d3236..3801d2aad 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -36,20 +36,16 @@ jobs: - { py: 3.5, toxenv: py35-epolls, ignore-error: false } - { py: 3.5, toxenv: py35-poll, ignore-error: false } - { py: 3.5, toxenv: py35-selects, ignore-error: false } - - { py: 3.5, toxenv: py35-dnspython1, ignore-error: false } - { py: 3.6, toxenv: py36-epolls, ignore-error: false } - { py: 3.6, toxenv: py36-poll, ignore-error: false } - { py: 3.6, toxenv: py36-selects, ignore-error: false } - - { py: 3.6, toxenv: py36-dnspython1, ignore-error: false } - { py: 3.7, toxenv: py37-epolls, ignore-error: false } - { py: 3.7, toxenv: py37-poll, ignore-error: false } - { py: 3.7, toxenv: py37-selects, ignore-error: false } - - { py: 3.7, toxenv: py37-dnspython1, ignore-error: false } - { py: 3.8, toxenv: py38-epolls, ignore-error: false } - { py: 3.8, toxenv: py38-openssl, ignore-error: false } - { py: 3.8, toxenv: py38-poll, ignore-error: false } - { py: 3.8, toxenv: py38-selects, ignore-error: false } - - { py: 3.8, toxenv: py38-dnspython1, ignore-error: false } - { py: 3.9, toxenv: py39-epolls, ignore-error: false } - { py: 3.9, toxenv: py39-poll, ignore-error: false } - { py: 3.9, toxenv: py39-selects, ignore-error: false } diff --git a/tox.ini b/tox.ini index 9617fd0fc..3697f7ebc 100644 --- a/tox.ini +++ b/tox.ini @@ -16,7 +16,7 @@ statistics = 1 [tox] minversion=2.5 envlist = - ipv6, pep8, py{27,35,36,37,38,39,py2,py3}-{selects,poll,epolls,dnspython1}, py38-openssl + ipv6, pep8, py{27,35,36,37,38,39,py2,py3}-{selects,poll,epolls}, py38-openssl, py27-dnspython1, py39-dnspython1 skipsdist = True [testenv:ipv6] From ecd55ad127ea630e45b630e45c53146bc064a65c Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Tue, 17 Aug 2021 00:46:49 +0800 Subject: [PATCH 6/8] Check _compute_expiration at module level --- 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] From 32a67efe6abda531e17064420dad3af3410ad983 Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Tue, 17 Aug 2021 00:57:14 +0800 Subject: [PATCH 7/8] Set flags from enums, and add QR to please dnspython >= 2.1 --- tests/isolated/socket_resolve_green.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/isolated/socket_resolve_green.py b/tests/isolated/socket_resolve_green.py index 6017d5ee2..611d7dc9d 100644 --- a/tests/isolated/socket_resolve_green.py +++ b/tests/isolated/socket_resolve_green.py @@ -7,6 +7,7 @@ import time import dns.message import dns.query + import dns.flags n = 10 delay = 0.01 @@ -17,7 +18,7 @@ def slow_udp(q, *a, **kw): addr = addr_map[qname.to_text()] r = dns.message.make_response(q) r.index = None - r.flags = 256 + r.flags = dns.flags.QR | dns.flags.RD r.answer.append(dns.rrset.from_text(str(qname), 60, 'IN', 'A', addr)) r.time = 0.001 eventlet.sleep(delay) From 4496d99294233383250c0aa38f37b2a0751a346d Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Tue, 17 Aug 2021 15:42:23 +0800 Subject: [PATCH 8/8] 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. --- 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