April 11, 2008

Creating a VPN with tinc

Author: Ben Martin

With tinc you can create a virtual private network (VPN) that lets you communicate between two machines over an insecure network such as the Internet with all of your traffic encrypted between the hosts on your virtual network.

Another interesting application for tinc is connecting your laptop to a Wi-Fi router at home. You might already be using WPA2 to ensure that only valid hosts can connect and communicate with your Wi-Fi router, but you might not be able to assign a fixed address to the laptop when it is connected over Wi-Fi. So if you want to connect to an SSH daemon on the laptop itself or access an NFS share on the laptop, you have to play guessing games as to which IP address the Wi-Fi router has given the laptop this time. Running tinc on the laptop and a server at home removes the guessing game -- just connect to the laptop's VPN IP address.

tinc allows you to create many VPNs per machine and bring up each one individually. The only kernel-side functionality that tinc requires is the universal TUN/TAP driver, which is likely to be available as a kernel module in your distribution's kernel package. To see if the kernel module is available, execute modprobe tun as root and check dmesg. You should see a message mentioning the TUN/TAP driver, and you will have a /dev/net/tun device. If you don't have it, you will have to compile a kernel to get it.

Packages for tinc are available for Fedora 7 but not for 8 at the moment. Ubuntu Gutsy universe has a tinc package. OpenSUSE users can use the open build system one-click install. To build from sources you will need to install the lzo, openssl, and zlib development packages or configure will fail. When building from sources you might want to set the prefix and various other paths explicitly with a command like ./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var
.

Creating a new VPN with tinc causes a new network interface to be set up. You send information over the VPN using normal kernel packet routing. For example, you might have a laptop with an IP address assigned randomly to it from the pool of 192.168.1.222 through 192.168.1.232. A server that is attached to the local network might have a static IP address of 192.168.1.221. You might choose to use the 192.168.11.0/24 subnet for the VPN, perhaps assigning 192.168.11.100 to the server and a fixed 192.168.11.7 for the laptop to use.

Now the server has two IP addresses, 192.168.1.221 assigned to the NIC and 192.168.11.100 assigned to be the VPN IP address. The laptop will get any address between 192.168.1.222 through 192.168.1.232 when it connects to the Wi-Fi router, but will always use 192.168.11.7 as its VPN IP address. If other hosts on your LAN send traffic for subnet 192.168.11.0/24 to the tinc server, they should be able to connect to any service on the laptop using its 192.168.11.7 VPN address. You will have to make sure that the laptop routes traffic back to the tincserver properly, prehaps by making the default route the tinc server.

Each virtual network that you create will have its configuration files in a subdirectory of /etc/tinc based on the network name. Having separate configuration trees based on network names like this allows you to run many VPNs without having to merge configuration files for each network. Although tinc itself does not enforce a client-server model, it is convenient to think of the laptop as a client because the server machine does not know beforehand the IP address of the laptop and thus cannot initiate the VPN connection.

The configuration files for the server are shown below. For this example I use my_home_vpn for the VPN name. It is convenient to add a name to a network in /etc/networks and use that name in your tinc configuration. Placing an entry in networks makes the output of commands like route easier to read. The tinc.conf file is trivial for the server machine; the daemon simply listens on all network interfaces for client connections to come in.

tinc will call various scripts, if they exist, to accomplish specific tasks. For example, the tinc-up script is called when a VPN connection is brought up, and tinc-down when one is taken back down again. You can use these scripts do whatever you like: change routing tables, mount and unmount NFS shares, or just pop up a message letting you know about things. Both the tunc-up and tinc-down script live in the /etc/tinc/my_home_vpn directory, with the last directory component being your nominated VPN name. The tinc-up script can be nearly identical on all hosts; the only difference is that you assign the IP address to the tinc network interface when the VPN is brought up. This is the 192.168.11.100 IP address for the server. The tinc-down script can be shared verbatim to all hosts.

