Getting IP address, MAC address, and subnet mask of localhost

Determining local IP address is easy, but determining MAC address, and subnet mask in Java has always been one of those hairy problems that sends me Googling. Using some of those same Java utilities, we can add a few Scala-isms and shorten the whole thing up significantly.

To get the IP address we can just statically retrieve an java.net.InetAddress to localhost and get the address String from that .

scala> import java.net._
import java.net._

scala> val localhost = InetAddress.getLocalHost
localhost: java.net.InetAddress = mymachine.domain.local/10.35.0.51

scala> val localIpAddress = localhost.getHostAddress               
localIpAddress: java.lang.String = 10.35.0.51

scala> println(localIpAddress)                      
10.35.0.51

Wrapping our localhost address object in a java.net.NetworkInterface, we can get the MAC address, or hardware address, formatted as an array of bytes, which we can convert to a Scala List, allowing us to format as hex and concatenate with the “:” separator with relatively little effort. Note that NetworkInterface.getNetworkAddress() requires Java 1.6.

scala> val localNetworkInterface = NetworkInterface.getByInetAddress(localhost)
localNetworkInterface: java.net.NetworkInterface = 
name:en0 (en0) index: 4 addresses:
/10.35.0.51;
/fe80:0:0:0:223:32ff:fec6:8a8a%4;

scala> val localMacAddress = localNetworkInterface.getHardwareAddress.toList.map(b => String.format("%02x",b.asInstanceOf[AnyRef])).mkString(":")
localMacAddress: String = 00:23:32:c6:8a:8a

We can use the same java.net.NetworkInterface instance to get us the subnet mask by retrieving the addresses for all interfaces (also a Java 1.6-only method) and for each of these retrieve the network prefix length, which essentially represents the subnet mask. We import scala.collection.JavaConversions._ to give us implicit Java-to-Scala list conversions, which I believe was introduced in Scala 1.8.

scala> import scala.collection.JavaConversions._       
import scala.collection.JavaConversions._

scala> val localSubnetCidrs = localNetworkInterface.getInterfaceAddresses.map(_.getNetworkPrefixLength)
localSubnetCidrs: scala.collection.mutable.Buffer[Short] = ArrayBuffer(24, 64)

Hmmm…that’s not quite right. 24 and 64 aren’t what we expect to see for subnet masks. But worry not, we’re on our way, right now we have the CIDR notation version of the subnet masks, in IPv4 and IPv6 respectively. We then just need to filter out the IPv6 address and convert the CIDR notation to our expected format, which I do using the import org.apache.commons.net.util.SubnetUtils class from Apache Commons Net

scala> import org.apache.commons.net.util.SubnetUtils
import org.apache.commons.net.util.SubnetUtils

scala> val localSubnetAddresses = localSubnetCidrs.filter(l => !(l < 0 || l > 32)).map(c => (new SubnetUtils("0.0.0.0/"+c)).getInfo.getNetmask)
localSubnetAddresses: scala.collection.mutable.Buffer1 = ArrayBuffer(255.255.255.0)

scala> println(localSubnetAddresses(0))
255.255.255.0

Voilé!

, , , , , ,

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>