⊕ 2016-01-01
tinc (there is no cabal) is an encrypted, compressed, and open-source mesh networking VPN. Simply put, it allows for indirect connections to hosts. With version 1.1 being in alpha for a long time, it is always good to take another look at why it is so interesting and why it offers so much. I also wanted to write about, specifically, version 1.1 instead of the other tutorials for tinc on the internet (which seem to completely ignore the tinc manuals and try and hack everything together) that focus only on 1.0.
I am going to attempt to stay as close to the man pages as possible, and if I stray at all from tinc standards feel free to contact me
tinc is very unique in many ways, but one of the ways to make it clear is to show a quick situational example that we will use for the rest of the write-up:
You have 3 hosts.
denver.int
: Server internal to the Denver site, behind a NAT.ny.int
: Server internal to the New York site, behind a firewall.dallas
: Server in the Dallas site that is exposed to the internet with static ip 31.3.3.7An important concept with tinc is that there is no difference between client and server, just whom to make connections with. Since tinc is meshing that would allow denver.int
and ny.int
to communicate through dallas
even though they are both behind a firewall or are in a NAT configuration. tinc also has the ability to do UDP hole punching. In fact, in our example there is a good chance that with the help of dallas
and hole punching denver.int
and ny.int
will be able to communicate directly. This of course depends on the firewall rules that ny.int
has in place.
tinc 1.1 (which has been available for years, but is considered in alpha) adds very real world cryptographic and usability benefits, choosing to adopt:
As always, before beginning our setup I highly recommend a good dose of RTFM. tinc is very easy to use and configure and leaves very little to guess work. After compiling and installing tinc 1.1 from http://www.tinc-vpn.org/download/ on all of the hosts it is time to create a network. For our fictional example we want to create a network with the name sprawl
. We will begin by logging into dallas
.
We will first initialize the sprawl
and the dallas host:
1dallas:~$ sudo tinc -n sprawl init dallas
This will initialize the network config, host config, and host keys. As a note the tinc name does not have to be the hostname, dallas
in this case, but is required to be unique within the tinc network. tinc will place these files in either /etc/tinc/sprawl/
or /usr/local/etc/tinc/sprawl/
and a quick peek into the directory should look something like this:
1dallas:~$ sudo ls -l1hp /usr/share/etc/tinc/sprawl
2-rw------- 1 200 Dec 31 17:34 ed25519_key.priv
3drwxr-xr-x 2 4.0K Dec 31 22:31 hosts/
4-rw------- 1 1.6K Dec 31 17:34 rsa_key.priv
5-rwxr-xr-x 162 Dec 31 20:49 tinc-up
6-rw-r--r-- 112 Dec 31 17:34 tinc.conf
Now we are not configuring tinc in switch mode so we just want each of these hosts to get a single assigned ip in the network. To do this we do the following:
1dallas:~$ sudo tinc -n sprawl add Subnet 10.0.1.1/32
We then want to expose the public address of the dallas node to the tinc network:
1dallas:~$ sudo tinc -n sprawl add Address 31.3.3.7
Now it's time to look at what the configuration looks like, this can be done in two ways. By using tinc directly:
1dallas:~$ sudo tinc -n sprawl edit dallas
Or just looking at the file directly:
1dallas:~$ sudo cat /usr/local/etc/tinc/sprawl/hosts/dallas
So far the configuration should look similar to the following, which has the host public keys (RSA and Ed25519) and the configuration options we set.
1Name = dallas
2-----BEGIN RSA PUBLIC KEY-----
3MIIBCgKCAQEAw0+bVYL/FVnooIFWboCIJDxX5CeOPfkckjQGAgoNJScD+9lIgChT
4SPfNOdgrIqCk8+Aq4rurgUZOHKxLRgLtNdiH6f2w1cpkNlpSxWdHvVoZns43vMe+
5mMeS6XcD8jkUp9hp8kQaJbseA5PgIYU/YAKcYrxfuGuf+UtbYA3TYu+J/Gk4JxBm
6GALKk7XcPxuTKm8H8HJTzJPBi9BumADaDQpPApLf4+Yc8HqGrH3WREtzb0ev/gbj
79Rr0AjA/4msoX1x4MYyX4ZUTeIFaWp1qmAF7zrdamLI3e17jTeQeGwRAXbl0iEaL
8CjYCIE7U8wXr/ttp4qzstBhjuIEWaOenwQIDAQAB
9-----END RSA PUBLIC KEY-----
10Ed25519PublicKey = Ur44MHR17plJjpqdnNHE5ZiBLmIOsB3ZRxYlrVIbJxH
11Subnet = 10.0.1.1/32
12Address = 31.3.3.7
tinc itself is very simple and doesn't actually handle any of the host configuration for interface management, instead you have to manually set up the tinc-up
script that gets run when tinc creates its virtual interface. I will explain some of the other scripts and their usages later.
1dallas:~$ sudo tinc -n sprawl edit tinc-up
2#!/bin/sh
3ifconfig $INTERFACE 10.0.1.1 netmask 255.255.255.0
At this point dallas
is ready to start up and begin taking connections. But first, lets get the other sites setup and their configs shared to the other hosts. The initial setup is very similar except we want to change the Subnet option and make a few other changes to fit the host:
1denver.int:~$ sudo tinc -n sprawl init denver
2denver.int:~$ sudo tinc -n sprawl add Subnet 10.0.1.2/32
Now in order to connect to dallas
we need to use the tinc ConnectTo option instead of Address:
1denver.int:~$ sudo tinc -n sprawl add ConnectTo dallas
Edit the tinc-up
script and change it to the address used in the previous Subnet option.
1denver.int:~$ sudo tinc -n sprawl edit tinc-up
Now we need to distribute the client configurations to all the hosts, this can be done manually by using the tinc options export
and import
or if you have ssh access you can use those in combination with exchange-all
to update all the configs on both hosts as follows:
1denver.int:~$ sudo tinc -n sprawl export | \
2ssh dallas.example.org -t "sudo tinc -n sprawl exchange-all" | \
3sudo tinc -n sprawl import
Now both hosts should have the same configuration files in hosts. While it is not 100% necessary to have configs for every host due to tinc's meta-connection model, I like to keep everything tidy and not throwing any warnings, so I will often run the previous one-liner across all the machines when I add a new host (tinc+ansible is very handy or even cron). As for the final host ny.int
do the exact same configuration we did for denver.int
except with Subnet giving it's own ip for the network (and in tinc-up
). I used 10.0.1.3
for ny.int
and ny
as it's Name variable for init. After that is complete it is time to get everything up and running, connect to dallas
and simply run tincd in non-daemonizing mode so we can see any errors that are produced:
1dallas:~$ sudo tinc -n sprawl start -D
2denver.int:~$ sudo tinc -n sprawl start -D
3ny.int:~$ sudo tinc -n sprawl start -D
Now we can finally test out our configuration and make sure everything is running. From denver.int
simply try and connect to ny.int
1denver.int:~$ ping -c 3 -q 10.0.1.3
2PING 10.0.1.3 (10.0.1.3) 56(84) bytes of data.
3
4--- 10.0.1.3 ping statistics ---
53 packets transmitted, 3 received, 0% packet loss, time 2000ms
6rtt min/avg/max/mdev = 91.487/91.856/92.397/0.462 ms
Congratulations you now have a very simple tinc setup. It is important to note that most people are used to VPNs that route all their traffic through as the default gateway, tinc does not do that by default. If this behavior is desired see http://www.tinc-vpn.org/examples/redirect-gateway/
tinc has a collection of scripts that if created will be run at certain points of VPN events. You have already used the tinc-up
which runs when tinc starts up. This is incredibly useful and makes tinc even more powerful, some of the available scripts are:
tinc-up
: Will be executed right after the tinc daemon has been started and has connected to the virtual network device.tinc-down
: Started right before the tinc daemon quits.host-up
: Started when any host becomes reachable.hosts-down
: Started when any host becomes unreachable.hosts/$HOST-up
: Started when the tinc daemon with name $HOST becomes reachable.hosts/$HOST-down
: Started when the tinc daemon with name $HOST becomes unreachable.subnet-up
: Started when a subnet becomes reachable. The Subnet and the node it belongs to are passed in environment variables.subnet-down
: Started when a subnet becomes unreachabletinc also sets environmental variables, like $INTERFACE in the tinc-up
examples. The variables that get defined by tinc are:
NETNAME
: Network name.NAME
: Name of the tinc daemon.DEVICE
: Virtual device tinc is using.INTERFACE
: Virtual interface tinc is using.NODE
: Set when a host or subnet is started (NODE is owner of subnet in the latter case).REMOTEADDRESS
: Real address.REMOTEPORT
: Port number being used.SUBNET
: The subnet being used.WEIGHT
: The subnets weight.It should also be pointed out that tinc inherits environmental variables, which means that you can use shell variables inside of configuration files. The best example is the Name variable. If you set Name to $HOST it will resolve that variable for tincs use (Name is also unique in that if $HOST is not set it also gets resolved through a call to gethostname();
).
For a full list of commands used on each host in the example see the following files: