Network Link monitor

I came up with this simple script to monitor my WAN links, and to notify me when a link goes down, and when it is available again. It does this by connecting to a port of a remote router. If the router responds, the link is alive. This script can be extended to support servers as well.

The script was tested on AIX 4.3.3 and ActiveState Perl for Windows on Windows 2000 server.

The data file

The data file is a text file, containing site information, and an IP address. They are seperated with the pipe symbol.

SITE-A|192.168.1.1
SITE-B|10.1.1.1

The config file

data=data.txt
port=23
sleep=120
systemlog=system.log
historylog=history.log
statustxt=status.txt
statushtml=c:\status.htm
title=My own network monitor
external=mailit.bat

The ini file is straight forward: which data file to use, which port to connect to, how long to sleep between intervals, the system log file name, the history log file name, the status log file name, the output HTML file name, a title, and the external application to call when the status changes.

One thing worth noting, is that all files will be stored in the local directory, all except the statushtml file, which have to be specified absolutely.

The external application will be called with the site, IP and status as parameters. You may use these in your email applications, etc.

Run the script as a daemon on Unix, or load it as a service with FireDaemon on Windows.

The code

#!/usr/bin/perl use IO::Socket; $slash = &getslash; $curdir = substr($0,0,rindex($0,$slash)+1); if($curdir eq "") { $curdir = ".$slash"; } $ini = "siteping.ini"; open(INI,"$curdir$ini"); foreach $i (<INI>) { chomp($i); ($v,$a) = split(/\=/,$i); $inih{$v} = $a; } close INI; #====================================================== $data = $inih{data}; $port = $inih{port}; $sleep = $inih{sleep}; $systemlog = $inih{systemlog}; $historylog = $inih{historylog}; $statustxt = $inih{statustxt}; $statushtml = $inih{statushtml}; $title = $inih{title}; $external = $inih{external}; #====================================================== open(DAT,"$curdir$data"); foreach $i (<DAT>) { chomp($i); ($site,$ip) = split(/\|/,$i); $hashsite{$site} = $ip; $currentstatus{$site} = "Ok!"; } close DAT; while(1) { unlink "$curdir$systemlog"; &log("Starting scanning","$systemlog"); foreach $site (sort keys %hashsite) { $host = $hashsite{$site}; $alive = &check_port($host,$port); if($alive == 1) { $status = "Ok!"; } else { $status = "FAILED!!"; $error = 1; } &log("$site = $status","$systemlog"); if($currentstatus{$site} ne $status) { &log("$site => $status","$historylog"); `$external $site $host $status`; } $currentstatus{$site} = $status; } #write realtime status files #============================ $time = localtime(time); open(STATUS,">$curdir$statustxt"); print STATUS "$time\n"; foreach $site (sort keys %hashsite) { $status = $currentstatus{$site}; print STATUS "$site=$status\n"; } close STATUS; #write html file from status file #=================================== open(STATUS,"$curdir$statustxt"); open(HTML,">$statushtml"); print HTML "<html><title>$title</title><h1>$title</h1><meta HTTP-E +QUIV=\"Refresh\" CONTENT=\"$sleep;\">\n"; print HTML &style; print HTML <<HTML; <table border=1> HTML ; $date = <STATUS>; foreach $l (<STATUS>) { chomp($l); ($site,$status) = split(/\=/,$l); if($status eq "Ok!") { $st = &htmlcell($status,"GREEN"); } else { $st = &htmlcell($status,"RED"); } print HTML "<tr><th>$site</th>$st</tr>\n"; } print HTML "</table>\n"; $d = &timeformat(time,"dd MMM YYYY hh:mm:ss"); print HTML "<hr><i>Last updated on $d, and will refresh in $sl +eep seconds</i></html>"; close STATUS; close HTML; &log("Sleeping for $sleep seconds","$systemlog"); sleep($sleep); } #===================================================================== +============ sub log { $txt = $_[0]; $file = $_[1]; $time = localtime(time); open(FOO,">>$curdir$file"); print FOO "$time $txt\n"; close FOO; } ################################################# # Get name or IP, do lookup ################################################# sub name { my ($host) = @_; ($name,$alias,$addrtype,$length,$new_addr) = gethostbyaddr(inet_aton($host),AF_INET); $ipaddr = inet_ntoa(scalar($new_addr)); return $ipaddr; } ################################################# # Check to see if a port is open ################################################# sub check_port { my ($host,$port) = @_; $remote = IO::Socket::INET -> new ( Proto => "tcp", PeerAddr => $host, PeerPort => $port ) ; if ($remote) { close $remote; return 1; } else { return 0; } } sub cl2 { local $cl_var = $ARGV[$_[0]]; local $cl_default = $_[1]; if($cl_var eq "") { $cl_var = $cl_default; } return $cl_var; } sub cl { ################################################################## +################### # CL ################################################################## +################### # Input 0 : Command line variable (0,1,2,3, etc) # Input 1 : Default text to display (if the command line var is bl +ank) # Input 2 : Default answer to the question # # Similar to the ASK procedure, except this proc reads from the co +mmand line, eg. # # $myvar = &cl(0,"What is your name","Bob"); # ################################################################## +################### local $cl_var = $ARGV[$_[0]]; local $cl_txt = $_[1]; local $cl_default = $_[2]; if($cl_var eq "") { $cl_var = &ask($cl_txt,$cl_default); } return $cl_var; } sub ask { ################################################################## +################### # ASK ################################################################## +################### # Input 0 : Message to display # Input 1 : Default answer # # This procedure works a lot like the input keyword in BASIC. You + can specify # a default answer to the question, eg. # # $myvar = &ask("What is your name","Bob"); # ################################################################## +################### local $ask_msg = $_[0]; local $ask_default = $_[1]; if($ask_default eq "") { $ask_ifdefault = ""; } else { $ask_ifdefault = " [$ask_default] "; } local $ask_val = ""; while($ask_val eq "") { print "$ask_msg$ask_ifdefault --> "; $ask_val = <STDIN>; chomp($ask_val); if($ask_val eq "") { $ask_val = $ask_default; } } return $ask_val; } sub getslash { $r = $ENV{PATH}; if(index($r,"\\") != -1) { return "\\"; } if(index($r,"/") != -1) { return "/"; } return "UNKNOWN"; } sub style { return <<END; <style> .parent {font-family: Verdana; font-size: 8pt; margin-top: 5; text-indent: 0; margin-left: 0; cursor: hand;} .child {font-family: Verdana; font-size: 8pt; margin-left: 10; margin-bottom:20; font-weight: normal;} .image {} BODY { BACKGROUND-COLOR : white; COLOR : black; FONT-FAMILY : verdana, arial; FONT-SIZE : 8pt; } H1 { COLOR : #000363; FONT-SIZE : 14pt; font-family : Verdana; border-style : solid; border-color : #000363; border-width : 0pt; border-bottom-width : 1pt; font-weight : bold; } H2 { COLOR : #000363; FONT-SIZE : 13pt; font-weight : bold; font-family : Verdana, arial; } H5 { COLOR : #000363; FONT-SIZE : 9pt; font-family : Verdana, arial; } H6 { COLOR : #000363; FONT-SIZE : 8pt; font-family : Verdana, arial; } P { COLOR : black; FONT-FAMILY : verdana, arial; FONT-SIZE : 8pt; } TD { COLOR : black; FONT-FAMILY : verdana, arial; FONT-SIZE : 8pt; } TH { BACKGROUND-COLOR : #000363; COLOR : white; FONT-FAMILY : verdana, arial; FONT-SIZE : 8pt; FONT-WEIGHT : bold; } H3 { font-size : 11pt; font-family : Verdana, arial; color : #000363; font-weight : bold; } H4 { font-size : 10pt; font-family : Verdana, arial; color : #000363; } A:hover { background-color : #00FFFF; color : #000000; } </style> END ; } #================================================================= sub timeformat { $tf_timesent = $_[0]; $tf_format = $_[1]; $timeformat_longmonth[1] = "January"; $timeformat_longmonth[2] = "February"; $timeformat_longmonth[3] = "March"; $timeformat_longmonth[4] = "April"; $timeformat_longmonth[5] = "May"; $timeformat_longmonth[6] = "June"; $timeformat_longmonth[7] = "July"; $timeformat_longmonth[8] = "August"; $timeformat_longmonth[9] = "September"; $timeformat_longmonth[10] = "October"; $timeformat_longmonth[11] = "November"; $timeformat_longmonth[12] = "December"; $timeformat_shortmonth[1] = "Jan"; $timeformat_shortmonth[2] = "Feb"; $timeformat_shortmonth[3] = "Mar"; $timeformat_shortmonth[4] = "Apr"; $timeformat_shortmonth[5] = "May"; $timeformat_shortmonth[6] = "Jun"; $timeformat_shortmonth[7] = "Jul"; $timeformat_shortmonth[8] = "Aug"; $timeformat_shortmonth[9] = "Sep"; $timeformat_shortmonth[10] = "Oct"; $timeformat_shortmonth[11] = "Nov"; $timeformat_shortmonth[12] = "Dec"; #FORMAT KEYS # hh -- 24 hour, no leading zero -- Done # HH -- 24 hour, leading zero -- Done # mm -- minute, leading zero -- Done # ss -- seconds, leading zero -- Done # DD -- Day (leading zero) -- Done # dd -- Day (no leading zero) -- Done # m -- Month (no leading zero) -- Done # MM -- Month (01 - Jan, 12 - Dec) -- Done # MMM -- Month (Jan, Feb) -- Done # MMMM -- Month (January, February) -- Done # YY -- Year (Leading zero, eg. 02) -- Done # YYYY -- Year (full year, eg 2002) -- Done ($tf_sec,$tf_min,$tf_hour,$tf_mday,$tf_mon,$tf_year,$tf_wday,$ +tf_yday,$tf_isdst) = localtime($tf_timesent); $tf_HH = &timeformat_leadingzero($tf_hour); $tf_hh = $tf_hour; $tf_mm = &timeformat_leadingzero($tf_min); $tf_ss = &timeformat_leadingzero($tf_sec); $tf_DD = &timeformat_leadingzero($tf_mday); $tf_dd = $tf_mday; $tf_m = $tf_mon + 1; $tf_MM = &timeformat_leadingzero($tf_m); $tf_MMM = $timeformat_shortmonth[$tf_m]; $tf_MMMM = $timeformat_longmonth[$tf_m]; $tf_YYYY = $tf_year + 1900; $tf_YY = substr($tf_YYYY,2,2); $tf_format =~ s/HH/$tf_HH/g; $tf_format =~ s/hh/$tf_hh/g; $tf_format =~ s/mm/$tf_mm/g; $tf_format =~ s/ss/$tf_ss/g; $tf_format =~ s/DD/$tf_DD/g; $tf_format =~ s/dd/$tf_dd/g; $tf_format =~ s/MMMM/$tf_MMMM/g; $tf_format =~ s/MMM/$tf_MMM/g; $tf_format =~ s/MM/$tf_MM/g; $tf_format =~ s/m/$tf_m/g; $tf_format =~ s/YYYY/$tf_YYYY/g; $tf_format =~ s/YY/$tf_YY/g; return $tf_format; } sub timeformat_leadingzero { $tflz_var = $_[0]; if(length($tflz_var) == 1) { $tflz_var = "0$tflz_var"; } return $tflz_var; } sub htmlcell { $txt = @_[0]; $col = $_[1]; if($col eq "RED") { return "<td bgcolor=\"#FF0000\">$txt</td>\n"; } if($col eq "GREEN") { return "<td bgcolor=\"#00FF00\">$txt</td>\n"; } }

Edited by footpad, ~ Tue Jul 30 11:07:47 2002 (UTC): Added <READMORE> tag, per Consideration.


In reply to Simple Network Availability Monitor by Massyn

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.