SamDecrock / node-tcp-hole-punching

Node.js script to demonstrate TCP hole punching through NAT
MIT License
73 stars 21 forks source link

Both client A and client B throw EADDRINUSE #7

Open jyang opened 6 years ago

jyang commented 6 years ago

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 commented 6 years ago

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.

jwh-hutchison commented 4 years ago

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.

kahveciderin commented 3 years ago

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

SamDecrock commented 3 years ago

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

kahveciderin commented 3 years ago

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

jwh-hutchison commented 3 years ago

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