[
'friendlyName' => 'Username',
'validators' => [
'required' => 'required',
]
],
'password' => [
'friendlyName' => 'User Password',
'type' => 'password',
'validators' => [
'required' => 'required',
]
],
'hostname' => [
'friendlyName' => 'Hostname/IP',
'validators' => [
'required' => 'required',
]
],
'database' => [
'friendlyName' => 'Database',
'validators' => [
'required' => 'required',
]
],
'ssh_host' => [
'friendlyName' => 'SSH Host',
'type' => 'text',
],
'ssh_username' => [
'friendlyName' => 'SSH User',
'type' => 'text',
],
'ssh_password' => [
'friendlyName' => 'SSH Password',
'type' => 'password',
],
'ssh_port' => [
'friendlyName' => 'SSH Port',
'type' => 'text'
],
'ssh_public_key' => [
'friendlyName' => 'SSH Public Key',
'type' => 'text',
],
'ssh_private_key' => [
'friendlyName' => 'SSH Private Key',
'type' => 'text',
],
'pdnsutil_path' => [
'friendlyName' => 'Path To PDNSUTIL',
'type' => 'text',
],
'default_ip' => [
'friendlyName' => 'Default IP',
'validators' => [
'required' => 'required',
'pattern' => Patterns::IP4_OR_IP6,
]
],
'soa_name' => [
'friendlyName' => 'Name',
'help' => '{$domain} will be repleaced with name of the domain',
],
'domain_type' => [
'friendlyName' => 'Domain Type',
'type' => 'select',
'options' => ['MASTER' => 'MASTER', 'SLAVE' => 'SLAVE', 'NATIVE' => 'NATIVE'],
],
'soa_primary' => [
'friendlyName' => 'Primary',
],
'soa_hostmaster' => [
'friendlyName' => 'Hostmaster',
],
'soa_refresh' => [
'friendlyName' => 'Refresh',
],
'soa_retry' => [
'friendlyName' => 'Retry',
],
'soa_expire' => [
'friendlyName' => 'Expire',
],
'soa_default_ttl' => [
'friendlyName' => 'Default TTL',
'type' => 'number',
],
'soa_ttl' => [
'friendlyName' => 'TTL',
'type' => 'number',
'value' => '555',
],
'soa_edit' => [
'friendlyName' => 'Allow To Edit SOA Records',
'type' => 'yesno'
],
'disable_validation' => [
'friendlyName' => 'Disable Records Validation',
'type' => 'yesno'
],
'disable_doubled' => [
'friendlyName' => 'Double Records',
'type' => 'yesno',
'help' => 'Select to enable creating double records'
],
'zone_account' => [
'friendlyName' => 'Zone Account',
],
'update_notified_serial' => [
'friendlyName' => 'Update Notified Serial',
'type' => 'yesno'
],
];
private $error;
private $ssh = null;
private $remote_db = null;
/** available records types * */
public $availableTypes = ['A', 'AAAA', 'NS', 'MX', 'CNAME', 'DNAME', 'TXT', 'SPF', 'SRV', 'PTR', 'SOA', 'CAA', 'AFSDB', 'ALIAS', 'DNSKEY', 'DS', 'HINFO', 'LOC', 'MINFO', 'MR', 'NAPTR', 'RP', 'RRSIG', 'WKS', 'URI', 'URL']; //LOC
public $typesCantBeDoubled = ['A', 'AAAA', 'SPF', 'SRV', 'PTR', 'SOA'];
public function __destruct()
{
$this->disconnect();
}
protected function validateIP()
{
if(empty($this->ip)) return false;
return (ip2long($this->ip) !== false);
}
private function mysql_safequery($query, $params = [] )
{
try
{
$this->connect();
$qsql = main\mgLibs\MySQL\query::debugQuery($query, $params);
$sql_query = main\mgLibs\MySQL\query::query($query, $params, 'pdns');
$this->disconnect();
$this->log('SQL: ' . $qsql);
}
catch( Exception $ex)
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException($ex, dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
return ($sql_query);
}
private function connect()
{
try
{
main\mgLibs\MySQL\query::createInstance([
'host' => $this->config['hostname'],
'user' => $this->config['username'],
'pass' => $this->config['password'],
'name' => $this->config['database']
]);
}
catch( Exception $ex)
{
throw new exceptions\DNSSubmoduleException('Unable to connect to the Power DNS database', dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
}
return true;
}
private function disconnect()
{
main\mgLibs\MySQL\query::dropInstance('pdns');
}
public function testConnection()
{
$this->log('TEST CONNECTION');
$this->connect();
$this->mysql_safequery('SELECT * FROM domains ');
$this->disconnect();
}
private function updateSoaSerial()
{
if (in_array($this->config['domain_type'], ['MASTER','NATIVE']) || preg_match('/in-addr.arpa$/', $this->domain))
{
$q = $this->mysql_safequery("SELECT r.id as record_id, r.content FROM records r JOIN domains d ON(r.domain_id = d.id) WHERE r.type = 'SOA' AND d.name = ?", [$this->domain]);
$row = $q->fetch();
$record_id = $row['record_id'];
$content = explode(' ', $row['content']);
if ($content[2])
{
$inc = (int) substr($content[2], 8, 2);
$current_date = date('Ymd');
$serial_current_date = substr($content[2], 0, 8);
$date = $serial_current_date === $current_date ? substr($content[2], 0, 8) : $current_date;
if ($serial_current_date !== $current_date)
{
$serial = $current_date . '00';
}
elseif ($inc === 99)
{
$serial = date('Ymd', strtotime($date) + (60 * 60 * 24)) . '00';
}
else
{
$inc++;
$serial = $date . ($inc <= 9 ? '0' . $inc : $inc);
}
}
if (!empty($serial))
{
$content[2] = $serial;
$this->mysql_safequery('UPDATE records SET content = ? WHERE id = ?', [implode(' ', $content), $record_id]);
}
}
}
private function updateNotifiedSerial()
{
if ($this->config['update_notified_serial'] === 'on')
{
$q = $this->mysql_safequery('SELECT notified_serial FROM domains WHERE name = ?', [$this->domain]);
$row = $q->fetch();
if ($row !== false)
{
$notified_serial = $row['notified_serial'];
if (empty($notified_serial))
{
$current_date = date('Ymd');
$serial = $current_date . '01';
}
else
{
$inc = (int) substr($notified_serial, 8, 2);
$current_date = date('Ymd');
$serial_current_date = substr($notified_serial, 0, 8);
$date = $serial_current_date == $current_date ? substr($notified_serial, 0, 8) : $current_date;
if ($serial_current_date !== $current_date)
{
$serial = $current_date . '01';
}
elseif ($inc === 99)
{
$serial = date('Ymd', strtotime($date) + (60 * 60 * 24)) . '01';
}
else
{
$inc += 2;
$serial = $date . ($inc <= 9 ? '0' . $inc : $inc);
}
}
$this->mysql_safequery('UPDATE domains SET notified_serial = ? WHERE name = ?', [$serial, $this->domain]);
}
}
}
public function zoneExists()
{
$this->log('CHECK ZONE EXIST');
$this->domain = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($this->domain);
if($this->connect())
{
$q = $this->mysql_safequery('SELECT name, account FROM domains WHERE name = ?', [$this->domain]);
$row = $q->fetch();
$this->disconnect();
return strtolower($row['name']) === strtolower($this->domain);
}
return false;
}
public function activateZone()
{
$this->log('ACTIVATE ZONE');
$this->domain = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($this->domain);
if ($this->zoneExists())
{
throw new exceptions\DNSSubmoduleException('Domain name already exists!', dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
if (empty($this->domain))
{
throw new exceptions\DNSSubmoduleException('Domain name is not valid!', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
if (preg_match('/in-addr.arpa$/', $this->domain))
{
$this->config['domain_type'] = 'MASTER';
}
if ($this->config['domain_type'] === 'SLAVE')
{
$ip = $this->ip == '' ? $this->config['default_ip'] : $this->ip;
if (!filter_var($ip, FILTER_VALIDATE_IP))
{
throw new exceptions\DNSSubmoduleException('This is not a valid IPv4 or IPv6 address.', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
}
if ($this->config['update_notified_serial'] === 'on' )
{
$current_date = date('Ymd');
$serial = $current_date . '00';
}
else
{
$serial = 0;
}
if ($this->connect())
{
if (in_array($this->config['domain_type'], ['MASTER','NATIVE']) || preg_match('/in-addr.arpa$/', $this->domain) || preg_match('/ip6.arpa$/', $this->domain))
{
if (!empty($this->config['zone_account']))
{
$args = [$this->domain, $serial, $this->config['zone_account']];
$query = "INSERT INTO domains (name, type, notified_serial, account) VALUES( ?, '" . $this->config['domain_type'] . "', ?, ? )";
}
else
{
$args = [$this->domain, $serial];
$query = "INSERT INTO domains (name, type, notified_serial) VALUES( ?, '" . $this->config['domain_type'] . "', ? )";
}
}
elseif(!empty($this->config['zone_account']))
{
$args = [$this->domain, $ip, $serial, $this->config['zone_account']];
$query = "INSERT INTO domains (name, type, master, notified_serial, account) VALUES( ?, 'SLAVE', ?, ?, ? )";
}
else
{
$args = [$this->domain, $ip, $serial];
$query = "INSERT INTO domains (name, type, master, notified_serial) VALUES( ?, 'SLAVE', ?, ?)";
}
if ($this->mysql_safequery($query, $args))
{
if ($this->config['domain_type'] === 'MASTER' || $this->config['domain_type'] === 'NATIVE' || preg_match('/in-addr.arpa$/', $this->domain) || preg_match('/ip6.arpa$/', $this->domain))
{
$to_search = ['{$domain}'];
$to_replace = [$this->domain];
$name = preg_match('/in-addr.arpa$/', $this->domain) || preg_match('/ip6.arpa$/', $this->domain) ? $this->domain : str_replace($to_search, $to_replace, $this->config['soa_name']);
if (preg_match('/in-addr.arpa$/', $this->domain) || preg_match('/ip6.arpa$/', $this->domain))
{
$content = $this->domain . ' ' . 'hostmaster.' . $this->domain . ' ' . date('Ymd') . '00' . ' ' . $this->config['soa_refresh'] . ' ' . $this->config['soa_retry'] . ' ' . $this->config['soa_expire'] . ' ' . $this->config['soa_default_ttl'];
}
else
{
$content = str_replace($to_search, $to_replace, $this->config['soa_primary']) . ' ' . str_replace($to_search, $to_replace, $this->config['soa_hostmaster']) . ' ' . date('Ymd') . '00' . ' ' . $this->config['soa_refresh'] . ' ' . $this->config['soa_retry'] . ' ' . $this->config['soa_expire'] . ' ' . $this->config['soa_default_ttl'];
}
$input = [
$this->domain,
$name,
'SOA',
$this->config['soa_ttl'],
time(),
$content
];
$this->mysql_safequery('INSERT INTO records (domain_id, name, type, ttl, prio, change_date, content) VALUES((SELECT id FROM domains WHERE name = ?), ?, ?, ?, 0, ?, ?)', $input);
}
$this->disconnect();
return true;
}
else
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException($this->remote_db->error, dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
}
return false;
}
public function terminateZone()
{
$this->domain = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($this->domain);
if (!$this->zoneExists())
{
throw new exceptions\DNSSubmoduleException('Domain name not exists!', dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
$this->log('TERMINATE ZONE');
if (empty($this->domain))
{
throw new exceptions\DNSSubmoduleException('Domain name is not valid!', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
if ($this->connect())
{
$q = $this->mysql_safequery('SELECT id FROM domains WHERE name = ?', [$this->domain]);
$row = $q->fetch();
if($this->mysql_safequery('DELETE FROM domains WHERE name = ?', [$this->domain]))
{
$this->mysql_safequery('DELETE FROM records WHERE domain_id = ?', [$row['id']]);
$this->disconnect();
return true;
}
else
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException($this->remote_db->error, dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
}
return false;
}
public function getRecords($recordType = false)
{
$this->log('GET RECORDS');
$out = [];
$this->domain = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($this->domain);
if ($this->connect())
{
$q = $this->mysql_safequery('SELECT r.id as record_id, r.name, r.type, r.ttl, r.prio, r.content FROM records r JOIN domains d ON(r.domain_id = d.id) WHERE d.name = ?', [$this->domain]);
while ($row = $q->fetch())
{
if ( !$recordType && $this->config['soa_edit'] !== 'on' && $row['type'] === 'SOA')
{
continue;
}
if ( in_array($row['type'], $recordType ? [strtoupper($recordType)] : $this->getAvailableRecordTypes(), true) )
{
$record = new dns\record\Record();
$record->line = $row['record_id'];
$record->name = rtrim($row['name'],'.') .'.';
$record->type = $row['type'];
$record->ttl = $row['ttl'];
$record->createRDATAObject();
if($record['type'] !=='TXT')
{
$row['content'] = main\mgLibs\custom\helpers\IdnaHelper::idnaDecode($row['content']);
}
switch ($row['type'])
{
case 'SRV':
$content = preg_split('/\s+/', $row['content']);
$record->rdata->priority = $row['prio'];
$record->rdata->weight = $content[0];
$record->rdata->port = $content[1];
$record->rdata->target = $content[2];
break;
case 'MX':
case 'URI':
$record->rdata->fromString($row['prio'] . ' ' . $row['content']);
break;
case 'DNSKEY':
$exploded = preg_split('/\s+/', $row['content']);
$newRecord['protocol'] = $exploded[0];
$newRecord['flags'] = $exploded[1];
$newRecord['algorithm'] = $exploded[2];
unset($exploded[0], $exploded[1], $exploded[2]);
$newRecord['publickey'] = implode(' ', $exploded);
$record->rdata->setDataFromArray($newRecord);
break;
default:
$record->rdata->fromString($row['content']);
break;
}
$out[] = $record;
}
}
$this->disconnect();
}
return $out;
}
public function addRecord(dns\record\Record $record)
{
$this->domain = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($this->domain);
if ( $record->type !== 'PTR' && (preg_match('/in-addr.arpa$/', $this->domain) || preg_match('/ip6.arpa$/', $this->domain)) )
{
throw new exceptions\DNSSubmoduleException('This record type (' . $record->type . ') is not allowe for rDNS zone', dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
switch ($record->type)
{
case 'MX':
$prio = $record->rdata->preference;
$value = $record->rdata->exchange;
break;
case 'SRV':
$prio = $record->rdata->priority;
$value = $record->rdata->toString(['weight', 'port', 'target']);
break;
case 'URI':
$prio = $record->rdata->priority;
$value = $record->rdata->toString(['weight', 'target']);
break;
case 'CNAME':
$prio = 0;
$value = rtrim($record->rdata->toString(), '.');
break;
default:
$prio = 0;
$value = $record->rdata->toString();
break;
}
$value = str_replace("\t", ' ', $value);
$value = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($value);
$input = [
strtolower($this->domain),
main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($record->nameToAbsolute($this->domain, false)),
$record->type,
$record->ttl,
$prio,
time(),
$value
];
$record->name = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($record->name);
$valid = $this->validate_input(false, $record->type, $value, $record->name, $prio, $record->ttl);
if ($valid === true)
{
$this->log('ADD RECORDS');
if ($this->connect())
{
if(empty($this->config['disable_doubled']) && in_array($record->type, $this->typesCantBeDoubled))
{
if($this->checkIfRecordSameExist($record))
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException('Such record alredy exists', dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
}
if ($this->mysql_safequery('INSERT INTO records (domain_id, name, type, ttl, prio, change_date, content) VALUES((SELECT id FROM domains WHERE LOWER(name) = ?), ?, ?, ?, ?, ?, ?)', $input))
{
$this->updateSoaSerial();
$this->updateNotifiedSerial();
$this->disconnect();
try
{
if($this->isSigned())
{
$this->rectify();
}
}
catch( Exception $ex)
{}
return true;
}
else
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException($this->remote_db->error, dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
}
else
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException('Connection problem', dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
}
}
else
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException('Validation error: ' . $this->error, dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
}
public function editRecord(dns\record\Record $record) //Prawie ctr + c -> ctrl + v
{
$this->domain = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($this->domain);
$record->name = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($record->name);
switch ($record->type)
{
case 'MX':
$prio = $record->rdata->preference;
$value = $record->rdata->exchange;
break;
case 'SRV':
$prio = $record->rdata->priority;
$value = $record->rdata->toString(['weight', 'port' , 'target']);
break;
case 'URI':
$prio = $record->rdata->priority;
$value = $record->rdata->toString(['weight', 'target']);
break;
case 'CNAME':
$prio = 0;
$value = rtrim($record->rdata->toString(), '.');
break;
default:
$prio = 0;
$value = $record->rdata->toString();
break;
}
$value = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($value);
$input = [
main\mgLibs\custom\helpers\IdnaHelper::idnaEncode( $record->nameToAbsolute($this->domain, false)),
$record->type,
$record->ttl,
$prio,
time(),
$value,
$record->line
];
$valid = $this->validate_input($record->line, $record->type, $value, $input[0], $prio, $record->ttl);
if ($valid === true)
{
$this->log('MODIFY RECORDS');
if ($this->connect())
{
if(empty($this->config['disable_doubled']) && in_array($record->type, $this->typesCantBeDoubled))
{
if($this->checkIfRecordSameExist($record))
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException('You cannot add two the same ' .$record->type. ' records', dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
}
if ($this->mysql_safequery('UPDATE records SET name = ?, type = ?, ttl = ?, prio = ?, change_date = ?, content = ? WHERE id = ?', $input))
{
$this->updateSoaSerial();
$this->updateNotifiedSerial();
$this->disconnect();
try
{
if($this->isSigned())
{
$this->rectify();
}
}
catch( Exception $ex)
{}
return true;
}
else
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException($this->remote_db->error, dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
}
else
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException('Connection problem', dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
}
}
else
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException('Validation error: ' . $this->error, dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
}
public function deleteRecord(dns\record\Record $record)
{
$this->domain = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($this->domain);
if ($this->connect())
{
if (strtoupper($record->type) == 'SOA')
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException('You can not remove the SOA record', dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
else
{
$q = $this->mysql_safequery('DELETE FROM records WHERE id = ?', [$record->line]);
$this->log('DELETE RECORD');
if ($q)
{
$this->updateSoaSerial();
$this->updateNotifiedSerial();
$this->disconnect();
try
{
if($this->isSigned())
{
$this->rectify();
}
}
catch( Exception $ex)
{}
return true;
}
else
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException('Error occured: ' . $this->remote_db->error, dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
}
}
else
{
$this->disconnect();
throw new exceptions\DNSSubmoduleException('Connection problem', dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
}
}
public function getZones()
{
$this->connect();
$q = $this->mysql_safequery('SELECT name, master FROM domains');
$this->log('GET ZONES');
$out = [];
while ($row = $q->fetch())
{
$out[$row['name']] = $row['master'];
}
$this->disconnect();
return $out;
}
/* * ****************************************
*
* VALIDATION
*
* **************************************** */
private function validate_input( $rid = false, $type, $content, $name, $prio, $ttl)
{
if ($this->config['disable_validation'] === 'on' || $type === 'PTR')
return true;
switch ($type)
{
case 'A':
if (!$this->is_valid_ipv4($content))
return false;
if (!$this->is_valid_rr_cname_exists($name, $rid))
return false;
if (!$this->is_valid_hostname_fqdn($name, 1))
return false;
break;
case 'AAAA':
if (!$this->is_valid_ipv6($content))
return false;
if (!$this->is_valid_rr_cname_exists($name, $rid))
return false;
if (!$this->is_valid_hostname_fqdn($name, 1))
return false;
break;
case 'CNAME':
if (!$this->is_valid_rr_cname_name($name))
return false;
if (!$this->is_valid_rr_cname_unique($name, $rid))
return false;
if (!$this->is_valid_hostname_fqdn($name, 1))
return false;
if (!$this->is_valid_hostname_fqdn($content, 0))
return false;
if (!$this->is_not_empty_cname_rr($name, $this->domain))
return false;
break;
case 'NS':
case 'MX':
if (!$this->is_valid_hostname_fqdn($content, 0))
return false;
if (!$this->is_valid_hostname_fqdn($name, 1))
return false;
if (!$this->is_valid_non_alias_target($content))
return false;
break;
case 'SOA':
if (!$this->is_valid_rr_soa_name($name, $this->domain))
return false;
if (!$this->is_valid_hostname_fqdn($name, 1))
return false;
if (!$this->is_valid_rr_soa_content($content))
return false;
break;
case 'SRV':
if (!$this->is_valid_rr_srv_name($name))
return false;
if (!$this->is_valid_rr_srv_content($content))
return false;
break;
case 'SPF':
case 'TXT':
if (!$this->is_valid_printable($name))
return false;
if (!$this->is_valid_printable(main\mgLibs\custom\helpers\IdnaHelper::idnaEncode(trim($content,'"'))))
return false;
break;
case 'LOC':
if (!$this->is_valid_loc($content))
return false;
if (!$this->is_valid_hostname_fqdn($name, 1))
return false;
break;
case 'CAA':
if(!$this->is_valid_caa($content))
return false;
break;
//2.9.0
case 'ALIAS':
if (!$this->is_valid_hostname_fqdn($name, 0))
return false;
if (!$this->is_valid_caa_target($content))
return false;
break;
case 'AFSDB':
if (!$this->is_valid_hostname_fqdn($name, 0))
return false;
if (!$this->is_valid_afsdb_record($content))
return false;
break;
case 'WKS':
if (!$this->is_valid_hostname_fqdn($name, 0))
return false;
if (!$this->is_valid_wks_record($content))
return false;
break;
case 'RP':
case 'NAPTR':
case 'MR':
case 'MINFO':
case 'HINFO':
case 'DS':
case 'DNSKEY':
case 'DNAME':
case 'RRSIG':
if (!$this->is_valid_hostname_fqdn($name, 0))
return false;
break;
case 'URL':
break;
default:
$this->error = ERR_DNS_RR_TYPE;
return false;
}
if (!$this->is_valid_rr_prio($prio, $type))
return false;
if (!$this->is_valid_rr_ttl($ttl))
return false;
return true;
}
private function is_valid_hostname_fqdn($hostname, $wildcard)
{
$hostname = main\mgLibs\custom\helpers\IdnaHelper::idnaEncode($hostname);
$dns_strict_tld_check = false;
$valid_tlds = false;
$hostname = preg_replace("/\.$/", '', $hostname);
# The full domain name may not exceed a total length of 253 characters.
if (strlen($hostname) > 253)
{
$this->error = ERR_DNS_HN_TOO_LONG;
return false;
}
$hostname_labels = explode('.', $hostname);
$label_count = count($hostname_labels);
if ($label_count == 1)
{
$this->error = ERR_DNS_HN_LENGTH;
return false;
}
foreach ($hostname_labels as
$hostname_label)
{
if ($wildcard == 1 && !isset($first))
{
if (!preg_match('/^(\*|[\w\-\/]+)$/', $hostname_label))
{
$this->error = ERR_DNS_HN_INV_CHARS;
return false;
}
$first = 1;
}
else
{
if (!preg_match('/^[\w\-\/]+$/', $hostname_label))
{
$this->error = ERR_DNS_HN_INV_CHARS;
return false;
}
}
if ( strpos($hostname_label, '-') === 0 )
{
$this->error = ERR_DNS_HN_DASH;
return false;
}
if (substr($hostname_label, -1, 1) === '-' )
{
$this->error = ERR_DNS_HN_DASH;
return false;
}
if ( $hostname_label === '' || strlen($hostname_label) > 63)
{
$this->error = ERR_DNS_HN_LENGTH;
return false;
}
}
if ($hostname_labels[$label_count - 1] === 'arpa' && (substr_count($hostname_labels[0], '/') === 1 XOR substr_count($hostname_labels[1], '/') === 1))
{
if (substr_count($hostname_labels[0], '/') === 1)
{
$array = explode('/', $hostname_labels[0]);
}
else
{
$array = explode('/', $hostname_labels[1]);
}
if (count($array) !== 2)
{
$this->error = ERR_DNS_HOSTNAME;
return false;
}
if (!is_numeric($array[0]) || $array[0] < 0 || $array[0] > 255)
{
$this->error = ERR_DNS_HOSTNAME;
return false;
}
if (!is_numeric($array[1]) || $array[1] < 25 || $array[1] > 31)
{
$this->error = ERR_DNS_HOSTNAME;
return false;
}
}
else
{
if (substr_count($hostname, '/') > 0)
{
$this->error = ERR_DNS_HN_SLASH;
return false;
}
}
if ($dns_strict_tld_check && !in_array(strtolower($hostname_labels[$label_count - 1]), $valid_tlds))
{
$this->error = ERR_DNS_INV_TLD;
return false;
}
return true;
}
private function is_valid_ipv4($ipv4, $answer = true)
{
if (!preg_match('/^[0-9.]{7,15}$/', $ipv4))
{
if ($answer)
{
$this->error = ERR_DNS_IPV4;
}
return false;
}
$quads = explode('.', $ipv4);
$numquads = count($quads);
if ($numquads !== 4)
{
if ($answer)
{
$this->error = ERR_DNS_IPV4;
}
return false;
}
for ($i = 0;
$i < 4;
$i++)
{
if ($quads[$i] > 255)
{
if ($answer)
{
$this->error = ERR_DNS_IPV4;
}
return false;
}
}
return true;
}
private function is_valid_ipv6($ipv6, $answer = true)
{
if (!preg_match('/^[0-9a-f]{0,4}:([0-9a-f]{0,4}:){0,6}[0-9a-f]{0,4}$/i', $ipv6))
{
if ($answer)
{
$this->error = ERR_DNS_IPV6;
}
return false;
}
$quads = explode(':', $ipv6);
$numquads = count($quads);
if ($numquads > 8 || $numquads < 3)
{
if ($answer)
{
$this->error = ERR_DNS_IPV6;
}
return false;
}
$emptyquads = 0;
for ($i = 1;
$i < $numquads - 1;
$i++)
{
if ($quads[$i] == '' )
$emptyquads++;
}
if ($emptyquads > 1)
{
if ($answer)
{
$this->error = ERR_DNS_IPV6;
}
return false;
}
if ($emptyquads === 0 && $numquads !== 8)
{
if ($answer)
{
$this->error = ERR_DNS_IPV6;
}
return false;
}
return true;
}
private function is_valid_printable($string)
{
if (!preg_match('/^[[:print:]]+$/', trim($string)))
{
$this->error = ERR_DNS_PRINTABLE;
return false;
}
return true;
}
private function is_valid_afsdb_record($string)
{
$record = explode(' ', $string);
if (!$this->is_valid_hostname_fqdn($record[1], 1)){
return false;
}
if(!$this->is_valid_subtype($record[0])){
return false;
}
return true;
}
private function is_valid_subtype($type){
if($type == 1 || $type == 2){
return true;
}
$this->error = ERR_DNS_SUBTYPE;
return false;
}
private function is_valid_wks_record($string)
{
$record = explode(' ', $string);
if (!$this->is_valid_ipv4($record[0])){
return false;
}
return true;
}
private function is_valid_rr_cname_name($name)
{
if ($this->connect())
{
$q = $this->mysql_safequery("SELECT type, content FROM records WHERE content = ? AND (type = 'MX' OR type = 'NS')", [
$name
]);
if ($q !== false)
{
if($q->numRows() > 0)
{
$this->error = ERR_DNS_CNAME;
return false;
}
}
else
{
$this->error = 'Power DNS database error: ' . $this->remote_db->error;
return false;
}
$this->disconnect();
}
else
{
$this->error = 'Unable connect to Power DNS database';
return false;
}
return true;
}
private function is_valid_rr_cname_exists($name, $rid)
{
if ($this->connect())
{
$args[] = $name;
if ($rid > 0)
{
$where = ' AND id != ? ';
$args[] = $rid;
}
else
{
$where = '';
}
$q = $this->mysql_safequery('SELECT type, name FROM records WHERE name = ?' . $where . " AND TYPE = 'CNAME'", $args);
if($q !== false)
{
if($q->numRows() > 0)
{
$this->error = ERR_DNS_CNAME_EXISTS;
return false;
}
}
else
{
$this->error = 'Power DNS database error: ' . $this->remote_db->error;
return false;
}
$this->disconnect();
}
else
{
$this->error = 'Unable connect to Power DNS database';
return false;
}
return true;
}
private function is_valid_rr_cname_unique($name, $rid)
{
if ($this->connect())
{
$args[] = $name;
if ($rid > 0)
{
$where = ' AND id != ? ';
$args[] = $rid;
}
else
{
$where = '';
}
$q = $this->mysql_safequery('SELECT * FROM records WHERE name = ? ' . $where . " AND TYPE IN ('A', 'AAAA', 'CNAME')", $args);
if ($q !== false)
{
if($q->numRows() > 0)
{
$this->error = ERR_DNS_CNAME_UNIQUE;
return false;
}
}
else
{
$this->error = 'Power DNS database error: ' . $this->remote_db->error;
return false;
}
$this->disconnect();
}
else
{
$this->error = 'Unable connect to Power DNS database';
return false;
}
return true;
}
private function is_not_empty_cname_rr($name, $zone)
{
if ($name == $zone)
{
$this->error = ERR_DNS_CNAME_EMPTY;
return false;
}
return true;
}
private function is_valid_non_alias_target($target)
{
if ($this->connect())
{
$q = $this->mysql_safequery("SELECT type, name FROM records WHERE name = ? AND TYPE = 'CNAME'", [
$target
]);
if ($q !== false)
{
if($q->numRows() > 0)
{
$this->error = ERR_DNS_NON_ALIAS_TARGET;
return false;
}
}
else
{
$this->error = 'Power DNS database error: ' . $this->remote_db->error;
return false;
}
$this->disconnect();
}
else
{
$this->error = 'Unable connect to Power DNS database';
return false;
}
return true;
}
private function is_valid_rr_soa_content($content)
{
$fields = preg_split("/\s+/", trim($content));
$field_count = count($fields);
if ($field_count == 0 || $field_count > 7)
{
return false;
}
else
{
if (!$this->is_valid_hostname_fqdn($fields[0], 0) || preg_match('/\.arpa\.?$/', $fields[0]))
{
return false;
}
$final_soa = $fields[0];
if (isset($fields[1]))
{
$addr_input = $fields[1];
}
else
{
global $dns_hostmaster;
$addr_input = $dns_hostmaster;
}
if (!preg_match('/@/', $addr_input))
{
$addr_input = preg_split('/(?is_valid_email($addr_to_check))
{
return false;
}
else
{
$addr_final = explode('@', $addr_to_check, 2);
$final_soa .= ' ' . str_replace('.', "\\.", $addr_final[0]) . '.' . $addr_final[1];
}
if (isset($fields[2]))
{
if (!is_numeric($fields[2]))
{
return false;
}
$final_soa .= ' ' . $fields[2];
}
else
{
$final_soa .= ' 0';
}
if ($field_count == 7)
{
for ($i = 3;
($i < 7);
$i++)
{
if (!is_numeric($fields[$i]))
{
return false;
}
else
{
$final_soa .= ' ' . $fields[$i];
}
}
}
}
$content = $final_soa;
return true;
}
private function is_valid_email($addr)
{
if (filter_var($addr, FILTER_VALIDATE_EMAIL) === false)
{
$this->error = ERR_INV_EMAIL;
return false;
}
else
{
return true;
}
}
private function is_valid_rr_soa_name($name, $zone)
{
$zone = rtrim($zone,'.').'.';
$name = rtrim($name,'.').'.';
if ($name != $zone)
{
$this->error = ERR_DNS_SOA_NAME;
return false;
}
return true;
}
private function is_valid_rr_prio(&$prio, $type)
{
if ($type == 'MX' || $type == 'SRV' )
{
if (!is_numeric($prio) || $prio < 0 || $prio > 65535)
{
$this->error = ERR_DNS_INV_PRIO;
return false;
}
}
else
{
$prio = 0;
}
return true;
}
private function is_valid_rr_srv_name(&$name)
{
if (strlen($name) > 255)
{
$this->error = ERR_DNS_HN_TOO_LONG;
return false;
}
$fields = explode('.', $name, 3);
if (!preg_match('/^_[\w-]+$/', $fields[0]))
{
$this->error = ERR_DNS_SRV_NAME;
return false;
}
if (!preg_match('/^_[\w]+$/', $fields[1]))
{
$this->error = ERR_DNS_SRV_NAME;
return false;
}
if (!$this->is_valid_hostname_fqdn($fields[2], 0))
{
$this->error = ERR_DNS_SRV_NAME;
return false;
}
$name = implode('.', $fields);
return true;
}
private function is_valid_rr_srv_content(&$content)
{
$fields = preg_split("/\s+/", trim($content), 3);
if (!is_numeric($fields[0]) || $fields[0] < 0 || $fields[0] > 65535)
{
$this->error = ERR_DNS_SRV_WGHT;
return false;
}
if (!is_numeric($fields[1]) || $fields[1] < 0 || $fields[1] > 65535)
{
$this->error = ERR_DNS_SRV_PORT;
return false;
}
if ($fields[2] === '' || ($fields[2] !== '.' && !$this->is_valid_hostname_fqdn($fields[2], 0)))
{
$this->error = ERR_DNS_SRV_TRGT;
return false;
}
$content = implode(' ', $fields);
return true;
}
private function is_valid_rr_ttl(&$ttl)
{
if (!isset($ttl) || $ttl == '' )
{
global $dns_ttl;
$ttl = $dns_ttl;
}
if (!is_numeric($ttl) || $ttl < 0 || $ttl > 2147483647)
{
$this->error = ERR_DNS_INV_TTL;
return false;
}
return true;
}
private function is_valid_loc($content)
{
$regex = "^(90|[1-8]\d|0?\d)( ([1-5]\d|0?\d)( ([1-5]\d|0?\d)(\.\d{1,3})?)?)? [NS] (180|1[0-7]\d|[1-9]\d|0?\d)( ([1-5]\d|0?\d)( ([1-5]\d|0?\d)(\.\d{1,3})?)?)? [EW] (-(100000(\.00)?|\d{1,5}(\.\d\d)?)|([1-3]?\d{1,7}(\.\d\d)?|4([01][0-9]{6}|2([0-7][0-9]{5}|8([0-3][0-9]{4}|4([0-8][0-9]{3}|9([0-5][0-9]{2}|6([0-6][0-9]|7[01]))))))(\.\d\d)?|42849672(\.([0-8]\d|9[0-5]))?))[m]?( (\d{1,7}|[1-8]\d{7})(\.\d\d)?[m]?){0,3}$^";
if (!preg_match($regex, $content))
{
return false;
}
else
{
return true;
}
}
private function is_valid_caa($content)
{
$vars = explode(' ',$content);
if($this->is_valid_caa_flag($vars[0]) && $this->is_valid_caa_tag($vars[1]) && $this->is_valid_caa_target($vars[2]))
{
return true;
}
return false;
}
private function is_valid_caa_flag($flag)
{
if(is_numeric($flag) && $flag >= 0 && $flag <= 255)
{
return true;
}
$this->error = ERR_DNS_CAA_FLAG;
return false;
}
private function is_valid_caa_tag($tag)
{
return is_string($tag);
}
private function is_valid_caa_target($target)
{
if($target[0] === '"' && $target[strlen($target) - 1] === '"')
{
return true;
}
$this->error = ERR_DNS_CAA_TARGET;
return false;
}
/**********************************************
* DNS SEC
*********************************************/
public function generateSignKeys()
{
}
/**
*
* @return DnsSec
*/
public function getSignKeys()
{
$dnssec = new DnsSec();
$command = $this->pdnsutil("show-zone $this->domain");
$keys = array_filter(explode("\n", substr($command['stdio'], strpos($command['stdio'], 'keys:')+5)));
foreach($keys as $index => $key)
{
if(strpos($key, 'DS') === 0)
{
$ex = preg_split('/\s+/', $key);
$ds = new dns\record\type\DS();
$ds->setKeytag($ex[5]);
$ds->setAlgorithm($ex[6]);
$ds->setDigestType($ex[7]);
$ds->setDigest($ex[8]);
$dnssec->addDs($ds);
}
elseif(strpos($key, 'CSK DNSKEY') === 0)
{
$ex = preg_split('/\s+/', $key);
$dnskey = new dns\record\type\DNSKEY();
$dnskey->setFlags($ex[6]);
$dnskey->setProtocol($ex[7]);
$dnskey->setAlgorithm($ex[8]);
$dnskey->setPublicKey($ex[9]);
$ex = array_map(function($field){return explode('=', $field);}, explode(',', $keys[$index-1]));
$ex = array_map(function($field){return [trim($field[0]) => trim($field[1])];}, $ex);
$zoneKey = new dns\dnssec\CSK();
$zoneKey->setId((int)$ex[2]['tag']);
$zoneKey->setBits((int)$ex[4]['bits']);
$zoneKey->setDnsKey($dnskey);
$dnssec->addKey($zoneKey);
}
elseif(strpos($key, 'KSK DNSKEY') === 0)
{
$ex = preg_split('/\s+/', $key);
$dnskey = new dns\record\type\DNSKEY();
$dnskey->setFlags($ex[6]);
$dnskey->setProtocol($ex[7]);
$dnskey->setAlgorithm($ex[8]);
$dnskey->setPublicKey($ex[9]);
$dnskey2 = new dns\record\type\DNSKEY();
$dnskey2->setFlags($ex[6]);
$dnskey2->setProtocol($ex[7]);
$dnskey2->setAlgorithm($ex[8]);
$ex = array_map(function($field){return explode('=', $field);}, explode(',', $keys[$index-1]));
$ex = array_map(function($field){return [trim($field[0]) => trim($field[1])];}, $ex);
$ksk = new dns\dnssec\KSK();
$ksk->setId((int)$ex[2]['tag']);
$ksk->setBits((int)$ex[4]['bits']);
$ksk->setDnsKey($dnskey);
$ex = array_map(function($field){return explode('=', $field);}, explode(',', $keys[$index-2]));
$ex = array_map(function($field){return [trim($field[0]) => trim($field[1])];}, $ex);
$zsk = new dns\dnssec\ZSK();
$zsk->setId((int)$ex[2]['tag']);
$zsk->setBits((int)$ex[4]['bits']);
$zsk->setDnsKey($dnskey2);
$dnssec->addKey($ksk);
$dnssec->addKey($zsk);
}
}
return $dnssec;
}
public function isSigned()
{
$command = $this->pdnsutil("show-zone $this->domain");
if(stripos($command['stderr'], 'No keys for zone') !== false)
{
return false;
}
return true;
}
public function sign()
{
$command = $this->pdnsutil("secure-zone $this->domain", false);
$match = preg_match("/Zone {$this->domain}\.? secured/", $command['stdio']);
if(!$match && $command['stderr'])
{
throw new exceptions\DNSSubmoduleException($command['stderr'], dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
}
public function unsign()
{
$command = $this->pdnsutil("disable-dnssec $this->domain");
if(!empty($command['stderr']))
{
throw new exceptions\DNSSubmoduleException($command['stderr'], dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
}
public function rectify()
{
$command = $this->pdnsutil("rectify-zone $this->domain");
if(!empty($command['stderr']) && stripos($command['stderr'], 'Adding NSEC') === false)
{
throw new exceptions\DNSSubmoduleException($command['stderr'], dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
}
protected function connectSSH()
{
if(!function_exists('ssh2_connect'))
{
throw new exceptions\DNSSubmoduleException('Cannot find SSH2 for PHP. Please install SSH2 extension', dns\SubmoduleExceptionCodes::COMMAND_ERROR);
}
if(empty($this->config['ssh_host']))
{
throw new exceptions\DNSSubmoduleException('SSH Host field is empty. Cannot connect to server', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
if(empty($this->config['ssh_username']))
{
throw new exceptions\DNSSubmoduleException('SSH Username field is empty. Cannot connect to server', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
if(empty($this->config['ssh_password']) && (empty($this->config['ssh_public_key']) && empty($this->config['ssh_private_key'])))
{
throw new exceptions\DNSSubmoduleException('SSH Password or SSH Key field is empty. Cannot connect to server', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
if(empty($this->config['ssh_port']))
{
throw new exceptions\DNSSubmoduleException('SSH Port field is empty. Cannot connect to server', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
$this->ssh = ssh2_connect($this->config['ssh_host'], $this->config['ssh_port']);
if(!$this->ssh)
{
throw new exceptions\DNSSubmoduleException('Cannot connect to SSH', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
if(!empty($this->config['ssh_public_key']) && !empty($this->config['ssh_private_key']))
{
$sshPublicKey =
$this->config['ssh_public_key'][0] === '/'
? $this->config['ssh_public_key']
: ROOTDIR.DIRECTORY_SEPARATOR.'ssh_keys'.DIRECTORY_SEPARATOR.$this->config['ssh_public_key'];
$shhPrivateKey =
$this->config['ssh_private_key'][0] === '/'
? $this->config['ssh_private_key']
: ROOTDIR.DIRECTORY_SEPARATOR.'ssh_keys'.DIRECTORY_SEPARATOR.$this->config['ssh_private_key'];
if(!file_get_contents($sshPublicKey)) {
throw new exceptions\DNSSubmoduleException('SSH public key file does not exist at path: ' . $sshPublicKey, dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
if(!file_get_contents($shhPrivateKey)) {
throw new exceptions\DNSSubmoduleException('SSH private key file does not exist at path: ' . $shhPrivateKey, dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
$auth = ssh2_auth_pubkey_file($this->ssh, $this->config['ssh_username'], $sshPublicKey, $shhPrivateKey);
if(!$auth)
{
$this->ssh = null;
throw new exceptions\DNSSubmoduleException('Cannot login to server (SSH). Check your credentials', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
}
else
{
$auth = ssh2_auth_password($this->ssh, $this->config['ssh_username'], $this->config['ssh_password']);
if(!$auth)
{
$this->ssh = null;
throw new exceptions\DNSSubmoduleException('Cannot login to server. Check your credentials', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
}
}
protected function pdnsutil($command = '', $throwErrorWhenStdErr = true)
{
if(!$this->ssh)
{
$this->connectSSH();
}
if(!$this->config['pdnsutil_path'])
{
throw new exceptions\DNSSubmoduleException('PDNSUTIL path empty. Cannot run command', dns\SubmoduleExceptionCodes::INVALID_PARAMETERS);
}
$pdnsutil = $this->config['pdnsutil_path'];
$stream = ssh2_exec($this->ssh, $pdnsutil.' '.$command);
$errorStream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);
stream_set_blocking($errorStream, true);
stream_set_blocking($stream, true);
$streamContent = stream_get_contents($stream);
$errorStreamContent = stream_get_contents($errorStream);
// Close the streams
fclose($errorStream);
fclose($stream);
return
[
'stdio' => $streamContent,
'stderr' => $errorStreamContent
];
}
public function checkIfRecordSameExist($record)
{
if(empty($record->line))
{
$res = $this->mysql_safequery('SELECT id, name, content FROM records WHERE domain_id = (SELECT id FROM domains WHERE LOWER(name) = ?) AND type = ? AND name = ?',
[strtolower($this->domain), $record->type, $record->name]);
}
else
{
$res = $this->mysql_safequery('SELECT id, name, content FROM records WHERE domain_id = (SELECT id FROM domains WHERE name = ?) AND type = ? AND name = ? AND id != ?',
[$this->domain, $record->type, $record->name, $record->line]);
}
return $res->numRows() > 0;
}
public function validateRecord($record)
{
if($this->server->getModuleConfiguration()['disable_validation'] !== 'on') {
parent::validateRecord($record);
}
}
}
$messages_file = substr(__DIR__, 0, strpos(__DIR__, '' . DIRECTORY_SEPARATOR . 'includes')) . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . 'addons' . DIRECTORY_SEPARATOR . 'dns_manager' . DIRECTORY_SEPARATOR . 'powerdns_messages.php';
if (file_exists($messages_file))
{
require_once($messages_file);
}
else
{
define('ERR_PERM_SEARCH', 'You do not have the permission to perform searches.');
define('ERR_PERM_ADD_RECORD', 'You do not have the permission to add a record to this zone.');
define('ERR_PERM_EDIT_RECORD', 'You do not have the permission to edit this record.');
define('ERR_PERM_VIEW_RECORD', 'You do not have the permission to view this record.');
define('ERR_PERM_DEL_RECORD', 'You do not have the permission to delete this record.');
define('ERR_PERM_ADD_ZONE_MASTER', 'You do not have the permission to add a master zone.');
define('ERR_PERM_ADD_ZONE_SLAVE', 'You do not have the permission to add a slave zone.');
define('ERR_PERM_DEL_ZONE', 'You do not have the permission to delete a zone.');
define('ERR_PERM_VIEW_COMMENT', 'You do not have the permission to view this comment.');
define('ERR_PERM_EDIT_COMMENT', 'You do not have the permission to edit this comment.');
define('ERR_PERM_DEL_SM', 'You do not have the permission to delete a supermaster.');
define('ERR_PERM_VIEW_ZONE', 'You do not have the permission to view this zone.');
define('ERR_PERM_EDIT_USER', 'You do not have the permission to edit this user.');
define('ERR_PERM_EDIT_PERM_TEMPL', 'You do not have the permission to edit permission templates.');
define('ERR_PERM_DEL_PERM_TEMPL', 'You do not have the permission to delete permission templates.');
define('ERR_PERM_ADD_USER', 'You do not have the permission to add a new user.');
define('ERR_PERM_DEL_USER', 'You do not have the permission to delete this user.');
define('ERR_PERM_EDIT_ZONE_TEMPL', 'You do not have the permission to edit zone templates.');
define('ERR_PERM_DEL_ZONE_TEMPL', 'You do not have the permission to delete zone templates.');
define('ERR_PERM_ADD_ZONE_TEMPL', 'You do not have the permission to add a zone template.');
/* DOMAIN STUFF */
define('ERR_DOMAIN_INVALID', 'This is an invalid zone name.');
define('ERR_SM_EXISTS', 'There is already a supermaster with this IP address and hostname.');
define('ERR_DOMAIN_EXISTS', 'There is already a zone with this name.');
/* USER STUFF */
define('ERR_USER_EXIST', 'Username exist already, please choose another one.');
define('ERR_USER_NOT_EXIST', 'User does not exist.');
define('ERR_USER_WRONG_CURRENT_PASS', 'You did not enter the correct current password.');
define('ERR_USER_MATCH_NEW_PASS', 'The two new password fields do not match.');
define('ERR_PERM_TEMPL_ASSIGNED', 'This template is assigned to at least one user.');
/* OTHER */
define('ERR_INV_INPUT', 'Invalid or unexpected input given.');
define('ERR_INV_ARG', 'Invalid argument(s) given to function %s');
define('ERR_INV_ARGC', 'Invalid argument(s) given to function %s %s');
define('ERR_UNKNOWN', 'Unknown error.');
define('ERR_INV_EMAIL', 'Enter a valid email address.');
define('ERR_ZONE_NOT_EXIST', 'There is no zone with this ID.');
define('ERR_REVERS_ZONE_NOT_EXIST', 'There is no matching reverse-zone for: %s.');
define('ERR_ZONE_TEMPL_NOT_EXIST', 'There is no zone template with this ID.');
define('ERR_INSTALL_DIR_EXISTS', 'The install/ directory exists, you must remove it first before proceeding.');
define('ERR_ZONE_TEMPL_EXIST', 'Zone template with this name already exists, please choose another one.');
define('ERR_ZONE_TEMPL_IS_EMPTY', 'Template name can\'t be an empty string.');
define('ERR_DEFAULT_CRYPTOKEY_USED', 'Default session encryption key is used, please set it in your configuration file.');
define('ERR_LOCALE_FAILURE', 'Failed to set locale.');
define('ERR_ZONE_UPD', 'Zone has not been updated successfully.');
define('ERR_EXEC_NOT_ALLOWED', 'Failed to call function exec. Make sure that exec is not listed in disable_functions at php.ini');
/* DATABASE */
define('ERR_DB_NO_DB_NAME', 'No database name has been set in config.inc.php.');
define('ERR_DB_NO_DB_HOST', 'No database host has been set in config.inc.php.');
define('ERR_DB_NO_DB_USER', 'No database username has been set in config.inc.php.');
define('ERR_DB_NO_DB_PASS', 'No database password has been set in config.inc.php.');
define('ERR_DB_NO_DB_TYPE', 'No or unknown database type has been set in config.inc.php.');
define('ERR_DB_NO_DB_FILE', 'No database file has been set in config.inc.php.');
define('ERR_DB_NO_DB_UPDATE', 'It seems that you forgot to update the database after Poweradmin upgrade to new version.');
define('ERR_DB_UNK_TYPE', 'Unknown database type.');
/* DNS */
define('ERR_DNS_CONTENT', 'Your content field doesnt have a legit value.');
define('ERR_DNS_HOSTNAME', 'Invalid hostname.');
define('ERR_DNS_HN_INV_CHARS', 'You have invalid characters in your hostname.');
define('ERR_DNS_HN_INV_CONTENT', 'Invalid content.');
define('ERR_DNS_HN_DASH', 'A hostname can not start or end with a dash.');
define('ERR_DNS_HN_LENGTH', 'Given hostname or one of the labels is too short or too long.');
define('ERR_DNS_HN_SLASH', 'Given hostname has too many slashes.');
define('ERR_DNS_RR_TYPE', 'Unknown record type.');
define('ERR_DNS_IP', 'This is not a valid IPv4 or IPv6 address.');
define('ERR_DNS_IPV6', 'This is not a valid IPv6 address.');
define('ERR_DNS_IPV4', 'This is not a valid IPv4 address.');
define('ERR_DNS_CNAME', 'This is not a valid CNAME. Did you assign an MX or NS record to the record?');
define('ERR_DNS_CNAME_EXISTS', 'This is not a valid record. There is already exists a CNAME with this name.');
define('ERR_DNS_CNAME_UNIQUE', 'This is not a valid CNAME. There is already exists an A, AAAA or CNAME with this name.');
define('ERR_DNS_CNAME_EMPTY', 'Empty CNAME records are not allowed.');
define('ERR_DNS_NON_ALIAS_TARGET', 'You can not point a NS or MX record to a CNAME record. Remove or rame the CNAME record first, or take another name.');
define('ERR_DNS_NS_HNAME', 'NS records must be a hostnames.');
define('ERR_DNS_MX_PRIO', 'A prio field should be numeric.');
define('ERR_DNS_SOA_NAME', 'Invalid value for name field of SOA record. It should be the name of the zone.');
define('ERR_DNS_SOA_MNAME', 'You have an error in the MNAME field of the SOA record.');
define('ERR_DNS_HINFO_INV_CONTENT', 'Invalid value for content field of HINFO record.');
define('ERR_DNS_HN_TOO_LONG', 'The hostname is too long.');
define('ERR_DNS_INV_TLD', 'You are using an invalid top level domain.');
define('ERR_DNS_INV_TTL', 'Invalid value for TTL field. It should be numeric.');
define('ERR_DNS_INV_PRIO', 'Invalid value for prio field. It should be numeric.');
define('ERR_DNS_SRV_NAME', 'Invalid value for name field of SRV record.');
define('ERR_DNS_SRV_WGHT', 'Invalid value for the priority field of the SRV record.');
define('ERR_DNS_SRV_PORT', 'Invalid value for the weight field of the SRV record.');
define('ERR_DNS_SRV_TRGT', 'Invalid SRV target.');
define('ERR_DNS_PRINTABLE', 'Invalid characters have been used in this record.');
define('ERR_DNS_CAA_FLAG', 'Invalid flag value.');
define('ERR_DNS_CAA_TARGET', 'Target has to be in " "');
/* PDNSSEC */
define('ERR_EXEC_PDNSSEC', 'Failed to call pdnssec utility.');
define('ERR_EXEC_PDNSSEC_SECURE_ZONE', 'Failed to secure zone.');
define('ERR_EXEC_PDNSSEC_RECTIFY_ZONE', 'Failed to rectify zone.');
/* GOOD! */
define('SUC_ZONE_ADD', 'Zone has been added successfully.');
define('SUC_ZONE_DEL', 'Zone has been deleted successfully.');
define('SUC_ZONE_UPD', 'Zone has been updated successfully.');
define('SUC_ZONES_UPD', 'Zones have been updated successfully.');
define('SUC_USER_UPD', 'The user has been updated successfully.');
define('SUC_USER_ADD', 'The user has been created successfully.');
define('SUC_USER_DEL', 'The user has been deleted successfully.');
define('SUC_RECORD_UPD', 'The record has been updated successfully.');
define('SUC_RECORD_DEL', 'The record has been deleted successfully.');
define('SUC_COMMENT_UPD', 'The comment has been updated successfully.');
define('SUC_SM_DEL', 'The supermaster has been deleted successfully.');
define('SUC_SM_ADD', 'The supermaster has been added successfully.');
define('SUC_PERM_TEMPL_ADD', 'The permission template has been added successfully.');
define('SUC_PERM_TEMPL_UPD', 'The permission template has been updated successfully.');
define('SUC_PERM_TEMPL_DEL', 'The permission template has been deleted successfully.');
define('SUC_ZONE_TEMPL_ADD', 'Zone template has been added successfully.');
define('SUC_ZONE_TEMPL_UPD', 'Zone template has been updated successfully.');
define('SUC_ZONE_TEMPL_DEL', 'Zone template has been deleted successfully.');
define('SUC_EXEC_PDNSSEC_RECTIFY_ZONE', 'Zone has been rectified successfully.');
//2.9.0
define('ERR_DNS_SUBTYPE', 'This is not a valid subtype. Valid type is 1 or 2 depending on whether the endpoint is an AFS Volume Location Server or DCE Authentication Server.');
}