use strict; use POSIX ":sys_wait_h"; $SIG{'CHLD'} = \&REAPER; # manage moribound children my %status = (); # hash of pid nš and their returned status my %scan = (); # users to scan my $ts = time(); # current time my @ports = (23, 24, 25, 1080, 1081); # ports to scan my $threads = 0; # current number of threads/scans, if $threads is reacher, enqueue. my $max = 3; # max number of simul scans my $last = $ts; # process the infinite loop each second only, no milliseconds needed sub REAPER { my $pid = 0; while (($pid = waitpid(-1, &WNOHANG)) > 0) { $status{$pid} = $?; } $SIG{'CHLD'} = \&REAPER; } # ok here we link to the IRC hub as a server # When a new client connects, we have to scan some @ports to check if he's using an unsecure proxy # Let's try with "hacker" : $scan{"hacker"}{'nick'} = "hacker"; # user's nickname $scan{"hacker"}{'start'} = $ts; # time of scan $scan{"hacker"}{'completed'} = 0; # scan completed? 1 = yes $scan{"hacker"}{'total'} = 0; # total number of scan to do (scalar(@ports)) $scan{"hacker"}{'list'} = (); # associate pid with port $scan{"hacker"}{'unsecure'} = 0; # is unsecure? 1 = yes $scan{"hacker"}{'proto'} = ""; # proto of an unsecure result $scan{"hacker"}{'port'} = 0; # port of an unsecure result # start the scan my $idx = 0; # list of threads foreach (@ports) { ++$idx; ++$scan{"hacker"}{'total'}; $scan{"hacker"}{'list'}{$idx}{'proto'} = "Wingate"; $scan{"hacker"}{'list'}{$idx}{'port'} = $_; $scan{"hacker"}{'list'}{$idx}{'start'} = 0; if ($threads >= $max) { # enqueue this scan, too many are running $scan{"hacker"}{'list'}{$idx}{'id'} = 0; $scan{"hacker"}{'list'}{$idx}{'queued'} = 1; } else { # start the scan my $id = &new_thread("hacker", "Wingate", $_); $scan{"hacker"}{'list'}{$idx}{'id'} = $id; $scan{"hacker"}{'list'}{$idx}{'start'} = $ts; } } # the scan routine sub new_thread { my ($nick, $proto, $port) = (shift, shift, shift); my $result = 0; # if 1, the we have an unsecure connection if (my $pid = fork()) { ++$threads; return($pid); } eval { local $SIG{'ALRM'} = sub { die("stopped\n"); }; alarm(2); $result = 0; # here we connect to the $nick's host and $port and send some stuff using a classical IO::Socket::INET alarm(0); }; exit($result); } sub del_threads { # delete all $nick's pid-related my $nick = shift; foreach (keys(%{$scan{$nick}{'list'}})) { if ($scan{$nick}{'list'}{$_}{'id'}) { my $id = $scan{$nick}{'list'}{$_}{'id'}; kill('SIGTERM', $id); --$threads; $scan{$nick}{'list'}{$_}{'id'} = 0; ++$scan{$nick}{'completed'}; } } return(0); } # infinite IRC loop routine sub timer_online { $ts = time(); if ($ts == $last) { return(); } $last = $ts; my $unsecure = 0; # got an insecure connex? my $port = 0; # if yes, copy the port nš my $proto = ""; # and the protocol used foreach (keys(%scan)) { my $nick = $scan{$_}{'nick'}; if ($scan{$nick}{'unsecure'} || ($scan{$nick}{'total'} == $scan{$nick}{'completed'})) { # finished scan of this user if ($scan{$nick}{'unsecure'}) { print STDOUT "unsecure!\n"; } else { print STDOUT "clean!\n"; } &del_threads($nick); delete($scan{$nick}); next; } foreach my $idx (keys(%{$scan{$nick}{'list'}})) { # foreach pid of this user foreach my $pid (keys(%status)) { # compare a pid with the "global" pid hash table if ($pid == $scan{$nick}{'list'}{$idx}{'id'}) { $scan{$nick}{'list'}{$idx}{'id'} = 0; ++$scan{$nick}{'completed'}; --$threads; if ($status{$pid}) { $scan{$nick}{'unsecure'} = 1; $scan{$nick}{'proto'} = $scan{$nick}{'list'}{$idx}{'proto'}; $scan{$nick}{'port'} = $scan{$nick}{'list'}{$idx}{'port'}; delete($status{$pid}); &del_threads($nick); $unsecure = 1; last; } } } if ($unsecure) { last; } if ($scan{$nick}{'list'}{$idx}{'id'} && ($ts - $scan{$nick}{'list'}{$idx}{'start'} > 3)) { # 3 sec timeout, stop this process my $id = $scan{$nick}{'list'}{$idx}{'id'}; kill('SIGTERM', $id); $scan{$nick}{'list'}{$idx}{'id'} = 0; ++$scan{$nick}{'completed'}; --$threads; next; } if ($scan{$nick}{'list'}{$idx}{'queued'} && ($threads < $max)) { # queued scans? my $id = &new_thread($nick, $scan{$nick}{'list'}{$idx}{'proto'}, $scan{$nick}{'list'}{$idx}{'port'}); $scan{$nick}{'list'}{$idx}{'id'} = $id; $scan{$nick}{'list'}{$idx}{'queued'} = 0; $scan{$nick}{'list'}{$idx}{'start'} = $ts; } } } return(0); } # infinite IRC loop for (;;) { &timer_online(); }