Tinc

Tinc is a self-routing, mesh networking protocol, used for compressed, encrypted, virtual private networks. This howto is intended as a guide to document some of the Tinc on OpenWrt specifics the author stumbled on and struggled with in hopes it saves others time and effort.

Tinc normally makes use of a series of files and directories under /etc/tinc/ for it's configuration. On OpenWrt much of configuration has been moved into the uci system into the file located at /etc/config/tinc. The OpenWrt Tinc init script will use the contents of the tinc uci config along with files in the /etc/tinc directories to generate a full Tinc configuration located under /tmp/tinc.

The Tinc UCI config file contains two types of sections: tinc-net and tinc-host.

The tinc-net sections start with config tinc-net NETNAME followed by options that match the options described in tinc.conf.5 / tinc with the exceptions of an enabled option and a few for command line options. The NETNAME will be mapped to /etc/tinc/NETNAME and the values in that section will be used to generate the equivalent of the /etc/tinc/NETNAME/tinc.conf file. While use of UCI this way can configure Tinc, you'll find it much less painful in the long run to make minimal use of the UCI methods to configure Tinc.

The tinc-host sections start with config tinc-host NODENAME followed by options that will be used to generate the Tinc host files normally located at /etc/tinc/NETNAME/hosts/NODENAME. UCI doesn't seem to have a place to hold the public keys that go in a host config file so you will still be expected to have files with public keys at /etc/tinc/NETNAME/hosts/NODENAME but the other values from the UCI section will be combined when a host file is generated under /tmp/tinc/NETNAME/hosts/NODENAME. Again, prefer Tinc's node configuration method when you can.

UCI also does not store the helper scripts such as tinc-up or NODENAME-up that are normally found in /etc/tinc/NETNAME and /etc/tinc/NETNAME/hosts so you will have to create them and store them there. Make sure they are executable.

The following helped this author have a more reliable coexistence between Tinc and the OpenWrt web interface managed Network/Firewall settings. The info below is based on my experience setting up Tinc to let me route between private LANs.

Because the network management of UCI may tear down and build up the network or firewall settings I found it advantageous to use the Networking/Firewall UCI settings as applied to the Tinc created interfaces as much as possible to prevent unexpected Tinc VPN failures. That said, it still isn't 100% reliable for me yet when making significant network changes. Reboot and verify changes come back online as expected.

I've evolved my tinc scripts into the four mostly generic scripts below. You can get away with less but for routing between networks, these work with minimal thought.

NETNAME="vpn"
 
cat << "EOF" > /etc/tinc/${NETNAME}/tinc-up
#!/bin/sh
NETADDR="$(uci get network.lan.ipaddr)"
ip address add ${NETADDR} dev ${INTERFACE}
EOF
 
cat << "EOF" > /etc/tinc/${NETNAME}/tinc-down
#!/bin/sh
ip link set dev ${INTERFACE} down
EOF
 
cat << "EOF" > /etc/tinc/${NETNAME}/subnet-up
#!/bin/sh
NODENAME="$(uci get tinc.${NETNAME}.Name)"
if [ ${NODE} != ${NODENAME} ]
then ip route add ${SUBNET} dev ${INTERFACE}
fi
EOF
 
cat << "EOF" > /etc/tinc/${NETNAME}/subnet-down
#!/bin/sh
NODENAME="$(uci get tinc.${NETNAME}.Name)"
if [ ${NODE} != ${NODENAME} ]
then ip route delete ${SUBNET} dev ${INTERFACE}
fi
EOF

Unlike some some Tinc howtos for other distributions I did not have any iptables rules in the tinc-up script. The uci get network.lan.ipaddr will extract the IP address of your LAN interface. If you've renamed this interface or want something else, change here.

The uci get tinc.NETNAME.Name extracts this host's name from the tinc config. You need to know this so the subnet-up script doesn't run to add a subnet for itself because that already exists. Versions of tinc newer than 1.0.19 have a better way around this but I don't recall at the moment.

NOTE: I (user mbello, not the author of this guide) followed this entire guide and it worked brilliantly except for this uci get tinc.NETNAME.Name command, I had to replace it with netname.

Instead I went into the OpenWrt LuCI web interface and under Network > Interfaces I Added a new interface… which I named NETNAME that was of Protocol unmanaged and covered the NETNAME interface. This makes UCI aware of the Tinc network interface but it shouldn't try to manage it.

Then, under Network > Interfaces > NETNAME > Firewall Settings I created or assigned the zone of vpn.

Next, under Network > Firewall > General Settings > Zones you can edit the vpn zone to enable Inter-Zone Forwarding to/from your lan zone.

Finally, under Network > Firewall > Traffic Rules you'l need to open the port Tinc is using, 655 by default. The summary table for me reads: Tinc-[NETNAME] | Any TCP, UDP From any host in wan To any router IP at port 655 on this device | Accept input

NOTE: I (user mnlipp, neither the author of this guide) had problems (using Chaos Calmer) with the coexistence of the unmanaged interface NETNAME (really nice to have in LuCI) and tinc managing that same interface. An unmanaged interface isn't completely unmanaged - it is created. There seems to be a conflict (or race condition) between netifd trying to create the interface and tincd attempting to do the same. Although the interface had been configured properly by tinc-up (I logged he results), I always found my INTERFACE to have no address at the end of the boot.

I think that tincd is faster than netifd and the latter overwrites the settings of the former by re-creating the interface. I could solve the problem by adding at the beginning of my tinc-up script:

ubus -t 15 wait_for network.interface.INTERFACE

NOTE: I (user mnlipp, neither the author of this guide) found that things stopped working with OpenWrt 21.02 (probably 21.0, but I didn't try that).

If you want to be compatible with the new network configuration (using interfaces and devices) you have to take a different approach. I don't know if this is the intended approach, so I'll keep the explanation to a rough sketch.

  • Create and configure a new bride device called br-NETNAME, make sure to check “Bring up empty bridge”.
  • Configure DeviceType = tap for your network.

The job of the up/down scripts is now to attach/detach the tap device to/from the bridge.

NETNAME="whatever"
 
cat << "EOF" > /etc/tinc/${NETNAME}/tinc-up
#!/bin/sh
# Note that PWD happens to be the networks configuration directory,
# but this is not documented
BRIDGE=br-`basename "$PWD"`
 
while ! brctl show $BRIDGE 2>/dev/null >/dev/null; do
  sleep 1
done
 
brctl addif $BRIDGE $INTERFACE
ip link set $INTERFACE up
EOF
 
cat << "EOF" > /etc/tinc/${NETNAME}/tinc-down
#!/bin/sh
# Note that PWD happens to be the networks configuration directory,
# but this is not documented
BRIDGE=br-`basename "$PWD"`
 
brctl delif $BRIDGE $INTERFACE
ip link set $INTERFACE down
EOF
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2021/10/10 13:41
  • by mnlipp