HOME · Twitter · Flickr · LinkedIn · publications · @ Ars Technica · Running IPv6 (Apress, 2005) · BGP (O'Reilly, 2002) · BGPexpert.com · presentations · iljitsch@muada.com

Taking Apple's NAT64 implementation for a spin

Posted 2015-07-13

As we learned last month, Apple has included a DNS64/NAT64 implementation in the upcoming version 10.11 of the Mac operating system, for the purpose of testing whether iOS applications are "IPv6-clean". I installed the public beta of 10.11 last week, so I was able to see how this DNS64/NAT64 implementation works.

You get to it by alt (option) clicking on the Sharing pane in the System Preferences. If you then go to Internet Sharing, you'll see an option "Create IPv6 Only Network":

The way it works is that you select the interface that connects the machine to the internet in "Share your connection from" and then one or more interfaces on which the IPv6-only network is created. I didn't have much luck with using the Wi-Fi interface for this on my MacBook Pro from 2007 sitting under a table in a corner with the lid closed, which probably doesn't mean anything. I eventually connected the machine directly to my cable modem using a USB Ethernet adapter and then shared the network on the built-in Ethernet interface that connects to my wired LAN and Wi-Fi.

What happens then is that the machine creates address 2001::1/64 on this interface as well as some other addresses in 2001::/64. Router advertisements are sent out with a prefix option 2001::/64 and an RDNSS option 2001::1. The M and O bits are not set, so there is no DHCPv6 server to allow systems that don't implement the RA RDNSS option to learn nameserver addresses. Looks like that's mainly the various flavors of Windows these days. However, you can modify the rtadvd.conf file that is used here: /etc/com.apple.mis.rtadvd.conf to set the O bit by adding raflags#64 and then kill rtadvd and restart it as follows:

Then, run a DHCPv6 server to announce 2001::1 as a nameserver.

A thing to note is that all of this does not create any real IPv6 connectivity. So what happens is that the included DNS64 implementation creates synthetic IPv6 responses in 64:ff9b::/96 for all requests rather than only for those that don't have actual AAAA records. So you'll be using NAT64 for everything, not just destinations that are IPv4-only. (Interestingly, by the way, 64:ff9b::/96 doesn't show up in the routing table.)

This is what another Mac (running 10.10.3) connected to the shared network sees:

So as expected, a regular traceroute doesn't work:

But an IPv6 traceroute does:

Note that all the hops have 64:ff9b: addresses—these are all NAT64-translated IPv4 addresses.

A traceroute to the real www.apple.com IPv6 address doesn't work:

The !N's indicate that the MacBook Pro returns an ICMPv6 network unreachable message.

Using this NAT64 setup for my entire network was an interesting experience in the sense that everything worked completely normally. I didn't go out of my way to test different applications, but everything that I used worked, on my other Mac, on my iPhone, on the Apple TV. The only application that wouldn't do anything was Skype.

The real thing

What I wanted to see is if I could turn this into a real NAT64 setup, where IPv6 destinations are reached over IPv6 and the NAT64 is only used for IPv4 destinations.

First step, add some IPv6 connectivity, in the form of a tunnelbroker.net tunnel using the following script:

In the System Preferences, I configured the en0 interface to only have a link local IPv6 address to avoid having the system listening to its own router advertisements.

And here's the cleanup script that we'll need later:

We now need router advertisements to let other systems know about our newly minted IPv6 router. The rtadvd daemon is already running because of the NAT64 network on the Wi-Fi interface. This is the config file:

So I added the following:

And then killed and restarted the rtadvd with as the last argument the en0 interface:

2001:db8::53 is the address where I run a DNS64 server. Unfortunately, it's not possible to do that on the MacBook Pro running the NAT64 service, because that one already has a DNS64 server running on port 53. But that one filters out real IPv6 addresses, so we can't use it. I guess I could have tried to figure out which process this is and killed it, but I decided to run BIND instead, which is trivially configured to be a DNS64 server, just add this line to options { } part of the config:

(64:ff9b::/96 is the NAT64 "well known prefix". It's also possible to run a NAT64 service using regular global unicast address space, though.)

With all of the above in place, I had a working "real" NAT64 setup. At first, this worked really well, but soon trouble started: my Mac kept losing its default route. I have no idea why this happens with the tunnel setup that I come up myself, while Apple's NAT64 setup is rock solid.

I did some tcpdumping and it looks like the default route learned from the MacBook Pro disappears as soon as the system tries to use the default route to send packets and does a neighbor solicitation (and gets a neighbor advertisement) for the link local address that the default route points to.

To solve the issue, I set up a Cisco 2503 router to generate router advertisements, which solved the problem at first:

(Annoyingly, I can't find any documentation for what these flags in the ndp output mean. If anyone has more information, please let me know!)

But it then turned out that my iPhone wouldn't learn the nameserver address and thus ignore the Wi-Fi network. After having been away and reconnected my Mac and my iPhone to the network, the iPhone worked fine but the Mac wouldn't get a nameserver address. I solved this by setting the O bit in the Cisco's router advertisements and running a DHCPv6 server to advertise the DNS64's address, but the network didn't become completely stable anymore and I wanted to get some work done, so I didn't do a big round of reboots to see if that would help but restored my normal dual stack environment.


Apple's NAT64 implementation works really well for its intended purpose: see if applications are IPv6-clean. However, because it doesn't work with real IPv6 connectivity, it's not useful for anything else. It's hackable to some degree, but don't expect much stability. If you want to test real DNS64/NAT64, you're probably better off finding a public service or using a more open implementation in a VM.

Search for:
RSS feed (no photos) - RSS feed (photos only)
Home, archives: 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015