New submission from Максим Аристов <aristov...@gmail.com>:
loop.create_connection doesn't handle ipv6 RFC4007 addresses right since 3.7 TEST CASE # Set up listener on link-local address fe80::1%lo sudo ip a add dev lo fe80::1 # 3.6 handles everything fine socat file:/dev/null tcp6-listen:12345,REUSEADDR & python3.6 -c 'import asyncio;loop=asyncio.get_event_loop();loop.run_until_complete(loop.create_connection(lambda:asyncio.Protocol(),host="fe80::1%lo",port="12345"))' # 3.7 and later fails socat file:/dev/null tcp6-listen:12345,REUSEADDR & python3.7 -c 'import asyncio;loop=asyncio.get_event_loop();loop.run_until_complete(loop.create_connection(lambda:asyncio.Protocol(),host="fe80::1%lo",port="12345"))' Traceback (most recent call last): File "<string>", line 1, in <module> File "/usr/lib/python3.7/asyncio/base_events.py", line 576, in run_until_complete return future.result() File "/usr/lib/python3.7/asyncio/base_events.py", line 951, in create_connection raise exceptions[0] File "/usr/lib/python3.7/asyncio/base_events.py", line 938, in create_connection await self.sock_connect(sock, address) File "/usr/lib/python3.7/asyncio/selector_events.py", line 475, in sock_connect return await fut File "/usr/lib/python3.7/asyncio/selector_events.py", line 480, in _sock_connect sock.connect(address) OSError: [Errno 22] Invalid argument CAUSE Upon asyncio.base_events.create_connection _ensure_resolved is called twice, first time here: https://github.com/python/cpython/blob/3.7/Lib/asyncio/base_events.py#L908 then here through sock_connect: https://github.com/python/cpython/blob/3.7/Lib/asyncio/base_events.py#L946 https://github.com/python/cpython/blob/3.7/Lib/asyncio/selector_events.py#L458 _ensure_resolved calls getaddrinfo, but in 3.7 implementation changed: % python3.6 -c 'import socket;print(socket.getaddrinfo("fe80::1%lo",12345)[0][4])' ('fe80::1%lo', 12345, 0, 1) % python3.7 -c 'import socket;print(socket.getaddrinfo("fe80::1%lo",12345)[0][4])' ('fe80::1', 12345, 0, 1) _ensure_connect only considers host and port parts of the address tuple: https://github.com/python/cpython/blob/3.7/Lib/asyncio/base_events.py#L1272 In case of 3.7 first call to _ensure_resolved returns ('fe80::1', 12345, 0, 1) then second call returns ('fe80::1', 12345, 0, 0) Notice that scope is now completely lost and is set to 0, thus actual call to socket.connect is wrong In case of 3.6 both first and second call to _ensure_resolved return ('fe80::1%lo', 12345, 0, 1) because in 3.6 case scope info is preserved in address and second call can derive correct address tuple ---------- components: asyncio messages: 332211 nosy: asvetlov, yselivanov, Максим Аристов priority: normal severity: normal status: open title: asyncio.base_events.create_connection doesn't handle scoped IPv6 addresses type: behavior versions: Python 3.7, Python 3.8 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue35545> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com