getarp
A perl script to get the ARP table out of a router.
Requires Net::SNMP, Net::hostent, and Sys::Syslog
getarp [-s IP [-c STRING ]] [TARGETIP]
-s IP query the router at IP
-c STRING use STRING as the SNMP community
TARGETIP only print results for TARGETIP
--HELP print this screen
You can hard-code the router IP and/or community string in the code. I use a shell alias since I only have one router at this site:
alias getarp='/usr/local/bin/getarp -s 10.0.0.1 -c MyComm'
Without a parameter, it dumps all the IP/MAC combinations it knows about.
With a TARGETIP, it only prints the MAC address for the provided IP.
Example usage:
$ getarp
xx.xx.205.254 -> 00:17:54:02:26:3e
xx.xx.205.255 -> 00:17:54:02:26:3e
xx.xx.207.33 -> 00:0e:39:3c:a1:54
$ getarp xx.xx.207.33
xx.xx.207.33 -> 00:0e:39:3c:a1:54
Notes
- It wasn't immediately obvious to me, but the router won't have its own MAC in its ARP table.
- If the IP you are querying has not sent packets to/through the router recently, the IP/MAC entry won't be in the ARP table. You can sometimes get around this by pinging the IP in question (assuming that it is reachable by you across the router).
- I use this script on firewalls as well.
The Script
use Sys::Syslog qw( :DEFAULT setlogsock);
use Net::SNMP qw(snmp_dispatcher oid_lex_sort);
use Net::hostent;
use Socket;
$BASENAME = $0;
$BASENAME =~ s|\\|/|g;
if ($BASENAME =~ m|(.*/)(.*)|)
{
$BASENAME = $2;
}
#
# code here.
while ($#ARGV > -1)
{
$_ = shift @ARGV;
if (/^-s$/) { $SERVER = shift @ARGV; next; }
if (/^-c$/) { $COMMUNITY = shift @ARGV; next; }
if (/^--DEBUG$/) { $DEBUG = 1; &debug("Debugging on"); next; }
if (/^--HELP$/) { &usage("__SHOW_HELP"); }
if (!$TARGET) { $TARGET = $_; next; }
&usage("$_");
}
sub usage
{
$gripe = shift @_;
print <<"EO_USAGE";
$BASENAME [-s IP [-c STRING ]] [TARGETIP]
-s IP query the router at IP
-c STRING use STRING as the SNMP v2c community
TARGETIP only print results for TARGETIP
--HELP print this screen
EO_USAGE
exit 0 if ($gripe eq "__SHOW_HELP");
&die("Don't understand:$gripe");
}
my $ipToMacs = '1.3.6.1.2.1.4.22.1.2';
$SERVER = $SERVER || '172.30.1.254';
$COMMUNITY = $COMMUNITY || 'public';
# Read the ARP table out of the router.
my ($session, $error) = Net::SNMP->session(
-hostname => $SERVER,
-community => $COMMUNITY,
-port => 161,
-translate => [-octetstring => 0x0] # http://rt.cpan.org/Public/Bug/Display.html?id=1946
);
if (!defined($session))
{
printf("ERROR: %s\n", $error);
exit 1;
}
if (defined($result = $session->get_table(-baseoid => $ipToMacs)))
{
foreach (oid_lex_sort(keys(%{$result})))
{
$raw = $_;
$value = &unpackMac($result->{$_});
$raw =~ s/$ipToMacs\.\d+\.//;
print "$raw -> $value\n" if (($TARGET eq $raw) or !$TARGET);
}
}
else
{
printf("ERROR: %s\n\n", $session->error());
}
$session->close;
sub unpackMac
{
# http://rt.cpan.org/Public/Bug/Display.html?id=1946
sprintf("%s:%s:%s:%s:%s:%s", unpack('H2' x 6, $_[0]));
}