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', ) ), 'ssl' => array( 'friendlyName' => 'SSL', 'type' => 'yesno', 'validators' => array( 'required' => 'required', ) ), 'port' => array( 'friendlyName' => 'Port', 'type' => 'number', 'value' => '8053', 'validators' => array( 'required' => 'required', ) ), 'httpauth' => array( 'friendlyName' => 'HTTP Auth Type', 'type' => 'select', 'options' => array(CURLAUTH_BASIC => 'BASIC', CURLAUTH_DIGEST => 'DIGEST'), ), 'ns1' => array( 'friendlyName' => 'Primary SOA DNS Server', 'validators' => array( 'required' => 'required', ) ), // 'ns2' => array( // 'friendlyName' => 'Secondary SOA DNS Server', // ), 'email' => array( 'friendlyName' => 'Email', 'type' => 'email', 'value' => 'change@me.com', 'validators' => array( 'required' => 'required', ) ), 'refresh' => array( 'friendlyName' => 'Refresh', 'type' => 'number', 'value' => '10800', 'validators' => array( 'min' => 1, 'required' => 'required', ) ), 'retry' => array( 'friendlyName' => 'Retry', 'type' => 'number', 'value' => '3600', 'validators' => array( 'min' => 1, 'required' => 'required', ) ), 'expire' => array( 'friendlyName' => 'Expire', 'type' => 'number', 'value' => '777600', 'validators' => array( 'min' => 1, 'required' => 'required', ) ), 'ttl' => array( 'friendlyName' => 'TTL', 'type' => 'number', 'value' => '360', 'validators' => array( 'min' => 1, 'required' => 'required', ) ), ); private $primaryDNS = ''; private $defaultTTL = ''; public $availableTypes = array('A', 'AAAA', 'NS', 'MX', 'CNAME', 'TXT', 'SRV', 'PTR'); /** * Connect to server using user query * @param type $function * @param type $params * @return boolean */ private function get($function, $params = array()) { $login = urlencode($this->config['username']); $password = $this->config['password']; $url = ($this->config['ssl'] == '1' ? 'https://'.$this->config['hostname'].':'.$this->config['port'] : 'http://'.$this->config['hostname'].':'.$this->config['port']).'/'.$function; $post = ''; if(is_array($params)) { foreach($params as $key => $value) { $value = urlencode($value); $post .= "{$key}={$value}&"; } } $ch = curl_init(); $chOptions = array ( CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_TIMEOUT => 30, CURLOPT_HEADER => 0, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $post, CURLOPT_USERPWD => $login.':'.$password, CURLOPT_HTTPAUTH => $this->config['httpauth'] ); curl_setopt_array($ch, $chOptions); $out = curl_exec($ch); curl_close($ch); if(curl_errno($ch) != 0 || $out === false) { throw new exceptions\DNSSubmoduleException('cURL error: ' . (curl_error($ch)?: 'Unknown Error'), dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM); } if(preg_match('/^\*(.)+\*$/', strtolower(trim($out)))) { throw new exceptions\DNSSubmoduleException(($out?:'Unknown Error'), dns\SubmoduleExceptionCodes::COMMAND_ERROR); } return $out; } private function addDot(dns\record\Record &$record) { if($record->type == 'CNAME' && $record->rdata->toString() == '@') { return; } if($record->type == 'SRV' || $record->type == 'MX' || $record->type == 'NS' || $record->type == 'CNAME' || $record->type == 'PTR') { $str = $record->rdata->toString(); $str = rtrim($str, '.') . '.'; $record->rdata->fromString($str); } } private function deleteDot(dns\record\Record &$record) { if($record->type == 'SRV' || $record->type == 'MX' || $record->type == 'NS' || $record->type == 'CNAME' || $record->type == 'PTR') { $record->value = rtrim($record->value, '.'); } } public function testConnection() { $login = urlencode($this->config['username']); $password = html_entity_decode($this->config['password']); $url = ($this->config['ssl'] == '1' ? 'https://'.$this->config['hostname'].':'.$this->config['port'].'/getzone?zone=mgdomain.com' : 'http://'.$this->config['hostname'].':'.$this->config['port']).'/getzone?zone=mgdomain.com'; $ch = curl_init(); $chOptions = array ( CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_TIMEOUT => 15, CURLOPT_HEADER => 0, CURLOPT_USERPWD => $login.':'.$password, CURLOPT_HTTPAUTH => $this->config['httpauth'] ); curl_setopt_array($ch, $chOptions); $out = curl_exec($ch); $info = curl_getinfo($ch); switch ($info['http_code']) { case 401: throw new exceptions\DNSSubmoduleException('Error: Invalid Connection Data', dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM); } if(strpos(strtolower($out), 'not found') !== false || strpos(strtoupper($out), 'IN SOA') !== false || strpos(strtolower($out), 'path does not exist') !== false ) { return true; } if(curl_errno($ch) != 0 || $out === false) { throw new exceptions\DNSSubmoduleException('cURL error: ' . (curl_error($ch)?: 'Unknown Error'), dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM); } else { throw new exceptions\DNSSubmoduleException('Error: '.$out, dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM); } } public function zoneExists() { try { $out = $this->get('zonelist', array()); $zones = explode("\n", trim($out)); foreach($zones as $zone) { if(trim(strtolower($zone)) == strtolower($this->domain)) { return true; } } return false; } catch( exceptions\DNSSubmoduleException $e) { if($e->getCode() == dns\SubmoduleExceptionCodes::COMMAND_ERROR) { return false; } throw $e; } } public function getRecords($recordType = false) { $out = $this->get('getzone', array( 'zone' => $this->domain )); $types = $this->availableTypes; $exploded = explode("\n", $out); foreach($exploded as $x){ if(strpos($x, 'TXT') === false) $zone[] = preg_replace('/(;.*)$/m', '', $x); else $zone[] = $x; } $records = array(); $line_number = -1; foreach($exploded as $line) { $line_number++; //find SOA if($this->primaryDNS == '') { if(strpos($line, 'SOA')) { $ex = explode("\t", trim($line)); $this->primaryDNS = trim(str_replace(array("(","\t",""),"", $ex[3]), "."); } //default TTL? if($this->defaultTTL == '' && strpos($line, '$TTL') !== false) { $ttl = (string)$line; $ex = explode(" ", trim($ttl)); $this->defaultTTL = trim($ex[1]); } } $pad = array_pad(preg_split("/[\s,]+/", $line), 4, ''); //two line record parser ;) $ex = array_merge(array_slice($pad,0, 4), array(implode(' ', array_slice($pad,4)))); if($ex[0] == '$TTL') { $defaultTTL = $ex[1]; } if(!is_numeric($ex[1])) { $name = $ex[0]; $ttl = $defaultTTL; $type = $ex[1]; $value = $type === 'MX' ? $ex[2].' '.$ex[3] : implode(' ', array_splice($ex, 2)); } else { $name = $ex[0]; $ttl = $ex[1]; $type = $ex[2]; $value = $type === 'MX' ? $ex[3].' '.$ex[4] : implode(' ', array_splice($ex, 3)); } if(empty($type)) { continue; } $type = strtoupper($type); if(!in_array($type, $recordType !== false ? array(strtoupper($recordType)) : $this->getAvailableRecordTypes()) ) { continue; } if($type === 'TXT' && !$name) { $reverseRecordsArray = array_reverse($records); foreach ($reverseRecordsArray as $record) { if($record->name) { $name = $record->name; break; } } } $record = new dns\record\Record(); $record->name = $name; $record->ttl = empty($ttl)?$this->defaultTTL:$ttl; $record->type = $type; $record->line = $line_number; $record->createRDATAObject(); $record->rdata->fromString(trim($value)); $this->deleteDot($record); $records[] = $record; } return $records; } private function recordToParamsArray(dns\record\Record $record) { $this->addDot($record); $relativeName = $record->nameToRelative($this->domain); return array( 'zone' => $this->domain, 'name' => empty($relativeName) ? '@' : $relativeName, 'type' => $record->type, 'ttl' => $record->ttl, 'data' => $record->rdata->toString(), ); } public function addRecord(dns\record\Record $record) { $ret = $this->get('addrecord', $this->recordToParamsArray($record)); if(strpos($ret, "OK") === false) { throw new exceptions\DNSSubmoduleException($ret, dns\SubmoduleExceptionCodes::COMMAND_ERROR); } } public function editRecord(dns\record\Record $record) { $recordsList = $this->getRecords(); foreach ($recordsList as $rec) { if($record->line == $rec->line) { $ret = $this->get('removerecord', $this->recordToParamsArray($rec)); if(strpos($ret, "OK") === false) { throw new exceptions\DNSSubmoduleException($ret, dns\SubmoduleExceptionCodes::COMMAND_ERROR); } $ret = $this->get('addrecord', $this->recordToParamsArray($record)); if(strpos($ret, "OK") === false) { throw new exceptions\DNSSubmoduleException($ret, dns\SubmoduleExceptionCodes::COMMAND_ERROR); } break; } } } /** * * @param type $data * @return boolean */ public function deleteRecord(dns\record\Record $record) { $ret = $this->get('removerecord', $this->recordToParamsArray($record)); if(strpos($ret, "OK") === false) { throw new exceptions\DNSSubmoduleException($ret, dns\SubmoduleExceptionCodes::COMMAND_ERROR); } } public function activateZone() { $data = "\$TTL ".$this->config['ttl']. "\n@ IN SOA\t(\t".$this->config['ns1'].".\n". str_replace('@', '.', $this->config['email']).".\n". time()."\n". $this->config['refresh']."\n". $this->config['retry']."\n". $this->config['expire']."\n". $this->config['ttl'].")\n". "\t".$this->config['ttl']."\tNS\t".$this->config['ns1'].".\n"; // if($this->config['ns2'] != '') //{ // $data.="\n\t".$this->config['ttl']."\tNS\t".$this->config['ns2'].".\n"; //} $this->get('updatezone', array( 'zone' => $this->domain, 'data' => $data )); if(!$this->zoneExists()) { throw new exceptions\DNSSubmoduleException('Cannot create zone', dns\SubmoduleExceptionCodes::COMMAND_ERROR); } } public function terminateZone() { $this->get('removezone', array( 'zone' => $this->domain )); if($this->zoneExists()) { throw new exceptions\DNSSubmoduleException('Cannot terminate zone', dns\SubmoduleExceptionCodes::COMMAND_ERROR); } } public function getZones() { $ret = $this->get('zonelist', array()); $zones = explode("\n", trim($ret)); $out = array(); foreach($zones as $zone) { $out[trim($zone)] = ''; } return $out; } }