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

net: EADDRINUSE when binding both IPv4 and IPv6 all addresses on Linux #7200

Closed
silverwind opened this issue Jun 7, 2016 · 7 comments
Closed
Labels
net Issues and PRs related to the net subsystem.

Comments

@silverwind
Copy link
Contributor

silverwind commented Jun 7, 2016

On a IPv6 enabled Linux machine, I observe certain daemons being able to bind on all v4 and v6 interfaces on a single pid, like sshd (output of ss -tnlp):

State       Recv-Q Send-Q    Local Address:Port   Peer Address:Port
LISTEN      0      128       :::22                :::*
LISTEN      0      128       *:22                 *:*

Trying to replicate the same in node, the second .listen always seems to fail:

net.Server().listen(12345, '::') // correctly binds to `:::12345`
net.Server().listen(12345, '0.0.0.0') // EADDRINUSE

Observed on Linux 3.16.0 and 4.4.12. It works on OS X, by the way.

@silverwind silverwind added the net Issues and PRs related to the net subsystem. label Jun 7, 2016
@bnoordhuis
Copy link
Member

That's because libuv uses dual-stack mode by default, i.e., the IPv6 socket listens on :: and 0.0.0.0.

Libuv supports IPv6-only mode but node doesn't expose it. If you apply the patch below, your example should work:

diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc
index 6904b27..1618493 100644
--- a/src/tcp_wrap.cc
+++ b/src/tcp_wrap.cc
@@ -239,7 +239,7 @@ void TCPWrap::Bind6(const FunctionCallbackInfo<Value>& args) {
   if (err == 0) {
     err = uv_tcp_bind(&wrap->handle_,
                       reinterpret_cast<const sockaddr*>(&addr),
-                      0);
+                      UV_TCP_IPV6ONLY);
   }
   args.GetReturnValue().Set(err);
 }

@silverwind
Copy link
Contributor Author

silverwind commented Jun 7, 2016

Thanks!

So would you say that the output of ss/netstat is in error and it really is listening on both protocols in dual stack mode? E.g. :: just gives me the :::12345 listener and 0.0.0.0 gives *:12345, but never both at the same time like sshd above.

@silverwind
Copy link
Contributor Author

silverwind commented Jun 7, 2016

So to clarify the current behaviour:

  • Listening on :: results in v4 and v6 listening (dual-stack), ss displaying only the v6-style listener.
  • Listening on 0.0.0.0 results in just v4 listening, ss correctly shows just the v4-style listener.

This dual-stack behaviour looks to only apply to Linux. On OS X and Windows, I can bind :: and 0.0.0.0 simultaneously.

Would it be feasible to disable dual-stack mode if an explicit IPv6 style address is given to .listen?

@bnoordhuis
Copy link
Member

Would it be feasible to disable dual-stack mode if an explicit IPv6 style address is given to .listen?

Yes, the patch I posted would do that, but it might be contrary to what Linux users would expect.

@silverwind
Copy link
Contributor Author

I'm fine with .listen(PORT) resulting in dual stack. It's just the explicit .listen(PORT, '::'), where :: is a common alias for "all IPv6 addresses", which I'd like to change to only listen on IPv6, as that's what I'd expect.

@AdamMajer
Copy link
Contributor

You can also change this default behaviour with

/proc/sys/net/ipv6/bindv6only

By default, this is 0, which means it binds to both IPv4 and IPv6. If
you set it to 1, IPv6 sockets will only bind to IPv6 only by default,
for all your applications.

http://serverfault.com/questions/408667/how-do-i-disable-ipv4-mapped-ipv6

Anyway, this is not an issue with NodeJS. This is the defaults of your
Linux distribution and default of Linux kernel.

@silverwind
Copy link
Contributor Author

Moving to #9390

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
net Issues and PRs related to the net subsystem.
Projects
None yet
Development

No branches or pull requests

3 participants