Description: |
It's nearly impossible for me to keep server connections labeled correctly at my core switches. This ditty uses nmap and Net::Ping to build a list of MAC addresses with associated hostnames/IP addresses for live connections on a local subnet/VLAN. I can then compare it with the switch's CAM table to find what box is connected at which port.
I dabbled with Linux arping utility, but stuck with Net::Ping for one less external dependancy.
Comments or suggestions for improvement are both welcomed and appreciated.
Update 3: 2001-04-30
hashamafied passel o' scalars and minor format cleanup.
Update 2:
cleaned up a few minor Perlish faux pas' and added to-do of using snmpwalk syntax based from riffraff's post in this thread.
Update1:
thanks to turnstep and to Ovid for feedback, and to ncw for his recent post Numeric list to optimised regexp , which made a no-brainer of regex's to match for nmap input.
|
#!/usr/bin/perl -w
# pingarp.pl
# pod at tail
use strict;
use Net::Ping;
my $subnet = shift; # a.b.c.d/nn subnet/bitwise_netma
+sk
my %file = (
nmapout => 'panout',
nmapclean => 'pamclean',
pingout => 'papout',
arpout => 'paaout',
arpclean => 'paaclean',
);
my %bin = (
nmap => '/usr/bin/nmap', # Debian 2.2r3 "Espy"
arp => '/usr/sbin/arp', # Debian 2.2r3 "Espy"
);
my @nmapregex = ( # text to remove from nmap output
'^.*Log of.*$', # header line
'^.*\.0\).*$', # subnet lines
'^.*\.255\).*$', # broadcast lines
'^Host\s+.*\(', # text prior to IP address
'\) appears to be up\.', # text following IP address
'^\s+', # whitespace-only lines
);
my @arpregex = ( # text to remove from copied ARP
+table
'^.*\(incomplete\).*$', # incomplete MAC address
'^Address\s+.*$', # header line
'\sether\s', # HW type
'\s+C\s+eth0', # Flags, Mask, Iface
'^\s+', # whitespace-only lines
);
# Make sure that *something* was entered by user for subnet/netmask
unless ($subnet) {
print "\nUsage: pingarp a.b.c.d/nn<enter>\n",
"where a.b.c.d is your local subnet ",
"and nn is your bitwise netmask netmask.\n\n";
exit;
}
$bin{nmapsyntax} = "-sP $subnet -o $file{nmapout}", # nmap v2.2
# Then check for valid subnet/mask from user to nmap
# ? how to prevent leading zeroes ? (nmap bombs on 'em)
# \. = octet boundry
# \/ = subnet-netmask separator
# 1st octet - match 1-254
# [1-9]|(?:[1-9]|1\d|2[0-4])\d|25[0-4]
# 2nd, 3rd, 4th octets - match 0-254
# \d|(?:[1-9]|1\d|2[0-4])\d|25[0-4]
# bitwise netmasks - 8..14, 16..22, 24..30
# [89]|1[012346789]|2[012456789]|30
print "\nChecking requirements.\n";
# if you got this far, Net::Ping must be installed,
# otherwise would have halted with compilation errors.
unless (-x $bin{nmap}) {
print "nmap not accessible where script expects.\n\n";
exit;
}
unless (-x $bin{arp}) {
print "arp not accessible where script expects.\n\n";
exit;
}
# Oddly enough, using nmap like this doesn't
# seem to properly populate system ARP table.
# System call uses "and" instead of "or" for some reason.
print "Building list of live hosts on local subnet.\n";
system ("$bin{nmap} $bin{nmapsyntax} > /dev/null") and (die "Error cal
+ling $bin{nmap}: $!");
open (NMAPOUT, "<$file{nmapout}")
or die "Error opening $file{nmapout} RO: $!";
open (NMAPCLEAN, ">$file{nmapclean}")
or die "Error opening $file{nmapclean} WO: $!";
while (<NMAPOUT>) {
foreach my $regex(@nmapregex) {s/$regex//g;}
print NMAPCLEAN $_;
}
close (NMAPOUT)
or die "Error closing $file{nmapout}: $!";
close (NMAPCLEAN)
or die "Error closing $file{nmapclean}: $!";
# So we have to do this with real pings.
print "Populating local ARP table.\n";
open (NMAPCLEAN, "<$file{nmapclean}")
or die "Error opening $file{nmapclean} RO: $!";
open (PINGOUT, ">$file{pingout}")
or die "Error opening $file{pingout} WO: $!";
my @hosts = (<NMAPCLEAN>);
my $p = Net::Ping->new("icmp");
foreach my $host (@hosts) {
print PINGOUT "$host is ";
print PINGOUT 'NOT ' unless $p->ping($host, 2);
print PINGOUT "reachable.\n";
sleep (1);
}
$p->close();
# don't actually do anything with $file{pingout}, save it anyway.
close (NMAPCLEAN)
or die "Error closing $file{nmapclean}: $!";
close (PINGOUT)
or die "Error closing $file{pingout}: $!";
print "Querying ARP table and cleaning results.\n";
system("$bin{arp} > $file{arpout}")
and die "Error running $bin{arp}: $!";
open (ARPOUT, "<$file{arpout}")
or die "Error opening $file{arpout} RO: $!";
open (ARPCLEAN, ">$file{arpclean}")
or die "Error opening $file{arpclean} WO: $!";
while (<ARPOUT>) {
foreach my $regex(@arpregex) {s/$regex//g;}
tr/A-Z/a-z/;
print ARPCLEAN $_;
}
close (ARPOUT)
or die "Error closing $file{arpout}: $!";
close (ARPCLEAN)
or die "Error closing $file{arpclean}: $!";
print(
"\nOutput files:\n",
" finished results: $file{arpclean}\n",
" raw arp table: $file{arpout}\n",
" ping-responding hosts: $file{pingout}\n",
" nmap-responding hosts: $file{nmapclean}\n",
" raw nmap results: $file{nmapout}\n\n"
);
=head1 Name
pingarp.pl
=head1 Summary
Generate list of MAC addrs for all live IP devices on your subnet.
=head1 Usage
pingarp.pl a.b.c.d/nn
a.b.c.d = your local subnet address
nn = bitwise netmask
eg;
pingarp.pl 172.31.0.0/16
Must run as root from host on same subnet as target hosts.
Output files are placed in current directory.
=head1 Requires and related
nmap v2.12
www.insecure.org/nmap/
www.debian.org/Packages/stable/nmap.html
Net::Ping
included in standard Perl distribution
arping
freshmeat.net/projects/arping/
www.debian.org/Packages/base/netbase.html
=head1 Tested
with Perl 5.00503 on Debian 2.2 "Espy"
=head1 Updated
2001-04-30 14:00
Hashamafy passel o' scalars.
Format for 75 chars/line max.
2001-03-30
Eliminate multiple useless "my var" at start of script
by calling with "my" when first used.
Clean up inconsistent indenting.
Replace doublequotes with singlequotes for strings.
2000-09-22
Initial working code.
=head1 ToDos
Replace "Querying ARP table..." section with
"snmpwalk <router> <community> IpnetToMediaPhysAddr"
to allow script to work for remote segments.
Will then need to prompt for (name|address) of remote router.
Check for valid subnet/mask input.
commented regex above or
(Net::IPv4Addr|NetAddr::IP|NetAddr::IP::Count|Network::IPv4Addr)
Check that script is being run by root (required for ICMP ping).
Check into File::Temp for mess o' working files.
Translate MACs for Token-Ring.
=head1 Author
ybiC
=cut
|