summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2019-12-09 14:39:54 (GMT)
committerƁukasz Langa <lukasz@langa.pl>2019-12-09 14:39:54 (GMT)
commit79c29742a8ba96fc933efe34e55e90537b3eb780 (patch)
tree6391cd052588825c65dc566599b4acb38a01c65c /Lib
parentb22183f2738e0e6c23f8c5fb5b232768c184ec96 (diff)
downloadcpython-79c29742a8ba96fc933efe34e55e90537b3eb780.zip
cpython-79c29742a8ba96fc933efe34e55e90537b3eb780.tar.gz
cpython-79c29742a8ba96fc933efe34e55e90537b3eb780.tar.bz2
bpo-37228: Fix loop.create_datagram_endpoint()'s usage of SO_REUSEADDR (GH-17311) (#17529)
(cherry picked from commit ab513a38c98695f271e448fe2cb7c5e39eeaaaaf) Co-authored-by: Kyle Stanley <aeros167@gmail.com>
Diffstat (limited to 'Lib')
-rw-r--r--Lib/asyncio/base_events.py25
-rw-r--r--Lib/test/test_asyncio/test_base_events.py41
2 files changed, 42 insertions, 24 deletions
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index 14b80bd..bfd4011 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -66,6 +66,10 @@ _HAS_IPv6 = hasattr(socket, 'AF_INET6')
# Maximum timeout passed to select to avoid OS limitations
MAXIMUM_SELECT_TIMEOUT = 24 * 3600
+# Used for deprecation and removal of `loop.create_datagram_endpoint()`'s
+# *reuse_address* parameter
+_unset = object()
+
def _format_handle(handle):
cb = handle._callback
@@ -1201,7 +1205,7 @@ class BaseEventLoop(events.AbstractEventLoop):
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):
"""Create datagram connection."""
if sock is not None:
@@ -1210,7 +1214,7 @@ class BaseEventLoop(events.AbstractEventLoop):
f'A UDP Socket was expected, got {sock!r}')
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,
@@ -1277,8 +1281,18 @@ class BaseEventLoop(events.AbstractEventLoop):
exceptions = []
- if reuse_address is None:
- reuse_address = os.name == 'posix' and sys.platform != 'cygwin'
+ # bpo-37228
+ 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 3.5.10 and is scheduled "
+ "for removal in 3.11.", DeprecationWarning,
+ stacklevel=2)
for ((family, proto),
(local_address, remote_address)) in addr_pairs_info:
@@ -1287,9 +1301,6 @@ class BaseEventLoop(events.AbstractEventLoop):
try:
sock = socket.socket(
family=family, type=socket.SOCK_DGRAM, proto=proto)
- if reuse_address:
- sock.setsockopt(
- socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if reuse_port:
_set_reuseport(sock)
if allow_broadcast:
diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py
index 92fdaf1..3a23059 100644
--- a/Lib/test/test_asyncio/test_base_events.py
+++ b/Lib/test/test_asyncio/test_base_events.py
@@ -1733,10 +1733,6 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
self.assertRaises(ValueError, self.loop.run_until_complete, fut)
fut = self.loop.create_datagram_endpoint(
- MyDatagramProto, reuse_address=True, sock=FakeSock())
- self.assertRaises(ValueError, self.loop.run_until_complete, fut)
-
- fut = self.loop.create_datagram_endpoint(
MyDatagramProto, reuse_port=True, sock=FakeSock())
self.assertRaises(ValueError, self.loop.run_until_complete, fut)
@@ -1746,7 +1742,6 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
def test_create_datagram_endpoint_sockopts(self):
# Socket options should not be applied unless asked for.
- # SO_REUSEADDR defaults to on for UNIX.
# SO_REUSEPORT is not available on all platforms.
coro = self.loop.create_datagram_endpoint(
@@ -1755,18 +1750,8 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
transport, protocol = self.loop.run_until_complete(coro)
sock = transport.get_extra_info('socket')
- reuse_address_default_on = (
- os.name == 'posix' and sys.platform != 'cygwin')
reuseport_supported = hasattr(socket, 'SO_REUSEPORT')
- if reuse_address_default_on:
- self.assertTrue(
- sock.getsockopt(
- socket.SOL_SOCKET, socket.SO_REUSEADDR))
- else:
- self.assertFalse(
- sock.getsockopt(
- socket.SOL_SOCKET, socket.SO_REUSEADDR))
if reuseport_supported:
self.assertFalse(
sock.getsockopt(
@@ -1782,13 +1767,12 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
coro = self.loop.create_datagram_endpoint(
lambda: MyDatagramProto(create_future=True, loop=self.loop),
local_addr=('127.0.0.1', 0),
- reuse_address=True,
reuse_port=reuseport_supported,
allow_broadcast=True)
transport, protocol = self.loop.run_until_complete(coro)
sock = transport.get_extra_info('socket')
- self.assertTrue(
+ self.assertFalse(
sock.getsockopt(
socket.SOL_SOCKET, socket.SO_REUSEADDR))
if reuseport_supported:
@@ -1803,6 +1787,29 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase):
self.loop.run_until_complete(protocol.done)
self.assertEqual('CLOSED', protocol.state)
+ 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
+
+ coro = self.loop.create_datagram_endpoint(
+ lambda: MyDatagramProto(create_future=True, 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
+
+ coro = self.loop.create_datagram_endpoint(
+ lambda: MyDatagramProto(create_future=True, loop=self.loop),
+ local_addr=('127.0.0.1', 0),
+ reuse_address=False)
+
+ with self.assertWarns(DeprecationWarning):
+ self.loop.run_until_complete(coro)
+
@patch_socket
def test_create_datagram_endpoint_nosoreuseport(self, m_socket):
del m_socket.SO_REUSEPORT