Bringing the IPv6 Internet to the IPv4-only land of NAT
WireGuard bringing IPv6 to NATland
The evil of NAT (Net Address Translation) has become institutionalized. And because NAT munges the network header, it causes all sorts of problems, including preventing simple IPv6 tunneling (6in4).
But go to any Starbucks, McDonald’s, the airport or even the Library, and you will find yourself on a NATted network. How to get on the IPv6 Internet when stuck behind NAT? Enter the VPN (Virtual Private Network).
VPN tunneling IPv6
Most people use VPNs make it appear they are in a different location, or are looking for the extra security. But most (99%) VPN providers only support IPv4, and in fact, either disable IPv6, or ask you to do so to prevent IPv6 leakage.
But what if you could use a VPN to transport IPv6 traffic to the IPv6 Internet (now over 25% utilization). I looked at OpenVPN, for this purpose, but found all the moving parts (Certs, pushing routes, lack of IPv6 examples) daunting. If you have a working OpenVPN setup, you may find it easier to tunnel IPv6 through it.
Wireguard, the easy VPN
Wireguard is getting a lot of buzz these days, as it is much easier to setup than OpenVPN. It works similar to
ssh keys. Create public/private key pair, for each node in the VPN, tell the each nodes the remote node IPv4 address, and connect! Wireguard is very good at making a complex VPN thing into a simple setup.
But the typical Wireguard VPN only has a roaming laptop at the far end. I wanted to share the IPv6 goodness with my friends, which meant that I wanted to have an entire IPv6 subnet available in IPv4-only NAT-Land.
Using OpenWrt to share IPv6 in NAT-Land
OpenWrt to the rescue. OpenWrt is an open source router software than runs on hundreds of different types of routers. And Wireguard is a package that is prebuilt for each of those routers. There’s even a friendly web GUI frontend to configure Wireguard! What’s not to like.
The network (above) shows the highlevel design. Allow IPv4 traffic to follow the usual NAT-Land path to the IPv4 Internet (via the Evil NAT Router). But push the IPv6 traffic through the Wireguard Tunnel, where there is another router which will forward it onto the IPv6 Internet. This is called split tunnel in VPN parlance.
The advantages of this topology are:
- IPv4 traffic follows the usual NATted path, no change there
- End stations (to the left of R1) require no special software configuration to use it
- Rather than just keeping the IPv6 to yourself, you can share the IPv6 goodness with anyone connecting to R1 router
The last point means you can bring IPv6 networking into the unfriendly IPv4 NAT-Land world, and show people there is a better way (like a 4K TV). Training is the obvious application, but there are other applications such as transitional networks, and better security.
Before we get too far, you will need an address plan. Since IPv6 will need a network for each link (almost, we’ll use link-local for the point-to-point link), we need a plan so that packets can be routed down to R1 at the far end of the WireGuard VPN from the internet.
Since I am routing the VPN tunneled IPv6 packets through my house, I will need more than a /64 from my ISP. Fortunately, I have a /48. The address plan should look something like this:
- ::/0 The Internet
- 2001:db8:ebbd::/48 My House Network
- 2001:db8:ebbd:9900::/56 my DMZ Network
- 2001:db8:ebbd:9908::/62 the LAN ports of R2, which are unused, but DHCPv6 allocates them automagically
- 2001:db8:ebbd:990a::/64 the LAN ports of R1, which is out in NATland
Assuming you are running a DMZ, and an internal LAN, you are going to need at least 3 /64 networks. Therefore if your ISP provides a /60 you have enough, and if they give you a /56, you have plenty to do other IPv6 projects as well.
Installing Wireguard on OpenWrt
The easiest method is to use the Web GUI to install software on the router. But it can also be done via the CLI, after ssh-ing to the router.
opkg install luci-app-wireguard
luci-app-wireguard is for the web GUI, but it also pulls in the kernel module which does most of the work
wireguard-tools which contains the CLI interface.
After installing wireguard, use the CLI tool
wg to create a private/public key pair. This command does both in one easy line
wg genkey | tee privatekey | wg pubkey > publickey
Just like when using ssh private/public keys, the private key is private. It never leaves the system it was created on. Whereas the public key can go anywhere, including publishing it on the internet!
Configuring Wireguard on OpenWrt
- Add a new interface called WGNET. This is quite easy using the OpenWrt LuCI Web GUI. Under Network->Interfaces, scroll to the bottom and click on the Add New Interface button.
- Add Private Key and Listening Port to WGNET
- Add a Peer, including the Peer’s public key and IPv6 Address. I used a Link-local address
- Click Save & Apply
- Click Connect WGNET
With any luck, WGNET will connect to the peer.
On the router using the
wg show command to show the state of the connection. It should look something like this:
root@makiki:~# wg show
public key: E/2sXvSeg8cggZhJvDOn22z5HqV+eSDduOw46BwBzww=
private key: (hidden)
listening port: 29998
allowed ips: ::/0, fe80::/64
latest handshake: 1 minute, 46 seconds ago
transfer: 1.05 MiB received, 1.03 MiB sent
persistent keepalive: every 25 seconds
The key info is the latest handshake. If that isn’t there, then the VPN isn’t up, and you will need to go back and re-check your configuration.
The OpenWrt GUI also has this information under Status->WireGuard Status. (if it is blank, the VPN link isn’t connected)
Setting up DHCPv6-PD
But getting the WireGuard VPN link up is only half the fun. You will quickly discover that you can’t ping6 from a host connected to the R1 LAN ports (and wireless) for two reasons:
- the hosts on that LAN don’t have GUA (Global Unique Address) yet
- There is no return route down to the R1 LAN (see address plan above)
Advertising RAs on the LAN and creating a DHCPv6 Client
The WireGuard interface is just an interface. We must use a stacked interface to run a DHCPv6 client on top of the WGNET interface. Create yet another interface on Router R1, called LAN6.
Select DHCPv6 Client as the interface type, and WGNET as the underlying interface. Then select Request IPv6-prefix length of 64 Click save and apply. Once the DHCPv6 client gets a Prefix Delegation from R2, the R1 LAN hosts will receive GUAs.
Setting up a DHCPv6-PD server on the upstream router
By configuring a DHCPv6-PD server on R2, not only will a PD be sent down to R1, but a route will be automagically installed on R2 pointing down to the Hosts attached to R1.
Configuring a DHCPv6-PD server on R2 is similar to the procedure on R1, In the web interface, Network -> Interfaces -> Add New Interface, create LAN_WG over the WGNET interface as a type Static Address. Then edit the following blanks:
- IPv6 Assignment length: 63
- IPv6 assignment hint: 990a, but you can try leaving this blank
Lower on the page, select the IPv6 Settings tab, and configure the following:
- Router-Advertisment-service: server mode
- DHCPv6-Service: server mode
- NDP-Proxy: disabled
- DHCPv6-Mode: stateless + stateful
Click save and apply.
Advantages of DHCPv6-PD
The advantage of using DHCPv6-PD is that it will automagically update the addressing if your ISP changes your prefix. All your hosts will automatically pick up the new prefix, and will still have connectivity to the IPv6 Internet.
What if your remote location is not static? What if the Evil NATland router changes your port? How can you fill in the Peer IP address and port if you have unpredictable NAT changing things on your?
I am still working on it. The real solution would be to leave the Peer IP and Port info blank, and let WireGuard figure it out. But alas with OpenWrt 18.06.1 that doesn’t work.
As a work-around, I have created a script for R2 which listens for the Peer, and reconfigures the R2 WireGuard IP and Port info dynamically. The script is on github.
Although WireGuard works quite well at tunneling IPv6 through multiple layers of NAT, it is not without its limitations.
- Network blocks UDP. Wireguard uses UDP as transport, and therefore won’t connect (there is no TCP option)
- Network Latency. Anytime you tunnel IPv6 inside of IPv4, the network latency of IPv6 will never be less than that of IPv4. Therefore the performance of IPv6 will not be shown at its best.
IPv6 Oasis in the desert sands of NAT-Land
A tunneled IPv6 connection is always less desirable than a native one, but using WireGuard does allow one to use IPv6 when stuck in the deserts of IPv4 NAT-Land. And by using it with OpenWrt, the Oasis just got roomy enough to share with your friends.
Article (with more detail) originally appeared on www.makikiweb.com