array ( 'friendlyName' => 'Username', 'validators' => array( 'required' => 'required', ) ), 'password' => array ( 'friendlyName' => 'Password', 'type' => 'password', 'validators' => array( 'required' => 'required', ) ), 'hostname' => array ( 'friendlyName' => 'Hostname', 'validators' => array( 'required' => 'required', ) ), 'port' => array ( 'friendlyName' => 'Port', 'value' => 2222, 'validators' => array( 'required' => 'required', ) ), 'ssl' => array ( 'friendlyName' => 'SSL', 'type' => 'yesno' ), 'default_ip' =>array ( 'friendlyName' => 'Default IP', 'validators' => array( 'required' => 'required', 'pattern' => Patterns::IP4_OR_IP6, ) ), 'ns1' => array ( 'friendlyName' => 'Nameserver 1', ), 'ns2' => array ( 'friendlyName' => 'Nameserver 2', ), 'full_mx_records' => array ( 'friendlyName' => 'Full MX Records', 'type'=> 'yesno', ), ); public $availableTypes = array('A', 'NS', 'MX', 'CNAME', 'TXT', 'AAAA', 'SRV', 'DS', 'PTR'); private function get($function, $params = array()) { $port = $this->config['port']?:'2222'; $username = urlencode($this->config['username']); $password = $this->config['password']; $url = ($this->config['ssl'] === 'on' ? 'https://'.$username.':'.urlencode($password).'@'.$this->config['hostname'].':'.$port : 'http://'.$username.':'.urlencode($password).'@'.$this->config['hostname'].':'.$port).'/'.$function; if( is_array($params) ) { $url .= '?' . http_build_query($params); } $this->log('REQUEST: ' . $url); $ch = curl_init(); $chOptions = array ( CURLOPT_URL => trim($url, '&').'&urlencoded=yes', CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_TIMEOUT => 30 ); curl_setopt_array($ch, $chOptions); $out = curl_exec($ch); $this->log('RESPONSE: ' . $out); if (curl_errno($ch)) { throw new exceptions\DNSSubmoduleException("cURL Error: " . curl_errno($ch) . " - " . curl_error($ch), dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM); } curl_close($ch); $this->checkOutput($out); //parsujemy $out1 = urldecode($out); parse_str($out1, $parsed); if(isset($parsed['error']) && $parsed['error'] > 0) { throw new exceptions\DNSSubmoduleException($parsed['text'].' '.$parsed['details'], dns\SubmoduleExceptionCodes::COMMAND_ERROR); } if($parsed === FALSE) { throw new exceptions\DNSSubmoduleException("Unknown error", dns\SubmoduleExceptionCodes::COMMAND_ERROR); } return $out; } public function testConnection() { $out = $this->get('CMD_API_SHOW_USER_USAGE', array('user' => $this->config['username'])); if(strpos($out, '') !== false) throw new exceptions\DNSSubmoduleException('Incorrect username or password', dns\SubmoduleExceptionCodes::COMMAND_ERROR); } public function zoneExists() { try { $out = $this->get('CMD_API_DNS_ADMIN', array( 'domain' => $this->domain )); if(strpos($out, '') !== false) { return false; } } catch (exceptions\DNSSubmoduleException $e) { if($e->getCode() == dns\SubmoduleExceptionCodes::COMMAND_ERROR) { return false; } throw $e; } return true; } public function getRecords($recordType = false) { $out = $this->get('CMD_API_DNS_ADMIN', array( 'domain' => $this->domain, 'urlencoded' => 'yes', 'full_mx_records' => $this->config['full_mx_records'] == 'on' ? 'yes' : 'no' )); /** TRZEBA TO ZMIENIC!!! **/ $lines = explode("\n", $out); $arr = array(); foreach($lines as $ex) { $line = explode('=', $ex, 2); //type=name=value&name1=value1 $data = explode('&', $line[1]); foreach($data as $d) { $x = explode('=', $d, 2); //name=value if(isset($x[0]) && isset($x[1])) { $arr[$line[0]][][urldecode($x[0])] = urldecode($x[1]); } } } $out = array(); $i = 0; foreach($arr as $type => $r) { foreach($r as $records) { if(in_array($type, $recordType!==false ? array(strtoupper($recordType)) : $this->getAvailableRecordTypes())) { foreach($records as $name => $value) { if(empty($name)) { continue; } $record = new dns\record\Record(); $record->line = $i; $record->name = $name; $record->type = $type; $record->createRDATAObject(); $record->rdata->fromString($value); switch($type) { case 'MX': if($this->config['full_mx_records'] != 'on'){ $record->name = $this->domain . '.'; $record->rdata->exchange = $name; } break; case 'NS': $record->name = $value; $record->rdata->setFirstProperty($name); break; } $out[] = $record; } } $i++; } } return $out; } public function addRecord(dns\record\Record $record) { $params = array( 'action' => 'add', 'domain' => $this->domain, 'type' => $record->type, ); switch($record->type) { case 'NS': $params['name'] = $record->rdata->toString(); $params['value'] = $record->nameToAbsolute($this->domain); break; case 'MX': if($this->config['full_mx_records'] == 'on'){ $params['full_mx_records'] = 'yes'; $params['mx_value'] = $record->rdata->exchange; $params['name'] = $record->nameToAbsolute($this->domain); } else { $params['full_mx_records'] = 'no'; $params['name'] = $record->rdata->exchange; } $params['value'] = $record->rdata->preference; break; case 'PTR': $params['name'] = $record->nameToAbsolute($this->domain); $params['value'] = trim($record->rdata->toString(), '.').'.'; break; default: $params['name'] = $record->nameToAbsolute($this->domain); $params['value'] = $record->rdata->toString(); break; } $params['value'] = str_replace("\t", ' ', $params['value']); $this->get('CMD_API_DNS_ADMIN', $params); } /* DA nie posiada update */ public function editRecord(dns\record\Record $record) { $records = $this->getRecords(); foreach($records as $r) { if($r->line == $record->line) { $this->deleteRecord($r); break; } } $this->addRecord($record); } public function deleteRecord(dns\record\Record $record) { $params = [ 'domain' => $this->domain, 'action' => 'select', 'delete' => 'yes' ]; if($record->type === 'MX' && $this->config['full_mx_records'] == 'on') { $params[strtolower($record->type) . 'recs0'] = 'full_mx_records=yes&name='.$record->nameToAbsolute($this->domain).'&value='.str_replace("\t", ' ', $record->rdata->toString()); $params[strtolower($record->type) . 'recs1'] = 'full_mx_records=yes&name='.urlencode($record->nameToRelative($this->domain)).'&value='.str_replace("\t", ' ', $record->rdata->toString()); } else if($record->type === 'TXT') { $params[strtolower($record->type) . 'recs0'] = 'name='.urlencode($record->nameToAbsolute($this->domain)).'&value='.(str_replace("\t", ' ', $record->rdata->toString())); $params[strtolower($record->type) . 'recs1'] = 'name='.urlencode($record->nameToRelative($this->domain)).'&value='.(str_replace("\t", ' ', $record->rdata->toString())); } else { $params[strtolower($record->type) . 'recs0'] = 'name='.urlencode($record->nameToAbsolute($this->domain)).'&value='.str_replace("\t", ' ', $record->rdata->toString()); $params[strtolower($record->type) . 'recs1'] = 'name='.urlencode($record->nameToRelative($this->domain)).'&value='.str_replace("\t", ' ', $record->rdata->toString()); } $this->get('CMD_API_DNS_ADMIN', $params); } public function activateZone() { if($this->ip != '') { if(!filter_var($this->ip, FILTER_VALIDATE_IP)) { throw new exceptions\DNSSubmoduleException('IP is not valid!', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS); } } else { $this->ip = $this->config['default_ip']; } global $CONFIG; $ns1 = !empty($this->config['ns1'])?$this->config['ns1'] : $CONFIG['DefaultNameserver1']; $ns2 = !empty($this->config['ns2'])?$this->config['ns2'] : $CONFIG['DefaultNameserver2']; $this->get('CMD_API_DNS_ADMIN', array( 'action' => 'create', 'domain' => $this->domain, 'ip' => $this->ip, 'ns1' => $ns1, 'ns2' => $ns2 )); } public function terminateZone() { $this->get('CMD_API_DNS_ADMIN', array( 'action' => 'delete', 'select0' => $this->domain )); } private function checkOutput($out){ if(strpos($out, 'You cannot execute that command') !== false) { throw new exceptions\DNSSubmoduleException('You cannot execute that command', dns\SubmoduleExceptionCodes::COMMAND_ERROR); } elseif(strpos($out, 'Please enter your Username and Password') !== false) { throw new exceptions\DNSSubmoduleException('Incorrect username or password', dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM); } elseif(strpos($out, 'Your IP is blacklisted') !== false) { throw new exceptions\DNSSubmoduleException('Your IP is blacklisted', dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM); } } public function getZones() { $page = 1; $out = []; do { $return = $this->get('CMD_API_DNS_ADMIN', ['page' => $page, 'ipp' => 1000, 'json' => 'yes']); $domainsData = array_diff_key(json_decode($return, true), array_flip(['info'])); foreach($domainsData as $data) { $out[$data['domain']] = ''; } $page++; } while( $domainsData ); return $out; } public function getSignKeys() { $ret = $this->getDnsSecKeys(); parse_str($ret, $arr); $arr = array_map(function($value){ return preg_split('/\s+/', $value); }, $arr); if(!isset($arr['DS'])) { return null; } //KSK $dnskey = new dns\record\type\DNSKEY(); $dnskey->setProtocol($arr['ksk_DNSKEY'][1]); $dnskey->setFlags($arr['ksk_DNSKEY'][0]); $dnskey->setAlgorithm($arr['ksk_DNSKEY'][2]); $dnskey->setPublicKey(implode(' ', array_slice($arr['ksk_DNSKEY'], 3))); $ksk = new dns\dnssec\KSK(); $ksk->setId($arr['ksk_id'][0]); $ksk->setDnsKey($dnskey); $ksk->setExpires($arr['expiry'][0]); //ZSK $dnskey = new dns\record\type\DNSKEY(); $dnskey->setProtocol($arr['zsk_DNSKEY'][1]); $dnskey->setFlags($arr['zsk_DNSKEY'][0]); $dnskey->setAlgorithm($arr['zsk_DNSKEY'][2]); $dnskey->setPublicKey(implode(' ', array_slice($arr['zsk_DNSKEY'], 3))); $zsk = new dns\dnssec\ZSK(); $zsk->setId($arr['zsk_id'][0]); $zsk->setDnsKey($dnskey); $zsk->setExpires($arr['expiry'][0]); //DS $ds1 = new dns\record\type\DS($arr['DS'][3], $arr['DS'][4], $arr['DS'][5], $arr['DS'][6]); $ds2 = new dns\record\type\DS($arr['DS'][10], $arr['DS'][11], $arr['DS'][12], $arr['DS'][13]); //DNSSEC $dnssec = new dns\dnssec\DnsSec(); $dnssec->addKsk($ksk); $dnssec->addZsk($zsk); $dnssec->addDs($ds1); $dnssec->addDs($ds2); return $dnssec; } public function sign() { $this->get('CMD_API_DNS_ADMIN', array( 'action' => 'dnssec', 'generate_keys' => true, 'domain' => $this->domain )); $this->get('CMD_API_DNS_ADMIN', array( 'action' => 'dnssec', 'sign_zone' => true, 'domain' => $this->domain )); } public function rectify(){ $this->sign(); } public function unsign() { throw new exceptions\DNSSubmoduleException('DirectAdmin does not support unsign command.', dns\SubmoduleExceptionCodes::COMMAND_ERROR); } public function isSigned() { return $this->getDnsSecKeys() ? true : false; } protected function getDnsSecKeys() { return $this->get('CMD_API_DNS_ADMIN', array( 'action' => 'dnssec', 'value' => 'get_keys', 'domain' => $this->domain )); } }