8

In Java, I'd like to find the java.net.NetworkInterface corresponding with the interface used reach the default gateway. The names of the interfaces, etc, are not know ahead of time.

In other-words, if the following was my routing table, I would want the interface corresponding with "bond0":

$ netstat -r
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
10.10.10.0     *               255.255.255.0   U         0 0          0 bond0
10.10.11.0     *               255.255.255.0   U         0 0          0 eth2
10.10.11.0     *               255.255.255.0   U         0 0          0 eth3
10.10.12.0     *               255.255.255.0   U         0 0          0 eth4
10.10.13.0     *               255.255.255.0   U         0 0          0 eth5
default         mygateway      0.0.0.0         UG        0 0          0 bond0

After doing some google searching, I still haven't found any answer.

edit:
The java runtime must "know" how to get this information (not to say that it's exposed). When joining a java.net.MulticastSocket to a multicast group using the join(InetAddress grpAddr) call (which does not specify an interface), the apparent behavior seems to be to join on the "default" interface (as define above). This works even when the default intf is not the first interface listed in the routing table. However, the underlying POSIX call that joins an mcast group requires this information!:

struct ip_mreqn group;
group.imr_multiaddr = ...
group.imr_address = **address of the interface!**
setsockopty(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));

The point: by providing a method to join a multicast group that doesn't require the intf, the java platform, implicitly, must know how to determine the appropriate intf on each platform.

Adam Lear
  • 38,111
  • 12
  • 81
  • 101
Josh
  • 323
  • 4
  • 8

2 Answers2

7

My way is:

try(DatagramSocket s=new DatagramSocket())
{
    s.connect(InetAddress.getByAddress(new byte[]{1,1,1,1}), 0);
    return NetworkInterface.getByInetAddress(s.getLocalAddress()).getHardwareAddress();
}

Because of using datagram (UDP), it isn't connecting anywhere, so port number may be meaningless and remote address (1.1.1.1) needn't be reachable, just routable.

motas
  • 95
  • 1
  • 2
  • in my experience this does not work with windows and ipv6. getLocalAddress returns a bogus v4 address despite being bound as a v6 socket – the8472 Feb 28 '15 at 12:45
  • Works for me with Microsoft-android-emulator, docker, and OpenVPN on Windows10 and Hyper-V enabled. – AlexS Feb 10 '17 at 15:51
  • 1
    Pay attention that if the address is not routable (for example, because there is no default route or you are on an IPv6-only network), then `NetworkInterface.getByInetAddress()` will return `null`. This is a good way to detect if you have a valid network configuration. – Guss Dec 15 '19 at 11:10
0

As far as I know, there will be no good way to do this, because such low level details are very difficult for Java to implement in a cross-platform way. java.net.NetworkInterface may help a little, but if the available methods aren't enough you might have to resort to something a little uglier.

Is this something that will run on a specified platform forever, or does it need to be more portable? At worst, you could try to exec a system command and parse the output, but this is not very portable or stable.

Some related topics:

Is it possible to get the default gateway IP and MAC addresses in java?

Finding SSID of a wireless network with Java

Community
  • 1
  • 1
Carl
  • 905
  • 5
  • 9
  • Ok, I see your point. However, it looks like that call still requires an address, yes? java.net.NetworkInterface can get the interfaces (and their addresses), and a little cleverness can decide which one owns the address given. I think your problem is more complex, because you're looking for lower level routing information first, then backwards to find an interface associated with the (default) route. – Carl Aug 03 '12 at 15:54
  • It requires the multicast address (i.e., special address in 224.xxx-239.xxx), not the address of the interface. No such information is provided in the arguments. So the problem that the "join" call must solve is the same. It magically picks the one with the default route (apparent behavior). Similarly, I want to know which interface has the default route. – Josh Aug 03 '12 at 16:05
  • I guess, if there really is no exposed way of finding the intf with the def route, I'm just a bit frustrated, since the problem of determining it in a platform indep way appears to be solved somewhere under the hood. Of course, to be clear, I haven't "proven" that join always picks the right intf (but empirically it always works!). So I can really only presume that, under the hood, it knows... – Josh Aug 03 '12 at 16:16
  • Understood. So if it really does figure it out under the hood, you could maybe do the ugly thing of using `java.net.MulticastSocket` to join the default interface, then use `MulticastSocket.getNetworkInterface` or `getInterface` to find out which one it chose. Then leave the group. This isn't very secure since you're opening up multicast sockets for no reason, so it's still not an ideal solution, of course. – Carl Aug 03 '12 at 16:22