IPv6 everywhere with tinc

Some time ago I described how to use 6to4 to provide a stable IPv6 connection for a host having a fixed, public IPv4 address, a really simple procedure (at least in its basic configuration) which allows us to access a new Internet with abundance of addresses where everyone can offer their own services.

However, the procedure is something of an entelechy since a host which has a fixed, public IPv4 address is already capable of offering services to the Internet. However, what about our home computers sitting behind a NAT device (thus with private addresses), or those we carry with ourselves (thus with dynamic addresses)?

In this article I describe how to use tinc to extend IPv6 connectivity from a host with its own (native or 6to4) IPv6 network into home and mobile devices, so that they have publicly accessible addresses in this network regardless of their location.

Network topology

Tinc is free/libre software used for building virtual private networks (VPN) which stands out from other VPN products in that it greatly eases setting up networks of a distributed topology with no need for central nodes doing routing or authentication. Each tinc node defines its own subnet and the system takes care of propagating the needed routes and keys for communication to take place in a direct (if possible) and secure way between nodes which don't explicitly know each other.

We'll assume that we have a so-called gateway node with a fixed, public IPv4 address and its own IPv6 network. To continue the example in the previous article, these will be and its associated 6to4 network 2002:0102:0304::/48 (but it may be any other public IPv6 network). We'll also assume that the rest of nodes have no connection to the IPv6 Internet nor fixed, public IPv4 addresses.

We'll set tinc up so that each node in the network gives access to its own subnet 2002:0102:0304:N::/64 (with N = 0 for the gateway). Nodes shall connect to the gateway, which shall thus connect all subnets together and provide access to the IPv6 Internet to those nodes which choose the tinc network as their default route.

IPv4 and IPv6 networks.

Please note how each node shall have the same address both in the tinc and local networks, something we achieve by using two different network masks. In this sense, the manual is a mix of this example and this article.

Gateway configuration

For setting the gateway with Debian or similar, in the first place we'll install package tinc. Next we'll create the directory /etc/tinc/inet6 which will hold the configuration files for our network, which we shall call inet6 here (tinc can manage several ones).

Now we'll create tinc's server configuration file for this node, /etc/tinc/inet6/tinc.conf:

AddressFamily = ipv4
BindToAddress = 655
Name = gateway

The only option actually necessary is Name, here setting this node's unique name in the tinc network to gateway. The AddressFamily option restricts tinc to always using IPv4 connections, something reasonable for providing IPv6 on top of it. The options BindToAddress fixes the address and port (TCP and UDP, default 655) where tinc will listen, and it can be useful if the gateway has multiple IPv4 addresses or if we're going to manage more than one network with tinc, since each one needs a different port.

For any two tinc nodes to connect in a secure way both must know beforehand their respective names and public keys, as well as the subnets they provide access to. If a node wants to connect to another, it will need to know the address and port where the other tinc server listens. Each node defines all these parameters in a host configuration file which must be copied to the nodes it wants to connect to.

Next we'll create the gateway's host configuration file, /etc/tinc/inet6/hosts/gateway. We'll need to create the hosts subdirectory first taking care that we use for the file the same name given above in Name.

Address = 655
Subnet = 2002:0102:0304:0000:0:0:0:0/64
Subnet = 0:0:0:0:0:0:0:0/0

Of course the values in Address are those given far above. The announced subnet is 2002:0102:0304:0000::/64 (tinc doesn't support compact notation) as shown in the diagram, as well as ::/0, i.e. the whole IPv6 Internet.

We'll complete this file with the node's public key, which we'll generate by running tincd -n inet6 -K and accepting the default answers. This will add a BEGIN/END RSA PUBLIC KEY block to the end of file.

Tinc doesn't automatically add any address or route to the host, instead it leaves the task to some network configuration scripts. In our case, assuming that the gateway already has set its IPv6 interfaces and routes up, we'll create the following scripts /etc/tinc/inet6/tinc-up

ip -6 link set "$INTERFACE" up mtu 1400
ip -6 addr add 2002:0102:0304:0000::1/48 dev "$INTERFACE"

and /etc/tinc/inet6/tinc-down

ip -6 addr del 2002:0102:0304:0000::1/48 dev "$INTERFACE"
ip -6 link set "$INTERFACE" down

that shall run when starting and stopping tinc's inet6 network (don't forget to make them executable with chmod a+rx SCRIPT). Please note how the maximum IPv6 datagram size (MTU) is limited to 1400 bytes: we take into account the overhead added by 6to4 (in our case) or tinc to reduce the chance of coming across problems during the discovery process of the MTU between two IPv6 hosts. The safest (and slightly less efficient) value is 1280. Please read this article for further information.

Finally we'll add inet6 to file /etc/tinc/nets.boot, which lists networks automatically started by tinc's init script, and we'll start it by running invoke-rc.d tinc restart. This completes the configuration of tinc itself.

If the gateway runs a firewall we'll still need some final touches. Since it will receive connections from other tinc nodes it's important that we open the TCP and UDP ports given above with rules that equal the following commands:

