Public Member Functions | Static Public Member Functions | Static Private Member Functions | Private Attributes | Static Private Attributes

PortScanner Class Reference

Encapsulates port scanning application. More...

Inheritance diagram for PortScanner:
Inheritance graph
[legend]
Collaboration diagram for PortScanner:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 PortScanner (RawIpAddress firstAddr, RawIpAddress lastAddr, int firstPort, int lastPort, PrintStream out)
 Creates instance of the PortScanner worker thread.
synchronized InetSocketAddress getNextSocketAddress ()
 Gets next socket address (end-point) from the pool.
synchronized void onPortConnected (long threadId, InetSocketAddress addr, boolean ok, String error, int timeMillis)
 Reports information about end-point.
synchronized void workerThreadSignIn (long threadId)
 Call-back from the worker thread reporting that it is alive.
synchronized void workerThreadSignOut (long threadId)
 Call-back from the worker thread reporting that it is zombie (dead waiting)
void run ()
 Starts working threads and monitors end-point scanning progress.

Static Public Member Functions

static void main (String[] args)
 Parses arguments then starts port scanner worker thread.

Static Private Member Functions

static String now ()
 Gets current time stamp (millis resolution)

Private Attributes

ServiceNames verboseServices
 Instance of the lookup database for TCP and UDP service names.
PrintStream out
 Output stream where the results are written.
boolean endpointDepleted
 True if pool is depleted.
RawIpAddress currentAddr
 The current IP address.
int currentPort
 The current TCP port.
RawIpAddress firstAddr
 The first IP address in the pool.
RawIpAddress lastAddr
 The last IP address in the pool.
int firstPort
 The first TCP port in the pool.
int lastPort
 The last TCP port in the pool.
int workerThreadCount = 0
 Number of active working threads.
int scannedEndpointCount = 0
 Number of scanned end-points.
int okEndpointCount = 0
 Number of connected end-points.
int failedEndpointCount = 0
 Number of failed to connect end-points.

Static Private Attributes

static final int connectionTimeout = 0
 Connection timeout constant.
static final int maxThreadCount = 1000
 Number of maximum allowed worker threads.
static final int maxEndpointsToScan = 1024 * 1024
 Maximum allowed number of end-points to scan.
static final boolean reportFailedEndpoints = false
 Should application report failed end-points or not.

Detailed Description

Encapsulates port scanning application.

The instance maintains pool of end-points (to be scanned) starts worker threads that scan end-points from the pool and displays progress to the user.

The static main() entry point facility parses command line arguments and starts the single instance of the class.

Author:
Mikica B Kocic

Definition at line 25 of file PortScanner.java.


Constructor & Destructor Documentation

PortScanner.PortScanner ( RawIpAddress  firstAddr,
RawIpAddress  lastAddr,
int  firstPort,
int  lastPort,
PrintStream  out 
)

Creates instance of the PortScanner worker thread.

Parameters:
firstAddrthe first raw IP address in range
lastAddrthe last raw IP address in range
firstPortthe first port in range
lastPortthe last port in range
outoutput stream for results

Definition at line 120 of file PortScanner.java.

References currentAddr, currentPort, endpointDepleted, firstAddr, firstPort, lastAddr, lastPort, and out.

Referenced by main().

    {
        this.firstAddr = firstAddr;
        this.lastAddr  = lastAddr;
        this.firstPort = firstPort;
        this.lastPort  = lastPort;
        this.out       = out;

        this.endpointDepleted = false;

        /* Set currentAddr <= copy of the firstAddr
         */
        this.currentAddr = new RawIpAddress( firstAddr );

        /* Set currentPort <= firstPort
         */
        this.currentPort = firstPort;
    }

Member Function Documentation

synchronized InetSocketAddress PortScanner.getNextSocketAddress (  ) [virtual]

Gets next socket address (end-point) from the pool.

The next end-point is retrieved by first scanning all addresses in range keeping the TCP port constant. This means that worker threads do not flood the specific IP address with different simultaneous connections on different TCP ports all at once.

The next algorithm clarifies previous explanation:

for( all ports in range ) { for ( all addresses in range ) { end-point := address + port; perform scan on end-point; } }

Implements PortConnect.Context.

Definition at line 161 of file PortScanner.java.

