This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: AsyncIO V4MAPPED addresses with V6ONLY.
Type: Stage:
Components: asyncio Versions:
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: asvetlov, giampaolo.rodola, jeeger, vstinner, yselivanov
Priority: normal Keywords:

Created on 2019-03-06 10:34 by jeeger, last changed 2022-04-11 14:59 by admin.

Files
File name Uploaded Description Edit
socket_test_bad.py jeeger, 2019-03-06 10:34 Program that shows error.
bugtest.py jeeger, 2019-03-06 13:12
Messages (4)
msg337289 - (view) Author: Jan Seeger (jeeger) Date: 2019-03-06 10:34
I'm working with aiocoap, which uses the AI_V4MAPPED flag to use IPv4-mapped addresses for dual-stack support. When trying to run on Windows, creating a connection fails, because the socket option IPV6_V6ONLY is set to true per default on Windows, whereas the value is configurable on Linux. I've attached a file that should reproduce the error.

A possible fix would be calling socket.setsockopt(socket.IPPROTO_IPV6,
socket.IPV6_V6ONLY, False) when V4-mapped addresses have been requested
(this bug can also appear on Linux when /proc/sys/net/ipv6/bindv6only
contains 1).

If you require any more information, feel free to contact me!
msg337291 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-03-06 11:16
See also bpo-35934.
msg337297 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2019-03-06 12:54
I'm not sure I understand the issue, but setting IPV6_V6ONLY to 0 by default is not an option because asyncio wants to serve IPv4 and IPv6 with 2 distinct sockets on purpose. The reason for that is because when an IPv4 connection occurs we want getpeername/getsockname to return '127.0.0.1' instead of '::ffff:127.0.0.1'.

Also, IPV6_V6ONLY = 1 is set by default on all platforms. It is not set on Windows because IPPROTO_IPV6 constant is missing due to issue29515, but that doesn't matter because IPV6_V6ONLY = 1 is already the default on Windows. As for Linux, /proc/sys/net/ipv6/bindv6only shouldn't matter because setting the option in Python is supposed to overwrite what /proc/sys/net/ipv6/bindv6only dictates.

With that said, what's your use case exactly? Why does your test script uses AF_INET6 and an IPv4 address?
msg337299 - (view) Author: Jan Seeger (jeeger) Date: 2019-03-06 13:12
The intention for V4MAPPED is to allow "single-stack" usage of V4 and V6 addresses (or am I misunderstanding the purpose of the V4MAPPED socket option here?). The application only handles V6 addresses, and the system transparently converts from mapped addresses to "proper" IPv4 addresses.

Unfortunately, when V6ONLY is set on a socket, this does not work. `man ipv6` states:

       IPV6_V6ONLY (since Linux 2.4.21 and 2.6)
              If this flag is set to false (zero), then the socket can be
              used to send and receive packets to and from an IPv6 address
              or an IPv4-mapped IPv6 address.

If IPV6_V6ONLY is always set, the V4MAPPED socket option is nonsensical, as the socket can't send IPv4 packages.

This is what the test_bad script is trying to simulate (badly☺): The lookup for neverssl.com returns only an IPv4 address (since the running system doesn't have IPv6 connectivity). If V6ONLY was 0, this would work, and we would get a mapped V4 address (something like '::ffff:52.222.163.80'). With V6ONLY=1, we cannot connect to this mapped address.

A better test script would have this main method (I've attached the new version as well):

async def main():
    on_con_lost = asyncio.Future()
    transport, protocol = await asyncio.get_event_loop().create_connection(
        lambda: TestProtocol(on_con_lost),
        family=socket.AF_INET6,
        flags=socket.AI_V4MAPPED,
        host='neverssl.com',
        port=80)

    try:
        await on_con_lost
    finally:
        transport.close()

On my system, the lookup returns a V4 address. Since I've enabled AI_V4MAPPED, I get a mapped V6 address that I would be able to connect to if V6ONLY is disabled. However, with V6ONLY enabled, the address is not connectable.
History
Date User Action Args
2022-04-11 14:59:12adminsetgithub: 80389
2019-03-06 13:12:28jeegersetfiles: + bugtest.py

messages: + msg337299
2019-03-06 12:54:39giampaolo.rodolasetmessages: + msg337297
2019-03-06 11:16:23vstinnersetnosy: + vstinner, giampaolo.rodola
messages: + msg337291
2019-03-06 10:34:18jeegercreate