#!/usr/bin/perl ######################################################### # Code released 03/22/07 under: # # the GNU GENERAL PUBLIC LICENSE, Version 2 # # http://www.gnu.org/licenses/gpl.txt # # # # It is recommended that this script is run as a cron # # job frequently to find changes in the network. This # # script will check the status of the wireless access # # points/routers as well as the daemons necessary to # # run the network. It will then output the results to # # another perl file that is copied to a remote # # webserver. When the script observes a change in the # # availability of any access point or daemon, email # # will be sent to the specified administrator # # address(es). The option exists to send an email to # # to an additional person for each access point. # # # # Additionally, the output file on the remote webserver # # will check when it was last updated, if that script # # is run from the command line or via cron. If it has # # not been updated for a specified number of minutes, # # it will send an email to the administrator. It is # # also recommended that this output script be run as a # # cron jobr. This output script can also be executed # # as a cgi program to generate a display of network # # status. # ######################################################### use strict; use Expect(); # needed to scp to webserver use Mail::Mailer; # needed to send emails if outages use Net::Ping; # needed to check the status of aps #variables for webserver to host status page's my $webServUname = "username"; my $webServPass = "password"; my $webServUrl = "lance.mckendree.edu"; my $webServTarg = "/var/www/cgi-bin/wireless/"; my $webOutputUrl = "http://lance.mckendree.edu/cgi-bin/wireless/status.cgi"; my $instName = "McKendree College"; #default background color of the status page my $defBGColor = "#660066"; # If the page on the webserver has not been updated # in $updateMin minutes send an email that the service # is down (set to =~ 3*crontime) my $updateMin = 10; #email address errors will be sent to my $fromEmail = 'admin1@email.com'; my $toEmail = 'admin1@email.com, admin2@email.com'; #file where errors will be stored on remote host my $logFileName = "/tmp/wirelesLog.txt"; #hash for routers/ap's #location is displayed on the webpage and in status emails #owner - changes in status regarding this AP are sent to # this address as well (optional) my %ipToLoc = ( "192.168.182.10" => { "LOCATION" => "Clark 205", "OWNER" => ''}, "192.168.182.11" => { "LOCATION" => "Clark 202a", "OWNER" => 'apUser1@email.com'}, "192.168.182.12" => { "LOCATION" => "PAC Lounge", "OWNER" => 'apUser2@email.com'}, "192.168.182.20" => { "LOCATION" => "Library Main", "OWNER" => 'apUser3@email.com'}, "192.168.182.21" => { "LOCATION" => "Library Upper", "OWNER" => ''}, "192.168.182.22" => { "LOCATION" => "Library Lower", "OWNER" => ''}, "192.168.182.30" => { "LOCATION" => "Carnegie", "OWNER" => 'apUser4@email.com'}); #hash for daemons my %daemons = ( "Dnsmasq - DNS Server" => { "IP_ADDR" =>"10.4.1.90", "PORT" =>"53", "PROTO" =>"TCP"}, "Radius - Authenticate" => { "IP_ADDR" =>"10.4.1.90", "PORT" =>"1812", "PROTO" =>"UDP"}, "Chilli - Capt. Portal" => { "IP_ADDR" =>"10.5.3.30", "PORT" =>"0", "PROTO" =>"LOCAL"}, "Squid - Web Cache" => { "IP_ADDR" =>"10.4.1.90", "PORT" =>"3128", "PROTO" =>"TCP"}, "Apache - Web Server" => { "IP_ADDR" =>"10.5.3.30", "PORT" =>"80", "PROTO" =>"TCP"}); ######################################################## # # # NO CHANGES NEED TO BE MADE TO THE FOLLOWING CODE # # # ######################################################## # get the current time my $currentTime = scalar localtime(); my $startTime = time(); # open old output status script to get previous status' open(OLD, "status.cgi"); my @tmpOldStatFile = ; my $oldStatFile = join("", @tmpOldStatFile); # check routers/ap's using ping my $diff = ''; my $allRouterStat; foreach my $host (sort keys %ipToLoc){ my $p = Net::Ping->new(); my $pingResult = $p->ping($host); if(!$pingResult){ sleep 10; $pingResult = $p->ping($host); } my $thisLastStat = ( $oldStatFile =~ m/$ipToLoc{$host}{LOCATION}<\/TD> (\$lastTime + (60 * $updateMin))){ \$systemStatus = "#FF0000"; \$message = "

Status Update Failed

