1
0

snmp.pm 14 KB

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