Skip to main content

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]));
}