Sunday, August 23, 2009

Finding Your IP v4 Broadcast Address Using Java

I was pleased when Java 1.4 added the ability to find the available network interfaces, and more recently added the ability to get details of the addresses of those interfaces (in 1.6), because these features make it easier to write "system" tools.

As part of writing a Java interface to the HDHomeRun, I wanted to broadcast a discovery packet to my local subnet, to which the HDHomeRun would respond. At first I just hard-coded the address 192.168.0.255, which worked fine, but wasn't very portable. In fact, I've since changed routers, which happened to change the local subnet to 192.168.1.0, with a broadcast address of 192.168.1.255. So, I made use of the Java classes java.net.NetworkInterface and java.net.InterfaceAddress, roughly as follows:

Enumeration<NetworkInterface> interfaces =
    NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
  NetworkInterface networkInterface = interfaces.nextElement();
  if (networkInterface.isLoopback())
    continue;    // Don't want to broadcast to the loopback interface
  for (InterfaceAddress interfaceAddress :
           networkInterface.getInterfaceAddresses()) {
    InetAddress broadcast = interfaceAddress.getBroadcast();
    if (broadcast == null)
      continue;
    // Use the address
  }
}

I was surprised when I ran my test of this code to discover that the broadcast address reported was 255.255.255.255. Something was clearly wrong. It turns out that the JRE will use the IPv6 stack if it is available, else will use IPv4. When using an IPv6 stack, InterfaceAddress never has an accurate IPv4 broadcast address. Sigh.

Fortunately, there is a Java system property that directs the JRE to use the IPv4 stack:
    java.net.preferIPv4Stack

This can be set on the command line (i.e. -Djava.net.preferIPv4Stack=true), or it can be set prior to calling NetworkInterface.getNetworkInterfaces(). Changing the system property after the first call to getNetworkInterfaces() has no effect (i.e. it is too late; it appears that the choice of network stacks is locked at that point).  I suspect that any call that loads the networking stack will lock the choice.

I found the pointer to the Java system property in a Sun Forums posting by Ivan Jozsef Balazs.

2 comments: