use strict; use Net::SNMP; use Cisco::CopyConfig; my($error,$session,$seed_oid,$oid_root,$community,$hostname,$seed_ip,$found, $htype,$tftpsvr,$line,$key,$value,$sysname,$ssn); my ($osysname,$ochassis,$ossn,$oifdesc,$ovlanallowed);#OID constants my(%done,%devices,%ssndone, %shapes); my(@todo, @lines, @hostinfo); #The sysObjectID OID returns a vendor system identifier OID #Read OIDs and descriptions from file to translate the OIDs open (FH, "c:/CiscoSysObjIDs.csv"); while (){ chomp($_); @lines = split ",", $_; if ($lines[0]){ $devices{$lines[0]} = $lines[1]; } } close FH; #Define OID constants $osysname = "1.3.6.1.2.1.1.5.0"; $ochassis = "1.3.6.1.2.1.1.2.0"; $ossn = "1.3.6.1.2.1.47.1.1.1.1.11.1"; $oifdesc = "1.3.6.1.2.1.2.2.1.2"; #Vlan allowed OID will show only the VLANs not pruned. #Administratively allowed VLANs is 1.3.6.1.4.1.9.5.1.9.3.1.5 $ovlanallowed = "1.3.6.1.4.1.9.9.46.1.6.1.1.4"; $done{"0.0.0.0"}=1; #We need a starting point, get an IP from command line die "usage: $0 seedip" unless ( @ARGV == 1 ); $seed_ip = $ARGV[0]; die "usage: $0 seedip" unless ($seed_ip =~ m{\d+\.\d+\.\d+\.\d+}); $tftpsvr = "xxx.xxx.xxx.xxx"; @todo=($seed_ip); #List of possible targets $oid_root = "1.3.6.1.4.1.9.9.23.1.2.1.1"; $seed_oid = ("$oid_root".".3"); print "Host Name,Host IP,Host Type,Local Interface,Neighbor IP,Neighbor Name,Remote Interface,Neighbor Type,Vlans Allowed to Neighbor\n"; while(@todo){ #Grab a target and go to work $hostname= shift(@todo); $community = "comm1"; unless(exists $done{$hostname}){ #Make sure we haven't done this one yet $done{$hostname}=1; #Remember that we checked this IP #Open SNMP session ($session,$error) = Net::SNMP->session(Hostname => $hostname, Community => $community); return unless($session); $sysname = Get_SNMP_Info($osysname); unless($sysname){ $community = "comm2"; Net::SNMP->session(Hostname => $hostname, Community => $community); $sysname = Get_SNMP_Info($osysname); } unless($sysname){ $community = "comm3"; Net::SNMP->session(Hostname => $hostname, Community => $community); $sysname = Get_SNMP_Info($osysname); } unless($sysname){$sysname = "Unknown device name";} $htype =(Get_SNMP_Info($ochassis)); $htype =~ s/1\.3\.6\.1\.4\.1\.9\.1\.//; if ($htype){ for my $key ( keys %devices ) { if ($htype eq $key) { $htype = $devices{$key} ;last; } } } else{$htype = "Unkown device type";} $ssn = Get_SNMP_Info($ossn); unless ($ssn){$ssn = "UknownSSN$found.$sysname.$hostname"};#Some devices do not support the entPhysical Table $ssndone{$ssn}=1; #Remember that we checked this ssn unless(exists $done{$ssn}){ #Make sure we haven't done this one yet print "$sysname,$hostname,$htype\n"; $found++; Get_Config($hostname,$community,$tftpsvr,$sysname.".cfg"); get_oids($seed_oid);#Get the SNMP info for this target } $session->close; } } print $found."devices found\n"; #---------------------------------------------------------- #This sub finds out how many neighbors the target has #and determines what oids we need to use to get the info that #we want, then calls other subs to get that info #---------------------------------------------------------- sub get_oids{ my($starting_oid , $new_oid , $unique_oid , $result , $crap, $index,$if_oid); my($ip , $name , $port, $type); $starting_oid = $_[0]; $new_oid = $starting_oid ; while(Net::SNMP::oid_context_match($starting_oid,$new_oid)){ $result = $session->get_next_request(($new_oid)); return unless (defined $result); ($new_oid , $crap) = %$result; if (Net::SNMP::oid_context_match($starting_oid,$new_oid)){ $unique_oid = $new_oid; $unique_oid =~ s/$starting_oid//g; $ip = (Convert_IP(Get_SNMP_Info("$oid_root".".4"."$unique_oid"))); $name = (Get_SNMP_Info("$oid_root".".6"."$unique_oid")); $port = (Get_SNMP_Info("$oid_root".".7"."$unique_oid")); $type = (Get_SNMP_Info("$oid_root".".8"."$unique_oid")); $if_oid = $unique_oid; $if_oid =~ s/\.\d+$//; my $ifdescr = Get_SNMP_Info($oifdesc.$if_oid); my $vlanallowed = Get_SNMP_Info($ovlanallowed.$if_oid); if ($vlanallowed){ $vlanallowed = Vlans_Allowed_Format($vlanallowed);} else{$vlanallowed = "Unavailable";} unless (($type=~/phone/i)||($type=~/server/i)||($type=~/ata/i)){@todo=(@todo,$ip)}; #Ignore phones, servers, and ATA devices unless (($type=~/phone/i)||($type=~/server/i)||($type=~/ata/i)){print ",,,$ifdescr,$ip,$name,$port,$type,\"$vlanallowed\"\n"}; get_oids($new_oid); } } } sub Convert_IP{ #This sub converts a hex IP to standard xxx.xxx.xxx.xxx format my($ip , $result , $crap); my($hex1 , $hex2 , $hex3 , $hex4); my($oct1 , $oct2 , $oct3 , $oct4); my($hex_ip) = $_[0] ; if ((substr($hex_ip,0,1) eq "")|| ($hex_ip !~ /0x/)){ $ip = "0.0.0.0"; } else{ $hex_ip =~ s/0x//g; $hex1 = (substr $hex_ip,0,2); $hex2 = (substr $hex_ip,2,2); $hex3 = (substr $hex_ip,4,2); $hex4 = (substr $hex_ip,6,2); $oct1 = hex($hex1); $oct2 = hex($hex2); $oct3 = hex($hex3); $oct4 = hex($hex4); $ip = "$oct1\.$oct2\.$oct3\.$oct4"; } return $ip; } sub Get_SNMP_Info{ #This sub gets the value of an oid my($crap , $value , $result); my($oid) = $_[0]; $result = $session->get_request("$oid"); return unless (defined $result); ($crap , $value) = %$result; return $value; } sub Get_Config{ my ($hostip, $community, $tftp, $cfg_file, $copy); $hostip = shift; $community = shift; $tftp = shift; $cfg_file = shift; unless ($cfg_file) {$cfg_file = $hostip}; $copy = Cisco::CopyConfig->new(Host => $hostip, Comm => $community, Tmout => 15, Retry => 2); $copy->copy($tftp, $cfg_file); if ($copy->error){print "Couldn't get config for $hostip : ".$copy->error."\n"}; } sub Convert_Octet_String{ my $octet_str = shift; my $basePort = 0; my ($index,$octet); my @octet; $octet_str = substr $octet_str, 2; while ($octet_str) { my $octet = hex substr $octet_str, 0, 2, ''; my $index = 0; while ($octet) { next unless $octet & 0x80; push @octet, $basePort + $index; } continue { ++$index; $octet = ($octet << 1) & 0xff; } $basePort += 8; } return @octet; } sub Vlans_Allowed_Format{ my ($vlans,$octets,$bits,$return); $vlans = shift; $octets = From_Hex($vlans); $bits = Reverse_Bit_Order($octets); $return = Range_Format($bits); if($return eq "1-1023"){ $return = "1-4094";#Assume the extended VLANs are allowed as well return $return; } return $return; } sub From_Hex { my ($hex) = @_ ; $hex =~ s/^0x//i ; return pack('H*', $hex) ; } sub Reverse_Bit_Order { my ($octets) = @_ ; return pack('B*', unpack('b*', $octets)) ; } sub Range_Format{ my $bits = shift; my $r = undef; my @s = (); for my $vn (1..length($bits) * 8) { if (vec($bits, $vn, 1)) { if (!defined($r)) { push @s, "$vn" ; $r = 0 ; } else { $r = $vn ; } ; } else { if (defined($r)) { if ($r) { $s[-1] .= "-$r" ; } ; $r = undef ; } ; } } return join(', ',@s); }