References RawIpAddress.compare(), currentAddr, currentPort, endpointDepleted, firstAddr, firstPort, RawIpAddress.getInetAddress(), RawIpAddress.increase(), lastAddr, lastPort, and RawIpAddress.set().

    {
        InetSocketAddress endpoint = null;

        while( ! endpointDepleted && endpoint == null ) 
        {
            /* Create end-point from the current IP address and the current TCP port
             */
            try {
                InetAddress addr = currentAddr.getInetAddress ();
                endpoint = new InetSocketAddress( addr, currentPort );
            } catch( Exception e ) {
                /* this should not happen; however, skip this address */
                e.printStackTrace ();
            }

            /* Advance to the next end-point 
             */
            currentAddr.increase ();

            if ( currentAddr.compare( lastAddr ) > 0 ) 
            {
                currentAddr.set( firstAddr ); // set currentAddr := firstAddr

                if ( ++currentPort > lastPort ) {
                    currentPort = firstPort; // start the loop all over again
                    endpointDepleted = true; // suppress further 'gets'
                }
            }
        }

        return endpoint;
    }
static void PortScanner.main ( String[]  args ) [static]

Parses arguments then starts port scanner worker thread.

Parameters:
args

Definition at line 368 of file PortScanner.java.

References firstAddr, firstPort, RawIpAddress.isSameVersion(), lastAddr, lastPort, out, PortScanner(), and RawIpAddress.subtract().

    {
        if ( args.length < 5 ) {
            System.err.println( 
                    "\nUsage: java -jar portScan.jar "
                    + "startAddr stopAddr startPort stopPort resultFile\n"
                    );
            System.exit( 0 );
        }

        String firstHostname = args[0];
        String lastHostname  = args[1];
        
        //////////////////////////////////////////////////////////////////////////////////
        
        /* Get the first raw IP address in range to scan
         */
        RawIpAddress firstAddr = null;
        try {
            firstAddr = new RawIpAddress( firstHostname );
        }  catch( UnknownHostException e ) {
            System.err.println( 
                    "\nError: Failed to parse startAddr " + firstHostname + "\n"
                    + e.toString () );
            System.exit( 0 );
        }

        //////////////////////////////////////////////////////////////////////////////////
        
        /* Get the last raw IP address in range to scan
         */
        RawIpAddress lastAddr = null;
        try {
            lastAddr = new RawIpAddress( lastHostname );
        } catch( UnknownHostException e ) {
            System.err.println( 
                    "\nError: Failed to parse stopAddr " + lastHostname + "\n"
                    + e.toString () );
            System.exit( 0 );
        }

        //////////////////////////////////////////////////////////////////////////////////
        
        /* Ensure not to mix IPv4 and IPv6 addresses
         */
        if ( ! firstAddr.isSameVersion( lastAddr ) ) {
            System.err.println( 
                    "\nError: The first and last IP addresses must be of the same IP version\n"
                    );
            System.exit( 0 );
        }

        //////////////////////////////////////////////////////////////////////////////////
        
        /* Ensure that the first is less then or equal the last IP address
         */
        long spanSize = lastAddr.subtract( firstAddr ) + 1; 
        if ( spanSize <= 0 ) {
            System.out.println( 
                    "\nWarning: The first IP address is greater than the last "
                    + "IP address.\nSwapping IP addresses...\n"
                    );
            RawIpAddress temp = firstAddr; firstAddr = lastAddr; lastAddr = temp;
        }

        //////////////////////////////////////////////////////////////////////////////////
        
        /* Parse the first port in range
         */
        int firstPort = -1;
        try {
            firstPort = Integer.parseInt( args[2] );
        } catch( NumberFormatException e ) {
            /* will fail later */
        }
        if ( firstPort < 0 ) {
            System.err.println( 
                    "\nError: The startPort must be integer between 0 and 65535\n"
                    );
            System.exit( 0 );
        }
        
        //////////////////////////////////////////////////////////////////////////////////
        
        /* Parse the last port in range
         */
        int lastPort  = 80;
        try {
            lastPort = Integer.parseInt( args[3] );
        } catch( NumberFormatException e ) {
            /* will fail later */
        }
        if ( lastPort < 0 ) {
            System.err.println( 
                    "\nError: The stopPort must be integer between 0 and 65535\n"
                    );
            System.exit( 0 );
        }

        //////////////////////////////////////////////////////////////////////////////////
        
        /* Ensure that the first port is less or equal than the last port
         */
        if ( firstPort > lastPort ) {
            System.out.println( 
                    "\nWarning: The first TCP port is greater than the last "
                    + "TCP port.\nSwapping TCP ports...\n"
                    );
            
            int temp = firstPort; firstPort = lastPort; lastPort = temp;
        }
        
        //////////////////////////////////////////////////////////////////////////////////
        
        /* Open the results file
         */
        String result = args[4];

        PrintStream out = null;
        try {
            FileOutputStream file = new FileOutputStream( result );
            out = new PrintStream( file );
        } catch( IOException e ) {
            System.err.println( 
                    "\nError: Failed to open file '" + result + "' for writing\n"
                    + e.toString () );
            System.exit( 0 );
        }

        //////////////////////////////////////////////////////////////////////////////////
        
        /* We have all parameters valid now.
         * Create the instance of the port scanner and start its main thread...
         */
        PortScanner ps = new PortScanner( firstAddr, lastAddr, firstPort, lastPort, out );
        ps.start ();
    }
