#!/usr/bin/perl
#< Ping a /24 network and report on host status
use Getopt::Long qw(:config no_ignore_case);
use Net::DNS::Resolver;
use Net::Ping;
use warnings;
use strict;
our $O_NAMESERVER;
our $O_NETWORK;
our $O_RESOLVE = 0;
our $O_HELP = 0;
our $O_VERBOSE = 0;
our $E_SUCCESS = 0;
our $E_ERROR = 1;
sub print_verbose {
print STDOUT "--> @_\n" if $O_VERBOSE;
}
sub print_error {
print STDERR "Error: @_\n";
}
sub display_help {
my $thisprog = $0;
$thisprog =~ s#^.*/##;
if ( $O_VERBOSE > 0 ) {
print_verbose "thisprog -> $thisprog"
}
printf( "Usage: %s [-hrv] [-R <namesever>] -n <network>\n", $thisprog );
printf( " -r Attempt to resolve addresses\n" );
printf( " -R Specify nameserver for resolution\n" );
printf( " -h Display this help message\n" );
printf( " -v Run in verbose mode\n" );
}
sub process_arguments {
GetOptions ( 'resolve' => \$O_RESOLVE,
'Resolver=s' => \$O_NAMESERVER,
'network=s' => \$O_NETWORK,
'help' => \$O_HELP,
'verbose+' => \$O_VERBOSE ) or $O_HELP++;
if ( $O_HELP > 0 ) {
display_help();
exit $E_SUCCESS;
}
if ( ! defined ( $O_NETWORK ) ) {
print_error "Network (-n) must be specified";
exit $E_ERROR;
}
}
sub check_ip_addr {
if ( defined( $O_NETWORK ) ) {
my $error_counter = 0;
my @octets = split( /\./, $O_NETWORK );
my $num_octets = scalar( @octets );
print_verbose "Network address has $num_octets octets";
++$error_counter if $num_octets != 4;
if ( $octets[$num_octets - 1] != 0 ) {
print_verbose "Not a /24 network address";
++$error_counter;
}
foreach my $octet ( @octets ) {
if ( $octet eq "" || $octet < 0 || $octet > 254 ) {
print_verbose "Octet $octet out of bounds";
++$error_counter;
}
}
if ( $error_counter != 0 ) {
print_error "Errors found in network address";
exit $E_ERROR;
}
}
if ( defined( $O_NAMESERVER ) ) {
my $error_counter = 0;
my @octets = split( /\./, $O_NAMESERVER );
my $num_octets = scalar( @octets );
print_verbose "Nameserver address has $num_octets octets";
++$error_counter if $num_octets != 4;
foreach my $octet ( @octets ) {
if ( $octet eq "" || $octet < 0 || $octet > 254 ) {
print_error "Octet $octet out of bounds";
++$error_counter;
}
}
if ( $error_counter != 0 ) {
print_error "Errors found in nameserver address";
exit $E_ERROR;
}
}
}
sub perform_test {
my @octets = split( /\./, $O_NETWORK );
for ( my $i = 1; $i <= 254; $i++ ) {
my $target = sprintf( "%s.%s.%s.%s", $octets[0], $octets[1], $octets[2], $i );
my $ping = Net::Ping->new();
my $hostname = "";
if ( $O_RESOLVE ) {
my $resolver;
if ( defined( $O_NAMESERVER ) ) {
$resolver = Net::DNS::Resolver->new(
nameservers => [$O_NAMESERVER],
udp_timeout => 1,
retry => 1
);
} else {
$resolver = Net::DNS::Resolver->new(
udp_timeout => 1,
retry => 1
);
}
if ( my $packet = $resolver->query( $target ) ) {
for my $answer ( $packet->answer() ) {
my $type = $answer->type();
if ( $type eq "PTR" ) {
$hostname = $answer->ptrdname();
} else {
$hostname = "Unable to resolve host";
}
}
} else {
$hostname = "Unable to resolve host";
}
}
if ( $ping->ping( $target, 1 ) ) {
if ( $hostname eq "" ) {
printf( "%s is UP\n", $target );
} else {
printf( "%s is UP\t[%s]\n", $target, $hostname );
}
} else {
if ( $hostname eq "" ) {
printf( "%s is DOWN\n", $target );
} else {
printf( "%s is DOWN\t[%s]\n", $target, $hostname );
}
}
}
}
process_arguments();
check_ip_addr();
perform_test();
exit $E_SUCCESS;