# discovery.pl Version 2.2 # # For information about this script visit http://www.networkdiscovery.net # #$mibdir = "-M c:\\snmp\\mibs"; #$usemibs = "-m all"; # $snmpget = "c:\\snmp\\5.2.1\\bin\\snmpget"; $snmpwalk = "c:\\snmp\\5.2.1\\bin\\snmpwalk"; $netsnmpversion = 5; $snmpver = "-v 1"; $snmptimeout = "-t 1"; $snmpretry = "-r 0"; $snmplog = "-P e"; $hexonly ="-O x"; $asciionly ="-O a"; # To turn on debugging, set debug to 1 $debug = 0; if ($debug == 1) { print "\n\nDebugging is active...\n\n"; `del debug_log.txt`; `del debug_discovery.txt`; `del debug_loops.txt`; `del debug_time.txt`; } if ($netsnmpversion == 5) { $snmplog = "-P e -L n"; if ($debug == 1) { $snmplog = "-P W -L f debug_log.txt"; } } print "\ndiscovery.pl Version 2.2\n\nChoose Output Format\n\n1. Csv\n2. Kiwi CatTools\n3. CiscoWorks 2000 RME\n4. Cisco MARS\n\n(1, 2, 3, or 4):"; chomp ($outformat = ); print "Seed IP Address (Seperate with commas if entering multiple): "; chomp ($seed_ip = ); print "Read SNMP Community (Seperate with commas if entering multiple): "; chomp ($comm = ); print "Would you like to query route tables as well as CDP tables? (y/n) "; chomp ($queryroutes = ); print "Would you like to keep unknown devices? (y/n) "; chomp ($unknown = ); unless ($outformat eq 1) { print "Write SNMP Community: "; chomp ($rwcomm = ); print "VTY Password: "; chomp ($vtypass = ); print "Telnet Username: "; chomp ($telnetuser = ); print "Telnet Password: "; chomp ($telnetpass = ); print "Enable Password: "; chomp ($enablepass = ); print "Enable Secret: "; chomp ($enablesec = ); } if ($outformat eq 2) { print "Group Name: "; chomp ($group = ); } print "Create hostfile entries? (y/n): "; chomp ($createhostfile = ); print "Save to File: "; chomp ($filename = ); if ($filename eq "") {$filename = "$group\.txt";} print "\n\nIt is safe to ignore SNMP timeout and error messages.\nYou will be returned to the prompt when finished.\n\n"; if ($netsnmpversion == 4) { print "If you are using Net-SNMP version 4.2.3 you will\nlikely see a lot of nasty errors. As long as the\nscript keeps running you can ignore them.\n\n"; sleep 15; } print "\! = New Device Discovered\n"; print "\% = Redundant Device Removed\n\n\n"; `del $filename`; print "Creating $filename\n"; ### Timestamp when discovery starts ($S_Second, $S_Minute, $S_Hour, $S_Day, $S_Month, $S_Year, $S_WeekDay, $S_DayOfYear, $S_IsDST) = localtime(time); ### Build first line of "database" with seed device @seeds = split(/,/, $seed_ip); $line = 0; for (@seeds) { $database{"$line"}[1] = $_; $line++ } @comms = split(/,/, $comm); ### Discovery loop $line = 0; $size = keys %database; @tempbase = (); while ($line < $size) { ### Build temp array of new neighbor IP's ### Figure out what SNMP community the device uses for (@comms) { $testcomm = $_; #if ($database{"$line"}[6] eq "") { if ($database{"$line"}[6] eq "" || $database{"$line"}[6] eq "unknown") { $testresult = `$snmpget $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $testcomm $database{"$line"}[1] .1.3.6.1.2.1.1.5.0`; unless ($testresult eq "") { $database{"$line"}[6] = $testcomm; } if ($testresult eq "") { $database{"$line"}[6] = "unknown"; } } } ### Poll for CDP neighbors @tempbase = &neighborip($database{"$line"}[1], $database{"$line"}[6]); ### Poll for Router neighbors if ($queryroutes eq "y") { @tempbase1 = &getroutes($database{"$line"}[1], $database{"$line"}[6]); ### Add the two neighbor tables together for (@tempbase1) { push @tempbase, $_; } } ### Debug if ($debug == 1) { `echo Discovery Cycle: $line Device Queried This Cycle: $database{"$line"}[1] >> debug_discovery.txt`; for (@tempbase) { `echo -- $_ >> debug_discovery.txt`; } } ### /Debug ### Make sure the array of new IP's is not empty $tempbasesize = 0; $tempbasesize = @tempbase; unless ($tempbasesize == 0) { for (@tempbase) { unless ($_ eq "0.0.0.0") { $newip = $_; ### Check to see if we have the IP in the %database ### If so, don't add it again. $newipstat = &dbcheck($newip); if ($newipstat eq "no") { $database{"$size"}[1] = $newip; $size = keys %database; print "\!"; } } } } @tempbase = (); $line++; } ### Device sysName loop $line = 0; $size = keys %database; ### Debug if ($debug == 1) { `echo Size after discovery loop: $size > debug_loops.txt`; } ### /Debug while ($line < $size) { $database{"$line"}[0] = `$snmpget $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $database{"$line"}[6] $database{"$line"}[1] .1.3.6.1.2.1.1.5.0`; $database{"$line"}[0] =~ s/.*\=//g; $database{"$line"}[0] =~ s/"//g; $database{"$line"}[0] =~ s/^ //g; $database{"$line"}[0] =~ s/^STRING: //g; chomp $database{"$line"}[0]; $line++; } ### No sysName loop (If a device didn't respond to a sysName oid, we don't want it.) $line = 0; $line2 = 0; $size = keys %database; %tempbase = (); while ($line < $size) { if ($unknown eq "n") { unless ($database{"$line"}[0] eq "") { $tempbase{"$line2"}[0] = $database{"$line"}[0]; $tempbase{"$line2"}[1] = $database{"$line"}[1]; $tempbase{"$line2"}[6] = $database{"$line"}[6]; $line2++; } } if ($unknown eq "y") { $tempbase{"$line2"}[0] = $database{"$line"}[0]; $tempbase{"$line2"}[1] = $database{"$line"}[1]; $tempbase{"$line2"}[6] = $database{"$line"}[6]; $line2++; } $line++; } %database = %tempbase; ### Device attribute loop $line = 0; $size = keys %database; ### Debug if ($debug == 1) { `echo Size after No sysName loop: $size >> debug_loops.txt`; } ### /Debug while ($line < $size) { unless ($database{"$line"}[0] eq "") { $database{"$line"}[2] = &gettype($database{"$line"}[1], $database{"$line"}[6]); $database{"$line"}[3] = &getserial($database{"$line"}[1], $database{"$line"}[6]); $database{"$line"}[4] = &getios($database{"$line"}[1], $database{"$line"}[6]); } $line++; } ### Duplicate sysName removal loop (Routers (almost) always have two or more IP address' ### so we might have a device in the list several times. We only need it in there once.) $line = 0; $line2 = 1; $size = keys %database; %tempbase = %database; if ($unknown eq "n") { while ($line < $size) { while ($line2 < $size) { if ($tempbase{"$line"}[0] eq $database{"$line2"}[0]) { delete $database{"$line2"}; print "%"; } $line2++; } $line++; $line2 = $line + 1; } $line = 0; $line2 = 0; $size = keys %database; %tempbase = (); while ($line < $size) { unless ($database{"$line"}[0] eq "") { $tempbase{"$line2"} = $database{"$line"}; $line2++; } $line++; } } if ($unknown eq "y") { while ($line < $size) { while ($line2 < $size) { unless ($tempbase{"$line"}[0] eq "") { if ($tempbase{"$line"}[0] eq $database{"$line2"}[0]) { delete $database{"$line2"}; print "%"; } } $line2++; } $line++; $line2 = $line + 1; } $line = 0; $line2 = 0; $size = keys %database; %tempbase = (); while ($line < $size) { unless ($database{"$line"}[6] eq "") { $tempbase{"$line2"} = $database{"$line"}; $line2++; } $line++; } } %database = %tempbase; ### Debug if ($debug == 1) { `echo Size after duplicate sysName loop: $size >> debug_loops.txt`; } ### /Debug ### AP Dot0 MAC address loop. This is handy info for easily finding the AP you are connected to. $line = 0; $size = keys %database; while ($line < $size) { $_ = $database{"$line"}[2]; if (/AIR-AP/) { $database{"$line"}[5] = `$snmpget $mibdir $usemibs $snmpver $snmptimeout $snmpretry -c $database{"$line"}[6] $database{"$line"}[1] .1.3.6.1.2.1.2.2.1.6.1`; $database{"$line"}[5] =~ s/.*: //g; $database{"$line"}[5] =~ s/\n//g; $database{"$line"}[5] =~ s/\s+//g; } $line++; } sort values %database; ### Timestamp when discovery finishes ($F_Second, $F_Minute, $F_Hour, $F_Day, $F_Month, $F_Year, $F_WeekDay, $F_DayOfYear, $F_IsDST) = localtime(time); print "\n\n\nStart Time: $S_Hour:$S_Minute:$S_Second\n"; print "End Time: $F_Hour:$F_Minute:$F_Second\n"; print "Devices Discovered: $size\n"; ### Debug if ($debug == 1) { `echo Start Time: $S_Hour:$S_Minute:$S_Second > debug_time.txt`; `echo End Time: $F_Hour:$F_Minute:$F_Second >> debug_time.txt`; } ### /Debug ### Print results # # Hostname -> $database{"$line"}[0] # IP Address -> $database{"$line"}[1] # Device Type -> $database{"$line"}[2] # Serial Number -> $database{"$line"}[3] # IOS Version -> $database{"$line"}[4] # AP Dot0 MAC -> $database{"$line"}[5] # SNMP RO Comm -> $database{"$line"}[6] if ($createhostfile eq "y") { # hostfile entries $line = 0; $size = keys %database; while ($line < $size) { `echo $database{"$line"}[1] $database{"$line"}[0]>> $filename.hosts`; $line += 1; } } if ($outformat eq 3) { `echo ; The following header line is mandatory - only the value of the > $filename`; `echo ; source attribute can be modified (e.g. source = Hand edit). >> $filename`; `echo cisco Systems NM data import, source = Hand edit; Version = 1.0; Type = Csv >> $filename`; `echo ; >> $filename`; `echo ; Here are the columns of the table. >> $filename`; `echo ; >> $filename`; `echo ;Col# = 1; Name = Device name include domain unless your site has >> $filename`; `echo ; unqualified device names registered in the name services >> $filename`; `echo ; - or - >> $filename`; `echo ; IP address in dotted decimal notation >> $filename`; `echo ;Col# = 2: Name = RO community string >> $filename`; `echo ;Col# = 3: Name = RW community string >> $filename`; `echo ;Col# = 4: Name = Serial Number >> $filename`; `echo ;Col# = 5: Name = User Field 1 >> $filename`; `echo ;Col# = 6: Name = User Field 2 >> $filename`; `echo ;Col# = 7: Name = User Field 3 >> $filename`; `echo ;Col# = 8: Name = User Field 4 >> $filename`; `echo ;Col# = 9: Name = Telnet password >> $filename`; `echo ;Col# = 10: Name = Enable password >> $filename`; `echo ;Col# = 11: Name = Enable secret >> $filename`; `echo ;Col# = 12: Name = Tacacs user >> $filename`; `echo ;Col# = 13: Name = Tacacs password >> $filename`; `echo ;Col# = 14: Name = Tacacs enable user >> $filename`; `echo ;Col# = 15: Name = Tacacs enable password >> $filename`; `echo ;Col# = 16: Name = Local user >> $filename`; `echo ;Col# = 17: Name = Local password >> $filename`; `echo ;Col# = 18: Name = Rcp user >> $filename`; `echo ;Col# = 19: Name = Rcp password; Comment = not used, leave blank >> $filename`; `echo ; >> $filename`; `echo ; Here are the rows of data. >> $filename`; `echo ; >> $filename`; $line = 0; $size = keys %database; while ($line < $size) { `echo $database{"$line"}[0],$database{"$line"}[6],${rwcomm},$database{"$line"}[3],,,,,${telnetpass},${enablepass},${enablesec},${telnetuser},${telnetpass},,${enablesec},${telnetuser},${telnetpass},,, >> $filename`; $line += 1; } } if ($outformat eq 2) { # Kiwi `echo Type Group Name HostAddress Filename Model ConnectVia Telnet TelnetPort Session VTYPass ConsolePass EnablePass PrivilegeLevel AAAUsername AAAPassword SNMPRead SNMPWrite RequireVTYLogin LoginUsesAAA EnableUsesAAA VTYPrompt ConsolePrompt EnablePrompt AAAUserPrompt AAAPassPrompt Address1 Address2 Address3 ContactName ContactPhone ContactEmail ContactOther AlertEmail SerialNumber AssetTag Identification SerialOther ActivitySpecific1 ActivitySpecific2 > $filename`; $line = 0; $size = keys %database; while ($line < $size) { `echo Cisco.Router.General $group $database{"$line"}[0] $database{"$line"}[1] $database{"$line"}[0] $database{"$line"}[2] Direct connect Telnet 23 ${vtypass} ${enablepass} ${telnetuser} ${telnetpass} $database{"$line"}[6] $rwcomm $database{"$line"}[3] >> $filename`; $line += 1; } } if ($outformat eq 1) { # CSV `echo Hostname,IP Address,Device Type,Serial Number,IOS Version,AP Dot0 MAC,SNMP RO Comm > $filename`; $line = 0; $size = keys %database; while ($line < $size) { `echo $database{"$line"}[0],$database{"$line"}[1],$database{"$line"}[2],$database{"$line"}[3],$database{"$line"}[4],$database{"$line"}[5],$database{"$line"}[6] >> $filename`; $line += 1; } } if ($outformat eq 4) { # MARS $line = 0; $size = keys %database; while ($line < $size) { $_ = $database{"$line"}[2]; unless (/AIR-AP/) { if (/2924|2950|3524|3548|3550|3560|3750|4506|4507|6506|6509|6513/) { `echo $database{"$line"}[1],$database{"$line"}[6],,,SWITCH-IOS,TELNET,$telnetuser,,$telnetpass,$enablepass,,,,,,,,,, >> $filename`; } if (/1700|1720|1721|1750|1751|1841|2600|2610|2611|2621|2651|2691|2811|2821|3600|3640|3660|3725|3745|7200|7202|7204|7206/) { `echo $database{"$line"}[1],$database{"$line"}[6],,,IOS,TELNET,$telnetuser,,$telnetpass,$enablepass,,,,,,,,,, >> $filename`; } else { `echo $database{"$line"}[1],$database{"$line"}[6],,,SWITCH-CATOS,TELNET,$telnetuser,,$telnetpass,$enablepass,,,,,,,,,, >> $filename`; } } $line++; } } ### Subroutines below ############################################ sub neighborip { @d_ip_temp = (); @d_ip_temp3 = (); @d_ip_temp4 = (); @device_ip = (); ### Get CDP Neighbor IP Address's $deviceip = `$snmpwalk $hexonly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.4.1.9.9.23.1.2.1.1.4`; ### Parse SNMP response, resulting in IP address's in HEX @d_ip_temp = split(/\n/, $deviceip); for (@d_ip_temp) { $d_ip = $_; if (/Hex-STRING/) { $d_ip =~ s/.*STRING://g; $d_ip =~ s/"//g; $d_ip =~ s/^ //g; push @d_ip_temp3, $d_ip; } } ### Convert HEX IP's to Decimal IP's for (@d_ip_temp3) { @d_ip_temp4 = split(/ /, $_); $oct1 = hex($d_ip_temp4[0]); $oct2 = hex($d_ip_temp4[1]); $oct3 = hex($d_ip_temp4[2]); $oct4 = hex($d_ip_temp4[3]); $ip_temp = "${oct1}\.${oct2}\.${oct3}\.${oct4}"; $ip_temp =~ s/\.\s*$//g; $_ = $ip_temp; # output must roughly take the shape of an IP address... if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) { push @device_ip, $ip_temp; } } @device_ip } ### End of sub neighbor sub gethost { $ip_addy = $_[0]; $AF_INET = 2; ($name,$aliases,$type,$len,$addr) = gethostbyname($ip_addy); ($hname,$aliases,$type,$len,@addrs) = gethostbyaddr($addr,$AF_INET); ($a,$b,$c,$d) = unpack('C4',$addr ); if ($hname eq "") {return "lookupfailure";} else {return $hname;} } ### End of sub gethost sub dbcheck { $dbcheck_ip = $_[0]; $_ = $dbcheck_ip; if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/) { $dbcheck_size = keys %database; $dbcheck_i = 0; while ($dbcheck_i <= $dbcheck_size) { if ($dbcheck_ip eq "0.0.0.0") {return "yes";} if ($dbcheck_ip eq $database{"$dbcheck_i"}[1]) {return "yes";} $dbcheck_i += 1; } return "no"; } else {return "yes";} } ### End of sub dbcheck sub getserial { unless ($_[1] eq "unknown") { $gserial = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.4.1.9.5.1.2.19.0`; if ($gserial eq "") { # Provisioning for new 6509 IOS $gserial = `$snmpget $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.4.1.9.5.1.2.19.0`; } if ($gserial eq "") { # Provisioning for older (CatOS) Cisco equipment $gserial = `$snmpget $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.2.1.47.1.1.1.1.11.1`; } $gserial =~ s/.*\=//g; $gserial =~ s/"//g; $gserial =~ s/^ //g; $gserial =~ s/^STRING: //g; $gserial =~ s/\(//g; $gserial =~ s/\)//g; chomp $gserial; return $gserial; } } ### End of sub getserial sub gettype { unless ($_[1] eq "unknown") { $gtype = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.2.1.47.1.1.1.1.2.1001`; $_ = $gtype; if (/Port/) { $gtype = ""; } if (/module/) { $gtype = ""; } if (/Mainboard/) { $gtype = ""; } if (/CPU/) { $gtype = ""; } if ($gtype eq ""){ $gtype = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.2.1.47.1.1.1.1.13.1`; } if ($gtype eq ""){ $gtype = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.4.1.9.9.92.1.1.1.3.1`; } if ($gtype eq "") { $gtype = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.4.1.9.3.6.11.1.3.1`; } if ($gtype eq "") { $gtype = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.4.1.9.5.1.2.16.0`; } $gtype =~ s/.*\=//g; $gtype =~ s/"//g; $gtype =~ s/^\ //g; $gtype =~ s/^STRING: //g; $gtype =~ s/\s+$//g; $gtype =~ s/\(//g; $gtype =~ s/\)//g; chomp $gtype; return $gtype; } } ### End of sub gettype sub getios { unless ($_[1] eq "unknown") { $gios = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.4.1.9.5.1.3.1.1.20.3`; if ($gios eq ""){ $gios = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.2.1.47.1.1.1.1.9.3000`; } if ($gios eq ""){ $gios = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.4.1.9.5.1.3.1.1.19.1`; } if ($gios eq ""){ $gios = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.2.1.47.1.1.1.1.10.1000`; } if ($gios eq ""){ $gios = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.4.1.9.9.92.1.1.1.7.1000`; } if ($gios eq ""){ $gios = `$snmpget $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.2.1.47.1.1.1.1.9.1`; } $gios =~ s/.*\=//g; $gios =~ s/"//g; $gios =~ s/^ //g; $gios =~ s/ Moth.*//g; $gios =~ s/^STRING: //g; $gios =~ s/\(//g; $gios =~ s/\)//g; chomp $gios; return $gios; } } ### End of sub getios sub getroutes { unless ($_[1] eq "unknown") { $routetable = `$snmpwalk $asciionly $snmpver $mibdir $usemibs $snmptimeout $snmpretry $snmplog -c $_[1] $_[0] .1.3.6.1.2.1.4.21.1.7`; @routes = split (/\n/, $routetable); for (@routes) { $_ =~ s/.*://g; $_ =~ s/^ //g; } return @routes; } } ### End of sub getroutes