1
0
Fork 0
misc-linux-tools/sbin/pinger
Andrew Tomaka e0e789b58f Force Hostname Lookup
By default, pinger will not lookup hostnames for IPs that are
unreachable.  This prevents extended times if dead IPs do not have host
entries.  However, there are also cases where DNS resolution is
important even when the IP is unreachable.  pinger now supports this
using the -f flag.
2013-02-28 07:56:40 -05:00

137 lines
3.4 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, $force, $startTime, $finishTime);
# handle command line options
my $status = getopts('dfrnth', \%switches);
help() if(!$status || $switches{'h'});
for (keys %switches) {
switch($_) {
case 'd' { $alive = 0; }
case 'f' { $force = 1; }
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 || $force)) {
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-f\t\tForce hostname lookup even if unreachable\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);
}