There are only two hosts on this VPN: the server and the laptop. The server's configuration file must be called tincserver to match the Name parameter in its tinc.conf. The laptop host file tells tinc to route traffic to only that specific IP address to that VPN host and contains the public key for the laptop machine. You can generate the public keys for your clients when the tinc.conf file is in place by running the command tincd -n my_home_vpn -K. The public key for the laptop host file can be taken from the /etc/tinc/my_home_vpn/hosts/laptop file on the laptop machine. Likewise the public key for the server machine will be placed into /etc/tinc/my_home_vpn/hosts/tincserver on the server machine when it is generated. As these are public keys and not private keys, I find it convenient have the key present in the hosts file on both machines. A side benefit of this is that the hosts files can then be exact copies on both machines. Here are the server configuration components:

# cat /etc/networks
default 0.0.0.0
loopback 127.0.0.0
my-home-vpn 192.168.11.0

# cd /etc/tinc/my_home_vpn
# cat tinc.conf
Name = tincserver
# cat tinc-up
#!/bin/sh
ifconfig $INTERFACE 192.168.11.100 netmask 255.255.255.0
# cat tinc-down
#!/bin/sh
ifconfig $INTERFACE down

# cd hosts
# cat tincserver
Address = tincserver
Subnet = 192.168.11.0/24
-----BEGIN RSA PUBLIC KEY-----
...
-----END RSA PUBLIC KEY-----

# cat laptop
Subnet = 192.168.11.7/32
-----BEGIN RSA PUBLIC KEY-----
...
-----END RSA PUBLIC KEY-----

So much for the server. The only two files that have to change on the laptop are tinc.conf and tinc-up. The machine name changes in tinc.conf, of course, and we tell tinc to try to initiate a connection to the tincserver machine. For other configuration file directives, see the manual.

# cd /etc/tinc/my_home_vpn
# cat tinc.conf
Name = laptop
ConnectTo = tincserver
# cat tinc-up
#!/bin/sh
ifconfig $INTERFACE 192.168.11.7 netmask 255.255.255.0

When you first test the VPN you might like to run tinc in debug mode in the foreground as shown below to see if it is having troubles connecting. Pressing Ctrl-c on the console that is running tincd this way will switch tinc into a more verbose mode, allowing you to see if it is getting or sending packets.

/usr/sbin/tincd -n my_home_vpn -D

Once tinc connects you will have another network interface on your machine and a new route to get to the machines on your VPN. The network setup on the laptop when a tinc VPN connection is up and running is shown below.

# ifconfig
eth1 Link encap:Ethernet HWaddr ...
...
my_home_vpn Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.168.11.7 P-t-P:192.168.11.7 Mask:255.255.255.0
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)

# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
...
my-home-vpn * 255.255.255.0 U 0 0 0 my_home_vpn
link-local * 255.255.0.0 U 0 0 0 eth1

# ping 192.168.11.100
PING 192.168.11.100 (192.168.11.100) 56(84) bytes of data.
64 bytes from 192.168.11.100: icmp_seq=1 ttl=64 time=1.77 ms
64 bytes from 192.168.11.100: icmp_seq=2 ttl=64 time=0.659 ms

--- 192.168.11.100 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.659/1.216/1.773/0.557 ms

# ssh hachiko@192.168.11.100
...

Given the simple nature of the tinc.conf file you can use and the fact that the files in the hosts directory don't have to change between the machines, you can set up tinc for a two-host VPN fairly quickly. You can use the provided example configuration to set up a tinc VPN with a machine behind a masquerading firewall. You can also use tinc to simulate a network switch, allowing the VPN to be used with some specialized network applications. The ability to connect to services on a laptop or other mobile device that is subject to non-predictable IP address assignments makes tinc a useful tool even if the network is already secured (for example with WPA2).

Categories:

  • Networking
  • System Administration
Click Here!