#--------------------------------------------------------------------#
# PingSweep
# Date Written: 27-Nov-2001 11:41:02 AM
# Last Modified: 03-Jan-2002 02:20:15 PM
# Author: Kurt Kincaid
# Copyright (c) 2001, Kurt Kincaid
# All Rights Reserved
#
# This is freesoftware and may be modified and/or redistributed
# under the same terms as Perl itself.
#--------------------------------------------------------------------#
use Tk;
use Tk::Dialog;
use Tk::DialogBox;
use Tk::Text;
use Tk::Menu;
use Tk::Menubutton;
use Tk::widgets qw(Menu);
use Net::Ping;
use IO::File;
use FileHandle;
use Time::HiRes qw( gettimeofday tv_interval );
use DBI;
use constant;
use Math::NumberCruncher;
use Getopt::Long;
use Mail::Sendmail;
use strict;
use Math::BigInt::Calc;
use DBD::AnyData;
use AnyData::Format::XML;
use AnyData::Storage::PassThru;
use vars
qw( $iterations $opt_n $title $mw $t $sth $ref $p $name $button $cou
+nt @button @label
$t0 $resp $elapsed $PingSweep $now $PingSweepLabel $total $info $ip
+@elapsed $VERSION
%mail $address $message %previous $m $update $hostfile $opt_f $opt_r
+ $repeat $seconds
$opt_h $opt_a $subject $opt_x $noemail $opt_v $desc );
GetOptions( 'help' => \$opt_h, 'pings=i' => \$opt_n, 'email=s' => \$op
+t_a,
'file=s' => \$opt_f, 'recur=i' => \$opt_r, 'xml' => \$opt_
+x,
'noemail' => \$noemail, 'version' => \$opt_v );
if ( $opt_r ) {
$opt_r *= 1000;
}
#--------------------------------------------------------------------#
# Change the following addresses to suit your needs.
#--------------------------------------------------------------------#
my $default_addr = 'someaddress@somedomain.com';
my $from_addr = 'someaddress@somedomain.com';
$iterations = $opt_n || 20;
$hostfile = $opt_f || "./hostdata.xml";
$repeat = $opt_r || 90000;
$seconds = $repeat / 1000;
$update = "03-Jan-2002 02:20:15 PM";
$address = $opt_a || $default_addr;
$subject = "SERVER UNAVAILABLE!";
$| = 1;
$VERSION = "1.01a";
$title = "PingSweep v$VERSION";
if ( $opt_v ) {
print $title;
exit;
}
if ( $opt_h ) {
print HelpText();
exit;
}
if ( $opt_x ) {
print HelpDetail();
exit;
}
my $dbh = DBI->connect( "dbi:AnyData(RaiseError=>1):" );
$dbh->func( 'hosts', 'XML', $hostfile, 'ad_import' );
$mw = Tk::MainWindow->new();
$mw->title( $title );
$m = $mw->Frame( -relief => 'groove', -bd => 2 )
->pack( -side => 'top', -anchor => 'n', -fill => 'x' );
$m->Menubutton(
-text => "File",
-tearoff => 0,
-menuitems => [
[
"command" => "Exit",
-command => sub { exit }
]
]
)->pack( -side => 'left' );
$m->Menubutton(
-text => "Help",
-tearoff => 0,
-menuitems => [
[
"command" => "Help...",
-command => \&help
],
[
"command" => "About...",
-command => \&about
]
]
)->pack( -side => 'left' );
$t = $mw->Scrolled("Text",
-width => 82,
-height => 38,
-cursor => 'arrow',
-wrap => 'word',
-background => '#808080',
-scrollbars => 'e'
)->pack( -expand => 1, -fill => 'both' );
$sth = $dbh->prepare( "SELECT * FROM hosts ORDER BY hostname" );
$sth->execute();
while ( $ref = $sth->fetchrow_hashref() ) {
$p = Net::Ping->new( "icmp", 1 );
$name = $ref->{ hostname };
$button = "button" . $count;
$count++;
$button[ $count ] = $t->Button(
-width => 30,
-command => [ \&Ping, $count ],
-cursor => 'hand2',
-text => "$ref->{hostname} ($ref->{ip_address})"
)->pack( -side => 'left', -anchor => 'w' );
$t->windowCreate( 'end', -window => $button[ $count ] );
$t0 = [ gettimeofday ];
$resp = $p->ping( $ref->{ ip_address } );
$elapsed = sprintf( "%.2f", tv_interval( $t0 ) );
if ( $resp ) {
$button[ $count ]->configure(
-foreground => 'black',
-background => 'green',
-activeforeground => 'white',
-activebackground => 'blue'
);
} else {
$elapsed = "n/a";
$button[ $count ]->configure(
-foreground => 'yellow',
-background => 'red',
-activeforeground => 'white',
-activebackground => 'blue'
);
}
$label[ $count ] = $t->Label(
-background => '#808080',
-foreground => 'white',
-width => 60,
-cursor => 'arrow',
-text => "Ping: $elapsed"
)->pack( -side => 'left', -anchor => 'w' );
$t->windowCreate( 'end', -window => $label[ $count ] );
$t->insert( 'end', "\n" );
}
$PingSweep = $t->Button(
-command => \&PingSweep,
-cursor => 'hand2',
-width => 30,
-text => "PingSweep"
)->pack( -side => 'bottom' );
$PingSweep->configure(
-foreground => 'black',
-background => 'yellow',
-activeforeground => 'yellow',
-activebackground => 'black'
);
$t->windowCreate( 'end', -window => $PingSweep );
$PingSweepLabel = $t->Label(
-background => '#808080',
-foreground => 'white',
-width => 60,
-cursor => 'arrow',
-text => "Last PingSweep: Never"
)->pack( -side => 'left', -anchor => 'w' );
$t->windowCreate( 'end', -window => $PingSweepLabel );
$total = scalar @button - 1;
$sth->finish();
$dbh->disconnect();
$mw->Label( -textvariable => \$info, -relief => 'ridge' )->pack( -side
+ => 'bottom', -fill => 'x' );
if ( $noemail ) {
$desc = " -- NOT SENDING EMAIL";
} else {
$desc = "";
}
$info = $title . " -- Auto PingSweep every $seconds seconds$desc";
$mw->repeat( $repeat, \&PingSweep );
MainLoop();
sub Ping {
my $num = shift;
my $text = $button[ $num ]->cget( '-text' );
$text =~ m/^(.*) \((.*)\)$/;
$name = $1;
$ip = $2;
$p = Net::Ping->new( "icmp", 1 );
my $success = 0;
my $failure = 0;
undef @elapsed;
my $failed = 0;
for ( 1 .. $iterations ) {
if ( $failure == 5 && $success == 0 ) {
$failed = 1;
last;
}
$t0 = [ gettimeofday ];
$resp = $p->ping( $ip );
if ( $resp ) {
$elapsed = tv_interval( $t0 );
push ( @elapsed, $elapsed );
$success++;
} else {
$failure++;
}
Time::HiRes::usleep( 10_000 );
}
my $percent = sprintf( "%.2f", ( $success / $iterations ) * 100 );
my ( $high, $low ) = Math::NumberCruncher::Range( \@elapsed );
$high = sprintf( "%.2f", $high );
$low = sprintf( "%.2f", $low );
if ( $high eq "" ) { $high = 0 }
if ( $low eq "" ) { $low = 0 }
my $mean;
if ( $failed ) {
my $current = time();
if ( $current - $previous{ $ip } > 900 && ! $noemail ) {
$now = localtime();
my $subj = $subject . " ($ip)";
$message = "Time: $now\nHostname: $name\nIP Addres
+s: $ip\n";
$previous{ $ip } = $current;
%mail = (
To => $address,
From => $from_addr,
Message => $message,
Subject => $subj
);
sendmail( %mail ) or die $Mail::Sendmail::error;
}
$mean = "n/a";
} else {
$mean = sprintf( "%.3f", Math::NumberCruncher::Mean( \@elapsed
+ ) );
}
if ( $resp ) {
$button[ $num ]->configure( -foreground => 'black', -backgroun
+d => 'green' );
} else {
$button[ $num ]->configure( -foreground => 'yellow', -backgrou
+nd => 'red' );
}
$label[ $num ]->configure( -text => "Ping Success: $percent\% ($su
+ccess/$iterations) Avg. Time: $mean (High: $high, Low: $low)" );
}
sub PingSweep {
$PingSweepLabel->configure( -text => "Starting PingSweep...." );
$info = "Updating Ping Data......";
for ( 1 .. $total ) {
if ( $_ eq "" ) { last }
Ping( $_ );
}
$info = $title . " -- Auto PingSweep every $seconds seconds";
$now = localtime();
$PingSweepLabel->configure( -text => "Last PingSweep: $now" );
}
sub about {
$mw->Dialog(
-title => "About...",
-text => <<"END", -popover => $mw, -font => 'ansi' )->Show;
$title
Last Update: $update
Author: Kurt Kincaid
Copyright (c) 2001, Kurt Kincaid
All Rights Reserved
This is free software and may be modified and/or
redistributed under the sames terms as Perl itself.
END
}
sub help {
my $helptext = HelpText();
$helptext .= "\n" . HelpDetail();
my $help_label = "$title Help";
my $help = MainWindow->new();
$help->title( "Help" );
my $mm = $help->Frame->pack( -side => 'top', -fill => 'x' );
$mm->Button( -text => "Close Window", -command => sub { $help->des
+troy() } )
->pack( -side => 'right' );
$help->Label( -textvariable => \$help_label, -relief => 'ridge' )
->pack( -side => 'bottom', -fill => 'x' );
my $tt = $help->Scrolled("Text",
-width => 80,
-wrap => 'word',
-background => '#ffff88',
-font => '{Courier} 8 {normal}',
-scrollbars => 'e'
)->pack(
-side => 'bottom',
-fill => 'both',
-expand => 1
);
$tt->insert( "end", $helptext );
}
sub HelpText {
my $where;
if ( $opt_h ) {
$where = "type \"pingsweep --xml\"";
} else {
$where = "see below."
}
my $ht = "$title
Last Update: $update
Usage: pingsweep [--email address] [--file host_file] [--help] [--noe
+mail]
[--pings num_of_pings] [--recur seconds] [--version]
+
--email Specify an email address to which warnings should be
emailed. The default address is: $address
Multiple addresses should be separated by commas.
--file Specify alternate XML file with host information. The
default is \"hostdata.xml,\" assumed to be stored in the
same directory as pingsweep. When specifying another file,
+ the
location must be in UNIX format (i.e. /some/dir/hosts.xml)
For XML file specifications, $where
--help This help text.
--noemail Do not send warning email, regardless of server failures.
This supercedes all other email settings.
--pings The number of pings per host. The default is 20.
--recur Frequency of the auto pingsweep, in seconds. Default: 90 s
+econds.
--version Prints the version number and exits.
Example: pingsweep --file somefile.xml --pings 10 --recur 300
NOTE: You may use equal signs (=) when passing command line paramet
+ers,
if preferred. (ex. pingsweep --file=somefile.xml)
";
return $ht;
}
sub HelpDetail {
my $dt = "XML Format Information
The host file must follow standard XML rules and must be in
the following format:
<hosts>
<host>
<hostname>some_hostname</hostname>
<ip_address>255.255.255.1</ip_address>
</host>
<host>
<hostname>some_other_hostname</hostname>
<ip_address>255.255.255.2</ip_address>
</host>
...
</hosts>
PingSweep supports an arbitrary number of hosts.
";
return $dt;
}
|