I want to do TCP Hole Punching (NAT Traversal) in C#. It can be done with a rendezvous server if needed. I found http://sharpstunt.codeplex.com/ but can not get this to work
http://sipsorcery.codeplex.com has a working stun server.
SipSorcery.core -> SipSorcery.Net -> Stun
It sounds like you might be getting TCP and UDP mixed up. TCP is a connection-orientated protocol, easily understood by firewalls and routers, and requires one initiator (client) and one listener (server). If both client and server are behind firewalls or NAT, you cannot punch a hole through without having them both connect to some proxy server (which is not firewalled). The problem with this is that then the proxy would be responsible for relaying all of their traffic.
From your question, it sounds like you are more interested in UDP hole punching, which exploits the fat that UDP is stateless, and not connection-orientated. Therefore most state-tracking firewalls will make a "best guess" about the UDP data flow, and assume that traffic leaving on a given port will receive replies on the same port, and automatically route them back. If, using some out-of-channel means (such as a TCP server which simply passes addresses and not data), both peers can be transmitting data to each other on the same ports, their respective firewalls/NAT routers will open up holes allowing the traffic in.
As for how to do it, it all depends on how you are going to get the IP address of the peers to each other. Once you have it, simply start transmitting UDP packets on an agreed port, and wait for a reply.
In each network scenario, TCP hole punching operates in a similar way to UDP hole punching. For example, if two peers A and B are behind different NATs, each peer’s first SYN packet sent to the other peer opens up a hole associated with its public address in its respective NAT. If A’s first SYN packet to B reaches B’s NAT before B’s first SYN packet to A reaches B’s NAT, B’s NAT considers A’s SYN packet unsolicited and drops it. However, subsequently B’s first SYN packet can travel through A’s NAT successfully because A’s NAT recognises B’s public address as the destination of the outgoing session that A has initiated.
So yes. It's possible to TCP holepunch. I don't see why anyone would think otherwise.
Also, could you not create this type of bahaviour manually? It doesn't need to depend on any specific protocol as long as the steps are the same to gather all of the required information.
In general, TCP hole punching (3.2.1) proceeds as follows:
Clients: A, B Server: S
• A uses its connection with S to ask S for a connection with B. • S replies to A with B’s private and public addresses, and simultaneously sends A’s addresses to B.
• A and B asynchronously make outgoing connection at- tempts (send SYN packets) to each other’s public and private addresses, from the same port that they used to register with S. At the same time, they listen for TCP incoming connection attempts on their local TCP ports.
• A and B wait for a SYN-ACK response to their out- going SYN packets, or an incoming connection request (SYN packet). If a connection fails, the peer can retry it up to a maximum timeout period.
• Once the three-way handshake process has completed, the peers authenticate each other. If the authentica- tion fails, the peers close that connection and wait until another connection is successfully authenticated. The first successfully authenticated connection will be used to transfer TCP data.
(I know this isn't much of an answer but there wasn't enough room for a comment).
We put together a library called IceLink that does P2P streaming using ICE/STUN/TURN with full NAT traversal. STUN-based hole-punching works for the majority of routers to establish a direct connection between peers, and for the "bad" routers out there, the connection falls back to a TURN-based relay.
The question is quite old but for anyone looking for a solution, you should take a look at the Open.NAT project it's really easy to use and work with both UPNP and PMP NATs!
Let's say that you want to forward external Port 1700 to local port 1600, all you have to do is:
var discoverer = new NatDiscoverer();
var device = await discoverer.DiscoverDeviceAsync();
await device.CreatePortMapAsync(new Mapping(Protocol.Tcp, 1600, 1700, "The mapping name"));
You can also list all existing mappings, so you can validate that your port is not already used.
var sb = new StringBuilder();
var ip = await device.GetExternalIPAsync();
sb.AppendFormat("\nAdded mapping: {0}:1700 -> 127.0.0.1:1600\n", ip);
sb.AppendFormat("\n+------+-------------------------------+--------------------------------+------------------------------------+-------------------------+");
sb.AppendFormat("\n| PROT | PUBLIC (Reacheable) | PRIVATE (Your computer) | Descriptopn | |");
sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
sb.AppendFormat("\n| | IP Address | Port | IP Address | Port | | Expires |");
sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
foreach (var mapping in await device.GetAllMappingsAsync())
{
sb.AppendFormat("\n| {5} | {0,-20} | {1,6} | {2,-21} | {3,6} | {4,-35}|{6,25}|",
ip, mapping.PublicPort, mapping.PrivateIP, mapping.PrivatePort, mapping.Description, mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP", mapping.Expiration.ToLocalTime());
}
sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
Console.WriteLine(sb.ToString());
There is also a blog post about NAT Traversal on MSDN: https://blogs.msdn.microsoft.com/ncl/2009/07/27/end-to-end-connectivity-with-nat-traversal/