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?
Many issues that might be making this a challenge.
First,
stunclientdefaults to UDP whereasncatdefaults to TCP. So your first issue is that you aren't passing the flag (-uon most systems) to tellncatto 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
--localportparameter). Then when you issue thencatcommand, use the local port it picked to connect to the remote mapped port of the other ip address.Hypothetical usage:
Host A
Host B
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,
ncatmay 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.Host B then does this in two separate consoles:
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.