OpenVPN over IPv6

Previous articles have detailed various aspects of getting IPv6 running on a home-gateway router. The aim is to migrate as much as possible towards an IPv6-only situation.

Here I cover the steps required to implement a simple point-to-point OpenVPN (SSL) VPN tunnel using PSK over IPv6 infrastructure.

One key element for me is to migrate my VPN connection to a remote host I own off IPv4 and entirely onto IPv6. This was not entirely straightforward! In fact it took hours and hours of research and experimentation to get this working. The eventual config required is not so mind-boggling. But getting there was tricky. As I’ve found out so many times before with regard to IPv6, the building bricks are lying around, but there are very few sources of information to help you stack them up. Once the steps are laid out, as you’ll see below, it’s actually pretty easy.

Migrating from what to OpenVPN IPv6?

We’re going to migrate an IPv4 OpenVPN point-to-point PSK VPN tunnel on Linux to an equivalent on native IPv6 infrastructure. We’re not trying to have an IPv4 tunnel over IPv6, nor an IPv6 tunnel over IPv4 (both of which are possible and useful in different situations). Here I aim to have an IPv6 OpenVPN SSL tunnel over pure IPv6 infrastructure.

My current VPN set up is:

  • Home gateway running Ubuntu 10.04 (Lucid)
  • Remote host running the same
  • Fixed public IPv4 and IPv6 (global) addresses on each.
  • OpenVPN point-to-point tunnel between them.
  • Simple PSK authentication.
  • Shorewall config as appropriate to OpenVPN.

To put some detail on it, there is a standard build of OpenVPN installed, with a config file such as /etc/openvpn/otherhost.conf:

remote <IPv4 address of the other host>
dev tun
ifconfig 192.168.2.22 192.168.2.1
secret topsecret.psk
comp-lzo
keepalive 60 180
ping-timer-rem
persist-tun
persist-key
user nobody
group nogroup
daemon

At the other host we’ve a similar config, without the “remote <address>” part, and with the VPN addresses specified by the ifconfig flipped around.

This all works a treat. It’s about as plain an OpenVPN config as you could really get – a simple point to point tunnel using private IPv4 addressing.

OpenVPN and IPv6

This is really where things go all over the place. My starting point was over at the OpenVPN site, looking for details on IPv6. I found that:

Is IPv6 support planned/in the works?

Currently, there’s limited support for IPv6.

Point-to-point IPv6 tunnels are supported on OSes which have IPv6 TUN driver support (this includes Linux and the BSDs). IPv6 over TAP is always supported as is any other protocol which can run over Ethernet.

When OpenVPN 2.0 is run in server mode, IPv6 is currently only supported in TAP mode, not TUN mode (Server mode IPv6 TUN support will likely be added post-2.0).

The VPN carrier connection must currently use IPv4 endpoints, however there’s a patch which can be found in the openvpn-devel archives which adds IPv6 support. This patch will probably be merged into the mainline post-2.0.

So just what do we conclude from that? It says that point-to-point works with the TUN driver. But I couldn’t find any useful information about how to set it up.

Researching further, I find that the version of OpenVPN we’re using with Ubuntu (which is the latest) has very limited IPv6 support indeed. Indeed somewhat less than the OpenVPN web-site led me to believe! Now it may well be that the problem is my inability to understand the nuances of what the OpenVPN folks are saying. But I sure couldn’t get it working with the installed, standard version.

So I then find a lot more information here, which strongly suggests that I need to use a special IPv6 payload patch to achieve what I want to achieve. Specifically it says:

in point-to-point TUN mode, OpenVPN can transport IPv6 packets with the –tun-ipv6 option. No support for configuring the IPv6 endpoints and routes from within OpenVPN either, you need to run external “up” scripts.

That implies that I could use the unpatched OpenVPN and then manual scripts. As we’ll see below, in fact I had to use the patched version and external scripts! Again, likely due to a lack of knowledge on my part. But as a network engineer, I figure if I can’t work it all out then others will be in the same predicament.

VPN addressing

With IPv6, as discussed previously, the whole notion of private and public is done away with. Or at least, the meaning is seriously changed. Since we no longer have NAT in IPv6 (due to the address space being so very large) we do not have private address ranges for use inside a NATted network. So when choosing IPv6 addresses to use on our VPN it would seem that we can use any values. Well, yes and no. Back in IPv4 we could also have used any values too, while running the risk of accidentally using addresses which do really exist in the public Internet. So it is with IPv6, where we might collide with real addresses. It’s unlikely in these early days of IPv6, but we want to avoid it.

Another point to note, as with IPv4, is security. If VPN traffic inadvertently “leaks” out of a public interface (and this is easier to achieve than you might think, particularly when you are setting things up!) then it would be good to use addresses which any compliant adjacent router will simply drop as unroutable, rather than propagate them in to the wider world. Indeed this desire to avoid “leaks” is also a reason to not simply use a chunk of IPv6 addresses out of your allocated pool. It’s not as if they are scarce – but mixing VPN addresses and public addresses so intimately is just asking for trouble. In a perfect world, then fine. But I do not live in that world. So an arbitrary addressing barrier betwen my VPN and the Internet is no bad thing.

