Cisco MAC Comparison
From Rabbi Blog
What?
Recently I had to start a process to map PCs to ports on Cisco switches. While I don't have access to the Cisco gear directly, I can request dumps of the mac and arp tables. With that, I wrote some PERL to cross match based on MAC addresses.
I have newer code that not only does DNS lookup, but WINS as well for better resolution. The newer code is also less specific on the format of the switch in data.
Perl
Switch Input
#!/usr/bin/perl opendir(DIR, "./switch_in"); my @files = grep(/\.txt$/,readdir(DIR)); closedir(DIR); my $out="routerinputcommands.txt"; my $COMBINED="scannedswitches.csv"; my $LOGFILE_IN=(); my $SWITCHNAME=(); my $MACADDRESS=(); my $VLAN=(); my $CONNECTIONTYPE=(); my $PORTS=(); open OUT, ">$out" or die "Cannot open $out for write :$!"; open COMBINED, ">$COMBINED" or die "Cannot open $COMBINED for write :$!"; foreach $file (@files) { $LOGFILE_IN="switch_in/$file"; open LOGFILE_IN, $LOGFILE_IN or die "Cannot open $LOGFILE_IN for read :$!"; while (<LOGFILE_IN>) { #Get Switch Name #sh mac-address-table | inc Fa0/ #sh mac-address-table | inc Fa0/ if ($_=~m/(.+)#sh mac(.+)/) { $SWITCHNAME=$1; print "Reading from Switch $1\n"; } #ES403(SVH) (enable) sh cam dy | ex 2/49 elsif ($_=~m/(.+) \(enable\) (.+)/) { $SWITCHNAME=$1; print "Reading from Switch $1\n"; } elsif ($_=~m/-------------------------------------------/) {} elsif ($_=~m/---- ----------- -------- -----/) {} elsif ($_=~m/Vlan Mac Address Type Ports/) {} elsif ($_=~m/Total Mac Addresses for this criterion:/) {} elsif ($_=~m/Total Matching CAM Entries Displayed/) {} elsif ($_=~m/---- ------------------ ----- -------------------------------------------/) {} elsif ($_=~m/ Mac Address Table/) {} elsif ($_=~m/\* \= Static Entry. \+ \= Permanent Entry. \# \= System Entry. R \= Router Entry./) {} elsif ($_=~m/X \= Port Security Entry \$ \= Dot1x Security Entry/) {} elsif ($_=~m/VLAN Dest MAC\/Route Des \[CoS\] Destination Ports or VCs \/ \[Protocol Type\]/) {} ###################################################################### ####################sh mac-address-table | inc Fa0/ output############ ###################################################################### #Get specific line from sh mac-address-table | inc Fa0/ output # 1 0007.e95a.57e8 DYNAMIC Fa0/2 elsif ($_=~m/^(.+) ([0-9a-f][0-9a-f][0-9a-f][0-9a-f]).([0-9a-f][0-9a-f][0-9a-f][0-9a-f]).([0-9a-f][0-9a-f][0-9a-f][0-9a-f]) (DYNAMIC) (.*)/) { $MACADDRESS="$2.$3.$4"; print OUT "sh arp \| inc $MACADDRESS\n"; $VLAN=$1; $CONNECTIONTYPE=$5; $PORTS=$6; print COMBINED "$SWITCHNAME,$MACADDRESS,$CONNECTIONTYPE,$VLAN,$PORTS\n"; } ###################################################################### #####################show mac-address-table########################### ###################################################################### # All 0100.0cdd.dddd STATIC CPU # 1 000f.1fd3.d85a DYNAMIC Fa0/14 elsif ($_=~m/^(.+) ([0-9a-f][0-9a-f][0-9a-f][0-9a-f]).([0-9a-f][0-9a-f][0-9a-f][0-9a-f]).([0-9a-f][0-9a-f][0-9a-f][0-9a-f]) (STATIC) (.*)/) { $MACADDRESS="$2.$3.$4"; print OUT "sh arp \| inc $MACADDRESS\n"; $VLAN=$1; $CONNECTIONTYPE=$5; $PORTS=$6; print COMBINED "$SWITCHNAME,$MACADDRESS,$CONNECTIONTYPE,$VLAN,$PORTS\n"; } #### VLAN Dest MAC/Route Des [CoS] Destination Ports or VCs / [Protocol Type] ###---- ------------------ ----- ------------------------------------------- ##1 00-01-e6-4b-59-d1 2/7 [ALL] elsif ($_=~m/^(.+) ([0-9a-f][0-9a-f])-([0-9a-f][0-9a-f])-([0-9a-f][0-9a-f])-([0-9a-f][0-9a-f])-([0-9a-f][0-9a-f])-([0-9a-f][0-9a-f]) (.*) (.*)\/(.*) (.*)/) { $MACADDRESS="$2$3.$4$5.$6$7"; print OUT "sh arp \| inc $MACADDRESS\n"; $VLAN=$1; $CONNECTIONTYPE="N/A"; my $tmpfa=$9; if ($tmpfa==2) { $tmpfa=0; } $PORTS="Fa$tmpfa/$10"; #print "$_\n"; print COMBINED "$SWITCHNAME,$MACADDRESS,$CONNECTIONTYPE,$VLAN,$PORTS\n"; } else {print "$_\n";} } } >
Router Input
#!/usr/bin/perl #### GET SWITCH INFO ##### my $SWITCH_IN="scannedswitches.csv"; my $out="scannedrouter.csv"; my $checkip=(); my $INFO="Matched Output.csv"; my $DEVICENAME=(); open SWITCH_IN, $SWITCH_IN or die "Cannot open $SWITCH_IN for read :$!"; while(<SWITCH_IN>) { $temp=$_; chop ($temp); #REMOVE ANY NEWLINE @SWITCH_ALL= split(/,/, $temp); #Split push @SWITCH_NAME, $SWITCH_ALL[0]; push @SWITCH_MACADDRESS, $SWITCH_ALL[1]; push @SWITCH_TYPE, $SWITCH_ALL[2]; push @SWITCH_VLAN, $SWITCH_ALL[3]; push @SWITCH_PORT, $SWITCH_ALL[4]; $SWITCH_TOTAL++; } close SWITCH_IN; opendir(DIR, "./router_in"); my @files = grep(/\.txt$/,readdir(DIR)); closedir(DIR); my $LOGFILE_IN=(); my $ROUTERNAME=(); my $ROUTERCONNECTION_TYPE=(); my $ROUTER_MACADDRESS=(); my $ROUTER_TIME=(); my $ROUTER_ARPA=(); my $ROUTER_IP=(); my $ROUTER_PORTSETTING=(); print "_________________________________________\n\n"; print "Reading in Router Data\n"; print "_________________________________________\n\n\n"; open OUT, ">$out" or die "Cannot open $out for write :$!"; foreach $file (@files) { $LOGFILE_IN="router_in/$file"; open LOGFILE_IN, $LOGFILE_IN or die "Cannot open $LOGFILE_IN for read :$!"; while (<LOGFILE_IN>) { #Get Router Name #RA80(SVH)#sh arp | inc 0000.f843.6c6f if ($_=~m/(.+)#(.+)/) { $ROUTERNAME=$1; } ###################################################################### ####################sh arp ############ ###################################################################### #Get specific line from sh arp output #Internet 192.168.111.119 3 0007.e95a.57e8 ARPA FastEthernet0/0 #Internet 192.168.117.1 - 000f.2405.d141 ARPA FastEthernet0/1.117 #^(.*) ([0-9][0-9][0-9]).([0-9][0-9][0-9]).([0-9][0-9][0-9]).([0-9][0-9][0-9]) (\d*) ([0-9a-f][0-9a-f][0-9a-f][0-9a-f]).([0-9a-f][0-9a-f][0-9a-f][0-9a-f]).([0-9a-f][0-9a-f][0-9a-f][0-9a-f]) (.*) (.*) elsif ($_=~m/^(.*) (\d+)\.(\d+)\.(\d+)\.(\d+) (.*) ([0-9a-f][0-9a-f][0-9a-f][0-9a-f]).([0-9a-f][0-9a-f][0-9a-f][0-9a-f]).([0-9a-f][0-9a-f][0-9a-f][0-9a-f])(.*) (.+)/) { $ROUTERCONNECTION_TYPE=$1; $ROUTER_IP="$2.$3.$4.$5"; $ROUTER_MACADDRESS="$7.$8.$9"; $ROUTER_TIME=$6; $ROUTER_ARPA=$11; $ROUTER_PORTSETTING=$10; print OUT "$ROUTERNAME,$ROUTERCONNECTION_TYPE,$ROUTER_IP,$ROUTER_MACADDRESS,$ROUTER_TIME,$ROUTER_ARPA,$ROUTER_PORTSETTING\n"; push @ROUTER_NAME, $ROUTERNAME; push @ROUTER_CONN, $ROUTERCONNECTION_TYPE; push @ROUTER_IPADDRESS, $ROUTER_IP; push @ROUTER_MAC, $ROUTER_MACADDRESS; push @ROUTER_UPTIME, $ROUTER_TIME; push @ROUTER_ARPALIST, $ROUTER_ARPA; push @ROUTER_PORT, $ROUTER_PORTSETTING; } else {print"$_\n";} } } ########## DONE GATHERING INFORMATION ########## ################################################ ########## Start Cross Matchnig ################ print "_________________________________________\n\n"; print "Cross Matching Router Data & Resolving DNS\n"; print "_________________________________________\n\n\n"; ### ELEMENTS ### # @SWITCH_NAME # @SWITCH_MACADDRESS # @SWITCH_TYPE # @SWITCH_VLAN # @SWITCH_PORT # @ROUTER_NAME # @ROUTER_CONN # @ROUTER_IPADDRESS # @ROUTER_MAC # @ROUTER_UPTIME # @ROUTER_ARPALIST # @ROUTER_PORT open INFO, ">$INFO" or die "Cannot open $INFO for write :$!"; print INFO "SWITCH_NAME,SWITCH_PORT,DEVICENAME,ROUTER_IPADDRESS,SWITCH_MACADDRESS,ROUTER_MAC,SWITCH_TYPE,SWITCH_VLAN,ROUTER_UPTIME,ROUTER_CONN\n"; my $SC=0; #switch count foreach $SWITCH_MACADDRESS (@SWITCH_MACADDRESS) { $ARRAYSIZE = scalar (@ROUTER_MAC); for ($i=0; $i < $ARRAYSIZE; $i++) { if ($ROUTER_MAC[$i] eq $SWITCH_MACADDRESS) { #print "$SWITCH_MACADDRESS = $ROUTER_MAC[$i]\n"; $checkip=$ROUTER_IPADDRESS[$i]; $DEVICENAME=""; &IPLOOKUP($checkip); print INFO "$SWITCH_NAME[$SC],$SWITCH_PORT[$SC],$DEVICENAME,$ROUTER_IPADDRESS[$i],$SWITCH_MACADDRESS[$SC],$ROUTER_MAC[$i],$SWITCH_TYPE[$SC],$SWITCH_VLAN[$SC],$ROUTER_UPTIME[$I],$ROUTER_CONN[$I]\n"; last; #Break from the loop } } $SC++; } ######### sub IPLOOKUP { use Net::DNS; use NetAddr::IP; my $ip = new NetAddr::IP (shift) || die "Unable to create NetAddr::IP object\n"; my $res = Net::DNS::Resolver->new; my $num = $ip->num(); for (my $i=0; $i<=$num; ++$i) { my $ip_address = $checkip; if ($ip_address) { my $query = $res->search("$ip_address"); if ($query) { foreach my $rr ($query->answer) { next unless $rr->type eq "PTR"; #print "$ip_address,",$rr->ptrdname, "\n"; $DEVICENAME=$rr->ptrdname; } } else { #print "$ip_address,",$res->errorstring,"\n"; } } ++$ip; } }