OK, here is the updated code. I modified it to read from a file instead of <DATA>. And guess what?!?! It runs under strict!! (Oh, it works too)
++ to
ferrency and
flocto for their help!!
#!/usr/bin/perl -w
use strict;
use vars qw/ $opt_s /;
use Getopt::Std;
use Net::Netmask;
my $subnet;
my %data = ();
my $ARP = '/tmp/arp.bak';
getopt('s');
if (defined($opt_s) && $opt_s ne '') {
$subnet = $opt_s;
} else {
help();
}
my $block = new Net::Netmask($subnet);
if (defined($block->{'ERROR'})) { die "Invalid subnet/mask combinati
+on."}
my @range = $block->enumerate();
#We need to get our temp file
system `tail -250000 /tmp/arp > $ARP`;
#Open the file and read it line by line
open(FH, $ARP) || die ("Couldn't open the arp file $ARP");
while (<FH>)
{
if (/^((?:\d{1,3}\.){3}\d{1,3})/)
{
if ($block->match($1)) { $data{$1}++; }
}
}
close FH;
#I need to specifically remove the network, gateway and broadcast
#addresses since we don't care about those.
#First remove from enumeration array
shift @range; #Network Address
shift @range; #Gateway Address
pop @range; #Broadcast Address
#Now remove from the IP's found in the ARP cache
delete $data{$block->base()};
delete $data{$block->nth(1)};
delete $data{$block->broadcast()};
my @matches = keys %data;
#Compare the array of matched IPs to the enumerated Netblock
my @intersection = my @difference = ();
undef %data;
foreach my $element (@matches, @range) { $data{$element}++ }
foreach my $element (keys %data) {
push @{ $data{$element} > 1 ? \@intersection : \@difference }, $
+element;
}
#Now I'd like to sort the IPs (a little Schwartzian Transform action
+ here...)
my @sorted = map { join '.', unpack 'N*', $_ }
sort
map { pack 'N*', split /\./ }
@difference;
print "Addresses that are candidates for reclaim in:\n";
print $block->desc(), "\n\n";
print join("\n",@sorted), "\n";
sub help {
print <<'HELP';
You must supply a valid subnet.
Acceptable formats are as follows:
192.168.1.0/24 <--- The preferred form.
192.168.1.0:255.255.255.0
192.168.1.0-255.255.255.0
syntax: arpscan.pl -s 192.168.1.0/24
HELP
exit(1);
}
Update: Modified the IP sort to use a Schwartzian Transform so I can have them truly sorted like IP's should be.
Update: Added a little help, support for VLSM's, and stripped out un-needed addresses (network, gateway, and broadcast). **note - the gateway is specific to our organization, yours may use a different address, we use network + 1. Thanks to
tye,
belg4mit, and
arturo for your help with my regex issue. /msg me if I left you out.
Update: Added code to check for invalid IP address/mask combination since some joker here already tried to enter something like 192.168.1.256/24.
Update: Fixed the regex (read as: removed a space that I would have never seen in a million years!) ++
tye
perl -e 'print reverse qw/o b n a e s/;'