Search code examples
javaandroidiosipv6oracle-maf

InetAddress.getAllByName() only receives IPv4 addresses with java.net.preferIPv6Addresses


tl;dr

InetAddress.getAllByName() only receives a list of IPv4 addresses, even when java.net.preferIPv6Addresses is set to true, on a NAT64 network, on iOS devices. The same code works as expected on an android connected to the same network.

This means in an ipv6 only network (as required by the Apple store) any application attempting to make a HttpURLConnection will fail, and will be rejected by Apple.

Original Post

I am creating an app for iOS in Java, I connect to the server using HttpsURLConnection and everything works fine until I test on an NAT64 network. The app is being rejected by the Apple review team, and so I am testing locally using an NAT64 network.

To create my NAT64 network I follow these steps: Supporting IPv6 DNS64/NAT64 Networks

Sample Code:

HttpsURLConnection testConn = null;
try {
    URL testUrl = new URL("https://google.com");
    testConn = (HttpsURLConnection) testUrl.openConnection();
    testConn.connect();     
}catch (Exception e){
    e.printStackTrace();
}finally {
    if(testConn != null){
        testConn.disconnect();              
    }           
}

This code fails with a java.net.SocketException: Network is unreachable while on my NAT64 network.

I have tried changing system properties:

System.setProperty("java.net.preferIPv4Stack", "false");
System.setProperty("java.net.preferIPv6Addresses", "true");

I have also tried setting the website to something other than our servers (as seen in the test code with google.com). I have also sniffed the packets from the wi-fi connection using wireshark, and the only traffic is a DNS request for google.com which does not seem to fail. Finally I have also tried moving back to a HttpURLConnection in case the problems was to do with HTTPS.

Also worth noting is safari on the test iPhone can reach all of our servers and domains without trouble, and the device seems to have a stable and functional internet connection otherwise. The app also fails on my android device when it is connected to the same NAT64 network.

Edit:

Setting System.setProperty("java.net.preferIPv6Addresses", "true"); solves the problem on android, so now the issue is isolated to my iPhone5 on the NAT64 network. My best guess at this stage is that the property is being set by another class and is being ignored. I have tried setting the property in a static initializer block at the top of my class, to no avail.

Edit 2:

I used System.getProperty("java.net.preferIPv6Addresses") and it returns true on the iPhone5 so it's definitely being set, leaving me stumped again.

Edit 3:

I dug into HttpsURLConnection and it implements a PlainSocketImpl class to handle its connection, which uses an InetAddress. I decided to test an InetAddress and when I call InetAddress.getByName("google.com") on the iPhone I get an ipv4 address, while on the android it is returning an ipv6 address. It seems that the property java.net.preferIPv6Addresses is being ignored on iOS. I have tried updating the JDK to the latest version but this has not helped.

I have also just tried InetAddress.getAllByName("www.google.com") and it only return IPv4 addresses on the iPhone. I would say this is clearly a DNS problem, but then why is it not an issue on an android connected to the same network?

So I now know what the issue is, yet have no idea how to fix it.


Solution

  • The solution was upgrading my app to run on the latest version of MAF.

    Details:

    Even though I had updated Eclipse and MAF to the latest version, my application was still using it's original MAF release as the target runtime. I discovered this by viewing my target SDK's and realizing I could not change the runtime verison.

    noting the MAF runtime in the SDK settings

    To update I had to create a new project, making sure to set the target runtime to the latest version of MAF. I then migrated my code to this new project, and was able to successfully run my app under an IPv6 only network.

    creating a new MAF project and setting the runtime version

    (at the time of writing MAF 2.3.2 was the latest version available for Eclipse)

    If there is a way to do this without creating a new project, I could not discover it.