Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AsyncIO V4MAPPED addresses with V6ONLY. #80389

Open
jeeger mannequin opened this issue Mar 6, 2019 · 4 comments
Open

AsyncIO V4MAPPED addresses with V6ONLY. #80389

jeeger mannequin opened this issue Mar 6, 2019 · 4 comments

Comments

@jeeger
Copy link
Mannequin

jeeger mannequin commented Mar 6, 2019

BPO 36208
Nosy @vstinner, @giampaolo, @asvetlov, @1st1, @jeeger
Files
  • socket_test_bad.py: Program that shows error.
  • bugtest.py
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2019-03-06.10:34:18.100>
    labels = ['expert-asyncio']
    title = 'AsyncIO V4MAPPED addresses with V6ONLY.'
    updated_at = <Date 2019-03-06.13:12:28.629>
    user = 'https://github.com/jeeger'

    bugs.python.org fields:

    activity = <Date 2019-03-06.13:12:28.629>
    actor = 'jeeger'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['asyncio']
    creation = <Date 2019-03-06.10:34:18.100>
    creator = 'jeeger'
    dependencies = []
    files = ['48190', '48191']
    hgrepos = []
    issue_num = 36208
    keywords = []
    message_count = 4.0
    messages = ['337289', '337291', '337297', '337299']
    nosy_count = 5.0
    nosy_names = ['vstinner', 'giampaolo.rodola', 'asvetlov', 'yselivanov', 'jeeger']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = None
    status = 'open'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue36208'
    versions = []

    @jeeger
    Copy link
    Mannequin Author

    jeeger mannequin commented Mar 6, 2019

    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!

    @jeeger jeeger mannequin added the topic-asyncio label Mar 6, 2019
    @vstinner
    Copy link
    Member

    vstinner commented Mar 6, 2019

    See also bpo-35934.

    @giampaolo
    Copy link
    Contributor

    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 bpo-29515, 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?

    @jeeger
    Copy link
    Mannequin Author

    jeeger mannequin commented Mar 6, 2019

    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.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    Status: Todo
    Development

    No branches or pull requests

    2 participants