#!/usr/bin/perl -w
#
# $Id: PortChk,v 1.1 2001/12/28 19:09:46 cvs Exp $
#
# PortChk: Checks LOCAL open ports
#
# Miguel Armas <kuko@ulpgc.es>
#

#--------------------------------------------[ Initialization Section ]----

use strict;
use Getopt::Std;
use pifia;

#--------------------------------------------[ Configuration Section ]----- 
my $priority = "Urgent";
my $alarm = "PortChk";
my $remind = <#$remind#>;        # Seconds

#--------------------------------------------[ Code Section ]----

# proactive flag indicates if we should take proactive measures, that is, 
# install/upgrade packages or just notify. Default is 0 but the global 
# variable proactive takes precedence
my $proactive='<#$proactive#>';

# Set a safe PATH
$ENV{'PATH'} = "/bin:/sbin:/usr/bin:/usr/sbin:/root/bin";

# Option declaration
use vars qw($opt_v $opt_n $opt_p $opt_q);
getopts('vnpq');

# Verbosity level. If not verbose, we shouldn't write any output unless 
# there is a problem. If quiet is set, we won't write ANY output (even if 
# there where errors). verbose has precedence
my $quiet = 1 if ($opt_q);
my $verbose = 1 if ($opt_v);
$quiet = 0 if ($verbose);

# proactive flag handling (parameter has precedence over global variable)
$proactive=1 if ($opt_p);
$proactive=0 if ($opt_n);

use vars qw(%lastnotify);

my %openports = openports();

perseval {
   # Read processes file
   my @ports = readObjectFiles($alarm);

   foreach my $line (@ports) {
      my ($port,$proto,$ip,$proc);
      $port = $proto = $ip = $proc = "";
      if ($line =~ /^(!?\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/) {
         ($port,$proto,$ip,$proc) = ($1,$2,$3,$4);
      }
      else {
         $port = $line;
      }
      my $error = 0;
      my $not = 0;
      if ($port =~ /^!(.*)/) {
         $port = $1;
	 $not = 1;
      }
      ## Is the port open?
      if (exists $openports{"$port"}) {
	 # Should it be open?
	 if ($not) {
            if ($verbose || !$quiet && needNotify($port,$remind)) {
	       print "ERROR: $port is OPEN by $openports{$port}{proc}\n";   
	       $lastnotify{"$port"} = time();
	    }
	 }
	 else {
	    # Are ALL other parameters ok?
	    # IP
	    if ($ip && ("$ip" ne ".") && 
	        ("$ip" ne $openports{$port}{ip})) {
               if ($verbose || !$quiet && needNotify($port,$remind)) {
	          print "ERROR: $port is OPEN in IP $openports{$port}{ip}\n";   
		  $lastnotify{"$port"} = time();
	       }
	    }
	    # Proto
	    if ($proto && ("$proto" ne ".") && 
	        ("$proto" ne $openports{$port}{proto})) {
               if ($verbose || !$quiet && needNotify($port,$remind)) {
	          print "ERROR: $port is OPEN with PROTO $openports{$port}{proto}\n";   
		  $lastnotify{"$port"} = time();
	       }
	    }
	    # Proc
	    if ($proc && ("$proc" ne ".") && 
	        ("$proc" ne $openports{$port}{proc})) {
               if ($verbose || !$quiet && needNotify($port,$remind)) {
	          print "ERROR: $port is OPEN by PROC $openports{$port}{proc}\n";   
		  $lastnotify{"$port"} = time();
	       }
	    }
	    else {
	       print "OK: $port is OPEN\n" if ($verbose);
	    }
	 }
	 delete $openports{"$port"};
      } else {
         if ($not) {
            print "OK: $port is CLOSED\n" if ($verbose);
	 }
	 else {
	    if ($verbose || !$quiet && needNotify($port,$remind)) {
	       print "ERROR: $port is CLOSED\n";
	       $lastnotify{"$port"} = time();
            }
	 }
      }
   }
   
   ## See what's left
   foreach my $port (keys %openports) {
      if ($verbose || !$quiet && needNotify($port,$remind)) {
         print "WARNING: $port is OPEN by $openports{$port}{proc}\n";
	 $lastnotify{"$port"} = time();
      }
   }
} preserve '%lastnotify';

# FUNCTION: openports()
# DESCRIPTION: Gets the host's open ports (in state LISTEN)
sub openports {
   my %openports;
   
   my $cmd = "lsof -i -n -P | grep -v '\\->' | grep -v '^COMMAND' ";
   
   open (CMD,"$cmd|") or die("Can't open command ($cmd): $! \n");
   while (<CMD>) {
      my @tmp = split(/\s+/,$_);
      my $proc = $tmp[0];
      my ($ip,$port) = split(":",$tmp[7]);
      my $proto = $tmp[6];
      $openports{$port}={ip=>"$ip",proto=>"$proto",proc=>"$proc"};
   }
   close CMD;
   
   return %openports;
}

