#!/usr/bin/perl
#
# sc4nner
# by Laurens (laurens@netric.org)
#
# simple forking c-class banner scanner
# tips to make it faster are welcome ;-)
#

use strict;
use Getopt::Std;
use Socket;

my (%opt);
my $version = 'v0.1';
my $timeout = 1;

getopts("c:p:t:l:g:s:h", \%opt);
&usage if not %opt or $opt{h};

if ($opt{c} and $opt{p}) {
if ($opt{t}) {
$timeout = $opt{t};
}
&header;
print "[ Range: $opt{c}.1-255 ] [ Port: $opt{p} ] [ Timeout: $timeout ]";
print " [ Grep: $opt{g} ]" if $opt{g};
print " [ Send: $opt{s} ]" if $opt{s};
print "\n\n";
$| = 1;
&forkje("$opt{c}","$opt{p}","$timeout");
}
else {
&usage;
}

sub header {
print "\n[ sc4nner $version ]\n";
print "by Laurens (laurens\@netric.org)\n\n";
}

sub usage {
&header;
print "usage: $0 [-c <c-class>] [-p <port>] [-t <timeout>] [-l <logfile>] [-g <grep>] [-s <send>] [-h]\n";
print "-c : c-class ip range\n";
print "-p : port to scan\n";
print "-t : timeout (default 1)\n";
print "-l : log to file\n";
print "-g : grep on output\n";
print "-s : send to socket\n";
print "-h : help\n";
print "example: $0 -c 192.168.1 -p 22\n";
exit;
}

sub forkje {
my ($range,$port,$timeout) = @_;
my ($i,$pid,$oldpid,$target,$output,$child,$parent);
my (@children);

$parent = 0;
@children = ();

FORK: for ($i = 1; $i < 255; $i++) {
$oldpid = $$;
$pid = fork;

if (not defined $pid) {
die "Can't fork: $!\n";
}
elsif ($pid == 0) {
$parent = $oldpid;
@children = ();
last FORK;
}
else {
push @children, $pid;
}
}
if ($parent) {
$target = "$range.$i";
($output) = tcp_connect("$target","$port","$timeout");
if ($output) {
chop($output);
if ($opt{l}) {
open (LOG,">>$opt{l}") or die "Can't open $opt{l} for writing $!";
print LOG "$target\t: $output\n";
close (LOG);
}
elsif ($opt{g}) {
if ($output =~ /$opt{g}/i) {
print "$target\t: $output\n";
}
}
else {
print "$target\t: $output\n";
}
}
}
else {
while ($child = shift @children) {
waitpid $child, 0;
}
}
}

sub tcp_connect {
my $host = inet_aton("$_[0]");
my $port = "$_[1]";
my $timeout = "$_[2]";
my @output;

if (defined($host)) {
$SIG{ALRM} = 'handler';
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp')||0) || die("Socket problems");
alarm($timeout);
if (connect(SOCK, pack "SnA4x8", 2, $port, $host)) {
alarm(0);
select(SOCK);
alarm($timeout);
if ($opt{s}) {
send(SOCK, "$opt{s}\n", 0);
}
while (<SOCK>) {
push @output, $_;
}
alarm(0);
select(STDOUT);
close(SOCK);

return @output;
}
else {
return 0;
}
}
}

sub handler {
close (SOCK);
}