snmp.pm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. package Rstat::snmp;
  2. #
  3. # Copyright (C) Roman Dmitiriev, rnd@rajven.ru
  4. #
  5. use strict;
  6. use English;
  7. use FindBin '$Bin';
  8. use lib "$Bin";
  9. use base 'Exporter';
  10. use vars qw(@EXPORT @ISA);
  11. use Data::Dumper;
  12. use Rstat::config;
  13. use Rstat::main;
  14. use Net::SNMP;
  15. @ISA = qw(Exporter);
  16. @EXPORT = qw(
  17. snmp_set_int
  18. snmp_get_request
  19. get_arp_table
  20. get_fdb_table
  21. get_mac_table
  22. get_vlan_at_port
  23. get_interfaces
  24. get_router_state
  25. get_bgp
  26. snmp_get_req
  27. snmp_get_oid
  28. snmp_walk_oid
  29. table_callback
  30. $ifAlias
  31. $ifName
  32. $ifDescr
  33. $ifIndex
  34. $bgp_prefixes
  35. $bgp_aslist
  36. $arp_oid
  37. $ipNetToMediaPhysAddress
  38. $fdb_table_oid
  39. $fdb_table_oid2
  40. $cisco_vlan_oid
  41. $port_vlan_oid
  42. $fdb_table;
  43. $timeout
  44. );
  45. BEGIN
  46. {
  47. our $ifAlias ='.1.3.6.1.2.1.31.1.1.1.18';
  48. our $ifName ='.1.3.6.1.2.1.31.1.1.1.1';
  49. our $ifDescr ='.1.3.6.1.2.1.2.2.1.2';
  50. our $ifIndex ='.1.3.6.1.2.1.2.2.1.1';
  51. our $bgp_prefixes ='.1.3.6.1.4.1.9.9.187.1.2.4.1.1';
  52. our $bgp_aslist ='.1.3.6.1.2.1.15.3.1.9';
  53. our $arp_oid ='.1.3.6.1.2.1.3.1.1.2';
  54. our $ipNetToMediaPhysAddress = '.1.3.6.1.2.1.4.22.1.2';
  55. our $fdb_table_oid ='.1.3.6.1.2.1.17.4.3.1.2';
  56. our $fdb_table_oid2='.1.3.6.1.2.1.17.7.1.2.2.1.2';
  57. our $port_vlan_oid ='.1.3.6.1.2.1.17.7.1.4.5.1.1';
  58. our $cisco_vlan_oid='.1.3.6.1.4.1.9.9.46.1.3.1.1.2';
  59. our $fdb_table;
  60. our $timeout = 5;
  61. #---------------------------------------------------------------------------------
  62. sub snmp_get_request {
  63. my $ip = shift;
  64. my $oid = shift;
  65. my $community = shift || $snmp_default_community;
  66. my $port = shift || '161';
  67. my $snmp_version = shift || '2';
  68. my ($session, $error) = Net::SNMP->session(
  69. -hostname => $ip,
  70. -community => $community,
  71. -port => $port,
  72. -version => $snmp_version
  73. );
  74. my $result = $session->get_request( -varbindlist => [$oid]);
  75. $session->close;
  76. return if (!$result->{$oid});
  77. return $result->{$oid};
  78. }
  79. #---------------------------------------------------------------------------------
  80. sub snmp_set_int {
  81. my $ip = shift;
  82. my $oid = shift;
  83. my $value = shift;
  84. my $community = shift || $snmp_default_community;
  85. my $port = shift || '161';
  86. my $snmp_version = shift || '2';
  87. my ($session, $error) = Net::SNMP->session(
  88. -hostname => $ip,
  89. -community => $community,
  90. -port => $port,
  91. -version => $snmp_version
  92. );
  93. my $result = $session->set_request( -varbindlist => [$oid,INTEGER,$value]);
  94. $session->close;
  95. return $result->{$oid};
  96. }
  97. #-------------------------------------------------------------------------------------
  98. sub get_arp_table {
  99. my ($host,$community,$version) = @_;
  100. # return if (!HostIsLive($host));
  101. my $port = 161;
  102. my $timeout = 5;
  103. if (!$version) { $version='2'; }
  104. ### open SNMP session
  105. my ($snmp_session, $error) = Net::SNMP->session( -hostname => $host, -community => $community , -version=>$version);
  106. return if (!defined($snmp_session));
  107. $snmp_session->translate([-all]);
  108. my $arp;
  109. my $arp_table1 = $snmp_session->get_table($arp_oid);
  110. my $arp_table2 = $snmp_session->get_table($ipNetToMediaPhysAddress);
  111. if ($arp_table1) {
  112. foreach my $row (keys(%$arp_table1)) {
  113. my ($mac_h) = unpack("H*",$arp_table1->{$row});
  114. next if (!$mac_h or $mac_h eq '000000000000' or $mac_h eq 'ffffffffffff');
  115. my $mac;
  116. if (length($mac_h)==12) { $mac=lc $mac_h; }
  117. next if (!$mac);
  118. $row=trim($row);
  119. my $ip;
  120. if ($row=~/\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/) { $ip=$1.".".$2.".".$3.".".$4; }
  121. next if (!$ip);
  122. $arp->{$ip}=$mac;
  123. };
  124. }
  125. if ($arp_table2) {
  126. foreach my $row (keys(%$arp_table2)) {
  127. my ($mac_h) = unpack("H*",$arp_table2->{$row});
  128. next if (!$mac_h or $mac_h eq '000000000000' or $mac_h eq 'ffffffffffff');
  129. my $mac;
  130. if (length($mac_h)==12) { $mac=lc $mac_h; }
  131. next if (!$mac);
  132. $row=trim($row);
  133. my $ip;
  134. if ($row=~/\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/) { $ip=$1.".".$2.".".$3.".".$4; }
  135. next if (!$ip);
  136. $arp->{$ip}=$mac;
  137. };
  138. }
  139. return $arp;
  140. }
  141. #-------------------------------------------------------------------------------------
  142. sub get_mac_table {
  143. my ($host,$community,$oid,$version) = @_;
  144. my $port = 161;
  145. my $timeout = 5;
  146. if (!$version) { $version='2'; }
  147. my $fdb;
  148. #need for callback
  149. $fdb_table=$oid;
  150. my $fdb_table1 = snmp_get_oid($host,$community,$oid,$version);
  151. if (!$fdb_table1) { $fdb_table1=snmp_walk_oid($host,$community,$oid,$version); }
  152. if ($fdb_table1) {
  153. foreach my $row (keys(%$fdb_table1)) {
  154. my $port_index = $fdb_table1->{$row};
  155. next if (!$port_index);
  156. my $mac;
  157. if ($row=~/\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/) {
  158. $mac=sprintf "%02x%02x%02x%02x%02x%02x",$1,$2,$3,$4,$5,$6;
  159. }
  160. next if (!$mac);
  161. $fdb->{$mac}=$port_index;
  162. };
  163. return $fdb;
  164. }
  165. }
  166. #-------------------------------------------------------------------------------------
  167. sub get_fdb_table {
  168. my ($host,$community,$version) = @_;
  169. # return if (!HostIsLive($host));
  170. my $port = 161;
  171. my $timeout = 5;
  172. if (!$version) { $version='2'; }
  173. my $fdb=get_mac_table($host,$community,$fdb_table_oid,$version);
  174. if (!$fdb) { $fdb=get_mac_table($host,$community,$fdb_table_oid2,$version); }
  175. #maybe cisco?!
  176. if (!$fdb) {
  177. my $vlan_table=snmp_get_oid($host,$community,$cisco_vlan_oid,$version);
  178. if (!$vlan_table) { $vlan_table=snmp_walk_oid($host,$community,$cisco_vlan_oid,$version); }
  179. #fuck!
  180. if (!$vlan_table) { return; }
  181. my %fdb_vlan;
  182. foreach my $vlan_oid (keys %$vlan_table) {
  183. next if (!$vlan_oid);
  184. my $vlan_id;
  185. if ($vlan_oid=~/\.([0-9]{1,4})$/) { $vlan_id=$1; }
  186. next if (!$vlan_id);
  187. next if ($vlan_id>1000 and $vlan_id<=1009);
  188. $fdb_vlan{$vlan_id}=get_mac_table($host,$community.'@'.$vlan_id,$fdb_table_oid,$version);
  189. if (!$fdb_vlan{$vlan_id}) { $fdb_vlan{$vlan_id}=get_mac_table($host,$community.'@'.$vlan_id,$fdb_table_oid2,$version); }
  190. }
  191. foreach my $vlan_id (keys %fdb_vlan) {
  192. next if (!exists $fdb_vlan{$vlan_id});
  193. if (defined $fdb_vlan{$vlan_id}) {
  194. my %tmp=%{$fdb_vlan{$vlan_id}};
  195. foreach my $mac (keys %tmp) {
  196. next if (!$mac);
  197. $fdb->{$mac}=$tmp{$mac};
  198. }
  199. }
  200. }
  201. }
  202. return $fdb;
  203. }
  204. #-------------------------------------------------------------------------------------
  205. sub get_vlan_at_port {
  206. my ($host,$community,$version,$port_index) = @_;
  207. my $port = 161;
  208. my $timeout = 5;
  209. if (!$version) { $version='2'; }
  210. my $vlan_oid=$port_vlan_oid.".".$port_index;
  211. # print "$host,$community,$vlan_oid,$version\n";
  212. my $vlan = snmp_get_req($host,$community,$vlan_oid,$version);
  213. return "1" if (!$vlan);
  214. return "1" if ($vlan=~/noSuchObject/i);
  215. return "1" if ($vlan=~/noSuchInstance/i);
  216. return $vlan;
  217. }
  218. #-------------------------------------------------------------------------------------
  219. sub get_interfaces {
  220. my ($host,$community,$snmp,$skip_empty) = @_;
  221. # return if (!HostIsLive($host));
  222. my $port = 161;
  223. my $timeout = 5;
  224. ### open SNMP session
  225. my ($snmp_session, $error) = Net::SNMP->session( -hostname => $host, -community => $community );
  226. return if (!defined($snmp_session));
  227. $snmp_session->translate([-timeticks]);
  228. my $if_name = $snmp_session->get_table($ifName);
  229. my $if_alias = $snmp_session->get_table($ifAlias);
  230. my $if_descr = $snmp_session->get_table($ifDescr);
  231. my $if_index = $snmp_session->get_table($ifIndex);
  232. my $dev_cap;
  233. foreach my $row (keys(%$if_index)) {
  234. my $index = $if_index->{$row};
  235. next if ($if_name->{$ifName.".".$index} =~/^lo/i);
  236. next if ($if_name->{$ifName.".".$index} =~/^dummy/i);
  237. next if ($if_name->{$ifName.".".$index} =~/^enet/i);
  238. next if ($if_name->{$ifName.".".$index} =~/^Nu/i);
  239. # next if ($if_name->{$ifName.".".$index} =~/^Po/i);
  240. my $ifc_alias;
  241. $ifc_alias=$if_alias->{$ifAlias.".".$index} if ($if_alias->{$ifAlias.".".$index});
  242. my $ifc_name;
  243. $ifc_name=$if_name->{$ifName.".".$index} if ($if_name->{$ifName.".".$index});
  244. my $ifc_desc;
  245. $ifc_desc=$if_descr->{$ifDescr.".".$index} if ($if_descr->{$ifDescr.".".$index});
  246. $dev_cap->{$index}->{alias}=$ifc_alias if ($ifc_alias);
  247. $dev_cap->{$index}->{name}=$ifc_name if ($ifc_name);
  248. $dev_cap->{$index}->{desc}=$ifc_desc if ($ifc_desc);
  249. $dev_cap->{$index}->{index} = $index;
  250. };
  251. return $dev_cap;
  252. }
  253. #-------------------------------------------------------------------------------------
  254. sub get_router_state {
  255. my ($host,$community,$snmp,$skip_empty) = @_;
  256. # return if (!HostIsLive($host));
  257. my $port = 161;
  258. my $timeout = 5;
  259. ### open SNMP session
  260. my ($snmp_session, $error) = Net::SNMP->session( -hostname => $host, -community => $community );
  261. return if (!defined($snmp_session));
  262. $snmp_session->translate([-timeticks]);
  263. my $router_status = $snmp_session->get_table("1.3.6.1.4.1.10.1");
  264. return ($router_status);
  265. }
  266. #-------------------------------------------------------------------------------------
  267. sub get_bgp {
  268. my ($host,$community,$snmp) = @_;
  269. return if (!HostIsLive($host));
  270. my $port = 161;
  271. my $timeout = 5;
  272. ### open SNMP session
  273. my ($snmp_session, $error) = Net::SNMP->session( -hostname => $host, -community => $community );
  274. return if (!defined($snmp_session));
  275. $snmp_session->translate([-timeticks]);
  276. #bgp annonce counter exists?
  277. my $bgp_annonces;
  278. $bgp_annonces = $snmp_session->get_table($bgp_prefixes);
  279. return if (!$bgp_annonces);
  280. my $bgp_status = $snmp_session->get_table($bgp_aslist);
  281. return if (!$bgp_status);
  282. my $as;
  283. foreach my $row (keys(%$bgp_status)) {
  284. my $as_ip=$row;
  285. $as_ip=~s/1\.3\.6\.1\.2\.1\.15\.3\.1\.9\.//;
  286. $as->{$as_ip}=$bgp_status->{$row};
  287. }
  288. return $as;
  289. }
  290. #-------------------------------------------------------------------------------------
  291. sub snmp_get_req {
  292. my ($host,$community,$oid,$version) = @_;
  293. #return if (!HostIsLive($host));
  294. if (!$version) { $version='2'; }
  295. ### open SNMP session
  296. my ($snmp_session, $error) = Net::SNMP->session( -hostname => $host, -community => $community , -version=>$version , -timeout => $timeout, );
  297. return if (!defined($snmp_session));
  298. $snmp_session->translate([-timeticks]);
  299. my $result = $snmp_session->get_request(-varbindlist => [$oid]) or return;
  300. $snmp_session->close();
  301. return $result->{$oid};
  302. }
  303. #-------------------------------------------------------------------------------------
  304. sub snmp_get_oid {
  305. my ($host,$community,$oid,$version) = @_;
  306. #return if (!HostIsLive($host));
  307. if (!$version) { $version='2'; }
  308. ### open SNMP session
  309. my ($snmp_session, $error) = Net::SNMP->session( -hostname => $host, -community => $community , -version=>$version , -timeout => $timeout, );
  310. return if (!defined($snmp_session));
  311. $snmp_session->translate([-timeticks]);
  312. my $table = $snmp_session->get_table($oid);
  313. $snmp_session->close();
  314. return $table;
  315. }
  316. #-------------------------------------------------------------------------------------
  317. sub snmp_walk_oid {
  318. my $host = shift;
  319. my $community = shift;
  320. my $oid = shift;
  321. my $version = shift || '2c';
  322. #return if (!HostIsLive($host));
  323. my ($session, $error) = Net::SNMP->session(
  324. -hostname => $host,
  325. -community => $community,
  326. -nonblocking => 1,
  327. -translate => [-octetstring => 0],
  328. -version => $version,
  329. -timeout => $timeout,
  330. );
  331. if (!defined $session) {
  332. printf "ERROR: %s.\n", $error;
  333. return;
  334. }
  335. my %table; # Hash to store the results
  336. my $result = $session->get_bulk_request(
  337. -varbindlist => [ $oid ],
  338. -callback => [ \&table_callback, \%table ],
  339. -maxrepetitions => 10,
  340. );
  341. snmp_dispatcher();
  342. $session->close();
  343. return \%table;
  344. }
  345. #-------------------------------------------------------------------------------------
  346. sub table_callback {
  347. my ($session, $table) = @_;
  348. my $list = $session->var_bind_list();
  349. if (!defined $list) {
  350. printf "ERROR: %s\n", $session->error();
  351. return;
  352. }
  353. my @names = $session->var_bind_names();
  354. my $next = undef;
  355. while (@names) {
  356. $next = shift @names;
  357. if (!oid_base_match($fdb_table, $next)) { return; }
  358. $table->{$next} = $list->{$next};
  359. }
  360. my $result = $session->get_bulk_request( -varbindlist => [ $next ], -maxrepetitions => 10);
  361. if (!defined $result) {
  362. printf "ERROR: %s.\n", $session->error();
  363. }
  364. return;
  365. }
  366. #-------------------------------------------------------------------------------------
  367. 1;
  368. }