Reputation: 45
I have two hosts A and B. They're in different networks, behind different NATs and ISPs. I'm trying to set up a p2p connection between them by using hole punching. I use a STUN server to obtain mapped IP addresses and ports for both A and B. It goes on like this:
For A:
.\stunclient.exe --mode behavior stunserver.stunprotocol.org 3478
Binding test: success
Local address: 192.168.0.110:54709
Mapped address: 186.233.160.141:28769
Behavior test: success
Nat behavior: Endpoint Independent Mapping
For B:
.\stunclient.exe --mode behavior stunserver.stunprotocol.org 3478
Binding test: success
Local address: 192.168.3.1:57015
Mapped address: 45.70.35.52:12870
Behavior test: success
Nat behavior: Endpoint Independent Mapping
Then I try to perform the TCP hole punching technique (using netcat) by executing these two lines simultaneously and multiple times on A and B:
On A:
ncat -p 54709 45.70.35.52 12870
Ncat: TIMEOUT.
On B:
ncat -p 57015 186.233.160.141 28769
Ncat: TIMEOUT.
I always get "Ncat: Timeout" as output (not immediatelly, it takes some time), however, I could make a direct connection between A and B via UDP hole punching by running the following commands three times:
On A:
ncat -u -p 54709 45.70.35.52 12870
On B:
ncat -u -p 57015 186.233.160.141 28769
So the problem is TCP hole punching isn't working. Any ideas why?
Upvotes: 0
Views: 922
Reputation: 104514
Many issues that might be making this a challenge.
First, stunclient
defaults to UDP whereas ncat
defaults to TCP. So your first issue is that you aren't passing the flag (-u
on most systems) to tell ncat
to run as UDP. Or, you can try running stunclient in tcp mode. (e.g. stunclient --protocol tcp stunserver.stunclient.org
), but TCP NAT traversal is much less reliable than UDP - especially with rudimentary command line tools )
I don't understand how your output above can have Host A and Host B behind the same NAT, yet both machines appear to have the same local IP address, using the same local port, but printing the same local ip address 192.168.3.3
. How is this a thing? Is this just a typo? Or is one machine a VM host of the other and they are sharing an IP?
The behavior you are trying to achieve, having two hosts behind the same NAT connect via the public ip address is called hairpinning. This relies on the NAT to be smart enough to see that an outbound packet is really meant for a host behind the router itself and to loop it back through its own routing table instead of going out on the WAN adapter. Not all NATs support hairpinning. So what you have to do is try connecting through to both the local and remote ip addresses.
Also, try to avoid picking hardcoded ports like 20000. Let stunclient.exe pick a randomly available port for you. (i.e. don't specify --localport
parameter). Then when you issue the ncat
command, use the local port it picked to connect to the remote mapped port of the other ip address.
Hypothetical usage:
Host A
stunclient.exe stunserver.stunprotocol.org
Binding test: success
Local address: 192.168.1.2:1111
Mapped address: 45.70.35.52:2222
Host B
stunclient.exe stunserver.stunprotocol.org
Binding test: success
Local address: 192.168.1.3:3333
Mapped address: 45.70.35.52:4444
Address candidates passed from A to B: {45.70.35.52:2222, 192.168.1.2:1111}
Address candidates passed from B to A: {45.70.35.52:4444, 192.168.1.3:3333}
Host A then runs these command in parallel. But oops, ncat
may not allow sharing the socket port between two running programs. Look at the documentation to see if the SO_REUSEADDR flag is exposed implicitly as a command line param. It may do this implicitly.
ncat -u -p 1111 45.70.35.52 4444
ncat -u -p 1111 192.168.1.3:3333
Host B then does this in two separate consoles:
ncat -u -p 3333 45.70.35.52 2222
ncat -u -p 3333 192.168.1.2:1111
In other words, try all 4 combinations of A to B and B to A.
I was about to mention making sure you don't have address dependent mapping by running the behavior test. (i.e. "symmetric NAT"). Symmetric NATs make p2p connectivity very difficult for the connection to "go direct". But you've got endpoint independent, which is good.
Upvotes: 0