Search code examples
c#portnatupnp

UPnP hole punching can't use external IP to access device on local subnet


I have a somewhat unique situation where I require the ability to perform NAT hole punching for a multi node peer to peer type application; where all nodes must reference each other from publicly accessible IP addresses, even when some of those nodes might reside on the local subnet.

I have been able to successfully map ports with help from this question (UDP hole punching implementation) using Open.Nat.

My code is basically as simple as this:

var discoverer = new NatDiscoverer();
var device = await discoverer.DiscoverDeviceAsync();
await device.CreatePortMapAsync(new Mapping(Open.Nat.Protocol.Tcp, port, port));

This successfully creates a map in my router

enter image description here

I can now successfully connect to this IP and port number from an external network (tested on mobile data connection) by doing something like this

TcpClient client = new TcpClient();
client.Connect("publicip", 6968);

However when I attempt to connect to the same public ip address from the local subnet the connection will fail with 'No connection could be made because the target machine actively refused it?'.

I have used wireshark to see if any packets land to the target machine and it appears they do not.

Obviously it is clear that the router is probably failing to forward/route the connections correctly on the local subnet, so what I am trying to understand is if this is a known limitation of the UPnP protocol or specific to my router? Perhaps there is a trick when you create the mappings that I have missed?

I note that my router appears to use MiniUPnP http://miniupnp.free.fr/ Version 20160321

I realise this is a tricky question to answer but hoping that we can get some clarification of what UPnP should be doing in this situation from an expert.

EDIT:

A bit more context to my question; let me elaborate why I have such a requirement. I am using Akka.NET clusters on mobile devices across network boundaries, the key point to remember with Akka clusters is to successfully get a Akka.NET cluster to form all members of the cluster must be bio-directionally reachable to one another.

Now consider a situation like this

enter image description here

My goal is to only have to assign a static ip to the server node and allow all the cluster nodes to move in and out the network boundaries seamlessly. The ideal way to achieve this is to assign publicly reachable addresses to each node on the network regardless of where it is physically located.


Solution

  • This isn't really something you can fix, and it isn't really specific to C#. Most routers will only match NAT packets that arrive on their internet facing interface. If you want to allow for multiple nodes running behind the same NAT to connect directly to each other, you will need to implement another solution.

    For example, you could share each node's private interface addresses. Then attempt to connect directly if the public address matches.