8

现在 IPv6 的使用正在慢慢开始,所以我目前正在修复和更新所有应用程序,为 IPv6 做好准备。

应用程序之一是 Java 编辑器 JOSM ( http://josm.openstreetmap.de/ )。即使操作系统使用 IPv6,Java 也不会在默认配置中真正使用 IPv6。

根据 http://docs.oracle.com/javase/1.5.0/docs/guide/net/ipv6_guide/#using 我设置java.net.preferIPv6Addresses让它true使用 IPv6。结果是有关断开互联网连接的用户错误报告。

似乎 Java 只切换到使用 IPv6 地址而不是 IPv4,但没有做任何其他事情。我维护的所有基于 C/C++ 的软件都已更改为检查并尝试所有可用的 IP 地址,因此只要其中一个地址有效,就会跳过损坏的 IPv6(或 IPv4)地址。对我来说,Java 似乎只尝试一次,这在现实世界中是行不通的。

当 IPv6 被隧道化时,操作系统通常更喜欢 IPv4 而不是 IPv6。Java 似乎也忽略了这个设置。

所以我的问题是:有什么好的方法可以让 Java 应用程序在默认情况下使用 IPV6,而不会破坏 IPv4 用户的应用程序。

用户错误报告: http: //josm.openstreetmap.de/ticket/8562,http : //josm.openstreetmap.de/ticket/8627

4

2 回答 2

1

似乎这个话题对其他人来说也很有趣,所以我描述了我目前的解决方案。

  • 该软件会检测 IPv6 是否工作并记住状态 -> 这是通过 TCP 连接到已知的 IPv6 地址来完成的(isReachable() 的 Ping 不可靠,请参阅此错误报告:https://josm。 openstreetmap.de/ticket/11452)。
  • 根据记住的状态,软件以“java.net.preferIPv6Addresses”设置为“true”开始。
  • 这意味着对于从 IPv4 到 IPv6 网络的切换,它将使用 IPv4 直到下一次重新启动,这没关系。
  • 对于从启用 IPv6 到仅 IPv4 的网络的切换,它根本无法工作,这可以通过重新启动软件来解决。
  • 如有疑问,我们假设 IPv6 不起作用。
  • 进行检测后无法更改“java.net.preferIPv6Addresses”,因为该值似乎只能在第一次网络连接之前读取。如果有办法在运行时重置该状态,我想知道它。

这个解决方案似乎有效,我们的日志 ATM 中有大约 4% 的 IPv6 连接,但这并不是一个真正令人满意的解决方案。

/**
 * 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();
  }
}
于 2016-02-14T13:48:56.150 回答
0

所以你在这里有两个问题:

  1. 操作系统供应商提供带有损坏的默认 IPv6 配置的操作系统,和/或用户启用损坏的 IPv6 配置。

  2. 当它不起作用时,他们会错误地责怪你。

您可以在这里做两件事:

  1. 建议用户如何禁用不必要的和损坏的 IPv6 转换机制,例如 Teredo、ISATAP 和 6to4。这些说明可在 Internet 上广泛获取。

    如果某些操作系统供应商默认不启用这种废话,那也很好,但这可能要求太多了。

  2. 在您的应用程序中实现 Happy Eyeballs ( RFC 6555 )。这就是现代网络浏览器解决这个问题的方式。

    Happy Eyeballs 指定了一种算法,应用程序通过该算法尝试(几乎)同时通过 IPv6 和 IPv4 进行连接,如果 IPv6 在短时间内无法工作,则回退到 IPv4 连接。该试验的结果也会被缓存几分钟。

    不幸的是,我对 Java 不够熟悉,无法为您提供特定的代码来绕过 Oracle 默认情况下向您隐藏的所有有趣的东西,但它应该是可行的。

于 2013-04-23T17:27:20.213 回答