static String PortScanner.now (  ) [static, private]

Gets current time stamp (millis resolution)

Returns:
time in ISO format

Definition at line 252 of file PortScanner.java.

Referenced by onPortConnected(), and run().

    {
        Calendar cal = Calendar.getInstance ();
        SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS " );
        return sdf.format( cal.getTime() );
    }
synchronized void PortScanner.onPortConnected ( long  threadId,
InetSocketAddress  addr,
boolean  ok,
String  error,
int  timeMillis 
) [virtual]

Reports information about end-point.

(Call-back from the scanning worker thread.)

Implements PortConnect.Context.

Definition at line 200 of file PortScanner.java.

References failedEndpointCount, ServiceNames.lookup(), now(), okEndpointCount, out, reportFailedEndpoints, scannedEndpointCount, and verboseServices.

    {
        ++scannedEndpointCount;
        
        if ( ok ) {
            ++okEndpointCount;
        } else {
            ++failedEndpointCount;
        }

        if ( ok || ( ! ok && reportFailedEndpoints ) ) 
        {
            String serviceName = verboseServices.lookup( "tcp", addr.getPort () );
    
            if ( serviceName != null ) {
                out.println( now () 
                        + error + ": " + addr.getAddress() + ":" + addr.getPort ()
                        + " (" + serviceName + ")"
                        + ", Thread " + threadId + ", Elapsed " + timeMillis + " ms" );
            } else {
                out.println( now () 
                        + error + ": " + addr.getAddress() + ":" + addr.getPort ()
                        + ", Thread " + threadId + ", Elapsed " + timeMillis + " ms" );
            }

            out.flush ();
        }
    }
void PortScanner.run (  )

Starts working threads and monitors end-point scanning progress.

Definition at line 263 of file PortScanner.java.

References connectionTimeout, failedEndpointCount, firstAddr, firstPort, lastAddr, lastPort, maxEndpointsToScan, maxThreadCount, now(), okEndpointCount, out, scannedEndpointCount, RawIpAddress.subtract(), verboseServices, and workerThreadCount.

    {
        long startTime = System.nanoTime ();

        out.println( now () + "Started...\n" );

        /* Load service names
         */
        verboseServices = new ServiceNames( "services.txt" );

        /* Calculate how long it will take to perform the scan
         * (if all ports throw timeouts)
         */
        int addrSpanSize = (int)( lastAddr.subtract( firstAddr ) + 1 );
        int portSpanSize = lastPort - firstPort + 1;
        int endpointCount = addrSpanSize * portSpanSize;

        System.out.println( "\nScanning " 
                + addrSpanSize + " hosts * " 
                + portSpanSize + " ports/host = total "
                + endpointCount + " end-points..."
                );
        
        /* Ensure that we do not scan impossible range of end-points
         */
        if ( endpointCount >= maxEndpointsToScan ) {
            String error = "Error: Cowardly refusing to scan more than " 
                + maxEndpointsToScan + " end-points!\n\n"
                + "If you really wanted to scan " + endpointCount + " end-points, "
                + "please start multiple instances of the port scanner "
                + "(either sequantially or in parallel).\n";
            
            out.println( now () + error ); 
            out.println( now () + "Completed." );
            
            System.err.println( "\n" + error ); 
            System.out.println( "Completed." );
            
            out.flush ();
            out.close ();
            
            return;
        }
        
        /* Start port scanner working threads (see PortConnect.run()) in the pool.
         * 
         */
        ExecutorService threadPool = Executors.newFixedThreadPool( maxThreadCount );
        for ( int i = 0; i < maxThreadCount; ++ i )
        {
            threadPool.execute( new PortConnect( this, connectionTimeout ) );
        }
        
        /* Wait all threads to complete. While waiting, display the progress.
         */
        while( true )
        {
            try {
                Thread.sleep( 1000 );
            } catch( InterruptedException e ) {
                break;
            }

            synchronized( this )
            {
                /* Display progress...
                 */
                int elapsed = (int) ( ( System.nanoTime () - startTime ) / 1000000000l );
                
                System.out.print(
                        "\rElapsed " + elapsed + " sec; "
                        + "Scanned " + scannedEndpointCount
                        + " of " + endpointCount
                        + " end-points (" + okEndpointCount
                        + " alive + " + failedEndpointCount
                        + " dead); " + workerThreadCount 
                        + " threads active                 "
                        );
                System.out.flush ();
                
                /* Done if no more working threads.
                 */
                if ( workerThreadCount <= 0) {
                    break;
                }
            }
        }

        /* Be nice and clean-up...
         */
        out.println( "\n" + now() + "Completed." );

        out.flush ();
        out.close ();
        
        threadPool.shutdownNow ();
        
        System.out.println( "\nCompleted." );
    }
