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

Why listening "::" (all IPv6) also get "0.0.0.0"(all IPv4) listened? #9390

Closed
jjqq2013 opened this issue Nov 1, 2016 · 13 comments
Closed

Why listening "::" (all IPv6) also get "0.0.0.0"(all IPv4) listened? #9390

jjqq2013 opened this issue Nov 1, 2016 · 13 comments
Labels
doc Issues and PRs related to the documentations. net Issues and PRs related to the net subsystem. question Issues that look for answers.

Comments

@jjqq2013
Copy link
Contributor

jjqq2013 commented Nov 1, 2016

  • Version:v7.0.0
  • Platform:Windows 7 Pro
  • Subsystem:

I found a strange problem, i created a simple TCP server to listen at port 5555 of "::"(all IPv6 interfaces)

net.createServer(c=>console.log).listen(5555,'::')

Then i found all IPv4 interfaces are also listening port 5555.

> netstat -an | findstr /I :5555
  TCP    0.0.0.0:5555           0.0.0.0:0              LISTENING
  TCP    [::]:5555              [::]:0                 LISTENING

Another relevant problem is, if i do not specify host, or use undefined, or empty string,

net.createServer(c=>console.log).listen(5555)
//or net.createServer(c=>console.log).listen(5555,undefined)
//or net.createServer(c=>console.log).listen(5555,'')

It should listen :: OR 0.0.0.0, not both, according the document:

server.listen([port][, hostname][, backlog][, callback])
If the hostname is omitted, the server will accept connections on any IPv6 address (::) when IPv6 is available, or any IPv4 address (0.0.0.0) otherwise

But the fact is both :: and 0.0.0.0 get listened.

I don't know which is correct? document or implementation? Anyway, this is a bit confusing.
Or maybe this is just a trick implementation of the Windows OS itself ?

@mscdex mscdex added question Issues that look for answers. net Issues and PRs related to the net subsystem. labels Nov 1, 2016
@bnoordhuis
Copy link
Member

Or maybe this is just a trick implementation of the Windows OS itself ?

It's called dual-stack mode and it's platform-specific. Linux lets you enable/disable it through the net.ipv6.bindv6only sysctl, I assume Windows has something similar.

I'll add doc tags because it doesn't look like the documentation currently mentions this. Libuv has UV_TCP_IPV6ONLY and UV_UDP_IPV6ONLY flags that we could leverage along the lines of net.createServer({ ipv6only: true }).

@bnoordhuis bnoordhuis added doc Issues and PRs related to the documentations. docs-requested labels Nov 1, 2016
@jjqq2013
Copy link
Contributor Author

jjqq2013 commented Nov 1, 2016

Thank you. You saved my time.

@silverwind
Copy link
Contributor

silverwind commented Nov 1, 2016

This dual stack mode is certainly confusing, as most people would expect :: (The alias for all v6 addresses) to bind to just v6, not magically also binding v4 on certain platforms.

The user has no way of knowing if the platform supports dual-stack, so if one wants to listen on v4 and v6, you'd have to try listening on both :: and 0.0.0.0 and catch the EADDRINUSE from the v4 listen on platforms that don't support it (I think macOS is an example).

I'd argue that ipv6only behavior should be made the default behaviour when hostname is ::. The dual-stack mode could still be in effect when hostname is undefined.

@sam-github sam-github added doc Issues and PRs related to the documentations. and removed doc Issues and PRs related to the documentations. docs-requested labels Dec 1, 2016
@mika-fischer
Copy link
Contributor

Two things to note about this bug:

  1. It makes it more difficult than necessary to create portable code.
  2. It makes it impossible to create a IPv6-only socket with nodejs on Linux, and that just seems wrong.

@jjqq2013
Copy link
Contributor Author

jjqq2013 commented Feb 5, 2017

Hi, i forgot to tell everyone that this phenomenon
not only happens in Windows, but also Linux, Mac.

As my test,

On Mac (OS X EI Captitan 10.11.6), the netstat does shows tcp46 which means TCP4 and TCP6.

tcp46      0      0  *.5555                 *.*                    LISTEN 

On Linux Ubuntu 16.04, the netstat does show only tcp6, but in fact, the same TCP4 port can be connected!

tcp6       0      0 :::5555                 :::*                    LISTEN     

After all, this is very OS-dependent.

@jjqq2013
Copy link
Contributor Author

jjqq2013 commented Feb 7, 2017

Someone help me please!

It seems only for :: have this confusing phenomenon, but i need someone do me a favour to test the last case in some Linux OS in Real Machine with IPv6 support.

