Automatic CLAT on macOS
We’re an all-Apple campus on the client side (we mostly run Linux on the server side). We noticed something interesting on our macs while testing IPv6-only connectivity using the NAT64 servers that we set up for testing IPv4 legacy protocols with IPv6-only connections.
One day I absent-mindedly tried to ping an IPv4 address literal (8.8.8.8). Normally, this doesn’t work with NAT64 because a literal address doesn’t involve a query to DNS, so DNS64 doesn’t get the chance to synthesize the v4-embedded address.
But in this case, I was able to ping and get responses! I thought
perhaps I had turned v4 on by accident (I had manually turned it off
to test native IPv6), but I confirmed it was still off. Then, I
noticed this in ifconfig
:
en0: flags=88e3<UP,BROADCAST,SMART,RUNNING,NOARP,SIMPLEX,MULTICAST> mtu 1500
options=6463<RXCSUM,TXCSUM,TSO4,TSO6,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
ether <redacted>
inet6 fe80::<redacted>%en0 prefixlen 64 secured scopeid 0xf
inet6 <redacted> prefixlen 64 autoconf secured
inet 192.0.0.2 netmask 0xffffffff broadcast 192.0.0.2
inet6 <redacted> prefixlen 64 clat46
nat64 prefix 64:ff9b:: prefixlen 96
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
That 192.0.0.2 address is pulled from the DS-Lite range, and represents a locally-assigned address that only works on the host. Checking the route tables, you can see that this address has a next-hop gateway that’s in the same range:
% netstat -f inet -rn
Routing tables
Internet:
Destination Gateway Flags Netif Expire
default 192.0.0.1 UGScg en0
127 127.0.0.1 UCS lo0
127.0.0.1 127.0.0.1 UH lo0
192.0.0.1/32 link#15 UCS en0 !
192.0.0.1 link#15 UHLWIir en0 !
192.0.0.2/32 link#15 UCS en0 !
192.0.0.2 f0:2f:4b:13:ed:bd UHLWIi lo0
224.0.0/4 link#15 UmCS en0 !
224.0.0.251 1:0:5e:0:0:fb UHmLWI en0
239.255.255.250 1:0:5e:7f:ff:fa UHmLWI en0
255.255.255.255/32 link#15 UCS en0 !
You’ll note that the 192.0.0.1
address is the default gateway for
v4, so as far as the node is concerned, it has a default route to the
v4 internet. Traffic to that address is handled by a client site
translator (CLAT) process
that converts the packets from v4 to v6 and embeds the v4 destination
in the v6 address (just like DNS64 synthesis would). The benefit here
is that no DNS is required, and the host has (what appears to be) a
valid IPv4 address, so applications that are v4-only on the host
continue to operate correctly even though the host doesn’t have a
routable v4 address.
I wasn’t the only one to see this behavior. Ondřej Caletka of the RIPE NCC observed this CLAT behavior in macOS and documented it in his article about IPv6-mostly networks. However, at the time of his article (2022), the CLAT was only activated in response to DHCPv4 providing the IPv6-only Preferred option, along with a PREF64 Advertisement in the v6 Router Advertisement.
In my case, I don’t have these set up (yet). So in 2023 it seems Apple has relaxed the requirements for activating the CLAT. My best guess is that when macOS detects both the absence of a v4 address (in my case, because I’ve explicitly disabled it) and detects a PREF64 value per RFC7050 it activates the CLAT. This is good, and helpful because the RA flag has not been adopted by any router vendors we have tested (Juniper, Arista, Aruba). I reached out to Ondřej and he confirmed my findings; he also said that he observed macOS 13 (Ventura) complaining unless it had a valid IPv4 address or a functioning CLAT/NAT64 (so it seems Apple is requiring IPv4 functionality to consider itself “connected”).
It’s worth noting that this feature is not 100% reliable. If I have
multiple network connections enabled (ethernet and wifi), and then
disconnect from ethernet, the CLAT doesn’t automatically pick up on
wifi. I usually have to bring wifi down and back up, and sometimes
toggle v4 on and back off before the functionality returns. I’ve
noticed that when it’s broken I sometimes see the CLAT output in
ifconfig
but netstat
shows no default v4 route installed, so the
packets won’t flow correctly.
Even though it looks like macOS doesn’t quite have all the kinks worked out, I’m still excited about this feature! I was prepared to deal with the loss of IPv4 literals when we switch to pure IPv6 with NAT64. However, having this CLAT functionality will help the transition by preventing immediate breakage of programs that still rely on raw IPv4. On the downside, it means that broken apps can stay broken longer and there will be less impetus to update them. But, given that some apps may not be able to be upgraded (e.g., because they’re discontinued), this prevents those apps from not working at all and possibly preventing a migration to IPv6-only.