TIL: NAT64 and DNS64

Today I learned about NAT64 and DNS64: some mechanisms used to allow IPv6-only networks to interact with IPv4-only ones. These mechanisms will cause any IPv4-only services that you are trying to access to be (locally) attributed to an IP address with the well-known prefix 64:ff9b::/96.

Recently, while using my phone to access a service (requiring to be accessed through VPN) on my personal server, I was returned an error "403 Forbidden". "That's odd," I thought. "I am connected through WireGuard, so I should be able to reach this..." Upon closer inspection, I noticed something unexpected: the WireGuard client (configured to reach an IPv4 address) was connected to an IPv6 endpoint with an address looking like 64:ff9b::xxxx:xxxx. Some investigations later, I discovered that somehow, the network was assigning an IPv6 to my server, and forcing all of the traffic to go through it.

After some Googling, I found out that my new phone carrier was using an IPv6-only network, and using NAT64 and DNS64 to connect to IPv4-only networks and services. Basically, what was happening is that:

  1. My phone was sending a DNS request to the network to access mysite.com
  2. My phone carrier DNS tried to resolve the non-existent AAAA DNS entry for mysite.com. Upon not being able to resolve it, it created an IPv6 in 64:ff9b::/96  (based on the DNS A record, using RFC 5062) and returned it to my phone
  3. When trying to connect to mysite.com, my phone used the attributed IPv6. My phone carrier's routing system was then using NAT64 to reach my server using IPv4
  4. Because my Wireguard Allowed IPs list was only listing my server's IPv4 and VPN CIDR, the traffic was not being routed through it, and therefore denied by my server

The following schema gives a good representation of all the interactions between the different components.

NAT64 and DNS 64 (source: Wikipedia)

Fortunately, the fix was pretty simple: editing my DNS record with new AAAA entries, and adding my server's IPv6 to the WireGuard's Allowed IPs configuration allowed everything to be routed as it should have.


Sources and Extra Reading

Credits