api.ipaclmgr.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. <?php
  2. /**
  3. * IP/Networks ACL management
  4. */
  5. class IpACLMgr {
  6. /**
  7. * Contais all existing IP ACLs as ip=>notes
  8. *
  9. * @var array
  10. */
  11. protected $allowedIps = array();
  12. /**
  13. * Contais all existing nets ACLs as network network=>notes
  14. *
  15. * @var array
  16. */
  17. protected $allowedNets = array();
  18. /**
  19. * Contains current administrator IP address
  20. *
  21. * @var string
  22. */
  23. protected $myIp = '';
  24. /**
  25. * System message helper placeholder
  26. *
  27. * @var object
  28. */
  29. protected $messages = '';
  30. /**
  31. * Some predefined URLs, routes, etc...
  32. */
  33. const URL_ME = '?module=ipaclmgr';
  34. const ROUTE_DELIPACL = 'deleteipacl';
  35. const ROUTE_DELNETACL = 'deletenetwacl';
  36. const PROUTE_NEWIPACLIP = 'newipacl';
  37. const PROUTE_NEWIPACLNOTE = 'newipaclnote';
  38. const PROUTE_EDIPACLIP = 'editipacl';
  39. const PROUTE_EDIPACLNOTE = 'editipaclnote';
  40. const PROUTE_NEWNETACLNET = 'newnetaclsubnet';
  41. const PROUTE_NEWNETACLNOTE = 'newnetaclnote';
  42. const PROUTE_EDNETACLNET = 'editnetaclsubnet';
  43. const PROUTE_EDNETACLNOTE = 'editnetaclnote';
  44. const COLOR_ALERT = 'f40000';
  45. const COLOR_HERE = '007b09';
  46. /**
  47. * Creates new IP ACL manager instance
  48. *
  49. * @return void
  50. */
  51. public function __construct() {
  52. $this->initMessages();
  53. $this->setMyIp();
  54. $this->loadAclIps();
  55. $this->loadAclNets();
  56. }
  57. /**
  58. * Sets current administrator IP address
  59. *
  60. * @return void
  61. */
  62. protected function setMyIp() {
  63. $this->myIp = $_SERVER['REMOTE_ADDR'];
  64. }
  65. /**
  66. * Inits system messages helper
  67. *
  68. * @return void
  69. */
  70. protected function initMessages() {
  71. $this->messages = new UbillingMessageHelper();
  72. }
  73. /**
  74. * Loads all existing IP ACLs into protected property
  75. *
  76. * @return void
  77. */
  78. protected function loadAclIps() {
  79. $tmp = rcms_scandir(IPACLALLOWIP_PATH);
  80. if (!empty($tmp)) {
  81. foreach ($tmp as $io => $eachIp) {
  82. $this->allowedIps[$eachIp] = file_get_contents(IPACLALLOWIP_PATH . $eachIp);
  83. }
  84. }
  85. }
  86. /**
  87. * Loads all existing networks ACLs into protected property
  88. *
  89. * @return void
  90. */
  91. protected function loadAclNets() {
  92. $tmp = rcms_scandir(IPACLALLOWNETS_PATH);
  93. if (!empty($tmp)) {
  94. foreach ($tmp as $io => $eachNet) {
  95. $eachNetCidr = str_replace('_', '/', $eachNet);
  96. $this->allowedNets[$eachNetCidr] = file_get_contents(IPACLALLOWNETS_PATH . $eachNet);
  97. }
  98. }
  99. }
  100. /**
  101. * Renders module controls panel
  102. *
  103. * @return string
  104. */
  105. public function renderControls() {
  106. global $ubillingConfig;
  107. $billCfg = $ubillingConfig->getBilling();
  108. $result = '';
  109. $result .= wf_BackLink('?module=sysconf') . ' ';
  110. $result .= wf_modalAuto(wf_img('skins/icon_ip.png') . ' ' . __('Allow access form some IP'), __('Allow access form some IP'), $this->renderIpAclCreateForm(), 'ubButton');
  111. $result .= wf_modalAuto(wf_img('skins/icon_net.png') . ' ' . __('Allow access form some subnet'), __('Allow access form some subnet'), $this->renderNetAclCreateForm(), 'ubButton');
  112. $result .= wf_modalAuto(wf_img('skins/question.png') . ' ' . __('Who am i') . '?', __('Who am i') . '?', $this->renderMyCurrentIp(), 'ubButton');
  113. if (!@$billCfg['IPACL_ENABLED']) {
  114. $result .= $this->messages->getStyledMessage(__('IP Access restrictions is disabled now'), 'warning');
  115. }
  116. // .-"-. .-"-. .-"-. .-"-.
  117. // _/_-.-_\_ _/.-.-.\_ _/.-.-.\_ _/.-.-.\_
  118. // / __} {__ \ /|( o o )|\ ( ( o o ) ) ( ( o o ) )
  119. // / // " \\ \ | // " \\ | |/ " \| |/ " \|
  120. // / / \'---'/ \ \ / / \'---'/ \ \ \'/^\'/ \ .-. /
  121. // \ \_/`"""`\_/ / \ \_/`"""`\_/ / /`\ /`\ /`"""`\
  122. // \ / \ / / /|\ \ / \
  123. return($result);
  124. }
  125. /**
  126. * Paints some text into some color
  127. *
  128. * @param string $text
  129. * @param string $color
  130. *
  131. * @return string
  132. */
  133. protected function colorize($text, $color = '') {
  134. $result = '';
  135. if (!empty($color)) {
  136. $result .= wf_tag('font', false, '', 'style="color:#' . $color . ';"');
  137. $result .= $text;
  138. $result .= wf_tag('font', true);
  139. } else {
  140. $result .= $text;
  141. }
  142. return($result);
  143. }
  144. /**
  145. * Returns list of available IP ACLs with some controls
  146. *
  147. * @return string
  148. */
  149. public function renderIpAclsList() {
  150. $result = '';
  151. if (!empty($this->allowedIps)) {
  152. $cells = wf_TableCell(__('IP'), '20%');
  153. $cells .= wf_TableCell(__('Notes'));
  154. $cells .= wf_TableCell(__('Actions'));
  155. $rows = wf_TableRow($cells, 'row1');
  156. foreach ($this->allowedIps as $eachIp => $eachNote) {
  157. $specialNotes = '';
  158. $deleteNote = '';
  159. if ($eachIp == $this->myIp) {
  160. $specialNotes .= ' ' . $this->colorize(__('This is you'), self::COLOR_HERE);
  161. $deleteNote .= $this->colorize(__('Think twice. This may block access for you') . '!', self::COLOR_ALERT);
  162. $deleteNote .= wf_delimiter(0);
  163. }
  164. $deleteNote .= $this->messages->getDeleteAlert();
  165. $cells = wf_TableCell($eachIp, '', '', 'sorttable_customkey="' . ip2int($eachIp) . '"');
  166. $cells .= wf_TableCell($eachNote . $specialNotes);
  167. $deleteUrl = self::URL_ME . '&' . self::ROUTE_DELIPACL . '=' . $eachIp;
  168. $actLinks = wf_ConfirmDialog($deleteUrl, web_delete_icon(), $deleteNote, '', self::URL_ME, __('Delete') . ' ' . $eachIp . '?') . ' ';
  169. $actLinks .= wf_modalAuto(web_edit_icon(), __('Edit') . ' ' . $eachIp, $this->renderIpAclEditForm($eachIp));
  170. $cells .= wf_TableCell($actLinks);
  171. $rows .= wf_TableRow($cells, 'row5');
  172. }
  173. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  174. } else {
  175. if (empty($this->allowedIps) AND empty($this->allowedNets)) {
  176. $result = $this->messages->getStyledMessage(__('Access is allowed from anywhere'), 'success');
  177. } else {
  178. $result = $this->messages->getStyledMessage(__('Nothing to show'), 'info');
  179. }
  180. }
  181. return($result);
  182. }
  183. /**
  184. * Renders IP ACL creation form
  185. *
  186. * @return string
  187. */
  188. protected function renderIpAclCreateForm() {
  189. $result = '';
  190. $ipPreset = '';
  191. $notesPreset = '';
  192. $formLabel = '';
  193. if (empty($this->allowedIps) AND empty($this->allowedNets)) {
  194. $ipPreset = $this->myIp;
  195. $notesPreset = whoami();
  196. $formLabel = __('Allow yourself access first, then access from all other addresses will be restricted');
  197. }
  198. $inputs = wf_TextInput(self::PROUTE_NEWIPACLIP, __('IP'), $ipPreset, false, 20, 'ip') . ' ';
  199. $inputs .= wf_TextInput(self::PROUTE_NEWIPACLNOTE, __('Notes'), $notesPreset, false, 30) . ' ';
  200. $inputs .= wf_Submit(__('Create'));
  201. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  202. $result .= $formLabel;
  203. return($result);
  204. }
  205. /**
  206. * Renders IP ACL notes edit form
  207. *
  208. * @param string $ip
  209. *
  210. * @return string
  211. */
  212. protected function renderIpAclEditForm($ip) {
  213. $result = '';
  214. if (!empty($ip)) {
  215. if (isset($this->allowedIps[$ip])) {
  216. $inputs = wf_HiddenInput(self::PROUTE_EDIPACLIP, $ip);
  217. $inputs .= wf_TextInput(self::PROUTE_EDIPACLNOTE, __('Notes'), $this->allowedIps[$ip], false, 30) . ' ';
  218. $inputs .= wf_Submit(__('Save'));
  219. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  220. } else {
  221. $result = $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('IP') . ' ' . __('Unknown'), 'error');
  222. }
  223. } else {
  224. $result = $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('IP') . ' ' . __('is empty'), 'error');
  225. }
  226. return($result);
  227. }
  228. /**
  229. * Creates new IP ACL
  230. *
  231. * @param string $ip
  232. * @param string $notes
  233. *
  234. * @return void/string on error
  235. */
  236. public function createIpAcl($ip, $notes = '') {
  237. $result = '';
  238. $ip = trim($ip);
  239. if (!empty($ip)) {
  240. if (zb_isIPValid($ip)) {
  241. if (!isset($this->allowedIps[$ip])) {
  242. if ($ip != '127.0.0.1') {
  243. file_put_contents(IPACLALLOWIP_PATH . $ip, $notes);
  244. log_register('IPACL CREATE IP `' . $ip . '`');
  245. } else {
  246. $result .= __('Access from localhost is always enabled by default');
  247. log_register('IPACL CREATE FAIL IP `' . $ip . '` LOCALHOST');
  248. }
  249. } else {
  250. $result .= __('This IP is already allowed') . ': ' . $ip;
  251. log_register('IPACL CREATE FAIL IP `' . $ip . '` DUPLICATE');
  252. }
  253. } else {
  254. $result = __('IP') . ' ' . __('wrong');
  255. log_register('IPACL CREATE FAIL IP `' . $ip . '` WRONG_FORMAT');
  256. }
  257. } else {
  258. $result = __('IP') . ' ' . __('is empty');
  259. log_register('IPACL CREATE FAIL IP EMPTY');
  260. }
  261. return($result);
  262. }
  263. /**
  264. * Edits new IP ACL notes
  265. *
  266. * @param string $ip
  267. * @param string $notes
  268. *
  269. * @return void/string on error
  270. */
  271. public function saveIpAcl($ip, $notes = '') {
  272. $result = '';
  273. $ip = trim($ip);
  274. if (!empty($ip)) {
  275. if (zb_isIPValid($ip)) {
  276. if (isset($this->allowedIps[$ip])) {
  277. file_put_contents(IPACLALLOWIP_PATH . $ip, $notes);
  278. log_register('IPACL EDIT IP `' . $ip . '`');
  279. } else {
  280. $result .= __('IP') . ' ' . __('Unknown') . ': ' . $ip;
  281. log_register('IPACL EDIT FAIL IP `' . $ip . '` NOT_EXISTS');
  282. }
  283. } else {
  284. $result = __('IP') . ' ' . __('wrong');
  285. log_register('IPACL EDIT FAIL IP `' . $ip . '` WRONG_FORMAT');
  286. }
  287. } else {
  288. $result = __('IP') . ' ' . __('is empty');
  289. log_register('IPACL EDIT FAIL IP EMPTY');
  290. }
  291. return($result);
  292. }
  293. /**
  294. * Deletes existing IP ACL
  295. *
  296. * @param string $ip
  297. *
  298. * @return void/string on error
  299. */
  300. public function deleteIpAcl($ip) {
  301. $result = '';
  302. if (!empty($ip)) {
  303. if (isset($this->allowedIps[$ip])) {
  304. unlink(IPACLALLOWIP_PATH . $ip);
  305. log_register('IPACL DELETE IP `' . $ip . '`');
  306. } else {
  307. $result = __('IP') . ' ' . __('Unknown');
  308. log_register('IPACL DELETE FAIL IP `' . $ip . '` UNKNOWN');
  309. }
  310. } else {
  311. $result = __('IP') . ' ' . __('is empty');
  312. log_register('IPACL DELETE FAIL IP EMPTY');
  313. }
  314. return($result);
  315. }
  316. /**
  317. * Returns list of available networks ACLs with some controls
  318. *
  319. * @return string
  320. */
  321. public function renderNetAclsList() {
  322. $result = '';
  323. if (!empty($this->allowedNets)) {
  324. $cells = wf_TableCell(__('Network') . '/' . __('CIDR'), '20%');
  325. $cells .= wf_TableCell(__('First IP') . ' - ' . __('Last IP'));
  326. $cells .= wf_TableCell(__('Notes'));
  327. $cells .= wf_TableCell(__('Actions'));
  328. $rows = wf_TableRow($cells, 'row1');
  329. foreach ($this->allowedNets as $eachNetwork => $eachNote) {
  330. $eachNetId = str_replace('/', '_', $eachNetwork);
  331. $specialNotes = '';
  332. $deleteNote = '';
  333. $networkParams = ipcidrToStartEndIP($eachNetwork);
  334. if (multinet_checkIP($this->myIp, $networkParams['startip'], $networkParams['endip'])) {
  335. $specialNotes .= ' ' . $this->colorize(__('You are here'), self::COLOR_HERE);
  336. $deleteNote .= $this->colorize(__('Think twice. This may block access for you') . '!', self::COLOR_ALERT);
  337. $deleteNote .= wf_delimiter(0);
  338. }
  339. $deleteNote .= $this->messages->getDeleteAlert();
  340. $cells = wf_TableCell($eachNetwork);
  341. $cells .= wf_TableCell($networkParams['startip'] . ' - ' . $networkParams['endip']);
  342. $cells .= wf_TableCell($eachNote . $specialNotes);
  343. $deleteUrl = self::URL_ME . '&' . self::ROUTE_DELNETACL . '=' . $eachNetId;
  344. $dialogTitle = __('Delete') . ' ' . $eachNetwork . '?';
  345. $actLinks = wf_ConfirmDialog($deleteUrl, web_delete_icon(), $deleteNote, '', self::URL_ME, $dialogTitle) . ' ';
  346. $actLinks .= wf_modalAuto(web_edit_icon(), __('Edit') . ' ' . $eachNetwork, $this->renderNetAclEditForm($eachNetwork));
  347. $cells .= wf_TableCell($actLinks);
  348. $rows .= wf_TableRow($cells, 'row5');
  349. }
  350. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  351. } else {
  352. if (empty($this->allowedIps) AND empty($this->allowedNets)) {
  353. $result = $this->messages->getStyledMessage(__('Access is allowed from anywhere'), 'success');
  354. } else {
  355. $result = $this->messages->getStyledMessage(__('Nothing to show'), 'info');
  356. }
  357. }
  358. return($result);
  359. }
  360. /**
  361. * Renders network ACL creation form
  362. *
  363. * @return string
  364. */
  365. protected function renderNetAclCreateForm() {
  366. $result = '';
  367. $inputs = wf_TextInput(self::PROUTE_NEWNETACLNET, __('Network') . '/' . __('CIDR'), '', false, 20, 'net-cidr') . ' ';
  368. $inputs .= wf_TextInput(self::PROUTE_NEWNETACLNOTE, __('Notes'), '', false, 30) . ' ';
  369. $inputs .= wf_Submit(__('Create'));
  370. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  371. return($result);
  372. }
  373. /**
  374. * Renders network ACL notes edit form
  375. *
  376. * @param string $netcidr
  377. *
  378. * @return string
  379. */
  380. protected function renderNetAclEditForm($netcidr) {
  381. $result = '';
  382. if (!empty($netcidr)) {
  383. if (isset($this->allowedNets[$netcidr])) {
  384. $inputs = wf_HiddenInput(self::PROUTE_EDNETACLNET, $netcidr);
  385. $inputs .= wf_TextInput(self::PROUTE_EDNETACLNOTE, __('Notes'), $this->allowedNets[$netcidr], false, 30) . ' ';
  386. $inputs .= wf_Submit(__('Save'));
  387. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  388. } else {
  389. $result = $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('Network') . ' ' . __('Unknown'), 'error');
  390. }
  391. } else {
  392. $result = $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('Network') . ' ' . __('is empty'), 'error');
  393. }
  394. return($result);
  395. }
  396. /**
  397. * Creates new network ACL
  398. *
  399. * @param string $netcidr
  400. * @param string $notes
  401. *
  402. * @return void/string on error
  403. */
  404. public function createNetAcl($netcidr, $notes = '') {
  405. $result = '';
  406. if (!empty($netcidr)) {
  407. if (!isset($this->allowedNets[$netcidr])) {
  408. $netId = str_replace('/', '_', $netcidr);
  409. file_put_contents(IPACLALLOWNETS_PATH . $netId, $notes);
  410. log_register('IPACL CREATE NET `' . $netcidr . '`');
  411. } else {
  412. $result .= __('This network is already allowed') . ': ' . $netcidr;
  413. log_register('IPACL CREATE FAIL NET `' . $netcidr . '` DUPLICATE');
  414. }
  415. } else {
  416. $result = __('Network') . ' ' . __('is empty');
  417. log_register('IPACL CREATE FAIL NET EMPTY');
  418. }
  419. return($result);
  420. }
  421. /**
  422. * Edits network ACL notes
  423. *
  424. * @param string $netcidr
  425. * @param string $notes
  426. *
  427. * @return void/string on error
  428. */
  429. public function saveNetAcl($netcidr, $notes = '') {
  430. $result = '';
  431. if (!empty($netcidr)) {
  432. if (isset($this->allowedNets[$netcidr])) {
  433. $netId = str_replace('/', '_', $netcidr);
  434. file_put_contents(IPACLALLOWNETS_PATH . $netId, $notes);
  435. log_register('IPACL EDIT NET `' . $netcidr . '`');
  436. } else {
  437. $result .= __('Network') . ' ' . __('Unknown') . ': ' . $netcidr;
  438. log_register('IPACL EDIT FAIL NET `' . $netcidr . '` NOT_EXISTS');
  439. }
  440. } else {
  441. $result = __('Network') . ' ' . __('is empty');
  442. log_register('IPACL EDIT FAIL NET EMPTY');
  443. }
  444. return($result);
  445. }
  446. /**
  447. * Deletes existing network ACL
  448. *
  449. * @param string $net
  450. *
  451. * @return void/string on error
  452. */
  453. public function deleteNetAcl($netId) {
  454. $result = '';
  455. if (!empty($netId)) {
  456. $netCidr = str_replace('_', '/', $netId);
  457. if (isset($this->allowedNets[$netCidr])) {
  458. unlink(IPACLALLOWNETS_PATH . $netId);
  459. log_register('IPACL DELETE NET `' . $netCidr . '`');
  460. } else {
  461. $result = __('Network') . ' ' . $netCidr . ' ' . __('Unknown');
  462. log_register('IPACL DELETE FAIL NET `' . $netCidr . '` UNKNOWN');
  463. }
  464. } else {
  465. $result = __('Network') . ' ' . __('is empty');
  466. log_register('IPACL DELETE FAIL NET EMPTY');
  467. }
  468. return($result);
  469. }
  470. /**
  471. * Returns current adminitstator IP address
  472. *
  473. * @return string
  474. */
  475. protected function renderMyCurrentIp() {
  476. $result = '';
  477. $result .= wf_tag('div', false, '', 'style="width:400px;"');
  478. $result .= $this->messages->getStyledMessage(__('Your IP address now is') . ': ' . $this->myIp, 'info');
  479. $result .= wf_tag('div', true);
  480. return($result);
  481. }
  482. }