131 lines
3 KiB
Text
131 lines
3 KiB
Text
|
#!/usr/bin/env perl
|
||
|
use strict;
|
||
|
use Net::Ping;
|
||
|
use POSIX;
|
||
|
use Time::HiRes qw/time/;
|
||
|
|
||
|
if($> != 0) {
|
||
|
die("pinger must be run as root\n");
|
||
|
}
|
||
|
|
||
|
my $alive = 1;
|
||
|
my $time = 0;
|
||
|
my($start,$finish);
|
||
|
while($ARGV[0] =~ /\-/) {
|
||
|
my $arg = shift(@ARGV);
|
||
|
$arg =~ s/-//;
|
||
|
|
||
|
my @switches = split('', $arg);
|
||
|
|
||
|
foreach my $switch (@switches) {
|
||
|
if($switch eq "d") {
|
||
|
$alive = 0;
|
||
|
} elsif($switch eq "r") {
|
||
|
$alive = 1;
|
||
|
} elsif($switch eq "t") {
|
||
|
$time = 1;
|
||
|
} elsif($switch eq "h") {
|
||
|
help();
|
||
|
} else {
|
||
|
print "pinger: invalid option -- '$switch'\n";
|
||
|
help();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(scalar(@ARGV) < 1 || scalar(@ARGV) > 2) {
|
||
|
die("Usage: pinger START_IP [END_IP]\n");
|
||
|
}
|
||
|
|
||
|
$start = time if($time);
|
||
|
my $p = Net::Ping->new('icmp');
|
||
|
my @ips;
|
||
|
if(scalar(@ARGV) == 2) {
|
||
|
# must be IP addresses
|
||
|
if($ARGV[0] !~ /((?:\d{1,3}\.){3}\d{1,3})/ || $ARGV[1] !~ /((?:\d{1,3}\.){3}\d{1,3})/) {
|
||
|
die("Both arguments must be IP addresses if two are specified.\n");
|
||
|
}
|
||
|
|
||
|
# and only the final octet should differ
|
||
|
my @ip1 = split(/\./, $ARGV[0]);
|
||
|
my @ip2 = split(/\./, $ARGV[1]);
|
||
|
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")
|
||
|
}
|
||
|
|
||
|
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++) {
|
||
|
$| = 1;
|
||
|
|
||
|
progressBar($k, $count);
|
||
|
|
||
|
my $ip = $baseIp . '.' . $i;
|
||
|
|
||
|
push(@ips, $ip) if($p->ping($ip, 1) == $alive);
|
||
|
}
|
||
|
} elsif(scalar(@ARGV) == 1) {
|
||
|
my $host = $ARGV[0];
|
||
|
|
||
|
push(@ips, $host) if($p->ping($host, 1) == $alive);
|
||
|
}
|
||
|
$p->close();
|
||
|
$finish = time if($time);
|
||
|
|
||
|
print "\n";
|
||
|
($alive) ? print "Reachable:\n" : print "Dead:\n";
|
||
|
print join(", ", @ips);
|
||
|
print "\n\n";
|
||
|
|
||
|
if($time) {
|
||
|
my $completed = $finish - $start;
|
||
|
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;
|
||
|
unless (ioctl(TTY, &TIOCGWINSZ, $winsize = '')) {
|
||
|
$available = 0;
|
||
|
}
|
||
|
if($available == 1) {
|
||
|
($row, $col, $xpixel, $ypixel) = unpack('S4', $winsize);
|
||
|
} else {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
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-r\t\tList reachable addresses (default)\n";
|
||
|
print "\t-t\t\tTime ping execution\n";
|
||
|
exit(1);
|
||
|
}
|