http://www.perlmonks.org?node_id=130178
Category: Networking Code
Author/Contact Info
Description: This program scans trough a given C-Class subnet and lists the addresses that respond to ping to a file.
I used it to list the addresses on our network, so i could find unused addresses.
It's not pretty or witty, but it worked for me.
The script keeps on scanning, until interrupted. Although the replys are written only once to the file.
Use the code with option 'sort <filename>' to sort the output
It uses a sort routine suggested by tye in the QA section on sorting. (Thanks for that)
Any suggestions are welcome.
This is also my first code post, so be gentle.

/cab
#type 'perl scansub.pl' for help
#
#This program scans a C-class subnet and prints the results to corresp
+onding text file.
#If a computer has once answered the ping, it will not be added to the
+ list again.
#To sort the output type 'perl scansub.pl sort <textfile>'

use strict;
use Net::Ping;

my $host;
my $subnet;
my %state;
my $h;
my $time;
my $if;
my $of;
my $line;

if ($ARGV[0] eq 'sort'){
    &sort;
    exit;
}

unless ($subnet=$ARGV[0]){
    &usage;
    exit;
}
open OF,">>$subnet\.txt";


for $h(1 .. 255){
    $host="$subnet\.$h";
    $state{$host}=''
}


while(){
open OF,">>$subnet\.txt";
for $h(1 .. 254){
    #sleep 2;
    $host="$subnet\.$h";
    my $p=Net::Ping->new('icmp');
    print "\nPinging host $host";
    if ($p->ping($host,1)){
        print " alive";
        if ($state{$host} ne 'up'){
            $time=localtime();
            print OF "$host\twas up at $time\n";
            $state{$host}='up';
        }
    
    }
   }
close OF;
sleep 600
}

sub usage{
    print"
This program scans a C-class subnet 
and lists all machines, that have answered ping,
in a text file.
Use this program to sort the output.

Usage:        perl scansub.pl <subnet>
Example:    perl scansub.pl 192.168.0

Sort:        perl scansub.pl sort <file>
Example:    perl scansub.pl sort 192.168.0.txt

";
}

