-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
proposal: net/v2: Listen is unfriendly to multiple address families, endpoints and subflows #9334
Comments
/cc @mikioh |
The correct way to listen for both tcp4 and tcp6 is to leave out the Will listen on tcp6 if it's dual-stack system. I don't think net.Listen should automatically create multiple listener for For example, what if the machine added another network interface and another |
That's not entirely accurate. There do exist dual-stack systems which don't support dual-stack sockets, so AF_INET and AF_INET6 must be kept separate. In that case,
If |
What should happen if more IPs are added to a hostname? Should No matter what we do, I think the behavior will surprise some users. Also, what do you think should the Listener's Addr() method return IMHO, the existing documentation actually precludes listening on I always think supporting hostname in Listen is just a convenience, |
I don't have a good answer, and that's the fundamental flaw I was referring to. Since there's nothing sane for
Perhaps have a type that stores a resolved AddressSet, and another type that holds the listening sockets, where you can Read the AddressSet (to see which sockets exist) or Write it (to open new sockets and close obsolete ones). Then sufficiently-crazy users could resolve multiple hostnames, merge the results together, and dynamically update the pool of sockets without interrupting existing listeners. But I don't care strongly about the dynamic stuff; I just think listening on localhost or ::+0.0.0.0 should be easy. The problem is that net.Listen() is easy, popular, and wrong. The alternative (keeping track of multiple listening sockets, with dual-stack behavior that varies by OS) is so much more involved that people avoid doing the right thing, and IPv6 compatibility suffers as a result. |
I wouldn't call the current net.Listen wrong. It just can't handle every See also #8124, which has more in-depth discussion of the prefer-IPv4 issue. |
I encountered the same question when working on a C networking library, and the solution was to funnel the IPV6_V6ONLY calls through a function with a test-only flag that emulates an OS without dualstack sockets: /* Returns 1 on success (dual-stack), 0 on failure (single-stack). */
static int set_socket_dualstack(int fd) {
if (!forbid_dualstack_sockets_for_testing) {
const int off = 0;
return 0 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off));
} else {
/* Force an IPv6-only socket, for testing purposes. */
const int on = 1;
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
return 0;
}
} Granted, a flag is a bit unsightly, but it's an easy way to ensure coverage of the
I don't agree with that defeatist position; When a standard library exposes hostname-based socket interfaces, it's the library's responsibility to follow best practices, instead of taking shortcuts. "one hostname ⇒ one socket" is a shortcut that's not obvious to users of the library, but which seems harmful to the networking ecosystem. Pretending that no code had yet been written, I don't think a |
We perhaps need to support this eventually. In that case the new stuff should support not only for dual-stack TCP listeners but for SCTP, MPTCP listeners. Random thoughts on API:
Random thoughts on testing:
Random thoughts on roadmap:
References: PS: Moreover, I'd want to see what happens with the IP Stack Evolution Program: http://www.ietf.org/proceedings/91/slides/slides-91-iab-techplenary-6.pdf |
Is this related issue? #7598 |
No, #7598 is a simple, Windows-specific investigation; how Windows dual IP stacks behave when we use it. |
CL https://golang.org/cl/31931 mentions this issue. |
In general, these functions cannot behave correctly when given a hostname, because a hostname may represent multiple IP addresses, and first(isIPv4) chooses at most one. Updates #9334 Change-Id: Icfb629f84af4d976476385a3071270253c0000b1 Reviewed-on: https://go-review.googlesource.com/31931 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
As noted [here](golang/go#9334 (comment)), the "correct way" to listen on both IPv4 and IPv6 loopback interfaces is to omit the address part. Closes: #2 And will also close: wincent/vim-clipper#1
I don't expect to tilt the scales much compared to the very impressive selection of open source projects that appear to have run into this, but add my vote to the pile in favor of allowing binding on a hostname or on a network interface name to listen to all associated IPs. It shouldn't be so hard to listen on both an IPv4 and IPv6 address associated with a given hostname (without listening on all interfaces). |
are there any updates on this issue? 8 years now. |
Do you have any examples of networking stdlibs that behave this way? I agree that the proposed behavior would be an improvement, but unfortunately Node.js doesn't have it either for example:
nor does Python:
In Rust, the only HTTP server I can find which accepts hostname is Iron, which also resolves only to one interface:
|
The following example program:
Currently yields this result:
While the following result would be optimal:
(Note that the first socket is actually dualstack, and bound to ::ffff:127.0.0.1, but that's less critical than adding the second socket bound to ::1.)
More generally, when you call
net.Listen()
on a hostname which resolves to multiple IPv4/IPv6 addresses, only the first IPv4 address is selected. An analogous problem occurs if youListen("tcp", ":8080")
on an operating system that doesn't support dualstack sockets: instead of returning a pair of sockets bound to[::]:8080
and0.0.0.0:80
, you only get IPv4.The fundamental flaw is that
Listen()
assumes a single socket, which is a leaky abstraction that's inappropriate for high-level things like example servers, e.g.:http://golang.org/pkg/net/#pkg-overview
Go should either adapt the
Listen()
API to support multiple sockets, or if that's not feasible, a new multi-socket API should be introduced, which deprecatesListen()
for all cases except simple non-wildcard addresses.The text was updated successfully, but these errors were encountered: