#!/usr/bin/perl -w
#
# [ http://www.rootshell.com/ ]
#
#       $Id: ss.pl,v 1.5 1998/01/28 22:08:56 zap Exp $
#
# Scan for open specified port on a class C IP address block, or all
# open ports on a single host. 
#
# Copyright (c) 1998 by zap <zap@arosnet.se>
#
# $Log: ss.pl,v $
# Revision 1.5  1998/01/28 22:08:56  zap
# More verbose. Source cleanup, more and/or instead of if().
#
# Revision 1.4  1998/01/27 06:11:40  zap
# Added some resolv functions, and more checking. Source cleanup.
#
# Revision 1.3  1998/01/26 10:34:29  zap
# Removed some unused variables. Made a private verbose variable for each
# type. Cleaned up the source a bit.
#
# Revision 1.2  1998/01/26 10:12:38  zap
# Added single host port scan.
#
# Revision 1.1  1998/01/26 09:35:00  zap
# Initial revision
#

use strict;
use Socket;

my ($verbose_ccipa, $verbose_shps, $connect_time, $protocol_name, $protocol_id,
    $ccnip, $port, $scdnip, $ecdnip, $i, $iaddr, $paddr, $cdnip);

$verbose_ccipa  = 1;
$verbose_shps   = 0;
$connect_time   = 1;
$protocol_name  = "tcp";
$protocol_id    = getprotobyname($protocol_name);

($ccnip, $port, $scdnip, $ecdnip) = @ARGV;

$ccnip or die global_usage();
$port and class_c_network_specified_port_scan() or single_host_port_scan();

sub global_usage()
{
        print "\nSingle host port scan:\n",
              " \$ ss.pl <dns/ip>\n",
              " - Scan for all open ports on <dns/ip>.\n\n",
              "Class C IP specified port scan:\n",
              " \$ ss.pl <ccnip> <port> [<scdnip>] [<ecdnip>]\n",
              " - Scan for specified open <port> on <ccnip>.<1|<scdnip>>\n",
              "   to <ccnip>.<255|<ecdnip>>.\n\n";
        
        exit 1;
}

sub class_c_network_specified_port_scan()
{
        $ccnip !~ /[0-9]+\.[0-9]+\.[0-9]+/ and
                die "Error: $ccnip [ccnip] is not in format <0-255>.<0-255>.",
                    "<0-255>\n";

        if ($scdnip) {
                $scdnip !~ /[0-9]+/ and
                        die "Error: $scdnip [scdnip] is not in format ",
                            "<0-255>\n";
                $scdnip > 254 and $scdnip = 254;
                $scdnip < 0 and $scdnip = 1;
        } else {
                $scdnip = 1;
        }

        if ($ecdnip) {
                $ecdnip !~ /[0-9]+/ and
                        die "Error: $ecdnip [ecdnip] is not in format ",
                            "<0-255>\n";
                $ecdnip > 254 and $ecdnip = 254;
                $ecdnip < 0 and $ecdnip = 1;
        } else {
                $ecdnip = 254;
        }

        print "\nScanning for open port $port on $ccnip.($scdnip > $ecdnip) ",
              "using $protocol_name protocol.\n";

        $verbose_ccipa and 
                print "Verbose mode is on, printing refused connections.\n\n"
        or
                print "Verbose mode is off, only printing accepted ",
                         "connections.\n\n";

        for ($i = $scdnip; $i < $ecdnip + 1; $i++) {
                $SIG{"ALRM"}    = sub { close(SOCKET); };
                alarm $connect_time;

                socket(SOCKET, PF_INET, SOCK_STREAM, $protocol_id);

                $cdnip  = "$ccnip.$i";
                $iaddr  = inet_aton($cdnip);
                $paddr  = sockaddr_in($port, $iaddr);

                if (connect(SOCKET, $paddr)) {
                        printf "%0s %20s %14s %12s", $protocol_name, $cdnip,
                               $port;
                        print "Connection accepted.\n";
                        close(SOCKET);
                } else {
                        if ($verbose_ccipa) {
                                printf "%0s %20s %14s %12s", $protocol_name,
                                        $cdnip, $port;
                                print "Connection refused.\n";
                        }
                        close(SOCKET);
                }
        }
        exit 1;
}

sub single_host_port_scan()
{
        if ($ccnip !~ /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { 
                gethostbyname($ccnip) or
                        die "Error: Can't resolv $ccnip [dns/ip].\n";
        }

        print "\nScanning for all open ports on $ccnip using $protocol_name ",
              "protocol.\n";

        $verbose_shps and
                print "Verbose mode is on, printing refused connections.\n\n"
        or
                print "Verbose is off, only printing accepted connections.\n\n";

        for ($port = 1; $port < 65536; $port++) {
                $SIG{"ALRM"}    = sub { close(SOCKET); };
                alarm $connect_time;
                
                socket(SOCKET, PF_INET, SOCK_STREAM, $protocol_id);

                $iaddr  = inet_aton($ccnip);
                $paddr  = sockaddr_in($port, $iaddr);   
        
                if (connect(SOCKET, $paddr)) {
                        printf "%0s %20s %14s %12s", $protocol_name, $ccnip,
                                $port;
                        print "Connection accepted.\n";
                        close(SOCKET); 
                } else {
                        if ($verbose_shps) {
                                printf "%0s %20s %14s %12s", $protocol_name,
                                       $ccnip, $port;
                                print "Connection refused.\n";
                        }
                        close(SOCKET);
                }
        }
        exit 0;
}
