api.1984tech.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119
  1. <?php
  2. class OrwellWorld {
  3. /**
  4. * Contains 1984tech.conf as key=>value
  5. *
  6. * @var array
  7. */
  8. protected $config = array();
  9. /**
  10. * Full filesystem path to 1984tech directory
  11. *
  12. * @var string
  13. */
  14. protected $basePath = '';
  15. /**
  16. * Contains name of file with domains list
  17. *
  18. * @var string
  19. */
  20. protected $domainsFile = '';
  21. /**
  22. * Contains domains list as index=>domain
  23. *
  24. * @var array
  25. */
  26. protected $domainsList = array();
  27. /**
  28. * Contains ACLs list for bind zones config
  29. *
  30. * @var string
  31. */
  32. protected $dnsAcl = '';
  33. /**
  34. * Contains path for generating DNS zones file
  35. *
  36. * @var string
  37. */
  38. protected $dnsZonesPath = '';
  39. /**
  40. * Contains bind server zone file with domain redirects
  41. *
  42. * @var string
  43. */
  44. protected $dnsRedirectsPath = '';
  45. /**
  46. * Contains DNS servers IPs
  47. *
  48. * @var array
  49. */
  50. protected $dnsServers = array();
  51. /**
  52. * DNS resolver object placeholder
  53. *
  54. * @var object
  55. */
  56. protected $resolver = '';
  57. /**
  58. * Contains ipfw table number to push IPs
  59. *
  60. * @var int
  61. */
  62. protected $ipfwTable = 0;
  63. /**
  64. * Contains ipfw binary path
  65. *
  66. * @var
  67. */
  68. protected $ipfwPath = '';
  69. /**
  70. * Contains ipfw variable name for scrips generation
  71. *
  72. * @var string
  73. */
  74. protected $ipfwMacro = '';
  75. /**
  76. * Contains ipfw script generation path
  77. *
  78. * @var string
  79. */
  80. protected $ipfwScriptPath = '';
  81. /**
  82. * Contains name of address list for Mikrotik
  83. *
  84. * @var string
  85. */
  86. protected $mtListName = '';
  87. /**
  88. * Contains path for generation of Mikrotik address-list update script
  89. *
  90. * @var string
  91. */
  92. protected $mtScriptPath = '';
  93. /**
  94. * Mikrotik static DNS default IP to point the domains to
  95. *
  96. * @var string
  97. */
  98. protected $mtDNSStaticIP = '127.0.0.1';
  99. /**
  100. * Mikrotik static DNS default TTL for added DNS records
  101. *
  102. * @var string
  103. */
  104. protected $mtDNSStaticTTL = "00:30:00";
  105. /**
  106. * Mikrotik static DNS script path
  107. *
  108. * @var string
  109. */
  110. protected $mtDNSStaticScriptPath = '';
  111. /**
  112. * Mikrotik domains list file chunks path
  113. *
  114. * @var string
  115. */
  116. protected $mtDNSStaticChunksPath = '';
  117. /**
  118. * Mikrotik domains list file chunks base name
  119. *
  120. * @var string
  121. */
  122. protected $mtDNSStaticChunksBaseName = 'mt_dnsstatic_chunk_';
  123. /**
  124. * Mikrotik domains list file chunks extension
  125. *
  126. * @var string
  127. */
  128. protected $mtDNSStaticChunksExt = '.1984t';
  129. /**
  130. * PDNSD script path
  131. *
  132. * @var string
  133. */
  134. protected $pdnsdScriptPath = '';
  135. /**
  136. * Contains path of iptables binary
  137. *
  138. * @var string
  139. */
  140. protected $iptablesPath = '';
  141. /**
  142. * Contains iptables blocking chain
  143. *
  144. * @var string
  145. */
  146. protected $iptablesChain = '';
  147. /**
  148. * Contains ipset blacklist name
  149. *
  150. * @var string
  151. */
  152. protected $ipsetListName = '';
  153. /**
  154. * Contains ipset binary path
  155. *
  156. * @var string
  157. */
  158. protected $ipsetPath = '';
  159. /**
  160. * Contains JunOS black list name
  161. *
  162. * @var string
  163. */
  164. protected $junListName = '';
  165. /**
  166. * Contains Cisco IOS access list number
  167. *
  168. * @var string
  169. */
  170. protected $cisListNum = '';
  171. /**
  172. * Contains default unbound redirection host
  173. *
  174. * @var string
  175. */
  176. protected $unboundRedirectHost = '127.0.0.1';
  177. /**
  178. * unbound zones config path
  179. *
  180. * @var string
  181. */
  182. protected $dnsUnboundZonesPath = '';
  183. /**
  184. * Squid directory path
  185. *
  186. * @var string
  187. */
  188. protected $SquidPath = '';
  189. /**
  190. * Primary configuration file path/name
  191. */
  192. const CONFIG_PATH = '1984tech.ini';
  193. /**
  194. * Creates new object instance
  195. *
  196. * @return void
  197. */
  198. public function __construct() {
  199. $this->loadConfig();
  200. $this->setOptions();
  201. $this->loadDomains();
  202. }
  203. /**
  204. * Loads 1948tech.conf for further usage
  205. *
  206. * @return void
  207. */
  208. protected function loadConfig() {
  209. $this->config = parse_ini_file(self::CONFIG_PATH);
  210. }
  211. /**
  212. * Sets options into protected props for further usage
  213. *
  214. * @return void
  215. */
  216. protected function setOptions() {
  217. $this->basePath = $this->config['BASE_PATH'];
  218. $this->domainsFile = $this->config['DOMAINS_LIST'];
  219. $this->dnsAcl = $this->config['DNS_ACL'];
  220. $this->dnsZonesPath = $this->config['DNS_ZONES'];
  221. $this->dnsUnboundZonesPath = $this->config['UNBOUND_DNS_ZONES'];
  222. $this->dnsRedirectsPath = $this->config['DNS_REDIRECTS'];
  223. $this->dnsRPZzoneName = $this->config['RPZ_ZONE_NAME'];
  224. $this->dnsRPZzoneFile = $this->config['RPZ_ZONE_FILE'];
  225. $this->ipfwPath = $this->config['IPFW_PATH'];
  226. $this->ipfwTable = $this->config['IPFW_TABLE'];
  227. $this->ipfwMacro = $this->config['IPFW_MACRO'];
  228. $this->ipfwScriptPath = $this->config['IPFW_SCRIPT_PATH'];
  229. $this->mtListName = $this->config['MT_LISTNAME'];
  230. $this->mtScriptPath = $this->config['MT_SCRIPT_PATH'];
  231. $this->mtDNSStaticIP = $this->config['MT_DNSSTATIC_IP'];
  232. $this->mtDNSStaticTTL = $this->config['MT_DNSSTATIC_TTL'];
  233. $this->mtDNSStaticScriptPath = $this->config['MT_DNSSTATIC_SCRIPT_PATH'];
  234. $this->mtDNSStaticChunksPath = $this->config['MT_DNSSTATIC_CHUNKS_PATH'];
  235. $this->pdnsdScriptPath = $this->config['PDNSD_SCRIPT_PATH'];
  236. $this->iptablesPath = $this->config['IPTABLES_PATH'];
  237. $this->iptablesChain = $this->config['IPTABLES_CHAIN'];
  238. $this->ipsetPath = $this->config['IPSET_PATH'];
  239. $this->ipsetListName = $this->config['IPSET_LISTNAME'];
  240. $this->SquidPath = $this->config['SQUID_PATH'];
  241. $this->junListName = $this->config['JUN_LISTNAME'];
  242. $this->cisListNum = $this->config['CIS_LISTNUM'];
  243. $dnsServersTmp = $this->config['DNS_RESOLVER_SERVERS'];
  244. if (isset($this->config['UNBOUND_REDIRECT_HOST'])) {
  245. if (!empty($this->config['UNBOUND_REDIRECT_HOST'])) {
  246. $this->unboundRedirectHost = $this->config['UNBOUND_REDIRECT_HOST'];
  247. }
  248. }
  249. if (!empty($dnsServersTmp)) {
  250. $dnsServersTmp = explode(',', $dnsServersTmp);
  251. if (!empty($dnsServersTmp)) {
  252. foreach ($dnsServersTmp as $index => $eachServer) {
  253. $eachServer = trim($eachServer);
  254. if (!empty($eachServer)) {
  255. $this->dnsServers[] = $eachServer;
  256. }
  257. }
  258. }
  259. }
  260. }
  261. /**
  262. * Returns domains list array from dataSource file as lineIndex=>domain
  263. *
  264. * @return array
  265. */
  266. protected function loadDomainsSource($dataSource) {
  267. $result = array();
  268. if (!empty($dataSource)) {
  269. $raw = file_get_contents($dataSource);
  270. if (!empty($raw)) {
  271. $raw = explode(PHP_EOL, $raw);
  272. if (!empty($raw)) {
  273. foreach ($raw as $line => $eachDomain) {
  274. if (!empty($eachDomain)) {
  275. $result[$line] = trim($eachDomain);
  276. }
  277. }
  278. }
  279. }
  280. }
  281. return ($result);
  282. }
  283. /**
  284. * Loads domains from domains list file into protected prop
  285. *
  286. * @return void
  287. */
  288. protected function loadDomains() {
  289. if (!empty($this->domainsFile)) {
  290. $this->domainsList = $this->loadDomainsSource($this->domainsFile);
  291. }
  292. }
  293. /**
  294. * Returns list of loaded domains
  295. *
  296. * @return array
  297. */
  298. public function getDomains() {
  299. return ($this->domainsList);
  300. }
  301. /**
  302. * Returns list of loaded domains
  303. *
  304. * @return string
  305. */
  306. public function renderDomainsRaw() {
  307. $result = '';
  308. if (!empty($this->domainsList)) {
  309. foreach ($this->domainsList as $io => $eachDomain) {
  310. $result .= $eachDomain . PHP_EOL;
  311. }
  312. }
  313. return ($result);
  314. }
  315. /**
  316. * Returns isc-bind zones file
  317. *
  318. * @return string
  319. */
  320. public function getBindZones() {
  321. $result = '';
  322. if (!empty($this->domainsList)) {
  323. foreach ($this->domainsList as $io => $eachDomain) {
  324. $result .= 'zone "' . $eachDomain . '" { type master; file "' . $this->dnsRedirectsPath . '"; allow-query { ' . $this->dnsAcl . ' }; };' . PHP_EOL;
  325. }
  326. }
  327. return ($result);
  328. }
  329. /**
  330. * Rewrites isc-bind zones files
  331. *
  332. * @return string/void - generated filename
  333. */
  334. public function saveBindZones() {
  335. $result = '';
  336. $zonesData = $this->getBindZones();
  337. if (!empty($this->dnsZonesPath)) {
  338. file_put_contents($this->dnsZonesPath, $zonesData);
  339. $result = $this->dnsZonesPath;
  340. } else {
  341. $result = '';
  342. }
  343. return ($result);
  344. }
  345. /**
  346. * Validate isc-bind RPZ zone file
  347. *
  348. * @return string
  349. */
  350. protected function validateBindRpzZoneFile() {
  351. $result = '';
  352. if (file_exists($this->dnsRPZzoneFile)) {
  353. $result = trim(shell_exec('named-checkzone rpz ' . $this->dnsRPZzoneFile . ' | grep "OK"'));
  354. }
  355. return $result;
  356. }
  357. /**
  358. * Returns current zone serial
  359. *
  360. * @return string
  361. */
  362. protected function getBindRpzSerial() {
  363. $result = '';
  364. $result = shell_exec('rndc zonestatus ' . $this->dnsRPZzoneName . ' | grep "serial: "');
  365. $result = trim(str_replace("serial: ", "", $result));
  366. return $result;
  367. }
  368. /**
  369. * Returns isc-bind RPZ zone file
  370. *
  371. * @return string
  372. */
  373. public function getBindRpzZone() {
  374. $result = '';
  375. if (!empty($this->domainsList)) {
  376. $result .= file_get_contents("cli/bind-rpz.template");
  377. foreach ($this->domainsList as $io => $eachDomain) {
  378. $result .= $eachDomain . "\t" . 'A' . "\t" . '127.0.0.1' . PHP_EOL;
  379. $result .= "*." . $eachDomain . "\t" . 'A' . "\t" . '127.0.0.1' . PHP_EOL;
  380. }
  381. }
  382. // replace current serial to new serial
  383. $result = preg_replace("/{serial}/", ($this->getBindRpzSerial()) + 1, $result);
  384. return ($result);
  385. }
  386. /**
  387. * Rewrite isc-bind RPZ zone file
  388. *
  389. * @return string/void - generated filename
  390. */
  391. public function saveBindRpzZone() {
  392. if (file_exists($this->dnsRPZzoneFile)) {
  393. rename($this->dnsRPZzoneFile, $this->dnsRPZzoneFile . ".bak");
  394. $zoneData = $this->getBindRpzZone();
  395. file_put_contents($this->dnsRPZzoneFile, $zoneData);
  396. if ($this->validateBindRpzZoneFile() == "OK") {
  397. $result = shell_exec('rndc reload ' . $this->dnsRPZzoneName);
  398. unlink($this->dnsRPZzoneFile . ".bak");
  399. return $result;
  400. } else {
  401. rename($this->dnsRPZzoneFile . ".bak", $this->dnsRPZzoneFile);
  402. die('BIND config error');
  403. }
  404. } else {
  405. die('no zone file found');
  406. }
  407. }
  408. /**
  409. * Returns unbound zones file
  410. *
  411. * @return string
  412. */
  413. public function getUnboundZones() {
  414. $result = '';
  415. if (!empty($this->domainsList)) {
  416. foreach ($this->domainsList as $io => $eachDomain) {
  417. $result .= 'local-zone: "' . $eachDomain . '" static' . PHP_EOL;
  418. $result .= 'local-data: "' . $eachDomain . ' A ' . $this->unboundRedirectHost . '"' . PHP_EOL;
  419. }
  420. }
  421. return ($result);
  422. }
  423. /**
  424. * Rewrites unbound zones files
  425. *
  426. * @return string/void - generated filename
  427. */
  428. public function saveUnboundZones() {
  429. $result = '';
  430. $zonesData = $this->getUnboundZones();
  431. if (!empty($this->dnsUnboundZonesPath)) {
  432. file_put_contents($this->dnsUnboundZonesPath, $zonesData);
  433. $result = $this->dnsUnboundZonesPath;
  434. } else {
  435. $result = '';
  436. }
  437. return ($result);
  438. }
  439. /**
  440. * Returns Squid configs file file
  441. *
  442. * @return string
  443. */
  444. public function getSquidConfig($config) {
  445. $result = '';
  446. if (!empty($config)) {
  447. $result .= $config;
  448. }
  449. return ($result);
  450. }
  451. /**
  452. * Rewrites Squid Configs files
  453. *
  454. * @return string/void - generated filename
  455. */
  456. public function saveSquid($config, $squidCA, $ERR_1984TECH) {
  457. $result = '';
  458. $zonesData = $this->renderDomainsRaw();
  459. if (!empty($zonesData) and !empty($config) and !empty($squidCA)) {
  460. file_put_contents($this->SquidPath . '/squid.conf', $config);
  461. file_put_contents($this->SquidPath . '/squidCA.pem', $squidCA);
  462. file_put_contents($this->SquidPath . '/1984tech.conf', $zonesData);
  463. if (is_dir($this->SquidPath) and !is_dir($this->SquidPath . '/errors/templates/')) {
  464. mkdir($this->SquidPath . '/errors/templates/', 0755, true);
  465. }
  466. file_put_contents($this->SquidPath . '/errors/templates/ERR_1984TECH', $ERR_1984TECH);
  467. $result = $this->SquidPath . '/squid.conf' . PHP_EOL;
  468. $result .= $this->SquidPath . '/1984tech.conf' . PHP_EOL;
  469. $result .= $this->SquidPath . '/errors/templates/ERR_1984TECH' . PHP_EOL;
  470. } else {
  471. $result = '';
  472. }
  473. return ($result);
  474. }
  475. /**
  476. * Initializes dns resolver object incstance for further usage
  477. *
  478. * @return void
  479. */
  480. protected function initDnsResolver() {
  481. require_once('Net/DNS2.php');
  482. $this->resolver = new Net_DNS2_Resolver(array('nameservers' => $this->dnsServers));
  483. }
  484. /**
  485. * Performs DNS lookup of some domain, returns list of received IPs
  486. *
  487. * @param string $domain
  488. * @param string $type
  489. *
  490. * @return array
  491. */
  492. protected function getDomainIps($domain, $type = 'A') {
  493. $result = array();
  494. if (empty($this->resolver)) {
  495. $this->initDnsResolver();
  496. }
  497. try {
  498. $queryTmp = $this->resolver->query($domain, $type);
  499. if (!empty($queryTmp)) {
  500. if (!empty($queryTmp->answer)) {
  501. foreach ($queryTmp->answer as $io) {
  502. $result[$io->address] = $io->name;
  503. }
  504. }
  505. }
  506. } catch (Exception $e) {
  507. print('Fail: ' . $e->getMessage() . PHP_EOL);
  508. }
  509. return ($result);
  510. }
  511. /**
  512. * Performs all loaded domains IPs resolving
  513. *
  514. * @return array
  515. */
  516. protected function resolveAllDomainsIps() {
  517. $result = array();
  518. if (!empty($this->domainsList)) {
  519. foreach ($this->domainsList as $domainIndex => $eachDomain) {
  520. $domainIps = $this->getDomainIps($eachDomain);
  521. if (!empty($domainIps)) {
  522. foreach ($domainIps as $domainIp => $domainName) {
  523. if (!empty($domainIp) and $domainIp != '127.0.0.1') {
  524. $result[$domainIp] = $domainName;
  525. }
  526. }
  527. }
  528. }
  529. }
  530. return ($result);
  531. }
  532. /**
  533. * Returns ipfw rules list
  534. *
  535. * @param bool $useMacro - use raw path or variable name as ipfw command
  536. *
  537. * @return string
  538. */
  539. public function getIpfwRules($useMacro) {
  540. $result = '';
  541. if ((!empty($this->domainsList)) and (!empty($this->ipfwTable)) and (!empty($this->ipfwPath))) {
  542. $allDomainIps = $this->resolveAllDomainsIps();
  543. if ($useMacro) {
  544. $ipfwCommand = '${' . $this->ipfwMacro . '}';
  545. } else {
  546. $ipfwCommand = $this->ipfwPath;
  547. }
  548. if (!empty($allDomainIps)) {
  549. foreach ($allDomainIps as $eachIp => $eachDomain) {
  550. $result .= $ipfwCommand . ' table ' . $this->ipfwTable . ' add ' . $eachIp . PHP_EOL;
  551. }
  552. }
  553. }
  554. return ($result);
  555. }
  556. /**
  557. * Returns ipfw script for table filling
  558. *
  559. * @return string
  560. */
  561. public function getIpfwScript() {
  562. $result = '#!/bin/sh' . PHP_EOL;
  563. $result .= $this->ipfwMacro . '="/sbin/ipfw -q"' . PHP_EOL;
  564. $result .= '${' . $this->ipfwMacro . '} -f table ' . $this->ipfwTable . ' flush' . PHP_EOL;
  565. $result .= $this->getIpfwRules(true);
  566. return ($result);
  567. }
  568. /**
  569. * Returns ipfw script for table filling
  570. *
  571. * @return string
  572. */
  573. public function getMikrotikScript() {
  574. $result = '/ip firewall address-list' . PHP_EOL;
  575. if ((!empty($this->domainsList)) and (!empty($this->mtListName))) {
  576. $allDomainIps = $this->resolveAllDomainsIps();
  577. if (!empty($allDomainIps)) {
  578. foreach ($allDomainIps as $eachIp => $eachDomain) {
  579. $result .= 'add address=' . $eachIp . ' list=' . $this->mtListName . PHP_EOL;
  580. }
  581. }
  582. }
  583. return ($result);
  584. }
  585. /**
  586. * Returns ipfw script for table filling
  587. *
  588. * @return string
  589. */
  590. public function getMikrotikScriptDomains() {
  591. $result = '/ip firewall address-list' . PHP_EOL;
  592. if ((!empty($this->domainsList)) and (!empty($this->mtListName))) {
  593. foreach ($this->domainsList as $io => $eachDomain) {
  594. $result .= 'add address=' . $eachDomain . ' list=' . $this->mtListName . PHP_EOL;
  595. }
  596. }
  597. return ($result);
  598. }
  599. /**
  600. * Saves mikrotik update script to filesystem
  601. *
  602. * @return string/void
  603. */
  604. public function saveMikrotikScript() {
  605. $result = '';
  606. $mtScript = $this->getMikrotikScript();
  607. if (!empty($this->mtScriptPath)) {
  608. file_put_contents($this->mtScriptPath, $mtScript);
  609. $result = $this->mtScriptPath;
  610. }
  611. return ($result);
  612. }
  613. /**
  614. * Generates suitable output for adding Mikrotik static DNS records
  615. *
  616. * @return string
  617. */
  618. public function getMTStaticDNSScript() {
  619. $result = '/ip dns static' . PHP_EOL;
  620. if (!empty($this->domainsList) and !empty($this->mtDNSStaticScriptPath)) {
  621. foreach ($this->domainsList as $io => $eachDomain) {
  622. $result .= 'add address=' . $this->mtDNSStaticIP . ' name=' . $eachDomain . ' ttl=' . $this->mtDNSStaticTTL . PHP_EOL;
  623. }
  624. }
  625. return ($result);
  626. }
  627. /**
  628. * Saves output for adding Mikrotik static DNS records into a file
  629. *
  630. * @return string
  631. */
  632. public function saveMTStaticDNSScript() {
  633. $result = '';
  634. $mtScript = $this->getMTStaticDNSScript();
  635. if (!empty($this->mtDNSStaticScriptPath)) {
  636. file_put_contents($this->mtDNSStaticScriptPath, $mtScript);
  637. $result = $this->mtDNSStaticScriptPath;
  638. }
  639. return ($result);
  640. }
  641. /**
  642. * Splits domains list to file chunks with size under 4096 bytes for processing with internal Mikrotik script
  643. *
  644. * @return int
  645. */
  646. public function splitDNsListToChunksForMT() {
  647. $chunk = '';
  648. $chunkSize = 4096;
  649. $chunkCounter = 0;
  650. $dnsRecParams = ',' . $this->mtDNSStaticIP . ',' . $this->mtDNSStaticTTL;
  651. if (!empty($this->domainsList)) {
  652. foreach ($this->domainsList as $io => $eachDomain) {
  653. $chunk .= $eachDomain . $dnsRecParams . PHP_EOL;
  654. if (strlen($chunk) >= $chunkSize) {
  655. $chunkCounter++;
  656. $chunk = str_replace($eachDomain . $dnsRecParams . PHP_EOL, '', $chunk);
  657. file_put_contents($this->mtDNSStaticChunksPath . DIRECTORY_SEPARATOR . $this->mtDNSStaticChunksBaseName . $chunkCounter . $this->mtDNSStaticChunksExt, $chunk);
  658. $chunk = '';
  659. }
  660. }
  661. if (!empty($chunk)) {
  662. $chunkCounter++;
  663. file_put_contents($this->mtDNSStaticChunksPath . DIRECTORY_SEPARATOR . $this->mtDNSStaticChunksBaseName . $chunkCounter . $this->mtDNSStaticChunksExt, $chunk);
  664. $chunk = '';
  665. }
  666. }
  667. return ($chunkCounter);
  668. }
  669. /**
  670. * Saves negation sections output suitable for PDNSD config to a file
  671. *
  672. * @return string
  673. */
  674. public function getPDNSDScript() {
  675. $result = '';
  676. if (!empty($this->domainsList) and !empty($this->pdnsdScriptPath)) {
  677. foreach ($this->domainsList as $io => $eachDomain) {
  678. $result .= 'neg {name=' . $eachDomain . '; types=domain;}' . PHP_EOL;
  679. }
  680. }
  681. return ($result);
  682. }
  683. /**
  684. * Generates negation sections output suitable for PDNSD config
  685. *
  686. * @return string
  687. */
  688. public function savePDNSDScript() {
  689. $result = '';
  690. $pdnsdScript = $this->getPDNSDScript();
  691. if (!empty($this->pdnsdScriptPath)) {
  692. file_put_contents($this->pdnsdScriptPath, $pdnsdScript);
  693. $result = $this->pdnsdScriptPath;
  694. }
  695. return ($result);
  696. }
  697. /**
  698. * Returns JunOS policy script
  699. *
  700. * @return string
  701. */
  702. public function getJunosScript() {
  703. $result = '';
  704. if ((!empty($this->domainsList)) and (!empty($this->junListName))) {
  705. $allDomainIps = $this->resolveAllDomainsIps();
  706. if (!empty($allDomainIps)) {
  707. foreach ($allDomainIps as $eachIp => $eachDomain) {
  708. $result .= 'set policy-options prefix-list ' . $this->junListName . ' ' . $eachIp . '/32' . PHP_EOL;
  709. }
  710. }
  711. }
  712. return ($result);
  713. }
  714. /**
  715. * Returns Cisco IOS script
  716. *
  717. * @return string
  718. */
  719. public function getCiscoScript() {
  720. $result = '';
  721. if ((!empty($this->domainsList)) and (!empty($this->cisListNum))) {
  722. $allDomainIps = $this->resolveAllDomainsIps();
  723. if (!empty($allDomainIps)) {
  724. foreach ($allDomainIps as $eachIp => $eachDomain) {
  725. $result .= 'access-list ' . $this->cisListNum . ' deny ip any host ' . $eachIp . '/32' . PHP_EOL;
  726. }
  727. }
  728. }
  729. return ($result);
  730. }
  731. /**
  732. * Saves ipfw script
  733. *
  734. * @return string/void
  735. */
  736. public function saveIpfwScript() {
  737. $result = '';
  738. $ipfwScript = $this->getIpfwScript();
  739. if (!empty($this->ipfwScriptPath)) {
  740. file_put_contents($this->ipfwScriptPath, $ipfwScript);
  741. $result = $this->ipfwScriptPath;
  742. }
  743. return ($result);
  744. }
  745. /**
  746. * Renders list of all loaded domains IPs
  747. *
  748. * @return string
  749. */
  750. public function renderDomainsIps() {
  751. $result = '';
  752. $allDomainIps = $this->resolveAllDomainsIps();
  753. if (!empty($allDomainIps)) {
  754. foreach ($allDomainIps as $ip => $domain) {
  755. $result .= $ip . ' ' . $domain . PHP_EOL;
  756. }
  757. }
  758. return ($result);
  759. }
  760. /**
  761. * Updates ipfw table with domains IPs
  762. *
  763. * @return string
  764. */
  765. public function ipfwTableUpdate() {
  766. $result = '';
  767. $allIpfwRules = $this->getIpfwRules(false);
  768. if ((!empty($allIpfwRules)) and (!empty($this->ipfwTable))) {
  769. $allIpfwRules = explode(PHP_EOL, $allIpfwRules);
  770. if (!empty($allIpfwRules)) {
  771. foreach ($allIpfwRules as $io => $eachRule) {
  772. if (!empty($eachRule)) {
  773. $result .= shell_exec($eachRule);
  774. }
  775. }
  776. }
  777. }
  778. return ($result);
  779. }
  780. /**
  781. * Returns ipset update script
  782. *
  783. * @param bool $run
  784. *
  785. * @return string
  786. */
  787. public function getIpsetScript($run = false) {
  788. $result = '';
  789. if ((!empty($this->domainsList)) and (!empty($this->ipsetListName)) and (!empty($this->ipsetPath))) {
  790. $allDomainIps = $this->resolveAllDomainsIps();
  791. if (!empty($allDomainIps)) {
  792. foreach ($allDomainIps as $eachIp => $eachDomain) {
  793. $template = $this->ipsetPath . ' -A ' . $this->ipsetListName . ' ' . $eachIp . PHP_EOL;
  794. if (!$run) {
  795. $result .= $template;
  796. } else {
  797. $result .= shell_exec($template);
  798. }
  799. }
  800. }
  801. }
  802. return ($result);
  803. }
  804. /**
  805. * Returns iptables update script
  806. *
  807. * @param bool $run
  808. *
  809. * @return string
  810. */
  811. public function getIptablesScript($run = false) {
  812. $result = '';
  813. if ((!empty($this->domainsList)) and (!empty($this->iptablesChain)) and (!empty($this->iptablesPath))) {
  814. $allDomainIps = $this->resolveAllDomainsIps();
  815. if (!empty($allDomainIps)) {
  816. foreach ($allDomainIps as $eachIp => $eachDomain) {
  817. $template = $this->iptablesPath . ' -A ' . $this->iptablesChain . ' -d ' . $eachIp . ' -j DROP' . PHP_EOL;
  818. if (!$run) {
  819. $result .= $template;
  820. } else {
  821. $result .= shell_exec($template);
  822. }
  823. }
  824. }
  825. }
  826. return ($result);
  827. }
  828. /**
  829. * Checks current domains list for domain duplicates
  830. *
  831. * @param bool $useLocalList
  832. *
  833. * @return void
  834. */
  835. public function uniqueCheck($useLocalList = false) {
  836. $domainTmp = array();
  837. $dupCount = 0;
  838. $totalCount = 0;
  839. if ($useLocalList) {
  840. $dataSource = 'domains.txt';
  841. $listToCheck = $this->loadDomainsSource($dataSource);
  842. } else {
  843. $dataSource = $this->domainsFile;
  844. $listToCheck = $this->domainsList;
  845. }
  846. if (!empty($this->domainsList)) {
  847. print('Looking for domain duplicates in ' . $dataSource . PHP_EOL);
  848. print(' ==================' . PHP_EOL);
  849. foreach ($listToCheck as $line => $eachDomain) {
  850. $eachDomain = strtolower($eachDomain);
  851. if (!empty($eachDomain)) {
  852. if (isset($domainTmp[$eachDomain])) {
  853. print($eachDomain . ' duplicate in line ' . $line . PHP_EOL);
  854. $dupCount++;
  855. } else {
  856. $domainTmp[$eachDomain] = $line;
  857. }
  858. } else {
  859. print('Error: empty domain in line ' . $line . PHP_EOL);
  860. }
  861. $totalCount++;
  862. }
  863. print('Total ' . $totalCount . ' domains checked' . PHP_EOL);
  864. print('Found ' . $dupCount . ' domain duplicates' . PHP_EOL);
  865. $checkLabel = ($dupCount == 0) ? 'PASSED' : 'FAILED!';
  866. print(' ===========================' . PHP_EOL);
  867. print('| DUPLICATES CHECK ' . $checkLabel . ' |' . PHP_EOL);
  868. print('============================' . PHP_EOL);
  869. } else {
  870. print('Error: empty domains list loaded from ' . $this->domainsFile . PHP_EOL);
  871. }
  872. }
  873. /**
  874. * Syncs local domains list with another or remote list.
  875. *
  876. * @param string $fileUrl The URL of the file to fetch the contents from (optional).
  877. *
  878. * @return void
  879. */
  880. public function sync($fileUrl = '') {
  881. $localCount = 0;
  882. $remoteCount = 0;
  883. $newCount = 0;
  884. $newList = '';
  885. $uniq = array();
  886. //using local source
  887. $dataSource = 'domains.txt';
  888. $localDomains = $this->loadDomainsSource($dataSource);
  889. if (empty($fileUrl)) {
  890. $fileUrl = 'newdomains.txt';
  891. }
  892. @$rawNewDomains = file_get_contents($fileUrl);
  893. print('Looking for new domains in ' . $fileUrl . PHP_EOL);
  894. if (!empty($rawNewDomains)) {
  895. $newDomains = explode(PHP_EOL, $rawNewDomains);
  896. $localDomains = array_flip($localDomains);
  897. $remoteCount = sizeof($newDomains);
  898. $localCount = sizeof($localDomains);
  899. print($remoteCount . ' Domains in ' . $fileUrl . PHP_EOL);
  900. print($localCount . ' Domains in ' . $dataSource . PHP_EOL);
  901. print(' ===========================' . PHP_EOL);
  902. foreach ($newDomains as $io => $eachDomain) {
  903. if (!empty($eachDomain)) {
  904. if (!isset($localDomains[$eachDomain])) {
  905. if ($this->isDomainValid($eachDomain)) {
  906. if (!isset($uniq[$eachDomain])) {
  907. $newList .= trim($eachDomain) . PHP_EOL;
  908. $uniq[$eachDomain] = 1;
  909. $newCount++;
  910. }
  911. }
  912. }
  913. }
  914. }
  915. if ($newCount > 0) {
  916. print($newList);
  917. }
  918. print(' ================================================' . PHP_EOL);
  919. print('| CHECK FINISHED: ' . $newCount . ' NEW DOMAINS FOUND |' . PHP_EOL);
  920. print('=================================================' . PHP_EOL);
  921. } else {
  922. print(' ===========================' . PHP_EOL);
  923. print('| CHECK FAILED: EMPTY LIST |' . PHP_EOL);
  924. print('============================' . PHP_EOL);
  925. }
  926. //print($rawNewDomains);
  927. }
  928. /**
  929. * Extracts domain name from shitty URLs
  930. *
  931. * @param string $address
  932. *
  933. * @return string
  934. */
  935. protected function getHost($address) {
  936. $result = '';
  937. $address = trim($address);
  938. $parseUrl = parse_url($address);
  939. if (isset($parseUrl['host'])) {
  940. $result = $parseUrl['host'];
  941. } else {
  942. if (isset($parseUrl['path'])) {
  943. $exploded = explode('/', $parseUrl['path']);
  944. $result = $exploded[0];
  945. }
  946. }
  947. return ($result);
  948. }
  949. /**
  950. * Basic domain names validator
  951. *
  952. * @return bool
  953. */
  954. protected function isDomainValid($domainName) {
  955. return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $domainName) //valid chars check
  956. && preg_match("/^.{1,253}$/", $domainName) //overall length check
  957. && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domainName));
  958. }
  959. /**
  960. * Runs all checks for all datasources
  961. *
  962. * @return void
  963. */
  964. public function runAllChecks() {
  965. $this->uniqueCheck();
  966. $this->uniqueCheck(true);
  967. $this->validityCheck();
  968. $this->validityCheck(true);
  969. }
  970. /**
  971. * Checks for domains validity
  972. *
  973. * @return void
  974. */
  975. public function validityCheck($useLocalList = false) {
  976. require_once('api.punycode.php'); //yep, we need this ;/
  977. $errCounter = 0;
  978. $totalCounter = 0;
  979. if ($useLocalList) {
  980. $dataSource = 'domains.txt';
  981. $listToCheck = $this->loadDomainsSource($dataSource);
  982. } else {
  983. $dataSource = $this->domainsFile;
  984. $listToCheck = $this->domainsList;
  985. }
  986. if (!empty($this->domainsList)) {
  987. print('Checking Domains validity in ' . $dataSource . PHP_EOL);
  988. print(' ==================' . PHP_EOL);
  989. foreach ($listToCheck as $line => $eachDomain) {
  990. $cleanDomain = $this->getHost($eachDomain);
  991. $cleanDomain = str_replace('www.', '', $cleanDomain);
  992. $cleanDomain = Punycode::encodeHostName($cleanDomain);
  993. if ($cleanDomain) {
  994. if ($eachDomain != $cleanDomain) {
  995. print_r('Error: domain ' . $eachDomain . ' must be like ' . $cleanDomain . ' at line ' . $line . PHP_EOL);
  996. $errCounter++;
  997. } else {
  998. if (!$this->isDomainValid($eachDomain)) {
  999. print_r('Error: domain ' . $eachDomain . ' is not valid in line ' . $line . PHP_EOL);
  1000. $errCounter++;
  1001. }
  1002. }
  1003. } else {
  1004. print_r('Error: domain ' . $eachDomain . ' is corrupted in line ' . $line . PHP_EOL);
  1005. $errCounter++;
  1006. }
  1007. $totalCounter++;
  1008. }
  1009. } else {
  1010. print('Error: empty domains list loaded from ' . $this->domainsFile . PHP_EOL);
  1011. $errCounter++;
  1012. }
  1013. print('Total ' . $totalCounter . ' domains checked' . PHP_EOL);
  1014. print('Found ' . $errCounter . ' domain errors' . PHP_EOL);
  1015. $checkLabel = ($errCounter == 0) ? 'PASSED' : 'FAILED!';
  1016. print(' =========================' . PHP_EOL);
  1017. print('| VALIDITY CHECK ' . $checkLabel . ' |' . PHP_EOL);
  1018. print(' =========================' . PHP_EOL);
  1019. }
  1020. }