
                                        /-----------------------------\
                                        | Xine - issue #4 - Phile 112 |
                                        \-----------------------------/

#!/usr/bin/perl

# scappa, b0z0/iKX
# a tcp service scanner, for the perl script series.
# scans a given set of internet hosts (range given by IP) for a given
# service version at a port, basing on a given scanning string (could be 
# a regexp even). 
# just written becoz someone asked me to do so.

use Socket;
require "getopts.pl";

::Getopts('b:e:t:s:p:');
# -b beginning IP address (either X.Y.Z.K or X.Y.Z. or X.Y. or X.)
#    if you leave one or more of the IP address bytes null then they will
#    be simply replaced with a zero value (1 for the last byte), that is 
#    beginning of that class
# -e ending IP address (either X.Y.Z.J or X.Y.Z. or X.Y. or X.)
#    if you leave one or more of the IP address bytes null then they will
#    be simply replaced with a 255 value (254 for the last byte), that is 
#    end of that class
# -p port where to search for service
# -t timeout when waiting for the connection
# -s search string to wait for (could be also a regular expression).
#
# Usage samples:
#   scan a given range for wingates
#     ./scappa -b 194.35.54.36 -e 194.35.54.69 -p 23 -s "Wingate>"
#   scan a C class for wingates
#     ./scappa -b 194.35.54 -p 23 -s "Wingate>"
#   scan a B class for wingates
#     ./scappa -b 194.35 -p 23 -s "Wingate>"

if (!($opt_b)) {
 print "Not enough parameters, read the script for infos\n";
 exit();
}

($from_1,$from_2,$from_3,$from_4)=split(/\./,$opt_b);

if (!($opt_e)) {
  $opt_e=join(".",$from_1,$from_2,$from_3);
}
($to_1,$to_2,$to_3,$to_4)=split(/\./,$opt_e);

$wait_to= $opt_t;
$wait_to=5 if (!($wait_to));

$search_string=$opt_s;
$search_string='Wingate>' if (!($search_string));

$porta=$opt_p;
$porta=23 if (!($porta));

foreach $exam ($from_1,$from_2,$from_3,$from_4) {
 $exam=0 if (($exam eq '') || (!($exam =~(/\d{1,3}/))) || ($exam>254));
}
$from_4++ if $from_4==0;

foreach $exam ($to_1,$to_2,$to_3,$to_4) {
 $exam=255 if (($exam eq '') || (!($exam =~(/\d{1,3}/))) || ($exam>254));
}
if (!($to_4==255)) { $to_4++;} else
{
   $to_3++;$to_4=1;
   if ($to_3>255) { $to_2++;$to_3=0;}
   if ($to_2>255) { $from_1++;$to_2=0;}
}

$|=1;

$AF_INET = 2;
$SOCK_STREAM = 1; # should be 2 for SunOS
$sockaddr = 'S n a4 x8';

chop ($hostname = `hostname `);
($name, $aliases, $type, $len, $thisaddr) = gethostbyname ($hostname);
($name, $aliases, $proto) = getprotobyname ('tcp');

$outta = pack ($sockaddr, $AF_INET, 0, $thisaddr);

while (!(($from_1==$to_1) && ($from_2==$to_2) &&
         ($from_3==$to_3) && ($from_4==$to_4))) {

  socket (OUT, $AF_INET, $SOCK_STREAM, $proto) || die "socket: $!";
  bind (OUT, $outta) || die "bind: $!";
  $string='';

  $to=join('.',$from_1,$from_2,$from_3,$from_4);
  $targetaddr=pack('C4',$from_1,$from_2,$from_3,$from_4);
  $that = pack ($sockaddr, $AF_INET, $porta, $targetaddr);

  print "$to: ";
  if (connect (OUT, $that))
   {
    select (OUT);
    $|=1;
    select (STDOUT);

    $SIG{'ALRM'}= sub{die};
    alarm ($wait_to);
    eval << 'EOW';
    while (read (OUT, $buf, 1)) { $string.=$buf; }
EOW
    alarm (0);
    print "Requested service ";
    $_=$string;
    if (!(/$search_string/)) { print "not ";}
    print "present.\n";
   }
  else
   {
    print "Can't connect: $!\n";
   }
   close(OUT);
   $from_4++;
   if ($from_4>254) { $from_3++;$from_4=1;}
   if ($from_3>255) { $from_2++;$from_3=0;}
   if ($from_2>255) { $from_1++;$from_2=0;}
}


