Tinc is another VPN daemon, secure, reliable, easy to use and easy to deploy. Lot of people tell me about this one to create distributed and decentralized VPN across different servers, and, honestly, I have not tried before. Easier to deploy and manage than IPsec, this is a really nice tool, and probably a must have on your server! So, a feature lists from official website (opens new window):

  • Encryption, authentication and compression
  • Automatic full mesh routing
  • NAT traversal
  • VPN Expansion
  • **Bridge ethernet segment **
  • IPv6 support and lot of environment

I will use tinc to create a meshed network on all my servers, OpenVPN can’t do that easily, and IPSec is really hard to deploy. Each of my servers will be in interconnection dedicated network one-by-one.

# Install Steps

tinc is ported on OpenBSD and FreeBSD system since a long time! You can install it with pre-build packages or install it from sources.

\# install tinc on OpenBSD  
pkg_add tinc

\# install tinc on FreeBSD  
pkg install tinc

If you want to build with your own feature and compiler flags, you can also use ports tree:

\# on OpenBSD  
cd /usr/ports/net/tinc  
make && make install

\# on FreeBSD  
cd /usr/ports/security/tinc  
make && make install

# Layer 2 Network Configuration

On OpenBSD, default configuration directory is located in /etc/tinc . A tinc configuration is a directory containing all required information to start tincd and let this one connect to remote endpoint. In our example, I will create a new tinc configuration named tunnel and create at the time the hosts directory which will contain information about each hosts.

# creating main tunnel configuration  
cd /etc/tinc  
mkdir -p /etc/tinc/tunnel/hosts

We can now configure the main tinc daemon configuration file, named tinc.conf . This one will contain the name of the tinc instance, all remote hosts to connect to, the device used to map each configuration, finally, for our example, the mode, in our case, in switch mode (L2).

# tinc.conf is the main configuration file  
# for the daemon  
touch /etc/tinc/tunnel/tinc.conf  
cat >> /etc/tinc/tunnel/tinc.conf << EOF  
Name = apoint  
ConnectTo = bpoint  
Device = /dev/tap0  
Mode = switch  
EOF

When tinc start, it execute tinc-up script. You can use it to initialize your interface…

# tinc-up script, used when tunnel is started  
touch /etc/tinc/tunnel/tinc-up  
cat >> /etc/tinc/tunnel/tinc-up << EOF  
#!/bin/sh  
ifconfig \\${INTERFACE} inet 172.16.0.1/30 up  
EOF

Tinc down script

# tinc-down script, used when we stop tunnel  
touch /etc/tinc/tunnel/tinc-down << EOF  
#!/bin/sh  
ifconfig \\${INTERFACE} down  
EOF

a point host configuration

# apoint host configuration  
# public key is automatically generated  
# in another step  
touch /etc/tinc/tunnel/apoint  
cat >> /etc/tinc/tunnel/apoint << EOF  
Address = ${apoint_address}  
Subnet = 172.16.0.0/30

\-----BEGIN RSA PUBLIC KEY-----  
...  
\-----END RSA PUBLIC KEY-----  
EOF

bpoint host configuration

# bpoint host configuration  
# public key must be imported from bpoint  
touch /etc/tinc/tunnel/bpoint  
cat >> /etc/tinc/tunnel/bpoint << EOF  
Address = ${bpoint_address}  
Subnet = 172.16.0.0/30

\-----BEGIN RSA PUBLIC KEY-----  
...  
\-----END RSA PUBLIC KEY-----  
EOF

We have now all our configuration, we can generate our key pair for our local server apoint .

# generate key  
tincd -n tunnel -K

If everything is okay, we can now start tincd in standalone and debug mode, see network traffic and other information.

# Start tinc standalone in debug mode  
tincd -n tunnel -Dd5

If something goes wrong, we can take a look on all network flow with tcpdump:

# We can also check with tcpdump is everthing is okay  
tcpdump -i ${interface} tcp port 655 or udp port 655

You can also look in route table

netstat -rnf inet  
route show

Packet Filter configuration

# Configure packet-filter  
mkdir -p /etc/pf.conf.d/tables  
touch /etc/pf.conf.d/tables/tinc  
echo "${apoint_address}" >> /etc/pf.conf.d/tables/tinc  
echo "${bpoint_address}" >> /etc/pf.conf.d/tables/tinc  
cat >> /etc/pf.conf << EOF  
set skip on tap  
table <tinc> counters persist file "/etc/pf.conf.d/tables/tinc"  
pass quick proto {tcp, udp} from <tinc> to port 655  
EOF

We can try to execute now pf.conf .

# check if our packet-filter configuration  
# is well written and start it  
pfctl -nf /etc/pf.conf  
pfctl -f /etc/pf.conf

Now, we can set tinc at startup… A good way to protect our services is to isolate everything. In our case, tinc can run with privilege separation (fortunately, OpenBSD create _tinc user for this task) with -Uargument. Tinc can also start in a chroot environment, locked in their own configuration directory with -R argument.

# enable tincd at startup  
rcctl enable tincd   
rcctl set tincd flags "-n tunnel -U _tinc -d1 -R"  
rcctl start tincd

# Layer 3 Network Configuration

# Monitoring Tunnel

I like simple tools but when we talk about monitoring and supervise services… It’s really hard to find a good solution. In my case, I like monit. A simple daemon, polling service and execute and action if something happen. Let see how to configure it.

# Resources