Wednesday, September 1, 2010

Finding RMI Ports with Groovy

In a previous blog post, I demonstrated using a simple Groovy script to display all names bound to a particular RMI registry on a specified host/port.  This script is easy to understand and use, but does require knowing which host and port to extract the bound names for.  The candidate ports could be identified via a tool like netstat or based on error information in a log message (such as stating an AlreadyBoundException).  In this blog post, I demonstrate another approach using Groovy to looking over a range of ports to find RMI bound names.  This is not a particularly efficient approach, but can be used to check over a range of ports for potential RMI registries and for listing their bound names.

rmiFinder.groovy
import java.rmi.ConnectException
import java.rmi.RemoteException
import java.rmi.registry.LocateRegistry
import java.rmi.registry.Registry

if (!args || args.length < 3)
{
   println "Provide name of host and range of ports (lowest and highest) on which to look for RMI-exposing ports."
   System.exit(-1)
}
def host = args[0]
def initialPort = args[1] as Integer
def finalPort = args[2] as Integer

println "Searching for RMI-exposed ports on host ${host} within port range ${initialPort}:${finalPort}"
for (port in initialPort..finalPort)
{   
   registry = LocateRegistry.getRegistry(host, port)

   try
   {
      def boundNames = registry.list()
      println "\nRMI Registry found on host:port ${host}:${port} with service names"
      boundNames.each{println "\t${it}"}
   }
   catch (ConnectException connectEx)
   {
      print "."
      // no RMI registry or cannot connect to it
   }
   catch (RemoteException remoteEx)
   {
      print "."
      // no RMI registry or cannot connect to it remotely (covers AccessException)
   }
}
println "\nNo ports with RMI exposed services found on host ${host} within range ${initialPort}:${finalPort}"

The simple rmiFinder.groovy script makes use of the approach demonstrated in the previous post regarding looking up a registry's bound names on a particular registry, but adds a simple looping mechanism to loop over a range of ports on the specified host rather than looking at a single specified port on that host.

The Registry.list() method can throw a RemoteException or its child AccessException or a ConnectException.  All three of these lead to giving up on the particular port being tried in the loop and moving onto the next port.  If none of these expected possible exceptions are caught, then the names of RMI services bounds to that port are displayed.  I actually could have caught a RemoteException only because both AccessException and ConnectException extend RemoteException.

This approach is not particularly speedy.  It takes a relatively long time to attempt the Registry.list() invocation and handle the inevitable exception handling that occurs for all non-RMI ports.  Because of this incredible slowness, I had the script print out a period (.) for each failed attempt to indicate some progress being made.

The following screen snapshot shows this simple script in action.  I started a simple Java application with an exposed RMI service on port 2999 to demonstrate.  Because I had the luxury of knowing the port I was looking for, I could keep my example to a small range (2990 to 3000).  This made it relatively quick.


The simple script did its job: it found an RMI registry on port 2999 and listed the single name bound to that registry: "jmxrmi".

It is quickest to use netstat, a similar tool, or logged output to determine a few likely candidate ports for the RMI port in question and then run the previously covered script against those.  However, the script demonstrated in this post could be used to check against an arbitrary range of ports for RMI-exposed services in a more automated (albeit slower) approach.  Another approach to automate this might be a script that runs a tool like netstat, parses its output, and tries only ports specified in that output that can not be ruled out as non-RMI ports.  But that is left for a possible future blog post.

No comments: