I’ve broken this topic out from the Time to get serious about my router discussion over the last few months.
Inspired by:
Just kidding, @jdownie
! But, as one of the group’s resident IPv6 nutters enthusiasts, I thought it was worth a post for those HLBers who might be hesitant to dip their toe into the IPv6 waters, or even want to leap straight in and go IPv6-only!
As I mentioned in that thread, I’ve been running IPv6 in various forms (e.g., native DHCPv6-PD, via Tunnel Brokers) for close to 20 years now, but they’ve all been Dual Stack (i.e., along side IPv4). This weekend was my first foray into a completely IPv6-only deployment at home and I thought it was worth opening the discussion for anyone else who wants to take the plunge and ditch IPv4.
Assuming that your ISP provides a v6 prefix, getting IPv6 Dual Stack going is straightforward. There may be some minor configuration (e.g., prefix length) on your router, but there’s a very good chance that you’re already using IPv6 without realising it. However, IPv6 adoption is an ongoing process, and the global adoption rate is about 50%, with Australia sitting somewhat below that overall (Source: Internet Society Pulse). Some large websites and services also have limited adoption or even no IPv6 adoption (e.g., GitHub remains IPv4 only).
Going fully IPv6-only at home will therefore “break stuff”, specifically “IPv4-only stuff”. To address this, there are various transition mechanisms, but I chose to use NAT64 and DNS64 on this occasion. Tayga and Jool both provide NAT64, and I’ve used Jool.
As implied in the name, the NAT64 service provides NAT between the IPv6 only network and an IPv4 network for services that don’t have IPv6. How does this work?
The 64:ff9b::/96 prefix is reserved and is used to map into IPv4 space. For example, 10.0.0.1 becomes 64:ff9b::a00:1 (0a00:0001 being a hexadecimal representation of the octets 10.0.0.1). The router on my IPv6-only network forwards this 64:ff9b::/96 prefix to the NAT64 host, and that NAT64 host sends IPv4 packets out to the IPv4-only host.
On my IPv6-only network (separate VLAN & SSID), I’ve got no IPv4 addresses configured on anything, and no DHCP (v4), etc. at all. I installed an Alpine Linux VM to serve as my NAT64 translator. For what it’s worth, I did the entire Alpine install using IPv6 only - very impressive!
Once installed, I set up a separate interface on the Alpine VM which connects via IPv4 to my existing Dual Stack LAN. Next:
- Enable IP forwarding so the machine acts as a router:
sysctl -w net.ipv4.conf.all.forwarding=1
sysctl -w net.ipv6.conf.all.forwarding=1
- Set a static IPv6 ULA address on the NAT64 machine:
auto eth0
iface eth0 inet6 static
address fd00::64
netmask 64
(eth1 left as DHCP - connected to the IPv4 network).
- Install Jool (Alpine Linux instructions)
- Configure Jool. My basic config is:
{
"instance": "nat64-minimal",
"framework": "netfilter",
"global": {
"pool6": "64:ff9b::/96"
}
}
- Set a route from your router for
64:ff9b::/96to your NAT64 machine (in my casefd00::64) and on my MikroTik router
ipv6 route add comment=NAT64 dst-address=64:ff9b::/96 gateway=fd00::64
Happy days - NAT64 works. Example ping to 8.8.8.8 below:
ping6 64:ff9b::8.8.8.8
PING6(56=40+8+8 bytes) <my IPv6 address> --> 64:ff9b::808:808
16 bytes from 64:ff9b::808:808, icmp_seq=0 hlim=118 time=22.463 ms
16 bytes from 64:ff9b::808:808, icmp_seq=1 hlim=118 time=24.962 ms
16 bytes from 64:ff9b::808:808, icmp_seq=2 hlim=118 time=21.277 ms
16 bytes from 64:ff9b::808:808, icmp_seq=3 hlim=118 time=26.514 ms
16 bytes from 64:ff9b::808:808, icmp_seq=4 hlim=118 time=26.176 ms
But what about DNS? DNS64 is the partner mechanism to NAT64 where A records are synthesised into AAAA records for NAT64 purposes. I understand that several self-hostable DNS servers (e.g., Bind, Technetium, and AdGuard Home) have this capability, but for this weekend’s testing I simply updated my IPv6 ND to advertise Cloudflare’s DNS64 server onto that IPv6-only VLAN. I’ll come back to hosting something here over the coming days, probably on that same NAT64 VM.
(Edit: I came back to this and set up Bind as a DNS64 server on the same VM. I only picked Bind because I was being lazy and there was an Alpine package for it, but not for Technetium or AdGuard Home. Bind is set up very close to the Jool documentation on DNS64, with the exception that I’ve set it up as a forwarder to my current ad-blocking self-hosted IPv4 DNS rather than a recursive resolver. DNS64 working with ad blocking still in place is the best of both worlds!)
An IPv6-only (and IPv6 capable) client will ask for AAAA DNS records. In cases where AAAA records don’t exist, then an IPv6-only client doesn’t know how to access the service, even with NAT64 in place. A DNS64 server synthesises these records out of A records. For example, there are no AAAA records for discourse.homelabbrisbane.com.au, however a DNS64 server will return a valid record of
discourse.homelabbrisbane.com.au. IN AAAA 64:ff9b::5df:2e20, which has been converted from discourse.homelabbrisbane.com.au. IN A 5.223.46.32 (Where **5.223.46.32** maps into the NAT64 address of 64:ff9b::**5df:2e20**. The IPv6-only client then accesses the service via that synthesised IPv6 address via the NAT64 service. (I promise I’m not picking on the HLB discourse for being IPv4-only - it was just a nice example!)
Everything just worked. Admittedly, I haven’t tested a Windows machine (merely because I don’t have one handy), but Android/iOS/macOS clients worked straight away and I haven’t noticed the difference. I’ve noticed no speed difference for IPv4-only services going via NAT64, and that Alpine Linux VM has barely been breaking a sweat. CPU usage is low, it’s using around 130MB RAM total, and network usage is at line speed for the Proxmox host.
I’ll try and find a way to collect some statistics at some stage about the amount of traffic going via the NAT64 service (i.e., how much IPv4-only traffic is left from the day to day services being used at home).
Hope that helps others and encourages others to get onboard the IPv6 train
.
