36

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. Ideally i need some method which i give a Port Number (int) as parameter that after a call to this method is available ("Port Forwarded") at the NAT. It would be also OK if the method just returns some port number which is then available at the NAT. Has anybody done this in C# ? Can you give me working examples for sharpstunt or something else?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
TobiHeidi
  • 1,201
  • 2
  • 14
  • 23
  • Hmm... why is this special case needed? if its just about the connection, install any Proxy, and confiugre that in the Webclient. should also solve it. – cRichter Jul 08 '10 at 11:39
  • 2
    Proxies are slow and not secure. –  Aug 31 '16 at 23:54

5 Answers5

26

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).

SilverX
  • 1,509
  • 16
  • 18
  • This will not work with Enterprise NATs (symmetric NAT). Why do A and B send to the private address? They cannot be routed over the Internet. What you are describing is STUNT – tobias Jul 26 '13 at 20:38
  • 2
    I am merely describing the hole-punching process. STUNT is an actual set of tools to aid in the hole-punching process. The main point of my answer was to show that TCP hole-punching is indeed possible because somebody had mentioned it wasn't. I am aware that there are scenarios in which it will not work but that wasn't the question. (As for why the mention of the private address. I don't know. I copied the majority of the data from other sources). – SilverX Jul 27 '13 at 02:27
  • 1
    Wikipedia for STUN under "Limitations": Since the IP address of the STUN server is different from that of the endpoint, in the symmetric NAT case, the NAT mapping will be different for the STUN server than for an endpoint. TURN offers better results with symmetric NAT. – SilverX Jul 27 '13 at 02:33
  • One thing I don't understand in this is what the "Private addess" means. Private addresss usually refers to the one looking like 192.168.x.x , but I don't understand how client A or B sending connection requests to it would help with anything. What am I not understanding here? – Hey'Youssef Jul 06 '21 at 21:30
5

The question is quite old but for anyone looking at an alternate solution for NAT Traversal, you should take a look at the Open.NAT project. It's really easy to use and work with both UPNP and PMP, but it's different than Hole Punching.

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/

JPelletier
  • 2,049
  • 16
  • 23
  • Yeah it's a bit tricky to get it to work perfectly and with some network hardware it may not work at all. – JPelletier Jul 25 '16 at 13:28
  • 3
    Just to be clear, UPnP is not the same thing as firewall hole punching. They are both forms of NAT traversal, however UPnP is just a way of creating a port forwarding entry in the NAT, while hole punching can connect two peers without explicitly defining these entries. – stenlan Mar 12 '18 at 21:32
  • @stenlan You are totally right, I edited the answer to make it clearer. – JPelletier May 10 '22 at 14:53
2

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.

Anton
  • 4,554
  • 2
  • 37
  • 60
1

http://sipsorcery.codeplex.com has a working stun server.

SipSorcery.core -> SipSorcery.Net -> Stun

jgauffin
  • 99,844
  • 45
  • 235
  • 372
0

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.

Tyr
  • 782
  • 8
  • 19
  • I can do UDP Hole punching which is nown as STUN its quite easy. BUT you can do TCP Hole punching, it is just more complex and called STUNT (last T is for TCP). http://sharpstunt.codeplex.com/ claims do be able to do it but i cant get it to work. There are also some JAVA libs that do it... – TobiHeidi Jul 10 '10 at 04:38
  • +1 >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 – Valmond Oct 09 '11 at 12:58
  • Keep in mind that STUN does Not work with all Kinds of NAT. ICE defines TURN as fallback. – tobias Jul 26 '13 at 20:43
  • TCP hole punching is possible, but it requires server to initiate the connection (but the server is not needed after the link is established - at least that's the way I understand it) [https://en.wikipedia.org/wiki/TCP_hole_punching](https://en.wikipedia.org/wiki/TCP_hole_punching) – Markaos May 08 '17 at 18:39