X Tutup
The Wayback Machine - https://web.archive.org/web/20230119202837/https://github.com/python/cpython/issues/79483
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

create_connection with local_addr misses valid socket bindings #79483

Open
kyuupichan mannequin opened this issue Nov 23, 2018 · 5 comments
Open

create_connection with local_addr misses valid socket bindings #79483

kyuupichan mannequin opened this issue Nov 23, 2018 · 5 comments
Labels
expert-asyncio type-bug An unexpected behavior, bug, or error

Comments

@kyuupichan
Copy link
Mannequin

kyuupichan mannequin commented Nov 23, 2018

BPO 35302
Nosy @ronaldoussoren, @asvetlov, @1st1, @kyuupichan, @twisteroidambassador
PRs
  • bpo-35302: Try each (remote addrinfo, local addrinfo) pair when connecting. #11241
  • 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 2018-11-23.18:30:53.167>
    labels = ['type-bug', '3.7', 'expert-asyncio']
    title = 'create_connection with local_addr misses valid socket bindings'
    updated_at = <Date 2018-12-20.13:02:23.769>
    user = 'https://github.com/kyuupichan'

    bugs.python.org fields:

    activity = <Date 2018-12-20.13:02:23.769>
    actor = 'twisteroid ambassador'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['asyncio']
    creation = <Date 2018-11-23.18:30:53.167>
    creator = 'kyuupichan'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 35302
    keywords = ['patch']
    message_count = 4.0
    messages = ['330354', '332136', '332147', '332224']
    nosy_count = 5.0
    nosy_names = ['ronaldoussoren', 'asvetlov', 'yselivanov', 'kyuupichan', 'twisteroid ambassador']
    pr_nums = ['11241']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue35302'
    versions = ['Python 3.5', 'Python 3.6', 'Python 3.7']

    @kyuupichan
    Copy link
    Mannequin Author

    kyuupichan mannequin commented Nov 23, 2018

    I run a machine with IPv4 and IPv6 interfaces on MacOSX Mojave.

    I try to loop.create_connection() to a remote machine whose domain resolves to an IPv6 address only, with a local_addr domain name argument that resolves to two local addresses: an IPv4 one first and an IPv6 one second.

    The loop https://github.com/python/cpython/blob/master/Lib/asyncio/base_events.py#L927-L943 that loops through the local addresses, IPv4 then IPv6, successfully binds the IPv4 laddr_info to the IPv6 socket successfully (something I find surprising) and then the connection attempt fails with OSError(65, 'No route to host'), at which point the sockets is closed and the IPv6 laddr_info is never tried and the connection attempt fails.

    If I reverse the order of the loop so that the IPv6 laddr_info is tried first then the connection succeeds.

    I suggest either all laddr_info bindings should be tried for each outer loop of infos, rather than just 1, or that those of a different socket "type" (IPv4 vs IPv6) should be skipped in the inner loop before attempting a binding.

    @kyuupichan kyuupichan mannequin added 3.7 expert-asyncio type-bug An unexpected behavior, bug, or error labels Nov 23, 2018
    @twisteroidambassador
    Copy link
    Mannequin

    twisteroidambassador mannequin commented Dec 19, 2018

    IMO macOS is at fault here, for even allowing an IPv6 socket to bind to an IPv4 address. ;-)

    I have given some thought about this issue when writing my happy eyeballs library. My current solution is closest to Neil's first suggestion, i.e. each pair of remote addrinfo and local addrinfo is tried in a connection attempt.

    @ronaldoussoren
    Copy link
    Contributor

    A better workaround is IMHO to force the socket to be IPV6 only:

    sd = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0)
    sd.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)

    That avoids the ordering problem as well as having to try all possible combinations of source and destination addreses.

    I've tested that setting this option makes it impossible to bind a IPv6 socket to an IPv4 address. This is on macOS 10.14.2, I haven't checked other versions of macOS.

    @twisteroidambassador
    Copy link
    Mannequin

    twisteroidambassador mannequin commented Dec 20, 2018

    I don't have a Mac, so I have not tested Ronald's workaround. Assuming it works, we will have to either i) implement platform-specific behavior and only apply IPV6_V6ONLY on macOS for each AF_INET6 socket created, or ii) apply it to all AF_INET6 sockets on all platforms, ideally after testing the option on all these platforms to make sure it doesn't have any undesirable side effect.

    Linux's man page of ipv6 (http://man7.org/linux/man-pages/man7/ipv6.7.html ) has this to say about IPV6_V6ONLY:

    If this flag is set to true (nonzero), then the socket is re‐
    stricted to sending and receiving IPv6 packets only. In this
    case, an IPv4 and an IPv6 application can bind to a single
    port at the same time.

    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.

    So setting IPV6_V6ONLY might break some use cases? I have no idea how prevalent that may be.

    The upside of this solution, as well as the second suggestion in Neil's OP (filter out local addrinfos with mismatching family), is that they should not increase connect time for normal cases. My solution (for which I have already submitted a PR) probably has a negligible increase in connection time and resource usage, because a fresh socket object is created for each pair of remote and local addrinfo.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    @kumaraditya303
    Copy link
    Contributor

    Seems this is fixed by #86508 but needs to be tested on a mac.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    expert-asyncio type-bug An unexpected behavior, bug, or error
    Projects
    Status: Todo
    Development

    No branches or pull requests

    2 participants
    X Tutup