[Bug 265064] connect(2): unexpected EADDRINUSE when connecting from IPv6 wildcard to IPv4 address

From: <bugzilla-noreply_at_freebsd.org>
Date: Wed, 06 Jul 2022 15:06:03 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=265064

            Bug ID: 265064
           Summary: connect(2): unexpected EADDRINUSE when connecting from
                    IPv6 wildcard to IPv4 address
           Product: Base System
           Version: Unspecified
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: kern
          Assignee: net@FreeBSD.org
          Reporter: dmgk@freebsd.org

I'm trying to get to the bottom of the Go issue reported in [1] and noticed
some differences in the bind(2)/connect(2) behavior between IPv4/IPv6 and
IPv4-mapped addresses. I wrote a small C reproducer [2] to isolate the issue.

When the available port range is exhausted, both IPv4->IPv4 and IPv6->IPv6
clients fail to bind(2) with EADDRNOTAVAIL, which is expected:

$ sysctl net.inet.ip.portrange.first=10000
$ sysctl net.inet.ip.portrange.last=10001
$ ./localdial -4
server4: listening on 0.0.0.0:10001
server6: listening on :::10001
client4: connecting          0.0.0.0:0     -> 127.0.0.1:10001
client4: connected         127.0.0.1:10000 -> 127.0.0.1:10001
server4: accepted          127.0.0.1:10000 ->   0.0.0.0:10001
client4: connecting          0.0.0.0:0     -> 127.0.0.1:10001
localdial: client4: bind: Can't assign requested address
$ ./localdial -6
server4: listening on 0.0.0.0:10001
server6: listening on :::10001
client6: connecting               :::0     ->       ::1:10001
client6: connected               ::1:10000 ->       ::1:10001
client6: connecting               :::0     ->       ::1:10001
server6: accepted                ::1:10000 ->        :::10001
localdial: client6: bind: Can't assign requested address

With IPv4-mapped address, the behavior is different:

$ sysctl net.inet.ip.portrange.first=10000
$ sysctl net.inet.ip.portrange.last=10001
$ ./localdial -M
server4: listening on 0.0.0.0:10001
server6: listening on :::10001
client6: connecting               :::0     -> ::ffff:127.0.0.1:10001
client6: connected  ::ffff:127.0.0.1:10000 -> ::ffff:127.0.0.1:10001
server4: accepted          127.0.0.1:10000 ->   0.0.0.0:10001
client6: connecting               :::0     -> ::ffff:127.0.0.1:10001
client6: connected  ::ffff:127.0.0.1:10000 -> ::ffff:127.0.0.1:10001
server4: accepted          127.0.0.1:10000 ->   0.0.0.0:10001
client6: connecting               :::0     -> ::ffff:127.0.0.1:10001
localdial: client6: connect: Address already in use

Here, the client successfully does bind(2) but then fails at connect(2) with
EADDRINUSE, which looks surprising. This seems to confuse the Go testing suite
and leads to [1].

Is this an expected/known issue? Reproducible on all FreeBSD versions from
12.3-RELEASE to 14.0-CURRENT.

[1] https://github.com/golang/go/issues/34264
[2] https://github.com/dmgk/localdial

-- 
You are receiving this mail because:
You are the assignee for the bug.