OS Listen IPv6 address Does equivalent IPv4 auto listened
Windows 7Pro/10 :: YES
Mac OS X EI Capitan 10.11.6 :: YES
Ubuntu 14.04/16.04 :: YES
Windows 7Pro/10 ::1 NO
Mac OS X EI Capitan 10.11.6 ::1 NO
Ubuntu 14.04/16.04 ::1 NO
Windows 7Pro/10 ActualIPv6Address NO
Mac OS X EI Capitan 10.11.6 ActualIPv6Address NO
Ubuntu 14.04/16.04 ActualIPv6Address Unknown (failed to bind (invalid parameter)

Now the new problem is I can not confirm the last case in Linux, i'v tried on Amazon VPC, VirtualBox VM.

Both show error, even i use socat or nc it still show invalid parameter.

socat tcp6-listen:5555,bind=fe80:0000:0000:0000:04bf:1eff:fefe:8015,reuseaddr,fork -

Show

...socat[...] E bind(3, {AF=10 [fe80:0000:0000:0000:04bf:1eff:fefe:8015]:5555}, 28): Invalid argument

##Would anyone to test as following steps (use Node.js 7.0.0**+**) on a Linux OS ? ( must NOT inside a VM or VPC)

  1. Create a tcp server to listen at 5555 of some actual IPv5 address, please do not specify :: or ::1
node -e "net.createServer(c=>console.log).listen(5555,'AN_ACTUAL_IPv6_ADDR')" &
  1. Connect to the equivalent IPv4 address.
node -e "net.connect(5555,'THE_EQUIVALENT_IPv4_ADDR',()=>console.log('connected'))"

It's expected only step2 has error of ECONNREFUSED.

jjqq2013 added a commit to sjitech/node that referenced this issue Feb 14, 2017
@sam-github
Copy link
Contributor

sam-github commented Feb 14, 2017

How do I calculate THE_EQUIVALENT_IPv4_ADDR? I run linux, and node -e "net.createServer(c=>console.log).listen(5555,'fe80::7d2b:81c4:1f2:2ad%wlan1')" worked fine.

@jjqq2013
Copy link
Contributor Author

@sam-github thank you for the test. I just run ip addr | grep inet to show all ip4 ip6 pair and find it manually.

@sam-github
Copy link
Contributor

Not sure this is what you want, or if my machine has enough support for IPv6, but here it is:

% ip addr | grep inet
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
    inet 192.168.0.181/24 brd 192.168.0.255 scope global dynamic wlan1
    inet6 fe80::7d2b:81c4:1f2:2ad/64 scope link 

% node -e "require('net').createServer(c=>console.log).listen(5555,'fe80::7d2b:81c4:1f2:2ad%wlan1')"
% node -e "net.connect(5555,'192.168.0.181',()=>console.log('connected'))"
events.js:161
      throw er; // Unhandled 'error' event
      ^

Error: connect ECONNREFUSED 192.168.0.181:5555

@jjqq2013
Copy link
Contributor Author

@sam-github thank you.

This is what i want! This is a proof of that "On linux, without special configuration, listening actual IPv6 address will not cause equivalent IPv4 address also being listened"

So, what is your linux distribution? (cat /etc/*release* can see it)

@sam-github
Copy link
Contributor

ubuntu 16.10, kernel 4.8.0-34-generic

@sam-github
Copy link
Contributor

I think it likely proves just "on this linux distro, with default configuration...", I could probably config ipv4 to redirect to ipv6

@jjqq2013
Copy link
Contributor Author

Yes, with default configuration, this is exactly what i want to prove.

Thank you.

So, all typical test are done.

OS Listen IPv6 address Does equivalent IPv4 auto listened
Windows 7Pro/10 :: YES
Mac OS X EI Capitan 10.11.6 :: YES
Ubuntu 14.04/16.04 :: YES
Windows 7Pro/10 ::1 NO
Mac OS X EI Capitan 10.11.6 ::1 NO
Ubuntu 14.04/16.04 ::1 NO
Windows 7Pro/10 ActualIPv6Address NO
Mac OS X EI Capitan 10.11.6 ActualIPv6Address NO
Ubuntu 16.10 ActualIPv6Address NO

All test is done under default configuration about IPv6.

So my conclusion is that we should only mention about the amazing effect of listening ::.

italoacasas pushed a commit to italoacasas/node that referenced this issue Feb 20, 2017
Fixes: nodejs#9390
PR-URL: nodejs#11134
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
italoacasas pushed a commit that referenced this issue Feb 22, 2017
Fixes: #9390
PR-URL: #11134
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
doc Issues and PRs related to the documentations. net Issues and PRs related to the net subsystem. question Issues that look for answers.
Projects
None yet
Development

No branches or pull requests

6 participants