DNS64/NAT64 and local IPv4 servers

When using IPv6 (PF_INET6) sockets on a mac that's connected to an IPv6 network with DNS64/NAT64, if you want to connect to an IPv4 server by address (not by name) the recommendation from Apple is to use getaddrinfo() to get a synthetic IPv6 address: "If your app needs to connect to an IPv4-only server without a DNS hostname, use getaddrinfo to resolve the IPv4 address literal. If the current network interface doesn’t support IPv4, but supports IPv6, NAT64, and DNS64, performing this task will result in a synthesized IPv6 address"


The problem is that if the mac client is also connected to an IPv4 network (on different network interface than the one that's connected to the IPv6 network), then there's no way to talk to the IPv4 servers on that network using an IPv4 literal, since the getaddrinfo() lookup will return an IPv6 address that will be routed through the IPv6 network and NAT64.


Let's take an example:

A mac client with two network interfaces enabled, say a Wifi interface and an ethernet interface, is connected to an IPv6 network with DNS64/NAT64 (for example a second mac with 'Internet Sharing' enabled, which creates an IPv6 network with DNS64/NAT64) over Wifi, and to a local IPv4 network over ethernet (for example a corporate LAN).

Say that the IPv4 address of the ethernet interface is 192.168.1.2. On that IPv4 network, there's another machine, with IP addr 192.168.1.1, with an HTTP server.

Now, if the mac client wants to connect to the IPv4 HTTP server at 192.168.1.1, using a PF_INET6 socket and an IPv4 literal, it should be able to do that with an IPv4-mapped address ::FFFF:192.168.1.1, but if we follow the recommendation to use getaddrinfo("192.168.1.1"), we get back a synthetic address (64:ff9b::192.168.1.1), which will get routed to the NAT64 router on the IPv6 Wifi network, so we fail to connect to the local IPv4 HTTP server on the ethernet network.

On the other hand, if we skip getaddrinfo() and use :FFFF:192.168.1.1, we are able to talk to the local IPv4 HTTP server, but now we can't talk to a remote IPv4 HTTP server (for example an external HTTP server with IPv4 address 207.189.56.79), since there's no route for that host, and unless we use the synthetic IPv6 address for this (64:ff9b::207.189.56.79), we won't be going throug NAT64.


So it seems that we can either connect to local IPv4 servers, or remote IPv4 servers, but not both!

What can be done?

By any chance is getaddrinfo() returning multiple synthesized addresses, and your code is copying the supplied Apple example and attempting to just use the first result it finds?


"There are several reasons why the linked list may have more than one addrinfo structure, including: the network host is multihomed, accessible over multiple protocols (e.g., both AF_INET and AF_INET6); or the same service is available from multiple socket types (one SOCK_STREAM address and another SOCK_DGRAM address, for example). Normally, the application should try using the addresses in the order in which they are returned. The sorting function used within getaddrinfo() is defined in RFC 3484; the order can be tweaked for a particular system by editing /etc/gai.conf (available since glibc 2.5)."


You're describing a multihomed host (two active network interfaces). And the result I would expect is that you get back one synthesized IPv6 address for each interface and then you have to figure out which network you want to talk to because the framework has no idea.

DNS64/NAT64 and local IPv4 servers
 
 
Q