synchronized void PortScanner.workerThreadSignIn ( long  threadId ) [virtual]

Call-back from the worker thread reporting that it is alive.

Implements PortConnect.Context.

Definition at line 234 of file PortScanner.java.

References workerThreadCount.

synchronized void PortScanner.workerThreadSignOut ( long  threadId ) [virtual]

Call-back from the worker thread reporting that it is zombie (dead waiting)

Implements PortConnect.Context.

Definition at line 242 of file PortScanner.java.

References workerThreadCount.


Member Data Documentation

final int PortScanner.connectionTimeout = 0 [static, private]

Connection timeout constant.

Definition at line 31 of file PortScanner.java.

Referenced by run().

The current IP address.

Definition at line 67 of file PortScanner.java.

Referenced by getNextSocketAddress(), and PortScanner().

int PortScanner.currentPort [private]

The current TCP port.

Definition at line 71 of file PortScanner.java.

Referenced by getNextSocketAddress(), and PortScanner().

boolean PortScanner.endpointDepleted [private]

True if pool is depleted.

Definition at line 63 of file PortScanner.java.

Referenced by getNextSocketAddress(), and PortScanner().

Number of failed to connect end-points.

Definition at line 107 of file PortScanner.java.

Referenced by onPortConnected(), and run().

The first IP address in the pool.

Definition at line 75 of file PortScanner.java.

Referenced by getNextSocketAddress(), main(), PortScanner(), and run().

int PortScanner.firstPort [private]

The first TCP port in the pool.

Definition at line 83 of file PortScanner.java.

Referenced by getNextSocketAddress(), main(), PortScanner(), and run().

The last IP address in the pool.

Definition at line 79 of file PortScanner.java.

Referenced by getNextSocketAddress(), main(), PortScanner(), and run().

int PortScanner.lastPort [private]

The last TCP port in the pool.

Definition at line 87 of file PortScanner.java.

Referenced by getNextSocketAddress(), main(), PortScanner(), and run().

final int PortScanner.maxEndpointsToScan = 1024 * 1024 [static, private]

Maximum allowed number of end-points to scan.

Definition at line 39 of file PortScanner.java.

Referenced by run().

final int PortScanner.maxThreadCount = 1000 [static, private]

Number of maximum allowed worker threads.

Definition at line 35 of file PortScanner.java.

Referenced by run().

int PortScanner.okEndpointCount = 0 [private]

Number of connected end-points.

Definition at line 103 of file PortScanner.java.

Referenced by onPortConnected(), and run().

PrintStream PortScanner.out [private]

Output stream where the results are written.

Definition at line 54 of file PortScanner.java.

Referenced by main(), onPortConnected(), PortScanner(), and run().

final boolean PortScanner.reportFailedEndpoints = false [static, private]

Should application report failed end-points or not.

Disabled by default: Who is interested in failed ports at all?

Definition at line 44 of file PortScanner.java.

Referenced by onPortConnected().

Number of scanned end-points.

Definition at line 99 of file PortScanner.java.

Referenced by onPortConnected(), and run().

Instance of the lookup database for TCP and UDP service names.

Definition at line 50 of file PortScanner.java.

Referenced by onPortConnected(), and run().

int PortScanner.workerThreadCount = 0 [private]

Number of active working threads.

Definition at line 95 of file PortScanner.java.

Referenced by run(), workerThreadSignIn(), and workerThreadSignOut().


The documentation for this class was generated from the following file: