Andrew Tomaka
d744edf83f
Miscellaneous minor functionality fixes, comment additions, and "refactoring" to make code slightly more readable.
135 lines
3.3 KiB
Perl
Executable file
135 lines
3.3 KiB
Perl
Executable file
#!/usr/bin/env perl
|
|
use strict;
|
|
use Getopt::Std;
|
|
use Net::Ping;
|
|
use POSIX;
|
|
use Socket;
|
|
use Switch;
|
|
use Time::HiRes qw/time/;
|
|
|
|
# force print before buffer is full
|
|
$| = 1;
|
|
|
|
# imcp requires root access
|
|
die("pinger must be run as root\n") if($> != 0);
|
|
|
|
my $alive = 1;
|
|
my(%switches, $time, $name, $startTime, $finishTime);
|
|
|
|
# handle command line options
|
|
my $status = getopts('drnth', \%switches);
|
|
help() if(!$status || $switches{'h'});
|
|
for (keys %switches) {
|
|
switch($_) {
|
|
case 'd' { $alive = 0; }
|
|
case 'r' { $alive = 1; }
|
|
case 'n' { $name = 1; }
|
|
case 't' { $time = 1; }
|
|
else {}
|
|
}
|
|
}
|
|
|
|
|
|
die("Usage: pinger START_IP [END_IP]\n")if(scalar(@ARGV) < 1 || scalar(@ARGV) > 2);
|
|
|
|
$startTime = time if($time);
|
|
my $p = Net::Ping->new('icmp');
|
|
my @ips;
|
|
|
|
# must be IP addresses
|
|
if($ARGV[0] !~ /((?:\d{1,3}\.){3}\d{1,3})/ || (defined($ARGV[1]) && $ARGV[1] !~ /((?:\d{1,3}\.){3}\d{1,3})/)) {
|
|
die("Both arguments must be IP addresses if two are specified.\n");
|
|
}
|
|
|
|
my @ip1 = split(/\./, $ARGV[0]);
|
|
# Set the second IP address to the first if no second argument
|
|
my @ip2 = (scalar(@ARGV) == 2) ? split(/\./, $ARGV[1]) : @ip1;
|
|
|
|
# and only the final octet should differ
|
|
if($ip1[0] != $ip2[0] || $ip1[1] != $ip2[1] || $ip1[2] != $ip2[2]) {
|
|
die("The first three octets of the IP addresses must match.\n")
|
|
}
|
|
|
|
# reverse IPs if 1 is larger than 2
|
|
if($ip1[3] > $ip2[3]) {
|
|
my $temp = $ip2[3];
|
|
$ip2[3] = $ip1[3];
|
|
$ip1[3] = $temp;
|
|
}
|
|
|
|
my $baseIp = $ip1[0] . '.' . $ip1[1] . '.' . $ip1[2];
|
|
my $start = $ip1[3];
|
|
my $end = $ip2[3];
|
|
my $count = $ip2[3] - $ip1[3] + 1;
|
|
|
|
for(my $i = $start, my $k = 1; $i <= $end; $i++, $k++) {
|
|
progressBar($k, $count);
|
|
|
|
my $ip = $baseIp . '.' . $i;
|
|
|
|
my $reachable = $p->ping($ip, 1);
|
|
if($reachable == $alive) {
|
|
if($name && $reachable) {
|
|
my $hostaddr = gethostbyaddr(inet_aton($ip), AF_INET);
|
|
$ip = $hostaddr if($hostaddr ne "");
|
|
}
|
|
|
|
push(@ips, $ip);
|
|
}
|
|
}
|
|
$p->close();
|
|
$finishTime = time if($time);
|
|
|
|
print "\n\n";
|
|
($alive) ? print "Reachable:\n" : print "Dead:\n";
|
|
print join(", ", @ips);
|
|
print "\n\n";
|
|
|
|
if($time) {
|
|
my $completed = $finishTime - $startTime;
|
|
printf("Completed in %.2f seconds.\n", $completed);
|
|
}
|
|
|
|
# details from http://stackoverflow.com/questions/1782107/how-do-i-retrieve-the-terminal-width-in-perl
|
|
sub findTerminalWidth {
|
|
my($winsize, $row, $col, $xpixel, $ypixel);
|
|
my $available = 1;
|
|
require 'sys/ioctl.ph';
|
|
$available = 0 unless defined &TIOCGWINSZ;
|
|
open(TTY, "+</dev/tty") or $available = 0;
|
|
$available = 0 unless (ioctl(TTY, &TIOCGWINSZ, $winsize = ''));
|
|
if($available == 1) {
|
|
($row, $col, $xpixel, $ypixel) = unpack('S4', $winsize);
|
|
} else {
|
|
return -1;
|
|
}
|
|
close(TTY);
|
|
|
|
return $col;
|
|
}
|
|
|
|
sub progressBar {
|
|
my($current, $total) = @_;
|
|
my $width = findTerminalWidth();
|
|
|
|
my $barWidth = $width - 11;
|
|
my $percent = ($current / $total) * 100;
|
|
my $barPercent = int($percent / 100 * $barWidth);
|
|
printf(" [%3d\%",$percent);
|
|
if($width > 0) {
|
|
print "] [";
|
|
for(my $i = 1; $i < $barWidth; $i++) {
|
|
($i <= $barPercent) ? print '=' : print ' ';
|
|
}
|
|
}
|
|
print "]\r";
|
|
}
|
|
|
|
sub help {
|
|
print "usage:\t pinger [-d] start [finish]\n\n";
|
|
print "\t-d\t\tList dead addresses\n";
|
|
print "\t-n\t\tReturn list as hostnames when possible\n";
|
|
print "\t-r\t\tList reachable addresses (default)\n";
|
|
print "\t-t\t\tTime ping execution\n";
|
|
exit(1);
|
|
}
|