Skip to content

Commit 59ea704

Browse files
hugovkambv
andauthored
bpo-45129 Remove deprecated reuse_address (GH-28207)
Due to significant security concerns, the reuse_address parameter of asyncio.loop.create_datagram_endpoint, deprecated in Python 3.9, is now removed. This is because of the behavior of the socket option SO_REUSEADDR in UDP. Co-authored-by: Łukasz Langa <[email protected]>
1 parent a561005 commit 59ea704

File tree

5 files changed

+33
-70
lines changed

5 files changed

+33
-70
lines changed

Doc/library/asyncio-eventloop.rst

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -493,24 +493,9 @@ Opening network connections
493493
.. coroutinemethod:: loop.create_datagram_endpoint(protocol_factory, \
494494
local_addr=None, remote_addr=None, *, \
495495
family=0, proto=0, flags=0, \
496-
reuse_address=None, reuse_port=None, \
496+
reuse_port=None, \
497497
allow_broadcast=None, sock=None)
498498
499-
.. note::
500-
The parameter *reuse_address* is no longer supported, as using
501-
:py:data:`~sockets.SO_REUSEADDR` poses a significant security concern for
502-
UDP. Explicitly passing ``reuse_address=True`` will raise an exception.
503-
504-
When multiple processes with differing UIDs assign sockets to an
505-
identical UDP socket address with ``SO_REUSEADDR``, incoming packets can
506-
become randomly distributed among the sockets.
507-
508-
For supported platforms, *reuse_port* can be used as a replacement for
509-
similar functionality. With *reuse_port*,
510-
:py:data:`~sockets.SO_REUSEPORT` is used instead, which specifically
511-
prevents processes with differing UIDs from assigning sockets to the same
512-
socket address.
513-
514499
Create a datagram connection.
515500

516501
The socket family can be either :py:data:`~socket.AF_INET`,
@@ -557,16 +542,31 @@ Opening network connections
557542
:ref:`UDP echo server protocol <asyncio-udp-echo-server-protocol>` examples.
558543

559544
.. versionchanged:: 3.4.4
560-
The *family*, *proto*, *flags*, *reuse_address*, *reuse_port,
545+
The *family*, *proto*, *flags*, *reuse_address*, *reuse_port*,
561546
*allow_broadcast*, and *sock* parameters were added.
562547

563548
.. versionchanged:: 3.8.1
564-
The *reuse_address* parameter is no longer supported due to security
565-
concerns.
549+
The *reuse_address* parameter is no longer supported, as using
550+
:py:data:`~sockets.SO_REUSEADDR` poses a significant security concern for
551+
UDP. Explicitly passing ``reuse_address=True`` will raise an exception.
552+
553+
When multiple processes with differing UIDs assign sockets to an
554+
identical UDP socket address with ``SO_REUSEADDR``, incoming packets can
555+
become randomly distributed among the sockets.
556+
557+
For supported platforms, *reuse_port* can be used as a replacement for
558+
similar functionality. With *reuse_port*,
559+
:py:data:`~sockets.SO_REUSEPORT` is used instead, which specifically
560+
prevents processes with differing UIDs from assigning sockets to the same
561+
socket address.
566562

567563
.. versionchanged:: 3.8
568564
Added support for Windows.
569565

566+
.. versionchanged:: 3.11
567+
The *reuse_address* parameter, disabled since Python 3.9.0, 3.8.1,
568+
3.7.6 and 3.6.10, has been entirely removed.
569+
570570
.. coroutinemethod:: loop.create_unix_connection(protocol_factory, \
571571
path=None, *, ssl=None, sock=None, \
572572
server_hostname=None, ssl_handshake_timeout=None)

Doc/whatsnew/3.11.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,12 @@ Removed
254254
Use ``bdist_wheel`` (wheel packages) instead.
255255
(Contributed by Hugo van Kemenade in :issue:`45124`.)
256256

257+
* Due to significant security concerns, the *reuse_address* parameter of
258+
:meth:`asyncio.loop.create_datagram_endpoint`, disabled in Python 3.9, is
259+
now entirely removed. This is because of the behavior of the socket option
260+
``SO_REUSEADDR`` in UDP.
261+
(Contributed by Hugo van Kemenade in :issue:`45129`.)
262+
257263
* Remove :meth:`__getitem__` methods of
258264
:class:`xml.dom.pulldom.DOMEventStream`, :class:`wsgiref.util.FileWrapper`
259265
and :class:`fileinput.FileInput`, deprecated since Python 3.9.

Lib/asyncio/base_events.py

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,6 @@
6666
# Maximum timeout passed to select to avoid OS limitations
6767
MAXIMUM_SELECT_TIMEOUT = 24 * 3600
6868

69-
# Used for deprecation and removal of `loop.create_datagram_endpoint()`'s
70-
# *reuse_address* parameter
71-
_unset = object()
72-
7369

