From 506a2aa1ebf6c6b7822f9c5b776fa5c27e2b164c Mon Sep 17 00:00:00 2001 From: Fantix King Date: Sat, 9 May 2020 14:50:43 -0500 Subject: [PATCH] apply bpo-37228 * refs python/cpython#17311 --- tests/test_udp.py | 41 +++++++++++++++++++++++++++++++++++++++++ uvloop/handles/udp.pxd | 2 +- uvloop/handles/udp.pyx | 5 +---- uvloop/includes/uv.pxd | 3 +-- uvloop/loop.pyx | 27 ++++++++++++++++++--------- 5 files changed, 62 insertions(+), 16 deletions(-) diff --git a/tests/test_udp.py b/tests/test_udp.py index 6f0f594..a747496 100644 --- a/tests/test_udp.py +++ b/tests/test_udp.py @@ -328,6 +328,47 @@ class _TestUDP: tr.close() self.loop.run_until_complete(pr.done) + def _skip_create_datagram_endpoint_reuse_addr(self): + if self.implementation == 'asyncio': + if sys.version_info[:2] >= (3, 11): + raise unittest.SkipTest() + if (3, 8, 0) <= sys.version_info < (3, 8, 1): + raise unittest.SkipTest() + if (3, 7, 0) <= sys.version_info < (3, 7, 6): + raise unittest.SkipTest() + if sys.version_info < (3, 6, 10): + raise unittest.SkipTest() + + def test_create_datagram_endpoint_reuse_address_error(self): + # bpo-37228: Ensure that explicit passing of `reuse_address=True` + # raises an error, as it is not safe to use SO_REUSEADDR when using UDP + + self._skip_create_datagram_endpoint_reuse_addr() + + coro = self.loop.create_datagram_endpoint( + lambda: MyDatagramProto(loop=self.loop), + local_addr=('127.0.0.1', 0), + reuse_address=True) + + with self.assertRaises(ValueError): + self.loop.run_until_complete(coro) + + def test_create_datagram_endpoint_reuse_address_warning(self): + # bpo-37228: Deprecate *reuse_address* parameter + + self._skip_create_datagram_endpoint_reuse_addr() + + coro = self.loop.create_datagram_endpoint( + lambda: MyDatagramProto(loop=self.loop), + local_addr=('127.0.0.1', 0), + reuse_address=False) + + with self.assertWarns(DeprecationWarning): + tr, pr = self.loop.run_until_complete(coro) + + tr.close() + self.loop.run_until_complete(pr.done) + class Test_UV_UDP(_TestUDP, tb.UVTestCase): diff --git a/uvloop/handles/udp.pxd b/uvloop/handles/udp.pxd index 0647f23..c4d2f3d 100644 --- a/uvloop/handles/udp.pxd +++ b/uvloop/handles/udp.pxd @@ -9,7 +9,7 @@ cdef class UDPTransport(UVBaseTransport): cdef _connect(self, system.sockaddr* addr, size_t addr_len) - cdef _bind(self, system.sockaddr* addr, bint reuse_addr) + cdef _bind(self, system.sockaddr* addr) cdef open(self, int family, int sockfd) cdef _set_broadcast(self, bint on) diff --git a/uvloop/handles/udp.pyx b/uvloop/handles/udp.pyx index 93596fa..4d590a6 100644 --- a/uvloop/handles/udp.pyx +++ b/uvloop/handles/udp.pyx @@ -104,16 +104,13 @@ cdef class UDPTransport(UVBaseTransport): exc = convert_error(err) raise exc - cdef _bind(self, system.sockaddr* addr, bint reuse_addr): + cdef _bind(self, system.sockaddr* addr): cdef: int err int flags = 0 self._ensure_alive() - if reuse_addr: - flags |= uv.UV_UDP_REUSEADDR - err = uv.uv_udp_bind(self._handle, addr, flags) if err < 0: exc = convert_error(err) diff --git a/uvloop/includes/uv.pxd b/uvloop/includes/uv.pxd index 5f034b3..cfb2be4 100644 --- a/uvloop/includes/uv.pxd +++ b/uvloop/includes/uv.pxd @@ -199,8 +199,7 @@ cdef extern from "uv.h" nogil: ctypedef enum uv_udp_flags: UV_UDP_IPV6ONLY = 1, - UV_UDP_PARTIAL = 2, - UV_UDP_REUSEADDR = 4 + UV_UDP_PARTIAL = 2 ctypedef enum uv_membership: UV_LEAVE_GROUP = 0, diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index 54b1194..a1ea92c 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -90,6 +90,11 @@ cdef inline socket_dec_io_ref(sock): sock._decref_socketios() +# Used for deprecation and removal of `loop.create_datagram_endpoint()`'s +# *reuse_address* parameter +_unset = object() + + @cython.no_gc_clear cdef class Loop: def __cinit__(self): @@ -2924,7 +2929,7 @@ cdef class Loop: async def create_datagram_endpoint(self, protocol_factory, local_addr=None, remote_addr=None, *, family=0, proto=0, flags=0, - reuse_address=None, reuse_port=None, + reuse_address=_unset, reuse_port=None, allow_broadcast=None, sock=None): """A coroutine which creates a datagram endpoint. @@ -2936,11 +2941,6 @@ cdef class Loop: socket family AF_INET or socket.AF_INET6 depending on host (or family if specified), socket type SOCK_DGRAM. - reuse_address tells the kernel to reuse a local socket in - TIME_WAIT state, without waiting for its natural timeout to - expire. If not specified it will automatically be set to True on - UNIX. - reuse_port tells the kernel to allow this endpoint to be bound to the same port as other existing endpoints are bound to, so long as they all set this flag when being created. This option is not @@ -2965,7 +2965,7 @@ cdef class Loop: 'A UDP Socket was expected, got {!r}'.format(sock)) if (local_addr or remote_addr or family or proto or flags or - reuse_address or reuse_port or allow_broadcast): + reuse_port or allow_broadcast): # show the problematic kwargs in exception msg opts = dict(local_addr=local_addr, remote_addr=remote_addr, family=family, proto=proto, flags=flags, @@ -2982,7 +2982,16 @@ cdef class Loop: udp.open(sock.family, sock.fileno()) udp._attach_fileobj(sock) else: - reuse_address = bool(reuse_address) + if reuse_address is not _unset: + if reuse_address: + raise ValueError("Passing `reuse_address=True` is no " + "longer supported, as the usage of " + "SO_REUSEPORT in UDP poses a significant " + "security concern.") + else: + warnings_warn("The *reuse_address* parameter has been " + "deprecated as of 0.15.", DeprecationWarning, + stacklevel=2) reuse_port = bool(reuse_port) if reuse_port and not has_SO_REUSEPORT: raise ValueError( @@ -3035,7 +3044,7 @@ cdef class Loop: udp._init(self, lai.ai_family) if reuse_port: self._sock_set_reuseport(udp._fileno()) - udp._bind(lai.ai_addr, reuse_address) + udp._bind(lai.ai_addr) except (KeyboardInterrupt, SystemExit): raise except BaseException as ex: