Category: Unix Utilities
Author/Contact Info Corey Gaffney cgaff@flashcom.net
Description: Monitors NT or Unix hosts from a Unix machine to determine if a host is alive via fping. One email is sent when a host(s) is down and one email is sent to specify the host is now alive. Hosts to monitor are gathered from a pagefile which specifies the hostname and the email address to send notifications to. Each host can have a specific address to send emails or pages to. Outages are logged to a local file. Fping was used instead of the Perl pingecho function because of it's ability to use timeouts, retries, etc. Pingecho can also generate problems in environments that use firewalls, especially when using the TCP ping option. Although not a true daemon it will run as an interrupted process that checks hosts availiibility every 30 seconds as specified by sleep.
#!/usr/bin/perl
# Host(s) Monitor (using fping)


#### Pagefile Usage ###########
#
# hostname:pagelist
#
# Example:
# goliath:steve@yahoo.com,mike@yahoo.com
# hercules:steve@yahoo.com,sarah@yahoo.com
#
###############################

#-----------------------------------------------------------
# Environment Variables                                    |
#-----------------------------------------------------------
$pagefile="pagelist";   # Config file for hostname:pagelist
$default_mail="root";
$timeout=90000;         # Adjusts Sensitivity Level for Network traffi
+c(milliseconds)
$fping="/usr/local/bin/fping";
$count=0;
$cnt=0;
$lines=0;
$check=0;
#-------------------------------------------------------------

#-------------------------------------------------------------
# Logging Options                                            |
#-------------------------------------------------------------
$log="hostlog";
$response_times="response_times";
$outages="outages";
#-------------------------------------------------------------

#-------------------------------------------------------------
# Required Perl Modules                                      |
#-------------------------------------------------------------
require Mail::Send;      # From Mail::Tools
#-------------------------------------------------------------

#-------------------------------------------------------------
# Make or notify user of required files                      |
#-------------------------------------------------------------
if ( ! -e $response_times ){
`touch $response_times`;
}

if ( ! -e $log ){
`touch $log`;
}
#--------------------------------------------------------------


#--------------------------------------------------------------
# Verify integrity of config file - loosely                   |
#--------------------------------------------------------------
open(FILE1, "<$pagefile") || die "Cannot find $pagefile\n";

while (<FILE1>){
 
        @letters= split(//);
        {
          $lines=$lines+1;

                foreach (@letters){
                        if(/:/){
                        $cnt=$cnt+1
                        }
                }
        }
}
                if ($lines ne $cnt){
                print("Error in config file\n");
                exit;
                }
close (FILE1);
#---------------------------------------------------------------

# Start

while (1){

        open(FILE1, "<$pagefile") || die "Cannot open $pagefile\n";

        while (<FILE1>){ 

        @data = split(/:/, $_);
        $hostname=@data[0];
        $mailto=@data[1];

        $mailstrl = length($mailto);

        if ( $mailstrl < 1 ){
        
                $mailto="$default_mail";
                chomp($mailto, $hostname);
                }

        foreach ($hostname){
        
        $date=localtime(time);
        $check = `$fping -e -r 10 -t $timeout $hostname`;
 
        open(RESPONSE,">>$response_times");
        print RESPONSE "$date $check";
        close(RESPONSE);

          if ( $check =~ /unreachable|down|not found/i ){
           
                $machine {"$hostname"}++;

                if ($machine {"$hostname"} == 1){

                open(RESPONSE,">>$outages");
                print RESPONSE "$hostname went down at $date\n";
                close(RESPONSE);

                $msg=new Mail::Send Subject=>"$hostname went down at $
+date", 
                To=>"$mailto";
                $fh=$msg->open;
                $fh->close;

                open(LOG,">> $log");
                print LOG "$hostname went down at $date\n";
                close(LOG);
                }
           }
        }

sleep 30;

# Are we still down? Only send page if host is now alive
# Send only one page, log to file
 
        foreach ($hostname){
        
           if ($machine {"$hostname"} >= 1){
           
           $date=localtime(time);
           $check2 = `$fping -e -r 10 -t $timeout $hostname`; 

                if ( $check2 =~ /alive/i ){

                open(RESPONSE,">>$outages");
                print RESPONSE "$hostname alive at $date\n";
                close(RESPONSE);

                $msg=new Mail::Send Subject=>"$hostname alive at $date
+",
                To=>"$mailto";
                $fh=$msg->open;
                $fh->close;

                open(LOG,">> $log");
                print LOG "$hostname alive at $date\n";
                close(LOG);

                $machine{"$hostname"}=0;
                }
       }
    }
  }
}