Using IPv6 in a Real Java Program

Using IPv6 is slowly starting now, so I'm in the process of fixing and updating all the applications that will be prepared for IPv6.

One application is the JOSM Java editor ( http://josm.openstreetmap.de/ ). Java really does not use IPv6 in the default configuration, even if the OS uses IPv6.

According to http://docs.oracle.com/javase/1.5.0/docs/guide/net/ipv6_guide/#using I set java.net.preferIPv6Addresses to true so that it uses IPv6. The result was user error messages about a damaged Internet connection.

Java seems to only switch to using an IPv6 address instead of IPv4, but does nothing. All the C / C ++-based software that I support has been modified to check and verify all available IP addresses, so broken IPv6 (or IPv4) addresses are skipped until one of the addresses works. For me, it looks like Java only tries once that does not work in the real world.

Also, the OS usually prefers IPv4 over IPv6 when IPv6 is tunneled. It seems that Java also ignores these settings.

So my question is: are there any good ways to force a Java application to use IPV6 by default, if available, without breaking the application for IPv4 users.

User error reporting: http://josm.openstreetmap.de/ticket/8562 , http://josm.openstreetmap.de/ticket/8627

+7
source share
2 answers

So you have two problems:

  • Operating system vendors deliver operating systems with broken IPv6 default configurations and / or users who allow broken IPv6 configurations.

  • When this does not work, they mistakenly blame you.

Here you can do two things:

  • Advise users on how to disable unnecessary and broken IPv6 transition mechanisms such as Teredo, ISATAP, and 6to4. Instructions for them are widely available on the Internet.

    It would be nice if some OS makers didn't turn on this shit by default, but they probably asked too much.

  • Add Happy Eyeballs ( RFC 6555 ) to your application. Here's how modern web browsers solve this problem.

    Happy Eyeballs defines the algorithm by which an application tries to connect through IPv6 and IPv4 at the same time (almost), and if IPv6 does not work for a short period of time, return to the IPv4 connection. The results of this test are also cached for several minutes.

    Unfortunately, I'm not good at Java to give you specific code to get around all the interesting things that Oracle hides from you by default, but this should be doable.

0
source

It seems that the topic is interesting for others as well, so I am describing my current solution.

  • The software detects whether IPv6 is working or not, and remembers the state β†’ This is done by connecting TCP to a known IPv6 address (Ping of isReachable () is not reliable, see this error report: https://josm.openstreetmap.de/ ticket / 11452 ).
  • Based on the memorized state, the software starts with "java.net.preferIPv6Addresses" set to true.
  • This means that to migrate from IPv4 to an IPv6 network, it will use IPv4 until the next restart, which is normal.
  • To switch from IPv6, which is included in the network only with IPv4, it will not work at all, which will be allowed by restarting the software.
  • If in doubt, assume that IPv6 is not working.
  • It is not possible to change "java.net.preferIPv6Addresses" after detection, since these values ​​seem to be read only until the first network connection. If at runtime there is a reset method that I would like to know about it.

This solution works, we have about 4% of IPv6 connections in our ATM logs, but this is actually not a satisfactory solution.

 /** * Check if IPv6 can be safely enabled and do so. Because this cannot be done after network activation, * disabling or enabling IPV6 may only be done with next start. */ private static void checkIPv6() { if ("auto".equals(Main.pref.get("prefer.ipv6", "auto"))) { new Thread(new Runnable() { /* this may take some time (DNS, Connect) */ public void run() { boolean hasv6 = false; boolean wasv6 = Main.pref.getBoolean("validated.ipv6", false); try { /* Use the check result from last run of the software, as after the test, value changes have no effect anymore */ if (wasv6) { Utils.updateSystemProperty("java.net.preferIPv6Addresses", "true"); } for (InetAddress a : InetAddress.getAllByName("josm.openstreetmap.de")) { if (a instanceof Inet6Address) { if (a.isReachable(1000)) { /* be sure it REALLY works */ Socket s = new Socket(); s.connect(new InetSocketAddress(a, 80), 1000); s.close(); Utils.updateSystemProperty("java.net.preferIPv6Addresses", "true"); if (!wasv6) { Main.info(tr("Detected useable IPv6 network, prefering IPv6 over IPv4 after next restart.")); } else { Main.info(tr("Detected useable IPv6 network, prefering IPv6 over IPv4.")); } hasv6 = true; } break; /* we're done */ } } } catch (IOException | SecurityException e) { if (Main.isDebugEnabled()) { Main.debug("Exception while checking IPv6 connectivity: "+e); } } if (wasv6 && !hasv6) { Main.info(tr("Detected no useable IPv6 network, prefering IPv4 over IPv6 after next restart.")); Main.pref.put("validated.ipv6", hasv6); // be sure it is stored before the restart! new RestartAction().actionPerformed(null); } Main.pref.put("validated.ipv6", hasv6); } }, "IPv6-checker").start(); } } 
0
source

All Articles