add vdns code

This commit is contained in:
Matthew Saunders Brown 2024-02-13 14:41:15 -08:00
parent 2cf6730523
commit 144d8a23b3
13 changed files with 517 additions and 31 deletions

View File

@ -0,0 +1,106 @@
<?php
/**
* vpanel-stack
* https://git.stack-source.com/msb/vpanel-stack
* Copyright (c) 2022 Matthew Saunders Brown <matthewsaundersbrown@gmail.com>
* GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
*/
namespace Panel;
class Vdns extends \Panel {
function beforeRoute($f3) {
parent::beforeRoute($f3);
if ($f3->get('PDNSADMIN') != '1') {
$f3->reroute('/');
}
}
public static function verifyZoneExists($zone) {
global $f3;
exec("/usr/local/bin/vdns-zone-ext.sh -z $zone", $output, $result_code);
if ($result_code == 0 && $output[0] == 'true') {
return TRUE;
} else {
return FALSE;
}
}
public static function returnZoneDefaultsArray($zone) {
global $f3;
if ($defaults_array = $f3->call('\Panel::vGet', array("vdns-zone-def.sh -z $zone -c", FALSE))) {
return $defaults_array;
} else {
return FALSE;
}
}
public static function returnZoneDefaultsNameserverArray($zone) {
global $f3;
if ($defaults_array = $f3->call('\Panel\Vdns::returnZoneDefaultsArray', $zone)) {
$defaults_ns_array = array();
foreach($defaults_array as $record_array) {
if ($record_array['type'] == "NS") {
$defaults_ns_array[] = $record_array['content'];
}
}
sort($defaults_ns_array);
return $defaults_ns_array;
} else {
return FALSE;
}
}
public static function returnNameserverArray($zone) {
global $f3;
$ns_array = array();
if ($dns_ns_array = dns_get_record("$zone", DNS_NS)) {
foreach ($dns_ns_array as $record_array) {
$ns_array[] = $record_array['target'];
}
sort($ns_array);
return $ns_array;
} else {
return FALSE;
}
}
public static function returnNameserverStatus($zone) {
global $f3;
if ($defaults_ns_array = $f3->call('\Panel\Vdns::returnZoneDefaultsNameserverArray', $zone)) {
if ($ns_array = $f3->call('\Panel\Vdns::returnNameserverArray', $zone)) {
if ($defaults_ns_array === $ns_array) {
return "Verified";
} else {
return "Pending";
}
} else {
return "Unknown";
}
} else {
return "Error";
}
}
}

View File

@ -0,0 +1,73 @@
<?php
/**
* vpanel-stack
* https://git.stack-source.com/msb/vpanel-stack
* Copyright (c) 2022 Matthew Saunders Brown <matthewsaundersbrown@gmail.com>
* GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
*/
namespace Panel\Vdns;
class Zones extends \Panel\Vdns {
/* use this to make query */
function beforeRoute($f3) {
parent::beforeRoute($f3);
if ($f3->exists('PARAMS.zone')) {
$zone = $f3->get('PARAMS.zone');
if ($f3->call('\Panel\Vdns::verifyZoneExists', $zone)) {
if ($zone_array = $f3->call('\Panel::vGet', array("vdns-zone-exp.sh -z $zone -c", FALSE))) {
$f3->set('zone_array', $zone_array);
}
$ns_info_array = array();
$ns_info_array['zone'] = $zone;
$ns_info_array['status'] = $f3->call('\Panel\Vdns::returnNameserverStatus', $zone);
if ($ns_info_array['status'] != "Verified") {
$ns_info_array['defaults_ns_array'] = $f3->call('\Panel\Vdns::returnZoneDefaultsNameserverArray', $zone);
$ns_info_array['ns_array'] = $f3->call('\Panel\Vdns::returnNameserverArray', $zone);
}
$f3->set('ns_info_array', $ns_info_array);
}
} else {
if ($zones_array = $f3->call('\Panel::vGet', array("vdns-zone-lst.sh", FALSE))) {
foreach ($zones_array as $k=>$zone_array) {
$zones_array[$k]['ns_status'] = $f3->call('\Panel\Vdns::returnNameserverStatus', $zone_array['zone']);
}
$f3->set('zones_array', $zones_array);
}
}
}
static function get($f3) {
if ($f3->exists('PARAMS.zone')) {
$zone = $f3->get('PARAMS.zone');
if (is_array($f3->get('zone_array'))) {
$f3->set('page_header', "DNS Zone records for $zone");
echo \Template::instance()->render('vdns/zones-zone.html');
} else {
$messages[] = "Zone $zone not found.";
$f3->set('SESSION.messages', $messages);
$f3->reroute("/DNS");
}
} else {
$f3->set('page_header', "DNS Zones");
echo \Template::instance()->render('vdns/zones.html');
}
}
}

