CapsManPlugin.pm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. package Foswiki::Plugins::CapsManPlugin;
  2. use utf8;
  3. use Net::SNMP qw(:snmp ticks_to_time TRANSLATE_NONE);
  4. use Net::Ping;
  5. # Always use strict to enforce variable scoping
  6. use strict;
  7. # $VERSION is referred to by Foswiki, and is the only global variable that
  8. # *must* exist in this package
  9. use vars qw( $VERSION $RELEASE $debug $pluginName );
  10. use Foswiki::Func (); # The plugins API
  11. use Foswiki::Plugins (); # For the API version
  12. # This should always be $Rev: 8713$ so that Foswiki can determine the checked-in
  13. # status of the plugin. It is used by the build automation tools, so
  14. # you should leave it alone.
  15. $VERSION = '$Rev: 8713$';
  16. # This is a free-form string you can use to "name" your own plugin version.
  17. # It is *not* used by the build automation tools, but is reported as part
  18. # of the version number in PLUGINDESCRIPTIONS.
  19. $RELEASE = '1.01';
  20. # Name of this Plugin, only used in this module
  21. $pluginName = 'CapsManPlugin';
  22. =pod
  23. ---++ initPlugin($topic, $web, $user, $installWeb) -> $boolean
  24. * =$topic= - the name of the topic in the current CGI query
  25. * =$web= - the name of the web in the current CGI query
  26. * =$user= - the login name of the user
  27. * =$installWeb= - the name of the web the plugin is installed in
  28. REQUIRED
  29. Called to initialise the plugin. If everything is OK, should return
  30. a non-zero value. On non-fatal failure, should write a message
  31. using Foswiki::Func::writeWarning and return 0. In this case
  32. %FAILEDPLUGINS% will indicate which plugins failed.
  33. In the case of a catastrophic failure that will prevent the whole
  34. installation from working safely, this handler may use 'die', which
  35. will be trapped and reported in the browser.
  36. You may also call =Foswiki::Func::registerTagHandler= here to register
  37. a function to handle tags that have standard Foswiki syntax - for example,
  38. =%MYTAG{"my param" myarg="My Arg"}%. You can also override internal
  39. Foswiki tag handling functions this way, though this practice is unsupported
  40. and highly dangerous!
  41. =cut
  42. sub initPlugin {
  43. my( $topic, $web, $user, $installWeb ) = @_;
  44. # check for Plugins.pm versions
  45. if( $Foswiki::Plugins::VERSION < 1.026 ) {
  46. Foswiki::Func::writeWarning( "Version mismatch between $pluginName and Plugins.pm" );
  47. return 0;
  48. }
  49. Foswiki::Func::registerTagHandler( 'CapsManINFO', \&_CapsManINFO );
  50. # Plugin correctly initialized
  51. return 1;
  52. }
  53. sub table_callback {
  54. my ($session, $OID_ifTable, $table) = @_;
  55. my $list = $session->var_bind_list();
  56. if (!defined $list) {
  57. printf "ERROR: %s\n", $session->error();
  58. return;
  59. }
  60. my @names = $session->var_bind_names();
  61. my $next = undef;
  62. while (@names) {
  63. $next = shift @names;
  64. if (!oid_base_match($OID_ifTable, $next)) {
  65. return; # Table is done.
  66. }
  67. $table->{$next} = $list->{$next};
  68. }
  69. my $result = $session->get_bulk_request( -varbindlist => [ $next ], -maxrepetitions => 10, );
  70. if (!defined $result) { printf "ERROR: %s.\n", $session->error(); }
  71. return;
  72. }
  73. sub StrToIp{
  74. return unpack('N',pack('C4',split(/\./,$_[0])));
  75. }
  76. sub get_last_dec {
  77. my $oid = shift;
  78. if ($oid=~/\.(\d*)$/) { return $1; }
  79. return '';
  80. }
  81. sub get_first_dec {
  82. my $oid = shift;
  83. if ($oid=~/(.*)\.(\d*)$/) { return $1; }
  84. return $oid;
  85. }
  86. sub extract_dec_mac {
  87. my $base_oid = shift;
  88. my $key = shift;
  89. $key =~s/^$base_oid\.//;
  90. return $key;
  91. }
  92. sub mac_splitted{
  93. my $mac=shift;
  94. return if (!$mac);
  95. my $ch=shift || ":";
  96. $mac=~s/(\S{2})(\S{2})(\S{2})(\S{2})(\S{2})(\S{2})/$1:$2:$3:$4:$5:$6/g;
  97. if ($ch ne ":") { $mac=~s/\:/$ch/g; }
  98. return $mac;
  99. }
  100. sub dec2mac {
  101. my $key = shift;
  102. my @dec_mac = split(/\./,$key);
  103. my @mac=();
  104. for (my $i = 0; $i < scalar(@dec_mac); $i++) { $mac[$i]=sprintf("%02x",$dec_mac[$i]); }
  105. $key = join(':',@mac);
  106. return $key;
  107. }
  108. sub expand_status {
  109. my $client = shift;
  110. my $ret ='';
  111. foreach my $id (sort keys %$client) {
  112. $ret.='| '.$client->{$id}->{int_name}.' | ';
  113. $ret.=$client->{$id}->{SSID}.' | ';
  114. $ret.=$client->{$id}->{mac}.' | ';
  115. $ret.=$client->{$id}->{rx}.' dBm / '.$client->{$id}->{tx}.'dBm | ';
  116. $ret.=$client->{$id}->{rxrate}.'M / '.$client->{$id}->{txrate}.'M | ';
  117. $ret.=$client->{$id}->{uptime}." |\n";
  118. }
  119. return $ret;
  120. };
  121. sub _CapsManINFO {
  122. my($session, $params, $theTopic, $theWeb) = @_;
  123. my $host = $params->{_DEFAULT} || $params->{host};
  124. ### check host alive
  125. my $p = Net::Ping->new("tcp",1,1);
  126. my $ok= $p->ping($host);
  127. $p->close();
  128. if (!$ok) { return "Ups $host is not available<BR>"; }
  129. undef($p);
  130. my $port = $params->{port} || 161;
  131. my $timeout = $params->{timeout} || 5;
  132. my $community = $params->{community};
  133. $community = 'public' if (!$community);
  134. #1 - client list
  135. #2 - mac list
  136. #3 - ssid list
  137. my $mode = $params->{mode} || '3';
  138. my $snmp_session;
  139. my $error;
  140. my %DefaultMibs=(
  141. 'Description' => '.1.3.6.1.2.1.1.1.0',
  142. 'Uptime' => '.1.3.6.1.2.1.1.3.0',
  143. 'Name' => '.1.3.6.1.2.1.1.5.0',
  144. );
  145. my %MikrotikCapsManMibs=(
  146. 'ClientMac'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.1',
  147. 'ClientUptime'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.3',
  148. 'ClientTxRate'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.8',
  149. 'ClientRxRate'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.9',
  150. 'ClientTx'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.10',
  151. 'ClientRx'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.11',
  152. 'ClientSSID'=>'.1.3.6.1.4.1.14988.1.1.1.5.1.12',
  153. 'InterfaceList'=>'.1.3.6.1.4.1.14988.1.1.14.1.1.2',
  154. #'APNames'=>'.1.3.6.1.4.1.14988.1.1.1.11.1.2',
  155. #'APStatus'=>'.1.3.6.1.4.1.14988.1.1.1.11.1.3',
  156. #'APAddress'=>'.1.3.6.1.4.1.14988.1.1.1.11.1.4',
  157. #'APRadioCount'=>'.1.3.6.1.4.1.14988.1.1.1.11.1.5',
  158. );
  159. ### open SNMP session
  160. eval {
  161. ($snmp_session, $error) = Net::SNMP->session(
  162. -hostname => $host,
  163. -community => $community,
  164. -nonblocking => 1,
  165. -translate => [-octetstring => 0],
  166. -version => 'snmpv2c',
  167. );
  168. };
  169. return "CapsMan is not available<BR>" if (!defined($snmp_session));
  170. $snmp_session->translate([-timeticks]);
  171. my %defaultTable;
  172. my $ret = $snmp_session->get_bulk_request(
  173. -varbindlist => [ '.1.3.6.1.2.1.1' ],
  174. -callback => [ \&table_callback, '.1.3.6.1.2.1.1', \%defaultTable ],
  175. -maxrepetitions => 10,
  176. );
  177. if (!defined $ret) {
  178. $snmp_session->close();
  179. return "CapsMan not answer!<BR>";
  180. }
  181. # Now initiate the SNMP message exchange.
  182. snmp_dispatcher();
  183. my %CapsManTable;
  184. foreach my $key (keys %MikrotikCapsManMibs) {
  185. my $Mikrotik_CapsMan_mib = $MikrotikCapsManMibs{$key};
  186. my %table;
  187. my $result = $snmp_session->get_bulk_request(
  188. -varbindlist => [ $Mikrotik_CapsMan_mib ],
  189. -callback => [ \&table_callback, $Mikrotik_CapsMan_mib, \%table ],
  190. -maxrepetitions => 10,
  191. );
  192. if (!defined $result) {
  193. printf "ERROR: %s\n", $snmp_session->error();
  194. $snmp_session->close();
  195. exit 1;
  196. }
  197. # Now initiate the SNMP message exchange.
  198. snmp_dispatcher();
  199. $CapsManTable{$key}=\%table;
  200. }
  201. $snmp_session->close();
  202. my %interfaces;
  203. foreach my $interface_oid (keys %{$CapsManTable{InterfaceList}}) {
  204. $interfaces{extract_dec_mac($MikrotikCapsManMibs{InterfaceList},$interface_oid)}=$CapsManTable{InterfaceList}->{$interface_oid};
  205. }
  206. my $result=$defaultTable{$DefaultMibs{Name}}."\n<br>";
  207. $result.=$defaultTable{$DefaultMibs{Description}}."\n<br>";
  208. my $uptime = int($defaultTable{$DefaultMibs{Uptime}}/100);
  209. my $day; my $hour; my $min;
  210. $day = int($uptime/86400);
  211. $hour = int(($uptime - 86400*$day)/3600);
  212. $min = int (($uptime - 86400*$day - 3600*$hour)/60);
  213. my $s_uptime = "$day days $hour:$min";
  214. $result.= "$s_uptime\n<br>\n";
  215. my %client_status;
  216. my $key = 'ClientMac';
  217. for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
  218. my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
  219. my $dec_mac = get_first_dec($dec_oid);
  220. my $int_id = get_last_dec($dec_oid);
  221. $client_status{$dec_mac}->{mac}=dec2mac($dec_mac);
  222. $client_status{$dec_mac}->{int_id}=$int_id;
  223. $client_status{$dec_mac}->{int_name}=$interfaces{$int_id};
  224. }
  225. $key = 'ClientTxRate';
  226. for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
  227. my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
  228. my $dec_mac = get_first_dec($dec_oid);
  229. my $rate = $CapsManTable{$key}->{$oid};
  230. $client_status{$dec_mac}->{txrate}=$rate/1000000;
  231. }
  232. $key = 'ClientRxRate';
  233. for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
  234. my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
  235. my $dec_mac = get_first_dec($dec_oid);
  236. my $rate = $CapsManTable{$key}->{$oid};
  237. $client_status{$dec_mac}->{rxrate}=$rate/1000000;
  238. }
  239. $key = 'ClientTx';
  240. for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
  241. my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
  242. my $dec_mac = get_first_dec($dec_oid);
  243. my $rate = $CapsManTable{$key}->{$oid};
  244. $client_status{$dec_mac}->{tx}=$rate;
  245. }
  246. $key = 'ClientRx';
  247. for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
  248. my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
  249. my $dec_mac = get_first_dec($dec_oid);
  250. my $rate = $CapsManTable{$key}->{$oid};
  251. $client_status{$dec_mac}->{rx}=$rate;
  252. }
  253. $key = 'ClientSSID';
  254. for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
  255. my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
  256. my $dec_mac = get_first_dec($dec_oid);
  257. my $ssid = $CapsManTable{$key}->{$oid};
  258. $client_status{$dec_mac}->{SSID}=$ssid;
  259. }
  260. $key = 'ClientUptime';
  261. for my $oid (oid_lex_sort(keys %{$CapsManTable{$key}})) {
  262. my $dec_oid = extract_dec_mac($MikrotikCapsManMibs{$key},$oid);
  263. my $dec_mac = get_first_dec($dec_oid);
  264. my $uptime = $CapsManTable{$key}->{$oid};
  265. my $day; my $hour; my $min;
  266. $day = int($uptime/86400);
  267. $hour = int(($uptime - 86400*$day)/3600);
  268. $min = int (($uptime - 86400*$day - 3600*$hour)/60);
  269. my $s_uptime = "$day days $hour:$min";
  270. $client_status{$dec_mac}->{uptime}=$s_uptime;
  271. }
  272. my %CapsMan_status;
  273. my $all_clients=0;
  274. foreach my $dec_mac (sort keys %client_status) {
  275. my $ssid = $client_status{$dec_mac}->{SSID};
  276. if (!exists($CapsMan_status{$ssid})) { $CapsMan_status{$ssid}{count}=0; }
  277. $CapsMan_status{$ssid}{count}++;
  278. $all_clients++;
  279. }
  280. $result.="\n<br>Wireless counters:\n<br>\n";
  281. $result.="| *SSID* | *Count* |\n";
  282. foreach my $ssid (sort keys %CapsMan_status) {
  283. $result.= "| $ssid | $CapsMan_status{$ssid}{count} |\n";
  284. }
  285. $result.= "\n<br>Total: $all_clients\n<br>\n";
  286. $result.= "| *Interface* | *SSID* | *Client* | *Rx/Tx* | *Bitr* | *Uptime* |\n";
  287. $result.=expand_status(\%client_status);
  288. return $result;
  289. }
  290. 1;