add first part of new dns-editor
Signed-off-by: Michael Kaufmann (d00p) <d00p@froxlor.org>
This commit is contained in:
@@ -2061,6 +2061,9 @@ elseif (Settings::Get('system.validate_domain') && ! validateDomain($domain)) {
|
||||
eval("echo \"" . getTemplate("domains/domains_import") . "\";");
|
||||
}
|
||||
}
|
||||
} elseif ($page == 'domaindnseditor') {
|
||||
|
||||
require_once __DIR__.'/dns_editor.php';
|
||||
}
|
||||
|
||||
function formatDomainEntry(&$row, &$idna_convert)
|
||||
|
||||
233
dns_editor.php
Normal file
233
dns_editor.php
Normal file
@@ -0,0 +1,233 @@
|
||||
<?php
|
||||
if (! defined('AREA'))
|
||||
die('You cannot access this file directly!');
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2016 the Froxlor Team (see authors).
|
||||
*
|
||||
* For the full copyright and license information, please view the COPYING
|
||||
* file that was distributed with this source code. You can also view the
|
||||
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright (c) the authors
|
||||
* @author Froxlor team <team@froxlor.org> (2016-)
|
||||
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
|
||||
* @package Panel
|
||||
*
|
||||
*/
|
||||
|
||||
// This file is being included in admin_domains and customer_domains
|
||||
// and therefore does not need to require lib/init.php
|
||||
|
||||
$domain_id = isset($_GET['domain_id']) ? (int) $_GET['domain_id'] : null;
|
||||
|
||||
$record = isset($_POST['record']['record']) ? trim($_POST['record']['record']) : null;
|
||||
$type = isset($_POST['record']['type']) ? $_POST['record']['type'] : 'A';
|
||||
$prio = isset($_POST['record']['prio']) ? (int) $_POST['record']['prio'] : null;
|
||||
$content = isset($_POST['record']['content']) ? trim($_POST['record']['content']) : null;
|
||||
$ttl = isset($_POST['record']['ttl']) ? (int) $_POST['record']['ttl'] : 18000;
|
||||
|
||||
// get domain-name
|
||||
$dom_stmt = Database::prepare("SELECT domain FROM `" . TABLE_PANEL_DOMAINS . "` WHERE id = :did");
|
||||
$domain = Database::pexecute_first($dom_stmt, array(
|
||||
'did' => $domain_id
|
||||
));
|
||||
$domain = $idna_convert->decode($domain['domain']);
|
||||
|
||||
// select all entries
|
||||
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_DOMAIN_DNS . "` WHERE domain_id = :did");
|
||||
Database::pexecute($sel_stmt, array(
|
||||
'did' => $domain_id
|
||||
));
|
||||
$dom_entries = $sel_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$errors = array();
|
||||
$success_message = "";
|
||||
|
||||
// action for adding a new entry
|
||||
if ($action == 'add_record' && ! empty($_POST)) {
|
||||
|
||||
// validation
|
||||
if (empty($record)) {
|
||||
$record = "@";
|
||||
}
|
||||
|
||||
$record = strtolower($record);
|
||||
|
||||
if ($ttl <= 0) {
|
||||
$ttl = 18000;
|
||||
}
|
||||
|
||||
if (empty($content)) {
|
||||
$errors[] = $lng['error']['dns_content_empty'];
|
||||
}
|
||||
|
||||
// types
|
||||
if ($type == 'A' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) {
|
||||
$errors[] = $lng['error']['dns_arec_noipv4'];
|
||||
} elseif ($type == 'AAAA' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
|
||||
$errors[] = $lng['errors']['dns_aaaarec_noipv6'];
|
||||
} elseif ($type == 'MX' && empty($prio)) {
|
||||
$errors[] = $lng['error']['dns_mx_prioempty'];
|
||||
} elseif ($type == 'CNAME') {
|
||||
// check for trailing dot
|
||||
if (substr($content, - 1) == '.') {
|
||||
// remove it for checks
|
||||
$content = substr($content, 0, - 1);
|
||||
}
|
||||
if (! validateDomain($content)) {
|
||||
$errors[] = $lng['error']['dns_cname_invaliddom'];
|
||||
} else {
|
||||
// check whether there are RR-records for the same resource
|
||||
foreach ($dom_entries as $existing_entries) {
|
||||
if (($existing_entries['type'] == 'A' || $existing_entries['type'] == 'AAAA' || $existing_entries['type'] == 'MX' || $existing_entries['type'] == 'NS') && $existing_entries['record'] == $record) {
|
||||
$errors[] = $lng['error']['dns_cname_nomorerr'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// append trailing dot (again)
|
||||
$content .= '.';
|
||||
} elseif ($type == 'TXT' && ! empty($content)) {
|
||||
// check that TXT content is enclosed in " "
|
||||
if (substr($content, 0, 1) != '"') {
|
||||
$content = '"' . $content;
|
||||
}
|
||||
if (substr($content, - 1) != '"') {
|
||||
$content .= '"';
|
||||
}
|
||||
} elseif ($type == 'SRV') {
|
||||
// check for trailing dot
|
||||
if (substr($content, - 1) == '.') {
|
||||
// remove it for checks
|
||||
$content = substr($content, 0, - 1);
|
||||
}
|
||||
//
|
||||
if (! validateDomain($content)) {
|
||||
$errors[] = $lng['error']['dns_srv_needdom'];
|
||||
} else {
|
||||
// check whether there is a CNAME-record for the same resource
|
||||
foreach ($dom_entries as $existing_entries) {
|
||||
$fqdn = $existing_entries['record'] . '.' . $domain;
|
||||
if ($existing_entries['type'] == 'CNAME' && $fqdn == $content) {
|
||||
$errors[] = $lng['error']['dns_srv_noalias'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// append trailing dot (again)
|
||||
$content .= '.';
|
||||
}
|
||||
|
||||
$new_entry = array(
|
||||
'record' => $record,
|
||||
'type' => $type,
|
||||
'prio' => $prio,
|
||||
'content' => $content,
|
||||
'ttl' => $ttl,
|
||||
'domain_id' => $domain_id
|
||||
);
|
||||
ksort($new_entry);
|
||||
|
||||
// check for duplicate
|
||||
foreach ($dom_entries as $existing_entry) {
|
||||
// compare serialized string of array
|
||||
$check_entry = $existing_entry;
|
||||
// new entry has no ID yet
|
||||
unset($check_entry['id']);
|
||||
// sort by key
|
||||
ksort($check_entry);
|
||||
// format integer fields to real integer (as they are read as string from the DB)
|
||||
$check_entry['prio'] = (int)$check_entry['prio'];
|
||||
$check_entry['ttl'] = (int)$check_entry['ttl'];
|
||||
$check_entry['domain_id'] = (int)$check_entry['domain_id'];
|
||||
// serialize both
|
||||
$check_entry = serialize($check_entry);
|
||||
$new = serialize($new_entry);
|
||||
// compare
|
||||
if ($check_entry === $new) {
|
||||
$errors[] = $lng['error']['dns_duplicate_entry'];
|
||||
unset($check_entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($errors)) {
|
||||
$ins_stmt = Database::prepare("
|
||||
INSERT INTO `" . TABLE_DOMAIN_DNS . "` SET
|
||||
`record` = :record,
|
||||
`type` = :type,
|
||||
`prio` = :prio,
|
||||
`content` = :content,
|
||||
`ttl` = :ttl,
|
||||
`domain_id` = :domain_id
|
||||
");
|
||||
|
||||
Database::pexecute($ins_stmt, $new_entry);
|
||||
|
||||
$new_entry_id = Database::lastInsertId();
|
||||
|
||||
// add temporary to the entries-array (no reread of DB necessary)
|
||||
$new_entry['id'] = $new_entry_id;
|
||||
$dom_entries[] = $new_entry;
|
||||
|
||||
// success message (inline)
|
||||
$success_message = $lng['success']['dns_record_added'];
|
||||
} else {
|
||||
// show $errors
|
||||
$errors = implode("<br>", $errors);
|
||||
}
|
||||
} elseif ($action == 'delete') {
|
||||
// remove entry
|
||||
$entry_id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
|
||||
if ($entry_id > 0) {
|
||||
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_DOMAIN_DNS . "` WHERE `id` = :id");
|
||||
Database::pexecute($del_stmt, array(
|
||||
'id' => $entry_id
|
||||
));
|
||||
|
||||
// remove deleted entry from internal data array (no reread of DB necessary)
|
||||
$_t = $dom_entries;
|
||||
foreach ($_t as $idx => $entry) {
|
||||
if ($entry['id'] == $entry_id) {
|
||||
unset($dom_entries[$idx]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
unset($_t);
|
||||
// success message (inline)
|
||||
$success_message = $lng['success']['dns_record_deleted'];
|
||||
}
|
||||
}
|
||||
|
||||
// show editor
|
||||
$record_list = "";
|
||||
$existing_entries = "";
|
||||
$type_select = "";
|
||||
$entriescount = 0;
|
||||
|
||||
if (! empty($dom_entries)) {
|
||||
$entriescount = count($dom_entries);
|
||||
foreach ($dom_entries as $entry) {
|
||||
eval("\$existing_entries.=\"" . getTemplate("dns_editor/entry_bit", true) . "\";");
|
||||
}
|
||||
}
|
||||
|
||||
// available types
|
||||
$type_select_values = array(
|
||||
'A',
|
||||
'AAAA',
|
||||
'NS',
|
||||
'MX',
|
||||
'SRV',
|
||||
'TXT',
|
||||
'CNAME'
|
||||
);
|
||||
asort($type_select_values);
|
||||
foreach ($type_select_values as $_type) {
|
||||
$type_select .= makeoption($_type, $_type, $type);
|
||||
}
|
||||
|
||||
eval("\$record_list=\"" . getTemplate("dns_editor/list", true) . "\";");
|
||||
eval("echo \"" . getTemplate("dns_editor/index", true) . "\";");
|
||||
@@ -557,7 +557,7 @@ INSERT INTO `panel_settings` (`settinggroup`, `varname`, `value`) VALUES
|
||||
('panel', 'password_special_char_required', '0'),
|
||||
('panel', 'password_special_char', '!?<>§$%+#=@'),
|
||||
('panel', 'version', '0.9.35.1'),
|
||||
('panel', 'db_version', '201604270');
|
||||
('panel', 'db_version', '201605090');
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `panel_tasks`;
|
||||
@@ -855,3 +855,16 @@ CREATE TABLE IF NOT EXISTS `panel_domaintoip` (
|
||||
PRIMARY KEY (`id_domain`,`id_ipandports`)
|
||||
) ENGINE=MyISAM CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `domain_dns_entries`;
|
||||
CREATE TABLE `domain_dns_entries` (
|
||||
`id` int(20) NOT NULL,
|
||||
`domain_id` int(15) NOT NULL,
|
||||
`record` varchar(255) NOT NULL,
|
||||
`type` varchar(10) NOT NULL DEFAULT 'A',
|
||||
`content` text NOT NULL,
|
||||
`ttl` int(11) NOT NULL DEFAULT '18000',
|
||||
`prio` int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||
|
||||
|
||||
@@ -3312,3 +3312,26 @@ if (isFroxlorVersion('0.9.35.1') && isDatabaseVersion('201603150')) {
|
||||
|
||||
updateToDbVersion('201604270');
|
||||
}
|
||||
|
||||
if (isFroxlorVersion('0.9.35.1') && isDatabaseVersion('201604270')) {
|
||||
|
||||
showUpdateStep("Adding new dns related tables and settings");
|
||||
$enable_dns = isset($_POST['enable_dns']) ? (int) $_POST['enable_dns'] : "0";
|
||||
Settings::AddNew("system.dnsenabled", $enable_dns);
|
||||
|
||||
Database::query("DROP TABLE IF EXISTS `domain_dns_entries`;");
|
||||
$sql = "CREATE TABLE `domain_dns_entries` (
|
||||
`id` int(20) NOT NULL,
|
||||
`domain_id` int(15) NOT NULL,
|
||||
`record` varchar(255) NOT NULL,
|
||||
`type` varchar(10) NOT NULL DEFAULT 'A',
|
||||
`content` text NOT NULL,
|
||||
`ttl` int(11) NOT NULL DEFAULT '18000',
|
||||
`prio` int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;";
|
||||
Database::query($sql);
|
||||
lastStepStatus(0);
|
||||
|
||||
updateToDbVersion('201605090');
|
||||
}
|
||||
|
||||
@@ -50,5 +50,6 @@ define('TABLE_PANEL_REDIRECTCODES', 'redirect_codes');
|
||||
define('TABLE_PANEL_DOMAINREDIRECTS', 'domain_redirect_codes');
|
||||
define('TABLE_PANEL_DOMAIN_SSL_SETTINGS', 'domain_ssl_settings');
|
||||
define('TABLE_DOMAINTOIP', 'panel_domaintoip');
|
||||
define('TABLE_DOMAIN_DNS', 'domain_dns_entries');
|
||||
|
||||
require dirname(__FILE__).'/version.inc.php';
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
$version = '0.9.35.1';
|
||||
|
||||
// Database version (YYYYMMDDC where C is a daily counter)
|
||||
$dbversion = '201604270';
|
||||
$dbversion = '201605090';
|
||||
|
||||
// Distribution branding-tag (used for Debian etc.)
|
||||
$branding = '';
|
||||
|
||||
@@ -4,6 +4,7 @@ $header
|
||||
<h2>
|
||||
<img src="templates/{$theme}/assets/img/icons/domain_edit_big.png" alt="{$title}" />
|
||||
{$title}
|
||||
(<small><a href="{$linker->getLink(array('section' => 'domains', 'page' => 'domaindnseditor', 'domain_id' => $id))}">edit DNS</a></small>)
|
||||
</h2>
|
||||
</header>
|
||||
|
||||
|
||||
22
templates/Sparkle/assets/css/main.css
vendored
22
templates/Sparkle/assets/css/main.css
vendored
@@ -601,6 +601,12 @@ input[type="password"] {
|
||||
background:#fff url(../img/icons/lock.png) no-repeat 5px 4px;
|
||||
}
|
||||
|
||||
input[class="small"] {
|
||||
width:auto;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BUTTONS
|
||||
*/
|
||||
@@ -1513,3 +1519,19 @@ fieldset.file {
|
||||
table.hl tbody tr.domain-hostname:hover {
|
||||
background-color: rgb(64, 150, 238);
|
||||
}
|
||||
|
||||
td.size-5 {
|
||||
width: 5%;
|
||||
}
|
||||
|
||||
td.size-10 {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
td.size-20 {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
td.size-50 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
10
templates/Sparkle/dns_editor/entry_bit.tpl
vendored
Normal file
10
templates/Sparkle/dns_editor/entry_bit.tpl
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<tr>
|
||||
<td>{$entry['record']}</td>
|
||||
<td>{$entry['type']}</td>
|
||||
<td><if $entry['prio'] <= 0> <else>{$entry['prio']}</if></td>
|
||||
<td>{$entry['content']}</td>
|
||||
<td>{$entry['ttl']}</td>
|
||||
<td>
|
||||
<a href="{$linker->getLink(array('section' => 'domains', 'page' => $page, 'action' => 'delete', 'domain_id' => $domain_id, 'id' => $entry['id']))}"><img src="templates/{$theme}/assets/img/icons/delete.png" alt="{$lng['panel']['delete']}" title="{$lng['panel']['delete']}" /></a>
|
||||
</td>
|
||||
</tr>
|
||||
28
templates/Sparkle/dns_editor/index.tpl
vendored
Normal file
28
templates/Sparkle/dns_editor/index.tpl
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
$header
|
||||
<article>
|
||||
<header>
|
||||
<h2>
|
||||
<img src="templates/{$theme}/assets/img/icons/domain_edit_big.png" alt="" />
|
||||
DNS Editor (<a href="{$linker->getLink(array('section' => 'domains', 'page' => 'domains', 'action' => 'edit', 'id' => $domain_id))}">{$domain}</a>, {$entriescount} records)
|
||||
</h2>
|
||||
</header>
|
||||
|
||||
<if !empty($errors)>
|
||||
<div class="errorcontainer bradius">
|
||||
<div class="errortitle">{$lng['error']['error']}</div>
|
||||
<div class="error">{$errors}</div>
|
||||
</div>
|
||||
</if>
|
||||
<if !empty($success_message)>
|
||||
<div class="successcontainer bradius">
|
||||
<div class="successtitle">{$lng['success']['success']}</div>
|
||||
<div class="success">{$success_message}</div>
|
||||
</div>
|
||||
</if>
|
||||
|
||||
<section>
|
||||
{$record_list}
|
||||
</section>
|
||||
|
||||
</article>
|
||||
$footer
|
||||
25
templates/Sparkle/dns_editor/list.tpl
vendored
Normal file
25
templates/Sparkle/dns_editor/list.tpl
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<form method="post" action="{$linker->getLink(array('section' => 'domains', 'page' => $page, 'action' => 'add_record', 'domain_id' => $domain_id))}">
|
||||
<table class="full hl">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="size-20">Record</th>
|
||||
<th class="size-5">Type</th>
|
||||
<th class="size-5">Priority</th>
|
||||
<th class="size-50">Content</th>
|
||||
<th class="size-10">TTL</th>
|
||||
<th class="size-10"> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><input id="dns_record" type="text" name="record[record]" class="small" placeholder="Record" value="{$record}" /></td>
|
||||
<td><select id="dns_type" name="record[type]" class="small">{$type_select}</select></td>
|
||||
<td><input id="dns_mxp" type="text" name="record[prio]" class="small" placeholder="MX priority" value="{$prio}" /></td>
|
||||
<td><input id="dns_content" type="text" name="record[content]" class="small" placeholder="Content" value="{$content}" /></td>
|
||||
<td><input id="dns_ttl" type="text" name="record[ttl]" class="small" placeholder="18000" value="{$ttl}" /></td>
|
||||
<td><input type="submit" class="submitsearch" value="add" name="add" /></td>
|
||||
</tr>
|
||||
{$existing_entries}
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
Reference in New Issue
Block a user