#!/usr/bin/perl
#------------------------------------------------------------------#
# CGI-based NetworkMonitor 'netmon.pl' 1.1
#------------------------------------------------------------------#
# Copyright (c) 1999-2004 by I.S. <ingolf@unixscout.org>
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions 
# are met:
# 
# * Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in
#   the documentation and/or other materials provided with the
#   distribution.
# * Neither the name of the <ORGANIZATION> nor the names of its
#   contributors may be used to endorse or promote products derived
#   from this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
# POSSIBILITY OF SUCH DAMAGE.
#------------------------------------------------------------------#
# * http://www.UNIXscout.org ///\\\ Use at your own risk! *
#------------------------------------------------------------------#

use warnings;

use Socket;
use Net::Ping;
use Sys::Hostname;
use DB_File;

$remo = $ENV{'REMOTE_ADDR'};

#if (! ($remo =~ /192.168.100/) ){               ### access
if (! ($remo =~ /.+/) ){
    print "Content-Type: text/html\n\n";
    print "Hello $remo ...\n";
} else {

@a = (                                           ### hosts
    "localhost",
    "www.openbsd.org",
    "bla.foo.bar",
);

@b = (                                           ### ports
    "ssh",
    "ftp",
    "www",
    #"pop3",
    #"smtp",
    #"telnet",
    #"domain",
    #"8000",
);

%c = (                                           ### exceptions
    "localhost"        =>   [ "www" ],
    "www.openbsd.org"  =>   [ "ssh", "ftp" ],
    #"no_exceptions"   =>   [ "null" ],
);

%d = (                                           ### comments
    "localhost"        =>   "Workstation",
    "www.openbsd.org"  =>   "Headquarters",
    #"bla.foo.bar"     =>   "no comments",
);

@rup = (                                         ### rup-hosts 
    "localhost",
    #"rup_not_installed",
);

$update = 600;                                   ### intervall

$email = "operator\@localhost";                  ### notification

$load = 0;                                       ### loadwarning 

tie %db, "DB_File", "/tmp/netmon.db", O_RDWR|O_CREAT, 0644, $DB_HASH;

sub scan {
  eval {
    local $SIG{ALRM} = sub { die "alarm" };
    alarm 3;
    my $remote = shift;
    $port = shift; 
    if ($port =~ /\D/) {$port = getservbyname($port, 'tcp')}
    die "No port" unless $port;
    my $iaddr = inet_aton($remote);
    $remip = inet_ntoa($iaddr) if defined $iaddr;
    $remip = "0" unless $remip;
    my $paddr = sockaddr_in($port, $iaddr) if defined $iaddr;
    my $proto = getprotobyname('tcp');
    socket(SOCK, PF_INET, SOCK_STREAM, $proto) || die "Socket: $!";
    $check = connect(SOCK, $paddr) if defined $paddr;
    close(SOCK) || die "Close: $!";
    alarm 0;
  };
  if ($@) {
    undef $check unless $@ eq "alarm\n";
    return $check;
  } else {
    return $check;
  }
}

sub comment {
  print "&nbsp;";
  foreach $key ( keys %d ) {
    if ( ($x eq $key) && ($z ne $x) ) {
      print "<font size=-1 color=navy>";
      print "$d{$key}";
      print "</font>";
    }
  }
  if ( ($z ne $x) && (grep /$x/, @rup) && ($db{$db_key} == 1) ){
    open(L, "rup $x |");
    $rup = <L>;
    $rup =~ s/$x//;
    print "<font size=-1 color=teal>";
    print "<br>&nbsp;$rup";
    print "</font>";
    $rup =~ /^.+\s+(.+)$/;
    $1 =~ /^.*(\d)[.].+$/;
    if ($1 > $load) {
      print "<font size=-1 color=fuchsia>";
      print "<br>&nbsp;Load Average Warning!";
      print "</font>";
    }
    close (L);
  }
}

sub alert {
  my $db_key = shift;
  if (defined $db{$db_key}) {
    if ($db{$db_key} == 1){
      ### first alerting (default off)
      #system("echo '1: Service ($x:$y) not available.' | mail -s ALERT $email");
      $db{$db_key} = 2; 
    } elsif ($db{$db_key} == 2){
      ### warn me only if two check in series failed (default on)
      system("echo '2: Service ($x:$y) not available.' | mail -s ALERT $email");
      $db{$db_key} = 0; 
    }
  } else {
      ### first alerting (default off)
      #system("echo '1: Service ($x:$y) not available.' | mail -s ALERT $email");
      $db{$db_key} = 2;
  }
}

print "Content-Type: text/html\n\n";
print "<html><head><title>NETMONITOR</title>";
print "<meta http-equiv=refresh content=$update></head>";
print "<body link=#000000 vlink=#000000 alink=#000000 bgcolor=#FFFFFF>";
print "<center><table width=98% border=0 bgcolor=#999999><tr><td>";
print "<table width=100% border=0 bgcolor=#EEEEEE><tr bgcolor=#808080>";
print "<th height=20><tt>SERVER [IP]</tt></th>";
print "<th><tt>PORT [NUMBER]</tt></th>";
print "<th><tt>OPEN</tt></th>";
print "<th><tt>CLOSE</tt></th>";
print "<th><tt>INFO</tt></th></tr>";

$z = "0";

out:foreach $x (@a){
inn:foreach $y (@b){
      foreach $key ( keys %c ) {
          if ( ($x eq $key) && (grep /$y/, @{$c{$key}} ) ) { next inn; };
      }
      $check = scan($x, $y);
      $db_key = $x . "_" . $y;
      if (defined $check){
          $db{$db_key} = 1;
          if ($z eq $x){
              print "<tr><td>";
              print "<br>";
          } else {
              print "<tr bgcolor=#D3D3D3><td valign=top>";
              print "$x [$remip]";
          }
          print "</td><td align=right valign=top>$y [$port]</td>";
          print "<td align=center valign=top><b><font color=green>x</font>";
          print "</b></td><td><br></td>";
          print "<td align=left>";
          if ($remip eq "0"){
             print "<font color=red size=-1>";
             print "&nbsp;Host lookup failed";
             print "</font>";
             print "</td></tr>";
             next out;
          }
	  comment();
          print "</td></tr>";
      } else {
          if ($z eq $x){
              print "<tr><td>";
              print "<br>";
          } else {
              print "<tr bgcolor=#D3D3D3><td valign=top>";
              print "$x [$remip]";
          }
          print "</td><td align=right valign=top>$y [$port]</td>";
          print "<td><br></td><td align=center valign=top><b><font color=red>x";
          print "</font></b></td>";
          print "<td align=left>";
          alert($db_key);
          comment();
          print "</td></tr>";
      }
      $z = $x;
    }
    $remip = "0";
}
print "</table><center>";
print "<small>", scalar localtime(), "</small>";
print "</center></tr></td></table>";
print "<font align=center color=silver><small>powered by OpenBSD</small></font>";
print "</body></html>";

untie %db;

}

### EOP

