#!/usr/bin/perl # name: Ping or Trace # author: Matt Rankin # purpose: Saves me the effort of manually finding reachable hosts on a network. # details: Reads a text file of candidate host machines (such as dig axfr # output) and sequentially traces or pings each one, suppressing most # failed attempts for clarity. # usage: pot [-type] hostfile [search] use strict; use constant MAX_HOSTS => 75; use constant WARN_HOSTS => 25; my $type; # type (p or t) my $file; # filename my $srch; # search filter (optional) my @host; # filtered list of hosts to interrogate my @rslt; # returned output from shell command my $a = 0, $b = 0; # counters while( @ARGV ){ if( $ARGV[0] =~ m/^-[pt]$/ ){ $type = shift; }elsif( !defined( $file ) ){ $file = shift; }elsif( !defined( $srch ) ){ $srch = shift; }else{ &help; } } $type = '-p' unless( defined( $type ) ); &help unless( defined( $file ) ); open( FH, $file ) or die( "IO Fail on \"$file\".\n" ); while( my $line = ){ next if( $line =~ m/^;/ or !( $line =~ m/\s+IN\s+A\s+/ ) or $line =~ m/^\s*$/ ); if( $line =~ m/^(\S*).*$/ ){ push( @host, $1 ) unless( &exists( \@host, $1, $srch ) ); $b++; } } close( FH ); exit( 0 ) unless( &confirm( scalar( @host ) ) ); foreach my $arg ( @host ){ print( STDERR "\nchecking $arg ...\n\n" ); sleep( 2 ); if( $type eq '-p' ){ @rslt = `ping -R -c 1 $arg` or next; }elsif( $type eq '-t' ){ @rslt = `traceroute -m 20 -w 2 $arg` or next; } unless( &errord( \@rslt ) ){ print( @rslt ); $a++; }else{ print( STDERR "Fail.\n" ); } } print( STDERR "\n$a of $b hosts successfully scanned.\n" ); exit( 0 ); # =============================== subroutines ================================ sub exists( $$$ ){ my @lotn = @{ shift( @_ ) }; # list of the now my $ph = shift; # present host my $fltr = shift; # filter (if any) foreach my $h ( @lotn ){ return 1 if( $ph eq $h ); } return ( defined( $fltr ) and not $ph =~ m/$fltr/i ) ? 1 : 0; } sub errord( $ ){ my @fail = ( '\* \* \*', '100% packet loss' ); my $re = join( '|', @fail ); my @out = @{ shift( @_ ) }; # program output foreach my $line ( @out ){ if( $line =~ m/$re/i ){ return 1; } } return 0; } sub confirm( $ ){ my $in; my $ln = shift; if( $ln > MAX_HOSTS ){ print( STDERR "There are more than " . MAX_HOSTS . " hosts. Exiting ...\n" ); return 0; }elsif( $ln > WARN_HOSTS ){ do{ print( STDERR "There are more than " . WARN_HOSTS . " hosts. Continue? ( y | n ) " ); $in = ; }until( $in =~ m/^[yn]/i ); return ( $in =~ m/^y/i ) ? 1 : 0; }else{ return 1; } } sub help{ print( STDERR "\nUsage: pot [-type] {axfr} [search]\n\n" . " type - can be either '-r' (ping -R) or '-t' (traceroute)\n" . " (default is ping)\n" . " axfr - path to domain transfer file\n" . " search - optional search parameters on hostname\n\n" . "Performs a single ping or trace on a list of hosts. pot filters\n" . "all duplicate host names and (sometimes) suppresses output of\n" . "unsuccessful attempts. I'm still working on that last bit.\n\n"); exit( 0 ); }