# iptables -A INPUT -p udp -m udp --dport 655 -j ACCEPT
# iptables -A INPUT -p tcp -m tcp --dport 655 -j ACCEPT

The gateway shall also route IPv6 traffic, so we'll need to allow IPv6 forwarding in the firewall with the rule equivalent to:

# ip6tables -P FORWARD ACCEPT

We'll also need to enable IPv6 forwarding in the kernel via sysctl, for instance:

# cat > /etc/sysctl.d/local-forwarding.conf << EOF
# sysctl -p /etc/sysctl.d/local-forwarding.conf

Other nodes' setup

As we saw before tinc is a distributed system, thus there are no servers and clients, only nodes which connect between themselves. In our case nodes without fixed, public IPv4 addresses will initiate connections towards the gateway node. But as we'll see configurations are nearly the same.

We'll install tinc and create directory /etc/tinc/inet6. We'll write the following server configuration file /etc/tinc/inet6/tinc.conf:

AddressFamily = ipv4
BindToAddress = * 655
Name = my_pc
ConnectTo = gateway

Since this node shall initiate connections to others (and not the other way round) the address where tinc shall listen doesn't matter (thus the *). Nonetheless, since each tinc network needs a different port it's still OK to make it explicit, and in our case we'll be using it later. Once again the name (my_pc) of this node is most important here, as well as appearances of ConnectTo options which indicate to which nodes (by their name) connections shall be initiated.

We'll create the host configuration file /etc/tinc/inet6/hosts/my_pc with the subnets that this node shall provide access to

Subnet = 2002:0102:0304:0004:0:0:0:0/64

and we'll invoke tincd -n inet6 -K to create node keys. By the way, if we only want to give access to this host we can use a /128 mask, e.g. 2002:0102:0304:0004:0:0:0:1/128.

Since we'll connect to the gateway node, we'll need to copy into its hosts directory this node's host file, as well as copy into this node's hosts directory the gateway's host file. Sharing host files can be the most obnoxious step in setting up a tinc network, and if we have lots of nodes with a complex connection topology the simplest way may be to provide all host files in the network together (e.g. by using some distributed version control system), which may also help in deciding unique new names and subnets.

Network configuration scripts will only differ from the gateway's (besides the assigned address, of course) in that they'll add a default route to the IPv6 Internet via the tinc network. Thus /etc/tinc/inet6/tinc-up:

ip -6 link set "$INTERFACE" up mtu 1400
ip -6 addr add 2002:0102:0304:0004::1/48 dev "$INTERFACE"
ip -6 route add default dev "$INTERFACE"

and /etc/tinc/inet6/tinc-down:

ip -6 route del default dev "$INTERFACE"
ip -6 addr del 2002:0102:0304:0004::1/48 dev "$INTERFACE"
ip -6 link set "$INTERFACE" down

Please note that there's no default gateway address given, only the interface where the packets shall be sent to. On packet reception, tinc takes care of locating the node that provides access to the proper destination subnet (and remember that the gateway node announces ::/0).

After enabling script execution with chmod, we'll add inet6 to /etc/tinc/nets.boot and restart tinc with invoke-rc.d tinc restart. Past a few seconds we shall be able to ping the gateway:

$ ping6 2002:0102:0304:0000::1
PING 2002:0102:0304:0000::1(2002:102:304::1) 56 data bytes
64 bytes from 2002:102:304::1: icmp_seq=1 ttl=64 time=141 ms
64 bytes from 2002:102:304::1: icmp_seq=2 ttl=64 time=141 ms
64 bytes from 2002:102:304::1: icmp_seq=3 ttl=64 time=142 ms
64 bytes from 2002:102:304::1: icmp_seq=4 ttl=64 time=142 ms

--- 2002:102:304::1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 141.617/142.174/142.737/0.505 ms

If there is any problem have a look at /var/log/daemon.log. If it works you can test your connectivity with the rest of the IPv6 Internet visiting or (:D), or where you can provide your address and get it pinged. Remember that your computer will be publicly accessible through IPv6, so you'd better prepare a good firewall configuration. And regarding firewalls, if you're going to provide access to more computers on your local IPv6 network, remember to enable IPv6 forwarding in your firewall and kernel as described before.

Direct connection on the local network

If you have a look at the network diagram you'll see that my_laptop is in the same local network as my_pc. However, since they aren't accessible from the Internet whenever they want to communicate on the IPv6 network, traffic must go through gateway, which isn't too efficient. Tinc 1.0.17 or above allows looking for known nodes in the local network, avoiding unneeded hops while keeping traffic security. This can be interesting in local WiFi networks with no encryption.

To enable this lookup we'll include the option LocalDiscovery = yes into the node's tinc.conf. This will make tinc broadcast on the local network UDP packets addressed to the port specified in that file (that's why fixing the value of the port in there is convenient), which means that this mechanism will only work if all nodes in the local network use the same port.

Of course we'll need that contacted nodes keep this port open in the firewall and that nodes to connect to have the others' host files. Once again, the simplest way is for all nodes to have the host files of all nodes in the network.


[...] IPv6 everywhere with tinc we saw how to use a tinc VPN to let a host with its own public IPv6 network provide entire [...]