api.policedog.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. <?php
  2. /**
  3. * Allows control apper of some MAC address in billing reality
  4. */
  5. class PoliceDog {
  6. /**
  7. * Contains system alter.ini config as key=>value
  8. *
  9. * @var array
  10. */
  11. protected $altCfg = array();
  12. /**
  13. * Contains system billing.ini config as key=>value
  14. *
  15. * @var array
  16. */
  17. protected $billCfg = array();
  18. /**
  19. * Contains all available MAC data as id=>macdata
  20. *
  21. * @var array
  22. */
  23. protected $macData = array();
  24. /**
  25. * Contains all MAC-s to search as mac=>id
  26. *
  27. * @var array
  28. */
  29. protected $allMacs = array();
  30. /**
  31. * Contains actual wanted MAC alerts as id=>data
  32. *
  33. * @var array
  34. */
  35. protected $alerts = array();
  36. /**
  37. * System message helper object placeholder
  38. *
  39. * @var object
  40. */
  41. protected $messages = '';
  42. /**
  43. * Contains MACs already assigned for users as login=>MAC
  44. *
  45. * @var array
  46. */
  47. protected $usersMacs = array();
  48. const URL_ME = '?module=policedog';
  49. /**
  50. * Creates new PoliceDog instance
  51. */
  52. public function __construct() {
  53. $this->loadConfig();
  54. $this->loadMacData();
  55. $this->loadUsersMacs();
  56. $this->loadAlerts();
  57. $this->initMessages();
  58. }
  59. /**
  60. * Loads system alter config for further usage
  61. *
  62. * @global object $ubillingConfig
  63. *
  64. * @return void
  65. */
  66. protected function loadConfig() {
  67. global $ubillingConfig;
  68. $this->altCfg = $ubillingConfig->getAlter();
  69. $this->billCfg = $ubillingConfig->getBilling();
  70. }
  71. /**
  72. * Inits system message helper object
  73. *
  74. * @return void
  75. */
  76. protected function initMessages() {
  77. $this->messages = new UbillingMessageHelper();
  78. }
  79. /**
  80. * Loads current MAC-s data into protected property
  81. *
  82. * @return void
  83. */
  84. protected function loadMacData() {
  85. $query = "SELECT * from `policedog`";
  86. $all = simple_queryall($query);
  87. if (!empty($all)) {
  88. foreach ($all as $io => $each) {
  89. $this->macData[$each['id']] = $each;
  90. $this->allMacs[$each['mac']] = $each['id'];
  91. }
  92. }
  93. }
  94. /**
  95. * Loads available police dog alerts
  96. *
  97. * @return void
  98. */
  99. protected function loadAlerts() {
  100. $query = "SELECT * from `policedogalerts`";
  101. $all = simple_queryall($query);
  102. if (!empty($all)) {
  103. foreach ($all as $io => $each) {
  104. $this->alerts[$each['id']] = $each;
  105. }
  106. }
  107. }
  108. /**
  109. * Loads available users macs into database
  110. *
  111. * @rerutn void
  112. */
  113. protected function loadUsersMacs() {
  114. $all = zb_UserGetAllMACs();
  115. if (!empty($all)) {
  116. $this->usersMacs = array_flip($all);
  117. }
  118. }
  119. /**
  120. * Renders module control panel
  121. *
  122. * @return string
  123. */
  124. public function panel() {
  125. $result = '';
  126. $result.= wf_modalAuto(web_icon_create() . ' ' . __('Upload new MACs'), __('Upload new MACs'), $this->renderUploadForm(), 'ubButton');
  127. $result.= wf_Link(self::URL_ME, wf_img('skins/undone_icon.png') . ' ' . __('Wanted MAC database'), false, 'ubButton');
  128. $result.= wf_Link(self::URL_ME . '&show=fastscan', wf_img('skins/icon_search_small.gif') . ' ' . __('Fast scan'), false, 'ubButton');
  129. $result.= wf_Link(self::URL_ME . '&show=deepscan', wf_img('skins/track_icon.png') . ' ' . __('Deep scan'), false, 'ubButton');
  130. return ($result);
  131. }
  132. /**
  133. * Renders MAC uploading form
  134. *
  135. * @return string
  136. */
  137. protected function renderUploadForm() {
  138. $result = '';
  139. $inputs = __('One MAC address per line') . wf_tag('br');
  140. $inputs.= wf_TextArea('newmacupload', '', '', true, '50x10');
  141. $inputs.= wf_TextInput('newnotes', __('Notes'), '', true, '40');
  142. $inputs.= wf_Submit(__('Upload'));
  143. $result.= wf_Form('', 'POST', $inputs, 'glamour');
  144. return ($result);
  145. }
  146. /**
  147. * Renders wanted MAC addresses database
  148. *
  149. * @return string
  150. */
  151. public function renderWandedMacList() {
  152. $result = '';
  153. $columns = array(__('ID'), __('Date'), __('MAC'), __('Notes'), __('Actions'));
  154. $opts = '"order": [[ 0, "desc" ]]';
  155. $result.= wf_JqDtLoader($columns, self::URL_ME . '&show=ajwlist', false, __('MAC'), 50, $opts);
  156. return ($result);
  157. }
  158. /**
  159. * Deletes some MAC from database
  160. *
  161. * @param int $id
  162. *
  163. * @return void
  164. */
  165. public function deleteWantedMac($id) {
  166. $id = vf($id, 3);
  167. if (isset($this->macData[$id])) {
  168. $deleteMac = $this->macData[$id]['mac'];
  169. $query = "DELETE from `policedog` WHERE `id`='" . $id . "';";
  170. nr_query($query);
  171. log_register('POLICEDOG DELETE MAC `' . $deleteMac . '`');
  172. }
  173. }
  174. /**
  175. * Renders ajax data reply with available MAC data list
  176. *
  177. * @return void
  178. */
  179. public function renderWantedMacListAjaxReply() {
  180. $result = '';
  181. $jsonAAData = array();
  182. if (!empty($this->macData)) {
  183. foreach ($this->macData as $io => $each) {
  184. $jsonItem = array();
  185. $jsonItem[] = $each['id'];
  186. $jsonItem[] = $each['date'];
  187. $jsonItem[] = $each['mac'];
  188. $jsonItem[] = $each['notes'];
  189. $actLinks = wf_JSAlert(self::URL_ME . '&delmacid=' . $each['id'], web_delete_icon(), $this->messages->getDeleteAlert());
  190. $jsonItem[] = $actLinks;
  191. $jsonAAData[] = $jsonItem;
  192. }
  193. }
  194. $result = array("aaData" => $jsonAAData);
  195. die(json_encode($result));
  196. die($result);
  197. }
  198. /**
  199. * Creates new MAC address database records
  200. *
  201. * @return void/string
  202. */
  203. public function catchCreateMacRequest() {
  204. $result = '';
  205. $count = 0;
  206. if (wf_CheckPost(array('newmacupload'))) {
  207. if (!empty($_POST['newmacupload'])) {
  208. $macsRaw = explodeRows($_POST['newmacupload']);
  209. if (!empty($macsRaw)) {
  210. $curDate = curdatetime();
  211. if (wf_CheckPost(array('newnotes'))) {
  212. $newNotes = mysql_real_escape_string($_POST['newnotes']);
  213. } else {
  214. $newNotes = '';
  215. }
  216. foreach ($macsRaw as $io => $eachmac) {
  217. $insertMac = trim($eachmac);
  218. $insertMac = mysql_real_escape_string($insertMac);
  219. $insertMac = strtolower_utf8($insertMac);
  220. if (!empty($insertMac)) {
  221. if (check_mac_format($insertMac)) {
  222. if (!isset($this->allMacs[$insertMac])) {
  223. $query = "INSERT INTO `policedog` (`id`,`date`,`mac`,`notes`) VALUES ";
  224. $query.= "(NULL,'" . $curDate . "','" . $insertMac . "','" . $newNotes . "');";
  225. nr_query($query);
  226. $count++;
  227. } else {
  228. $result.= $this->messages->getStyledMessage(__('MAC duplicate') . ': ' . $insertMac, 'warning');
  229. }
  230. } else {
  231. $result.= $this->messages->getStyledMessage(__('This MAC have wrong format') . ': ' . $insertMac, 'error');
  232. }
  233. }
  234. }
  235. log_register('POLICEDOG UPLOAD `' . $count . '` MAC');
  236. }
  237. }
  238. }
  239. return ($result);
  240. }
  241. /**
  242. * Checks is MAC already alerted or not?
  243. *
  244. * @param string $mac
  245. *
  246. * @return bool
  247. */
  248. protected function isNotAlertedYet($mac) {
  249. $result = true;
  250. if (!empty($this->alerts)) {
  251. foreach ($this->alerts as $io => $each) {
  252. if ($each['mac'] == $mac) {
  253. $result = false;
  254. break;
  255. }
  256. }
  257. }
  258. return ($result);
  259. }
  260. /**
  261. * Performs fast database scan for wanted MAC addresses
  262. *
  263. * @return void
  264. */
  265. public function fastScan() {
  266. $curDate = curdatetime();
  267. if (!empty($this->allMacs)) {
  268. foreach ($this->allMacs as $eachmac => $eachId) {
  269. if (isset($this->usersMacs[$eachmac])) {
  270. $detectedLogin = $this->usersMacs[$eachmac];
  271. if ($this->isNotAlertedYet($eachmac)) {
  272. $query = "INSERT INTO `policedogalerts` (`id`,`date`,`mac`,`login`) VALUES ";
  273. $query.= "(NULL, '" . $curDate . "', '" . $eachmac . "', '" . $detectedLogin . "');";
  274. nr_query($query);
  275. log_register('POLICEDOG MAC `' . $eachmac . '` ALERT `' . $detectedLogin . '`');
  276. }
  277. }
  278. }
  279. }
  280. }
  281. /**
  282. * Renders fast scan interface with current alerts
  283. *
  284. * @return string
  285. */
  286. public function renderFastScan() {
  287. $result = '';
  288. $result.=wf_Link(self::URL_ME . '&show=fastscan&forcefast=true', wf_img('skins/refresh.gif') . ' ' . __('Renew'), true, 'ubButton');
  289. if (!empty($this->alerts)) {
  290. $cells = wf_TableCell(__('ID'));
  291. $cells.= wf_TableCell(__('Date'));
  292. $cells.= wf_TableCell(__('MAC'));
  293. $cells.= wf_TableCell(__('Assigned'));
  294. $cells.= wf_TableCell(__('Actions'));
  295. $rows = wf_TableRow($cells, 'row1');
  296. foreach ($this->alerts as $io => $each) {
  297. $cells = wf_TableCell($each['id']);
  298. $cells.= wf_TableCell($each['date']);
  299. $cells.= wf_TableCell($each['mac']);
  300. $profileLink = wf_Link('?module=userprofile&username=' . $each['login'], web_profile_icon() . ' ' . $each['login'], false, '');
  301. $cells.= wf_TableCell($profileLink);
  302. $actLinks = wf_JSAlertStyled(self::URL_ME . '&delalertid=' . $each['id'], web_delete_icon(), $this->messages->getDeleteAlert(), '');
  303. $cells.= wf_TableCell($actLinks);
  304. $rows.= wf_TableRow($cells, 'row3');
  305. }
  306. $result.=wf_TableBody($rows, '100%', 0, 'sortable');
  307. } else {
  308. $result.= $this->messages->getStyledMessage(__('Nothing found'), 'info');
  309. }
  310. return ($result);
  311. }
  312. /**
  313. * Deletes existing alert from database
  314. *
  315. * @param int $id
  316. *
  317. * @return void
  318. */
  319. public function deleteAlert($id) {
  320. $id = vf($id, 3);
  321. if (isset($this->alerts[$id])) {
  322. $alertData = $this->alerts[$id];
  323. $query = "DELETE from `policedogalerts` WHERE `id`='" . $id . "';";
  324. nr_query($query);
  325. log_register('POLICEDOG DELETE ALERT [' . $id . '] MAC `' . $alertData['mac'] . '`');
  326. }
  327. }
  328. /**
  329. * Performs and renders deep scan results
  330. *
  331. * @return string
  332. */
  333. public function renderDeepScan() {
  334. set_time_limit(0);
  335. $result = '';
  336. if (!empty($this->allMacs)) {
  337. //nethosts scanning
  338. $nethostsAlerts = '';
  339. $nethostsAlertsTmp = array();
  340. if (!empty($this->allMacs)) {
  341. foreach ($this->allMacs as $eachmac => $eachId) {
  342. if (isset($this->usersMacs[$eachmac])) {
  343. if (!isset($nethostsAlertsTmp[$eachmac])) {
  344. $nethostsAlerts.= $this->messages->getStyledMessage(__('Wanted MAC assigned to user') . ': ' . $eachmac, 'error');
  345. $nethostsAlertsTmp[$eachmac] = $eachmac;
  346. }
  347. }
  348. }
  349. if (!empty($nethostsAlerts)) {
  350. $result.=$nethostsAlerts;
  351. } else {
  352. $result.=$this->messages->getStyledMessage(__('No wanted MAC assigned to existing users'), 'success');
  353. }
  354. }
  355. //DHCP logs parsing
  356. $cat_path = $this->billCfg['CAT'];
  357. $sudo_path = $this->billCfg['SUDO'];
  358. $tail_path = $this->billCfg['TAIL'];
  359. $leasefile = $this->altCfg['NMLEASES'];
  360. $command = $sudo_path . ' ' . $cat_path . ' ' . $leasefile . ' | ' . $tail_path . ' -n 10000';
  361. $rawDhcp = shell_exec($command);
  362. $dhcpAlerts = '';
  363. $dhcpAlertsTmp = array();
  364. if (!empty($rawDhcp)) {
  365. $rawDhcp = explodeRows($rawDhcp);
  366. if (!empty($rawDhcp)) {
  367. foreach ($rawDhcp as $eachLine) {
  368. $macExtract = zb_ExtractMacAddress($eachLine);
  369. if (!empty($macExtract)) {
  370. if (isset($this->allMacs[$macExtract])) {
  371. if (!isset($dhcpAlertsTmp[$macExtract])) {
  372. $dhcpAlerts.=$this->messages->getStyledMessage(__('DHCP request from') . ': ' . $macExtract, 'error');
  373. $dhcpAlertsTmp[$macExtract] = $macExtract;
  374. }
  375. }
  376. }
  377. }
  378. }
  379. if (!empty($dhcpAlerts)) {
  380. $result.=$dhcpAlerts;
  381. } else {
  382. $result.=$this->messages->getStyledMessage(__('No wanted MAC DHCP requests detected'), 'success');
  383. }
  384. }
  385. //FDB cache processing
  386. $fdbCachePath = 'exports/';
  387. $fdbAlerts = '';
  388. $fdbMacTmp = array();
  389. $fdbAlertsTmp = array();
  390. $allFdb = rcms_scandir($fdbCachePath, '*_fdb');
  391. if (!empty($allFdb)) {
  392. foreach ($allFdb as $io => $eachFdbFile) {
  393. $fdbData = file_get_contents($fdbCachePath . $eachFdbFile);
  394. $fdbData = unserialize($fdbData);
  395. if (!empty($fdbData)) {
  396. foreach ($fdbData as $fdbmac => $port) {
  397. $fdbMacTmp[$fdbmac] = $fdbmac;
  398. }
  399. }
  400. }
  401. if (!empty($fdbMacTmp)) {
  402. foreach ($fdbMacTmp as $io => $eachFdbMac) {
  403. if (isset($this->allMacs[$eachFdbMac])) {
  404. if (!isset($fdbAlertsTmp[$eachFdbMac])) {
  405. $fdbAlerts.=$this->messages->getStyledMessage(__('Wanted MAC occurs in FDB') . ': ' . $eachFdbMac, 'error');
  406. $fdbAlersTmp[$eachFdbMac] = $eachFdbMac;
  407. }
  408. }
  409. }
  410. }
  411. }
  412. if (!empty($fdbAlerts)) {
  413. $result.= $fdbAlerts;
  414. } else {
  415. $result.= $this->messages->getStyledMessage(__('No wanted MAC in FDB cache detected'), 'success');
  416. }
  417. //weblogs assigns parsing
  418. $logAlerts = '';
  419. $logAlertsTmp = array();
  420. $weblogs_q = "SELECT `event` from `weblogs` WHERE `event` NOT LIKE '%POLICEDOG%' AND `event` LIKE '%MAC%'";
  421. $weblogsRaw = simple_queryall($weblogs_q);
  422. if (!empty($weblogsRaw)) {
  423. foreach ($weblogsRaw as $io => $eachEvent) {
  424. $macExtract = zb_ExtractMacAddress($eachEvent['event']);
  425. if (!empty($macExtract)) {
  426. if (isset($this->allMacs[$macExtract])) {
  427. if (!isset($logAlertsTmp[$macExtract])) {
  428. $logAlerts.= $this->messages->getStyledMessage(__('Wanted MAC occurs in event logs') . ': ' . $macExtract, 'error');
  429. $logAlertsTmp[$macExtract] = $macExtract;
  430. }
  431. }
  432. }
  433. }
  434. }
  435. if (!empty($logAlerts)) {
  436. $result.=$logAlerts;
  437. } else {
  438. $result.= $this->messages->getStyledMessage(__('No wanted MAC in event logs detected'), 'success');
  439. }
  440. //PON devices processing
  441. if ($this->altCfg['PON_ENABLED']) {
  442. $ponAlerts = '';
  443. $ponAlertsTmp = array();
  444. $pon_q = "SELECT `mac` from `pononu`";
  445. $ponRaw = simple_queryall($pon_q);
  446. if (!empty($pon_q)) {
  447. foreach ($ponRaw as $io => $eachPonMac) {
  448. $eachPonMac = $eachPonMac['mac'];
  449. if (isset($this->allMacs[$eachPonMac])) {
  450. if (!isset($ponAlertsTmp[$eachPonMac])) {
  451. $ponAlerts.= $this->messages->getStyledMessage(__('Wanted MAC occurs in PON ONU devices') . ': ' . $eachPonMac, 'error');
  452. $ponAlertsTmp[$eachPonMac] = $eachPonMac;
  453. }
  454. }
  455. }
  456. }
  457. if (!empty($ponAlerts)) {
  458. $result.= $ponAlerts;
  459. } else {
  460. $result.= $this->messages->getStyledMessage(__('No wanted MAC in PON ONU devices detected'), 'success');
  461. }
  462. }
  463. } else {
  464. $result.= $this->messages->getStyledMessage(__('Wanted MAC database') . ': ' . __('No'), 'warning');
  465. }
  466. return ($result);
  467. }
  468. }
  469. ?>