"; } # if this is cron running the script if (\$currentUser =~ "$webServUname"){ # send email if status is down & logFile doesn't exist &sendEmail() if ( (\$systemStatus =~ "#FF0000") && !(-e "$logFileName") ); # delete log file if everything is up unlink("$logFileName") if ( (!(\$systemStatus =~ "#FF0000")) && (-e "$logFileName") ); } #else apache is accessing the page (its a web request) else{ #print the page print header(); ############################ # start of html output # ############################ print < $instName Wireless Status

$instName Wireless Status

\$message $allRouterStat
Access Point Status

$allDaemonStat
Daemon Status


Last updated $currentTime
WEB_OUTPUT ########################## # end of html output # ########################## }#end else sub sendEmail { my \$mailer = Mail::Mailer->new("sendmail"); \$mailer->open({From => '$fromEmail', To => [\$toEmail], Subject => "Wireless Problem"}); my \$message = "The wireless system has failed to " ."it's status.\n\n$webOutputUrl\n"; print \$mailer \$message; \$mailer->close(); open(FILE, ">>$logFileName"); print FILE "Failed to Update system."; close(FILE); } OUTPUT_FILE_FOR_REMOTE_HOST ######################################################## # end of script output block # ######################################################## #write output code to the file my $perlOutputFile = "status.cgi"; open (OUT, ">$perlOutputFile"); print OUT $perlOutput; close (OUT); chmod 0755, $perlOutputFile; #send email is necessary &sendEmail($diff, $webOutputUrl, $fromEmail, $toEmail) if ($diff); #send perl file to webserver &scpFile($perlOutputFile, $webServUname, $webServPass, $webServUrl, $webServTarg); ################################################ # # # END MAIN CODE BLOCK, START FUNCTIONS # # # ################################################ # given the name and status of something (ap or # daemon), this returns a string for the table # row for displaying the status of the ap/daemon sub printStatus { my ($service, $status, $oldStatus, $owner, $toEmail,$oldStatusFile, $currentTime ) = @_; my $msg = ""; my $statusLine = "\n $serviceUP"; # if last two status' were down if ($oldStatusFile =~ m/\($service\)-0--->/){ $msg = "$service back up at $currentTime\n"; # if service has owner & not already in mail list, # add owner to mail list $toEmail .= ", \'$owner\'" if ($owner && (!($toEmail =~ $owner))); } } #else current status is down else{ $statusLine .= "down\">DOWN"; # if last status was down & before that status was up if ($oldStatusFile =~ m/\($service\)-0-1-->/){ $msg = "$service down at $currentTime\n"; # if service has owner & not already in mail list, # add owner to mail list $toEmail .= ", \'$owner\'" if ($owner && (!($toEmail =~ $owner))); } } $statusLine .= ""; return ($statusLine, $toEmail, $msg); }#end printStatus function # checks the status for the given daemon # takes in IP, port to check, daemon name, and protocol # (tcp/udp). if given port=0 it checks for local daemon sub checkDaemon { my ($ip, $port, $daemon, $proto) = @_; my $dStat = 0; if ($proto !~ /LOCAL/){ #sU checks for udp ports my $com = ($proto =~ "TCP") ? ("nmap -p $port $ip | grep $port") : ("nmap -sU -p $port $ip | grep $port"); open(TMP, "$com|"); my $comOut = ; close(TMP); if ($comOut =~ /open/){ $dStat = 1; #if port is open, status is up } } else{ $daemon =~ s/ +.*//g; #\l lowercases the first letter of $daemon my $com = "which \l$daemon"; open(TMP, "$com|"); my $comOut = ; close(TMP); $com = "ps aux | awk '{print \$11}' | grep $comOut"; open(TMP, "$com|"); $comOut = ; close(TMP); $dStat = 1 if ($comOut); } return $dStat; } # end checkDaemon function # send the output perl status file to the webserver sub scpFile { my ($filePath, $webServUname, $webServPass, $webServUrl, $webServTarg ) = @_; my $command = "scp $filePath $webServUname" ."\@$webServUrl:$webServTarg"; my $exp1 = Expect->spawn ($command); # the first argument "30" may need to be adjusted # if your system has very high latency my $ret = $exp1->expect(30, "word:"); print $exp1 "$webServPass\r"; my $ret = $exp1->expect(undef); $exp1->close(); } # end scpFile function # send an email to the admin & append error to log file sub sendEmail { my ($errorList, $webOutputUrl, $fromEmail, $toAddresses ) = @_; my $mailer = Mail::Mailer->new("sendmail"); $mailer->open({From => "$fromEmail", To => [$toAddresses], Subject => "Wireless Problem"}); $errorList .= "\n\n$webOutputUrl"; print $mailer $errorList; $mailer->close(); } # end sendEmail function