7470
def _format_handle(handle):
7571
cb = handle._callback
@@ -1235,7 +1231,7 @@ async def start_tls(self, transport, protocol, sslcontext, *,
12351231
async def create_datagram_endpoint(self, protocol_factory,
12361232
local_addr=None, remote_addr=None, *,
12371233
family=0, proto=0, flags=0,
1238-
reuse_address=_unset, reuse_port=None,
1234+
reuse_port=None,
12391235
allow_broadcast=None, sock=None):
12401236
"""Create datagram connection."""
12411237
if sock is not None:
@@ -1248,7 +1244,7 @@ async def create_datagram_endpoint(self, protocol_factory,
12481244
# show the problematic kwargs in exception msg
12491245
opts = dict(local_addr=local_addr, remote_addr=remote_addr,
12501246
family=family, proto=proto, flags=flags,
1251-
reuse_address=reuse_address, reuse_port=reuse_port,
1247+
reuse_port=reuse_port,
12521248
allow_broadcast=allow_broadcast)
12531249
problems = ', '.join(f'{k}={v}' for k, v in opts.items() if v)
12541250
raise ValueError(
@@ -1311,19 +1307,6 @@ async def create_datagram_endpoint(self, protocol_factory,
13111307

13121308
exceptions = []
13131309

1314-
# bpo-37228
1315-
if reuse_address is not _unset:
1316-
if reuse_address:
1317-
raise ValueError("Passing `reuse_address=True` is no "
1318-
"longer supported, as the usage of "
1319-
"SO_REUSEPORT in UDP poses a significant "
1320-
"security concern.")
1321-
else:
1322-
warnings.warn("The *reuse_address* parameter has been "
1323-
"deprecated as of 3.5.10 and is scheduled "
1324-
"for removal in 3.11.", DeprecationWarning,
1325-
stacklevel=2)
1326-
13271310
for ((family, proto),
13281311
(local_address, remote_address)) in addr_pairs_info:
13291312
sock = None
@@ -1407,7 +1390,6 @@ async def create_server(
14071390
sock=None,
14081391
backlog=100,
14091392
ssl=None,
1410-
reuse_address=None,
14111393
reuse_port=None,
14121394
ssl_handshake_timeout=None,
14131395
start_serving=True):
@@ -1438,8 +1420,6 @@ async def create_server(
14381420
raise ValueError(
14391421
'host/port and sock can not be specified at the same time')
14401422

1441-
if reuse_address is None:
1442-
reuse_address = os.name == 'posix' and sys.platform != 'cygwin'
14431423
sockets = []
14441424
if host == '':
14451425
hosts = [None]
@@ -1469,9 +1449,6 @@ async def create_server(
14691449
af, socktype, proto, exc_info=True)
14701450
continue
14711451
sockets.append(sock)
1472-
if reuse_address:
1473-
sock.setsockopt(
1474-
socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
14751452
if reuse_port:
14761453
_set_reuseport(sock)
14771454
# Disable IPv4/IPv6 dual stack support (enabled by

Lib/test/test_asyncio/test_base_events.py

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,32 +1794,6 @@ def test_create_datagram_endpoint_sockopts(self):
17941794
self.loop.run_until_complete(protocol.done)
17951795
self.assertEqual('CLOSED', protocol.state)
17961796

1797-
def test_create_datagram_endpoint_reuse_address_error(self):
1798-
# bpo-37228: Ensure that explicit passing of `reuse_address=True`
1799-
# raises an error, as it is not safe to use SO_REUSEADDR when using UDP
1800-
1801-
coro = self.loop.create_datagram_endpoint(
1802-
lambda: MyDatagramProto(create_future=True, loop=self.loop),
1803-
local_addr=('127.0.0.1', 0),
1804-
reuse_address=True)
1805-
1806-
with self.assertRaises(ValueError):
1807-
self.loop.run_until_complete(coro)
1808-
1809-
def test_create_datagram_endpoint_reuse_address_warning(self):
1810-
# bpo-37228: Deprecate *reuse_address* parameter
1811-
1812-
coro = self.loop.create_datagram_endpoint(
1813-
lambda: MyDatagramProto(create_future=True, loop=self.loop),
1814-
local_addr=('127.0.0.1', 0),
1815-
reuse_address=False)
1816-
1817-
with self.assertWarns(DeprecationWarning):
1818-
transport, protocol = self.loop.run_until_complete(coro)
1819-
transport.close()
1820-
self.loop.run_until_complete(protocol.done)
1821-
self.assertEqual('CLOSED', protocol.state)
1822-
18231797
@patch_socket
18241798
def test_create_datagram_endpoint_nosoreuseport(self, m_socket):
18251799
del m_socket.SO_REUSEPORT
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Due to significant security concerns, the *reuse_address* parameter of
2+
:meth:`asyncio.loop.create_datagram_endpoint`, disabled in Python 3.9, is
3+
now entirely removed. This is because of the behavior of the socket option
4+
``SO_REUSEADDR`` in UDP.
5+
6+
Patch by Hugo van Kemenade.

0 commit comments

Comments
 (0)