IPv6 addresses... everywhere

As you may not be able to guess (I'm just kidding), I have IPv6 addresses handy. In the previous article, I said that I would install OPNsense on my network to split the virtual machines network from the rest. I have also mentioned that I had a few "projects" for the usage of this router. IPv6 address was part of thoser plans. Until here, I reassure you, everything works properly, even though I had to change some initial plans with Wireguard.

Prelude of the story

I have one IPv6 block from my ISP so, in theory, even in practice, I can totally use it to make AAAA records and this would be a short blog post. Yes... but no. The provided prefix is based on a changing IPv4 address. How to say that I don't fancy updating X AAAA DNS records when one IPv4 address decides to change.

So the domain was available only in IPv4 and "that's it". Until the day one friend of mine offered me to use one IPv6 prefix routed through a Wireguard VPN. Great !

The choice of Wireguard has been mainly motivated by the tolerance to one of the endpoints changing its IP address, in this case mine. This capacity to change its IP address on the fly without flinching has proven useful.

The story with Wireguard

I tried to setup a Wireguard tunnel to have the IPv6 prefix on OPNsense. However, how to say that the configuration was a pain in the butt ?

I won't go into details because I was so lost. Eventually, I managed to route with an axe and it was working more or less. At least, network packets were passing without any issues, with settings like "Oh dear, what's happening ?".

I had at this time, strap yourself in: 9.2234×1018 addresses on hand because the routing with a chainsaw, but more than enough.

Then I noticed a few performance issues with a lower than expected throughput. From what I understood, Wireguard would be running in the userspace, with the supplemental package for OPNsense. Small (big) issue since Wireguard is made to run in the kernelspace. So I had to come up with something else.

Hello again, Debian !

The direct enough answer to the issue, at least what I was thinking, was to setup a Debian virtual machine that would be in charge of doing needed things properly with Wireguard. Fortunately, while I was struggling with OPNsense, I set up a virtual machine that would do the job. So going from one to the other was quick and the routing has been made properly.

After some benchmarking to see if I changed something (spoiler alert: little to nothing), I conclude that it is probably the fact that the virtual machine runs with qemu in the userspace ofthe hypervisor. Oops.

The trick to route cleanly

I think it is time to reveal a few details I have promised. Like I said before, I have a /64 IPv6 prefix. Therefore, I can assign:

  • 264;
  • 1.8447×1019;
  • 18 446 744 073 709 551 616;
  • Eighteen quintillion four hundred fourty-six quadrillion seven hundred and fourty-four trillion seventy-three billion seven hundred and nine million five hundred fifty-one six hundred sixty-dix;

addresses. Yes, it is weird to say that someone gives you one IPv6 prefix that allows you to have that many addresses without second thoughts !

Anyway. Which "trick" have I used to cleanly route my prefix to all the virtual machines ? The astuce used is to assign the IP address on the network card facing the virtual machines. Then, I have parametered Wireguard to pass all IPv6 through the tunnel, otherwise the routing won't be right.

The configuration should look like this:

[Interface]
PrivateKey = [private part of your keypair]
MTU = 1380
# No IP address

[Peer]
PublicKey = [public key]
AllowedIPs = ::/0
Endpoint = [IPv4 address:port]
PersistentKeepalive = 15

Furthermore, configuring like this, the firewall will be automagically configured and so will be the routing table. Isn't that wonderful ?

Small techincal detail: the IPv6 packet is wrapped in an IPv4 packet and unwrapped at the other end of the tunnel. It is weird to say that but we do with what we have. It is possible to have some sort of MTU issues because I can have done maths wrong. Maybe I could get away without setting it lower than Wireguard defaults to.

I set an explicit KeepAlive to avoid bad surprises with a NAT. 15 seconds looks like a reasonable interval. Moreover, with that configuration directive, the second peer is aware of address changes (if peers weren't chatting in the meantime) and will send packets to the right place.

Two more options in sysctl

We have the routing that is properly configured by Wireguard because we have set the correct parameters. But if we try to pass a network packet with the current settings... it doesn't pass.

Indeed, the router received the packet but doesn't relay it because one setting, deactivated by default, needs to be activated.

To do this, we are going to edit the file /etc/sysctl.d/99-sysctl.conf and enable the forwarding of IPv6 packets. We don't forget to reload with sysctl -p.

If we try again, packets are relayed properly.

Router Solicitation - Router Advertisement

I have configured a DHCPv6 server to assign IPv6 addresses when there is no need of configuring a static one. Everything works properly until I try to get out of the network, still with IPv6 packets. Uh, nothing is going through. So I busted out couple of frighteningly effective weapons to debug networks: tcpdump and Wireshark.

I start a small capture on ICMPv6 packets. What interesting things do I see ? Router Solicitation packets thrown on the network and left without answer. Getting out of the network without gateway proves to be... complicated, to not say impossible.

But no need to panic, the daemon radvd (initials for Router ADVertisement) will be able to answer router solicitations with advertisements.

The dance of packets can begin !

Everything is setup and correctly configured, may the ballet of networking packets begin ! *watches packets going from one place to the other*

# traceroute -I6 searx.gnous.eu
traceroute to searx.gnous.eu (2001:67c:1740:900a::122), 30 hops max, 80 byte packets
 1  l4p1n.cust.infra.enpls.org (2a0e:e704:42:13::2)  0.215 ms  0.215 ms  0.230 ms
 2  gw.fr.infra.enpls.org (2a0e:e704:42:13::1)  19.487 ms  18.469 ms  19.712 ms
 3  gre0.ccr1072.core.brs.infra.ip6.milkywan.net (2a0b:cbc0:1::15d)  19.701 ms  19.810 ms  19.848 ms
 4  te1.ccr1072.core.th2.infra.ip6.milkywan.net (2a0b:cbc0:1::8d)  19.858 ms  19.848 ms  20.030 ms
 5  ve503-rt2-th2.bb.hivane.net (2001:67c:1740:8008::1)  20.594 ms  21.200 ms  21.202 ms
 6  ae0-3000-rt2-th2.bb.hivane.net (2001:67c:1740:1::65)  21.204 ms  20.302 ms  20.258 ms
 7  xe-0-0-3-rt-lyn.bb.hivane.net (2001:67c:1740:1::6a)  26.181 ms  28.077 ms  26.503 ms
 8  ricard.gnous.eu (2001:67c:1740:900a::122)  25.573 ms  25.591 ms  25.593 ms