2015-10-06 44 views
2

尽管使用NetworkInterface,InterfaceAddress,InetAddress的组合找到机器IP地址的线程很多,但我的情况超出了这个范围。在Windows平台上使用Java查找特定路由的传出IP地址

我需要确定在与特定(给定)目标通信期间将使用的传出IP地址。我必须假设主机上有多个具有多个IP地址的接口。这是我可以想象的现实生活场景中的最佳逼近,在这种场景中,我必须提供给远程机器,远程机器仅通过IP地址知道可用于访问我的主机的自己的IP。

到目前为止,我没有发现这个任务的纯Java解决方案。凭借我非常有限的Java知识,我看不出分析可能的路由选项的简单方法。这就是为什么在Linux上,我将只执行外部和解析这样的事情:

ip -o route get 10.10.xx.xx 

而这又会给我想要的值(“SRC XX.XX.XX.XX”):

10.10.xx.xx dev eth1 src 10.20.xx.xx \ cache mtu 1500 advmss 1460 hoplimit 64 

我的问题是如果有一种本地方式来实现相同的结果,而不需要调用上述的外部命令。如果不是,那么你对Windows的建议是什么?


我也用InetAddress.isReachable(...)和外部ping与给定的源地址尝试,但回落到TCP回声,当在我的环境前者失败的防火墙,而其他提供误报。 (在我的测试虚拟机上,我有一个接口直接绑定到主机网络,另一个接口通过VM主机作为网桥(NAT)。因此对于ping来说,两个路由根据需要都不支持相反的方向。

我将不胜感激任何建议,如何与继续...

+0

虽然你不说出来明确,我得到你想找到不进行实际连接这些信息的印象。如果建立连接是可以接受的,[Socket.getLocalAddress()](http://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#getLocalAddress--)就足够了。 – VGR

+0

@VGR:你说得对 - 我想依赖路由数据而不是实际连接。让我们考虑一下配置应用程序,它将与使用连接的真实应用程序保持区别。而且只有远程主机才会启动所有的连接。从我这边来看,我可以做的很可能是ICMP请求,如ping。这就是我称之为“近似”的原因...... –

回答

0

最后,我结束了与解析路由表(IP4只,没有静态路由)。这是一段代码,也许对某人有用。更具体的路线优于更通用的路线。对于相同的网络部分长度,最好的度量标准会获胜

private static String findOutgoingIpForGivenAdress(String remoteIP) { 
    final String COMMAND = "route print -4"; 
    List<RouteInfo> routes = new ArrayList<>(); 
    try { 
     Process exec = Runtime.getRuntime().exec(COMMAND); 
     BufferedReader reader = new BufferedReader(new InputStreamReader(exec.getInputStream())); 

     String localIP = null; 
     String line; 
     /* examples: 
       0.0.0.0   0.0.0.0  10.172.180.1 10.172.180.36  20 
       0.0.0.0   0.0.0.0  10.187.20.1 10.187.20.225  25 
      10.172.180.0 255.255.255.0   On-link  10.172.180.36 276 
      10.172.180.36 255.255.255.255   On-link  10.172.180.36 276 
     */ 
     Pattern p = Pattern.compile("^\\s*(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+\\S+?\\s+(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+(\\d+)\\s*$"); 
     while ((line = reader.readLine()) != null) { 
      Matcher match = p.matcher(line); 
      if (match.matches()) { 
       String network = match.group(1); 
       String mask = match.group(2); 
       String address = match.group(3); 
       short maskLength = 0; 
       boolean networkMatch = network.contentEquals("0.0.0.0"); 
       if (!networkMatch) { 
        SubnetUtils subnet = new SubnetUtils(network, mask); 
        SubnetUtils.SubnetInfo info = subnet.getInfo(); 
        networkMatch = info.isInRange(remoteIP); 
        maskLength = Short.valueOf(info.getCidrSignature().split("/")[1]); 
       } 
       if (networkMatch) { 
        short metric = Short.valueOf(match.group(4)); 
        routes.add(new RouteInfo(address, maskLength, metric)); 
       } 
      } 
     } 
     Collections.sort(routes); 
     for (RouteInfo route : routes) { 
     } 
     if (!routes.isEmpty()) 
      return routes.get(0).source; 
     if (localIP != null) 
      return localIP; 
    } catch (Exception ex) { 
     ex.printStackTrace(); 
    } 
    return null; 
} 

而且有RouteInfo辅助类:

public class RouteInfo implements Comparable<RouteInfo> { 
    public final String source; 
    public final short maskLength; 
    public final short metric; 

    public RouteInfo(String src, short mask, short mtr) { 
     source = src; 
     maskLength = mask; 
     metric = mtr; 
    } 

    @Override 
    public int compareTo(RouteInfo ri) { 
     if (ri.maskLength != maskLength) 
      return ri.maskLength - maskLength; 
     return metric - ri.metric; 
    } 
}