Question is below. Here is my current test code which did not succeed.
static void Main(string[] args)
{
if (args.Count() != 3)
{
Console.WriteLine("Bad args");
}
var ep = new IPEndPoint(IPAddress.Parse(args[0]), int.Parse(args[1]));
var lp = new IPEndPoint(IPAddress.Any, int.Parse(args[2]));
var s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
s.Bind(lp);
var c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
c.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
c.Bind(lp);
Task.Run(() => { try { c.Connect(ep); } catch { } });
s.Listen(10);
var v = s.Accept();
v.Close();
}
How do I do TCP hole punching? I am testing using a remote server. I'm running wget local_public_ip:port/test
. I have my router setup for port 80 so it doesn't need a hole punch. My code got a connection. Now I try on other ports and I can't exactly figure out how to punch the hole.
What I have done is (C# code)
var l = new TcpListener(8090);
l.Start();
try { var o = new TcpClient(); o.Connect("myserverip", 123); }
catch(Exception ex) {}
var e = l.AcceptSocket();
Console.WriteLine(e.RemoteEndPoint.AddressFamily);
I thought maybe I need to setup the local endpoint on the out tcp connection.
TcpClient(new System.Net.IPEndPoint(new System.Net.IPAddress(bytearray), port));
I made a mistake and got this exception
The requested address is not valid in its context
Fixing up the byte array to 192,168,1,5
it appears to make outgoing connects correctly. Now that I have a out connection to the remote IP using my listening port I thought wget would be able to connect to me. It wasn't the case
How do I do TCP hole punching?
Best Solution
I'd use the "sequential hole punching technique" detailed in http://www.bford.info/pub/net/p2pnat/index.html. It seems much simpler to do that simultaneous connections and socket reuse. It is not necessary for hole punching to do anything exactly simultaneously (that is a meaningless notion in distributed systems anyway).
I have implemented hole punching. My router seems not to like it. Wireshark shows the outbound hole punching SYN is correct but the remote party can't get through to me. I verifies all ports with TcpView.exe and disabled all firewalls. Must be a router issue. (It is a strange and invasive router.)
You can try both values for
useParallelAlgorithm
. Both should work.This code is for the server. It punches a hole into the local NAT. You can then connect from the remote side using any client that allows to pick the local port. I used
curl.exe
. Apparently, telnet on Windows does not support binding to a port. wget apparently neither.Verify that the ports are correct on both sides using TcpView or Process Explorer. You can use Wireshark to verify packets. Set a filter like
tcp.port = 1234
.When you "call out" to punch a hole you enable the tuple (your-ip, your-port, remote-ip, remote-port) to communicate. This means that all further communication must use those values. All sockets (inbound or outbound) must use these exact port numbers. In case you aren't aware: outgoing connections can control the local port as well. This is just uncommon.