#!/usr/bin/perl -w ## Name: test/arp ## Author: Simon Leinen ## Description: Dump ARP table using Perl SNMP library ###################################################################### ## Usage: arp hostname [community] ## ## Extracts HOSTNAME's network to media address table using SNMP and ## prints it to standard output. Example output (errors probably due ## to the agent): ## ## $ perl test/arp babar public ## lo0 130.59.4.11 dynamic 08:00:20:12:cc:3f ## lo0 130.59.4.22 dynamic 08:00:20:88:9a:5e ## lo0 130.59.4.30 dynamic 08:00:20:76:48:af ## lo0 130.59.4.33 dynamic 08:00:09:f7:f2:9b ## lo0 130.59.4.38 dynamic 08:00:20:86:95:57 ## lo0 130.59.4.110 dynamic 00:05:02:9c:34:1e ## lo0 130.59.4.134 dynamic 00:05:02:ec:a3:1b ## lo0 130.59.4.202 dynamic 00:00:0c:5d:05:d0 ## lo0 224.0.0.0 dynamic 01:00:5e:00:00:00 ## lo0 224.1.127.255 dynamic 01:00:5e:01:7f:ff ## lo0 224.2.127.253 dynamic 01:00:5e:02:7f:fd ## lo0 224.2.127.254 dynamic 01:00:5e:02:7f:fe ## lo0 239.255.255.255 dynamic 01:00:5e:7f:ff:ff ## hme0 130.59.4.2 dynamic 08:00:20:83:00:69 ## ## The interface name in the first column is the ifDescr value for the ## interface to which the ipNetToMediaIfIndex refers. ###################################################################### require 5.002; use strict; use SNMP_Session "0.57"; # needs map_table use BER; sub out_arp_entry ($$$); sub ether_hex ($); sub ifDescr ($$); sub usage (); # # OIDs we know by name. # my %OIDS = ( 'ipNetToMediaPhysAddress' => [1,3,6,1,2,1,4,22,1,2], 'ipNetToMediaType' => [1,3,6,1,2,1,4,22,1,4], ); my $hostname = $ARGV[0] || usage (); my $community = $ARGV[1] || "public"; my $session; die "Couldn't open SNMP session to $hostname" unless ($session = SNMP_Session->open ($hostname, $community, 161)); $session->map_table ([$OIDS{'ipNetToMediaPhysAddress'}, $OIDS{'ipNetToMediaType'}], \&out_arp_entry); $session->close (); 1; ## out_arp_entry (INDEX, PHYS_ADDRESS, TYPE) ## ## Writes a line of ARP output from a partial row of the ## ipNetToMediaTable. The does not use the ipNetToMediaIfIndex or ## ipNetToMediaNetAddress, because those can be derived from the row ## index. ## sub out_arp_entry ($$$) { my ($index, $physAddress, $type) = @_; ## the index of this table has the form IFINDEX.IPADDRESS, where ## IPADDRESS is a "dotted quad" of four integers. We simply split ## at the first dot to get the interface index and the IP address in ## readable notation: ## my ($ifIndex, $netAddress) = split(/\./, $index, 2); $type = pretty_print ($type); if ($type eq 1) { $type = "other"; } elsif ($type eq 2) { $type = "invalid"; } elsif ($type eq 3) { $type = "dynamic"; } elsif ($type eq 4) { $type = "static"; } $physAddress = ether_hex (hex_string ($physAddress)); printf STDOUT ("%-20s %-15s %-10s %s\n", ifDescr ($ifIndex, $session), $netAddress, $type, $physAddress); } ## ether_hex (HEX_STRING) ## ## Converts a raw hex representation into the common form used in ## Ethernet addresses, e.g. "080020830069" becomes ## "08:00:20:83:00:69". ## sub ether_hex ($) { my ($string) = @_; $string =~ s/([0-9a-f][0-9a-f])/$1:/g; $string =~ s/:$//; $string; } my %ifDescrCache; ## ifDescr (IFINDEX, SESSION) ## ## Return the interface description associated with the given ## IFINDEX. Uses SESSION as the destination for SNMP request. ## Results are cached in %ifDescrCache to avoid sending the same SNMP ## request more than once. ## sub ifDescr ($$) { my @ifDescr = split ('\.','1.3.6.1.2.1.2.2.1.2'); my ($ifIndex, $session) = @_; return $ifDescrCache{$ifIndex,$session} if defined ($ifDescrCache{$ifIndex,$session}); push @ifDescr,$ifIndex; if ($session->get_request_response (encode_oid (@ifDescr))) { my $response = $session->pdu_buffer; my ($bindings, $binding, $oid, $value); ($bindings) = $session->decode_get_response ($response); ($binding,$bindings) = decode_sequence ($bindings); ($oid,$value) = decode_by_template ($binding, "%O%@"); return $ifDescrCache{$ifIndex,$session} = pretty_print ($value); } else { return "if#".$ifIndex; } } sub usage () { die "usage: $0 host [community]"; }