#!/usr/bin/perl -w
# cdppoll.pl
use strict;
no strict "subs";
use Net::SNMP;
# Oid for SysName
my($sysNameOID) = '1.3.6.1.2.1.1.5.0';
# Starting Oid for InterfaceName
my($interfaceNameOID) = '1.3.6.1.2.1.31.1.1.1.1';
# Starting OID for the whole CDP-Mib
my($cdp_mibOID) = "1.3.6.1.4.1.9.9.23.1.2.1.1";
# Starting OID for Interfaces to neighbors
my($cdp_mib_ifIndexesOID) = "$cdp_mibOID.3";
my($tmp,$sysName,%systems);
# Regex for interesting IP-Adresses
my($interesting) = "^192\.168\.198\.";
# should normal output be done?
my($putout) = 0;
# print some additional things that might be interesting
my($debug) = 0;
# write csv-File for Visio?
my($visio) = 1;
# All the used variables
my($error,$session,$community,$hostip,$i,$ipOID,$nameOID,$typeOID,$rpo
+rtOID,$lportOID);
my($ifIndex,$ifNIndex,$sys,$link,$fromlink,$tolink,$linktext,$linkdesc
+);
my(@todo,@ifIndexes,@ifNIndexes,@links);
my(%sortedlinks);
# Special trick to get a self-increasing variable
my($getnextid);
tie $getnextid, GetNextID;
#We need a startin point, get an IP from command line
die "usage: $0 seedip" unless ( @ARGV == 1 && $ARGV[0] =~ m{\d+\.\d+\.
+\d+\.\d+});
push(@todo, $ARGV[0]);
#Prompt for SNMP community string
print STDERR "community: ";
chomp($community = <STDIN>);
while(@todo){ #Grab a target and go to work
$hostip= shift(@todo);
next if($hostip !~ m!$interesting!);
print STDERR "\ntrying host $hostip ...\n" if($debug);
#Open SNMP session
($session,$error) = Net::SNMP->session(-hostname => $hostip, -commu
+nity => $community);
return unless($session);
# Ask for sysName
$tmp = $session->get_request( -varbindlist => [$sysNameOID] );
next if(! $tmp); # Cannot ask for sysName, seems to be down/unreach
+able
$sysName = $tmp->{$sysNameOID};
next if($systems{$sysName}->{"seen"}); # seen already
$systems{$sysName}->{"hostip"} = $hostip if(!$systems{$sysName}->{"
+hostip"});
$systems{$sysName}->{"id"} = $getnextid if(!$systems{$sysName}->{"i
+d"});
$systems{$sysName}->{"seen"} = 1;
# Get list of Interfaces with neighbors
undef(@ifIndexes);
$tmp = $session->get_table(-baseoid => $cdp_mib_ifIndexesOID);
# split the interface-OIDs into two arrays (should be fixed ...)
foreach $i (keys(%$tmp)) {
$i =~ m!$cdp_mib_ifIndexesOID\.(([0-9]+)\.[0-9]+)!;
push(@ifIndexes, $2);
push(@ifNIndexes, $1);
}
# Are there any neighbors?
if(@ifIndexes) {
print "Neighbors of $sysName:\n" if($putout);
printf("%-13s %-30s %-30s %-15s\n", "LocalPort", "RemotePort", "Re
+moteName", "RemoteIP") if($putout);
while(@ifIndexes) {
$ifIndex = shift(@ifIndexes);
$ifNIndex = shift(@ifNIndexes);
$ipOID = "$cdp_mibOID.4.$ifNIndex";
$nameOID = "$cdp_mibOID.6.$ifNIndex";
$rportOID = "$cdp_mibOID.7.$ifNIndex";
$typeOID = "$cdp_mibOID.8.$ifNIndex";
$lportOID = "$interfaceNameOID.$ifIndex";
$session->debug(0x10) if($debug);
$tmp = $session->get_request(-varbindlist => [$ipOID, $nameOID,
+$rportOID, $typeOID, $lportOID] );
next if(!$tmp);
# Change FastEthernet and GigabitEthernet to shorter names
$tmp->{$rportOID} =~ s/FastEthernet/Fa/i;
$tmp->{$rportOID} =~ s/GigabitEthernet/Gi/i;
$tmp->{$lportOID} =~ s/FastEthernet/Fa/i;
$tmp->{$lportOID} =~ s/GigabitEthernet/Gi/i;
if($tmp->{$nameOID} =~ m!\(([^\)]+)\)!) {
$tmp->{$nameOID} = $1;
}
# Build remote host structure if not already done
if(! $systems{ $tmp->{$nameOID} } ) {
$systems{ $tmp->{$nameOID} }->{"hostip"} = Convert_IP($tmp->{$
+ipOID});
$systems{ $tmp->{$nameOID} }->{"id"} = $getnextid;
}
# Build link
push(@links, [ $sysName,
$tmp->{$nameOID},
$systems{$sysName}->{"id"},
$systems{ $tmp->{$nameOID} }->{"id"},
$tmp->{$lportOID},
$tmp->{$rportOID}
] );
printf("%-13s %-30s %-30s %-15s\n",
$tmp->{$lportOID},
$tmp->{$rportOID},
$tmp->{$nameOID},
Convert_IP($tmp->{$ipOID})
) if($putout);
push(@todo, Convert_IP($tmp->{$ipOID}) );
} # while(@ifIndexes)
} # if(@ifIndexes)
$session->close;
}
# Generate output for Visio
if($visio) {
print "; Network connections\n";
print "Template, \"Audit Diagram.vst\"\n";
print "\n";
print "; Systems:\n";
foreach $sys (keys(%systems)) {
print "; $sys: IP=";
print "$systems{$sys}->{hostip}, ID=$systems{$sys}->{id}\n";
printf("Shape,\"%s\",\"Ereignis\",\"%s\",,,,,,,\n", $systems{$sys}
+->{id}, "$sys - $systems{$sys}->{hostip}");
}
print "\n; Links:\n";
foreach $link (@links) {
if(${$link}[2] < ${$link}[3] ) {
$linkdesc = "${$link}[0] (${$link}[4]) -> ${$link}[1] (${$link}[
+5])";
$fromlink = ${$link}[2]; $tolink = ${$link}[3];
$linktext = "${$link}[4] -> ${$link}[5]"
} else {
$linkdesc = "${$link}[1] (${$link}[5]) -> ${$link}[0] (${$link}[
+4])";
$fromlink = ${$link}[3]; $tolink = ${$link}[2];
$linktext = "${$link}[5] -> ${$link}[4]"
}
if(! $sortedlinks{$linkdesc} ) {
$sortedlinks{$linkdesc} ++;
printf("Link,,\"Dynamischer Verbinder\",\"%s\",\"%s\",\"%s\"\n",
+$linktext,$fromlink,$tolink);
}
}
}
##### End Of Main #####
sub Convert_IP{ #This sub converts a hex IP to standard xxx.xxx.xxx.xx
+x format
if( $_[0] !~ m!^0x(..)(..)(..)(..)!) {
return "0.0.0.0";
}
return sprintf("%s.%s.%s.%s", hex($1), hex($2), hex($3), hex($4) );
}
# Special trick to get a self-increasing var
package GetNextID;
sub TIESCALAR {
my $class = $_[0];
my $value = $_[1] || 0;
# Leerzeichen weg
$value =~ s/^\s*(.*?)\s*$/$1/;
return bless \$value, $class;
}
sub FETCH {
my $self = shift;
$$self ++;
return $$self;
}
sub STORE {
my $self = shift;
$$self = shift || 0;
# Leerzeichen weg
$$self =~ s/^\s*(.*?)\s*$/$1/;
}
|