Since I wrote my blog post about using a WireGuard tunnel for getting IPv6 connectivity there was one thing that was bugging me immensely: having to use NAT for IPv6. 😓
My initial howto used a private network for the WireGuard VPN which led to having two translation steps: one when entering the WireGuard VPN and one when exiting. I later realized I could use the global /64
assigned to the cloud VPN endpoint for the WireGuard VPN itself and just forward all traffic to and from it on the cloud VPN endpoint. This was easy, because the address mapping was 1:1 (cloud server’s /64
⇔ WireGuard VPNs /64
). This eliminated one translation.
The second translation (i.e. the one on the OpenWRT router) is more difficult to remove. The crux of the matter is that I only have a /64
for the tunnel which means I either have to select which internal network gets to be connected or I have to “multiplex” multiple internal /64
s onto one upstream /64
.
I’ve explored three different methods for solving this:
- IPv6-PD (i.e. Prefix Delegation)
- NAT6 (a.k.a. Masquerading)
- NPTv6 (i.e. Network Prefix Translation)
I’ll try to show how to set each of them up and try to convey their pros and cons.
TL;DR
You should always consider IPv6-PD first!
Consider any other option only if:
- you have a “weird” setup or want to support an esoteric use case (like I do e.g. with too many local subnets for too long a public prefix)
- you’re willing to set up, debug and maintain a somewhat experimental configuration
- you more or less understand the tradeoffs
- all of the above!
Starting Point
I’ll assume the following has been set up:
- default OpenWRT networks named “LAN”, “WAN”, “WAN6”
- default OpenWRT firewall rules
- an IPv6 WireGuard tunnel with the endpoint on our OpenWRT router being
2000:30:40:50::2
- the remote WireGurad tunnel end point forwards the whole
to our OpenWRT router2000:30:40:50::
/64
IPv6-PD (Prefix Delegation)
IPv6-PD (i.e. prefix delegation) is basically the built-in mechanism of sharing global IPv6 addresses with internal networks. As the word “delegation” implies you give away (a portion/sub-prefixes) to “downstream” networks. This also implies that if you get a long global prefix you may not be able to partition it for delegating it to (all) your internal networks. Normally you’ll get something like a /56
from your ISP, but I only have a /64
, because I “hijacked” a cloud server’s addresses.
Setup
On the “Network > Interfaces” page edit the “WAN6” interface:
- Set “Protocol” to “static”.
- Set “Device” to “Alias interface: @wan6_wg”.
- Set “IPv6 routed prefix” to the WireGuard public prefix (i.e.
2000:30:40:50::/64
in our case). - Make sure that in the “Advanced Settings” tab “Delegate IPv6 prefixes” is enabled.
After saving and applying those settings the “Network > Interfaces” page should look like the following screenshot.
Make sure that your WireGuard interface has its address set to 2000:30:40:50::2/128
. If you have something like
(note the 2000:30:40:50::2
/64/64
) set as described in an earlier version of the previous how-to you’ll get the same /64
route for both the “WAN6” and the “WAN6_WG” interfaces. In my case packets from the “LAN” network would reach the Internet correctly, but the responses would arrive at the OpenWRT router’s WireGuard interface but never turn up in the “LAN” network. The following screenshot shows a working configuration on the “Status > Routes” page.
Pros
- simple, built-in
- devices can “directly” connect to the Internet (“no NAT, no nothin”; see below)
- middleware boxes don’t need to keep state (it’s all just routing)
- few things can break
Cons
- your global prefix needs a short enough to be useful (i.e. shorter than
/64
) - internal devices have a routable address reachable from the Internet (i.e. your firewall should deny incoming connections from the Internet by default)