So for this IPv6 VPN, we shall use so-called Unique Local Addresses, (Over here I touched upon Link Local addresses which are, as the name suggests, valid only within a single network.) as per RFC 4193. The history of all this is damn messy, but the bottom line is you should choose addresses in the range fd00::/8. So I will, merrily ignoring all the rest of RFC 4193, with its try-and-make-it-random stuff, use the following:

  • fd22::22 – the gateway device
  • fd22::1 – the remote host

What does good look like

What’s our definition of a working IPv6 VPN? How will I know when “it’s working”? My criteria include:

  • if I do an ifconfig I see a discrete VPN interface.
  • I can ping6 from one host to another.
  • during a ping6 I can tcpdump the tunnel interface and see clear traffic.
  • during a ping6 I can tcpdump the real WAN interface and see encrypted traffic.

Install a patched OpenVPN

As mentioned in the introduction, I ended up using a patched OpenVPN. I still believe that, based upon what the OpenVPN website says that this should not be required! But I ended up doing it. If you trust the use of a pre-built binary (I did) then it’s actually pretty easy to install. Bearing in mind that the system being used are running Ubuntu Lucid, follow these steps and you should be good to go:

  • Go to this page and have a bit of a read.
  • Towards the bottom, you should find a link that takes you to this page.
  • At the time of writing, this page only has builds for Intrepid and Karmic. And we’re Lucid. But fear not, and assume Karmic is correct…
  • As per the instructions, add the repository and signing key as per karmic.
  • Then perform the usual apt-get update followed either by a apt-get install openvpn or just a apt-get upgrade if openvpn was already installed.

And you should be all set with the required version.

Ancillary config

I’m just going to cover the IPv6-specific OpenVPN config file. I’m not going to go in to every last detail required “around the edges”. Just a few reminders:

  • You will point to your new IPv6 OpenVPN config from /etc/default/openvpn
  • You need to add the required config, just as for IPv4, to your shorewall6 config.

Core config

Here we get to the details. The configs used will actually be very similar to the IPv4 versions, with obvious changes for IPv6.

I’ll say again: I simply do not understand why the config has to be this way. Based upon the documents and info above, I should be able to put this all neatly within the OpenVPN config. But I could not, and hence the configs below reference simple ‘helper’ script to bring the tunnel up correctly.
Here is the config for the home gateway device:

local local6address_as_per_hosts_file
remote remote6address_as_per_hosts_file

# Local and remote unique-local addresses
ifconfig-ipv6   fd22::22 fd22::1
# Allow external script to be run
script-security 2
# Script to do the rest of the work...
up /etc/openvpn/helper.up

proto udp6
dev tun
tun-ipv6
secret topsecret.psk
comp-lzo
keepalive 60 180
ping-timer-rem
persist-tun
persist-key
user root
group root
daemon

And here is the referenced helper script helper.up:

#!/bin/bash
ip -6 link set tun0 up
ip -6 addr add fd22::22 dev tun0
ip -6 route add fd22::1 dev tun0

(And remember to make the script executable)

And here’s one for the remote server:

# Local and remote addresses
ifconfig-ipv6 fd22::1 fd22::22

# Allow external script to be run
script-security 2
# Script to do the rest of the work...
up /etc/openvpn/helper.up
proto udp6
dev tun
tun-ipv6
secret supersecret.psk
comp-lzo
keepalive 60 180
ping-timer-rem
persist-tun
persist-key
user nobody
group nogroup
daemon

And the helper.up for that one is:

#!/bin/bash
ip -6 link set tun0 up
ip -6 addr add fd22::1 dev tun0
ip -6 route add fd22::22 dev tun0

Again, make sure it’s executable.

Note that each makes use of names, where posible, rather than IPv6 addresses, which have been added to /etc/hosts to make everything easier to read and less prone to typos!

Static addressing

Yes, the addressing scheme is kinda static, I know. I wanted to keep this as simple as possible (which already isn’t so very simple…) and have everything point-to-point, with all routing being host-specific routing, rather than ranges. The obvious way to slightly adapt this is to allocate two IPv6 subnets within the unique-local adresses being used, and then of course adapt the helper scripts to add the route for the subnets rather than the specific hosts. I’m sure anyone who has got this far can make that change.

Success!

That’s about all that’s required. With the above config in place and the firewall set up correctly an ifconfig on the home router returns:

tun0    Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet6 addr: fd22::22/128 Scope:Global
UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
RX packets:44 errors:0 dropped:0 overruns:0 frame:0
TX packets:44 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:4576 (4.5 KB)  TX bytes:4576 (4.5 KB)
and the routing table shows two new entries:

fd22::1 dev tun0  metric 1024  mtu 1500 advmss 1440 hoplimit 0
fd22::22 dev tun0  proto kernel  metric 256  mtu 1500 advmss 1440 hoplimit 0

And if I ping6 the other VPN address I get a response! Checking with tcpdump directly on the virtual tun0 interface I see meaningful ping-like traffic. While a similar scoping of the bearer interface, eth0, shows me the expected random-looking traffic (i.e. my highly sophisticated test for “Yes, it’s encrypted”!)

2 comments to OpenVPN over IPv6