#!/usr/bin/perl
# Simple forking port scanner
# By: magikh0e

use strict;
use warnings;
use IO::Socket::INET;
use Getopt::Std;

my $opts = 'hvdt:p:s:e:';
my %opt;
getopts( "$opts", \%opt );


sub help() {
print <<EOF;

    Simple Forking port scanner
	   By: magikh0e
      Http://magikh0e.ihtb.org
    
     usage: $0 [-hvdtpse]

     -h        		: this (help) message
     -v        		: verbose output
     -d        	    	: print debugging messages to stderr
     -t <IP/Host>   	: Target IP or hostname
     -p <tcp/udp>	: Protocol to scan on (default: tcp)
     -s <port_number>	: Starting port (default: 1)
     -e <port_number>	: End port (default: 65535)

     $0 -t 127.0.0.1 -p tcp -s 1 -e 80

EOF
exit;
}

help() if $opt{h} || !%opt;

$| = 1;
my $host = $opt{t};
my $protocol = $opt{p};
my $port1 = $opt{s};
my $port2 = $opt{e};
my $parent = 0;
my @kids = ();


$protocol = 'tcp' unless $protocol;
$port1 = 1 unless $port1;
$port2 = 65535 unless $port2;

if ($opt{t}) {
print "Scanning: $host on ($protocol) Ports: [$port1-$port2]\n";
my $port;
FORK: for ($port=$port1; $port<=$port2; $port++) {
	my $oldpid = $$;
	my $pid = fork;

	if (not defined $pid) {
		if ($! =~ /Resource temporarily unavailable/) {
			&DoKill;
			$port --;
		} else { die "Can't fork: $!\n"; }
	} elsif ($pid == 0) {
		$parent = $oldpid;
		@kids = ();
		last FORK;
	} else { push @kids, $pid; }
}

if ($parent) {
	my $socket;
	my $protocol;
	my $success = eval { $socket = IO::Socket::INET->new( PeerAddr => $host, PeerPort => $port, Proto => $protocol) };
			
	if ($success) {	print "Port $port: Open\n"; shutdown($socket, 2); }
	exit 0;
	} else { &DoKill;}

}

sub DoKill { while (my $kid = shift @kids) { waitpid $kid, 0; } }
