UPnP support in tinc

Etienne Dechamps etienne at edechamps.fr
Wed Nov 11 22:04:20 CET 2015


Hi Guus,

Unfortunately, I often notice that even with the advanced UDP hole
punching mechanisms that tinc uses, I still come across cases on my
network where two nodes behind NATs cannot talk to each other because
one of the nodes is behind a "strict" NAT that won't use consistent
source ports for UDP packets that are sent to different destination
addresses.

More formally, this type of NAT is referred to as using
"endpoint-dependent mapping" (EDM-NAT) in RFC 5128 (§5.2). According
to Google searches another name for it is "symmetric NAT" (as opposed
to "full cone NAT"). This type of NAT will stop any UDP hole punching
attempt dead in its tracks, and there's nothing we can do about it.

According to an online NAT check service, around 50% of NATs in the
wild have this problem, making this a very real issue:
http://nattest.net.in.tum.de/results.php

I have at least two examples of users on my network who are hitting
this issue: one is using an ISP-provided home router based on a model
from ZTE (ZXHN H298N), the other one is using pfSense. The latter is
especially worrying, since I would expect it to be used as the basis
of a number of commercial products. A Google search for "pf cone nat"
returns somewhat depressing results: apparently it's not even possible
to configure pf to act as an EIM-NAT, and people asking for such an
option are basically being told to go away with demonstrably weak
security-related arguments (which can easily be debunked by pointing
out that NATs and firewalls have different goals, and that providing
endpoint-independent mapping does not preclude endpoint-dependent
*filtering*, which would still allow UDP hole punching to work). But I
digress.

So, I'm afraid there's still work to be done to ensure that tinc uses
the network in the most efficient way possible for users behind NATs
(i.e. "road warriors"). The only way we can try to get through
EDM-NATs is by using UPnP-IGD, which tinc could use to explicitly open
its UDP port on the NAT. This should pretty much fix the issue with
home routers since most of them support UPnP (for example the
aforementioned ZTE router does). As a bonus, if we also use UPnP to
open the TCP metaconnection port, it could even allow AutoConnect to
work between nodes behind NATs, which would be quite nice.
Furthermore, even if the offending NAT doesn't support UPnP, UDP Hole
Punching will still work if the NAT of the *other* node supports UPnP,
further reducing the number of scenarios in which direct communication
will fail.

Now, the reason why this is not already a pull request is because
bringing UPnP support to tinc is more complicated than it sounds. I
could only find one UPnP library that can be qualified as
"lightweight" (i.e. doesn't require ridiculous dependencies like XML
libraries), that's miniupnpc: http://miniupnp.free.fr/ Here's the
catch: miniupnpc only provides a blocking API, there is no way to
integrate it into an event loop. That pretty much means we will need
to run the UPnP code in a separate thread. Which means using pthreads
on POSIX, and then we would either have a dependency on pthreads-Win32
on Windows, or we would need to #ifdef Win32 thread code in.

I'm wondering what your thoughts are on this topic. I can definitely
give miniupnpc integration a try if you are okay with adding these
extra dependencies to tinc. It would be very easy to provide a
configure option to disable UPnP support, making these new
dependencies less of a concern.


More information about the tinc mailing list