node-tcp-hole-punching icon indicating copy to clipboard operation
node-tcp-hole-punching copied to clipboard

Both client A and client B throw EADDRINUSE

Open jyang opened this issue 6 years ago • 6 comments

First, thank you for this little sample! It's so exciting to get it to work with minimal dependencies.

My issue looks different than the other two already filed. My public server runs on a host with a public IP. My client A and client B run behind their own NAT. Both of them are on Linux. I have this issue on Ubuntu 18.04 and Debian Stretch. Node version is 8.9.4 or 6.14.2.

$ node clientA.js
> (A->S) connecting to S
> (A->S) connected to S via 192.168.0.188 44808
> (A->S) response from S: {"name":"A","localAddress":"192.168.0.188","localPort":44808,"remoteAddress":"172.58.36.250","remotePort":43526}

> (A) 192.168.0.188:44808 ===> (NAT of A) 172.58.36.250:43526 ===> (S) 104.198.1.109:9999

> (A->S) response from S: {"name":"B","localAddress":"192.168.86.108","localPort":42688,"remoteAddress":"107.194.153.239","remotePort":42688}
> (A) time to listen on port used to connect to S (44808)
> (A->B) connecting to B: ===> (B) 107.194.153.239:42688
events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE 192.168.0.188:44808
    at Object._errnoException (util.js:1024:11)
    at _exceptionWithHostPort (util.js:1046:20)
    at Server.setupListenHandle [as _listen2] (net.js:1351:14)
    at listenInCluster (net.js:1392:12)
    at doListen (net.js:1501:7)
    at _combinedTickCallback (internal/process/next_tick.js:141:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)
$ node clientB.js 
> (B->S) connecting to S
> (B->S) connected to S via 192.168.86.108 42688
> (B->S) response from S: {"name":"B","localAddress":"192.168.86.108","localPort":42688,"remoteAddress":"107.194.153.239","remotePort":42688}

> (B) 192.168.86.108:42688 ===> (NAT of B) 107.194.153.239:42688 ===> (S) 104.198.1.109:9999

> (B->S) response from S: {"name":"A","localAddress":"192.168.0.188","localPort":44808,"remoteAddress":"172.58.36.250","remotePort":43526}
> (B) time to listen on port used to connect to S (42688)
> (B->A) connecting to A: ===> (A) 172.58.36.250:43526
events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE 192.168.86.108:42688
    at Object._errnoException (util.js:1024:11)
    at _exceptionWithHostPort (util.js:1046:20)
    at Server.setupListenHandle [as _listen2] (net.js:1351:14)
    at listenInCluster (net.js:1392:12)
    at doListen (net.js:1501:7)
    at _combinedTickCallback (internal/process/next_tick.js:141:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)

Apparently, this line failed:

socketToS = require('net').createConnection({host : addressOfS, port : portOfS}, function () {
  ...
});

jyang avatar May 09 '18 03:05 jyang

I see the issue being listening on a port that is already open.

BTW, node-udp-hole-punching works for the same hosts and networks that I tested here.

jyang avatar May 10 '18 16:05 jyang

I see the issue being listening on a port that is already open.

BTW, node-udp-hole-punching works for the same hosts and networks that I tested here.

https://pdos.csail.mit.edu/papers/p2pnat.pdf Check out section 4.1, it looks like there's a potential workaround.

jwh-hutchison avatar Oct 26 '20 09:10 jwh-hutchison

I have the same issue, both client a and b are on different nat's, and they both throw EADDRINUSE when I run B

kahveciderin avatar Jul 14 '21 05:07 kahveciderin

TCP hole punching doesn't always work. It depends on the underlying operating system.

SamDecrock avatar Jul 14 '21 06:07 SamDecrock

then how do torrenting or other p2p technologies work with people under nat's? I can download a torrent, let's say linux iso's with this exact setup and also seed them but this demo does not work for some reason

kahveciderin avatar Jul 14 '21 10:07 kahveciderin

then how do torrenting or other p2p technologies work with people under nat's? I can download a torrent, let's say linux iso's with this exact setup and also seed them but this demo does not work for some reason

They use a combination of TCP (where possible), error-tolerant UDP hole punching and also uPnP where available. Most routers seem to come with uPnP enabled by default so it's worth considering that feature for the app that you are working on.

The availability of TCP/UDP hole punching seems to also depend on the type of NAT that you are behind, if you are working with JavaScript then the package that I worked on (npm link at bottom) might help determine the possibile options, i.e. you can have difficulties with different kind of NATs especially 4G and business networks which mess up UDP hole punching with symmetric NATs.

library: https://www.npmjs.com/package/nat-type-identifier. further reading: https://www.researchgate.net/publication/228411948_A_New_Method_for_Symmetric_NAT_Traversal_in_UDP_and_TCP

jwh-hutchison avatar Jul 14 '21 10:07 jwh-hutchison