Skip to main content

Tunneling IPv6 subnets through Wireguard

This blog entry will hopefully serve as a (mostly) no BS guide on tunneling IPv6 subnets through Wireguard. If you ever found yourself wanting to tunnel /48 (or any size) subnets straight to your router/device then read on.

Preflight check list

  • An already working Wireguard setup.
  • IPv6 forwarding enabled
  • Make sure the prefix you’ll be routing is NOT assigned to any interface

So.. Why a link local address exactly? Because your 2 Wireguard nodes are connected to eachother directly so it doesn’t make sense to assign a ULA or even a globally routable address to it. You can either randomly generate this or use the Wireguard public key’s first 4 hextets once decoded from base64 to hex.

For example, consider the public key below:

7fKLCZ7k8VEZYKM43Gv6vTC2oh/n4x9woeV8AS6kZUU=

The first 4 hextets of our public key are edf2 8b09 9ee4 f151. To get our link local address all we need to do is add a : between each hextet, prepend fe80: and append a /64. With this procedure we should end up with fe80::edf2:8b09:9ee4:f151/64. Congratulations, you got yourself a key-based link local address. Do this for both nodes and assign the address.

AllowedIPs

I know, “Server” and “Client” doesn’t make sense in Wireguard but let’s use the terms for brevity. I’ll also use fe80::1 for the server and fe80::2 for the client.

Open the server’s config and add the subnet to the client’s AllowedIPs. For example

AllowedIPs = 2001:db8::/48

AllowedIPs is pretty much a poor man’s ACL. This instructs Wireguard to allow this peer to use all the IPs within that subnet. Although not required, It’s also recommended to add the link local prefix here.

Routing

Now for the fun part. This is entirely up to the reader, but my personal preference is to add Table=off in my Wireguard config to disable Wireguard’s route table management and do it manually. All you need to know is that 2001:db8::/48 needs to get routed to the client’s link local address. In Linux & iproute2 this would end up looking like

ip -6 route add 2001:db8::/48 via fe80::2 dev wg0

The dev wg0 part is very important here. Link local addresses require you to specify an interface. All that’s left to do on the client side is to actually use the prefix. The default gateway on the client side should point to the server’s link local address. For example

ip -6 route add 2000::/3 via fe80::1 dev wg0

That’s it. Nothing left to do. Note that if you’re experiencing sporadic connectivity issues then the culprit is likely MTU and MSS. This is outside the scope of this guide. It’s also not necessary to assign an address from that range to your Wireguard interface. You can assign it to any interface and it’ll work fine.