marto9 has asked for the wisdom of the Perl Monks concerning the following question:

Hi everyone,

I created a multithreaded port scanner. It's not perfect yet, so that's why I am asking for help here. :)

First of, is there a way to increase the scanningspeed besides using more threads? Now I create a sock with a 2 secs timeout.

I've also got some questions concerning the threading.
I made two versions:

1. This script gives an ip to a thread make and then the thread checks it. Afterwards the thread closes and new ones are created.
I think I have a memory leak here. The size is about 200mb with 20 threads and it keeps on rising.
Any idea how this is caused?

use IO::Socket; use threads; use threads::shared; use warnings; $0 =~ s/.*\\//; die "usage: $0 <-p/-web/-ban> <port> <first_ip> <second_ip> <threads>\ +n" unless ($ARGV[4]); $choice = $ARGV[0]; $port = $ARGV[1]; $first = $ARGV[2]; $second = $ARGV[3]; $maxthreads = $ARGV[4]; unless ($choice =~ /^-p$|^-web$|^-ban$/) { die "usage: $0 <-p/-web/-ban> <port> <first_ip> <second_ip> <threa +ds>\n"; } my $threads : shared = 0; my $found : shared = 0; my $count : shared = 0; open(OUTPUT,">>pscan.txt"); OUTPUT->autoflush(1); STDOUT->autoflush(1); $f = inet_aton($first); $s = inet_aton($second); $f_ip = unpack('N', $f); $s_ip = unpack('N', $s); for ($o = $f_ip; $o < $s_ip; $o++) { $o = pack('N', $o); $ip = inet_ntoa($o); push @range, $ip; $o = unpack( 'N', $o ); } $size = @range-1; for ($i = 0; $i <= $size; $i++) { while (1) { if ($threads < $maxthreads) { last unless defined($range[$i]); $thr = threads->create(\&scan, $range[$i]); $thr->detach(); $percent = ($count/$size)*100; $percent = sprintf("%.1f", $percent); print "THREADS: $threads || STATUS: $percent% || FOUND: $f +ound\t\r"; last; } else { sleep(1); } } } while ($threads > 0) { print "THREADS: $threads || STATUS: 100% || FOUND: $found\t\r"; sleep(1); } close(OUTPUT); print "THREADS: $threads || STATUS: 100% || FOUND: $found\t\r"; exit; sub scan() { {lock($count);$count++;} {lock($threads);$threads++;} $sock = new IO::Socket::INET (PeerAddr => $_[0],PeerPort => $port, + Proto => "tcp", Timeout => 2); if ($sock) { if ($choice =~ /^-p$/) { {lock($found);$found++;} print OUTPUT $_[0].":".$port."\n"; } elsif ($choice =~ /^-web$/) { print $sock "HEAD / HTTP/1.0\012\012"; while (<$sock>) { chomp($_); if ($_ =~ /^Server: (.*)$/) { {lock($found);$found++;} $ban = $1; chomp($ban); $ban =~ s/\n|\r//g; print OUTPUT $_[0].":".$port." [".$ban."]\n"; last; } } } elsif ($choice =~ /^-ban$/) { {lock($found);$found++;} print $sock "GET / HTTP/1.0\n\n"; while (<$sock>) { chomp($_); $_ =~ s/\n|\r//g; print OUTPUT $_[0].":".$port." [".$_."]\n"; last; } } close $sock; } {lock($threads);$threads--;} }

2. This script creates the amount of threads given and every threads takes and checks an ip. So no new threads are created.
This way my memory doesn't increase and it's also not that high.
The problem is with the procentage I can't get right. Within the "while" loop the $count number is correct. But when I use $count outside the loop it adds some extra numbers, actually the number of amount of threads I started.
With for example 5 threads the count goes like this:
0 0 0 0 0 1 2 3 4 5 6 ...

use IO::Socket; use threads; use threads::shared; use warnings; $0 =~ s/.*\\//; die "usage: $0 <-p/-web/-ban> <port> <first_ip> <second_ip> <threads>\ +n" unless ($ARGV[4]); $choice = $ARGV[0]; $port = $ARGV[1]; $first = $ARGV[2]; $second = $ARGV[3]; $maxthreads = $ARGV[4]; unless ($choice =~ /^-p$|^-web$|^-ban$/) { die "usage: $0 <-p/-web/-ban> <port> <first_ip> <second_ip> <threa +ds>\n"; } my $threads : shared = 0; my $found : shared = 0; my $count : shared = 0; open(OUTPUT,">>pscan.txt"); OUTPUT->autoflush(1); STDOUT->autoflush(1); $f = inet_aton($first); $s = inet_aton($second); $f_ip = unpack('N', $f); $s_ip = unpack('N', $s); for ($o = $f_ip; $o < $s_ip; $o++) { $o = pack('N', $o); $ip = inet_ntoa($o); push @range, $ip; $o = unpack( 'N', $o ); } $size = @range-1; for ($i = 1; $i <= $maxthreads; $i++) { $thr = threads->create(\&scan); $thr->detach(); } while ($threads > 0) { $percent = ($count/$size)*100; $percent = sprintf("%.1f", $percent); print "THREADS: $threads || STATUS: $percent% || FOUND: $found\t\r +"; } close(OUTPUT); print "THREADS: $threads || STATUS: $percent% || FOUND: $found\t\r"; exit; sub scan() { {lock($threads);$threads++;} while($count <= $size) { unless (defined($range[$count])) { {lock($count);$count++;} next; } $sock = new IO::Socket::INET (PeerAddr => $range[$count],PeerP +ort => $port, Proto => "tcp", Timeout => 2); if ($sock) { if ($choice =~ /^-p$/) { {lock($found);$found++;} print OUTPUT $range[$count].":".$port."\n"; } elsif ($choice =~ /^-web$/) { print $sock "HEAD / HTTP/1.0\012\012"; while (<$sock>) { chomp($_); if ($_ =~ /^Server: (.*)$/) { {lock($found);$found++;} $ban = $1; chomp($ban); $ban =~ s/\n|\r//g; print OUTPUT $range[$count].":".$port." [".$ba +n."]\n"; last; } } } elsif ($choice =~ /^-ban$/) { {lock($found);$found++;} print $sock "GET / HTTP/1.0\n\n"; while (<$sock>) { chomp($_); $_ =~ s/\n|\r//g; print OUTPUT $range[$count].":".$port." [".$_."]\n +"; last; } } close $sock; } {lock($count);$count++;} } {lock($threads);$threads--;} }

Thx in advance

Replies are listed 'Best First'.
Re: Multithreaded Port Scanner
by Bloodnok (Vicar) on Mar 09, 2009 at 16:59 UTC
    I presume AM means i.e. refers to, ...Nmap::Scanner

    A user level that continues to overstate my experience :-))
Re: Multithreaded Port Scanner
by zwon (Abbot) on Mar 09, 2009 at 17:15 UTC

    If you still want to write it yourself, do not use threads at all, use IO::Select, Event, or EV.

Re: Multithreaded Port Scanner
by Anonymous Monk on Mar 09, 2009 at 16:39 UTC
    Why not use nmap, an industry standard tool, that works? There is a cpan module.
Re: Multithreaded Port Scanner
by marto9 (Beadle) on Mar 10, 2009 at 12:08 UTC
    Thx for the replies everyone.
    I'll try to use the techniques that you guys proposed.
    But I'd like to make the multithreading work. So I can make a good multithreaded program, also for other projects.
    I'd appreciate it if someone could help me out with the second script.
    If you run the script you'll see that somethings wrong with the percentage. I believe this is caused by the threading.