sub sort{
    unless ($if=$ARGV[1]){
        &usage;
        exit;
    }
open IF,"$if" or die "Cannot open file $if for read: $!";
$of=">s.$if";
open OF,$of;

my @data=<IF>;
my @sorted=grep {s/(^|\D)0+(\d)/$1$2/g,1} sort
    grep {s/(\d+)/sprintf"%06.6d",$1/ge,1} @data;

foreach $line(@sorted){
    print OF $line;
}
close IF;
close OF;

exit;
}
Replies are listed 'Best First'.
Re: Scan C-Class for used IP-addresses
by Chmrr (Vicar) on Dec 07, 2001 at 18:41 UTC

    I had copious free time on my hands, so I decided to give this a once-over. I tried to scribble down what I was doing and why in the comments, but do ask if there's anything confusing that I changed -- either in how I diddled with it, or why.

    Yeah, it looks a lot more verbose, but it's actually a bit more concise, with copious comments. Which come would say is a good thing. ;>

    #!/usr/bin/perl -w ## Always use warnings # # Run with no arguments for help # # This program scans a C-class subnet and prints the results to corres +ponding text file. # If a computer has once answered the ping, it will not be added to th +e list again. # To sort the output type 'perl scansub.pl sort <textfile>' use strict; use Net::Ping; ## Unbuffer your putput so we see it in real time $|++; ## Let's be nice and be case-insensitive.. sort_file($ARGV[1]) if lc $ARGV[0] eq 'sort'; my $subnet = shift @ARGV; ## Usage always exits, so we can be succint here.. usage() unless $subnet; ## Periods don't have to be escaped.. # open OF,">>$subnet.txt" or die "Can't create $subnet.txt: $!"; ## ..and ALWAYS check the return value of open! ## And it turns out that we'll end up doing this shortly anyways, so w +e can take it out here. ## This look isn't useful, really. Hash values start out being undefi +ned. # for (1 .. 255){ ## You could also save yourself a variable AND roll it into one line. # $state{"$subnet.$_"}='' # } ## I pulled this object out of the loop -- we can use the same Net::Pi +ng object over and over. my $p = Net::Ping->new('icmp'); my %state; while () { ## Always check the return value of open.. open OF,">>$subnet.txt" or die "Can't create $subnet.txt: $!"; ## Unbuffer the OF filehandle -- that way, you can tail the file, an +d killing the process won't lose any data select OF; $|++; select STDOUT; ## Scope stuff as tightly as possible -- hence the my $h right here, + not up top. for my $h (1 .. 254){ #sleep 2; ## Ditto with scoping $host to this block. ## Again, period arn't special or anything in double quotes. my $host = "$subnet.$h"; print "\nPinging host $host"; if ($p->ping($host,1)) { ## If we didn't know it was up, spew that out now.. print OF "$host\twas up at ", scalar localtime, "\n" unless $sta +te{$host}; ## Update the number of times we've seen it up $state{$host}++; ## And let STDOUT know about it, too. print " alive ($state{$host} times)"; } else { print " down"; } } close OF; sleep 600; } sub usage { ## HERE documents are your friend for this kind of thing: print <<"EO_USAGE"; This program scans a C-class subnet and lists all machines, that have answered ping in a text file. You can also use this program to sort the output. Usage: perl $0 <subnet> Example: perl $0 192.168.0 Sort: perl $0 sort <file> Example: perl $0 sort 192.168.0.txt EO_USAGE exit; } ## Naming subroutines the same name as builtins is vaguely sketchy, ## and probably good practice to avoid doing. sub sort_file { ## Find out the filename by what we were passed. my $file = shift; usage() unless $file; ## Good error checking here. ++ open IF,"$file" or die "Cannot open file $file for read: $!"; ## I moved the read and close all together up here ## It's a little more obvious what you're doing this way my @data=<IF>; close IF; ## Not overly useful variable $of cleaned out -- it was only used on +ce ## ..and always check the return value of open. Is there a pattern +here? ;> open OF,">s.$file" or die "Cannot open file s.$file for write: $!"; ## Any particular reason you were using grep here instead of map? my @sorted = map {s/(^|\D)0+(\d)(?=\t)/$1$2/g; $_} sort map {s/(\d+)(?=\t)/sprintf"%03.3d",$1/ge; $_} @data; ## You can print it all in one go -- no need for a foreach. Just pr +int the array print OF @sorted; close OF; exit; }

    perl -pe '"I lo*`+$^X$\"$]!$/"=~m%(.*)%s;$_=$1;y^`+*^e v^#$&V"+@( NO CARRIER'

Re: Scan C-Class for used IP-addresses
by grinder (Bishop) on Dec 10, 2001 at 18:09 UTC
    You might be interested in comparing this with pinger - ping a range of hosts to look at Another Way of Doing It.

    --
    g r i n d e r
    just another bofh

    print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u';
Re: Scan C-Class for used IP-addresses
by cab (Beadle) on Dec 07, 2001 at 16:41 UTC
    I just noticed when i tried to dl the code, it gives the file name index.pl, when it should be scansub.pl, someone know how to change the file name, when posting code?

    /cab

      In short, you can't, really. The way I use the "Download code" link is to click on it, bringint up a window with the code in plain text, all alone, then saying File->Save as.. to save it as some file with a vaguely correct name. The reason that your browser is saving it as index.pl is because that's the name of the bit on perlmonks which is serving you the code.

      If your concern is because you mention "scansub.pl" in the code -- well, that's what $0 is for, no? ;>

      perl -pe '"I lo*`+$^X$\"$]!$/"=~m%(.*)%s;$_=$1;y^`+*^e v^#$&V"+@( NO CARRIER'

        Thanks, i seem to learn something new about perl every day :)

        /cab