This article is part of a series of how I built a WireGuard tunnel for getting IPv6 connectivity. Where the last step was to figure out how to route packets from devices in my private network through the WireGuard tunnel to the Internet.
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 WireGuard tunnel end point forwards the whole
to our OpenWRT router2000:30:40:50::
/64
NAT6 a.k.a. Masquerading
NAT6 is basically a rehash of the “the old way” of using NAT for the IPv4 Internet. The router/gateway replaces the internal source (i.e. sender) address of a packet going out with its own public address. The router makes note of original sender and recipient to be able to reverse the process when an answer comes back. When the router receives a packet it forwards it to the actual recipient by replacing the destination address with the internal address of original sender.
Setup
On the “Network > Interfaces” page edit the “WAN6” interface and set “Protocol” to “unmanaged”. Then follow the OpenWRT NAT6 and IPv6 Masquerading documentation.
In my tests the masq6_privacy
setting had no impact. All outgoing packages always had an address of 2000:30:40:50::2
(i.e. the router’s WireGuard interface address). 😕 It seems using WireGuard interferes with OpenWRT’s ability to generate temporary addresses for the interface. No amount of fiddling (e.g. setting addresses with /64
, suffixes to “random”, setting prefix filters, setting a delegatable prefix, but disabling delegation, … I really got desperate) on the “WAN6_WG” interfaces’ settings or creating a “WAN6” alias and doing the same to it made the temporary addresses work. 😵 You could manually add addresses with random suffixes to the WireGuard interface … maybe even write a script that changes them periodically … 😅😐😞
Pros
- multiple internal networks can be multiplexed onto one upstream network (even when the upstream prefix is too long (e.g. for IPv6-PD))
- internal devices are not directly reachable from the Internet (this is not a replacement for a firewall!)
Cons
- connections can only be started from internal devices
- router needs to keep state for every connection
- router needs to touch/manipulate every packet
- you only have one static external address, because it seems temporary addresses (i.e. IPv6 privacy extensions) don’t work with WireGuard connections