View File

@ -0,0 +1,69 @@
<?php
/**
* vpanel-stack
* https://git.stack-source.com/msb/vpanel-stack
* Copyright (c) 2024 Matthew Saunders Brown <matthewsaundersbrown@gmail.com>
* GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
*/
namespace Panel\Vdns;
class ZonesAdd extends \Panel\Vdns {
function beforeRoute($f3) {
parent::beforeRoute($f3);
}
static function get($f3) {
echo \Template::instance()->render('vdns/zones-add.html');
}
function post($f3) {
// print_r($_POST);
/* force zone to be all lower case */
$zone = strtolower($_POST['zone']);
/* strip spaces */
$zone = trim($zone);
/* remove leading www. */
$zone = preg_replace('/^www\./', '', $zone);
/* remove trailing . (dot) */
$zone = rtrim($zone, '.');
if ($f3->call('\Panel::validateDomain', $zone)) {
/* check if zone exists */
if ($f3->call('\Panel\Vdns::verifyZoneExists', $zone)) {
$messages[] = "Zone $zone already exists in DNS.";
$messages[] = "Note if $zone should be associated with this server but it's now showing up in the list below please contact support.";
$f3->set('SESSION.messages', $messages);
$f3->call('\Panel\Vdns\ZonesAdd::get', $f3);
} else {
$hostname = $f3->get('NAV.hostname');
exec("/usr/local/bin/vdns-zone-add.sh -z $zone -w hostname=$hostname/$zone", $output, $result_code);
if ($result_code == 0) {
$messages[] = "Zone (Domain Name) $zone has been added to DNS.";
$f3->set('SESSION.messages', $messages);
$f3->reroute("/DNS");
} else {
if (count($output) > 0) {
foreach ($output as $k=>$output_message) {
$messages[] = "$output_message";
}
} else {
$messages[] = "Unknown error adding Zone $zone to DNS.";
}
$f3->set('SESSION.messages', $messages);
$f3->call('\Panel\Vdns\ZonesAdd::get', $f3);
}
}
} else {
$f3->call('\Panel\Vdns\ZonesAdd::get', $f3);
}
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* vpanel-stack
* https://git.stack-source.com/msb/vpanel-stack
* Copyright (c) 2022 Matthew Saunders Brown <matthewsaundersbrown@gmail.com>
* GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
*/
namespace Panel\Vdns;
class ZonesDelete extends \Panel\Vdns {
function beforeRoute($f3) {
parent::beforeRoute($f3);
/* verify zone exists */
$zone = $f3->get('PARAMS.zone');
if (!$f3->call('\Panel\Vdns::verifyZoneExists', $zone)) {
$messages[] = "Zone '$zone' does not exist.";
$f3->set('SESSION.messages', $messages);
$f3->reroute("/DNS");
}
}
static function get($f3) {
$f3->set('confirm', 'true');
echo \Template::instance()->render('vdns/zones-delete.html');
}
function post($f3) {
/* run delete command here */
$zone = $f3->get('PARAMS.zone');
exec("/usr/local/bin/vdns-zone-del.sh -z $zone -x", $output, $result_code);
$messages[] = "Zone '$zone' has been deleted from DNS.";
$f3->set('SESSION.messages', $messages);
$f3->reroute("/DNS");
}
}

View File

@ -1,30 +1,36 @@
; vpanel-stack
; https://git.stack-source.com/msb/vpanel-stack
; Copyright (c) 2022 Matthew Saunders Brown <matthewsaundersbrown@gmail.com>
; GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
[globals]
DEBUG=0
UI=ui/
AUTOLOAD=classes/
TEMP=tmp/
LOGS=tmp/logs/
UPLOADS=tmp/uploads/
PACKAGE=Stack-Panel
AUTHOR=Matthew Saunders Brown
LICENSE=GPL-3.0
LICENSEURL=https://www.gnu.org/licenses/gpl-3.0.txt
CASELESS=FALSE
CACHE=TRUE
; Session lifetime in seconds
TIMEOUT=900
; Remote IP address that is automatically logged in without auth
ADMINIP=
; Jail new users by default. 1 = Yes, blank or 0 = No
JAILUSER=1
; PHP-FPM pm.max_children. Recommended range 2-12 on Shared Server
FPMMAX=4
; Write user info to /home/username/.passwd. 1 = Yes, blank or 0 = No
WRITEUSERINFO=1
; Show "Write User Info" & "Write DB Info" options. If no then just use defaults above without giving users the option to change. 1 = Yes, blank or 0 = No
SHOWWRITEINFO=0
; vpanel-stack
; https://git.stack-source.com/msb/vpanel-stack
; Copyright (c) 2022 Matthew Saunders Brown <matthewsaundersbrown@gmail.com>
; GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
[globals]
DEBUG=0
UI=ui/
AUTOLOAD=classes/
TEMP=tmp/
LOGS=tmp/logs/
UPLOADS=tmp/uploads/
PACKAGE=Stack-Panel
AUTHOR=Matthew Saunders Brown
LICENSE=GPL-3.0
LICENSEURL=https://www.gnu.org/licenses/gpl-3.0.txt
CASELESS=FALSE
CACHE=TRUE
; Session lifetime in seconds
TIMEOUT=900
; Remote IP address that is automatically logged in without auth
ADMINIP=
; Jail new users by default. 1 = Yes, blank or 0 = No
JAILUSER=1
; PHP-FPM pm.max_children. Recommended range 2-12 on Shared Server
FPMMAX=4
; Write user info to /home/username/.passwd. 1 = Yes, blank or 0 = No
WRITEUSERINFO=1
; Show "Write User Info" & "Write DB Info" options. If no then just use defaults above without giving users the option to change. 1 = Yes, blank or 0 = No
SHOWWRITEINFO=0
; DNS admin. 1 = Yes, blank or 0 = No
PDNSADMIN=0
; Maximum number of results returned for DNS listings. Defaults to 100 if unspecified.
;PDNSMAX=100
; URL to phpMyPDNS. If this is set, and PDNSADMIN is enabled, show link to phpMyPDNS
PHPMYPDNSURL=

View File

@ -0,0 +1,11 @@
; vpanel-stack
; https://git.stack-source.com/msb/vpanel-stack
; Copyright (c) 2024 Matthew Saunders Brown <matthewsaundersbrown@gmail.com>
; GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
[maps]
; Vdns
/DNS [sync] = Panel\Vdns\Zones
/DNS/@zone [sync] = Panel\Vdns\Zones
/DNS/Add [sync] = Panel\Vdns\ZonesAdd
/DNS/@zone/Delete [sync] = Panel\Vdns\ZonesDelete

View File

@ -84,4 +84,3 @@
/Certs/@cert/Delete [sync] = Panel\Cert\CertsDelete
/Databases [sync] = Panel\MySQL\Databases

View File

@ -38,6 +38,11 @@ if ($f3->get('HOST') == $f3->get('NAV.hostname')) {
$f3->set('NAV.mapping', $mapping);
$f3->config("config/maps-$mapping.ini");
/* load DNS mapping, if enabled */
if ($f3->get('PDNSADMIN') == '1') {
$f3->config("config/maps-vdns.ini");
}
/* custom error page */
$f3->set('ONERROR',function($f3){
echo \Template::instance()->render('error.html');

View File

@ -33,6 +33,7 @@
<a href="{{@BASE}}/Databases">Databases</a> |
<a href="{{@BASE}}/Certs">Certificates</a> |
<a href="{{@BASE}}/Users">Users</a> |
<check if="{{ @PDNSADMIN=='1' }}"><a href="{{@BASE}}/DNS">DNS</a> |</check>
<a href="{{@BASE}}/Logout">Logout</a>
</check>

View File

@ -0,0 +1,20 @@
<include href="header.html" />
<form action="{{@REALM}}" method="POST">
<h4 id="Add_New_Zone">Add New Zone</h4>
<fieldset>
<legend>Domain name to be added to DNS</legend>
<label for="zone">Zone <small>(Domain Name)</small></label>
<input id="zone" name="zone" type="text" placeholder="example.com" value="" required>
<br>
<input type="submit" value="Submit">
<button id="reset" type="reset" disabled>Reset</button>
<!-- <small>Any other form instructions go here.</small> -->
</fieldset>
</form>
<p>
<b>Zone</b> Enter the Domain Name that will be added to DNS.<br>
</p>
<include href="footer.html" />

View File

@ -0,0 +1,17 @@
<include href="header.html" />
<check if="isset(@confirm)">
<form action="{{@NAV.fullpath}}" method="POST">
<fieldset>
<legend>Really Delete Zone {{ @PARAMS.zone }} from DNS</legend>
<br>
<input type="submit" value="Delete {{ @PARAMS.zone }}">
<br>
<small><b>CAUTION:</b> This will permanently remove the zone {{ @PARAMS.zone }} and all associated records from DNS. There is no undo after this!</small>
</fieldset>
</form>
</check>
<include href="footer.html" />

View File

@ -0,0 +1,86 @@
<include href="header.html" />
<check if="isset(@zone_array)">
<p>
<small>
<check if="{{ @ns_info_array.status=='Verified' }}">
<true>
Nameservers for {{ @ns_info_array.zone }} verified. The DNS records below are active.<br>
<check if="isset(@PHPMYPDNSURL)">
You can manage these DNS entries here: <a href="{{ @PHPMYPDNSURL }}">{{ @PHPMYPDNSURL }}</a>
</check>
</true>
<false>
<section style="color:red">NOTICE:</section>
</false>
</check>
<check if="{{ @ns_info_array.status=='Pending' }}">
The Nameservers for {{ @ns_info_array.zone }} are not pointing to this DNS system.<br>
To make this DNS active update the Nameservers at your current Domain Name Registrar to:<br>
<repeat group="{{ @ns_info_array.defaults_ns_array }}" value="{{ @nameserver }}">
<b>{{ @nameserver }}</b><br>
</repeat>
Note that after making this change it can take up to 24 hours for the changes to go through.<br>
<br>
If you are intentionally using another provider for DNS you can reference the records below for what should be added to your DNS (excluding the NS & SOA records).
</check>
<check if="{{ @ns_info_array.status=='Unknown' }}">
The Nameserver verification system could not find nameserver information for {{ @ns_info_array.zone }}.<br>
Make sure the domain name is registered and has the folowing nameservers set:<br>
<repeat group="{{ @ns_info_array.defaults_ns_array }}" value="{{ @nameserver }}">
<b>{{ @nameserver }}</b><br>
</repeat>
</check>
<check if="{{ @ns_info_array.status=='Error' }}">
There was an error verifying the Namservers for {{ @ns_info_array.zone }}.<br>
If this persists please contact tech support.
</check>
</small>
</p>
<true>
<table>
<tr>
<th>Name</th>
<th>TTL</th>
<th>Class</th>
<th>Type</th>
<th>Value</th>
</tr>
<repeat group="{{ @zone_array }}" value="{{ @record_array }}">
<tr>
<td>{{ @record_array.name }}</td>
<td>{{ @record_array.ttl }}</td>
<td>{{ @record_array.class }}</td>
<td>{{ @record_array.type }}</td>
<check if="{{ @record_array.type=='TXT' }}">
<true><td>"{{ @record_array.value }}"</td></true>
<false><td>{{ @record_array.value }}</td></false>
</check>
</tr>
</repeat>
</table>
<p><b>Notes:</b><br>
<ul>
<li>Zone info is displayed in BIND format.<br>You should be able to cut-and-past above records directly into a BIND file, if desired.</li>
<li>MX & SRV records will show the Priority as part of the record.<br>e.g. "10 mail.example.com" indicates a Priority of "10" for "mail.example.com".<br>Only MX & SRV records use Priority, all other records have an unused priority of "0".</li>
</ul>
</p>
<check if="isset(@PHPMYPDNSURL)">
<p><b>phpMyPDNS</b> can be used to manage DNS entries here: <a href="{{ @PHPMYPDNSURL }}">{{ @PHPMYPDNSURL }}</a></p>
</check>
</true>
<false>
<p>No Zone info.</p>
</false>
</check>
<include href="footer.html" />

47
panel/ui/vdns/zones.html Normal file
View File

@ -0,0 +1,47 @@
<include href="header.html" />
<check if="isset(@zones_array)">
<true>
<table>
<tr>
<th>Zone</th>
<th>Nameservers</th>
<th>Action</th>
</tr>
<repeat group="{{ @zones_array }}" value="{{ @zone }}">
<tr>
<td>{{ @zone.zone }}</td>
<check if="{{ @zone.ns_status=='Verified' }}">
<true><td>&check; {{ @zone.ns_status }}</td></true>
<false><td style="color:red">{{ @zone.ns_status }} <small>- click view for details &rarr;</small></td></false>
</check>
<td><a href="{{@REALM}}/{{ @zone.zone }}">View</a> <a href="{{@REALM}}/{{ @zone.zone }}/Delete">Delete</a></td>
</tr>
</repeat>
</table>
</true>
<false>
<p>There are no DNS Zones on this server.</p>
</false>
</check>
<p>
<b>Zone</b> is what a Domain Name is called in DNS.<br>
<b>View</b> zone to see list of all DNS entries.<br>
<b>Delete</b> will remove the zone from DNS entirely.<br>
</p>
<check if="isset(@PHPMYPDNSURL)">
<p><b>phpMyPDNS</b> can be used to manage DNS entries here: <a href="{{ @PHPMYPDNSURL }}">{{ @PHPMYPDNSURL }}</a></p>
</check>
<p>
<a href="{{@NAV.fullpath}}/Add">Add new DNS Zone</a>
</p>
<include href="footer.html" />