简体   繁体   English

在 Windows 平台上使用 Java 查找特定路由的传出 IP 地址

[英]Finding outgoing IP address for specific route using Java on Windows platform

Although there is a lot of threads for finding machine IP addresses using combinations of NetworkInterface , InterfaceAddress , InetAddress , yet my case goes a bit beyond that.尽管有很多线程使用NetworkInterfaceInterfaceAddressInetAddress组合来查找机器 IP 地址,但我的情况远不止于此。

I need to determine outgoing IP address which will be used during communication with particular (given) target.我需要确定在与特定(给定)目标通信期间将使用的传出 IP 地址。 I have to assume that several interfaces with many ip addresses may be available at the host.我必须假设主机上可能有多个具有许多 ip 地址的接口。 This is the best approximation I can imagine for real life scenario where I have to supply to the remote machine which is known only by IP address an own IP that it may use to reach my host.这是我可以想象的最佳近似值,用于现实生活场景,我必须向仅通过 IP 地址知道的远程机器提供一个自己的 IP,它可以用来访问我的主机。

So far I have found no pure Java solution for this task.到目前为止,我还没有找到针对此任务的纯 Java 解决方案。 With my very limited Java knowledge I see no easy way to analyse possible routing options.以我非常有限的 Java 知识,我看不出分析可能的路由选项的简单方法。 That's why on Linux I will just execute externally and parse something like that:这就是为什么在 Linux 上我只会在外部执行并解析类似的东西:

ip -o route get 10.10.xx.xx

Which in turn will give me desired value ("src xx.xx.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

My question is if there is a native way to achieve the same result without calling external commands like above.我的问题是是否有一种本地方式可以在不调用上述外部命令的情况下实现相同的结果。 If not then what do you suggest for Windows equivalent?如果不是,那么您对 ​​Windows 等效建议是什么?


I have also tried using InetAddress.isReachable(...) and external ping with given source address but former fails on firewall in my environment when falling back to TCP echo, while the other provides false positives.我还尝试使用InetAddress.isReachable(...)和具有给定源地址的外部ping ,但前者在回退到 TCP 回显时在我的环境中的防火墙上失败,而另一个则提供误报。 (On my test VM I have one interface bound directly to the host network and second one as a bridge (NAT) via VM host. So for ping both routes do the trick by route via host is not supported in opposite direction as required.) (在我的测试 VM 上,我有一个接口直接绑定到主机网络,第二个接口作为通过 VM 主机的网桥 (NAT)。因此,对于 ping 两条路由,不支持在相反方向上按要求通过主机路由。)

I would appreciate any suggestions how to proceed with that...我将不胜感激任何建议如何继续...

Finally I ended up with parsing routing table (IP4 only, no static routes).最后我最终解析了路由表(仅限 IP4,没有静态路由)。 Here is a code snippet, maybe it can be useful to somebody.这是一个代码片段,也许它对某人有用。 More specific routes are preferred over more generic ones.更具体的路线比更通用的路线更受欢迎。 For the same network part lengths the best metric wins.对于相同的网络部分长度,最佳指标获胜。

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;
}

And there is RouteInfo helper class:还有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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM