DNS4PSA.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. <?php
  2. namespace MGModule\DNSManager2\mgLibs\custom\dns\submodules;
  3. use \MGModule\DNSManager2\mgLibs\custom\dns;
  4. use \MGModule\DNSManager2\mgLibs\custom\dns\exceptions;
  5. use \MGModule\DNSManager2\mgLibs\custom\dns\interfaces;
  6. use \MGModule\DNSManager2\mgLibs\custom\dns\submodules\dns4psa\SoapClient4psa;
  7. use \MGModule\DNSManager2\mgLibs\custom\dns\utils\Patterns;
  8. use \SoapHeader;
  9. use \SoapVar;
  10. use \stdClass;
  11. /* define request type constant */
  12. define('CLIENT_TYPE', 'client');
  13. define('DNSZONE_TYPE', 'dnszone');
  14. define('DNSRECORD_TYPE', 'dnsrecord');
  15. ini_set('soap.wsdl_cache_enabled', 0);
  16. class DNS4PSA extends dns\SubmoduleAbstract implements interfaces\SubmoduleImportInterface, interfaces\SubmoduleIPInterface, interfaces\SubmoduleRDNSInterface
  17. {
  18. public $configFields = [
  19. 'username' => [
  20. 'friendlyName' => 'Username',
  21. 'validators' => [
  22. 'required' => 'required',
  23. ]
  24. ],
  25. 'password' => [
  26. 'friendlyName' => 'Password',
  27. 'type' => 'password',
  28. 'validators' => [
  29. 'required' => 'required',
  30. ]
  31. ],
  32. 'hostname' => [
  33. 'friendlyName' => 'Hostname',
  34. 'validators' => [
  35. 'required' => 'required',
  36. ]
  37. ],
  38. 'port' => [
  39. 'friendlyName' => 'Port',
  40. 'type' => 'number',
  41. ],
  42. 'template' => [
  43. 'friendlyName' => 'Template',
  44. ],
  45. 'client_name' => [
  46. 'friendlyName' => 'Client Name',
  47. ],
  48. 'ssl' => [
  49. 'friendlyName' => 'SSL',
  50. 'type' => 'yesno',
  51. ],
  52. 'default_ip' => [
  53. 'friendlyName' => 'Default IP',
  54. 'validators' => [
  55. 'required' => 'required',
  56. 'pattern' => Patterns::IP4_OR_IP6,
  57. ]
  58. ],
  59. 'override_wsdl_url' => [
  60. 'friendlyName' => 'Override WSDL URL',
  61. 'type' => 'yesno'
  62. ]
  63. ];
  64. public $availableTypes = ['A', 'AAAA', 'NS', 'MX', 'CNAME', 'TXT', 'SRV']; //'A', 'AAAA', 'NS', 'MX', 'CNAME', 'TXT', 'PTR', 'SRV', 'NAPTR'
  65. private function get($function, $params = null, $retback = false, $locationType = DNSZONE_TYPE)
  66. {
  67. $soap = $this->loadSoap();
  68. if (!$soap)
  69. {
  70. throw new exceptions\DNSSubmoduleException("SOAP Error: Cannot load soap class", dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
  71. }
  72. try
  73. {
  74. //Optimization
  75. if( $this->config['override_wsdl_url'] === 'on' )
  76. {
  77. throw new \Exception('Skipping WSDL URL');
  78. }
  79. $result = $soap->$function($params);
  80. }
  81. catch( \Exception $exception ) //try with location changing
  82. {
  83. $soap = $this->loadSoap();
  84. $soap->__setLocation("http://{$this->config['hostname']}/soap/{$locationType}_agent.php"); // it is const
  85. $result = $soap->$function($params);
  86. }
  87. if ($retback && isset($result->$retback))
  88. {
  89. return true;
  90. }
  91. if (is_a($result, 'SoapFault'))
  92. {
  93. throw new exceptions\DNSSubmoduleException($result->getMessage(), dns\SubmoduleExceptionCodes::COMMAND_ERROR);
  94. }
  95. elseif (isset($result->notice->message))
  96. {
  97. throw new exceptions\DNSSubmoduleException($result->notice->message, dns\SubmoduleExceptionCodes::COMMAND_ERROR);
  98. }
  99. else
  100. {
  101. if ($retback)
  102. {
  103. throw new exceptions\DNSSubmoduleException('Unexpected Error', dns\SubmoduleExceptionCodes::COMMAND_ERROR);
  104. }
  105. return $result;
  106. }
  107. }
  108. private function loadSoap()
  109. {
  110. /* the class that prepares the soapClient */
  111. require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'dns4psa' . DIRECTORY_SEPARATOR . 'misc.php');
  112. $files_location = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'dns4psa' . DIRECTORY_SEPARATOR;
  113. $dnsmanager_version = '1.5';
  114. $context = stream_context_create([
  115. 'ssl' => [
  116. 'verify_peer' => false,
  117. 'verify_peer_name' => false,
  118. 'allow_self_signed' => false
  119. ]
  120. ]);
  121. try
  122. {
  123. $client_class = new SoapClient4psa($files_location, ['trace' => 1, 'exceptions' => 1, 'connection_timeout' => 120, 'cache_wsdl' => WSDL_CACHE_NONE, 'stream_context' => $context], $this->config['hostname'], $this->config['port'] == '' ? 80 : $this->config['port'], $this->config['ssl'] == '1' ? 1 : 0, $dnsmanager_version);
  124. }
  125. catch (\Throwable $exception)
  126. {
  127. throw new exceptions\DNSSubmoduleException($exception->getMessage(), dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
  128. }
  129. if ($client_class->error != '')
  130. {
  131. throw new exceptions\DNSSubmoduleException($client_class->error, dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
  132. }
  133. $client = $client_class->getSoapClient();
  134. $auth = new stdClass();
  135. $auth->username = $this->config['username'];
  136. $auth->password = $this->config['password'];
  137. $authvalues = new SoapVar($auth, SOAP_ENC_OBJECT, 'http://4psa.com/HeaderData/' . $dnsmanager_version);
  138. $header = new SoapHeader('http://4psa.com/HeaderData/' . $dnsmanager_version, 'userCredentials', $authvalues, false);
  139. $client->__setSoapHeaders([$header]);
  140. return $client;
  141. }
  142. public function testConnection()
  143. {
  144. $ret = $this->get('GetDNSZone', '', 'DNSZone');
  145. }
  146. public function zoneExists()
  147. {
  148. try
  149. {
  150. $dns_zone = new stdClass();
  151. $dns_zone->DNSZoneName = $this->domain;
  152. $this->get('GetDNSZone', $dns_zone, 'DNSZone');
  153. }
  154. catch (exceptions\DNSSubmoduleException $e)
  155. {
  156. if ($e->getCode() == dns\SubmoduleExceptionCodes::COMMAND_ERROR)
  157. {
  158. return false;
  159. }
  160. throw $e;
  161. }
  162. return true;
  163. }
  164. public function getRecords($recordType = false)
  165. {
  166. $dns_zone = new stdClass();
  167. $dns_zone->DNSZoneName = $this->domain;
  168. try
  169. {
  170. $ret = $this->get('GetDNSRecord', $dns_zone);
  171. }
  172. catch (exceptions\DNSSubmoduleException $e)
  173. {
  174. if ($e->getMessage() != 'No DNS record has been found.')
  175. {
  176. throw $e;
  177. }
  178. }
  179. $out = [];
  180. if (!is_array($ret->DNSRecord))
  181. {
  182. $ret->DNSRecord = [$ret->DNSRecord];
  183. }
  184. foreach ($ret->DNSRecord as $r)
  185. {
  186. if (in_array((string)$r->type, $recordType !== false ? [strtoupper($recordType)] : $this->getAvailableRecordTypes()))
  187. {
  188. $record = new dns\record\Record();
  189. $record->line = (string)$r->DNSRecordId;
  190. $record->name = (string)$r->host;
  191. $record->type = (string)$r->type;
  192. //$record->ttl = (string)$r->TTL;
  193. $record->createRDATAObject();
  194. switch ((string)$r->type)
  195. {
  196. case 'MX':
  197. $record->rdata->preference = (string)$r->opt;
  198. $record->rdata->exchange = (string)$r->value;
  199. break;
  200. case 'NAPTR':
  201. $record->rdata->setDataFromArray((array)$r);
  202. $record->rdata->regexp = (string)$r->regex;
  203. $record->rdata->flags = (string)$r->flag;
  204. $record->rdata->replacement = (string)$r->replace;
  205. break;
  206. case 'SRV':
  207. //fucking 4PSA! it require new request to fetch details data
  208. $data = new \stdClass();
  209. $data->DNSRecordId = $r->DNSRecordId;
  210. $fullRecord = $this->get('GetDNSRecord', $data)->DNSRecord;
  211. $service = '_'.ltrim($fullRecord->service, '_');
  212. $protocol = '_'.ltrim($fullRecord->protocol, '_');
  213. $record->name = "{$service}.{$protocol}.{$fullRecord->host}";
  214. $record->rdata->setDataFromArray((array)$fullRecord);
  215. break;
  216. default:
  217. $record->rdata->setFirstProperty((string)$r->value);
  218. break;
  219. }
  220. $out[] = $record;
  221. }
  222. }
  223. return $out;
  224. }
  225. private function recordToParamsArray(dns\record\Record $record)
  226. {
  227. $dns_zone = new stdClass();
  228. $dns_zone->DNSZoneName = $this->domain;
  229. $dns_zone->host = $record->nameToAbsolute($this->domain);
  230. $dns_zone->type = $record->type;
  231. switch ($record->type)
  232. {
  233. case 'MX':
  234. $dns_zone->opt = $record->rdata->preference;
  235. $dns_zone->value = $record->rdata->exchange;
  236. break;
  237. case 'NAPTR':
  238. $dns_zone->order = $record->rdata->order;
  239. $dns_zone->preference = $record->rdata->preference;
  240. $dns_zone->flag = $record->rdata->flags;
  241. $dns_zone->replace = $record->rdata->replacement;
  242. $dns_zone->regex = $record->rdata->regexp;
  243. $dns_zone->services = $record->rdata->services;
  244. break;
  245. case 'SRV':
  246. $exploded = explode('.', $record->name, 3);
  247. list($service, $protocol, $name) = $exploded;
  248. $dns_zone->service = ltrim($service, '_');
  249. $dns_zone->protocol = ltrim($protocol, '_');
  250. $record->name = $name;
  251. $dns_zone->host = $record->nameToAbsolute($this->domain);
  252. $dns_zone->priority = $record->rdata->priority;
  253. $dns_zone->weight = $record->rdata->weight;
  254. $dns_zone->port = $record->rdata->port;
  255. $dns_zone->target = $record->rdata->target;
  256. break;
  257. case 'TXT':
  258. $dns_zone->value = trim($record->rdata->toString(), '"');
  259. break;
  260. default:
  261. $dns_zone->value = $record->rdata->toString();
  262. break;
  263. }
  264. return $dns_zone;
  265. }
  266. public function addRecord(dns\record\Record $record)
  267. {
  268. $dns_zone = $this->recordToParamsArray($record);
  269. $this->get('AddDNSRecord', $dns_zone);
  270. }
  271. public function editRecord(dns\record\Record $record)
  272. {
  273. $dns_zone = $this->recordToParamsArray($record);
  274. $dns_zone->DNSRecordId = $record->line;
  275. $this->get('EditDNSRecord', $dns_zone);
  276. }
  277. public function deleteRecord(dns\record\Record $record)
  278. {
  279. $dns_zone = $this->recordToParamsArray($record);
  280. $dns_zone->DNSRecordId = $record->line;
  281. $dns_zone = $this->prepareForDeleteOrEdit($dns_zone);
  282. $dns_zone_for_del = new stdClass();
  283. $dns_zone_for_del->DNSRecord = $dns_zone;
  284. $this->get('DelDNSRecord', $dns_zone_for_del);
  285. }
  286. public function prepareForDeleteOrEdit($dns_zone)
  287. {
  288. switch ($dns_zone->type)
  289. {
  290. case 'SRV':
  291. $dns_zone->host = "_{$dns_zone->service}._{$dns_zone->protocol}.{$dns_zone->host}";
  292. $dns_zone->value = $dns_zone->target;
  293. break;
  294. }
  295. return $dns_zone;
  296. }
  297. public function activateZone()
  298. {
  299. if ($this->ip != '')
  300. {
  301. if (!filter_var($this->ip, FILTER_VALIDATE_IP))
  302. {
  303. throw new exceptions\DNSSubmoduleException('IP is not valid!', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
  304. }
  305. }
  306. else
  307. {
  308. $this->ip = $this->config['default_ip'];
  309. }
  310. $clients = $this->get('GetClient', null, false, CLIENT_TYPE);
  311. $dns_zone = new stdClass();
  312. $dns_zone->name = $this->domain;
  313. if ($this->config['template'])
  314. {
  315. $dns_zone->templateIP = $this->ip;
  316. $dns_zone->templateId = $this->config['template'];
  317. }
  318. // get client
  319. if (!empty($this->config['client_name']))
  320. {
  321. if (is_array($clients->client))
  322. {
  323. foreach ($clients->client as $client)
  324. {
  325. if ($client->name === $this->config['client_name'])
  326. {
  327. $dns_zone->clientId = $client->clientId;
  328. break;
  329. }
  330. }
  331. }
  332. else
  333. {
  334. if (!empty($clients->client->clientId) && $clients->client->name === $this->config['client_name'])
  335. {
  336. $dns_zone->clientId = $clients->client->clientId;
  337. }
  338. }
  339. }
  340. $this->get('AddDNSZone', $dns_zone);
  341. }
  342. public function terminateZone()
  343. {
  344. $dns_zone = new stdClass();
  345. $dns_zone->DNSZoneName = $this->domain;
  346. $this->get('DelDNSZone', $dns_zone);
  347. }
  348. public function getZones()
  349. {
  350. $ret = $this->get('GetDNSZone', new stdClass());
  351. if (!is_array($ret->DNSZone))
  352. {
  353. $ret->DNSZone = [$ret->DNSZone];
  354. }
  355. $out = [];
  356. foreach ($ret->DNSZone as $zone)
  357. {
  358. $zone->name = trim($zone->name, '.');
  359. $out[(string)$zone->name] = isset($zone->templateIP) ? (string)$zone->templateIP : '';
  360. }
  361. return $out;
  362. }
  363. }