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.
On Wed, Nov 11, 2015 at 3:04 PM, Etienne Dechamps <etienne at edechamps.fr> wrote:> 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. >it is entirely possible to write code that uses threads on Win32 and forks on POSIX by abstracting the communication bits generically. Signalling could work over pipes on both. https://msdn.microsoft.com/en-us/library/windows/desktop/aa365152(v=vs.85).aspx -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://www.tinc-vpn.org/pipermail/tinc/attachments/20151111/3cf3e7d7/attachment.html>
On 11 November 2015 at 21:57, David Nicol <davidnicol at gmail.com> wrote:> it is entirely possible to write code that uses threads on Win32 and forks > on POSIX by abstracting the communication bits generically. Signalling could > work over pipes on both. > > https://msdn.microsoft.com/en-us/library/windows/desktop/aa365152(v=vs.85).aspxHum... yes of course, but I don't see how that addresses my concern. My point was, we either need to do something different between Win32 and POSIX (whether that implies different thread APIs or different process models is besides the point), which means we'll end up with #ifdefs (which is not great, because that makes code harder to maintain). Or we add a dependency on pthreads-win32 on Windows so that we can write the same code on both platforms. It's mostly a matter of taste really. (Personally I'm leaning towards the latter.) I'm not really concerned with communication. In fact I'm pretty sure the UPnP thread wouldn't have to communicate with tinc at all: it's pretty much a fire-and-forget affair. The UPnP code would only need to know which ports to forward, a parameter that can be provided at thread start. Afterwards, the thread would just keep the UPnP mapping alive indefinitely without having to talk to tinc at all. Therefore there's no need for pipes. (I realize that this means UPnP support could possibly be achieved simply by suggesting that the user spawn some standalone UPnP client process in the background from the tinc-up hook. That's not very user-friendly, though. Especially on Windows.)
On Wed, Nov 11, 2015 at 09:04:20PM +0000, Etienne Dechamps wrote:> 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 [...]. 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.phpAre you referring to port restricted NAT in the first graph? Because that should still work with tinc. Symmetric NAT looks like 15% or so, and if you include everything to the right of it, it comes to 35% or so. What is more interesting is the last graph: tinc does UDP hole punching but not UPnP (yet), the difference between the first two bars is about 10%. Not unworthwile.> 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).Yes, and they are not RFC 4787 compliant.> 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.Indeed. (That reminds me, I have to do something similar with the SOCKS proxy code, as it also support opening listening ports.)> 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.When I started looking at NAT traversal support for tinc, there were several libraries, but all of them quite large, some larger than tinc itself, and it was indeed difficult to integrate them into tinc's event loop. Since a STUN-like protocol was easy to implement in tinc itself, I opted for that solution. Of course if there is a lightweight, cross-platform library that is easy to integrate we should have a look at that. If that can be done with MiniUPnP, go ahead. As for dependencies: it should be possible to disable support for UPnP for those who want to build a minimal version of tinc. As for threads, tinc 1.0.x on Windows already uses threads (as you should know) without using libpthread. If UPnP can be integrated by just using CreateThread() and maybe Enter/LeaveCriticalSection(), I'd use that and avoid the whole issue of libpthread. NAT-PMP (and PCP?) seems interesting to, maybe it is simple enough to code directly into tinc? -- Met vriendelijke groet / with kind regards, Guus Sliepen <guus at tinc-vpn.org> -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: <http://www.tinc-vpn.org/pipermail/tinc/attachments/20151112/30644838/attachment.sig>
On 12 November 2015 at 21:29, Guus Sliepen <guus at tinc-vpn.org> wrote:> On Wed, Nov 11, 2015 at 09:04:20PM +0000, Etienne Dechamps wrote: >> 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 > > Are you referring to port restricted NAT in the first graph? Because > that should still work with tinc. Symmetric NAT looks like 15% or so, > and if you include everything to the right of it, it comes to 35% or so.Hmm. Well I was only looking at the third graph, which presents a simplified view where "UDP hole punching" only works in 50% of cases, which is the number I pulled. To be honest I am not quite sure how that follows from the first or second graph. My best guess is that it's simply a direct application of probabilities: if the probability that a NAT is "compliant" is 70%, then the probability that *both* NATs at both ends of the tunnel are "compliant" is only 50% (0.70*0.70). Indeed both NATs need to be compliant in order for UDP hole punching to work. However, that indeed means that my original post was badly worded - I should have said "50% of *cases*" not "50% of NATs". My bad.> What is more interesting is the last graph: tinc does UDP hole punching > but not UPnP (yet), the difference between the first two bars is about > 10%. Not unworthwile.It is especially worthwhile if you consider that UPnP makes you reachable not only if your NAT is making things difficult, but also if the NAT of *the other side* is making things difficult, too. UPnP is basically a "get out of jail free" card that makes you look exactly like a publicly addressable node, which means you can establish direct communication with anyone even if they themselves don't have the luxury of sitting behind a "good" NAT. That makes it very useful IMHO (in fact it makes it even more useful than fixing the user's NAT). I'm not sure if the graph takes that fact into account - I would have expected way more than a 10% difference if that was the case.> Of course if there is a lightweight, > cross-platform library that is easy to integrate we should have a look > at that. If that can be done with MiniUPnP, go ahead.Understood. I'll get busy this week-end :)> As for dependencies: it should be possible to disable support for UPnP > for those who want to build a minimal version of tinc. As for threads, > tinc 1.0.x on Windows already uses threads (as you should know) without > using libpthread. If UPnP can be integrated by just using CreateThread() > and maybe Enter/LeaveCriticalSection(), I'd use that and avoid the whole > issue of libpthread.Okay.> NAT-PMP (and PCP?) seems interesting to, maybe it is simple enough to > code directly into tinc?Well, the author of miniupnpc also wrote libnatpmp, which apparently *is* specifically designed to be integrated into an event loop: http://miniupnp.free.fr/libnatpmp.html