About a week or two ago, I tried to connect my Thinkpad to my iPhone’s hotspot. It was right after a recent iOS update (17.3). It was a very odd moment as my Firefox could not load anything. My first instinct was to perform ip a, which would show if my wlan0 connection interface is connected. And it was. My next thought was maybe it was one of those odd Linux moments where you have WiFi but no internet because DHCP somehow failed. So I tried to set a static IP via a systemd-networkd configuration. And it still didn’t work. Furthermore, this whole time ping 1.1.1.1 did not work. It was more frustrating that the message was “ping: connect: Network is unreachable”. It was frustrating since it was clearly connected.

One afternoon, I took a bit of time to investigate the issue. Again, I tried looking at ip a and interestingly, there was no “inet” field and there was only an “inet6” field. I had a suspicion that perhaps DHCP worked for IPv6 but not for IPv4. So I performed ping ipv6.google.com and it worked! Somehow Apple managed to screw up hotspot so badly that it didn’t even issue an IPv4 to my device and gave only an IPv6 address. Why Apple would you do this?

While having an IPv6-only connection, the internet is a trippy experience. As of 2024 February, the global adoption rate for IPv6 is around 41%. (according to Google) That means that more than half the web doesn’t work. My Firefox couldn’t load “anything” initially because my main search engine, Duckduckgo, is IPv4-only. Using Google worked. Hackernews worked. Wikipedia worked. richardwong.io didn’t work. Of course it didn’t work, I didn’t add AAAA records to the IPv6 address of my server. At that point I realized that I was part of the 59% that contributed to the IPv6 adoption problem. And so I became a compliant citizen of the world and added IPv6 records for richardwong.io. richardwong.io is dual-stack (IPv4 and IPv6) networked from now on.1

But coming back to my broken hotspot, how am I to restore my connection to the remaining 59% of the world’s websites that are still using IPv4? In other words, how can I access IPv4 websites from an IPv6-only connection? A complicated way to go about it is via DNS64/NAT64. This is a process where IPv6-only hosts can talk to IPv4-hosts via an intermediate translation mechanism where all IPv4 A-records can be converted into IPv6 AAAA-records that my IPv6-only machine can understand. It is complicated because the kernel does not support NAT64 natively and so additional tools and kernel modules are required. Considering that I am mainly using WiFi connections from fixed residential/school routers, I will still be using mainly IPv4. This is not the way.

A much simpler method would simply to use richardwong.io as a proxy. By using ssh -D <port> <proxy>, I am able to proxy via a IPv6-enabled public server using SOCKS. All connections through the proxy are possible through the IPv4 and IPv6 connections of the server, not my client. In effect, I am browsing through my server and using its IPv4 connection instead. And so I was able to workaround the limitations that the bug has given me, and finally got around to enabling IPv6 for my website and reading more on it (Just the fact that there are hexadecimals in the IPv6 string scared me for a really long time, but I guess it beats writing 128 0s and 1s…).

Now for some thoughts. It is horrifying that something as important as IPv6 is not backward compatible with IPv4. I guess the lack of compatibility is causing all the issues with IPv6 adoption. And that really sucks, because IPv6 can enable all machines to be publically and uniquely addressable (IPv6 can hold hundreds of times more addresses than atoms on Earth). Because of the limited number of IPv4 addresses, most ISPs utilize a double-NAT where each IPv4 address would have an internal network shared by the whole neighborhood. Home routers would therefore have a private IP not reachable from the public internet. This increases the utilization of each public IPv4 address and therefore reduces the need for more addresses. But double-NAT is a terrible technology that feeds into the consumption aspect of the internet and dissuades the aspect on sharing and creation. You can ask from others but others can’t ask from you. I believe this is one of the reasons why most people don’t make their own websites, because they can’t just host stuff on their home machines. Instead you have to use a publicly-addressable server from a company with a large pool of IPv4/IPv6. I mean, who would want to rent a VPS box and configure their own reverse-proxy to link their home machines to speak to the internet to host a bunch of files (I will write a blog post on this in the future).

IPv6 adoption is necessary for a more grassroots-based internet, where services and websites are hosted on small, independent machines rather than on one of the big, commercial cloud server offerings. As of right now, most ISPs are not offering static IPv6 for homes.

I think I still need to readup more on IPv6. A good resource would be to look at the tldp Linux IPv6 how-to guide. Considering how VPS services and Amazon AWS now charges more for IPv4 instances, it would be wise to know how to setup a IPv4-compatible IPv6-only server.

Update: [2024-04-21 Sun]

It is possible to access IPv4 via an IPv6-only network on linux. Just add the following DNS64 addresses from cloudflare to your systemd-resolved config:

2606:4700:4700::64
2606:4700:4700::6400

Somehow systemd-resolved is able to start resolving IPv4 addresses despite not having set-up a NAT64 on the network.

When I am using my IPv6 machine to get an IPv4 request via the DNS64 server, it will get a AAAA resource record (RR) from the DNS64 server. Its just like any other AAAA RR, like an IPv6 address. Then my machine sends an IPv6 packet with the destination address being the synthesized AAAA record starting with the standard DNS64 prefix “64:ff9b::” to the wild. By using a traceroute, I was able to find that somewhere along the way servers receiving my packet transitions from “2001:..” (an IPv6 server) to “64:ff9b:..” (an IPv4 address translated back into IPv6), suggesting that the packet was translated somewhere along the way. It would appear that the network itself already had NAT64 services provided by someone. By referencing this article2, it would seem that Korean ISPs do indeed provide NAT64 as a provider-side translator (PLAT) service. Since the NAT64 translation is already provided by the network, the IPv4 destination server response will likewise be translated back to IPv6 packets and back to me, which my IPv6-only machine can read.

So this ties up the mystery of why a simple addition of DNS64 in system-resolved config suddenly allowed IPv4 access from my IPv6 machine.