Free Open Tinc VPN Service for private vpn eally needed “direct” machine to machine access between an number of staff and their local file servers. The obvious way to approach this sort of thing is to use a Virtual Private Network technology, but which one?There are a lot of VPN solutions out there. Quite a number of proprietary ones, and of course the usual contingent of “it’s-free-except-that-then-you-have-to-pay-for-it”. In both cases, why anyone would trust the integrity of code they can’t review is quite beyond me.
We’ve used OpenVPN for some of our enterprise clients, and it’s quite robust. Its model excels at giving remote users access to resources on the corporate network. Technically it is implemented by each user getting a point-to-point connection on an internal network (something along the lines of a 10.0.1.0/30
) between the user’s remote machine and a gateway server, and then adding routes to the client’s system to the corporate IP range (ie good old 192.168.1.0/24
). That’s fine so long as the assumption is that all the servers on the corporate network have the gateway as their default route, then reply packets to 10.0.1.2 or whatever will just go do default and be sent back down the rabbit hole. Gets messy with things like Postgres if your remote developers need access to the databases; in the configs you do need to add eg 10.0.1.0/24
to the list of networks that the database will accept connections from.
Anyway, that’s all fairly reasonable, and you can set up the client side from NetworkManager (install Debian package network-manager-openvpn-gnome
) which is really important too. Makes a good remote access solution.
Peer to Peer
But for our current work, we needed something less centralized. We’re not trying to grant connectivity to a remote corporate network; we’re trying to set up a private network in the old-fashioned frame-relay sense of the word — actually join several remote networks together.
Traditional VPN solutions route all the traffic through the secure central node. If you’ve got one system in NSW and another in Victoria, but the remote access gateway is in California, then despite the fact that the two edges are likely less than 50 ms away direct path, all your traffic is going across the Pacific and back. That’s stupid.
A major complication for all of us was that everyone is (of course) stuck behind NAT. Lots of developers, all working remotely, really don’t need to send all their screen casts, voice conferences, and file transfer traffic into the central corporate network just to come all the way out again.
The 1990s approach to NAT implies a central point that everyone converges to as a means of getting their packets across the port address translation boundary. Things have come a long way since then; the rise of peer-to-peer file sharing and dealing with the challenges of internet telephony has also helped a great deal. Firewalls are more supportive and protocols have evolved in the ongoing attempt to deal with the problem.
Meet tinc
So the landscape is different today, and tinc takes advantage of this. According to their goals page, tinc is a “secure, scalable, stable and reliable, easy to configure, and flexible” peer-to-peer VPN. Uh huh. Because of its peer-to-peer nature, once two edges become aware of each other and have exchanged credentials, they can start sending traffic directly to each other rather than through the intermediary.
$ ping 172.16.50.2
PING 172.16.50.2 (172.16.50.2) 56(84) bytes of data.
64 bytes from 172.16.50.2: icmp_req=1 ttl=64 time=374 ms
64 bytes from 172.16.50.2: icmp_req=2 ttl=64 time=179 ms
64 bytes from 172.16.50.2: icmp_req=3 ttl=64 time=202 ms
64 bytes from 172.16.50.2: icmp_req=4 ttl=64 time=41.6 ms
64 bytes from 172.16.50.2: icmp_req=5 ttl=64 time=45.4 ms
64 bytes from 172.16.50.2: icmp_req=6 ttl=64 time=51.3 ms
64 bytes from 172.16.50.2: icmp_req=7 ttl=64 time=43.3 ms
64 bytes from 172.16.50.2: icmp_req=8 ttl=64 time=42.3 ms
64 bytes from 172.16.50.2: icmp_req=9 ttl=64 time=44.2 ms
...
$
This is with the tincd
daemons freshly restarted on each endpoint. The first packet clearly initiates edge discovery, key exchange, and setup of the tunnels. It, and the next two packets, are passed across the Pacific to the central node. Ok, fine. But after that, the tunnel setup completes, and both edge nodes have been informed of the peer’s network addresses and start communicating directly. Nice.
See for yourself
Watching the logs under the hood confirms this. If you run tincd in the foreground then you can specify a debug level on the command line; I find “3″ a good setting for testing:
# tincd -n private -D -d3
tincd 1.0.13 (May 16 2010 21:09:47) starting, debug level 3
/dev/net/tun is a Linux tun/tap device (tun mode)
Executing script tinc-up
Listening on 0.0.0.0 port 655
Ready
Trying to connect to einstein (1.2.3.4 port 655)
Trying to connect to newton (5.6.7.8 port 655)
...
If you give it SIGINT
by pressing Ctrl+C
then it’ll switch itself up to the exceedingly verbose debug level 5, which is rather cool. SIGQUIT
terminates, which you can send with Ctrl+
. If you’re not running in the foreground (which of course you’d only be doing in testing),
# tincd -n private -kINT
does the trick. Quite handy, actually.
Performance is respectable indeed; copying a 2.8 MB file across the Pacific,
$ scp video.mpeg [email protected]:/var/tmp
gave an average of 31.625 seconds over a number of runs. Doing the same copy but sending it over the secure tunnel by addressing the remote machine by its private address,
$ scp video.mpeg [email protected]:/var/tmp
came in at an average of 32.525 seconds. Call it 3% overhead; that’s certainly tolerable.
Setup
Despite my talking above about joining remote networks, an important and common subcase is merely joining various remote machines especially when those machines are both behind NAT boundaries. That’s our in-house use case.
The tinc documentation is fairly comprehensive, and there are a few HOWTOs out there. There are a few gotchas, though, so without a whole lot of elaboration I wanted to post some sample config files to make it easier for you to bootstrap if you’re interested in trying this (install Debian package tinc
).
tinc has a notion of network names; you can (and should) organize your files under one such. For this post I’ve labelled it the incredibly original “private
“. Note that when you specify host names here they are not DNS hostnames; they are just symbolic names for use in control signalling between the tinc deaemons. Flexibility = Complexity. What else is new. Obviously you’d probably use hostnames anyway but administration of the tinc network doesn’t need to be co-ordinated with people naming their laptop my-fluffy-bunny
or some damn thing. Anyway, on system labelled hawking
I have:
hawking:/etc/tinc/private/tinc.conf
Name = hawking
AddressFamily = ipv4
ConnectTo = einstein
ConnectTo = newton
Interface = tun0
Note that I’ve got an Interface
statement there, not a Device
one. That’s a bit add odds with what the documentation said but what I needed to make it all work. Only one ConnectTo
is actually necessary, but I’ve got one server in California that is reliably up and one in Victoria that is not so I just threw both in there. That’s what your tincd
is going to (compulsively) try to establish tunnels to.
hawking:/etc/tinc/private/hosts/hawking
Subnet = 172.16.50.31/32
Somewhat confusingly, you need a “hosts” entry for yourself. Above is what you start with. Each host also needs a keypair which you can generate with:
# tincd -n private -K4096
with /etc/tinc/private/rsa_key.priv
getting the private key and the public key being appended to the hosts/hawking
file:
Subnet = 172.16.50.31/32
-----BEGIN RSA PUBLIC KEY-----
MIICCgKCAgEAzSd5V91X6r3NB3Syh2FV8/JC2M7cx6o2OKbVzP6X5SFPI1lEH1AD
7SfIlQF4TE++X8RcpJaBi4KjMS/Ul36Tuk75eKA18aNTBoVqH/ytY0BipQvJ6TUd
BEkCjYrOUHFYOQn8MxQzziG6nk9tvhTWS0yKCNbd68e5i9uyKOem3R/pJsd/Kh9V
wdVB51Wxs1Sv07OYmGYyRmGWh450wBNEmQfPHmM60Yh6uoQNJ0Ef41k1ZcswWcfO
0jp9EOvbW/ZCdBW6teIYZ3GMuMB/cFj0Dw2fx6dHNHZVZrPcivt0cuOG8L4jNoHj
HQUGuzMrpDN8N1ymM/eDlx+kBFYreKiEYGoWWqlZPNoY+bCekMrNf6Sr9bBwbj23
xmY1jf6v1LkxGtOi4wWJfbU4xaMnquIRQe6FtB4LHp29l2SYWcpZnjuLcZ4ZoZLQ
WK4bb0bUCAI/eYb19JRnfKEwS9MhYaQhZLWAJ3xyOt9u/Kk9KV7vWApxR1f5e2KT
77A446eQU5aedm8nBDbd+WHqTdklAQ7SdRyYmbD8PoXBd3DGP6dFiURVTy8Wn4gz
Bn7PMI3zmhfCMtwq/3A/xfyjQY3qesGCmKUwTno3fhv1DScS0rS9TRxZfyxlaOB1
qjtlU79VhI0UKlha2Fv4XLshQ5dYEutpatpij0NzPYlwiQFphFQKStsCAwEAAQ==
-----END RSA PUBLIC KEY-----
These are the public identifiers of your system and indeed the remote system in your ConnectTo statement must have a copy of this in its hosts/ directory. For nets of servers we maintain them in Bazaar and share them around using Puppet. Central distribution brings its own vulnerabilities and hassles; for very small team nets we just share around a tarball :)
.
You don’t need the /32
, it turns out, but I left it in here to show you that tincd
is effectively trading around network route advertisements, not host address.
hawking:/etc/tinc/private/tinc-up
#!/bin/sh
ifconfig $INTERFACE 172.16.50.31 netmask 255.255.255.0
This gets run when the net comes up. You can do all kinds of interesting things here, but the really magic part is assigning a broader /24
network mask than that given the interface in the hosts/hawking
file. That means this interface is the route to the network as a whole (not just to a single-attached host on the other side of a point-to-point tunnel, which is what OpenVPN does, leaving the default
gateway to sort it all out). Lots of other ways to wire it of course, but one /24
in RFC 1918 land is more than enough. I’ve even heard of some people using Avahi link-local networking to do the addressing.
I could have hard coded tun0
there, I suppose, but they supply some environment variables. Much better.
Now for the California node:
einstein:/etc/tinc/private/tinc.conf
Name = einstein
AddressFamily = ipv4
Interface = tun0
Device = /dev/net/tun
That one I did need a Device entry. Not sure what’s up there; it’s a server running Stable, so could just be older kernel interfaces. Doesn’t matter.
Note again though that the tinc.conf
file doesn’t have a public IP in it or anything. Bit unexpected, but hey. It turns up in the hosts files:
einstein:/etc/tinc/private/hosts/einstein
Address = 1.2.3.4
Subnet = 172.16.50.1/32
-----BEGIN RSA PUBLIC KEY-----
MIICCgKCAgEAqh/4Pmxy5fXZh/O7NkvebFK0OP+YD8Ph7JvK8RsUn75FY3DXjCCg
VNRR+kRhnVoKVJcIAuvW7Tbs4fovWELOJbbUbKea8G+HANCgOY5F0rkJVtIAcTCL
Jg1OelAfhF6yHV4vVgcawafWiMF2CtprveHomCnOwCbGuTDwTBqaUBZ9IOLzU2bx
ArVA2No9Ks+xaaeSHejYoii3+WT58HUccntmIYkcdBa0uKZSis1XLUwdT7Evr1Ew
K54RyMMEPC0MUziYZhAA0Qqpz79EzLXAGgQeuFxLjPoW/NbAD0PEBmsdmI5odprp
t9Tx11v/UuhK2fszYKjM+DF2pYxxrKlOyus58zx5KKJQjjrzazrru5Ny0DNf/E6Y
uB2kUtt7TCmoZg2CLAbIkyGJEiK+Wy2x2mabGDgicIs422XVslz2EODSI3qqF+f6
gu+h/vYvjZxglYrL0SxTRV7wkUc+o9OVXMMYPazgPIkwnBeLrEhGL8GS4wDIYu4G
E89m9UBE0fhVPJyw4QSfdeJZ4PgpJk6SG/7koVsJqr9EZOLp53K7ipnPylUKaRLD
mcarvoDO6ybCuHUVUsLuzZZStSG8JEEe/8jb/Ex7UNBzJ14Nglqtu0aUZ/tzkrdS
nPFFhdIwlUctM7sWKVfBugEkWjs3sR+XRVsCjxMrpZX0lXzcw9vhu60CAwEAAQ==
-----END RSA PUBLIC KEY-----
This file must be on every system in the net (that has a ConnectTo
it) — it’s how the edges know where to call. So the same file is copied to hawking
:
hawking:/etc/tinc/private/hosts/einstein
Address = 1.2.3.4
Subnet = 172.16.50.1/32
-----BEGIN RSA PUBLIC KEY-----
MIICCgKCAgEAqh/4Pmxy5fXZh/O7NkvebFK0OP+YD8Ph7JvK8RsUn75FY3DXjCCg
VNRR+kRhnVoKVJcIAuvW7Tbs4fovWELOJbbUbKea8G+HANCgOY5F0rkJVtIAcTCL
Jg1OelAfhF6yHV4vVgcawafWiMF2CtprveHomCnOwCbGuTDwTBqaUBZ9IOLzU2bx
ArVA2No9Ks+xaaeSHejYoii3+WT58HUccntmIYkcdBa0uKZSis1XLUwdT7Evr1Ew
K54RyMMEPC0MUziYZhAA0Qqpz79EzLXAGgQeuFxLjPoW/NbAD0PEBmsdmI5odprp
t9Tx11v/UuhK2fszYKjM+DF2pYxxrKlOyus58zx5KKJQjjrzazrru5Ny0DNf/E6Y
uB2kUtt7TCmoZg2CLAbIkyGJEiK+Wy2x2mabGDgicIs422XVslz2EODSI3qqF+f6
gu+h/vYvjZxglYrL0SxTRV7wkUc+o9OVXMMYPazgPIkwnBeLrEhGL8GS4wDIYu4G
E89m9UBE0fhVPJyw4QSfdeJZ4PgpJk6SG/7koVsJqr9EZOLp53K7ipnPylUKaRLD
mcarvoDO6ybCuHUVUsLuzZZStSG8JEEe/8jb/Ex7UNBzJ14Nglqtu0aUZ/tzkrdS
nPFFhdIwlUctM7sWKVfBugEkWjs3sR+XRVsCjxMrpZX0lXzcw9vhu60CAwEAAQ==
-----END RSA PUBLIC KEY-----
Ok, you get the idea with the public keys, but I wanted to emphasize the point it’s the same file. This is what you need to share around to establish the trust relationship and to tell E.T. where to phone home.
The Address
entry in the hosts/einstein
files spread around is what tells edge nodes which have been configured to ConnectTo
to einstein
where the real public IP address is. You can use DNS names here, and could play dynamic DNS games if you have to (sure, further decentralizing, but). If you have a few machines capable of being full time central supernodes then you’ll have much better resiliency.
You do not, however, need to share a hosts/
file for every other node on the net! If laptop penrose
is already connected in to einstein
and has been assigned 172.16.50.142
say, and hawking
joins einstein
and tries to ping .142
, the central node einstein
will facilitate a key exchange even though neither hawking
nor penrose
have each others’ keys, and then get out of the way. Awesome.
And finally, this all works over further distributed topologies. When new nodes join the new edges and their subnets are advertised around to the rest of the net. So if central nodes einstein
and curie
are already talking, and sakharov
joins currie
, then traffic from our hawking
will reach sakharov
via eintstein
and currie
, and in fairly short order they will have handled key exchange, step out of the way, and hawking
will be communicating with sakharov
direct peer to peer. Brilliant.
Nothing stopping you from share around (or centrally managing out-of-band) the hosts/
files with the Subnet declarations and the public keys, of course; it’ll save a few round trips during initial key exchange. Up to you how you manage the trust relationships and initial key distribution.
For completeness,
einstein:/etc/tinc/private/tinc-up
#!/bin/sh
ifconfig $INTERFACE 172.16.50.1 netmask 255.255.255.0
No surprises there.
Applications
Using tinc to cross arbitrary NAT boundaries has turned out to be supremely useful. I have successfully used this from within my office, over 3G UTMS mobile broadband, at internet cafes around Australia, in airport lounges in the States, and even from beach-side resorts in Thailand. In all cases I was able to join the private network topology. In fact, I now just leave tincd
running as a system daemon on my laptop. When I need to talk to one of the file servers, I ping, and it’s there.
One surprising benefit was in getting voice-over-Jabber running again. We had some horrible regressions with audio quality during the Maverick release series of Ubuntu Linux. At one point in our diagnostics we found that the STUN algorithms for local and remote candidate IP detection were preferentially choosing localhost virtual bridges with lower route metrics than the default gateway resulting in routing loops. We brought up tinc and since both parties were on 172.16.50.x
, Empathy and Jingle chose those as the “best” network choice. Packet loss problems vanished and the audio quality really improved (it didn’t finally get resolved until we got a Natty base system, tore out the Unity stuff, and got GNOME 3 and Empathy 3.0 on board via ppa:gnome3-team/gnome3
but that’s a separate issue). And as a side-effect we’ve got some ice on our voice channel. Excellent.
I’ve since read about a number of other interesting applications. A frequent use case is not needing encryption. While most people would interpret the “private” in virtual private network as meaning “secure”, in the old days it just meant a custom routing and network topology layered over whatever the underlying physical transport was. One crew running a large farm of servers on cloud provided infrastructure struggled to enable their various distributed nodes to find and talk to each other. So they disabled the encryption layer but used tinc as a means to facilitate do IP-over-IP tunnelling and giving their sys admins a stable set of (private) addresses with which to talk to the machines. They gave a talk at FOSDEM [their slides here] about it.
Also at FOSDEM was a talk by the “Fair VPN” effort, who are looking at improving efficiency of the network when the number of nodes scales into the thousands. Some nodes are “closer” than others so presumably they should be used preferentially; you don’t really need to discover information about every other node in the network on joining, and so on. The fact that they were able to use tinc as a research platform for this is fascinating and a nice kudo.
Next steps
So I’m pretty pleased with tinc, obviously. We’ve had a very positive experience, and I wanted to put a word in. If you’re involved in network engineering or security hardening, then I’m sure they’d welcome your interest.
It would be outstandingly cool if we could work out a NetworkManager plugin to set this up on demand, but that can wait for tinc version 1.1 or 2.0. I gather they’re working on making the key exchange and configuration easier; what I showed above is obviously well thought out and flexible, but there’s no denying it’s a bit cumbersome; there are a fair number of little knobs that need to be just right. A fire-and-forget daemon cross-product with some form of automatic addressing would be brilliant. But on the other hand, when you put network and security in the same sentence there’s a limit to how much you want to happen without any direct influence over the process. As it stands now tinc strikes a good balance there, and is entirely suitable for an environment managed by properly competent sysadmins.
Tinc GUI
Android port of tinc VPN with basic GUI
Welcome to Tinc GUI for Android home page.
Tinc is an open source peer to peer VPN daemon. Find more information at http://www.tinc-vpn.org.
Tinc GUI for Android is a (slightly modified) cross-compiled version of tincd for Arm, associated with a basic GUI for daemon management.
Where to get it?
Preferred way to get Tinc GUI is via Google Play.
You may also get directly the APK for manual installation:
Tinc GUI 0.9.5
How does it work?
As this is a simple GUI around the original tincd daemon, please refer to the official documentation for the configuration.
The easiest solution is to build your configuration and store it on your external SD card. Because Android devices usually mount it with noexec flag, a new option has been added to tinc's configuration file, in order to specify the script interpreter to use for configuration scripts (instead of having them executable):
# Use sh to execute all configuration scripts
ScriptsInterpreter = /system/bin/sh
FAQ
Why does this application need SuperUser rights?
It doesn't really need them by itself (there's an option to disable it). However tincd daemon will most probably need super user rights to work properly: access to TUN/TAP device is usually restricted to root.
Do you have any configuration example?
The configuration follows standard tinc's one. For an easier start, here's mine.
It uses switch mode on CM 10.1 (thus TUN device is /dev/tun), and routes all the traffic through the VPN (using host-up file).
tinc.conf
Name = android
AddressFamily = ipv4
ConnectTo = another_peer
Device = /dev/tun
DeviceType = tap
Mode = switch
KeyExpire = 3600
Interface = tap0
PrivateKeyFile = /sdcard/tinc/vpn/rsa_key.priv
ScriptsInterpreter = /system/bin/sh
tinc-up
#!/system/bin/sh
ifconfig $INTERFACE 10.0.0.130
echo 1 > /proc/sys/net/ipv4/conf/$INTERFACE/rp_filter
hosts/another_peer
Address = another_peer.org
Subnet = 10.0.0.0/24
-----BEGIN RSA PUBLIC KEY-----
...
-----END RSA PUBLIC KEY-----
hosts/another_peer-up
#!/system/bin/sh
echo $REMOTEADDRESS
echo $INTERFACE
VPN_GATEWAY=10.0.0.254
ORIGINAL_GATEWAY=`ip route show | grep ^default | cut -d ' ' -f 2-5`
ip route add $REMOTEADDRESS $ORIGINAL_GATEWAY
ip route add $VPN_GATEWAY dev $INTERFACE
ip route add 0.0.0.0/1 via $VPN_GATEWAY dev $INTERFACE
ip route add 128.0.0.0/1 via $VPN_GATEWAY dev $INTERFACE
hosts/another_peer-down
#!/system/bin/sh
VPN_GATEWAY=10.0.0.254
ORIGINAL_GATEWAY=`ip route show | grep ^default | cut -d ' ' -f 2-5`
ip route del $REMOTEADDRESS $ORIGINAL_GATEWAY
ip route del $VPN_GATEWAY dev $INTERFACE
ip route del 0.0.0.0/1 via $VPN_GATEWAY dev $INTERFACE
ip route del 128.0.0.0/1 via $VPN_GATEWAY dev $INTERFACE
I'm getting "/dev/net/tun not found" error when starting tinc
Depending on your ROM, the path to TUN/TAP device might be different. Use the Device directive in tinc.conf to specify the correct one (eg. "Device = /dev/tun for CM ROMs).
I'm getting "Reading RSA private key file `xxx' failed" error when starting tinc
This happens when the private key can't be read for some reason. Regenerate it and copy it to the device properly.
What are the supported CPU architectures?
ARM only for the time being.
Is it working?
Used to work very well on my SGS2 i9100, under CyanogenMod 9. Now running on Nexus 4 with CM 11 (Android 4.4) without a glitch. Waiting for more feedback.
Is it free?
Yes, it's even released under GPLv3.