From 161d24650b6020393b57238c0a0d4e40110dc6d3 Mon Sep 17 00:00:00 2001 From: Stephan de Wit <33954429+swhite2@users.noreply.github.com> Date: Mon, 24 Jan 2022 20:19:06 +0100 Subject: [PATCH] unbound: overrides: migrate to mvc model (#5488) * unbound: overrides: migrate to mvc model * unbound: overrides: generate host_entries via model, revert template generation * unbound: overrides migration: fix missing include * unbound: overrides: clean up Co-authored-by: Stephan de Wit --- plist | 12 +- src/etc/inc/plugins.inc.d/unbound.inc | 152 +++---- .../Unbound/Api/SettingsController.php | 135 +++++++ .../OPNsense/Unbound/OverridesController.php | 42 ++ .../Unbound/forms/dialogDomainOverride.xml | 33 ++ .../Unbound/forms/dialogHostAlias.xml | 26 ++ .../Unbound/forms/dialogHostOverride.xml | 50 +++ .../Base/FieldTypes/HostnameField.php | 28 +- .../app/models/OPNsense/Unbound/ACL/ACL.xml | 17 +- .../app/models/OPNsense/Unbound/Menu/Menu.xml | 5 +- .../OPNsense/Unbound/Migrations/M1_0_1.php | 108 +++++ .../app/models/OPNsense/Unbound/Unbound.xml | 124 +++++- .../app/views/OPNsense/Unbound/overrides.volt | 289 ++++++++++++++ .../modules/addons/template_helpers.py | 1 - src/opnsense/service/modules/template.py | 3 + .../templates/OPNsense/Unbound/core/+TARGETS | 2 + .../Unbound/core/domainoverrides.conf | 17 + .../Unbound/core/private_domains.conf | 13 + .../services_unbound_domainoverride_edit.php | 166 -------- src/www/services_unbound_host_edit.php | 377 ------------------ src/www/services_unbound_overrides.php | 252 ------------ 21 files changed, 927 insertions(+), 925 deletions(-) create mode 100755 src/opnsense/mvc/app/controllers/OPNsense/Unbound/OverridesController.php create mode 100755 src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogDomainOverride.xml create mode 100755 src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogHostAlias.xml create mode 100755 src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogHostOverride.xml create mode 100755 src/opnsense/mvc/app/models/OPNsense/Unbound/Migrations/M1_0_1.php create mode 100755 src/opnsense/mvc/app/views/OPNsense/Unbound/overrides.volt create mode 100755 src/opnsense/service/templates/OPNsense/Unbound/core/domainoverrides.conf create mode 100755 src/opnsense/service/templates/OPNsense/Unbound/core/private_domains.conf delete mode 100644 src/www/services_unbound_domainoverride_edit.php delete mode 100644 src/www/services_unbound_host_edit.php delete mode 100644 src/www/services_unbound_overrides.php diff --git a/plist b/plist index 5d2904308..ae993cd2f 100644 --- a/plist +++ b/plist @@ -377,9 +377,13 @@ /usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/Api/SettingsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/DnsblController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/DotController.php +/usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/OverridesController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/StatsController.php /usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogDot.xml /usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dnsbl.xml +/usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogDomainOverride.xml +/usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogHostAlias.xml +/usr/local/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogHostOverride.xml /usr/local/opnsense/mvc/app/library/Google/API/Drive.php /usr/local/opnsense/mvc/app/library/OPNsense/Auth/API.php /usr/local/opnsense/mvc/app/library/OPNsense/Auth/AuthenticationFactory.php @@ -564,6 +568,7 @@ /usr/local/opnsense/mvc/app/models/OPNsense/Unbound/ACL/ACL.xml /usr/local/opnsense/mvc/app/models/OPNsense/Unbound/Menu/Menu.xml /usr/local/opnsense/mvc/app/models/OPNsense/Unbound/Migrations/M1_0_0.php +/usr/local/opnsense/mvc/app/models/OPNsense/Unbound/Migrations/M1_0_1.php /usr/local/opnsense/mvc/app/models/OPNsense/Unbound/Unbound.php /usr/local/opnsense/mvc/app/models/OPNsense/Unbound/Unbound.xml /usr/local/opnsense/mvc/app/views/OPNsense/CaptivePortal/clients.volt @@ -608,6 +613,7 @@ /usr/local/opnsense/mvc/app/views/OPNsense/TrafficShaper/statistics.volt /usr/local/opnsense/mvc/app/views/OPNsense/Unbound/dnsbl.volt /usr/local/opnsense/mvc/app/views/OPNsense/Unbound/dot.volt +/usr/local/opnsense/mvc/app/views/OPNsense/Unbound/overrides.volt /usr/local/opnsense/mvc/app/views/OPNsense/Unbound/stats.volt /usr/local/opnsense/mvc/app/views/layout_partials/base_dialog.volt /usr/local/opnsense/mvc/app/views/layout_partials/base_dialog_processing.volt @@ -989,6 +995,9 @@ /usr/local/opnsense/service/templates/OPNsense/Syslog/syslog-ng.conf /usr/local/opnsense/service/templates/OPNsense/Unbound/core/+TARGETS /usr/local/opnsense/service/templates/OPNsense/Unbound/core/blocklists.conf +/usr/local/opnsense/service/templates/OPNsense/Unbound/core/domainoverrides.conf +/usr/local/opnsense/service/templates/OPNsense/Unbound/core/host_entries.conf +/usr/local/opnsense/service/templates/OPNsense/Unbound/core/private_domains.conf /usr/local/opnsense/service/templates/OPNsense/Unbound/core/dot.conf /usr/local/opnsense/service/templates/OPNsense/Unbound/core/miscellaneous.conf /usr/local/opnsense/service/templates/OPNsense/Unbound/core/root.min.hints @@ -1804,9 +1813,6 @@ /usr/local/www/services_unbound.php /usr/local/www/services_unbound_acls.php /usr/local/www/services_unbound_advanced.php -/usr/local/www/services_unbound_domainoverride_edit.php -/usr/local/www/services_unbound_host_edit.php -/usr/local/www/services_unbound_overrides.php /usr/local/www/status_dhcp_leases.php /usr/local/www/status_dhcpv6_leases.php /usr/local/www/status_habackup.php diff --git a/src/etc/inc/plugins.inc.d/unbound.inc b/src/etc/inc/plugins.inc.d/unbound.inc index be249c3c1..eb6c07448 100644 --- a/src/etc/inc/plugins.inc.d/unbound.inc +++ b/src/etc/inc/plugins.inc.d/unbound.inc @@ -219,14 +219,7 @@ EOF; } } - /* allow DNS Rebind for forwarded domains */ - if (!empty($config['unbound']['domainoverrides'])) { - $private_domains = "# Set private domains in case authoritative name server returns a Private IP address\n"; - $private_domains .= unbound_add_domain_overrides(true); - } - unbound_add_host_entries($ifconfig_details); - unbound_add_domain_overrides(); unbound_acls_config(); $port = is_port($config['unbound']['port']) ? $config['unbound']['port'] : "53"; @@ -359,7 +352,9 @@ prefetch-key: {$prefetch_key} # DNS Rebinding {$private_addr} -{$private_domains} + +# Private domains (DNS Rebinding) +include: /var/unbound/private_domains.conf # Access lists include: /var/unbound/access_lists.conf @@ -370,9 +365,6 @@ include: /var/unbound/host_entries.conf # DHCP leases (if configured) {$include_dhcpleases} -# Domain overrides -include: /var/unbound/domainoverrides.conf - # Custom includes include: /var/unbound/etc/*.conf @@ -439,56 +431,6 @@ function unbound_configure_do($verbose = false, $interface = '') } } -function unbound_add_domain_overrides($pvt = false) -{ - global $config; - - $domains = config_read_array('unbound', 'domainoverrides'); - - usort($domains, function ($a, $b) { - return strcasecmp($a['domain'], $b['domain']); - }); - - $result = array(); - $forward_local = ''; - - foreach ($domains as $domain) { - $domain_key = current($domain); - if (!isset($result[$domain_key])) { - $result[$domain_key] = array(); - } - $result[$domain_key][] = $domain['ip']; - } - - $domain_entries = ''; - foreach ($result as $domain => $ips) { - if ($pvt == true) { - $domain_entries .= "domain-insecure: \"$domain\"\n"; - if (preg_match('/.+\.(in-addr|ip6)\.arpa\.?$/', $domain)) { - $domain_entries .= "local-zone: \"$domain\" typetransparent\n"; - } elseif (!isset($config['system']['webgui']['nodnsrebindcheck'])) { - $domain_entries .= "private-domain: \"$domain\"\n"; - } - } else { - $domain_entries .= "forward-zone:\n"; - $domain_entries .= "\tname: \"$domain\"\n"; - foreach ($ips as $ip) { - if (strpos($ip, '127.') === 0 || $ip == '::1') { - $forward_local = "server:\n\tdo-not-query-localhost: no\n"; - } - $domain_entries .= "\tforward-addr: $ip\n"; - } - } - } - - if ($pvt == true) { - return $domain_entries; - } else { - $domain_entries .= $forward_local; - file_put_contents('/var/unbound/domainoverrides.conf', $domain_entries); - } -} - function unbound_add_host_entries($ifconfig_details = null) { global $config; @@ -577,55 +519,59 @@ function unbound_add_host_entries($ifconfig_details = null) unset($tmp_known_domains); // remove temporary variable } - if (isset($config['unbound']['hosts'])) { - foreach ($config['unbound']['hosts'] as $host) { - $aliases = array(array( - 'domain' => $host['domain'], - 'descr' => $host['descr'], - 'host' => $host['host'], - )); + $unbound_mdl = new \OPNsense\Unbound\Unbound(); + $hosts = iterator_to_array($unbound_mdl->hosts->host->iterateItems()); + $aliases = iterator_to_array($unbound_mdl->aliases->alias->iterateItems()); - if (!empty($host['aliases']['item'])) { - foreach ($host['aliases']['item'] as $alias) { - $aliases[] = array( - 'domain' => !empty($alias['domain']) ? $alias['domain'] : $aliases[0]['domain'], - 'descr' => !empty($alias['descr']) ? $alias['descr'] : $aliases[0]['descr'], - 'host' => !empty($alias['host']) ? $alias['host'] : $aliases[0]['host'], - ); - } - } + if (!empty($hosts)) { + foreach ($hosts as $host) { + if ($host->enabled == '1') { + $tmp_aliases = array(array( + 'domain' => (string)$host->domain, + 'description' => (string)$host->description, + 'hostname' => (string)$host->hostname + )); - /* Backwards compatibility for records created before introducing RR types. */ - if (!isset($host['rr'])) { - $host['rr'] = (is_ipaddrv6($host['ip'])) ? 'AAAA' : 'A'; - } - - foreach ($aliases as $alias) { - if ($alias['host'] != '') { - $alias['host'] .= '.'; - } - - switch ($host['rr']) { - case 'A': - case 'AAAA': - /* Handle wildcard entries which have "*" as a hostname. Since we added a . above, we match on "*.". */ - if ($alias['host'] == '*.') { - $unbound_entries .= "local-zone: \"{$alias['domain']}\" redirect\n"; - $unbound_entries .= "local-data: \"{$alias['domain']} IN {$host['rr']} {$host['ip']}\"\n"; - } else { - $unbound_entries .= "local-data-ptr: \"{$host['ip']} {$alias['host']}{$alias['domain']}\"\n"; - $unbound_entries .= "local-data: \"{$alias['host']}{$alias['domain']} IN {$host['rr']} {$host['ip']}\"\n"; + if (!empty($aliases)) { + foreach ($aliases as $alias) { + if ($alias->enabled == '1' && $alias->host == $host->getAttribute('uuid')) { + $tmp_aliases[] = array( + 'domain' => !empty((string)$alias->domain) ? $alias->domain : $tmp_aliases[0]['domain'], + 'description' => !empty((string)$alias->description) ? $alias->description : $tmp_aliases[0]['description'], + 'hostname' => !empty((string)$alias->hostname) ? $alias->hostname : $tmp_aliases[0]['hostname'] + ); } - break; - case 'MX': - $unbound_entries .= "local-data: \"{$alias['host']}{$alias['domain']} IN MX {$host['mxprio']} {$host['mx']}\"\n"; - break; + } } - if (!empty($alias['descr']) && isset($config['unbound']['txtsupport'])) { - $unbound_entries .= "local-data: '{$alias['host']}{$alias['domain']} TXT \"" . addslashes($alias['descr']) . "\"'\n"; + foreach ($tmp_aliases as $alias) { + if ($alias['hostname'] != '') { + $alias['hostname'] .= '.'; + } + + switch ($host->rr) { + case 'A': + case 'AAAA': + /* Handle wildcard entries which have "*" as a hostname. Since we added a . above, we match on "*.". */ + if ($alias['hostname'] == '*.') { + $unbound_entries .= "local-zone: \"{$alias['domain']}\" redirect\n"; + $unbound_entries .= "local-data: \"{$alias['domain']} IN {$host->rr} {$host->server}\"\n"; + } else { + $unbound_entries .= "local-data-ptr: \"{$host->server} {$alias['hostname']}{$alias['domain']}\"\n"; + $unbound_entries .= "local-data: \"{$alias['hostname']}{$alias['domain']} IN {$host->rr} {$host->server}\"\n"; + } + break; + case 'MX': + $unbound_entries .= "local-data: \"{$alias['hostname']}{$alias['domain']} IN MX {$host->mxprio} {$host->mx}\"\n"; + break; + } + + if (!empty($alias['description']) && isset($config['unbound']['txtsupport'])) { + $unbound_entries .= "local-data: '{$alias['hostname']}{$alias['domain']} TXT \"" . addslashes($alias['description']) . "\"'\n"; + } } } + } } diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Unbound/Api/SettingsController.php b/src/opnsense/mvc/app/controllers/OPNsense/Unbound/Api/SettingsController.php index f1eaf5337..a1c441fff 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Unbound/Api/SettingsController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/Unbound/Api/SettingsController.php @@ -65,4 +65,139 @@ class SettingsController extends ApiMutableModelControllerBase { return $this->toggleBase('dots.dot', $uuid, $enabled); } + + /* Host overrides */ + + public function searchHostOverrideAction() + { + return $this->searchBase( + 'hosts.host', + ['enabled', 'hostname', 'domain', 'rr', 'mxprio', 'mx', 'server', 'description'], + "sequence" + ); + } + + public function getHostOverrideAction($uuid = null) + { + return $this->getBase('host', 'hosts.host', $uuid); + } + + public function addHostOverrideAction() + { + return $this->addBase('host', 'hosts.host'); + } + + public function delHostOverrideAction($uuid) + { + /* Make sure the linked aliases are deleted as well. */ + $node = $this->getModel(); + foreach ($node->aliases->alias->iterateItems() as $alias_uuid => $alias) { + if ($alias->host == $uuid) { + $this->delBase('aliases.alias', $alias_uuid); + } + } + + return $this->delBase('hosts.host', $uuid); + } + + public function setHostOverrideAction($uuid) + { + return $this->setBase('host', 'hosts.host', $uuid); + } + + public function toggleHostOverrideAction($uuid, $enabled = null) + { + return $this->toggleBase('hosts.host', $uuid, $enabled); + } + + /* Aliases for hosts */ + + public function searchHostAliasAction() + { + $host = $this->request->get('host'); + $filter_func = null; + if (!empty($host)) { + $filter_func = function ($record) use ($host) { + return $record->host == $host; + }; + } + return $this->searchBase( + 'aliases.alias', + ['enabled', 'host', 'hostname', 'domain'], + "sequence", + $filter_func + ); + } + + public function getHostAliasAction($uuid = null) + { + $host_uuid = $this->request->get('host'); + $result = $this->getBase('alias', 'aliases.alias', $uuid); + if (empty($uuid) && !empty($host_uuid)) { + foreach($result['alias']['host'] as $key => &$value) { + if ($key == $host_uuid) { + $value['selected'] = 1; + } else { + $value['selected'] = 0; + } + } + } + return $result; + } + + public function addHostAliasAction() + { + return $this->addBase('alias', 'aliases.alias'); + } + + public function delHostAliasAction($uuid) + { + return $this->delBase('aliases.alias', $uuid); + } + + public function setHostAliasAction($uuid) + { + return $this->setBase('alias', 'aliases.alias'); + } + + public function toggleHostAliasAction($uuid, $enabled = null) + { + return $this->toggleBase('aliases.alias', $uuid, $enabled); + } + + /* Domain overrides */ + + public function searchDomainOverrideAction() + { + return $this->searchBase( + 'domains.domain', + ['enabled', 'domain', 'server', 'description'], + "sequence" + ); + } + + public function getDomainOverrideAction($uuid = null) + { + return $this->getBase('domain', 'domains.domain', $uuid); + } + + public function addDomainOverrideAction() + { + return $this->addBase('domain', 'domains.domain'); + } + + public function delDomainOverrideAction($uuid) + { + return $this->delBase('domains.domain', $uuid); + } + + public function setDomainOverrideAction($uuid) + { + return $this->setBase('domain', 'domains.domain', $uuid); + } + + public function toggleDomainOverrideAction($uuid, $enabled = null) + { + return $this->toggleBase('domains.domain', $uuid, $enabled); + } } diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Unbound/OverridesController.php b/src/opnsense/mvc/app/controllers/OPNsense/Unbound/OverridesController.php new file mode 100755 index 000000000..d6fea3426 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Unbound/OverridesController.php @@ -0,0 +1,42 @@ + + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +namespace OPNsense\Unbound; + +use OPNsense\Base\IndexController; + +class OverridesController extends IndexController +{ + public function indexAction() + { + $this->view->pick('OPNsense/Unbound/overrides'); + $this->view->formDialogHostOverride = $this->getForm("dialogHostOverride"); + $this->view->formDialogHostAlias = $this->getForm("dialogHostAlias"); + $this->view->formDialogDomainOverride = $this->getForm("dialogDomainOverride"); + } +} diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogDomainOverride.xml b/src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogDomainOverride.xml new file mode 100755 index 000000000..538b27ab7 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogDomainOverride.xml @@ -0,0 +1,33 @@ +
+ + domain.enabled + + checkbox + Enable this domain override + + + domain.domain + + text + + Domain to override (NOTE: this does not have to be a valid TLD!), + e.g. 'test' or 'mycompany.localdomain' or '1.168.192.in-addr.arpa' + + + + domain.server + + text + + IP address of the authoritative DNS server for this domain, + e.g. '192.168.100.100'. To use a nondefault port for communication, + append an '@' with the port number. + + + + domain.description + + text + You may enter a description here for your reference (not parsed). + +
diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogHostAlias.xml b/src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogHostAlias.xml new file mode 100755 index 000000000..2936a0084 --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogHostAlias.xml @@ -0,0 +1,26 @@ +
+ + alias.enabled + + checkbox + Enable this alias for the selected host + + + alias.host + + dropdown + Select the associated host override to apply this alias on + + + alias.hostname + + text + Name of the host, without the domain part. Use "*" to create a wildcard entry. + + + alias.domain + + text + Domain of the host, e.g. example.com + +
diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogHostOverride.xml b/src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogHostOverride.xml new file mode 100755 index 000000000..61fb7b28e --- /dev/null +++ b/src/opnsense/mvc/app/controllers/OPNsense/Unbound/forms/dialogHostOverride.xml @@ -0,0 +1,50 @@ +
+ + host.enabled + + checkbox + Enable the override for this host + + + host.hostname + + text + Name of the host, without the domain part. Use "*" to create a wildcard entry. + + + host.domain + + text + Domain of the host, e.g. example.com + + + host.rr + + dropdown + Type of resource record, e.g. A or AAAA for IPv4 or IPv6 addresses + + + host.mxprio + + text + Priority of MX record, e.g. 10 + + + host.mx + + text + Host name of MX host, e.g. mail.example.com + + + host.server + + text + IP address of the host, e.g. 192.168.100.100 or fd00:abcd::1 + + + host.description + + text + You may enter a description here for your reference (not parsed) + +
diff --git a/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/HostnameField.php b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/HostnameField.php index c734d6dd0..1374bbe74 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/HostnameField.php +++ b/src/opnsense/mvc/app/models/OPNsense/Base/FieldTypes/HostnameField.php @@ -57,10 +57,15 @@ class HostnameField extends BaseField private $internalAsList = false; /** - * @var bool wildcard (any) enabled + * @var bool IP address allowed */ protected $internalIpAllowed = true; + /** + * @var bool wildcard (*) enabled + */ + protected $internalWildcardAllowed = false; + /** * ip addresses allowed * @param string $value Y/N @@ -74,6 +79,15 @@ class HostnameField extends BaseField } } + public function setWildcardAllowed($value) + { + if (trim($value) == "Y") { + $this->internalWildcardAllowed = true; + } else { + $this->internalWildcardAllowed = false; + } + } + /** * always trim hostnames * @param string $value @@ -132,11 +146,13 @@ class HostnameField extends BaseField { $validators = parent::getValidators(); if ($this->internalValue != null) { - $validators[] = new HostValidator(array( - 'message' => $this->internalValidationMessage, - 'split' => $this->internalFieldSeparator, - 'allowip' => $this->internalIpAllowed - )); + if ($this->internalValue != "*" || $this->internalWildcardAllowed == false) { + $validators[] = new HostValidator(array( + 'message' => $this->internalValidationMessage, + 'split' => $this->internalFieldSeparator, + 'allowip' => $this->internalIpAllowed + )); + } } return $validators; } diff --git a/src/opnsense/mvc/app/models/OPNsense/Unbound/ACL/ACL.xml b/src/opnsense/mvc/app/models/OPNsense/Unbound/ACL/ACL.xml index ccb5279a7..df3c4a2c8 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Unbound/ACL/ACL.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Unbound/ACL/ACL.xml @@ -17,20 +17,13 @@ services_unbound_advanced.php* - - Services: Unbound DNS: Edit Domain Override + + Services: Unbound DNS: Edit Host and Domain Override - services_unbound_overrides.php - services_unbound_domainoverride_edit.php* + ui/unbound/overrides/* + api/unbound/overrides/* - - - Services: Unbound DNS: Edit Host Override - - services_unbound_overrides.php - services_unbound_host_edit.php* - - + Services: Unbound DNS: Log File diff --git a/src/opnsense/mvc/app/models/OPNsense/Unbound/Menu/Menu.xml b/src/opnsense/mvc/app/models/OPNsense/Unbound/Menu/Menu.xml index 4d0c98a08..8161bbda5 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Unbound/Menu/Menu.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Unbound/Menu/Menu.xml @@ -2,10 +2,7 @@ - - - - + diff --git a/src/opnsense/mvc/app/models/OPNsense/Unbound/Migrations/M1_0_1.php b/src/opnsense/mvc/app/models/OPNsense/Unbound/Migrations/M1_0_1.php new file mode 100755 index 000000000..45c19d680 --- /dev/null +++ b/src/opnsense/mvc/app/models/OPNsense/Unbound/Migrations/M1_0_1.php @@ -0,0 +1,108 @@ +object(); + + if (!empty($config->unbound->hosts)) { + foreach($config->unbound->hosts as $old_host) { + $new_host = $model->hosts->host->add(); + + /* Backwards compatibility for records created before introducing RR types. */ + if (!isset($old_host->rr)) { + $old_host->rr = (strpos($old_host->ip, ':') !== false) ? 'AAAA' : 'A'; + } + + $host_data = [ + 'enabled' => 1, + 'hostname' => !empty($old_host->host) ? $old_host->host : null, + 'domain' => $old_host->domain, + 'rr' => $old_host->rr, + 'server' => $old_host->rr == 'A' ? $old_host->ip : null, + 'mxprio' => $old_host->rr == 'MX' ? $old_host->mxprio : null, + 'mx' => $old_host->rr == 'MX' ? $old_host->mx : null, + 'description' => !empty($old_host->descr) ? $old_host->descr : null + ]; + + $new_host->setNodes($host_data); + + $uuid = $new_host->getAttribute('uuid'); + foreach ($old_host->aliases->item as $old_alias) { + if (!empty($old_alias)) { + $new_alias = $model->aliases->alias->add(); + $alias_data = [ + 'enabled' => 1, + 'host' => $uuid, + 'domain' => $old_alias->domain, + 'hostname' => !empty($old_alias->host) ? $old_alias->host : null + ]; + $new_alias->setNodes($alias_data); + } + } + } + } + + if (!empty($config->unbound->domainoverrides)) { + foreach($config->unbound->domainoverrides as $old_domain) { + $new_domain = $model->domains->domain->add(); + $domain_data = [ + 'enabled' => 1, + 'domain' => $old_domain->domain, + 'server' => $old_domain->ip, + 'description' => !empty($old_domain->descr) ? $old_domain->descr : null + ]; + $new_domain->setNodes($domain_data); + } + } + } + + /** + * cleanup old config after config save + * @param $model + */ + public function post($model) + { + $cfgObj = Config::getInstance()->object(); + unset($cfgObj->unbound->hosts, $cfgObj->unbound->domainoverrides); + } +} diff --git a/src/opnsense/mvc/app/models/OPNsense/Unbound/Unbound.xml b/src/opnsense/mvc/app/models/OPNsense/Unbound/Unbound.xml index a1bbd0b71..8467c9af2 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Unbound/Unbound.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Unbound/Unbound.xml @@ -1,7 +1,7 @@ //OPNsense/unboundplus Unbound configuration - 1.0.0 + 1.0.1 unbound.enable @@ -73,6 +73,128 @@ + + + + 1 + Y + + + N + Y + + + Y + /^(?:(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$/i + A valid domain must be specified. + + + Y + A + + A or AAAA (IPv4 or IPv6 address) + MX (Mail server) + + + + + + The field MX Priority is required. + SetIfConstraint + rr + MX + + + + + + + The field MX Host is required. + SetIfConstraint + rr + MX + + + + + + + The field IP address is required. + SetIfConstraint + rr + A + + + + + N + /^([\t\n\v\f\r 0-9a-zA-Z.,_\x{00A0}-\x{FFFF}]){1,255}$/u + Description should be a string between 1 and 255 characters + + + + + + + 1 + Y + + + + + OPNsense.Unbound.Unbound + hosts.host + domain + + + Y + + + + + The host field is required if a domain has not been specified. + SetIfConstraint + domain + + + + Y + + + + + The domain field is required if a host has not been specified. + SetIfConstraint + hostname + + + + /^(?:(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$/i + A valid domain must be specified. + + + + + + + 1 + Y + + + Y + /^(?:(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$/i + A valid domain must be specified. + + + Y + + + N + /^([\t\n\v\f\r 0-9a-zA-Z.,_\x{00A0}-\x{FFFF}]){1,255}$/u + Description should be a string between 1 and 255 characters + + + N diff --git a/src/opnsense/mvc/app/views/OPNsense/Unbound/overrides.volt b/src/opnsense/mvc/app/views/OPNsense/Unbound/overrides.volt new file mode 100755 index 000000000..d5a19128c --- /dev/null +++ b/src/opnsense/mvc/app/views/OPNsense/Unbound/overrides.volt @@ -0,0 +1,289 @@ +{# + # Copyright (c) 2014-2022 Deciso B.V. + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without modification, + # are permitted provided that the following conditions are met: + # + # 1. Redistributions of source code must retain the above copyright notice, + # this list of conditions and the following disclaimer. + # + # 2. Redistributions in binary form must reproduce the above copyright notice, + # this list of conditions and the following disclaimer in the documentation + # and/or other materials provided with the distribution. + # + # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + # POSSIBILITY OF SUCH DAMAGE. + #} + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + +
{{ lang._('ID') }}{{ lang._('Enabled') }}{{ lang._('Host') }}{{ lang._('Domain') }}{{ lang._('Type') }}{{ lang._('Value') }}{{ lang._('Description') }}{{ lang._('Edit') }} | {{ lang._('Delete') }}
+ + +
+
+ {{ lang._('Entries in this section override individual results from the forwarders.') }} + {{ lang._('Use these for changing DNS results or for adding custom DNS records.') }} + {{ lang._('Keep in mind that all resource record types (i.e. A, AAAA, MX, etc. records) of a specified host below are being overwritten.') }} +
+
+ +
+ + + + + + + + + + + + + + + + + + + +
{{ lang._('ID') }}{{ lang._('Enabled') }}{{ lang._('Domain') }}{{ lang._('IP') }}{{ lang._('Description') }}{{ lang._('Edit') }} | {{ lang._('Delete') }}
+ + +
+
+ {{ lang._('Entries in this area override an entire domain by specifying an authoritative DNS server to be queried for that domain.') }} +
+
+
+ +
+ + + + + + + + + + + + + + + + + + +
{{ lang._('ID') }}{{ lang._('Enabled') }}{{ lang._('Host') }}{{ lang._('Domain') }}{{ lang._('Commands') }}
+ + +
+
+ +
+ + + + + + + +
+ +
+
+ +{{ partial("layout_partials/base_dialog",['fields':formDialogHostOverride,'id':'DialogHostOverride','label':lang._('Edit Host Override')])}} +{{ partial("layout_partials/base_dialog",['fields':formDialogHostAlias,'id':'DialogHostAlias','label':lang._('Edit Host Override Alias')])}} +{{ partial("layout_partials/base_dialog",['fields':formDialogDomainOverride,'id':'DialogDomainOverride','label':lang._('Edit Domain Override')])}} diff --git a/src/opnsense/service/modules/addons/template_helpers.py b/src/opnsense/service/modules/addons/template_helpers.py index c886563da..ec60075dd 100644 --- a/src/opnsense/service/modules/addons/template_helpers.py +++ b/src/opnsense/service/modules/addons/template_helpers.py @@ -33,7 +33,6 @@ import glob import collections import netaddr - class SortKeyHelper: """ generate item key for sort function """ diff --git a/src/opnsense/service/modules/template.py b/src/opnsense/service/modules/template.py index 00716a008..242872297 100644 --- a/src/opnsense/service/modules/template.py +++ b/src/opnsense/service/modules/template.py @@ -69,6 +69,9 @@ class Template(object): self._j2_env.filters['shlex_split'] = shlex.split self._j2_env.filters['regex_replace'] = lambda value, pattern, replacement: re.sub(pattern, replacement, value) + # register additional tests + self._j2_env.tests['regex_match'] = lambda value, pattern: bool(re.match(pattern, value)) + @staticmethod def _encode_idna(x): """ encode string to idna, preserve leading dots diff --git a/src/opnsense/service/templates/OPNsense/Unbound/core/+TARGETS b/src/opnsense/service/templates/OPNsense/Unbound/core/+TARGETS index a6eff6f6f..d0234382e 100644 --- a/src/opnsense/service/templates/OPNsense/Unbound/core/+TARGETS +++ b/src/opnsense/service/templates/OPNsense/Unbound/core/+TARGETS @@ -1,5 +1,7 @@ blocklists.conf:/tmp/unbound-blocklists.conf dot.conf:/usr/local/etc/unbound.opnsense.d/dot.conf +private_domains.conf:/var/unbound/private_domains.conf +domainoverrides.conf:/usr/local/etc/unbound.opnsense.d/domainoverrides.conf miscellaneous.conf:/usr/local/etc/unbound.opnsense.d/miscellaneous.conf root.min.hints:/var/unbound/root.hints unbound_dhcpd.conf:/usr/local/etc/unbound_dhcpd.conf diff --git a/src/opnsense/service/templates/OPNsense/Unbound/core/domainoverrides.conf b/src/opnsense/service/templates/OPNsense/Unbound/core/domainoverrides.conf new file mode 100755 index 000000000..107c7976e --- /dev/null +++ b/src/opnsense/service/templates/OPNsense/Unbound/core/domainoverrides.conf @@ -0,0 +1,17 @@ +{% if not helpers.empty('OPNsense.unboundplus.domains.domain') %} +{% set forwardlocal = namespace(found=false) %} +{% for domain in helpers.toList('OPNsense.unboundplus.domains.domain') %} +{% if domain.enabled == '1' %} +forward-zone: + name: "{{ domain.domain }}" +{% if domain.server.startswith('127.') or domain.server == '::1' %} +{% set forwardlocal.found = true %} +{% endif%} + forward-addr: {{ domain.server }} +{% endif %} +{% endfor %} +{% if forwardlocal.found %} +server: + do-not-query-localhost: no +{% endif %} +{% endif%} \ No newline at end of file diff --git a/src/opnsense/service/templates/OPNsense/Unbound/core/private_domains.conf b/src/opnsense/service/templates/OPNsense/Unbound/core/private_domains.conf new file mode 100755 index 000000000..4bd85236a --- /dev/null +++ b/src/opnsense/service/templates/OPNsense/Unbound/core/private_domains.conf @@ -0,0 +1,13 @@ +{% if not helpers.empty('OPNsense.unboundplus.domains.domain') %} +# Set private domains in case authoritative name server returns a Private IP address +{% for domain in helpers.toList('OPNsense.unboundplus.domains.domain') %} +{% if domain.enabled == '1' %} +domain-insecure: "{{ domain.domain }}" +{% if domain.domain is regex_match('.+\.(in-addr|ip6)\.arpa\.?$') %} +local-zone: {{ domain.domain }} typetransparent +{% elif not helpers.exists('system.webgui.nodnsrebindcheck') %} +private-domain: "{{ domain.domain }}" +{% endif%} +{% endif %} +{% endfor %} +{% endif %} diff --git a/src/www/services_unbound_domainoverride_edit.php b/src/www/services_unbound_domainoverride_edit.php deleted file mode 100644 index 98b58b38a..000000000 --- a/src/www/services_unbound_domainoverride_edit.php +++ /dev/null @@ -1,166 +0,0 @@ - - * Copyright (C) 2003-2005 Bob Zoller - * Copyright (C) 2003-2005 Manuel Kasper - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -require_once("guiconfig.inc"); -require_once("interfaces.inc"); - -$a_domainOverrides = &config_read_array('unbound', 'domainoverrides'); - -if ($_SERVER['REQUEST_METHOD'] === 'GET') { - if (isset($_GET['id']) && !empty($a_domainOverrides[$_GET['id']])) { - $id = $_GET['id']; - } - $pconfig = array(); - $pconfig['domain'] = isset($id) && !empty($a_domainOverrides[$id]['domain']) ? $a_domainOverrides[$id]['domain'] : null; - $pconfig['ip'] = isset($id) && !empty($a_domainOverrides[$id]['ip']) ? $a_domainOverrides[$id]['ip'] : null; - $pconfig['descr'] = isset($id) && !empty($a_domainOverrides[$id]['descr']) ? $a_domainOverrides[$id]['descr'] : null; -} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { - if (isset($_GET['id']) && !empty($a_domainOverrides[$_POST['id']])) { - $id = $_POST['id']; - } - $input_errors= array(); - $pconfig = $_POST; - - /* input validation */ - $reqdfields = explode(" ", "domain ip"); - $reqdfieldsn = array(gettext("Domain"),gettext("IP address")); - - do_input_validation($pconfig, $reqdfields, $reqdfieldsn, $input_errors); - if (!empty($pconfig['domain']) && substr($pconfig['domain'], 0, 6) == '_msdcs') { - $subdomainstr = substr($pconfig['domain'], 7); - if ($subdomainstr && !is_domain($subdomainstr)) { - $input_errors[] = gettext("A valid domain must be specified after _msdcs."); - } - } elseif (!empty($pconfig['domain']) && !is_domain($_POST['domain'])) { - $input_errors[] = gettext("A valid domain must be specified."); - } - - if (!empty($pconfig['ip'])) { - if (strpos($pconfig['ip'],'@') !== false) { - $ip_details = explode("@", $pconfig['ip']); - if (!is_ipaddr($ip_details[0]) && !is_port($ip_details[1])) { - $input_errors[] = gettext("A valid IP address and port must be specified, for example 192.168.100.10@5353."); - } - } elseif (!is_ipaddr($pconfig['ip'])) { - $input_errors[] = gettext("A valid IP address must be specified, for example 192.168.100.10."); - } - } - - if (count($input_errors) == 0) { - $doment = array(); - $doment['domain'] = $pconfig['domain']; - $doment['ip'] = $pconfig['ip']; - $doment['descr'] = $pconfig['descr']; - - if (isset($id)) { - $a_domainOverrides[$id] = $doment; - } else { - $a_domainOverrides[] = $doment; - } - - mark_subsystem_dirty('unbound'); - write_config(); - header(url_safe('Location: /services_unbound_overrides.php')); - exit; - } -} - -$service_hook = 'unbound'; -legacy_html_escape_form_data($pconfig); -include("head.inc"); -?> - - -
-
-
- 0) print_input_errors($input_errors); ?> -
-
-
-
- - - - - - - - - - - - - - - - - - - - - -
- - -
- - -
- - -
- - -
  - - - - - -
-
-
-
-
-
-
-
- diff --git a/src/www/services_unbound_host_edit.php b/src/www/services_unbound_host_edit.php deleted file mode 100644 index 9102232d7..000000000 --- a/src/www/services_unbound_host_edit.php +++ /dev/null @@ -1,377 +0,0 @@ - - * Copyright (C) 2014-2016 Deciso B.V. - * Copyright (C) 2014 Warren Baker - * Copyright (C) 2003-2004 Bob Zoller - * Copyright (C) 2003-2004 Manuel Kasper - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -require_once("guiconfig.inc"); -require_once("interfaces.inc"); - -$a_hosts = &config_read_array('unbound', 'hosts'); - -if ($_SERVER['REQUEST_METHOD'] === 'GET') { - if (isset($_GET['id']) && !empty($a_hosts[$_GET['id']])) { - $id = $_GET['id']; - } - $pconfig = array(); - foreach (array('rr', 'host', 'domain', 'ip', 'mxprio', 'mx', 'descr', 'aliases') as $fieldname) { - if (isset($id) && !empty($a_hosts[$id][$fieldname])) { - $pconfig[$fieldname] = $a_hosts[$id][$fieldname]; - } else { - $pconfig[$fieldname] = null; - } - } -} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') { - if (isset($_POST['id']) && !empty($a_hosts[$_POST['id']])) { - $id = $_POST['id']; - } - - $input_errors = array(); - $pconfig = $_POST; - - $pconfig['aliases'] = array(); - if (isset($pconfig['aliases_host'])) { - $pconfig['aliases']['item'] = array(); - foreach ($pconfig['aliases_host'] as $opt_seq => $opt_host) { - if (empty($opt_host) && empty($pconfig['aliases_domain'][$opt_seq]) && empty($pconfig['aliases_descr'][$opt_seq])) { - continue; - } - $pconfig['aliases']['item'][] = array( - 'domain' => $pconfig['aliases_domain'][$opt_seq], - 'descr' => $pconfig['aliases_descr'][$opt_seq], - 'host' => $opt_host, - ); - } - } - - $reqdfields = explode(" ", "domain rr"); - $reqdfieldsn = array(gettext("Domain"),gettext("Type")); - - do_input_validation($pconfig, $reqdfields, $reqdfieldsn, $input_errors); - - if (!empty($pconfig['host']) && !is_hostname($pconfig['host']) && $pconfig['host'] != '*') { - $input_errors[] = gettext("The hostname can only contain the characters A-Z, 0-9 and '-'."); - } - - if (!empty($pconfig['domain']) && !is_domain($pconfig['domain'])) { - $input_errors[] = gettext("A valid domain must be specified."); - } - - if (!empty($pconfig['domain']) && $pconfig['domain'] == $config['system']['domain'] && $pconfig['host'] == '*') { - $input_errors[] = sprintf( - gettext("A wildcard domain override is not supported for the local domain '%s'."), - $config['system']['domain'] - ); - } - - switch ($pconfig['rr']) { - case 'A': /* also: AAAA */ - $reqdfields = explode(" ", "ip"); - $reqdfieldsn = array(gettext("IP address")); - do_input_validation($pconfig, $reqdfields, $reqdfieldsn, $input_errors); - - if (!empty($pconfig['ip']) && !is_ipaddr($pconfig['ip'])) { - $input_errors[] = gettext("A valid IP address must be specified."); - } - break; - case 'MX': - $reqdfields = explode(" ", "mxprio mx"); - $reqdfieldsn = array(gettext("MX Priority"), gettext("MX Host")); - do_input_validation($pconfig, $reqdfields, $reqdfieldsn, $input_errors); - - if (!empty($pconfig['mxprio']) && !is_numericint($pconfig['mxprio'])) { - $input_errors[] = gettext("A valid MX priority must be specified."); - } - - if (!empty($pconfig['mx']) && !is_domain($pconfig['mx'])) { - $input_errors[] = gettext("A valid MX host must be specified."); - } - break; - default: - $input_errors[] = gettext("A valid resource record type must be specified."); - break; - } - - foreach ($pconfig['aliases']['item'] as $idx => $alias) { - if (!empty($alias['host']) && !is_hostname($alias['host'])) { - $input_errors[] = gettext('Hostnames in alias list can only contain the characters A-Z, 0-9 and \'-\'.'); - } - if (!empty($alias['domain']) && !is_domain($alias['domain'])) { - $input_errors[] = gettext('A valid domain must be specified in alias list.'); - } - if (empty($alias['host']) && empty($alias['domain'])) { - $input_errors[] = gettext('A valid hostname or domain must be specified in alias list.'); - } - } - - if (count($input_errors) == 0) { - $hostent = array(); - $hostent['host'] = $pconfig['host']; - $hostent['domain'] = $pconfig['domain']; - /* distinguish between A and AAAA by parsing the passed IP address */ - $hostent['rr'] = ($pconfig['rr'] == 'A' && is_ipaddrv6($pconfig['ip'])) ? 'AAAA' : $pconfig['rr']; - $hostent['ip'] = $pconfig['ip']; - $hostent['mxprio'] = $pconfig['mxprio']; - $hostent['mx'] = $pconfig['mx']; - $hostent['descr'] = $pconfig['descr']; - $hostent['aliases'] = $pconfig['aliases']; - - if (isset($id)) { - $a_hosts[$id] = $hostent; - } else { - $a_hosts[] = $hostent; - } - - usort($a_hosts, function ($a, $b) { - return strcasecmp($a['host'], $b['host']); - }); - - mark_subsystem_dirty('unbound'); - write_config(); - header(url_safe('Location: /services_unbound_overrides.php')); - exit; - } -} - -$service_hook = 'unbound'; -legacy_html_escape_form_data($pconfig); -include("head.inc"); -?> - - - - -
-
-
- 0) print_input_errors($input_errors); ?> -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - -
- - - - - - - - - - - null, 'value' => null, 'type' => null); - - foreach($aliases as $item): ?> - - - - - - - - - - - - - -
-
-
- - - - - -
-
-
- -
  - - - - - -
-
-
-
-
-
-
-
- diff --git a/src/www/services_unbound_overrides.php b/src/www/services_unbound_overrides.php deleted file mode 100644 index 93c98ec74..000000000 --- a/src/www/services_unbound_overrides.php +++ /dev/null @@ -1,252 +0,0 @@ - - * Copyright (C) 2014-2016 Deciso B.V. - * Copyright (C) 2014 Warren Baker - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -require_once("guiconfig.inc"); -require_once("system.inc"); -require_once("interfaces.inc"); -require_once("plugins.inc.d/unbound.inc"); - -$a_hosts = &config_read_array('unbound', 'hosts'); -$a_domains = &config_read_array('unbound', 'domainoverrides'); - -/* Backwards compatibility for records created before introducing RR types. */ -foreach ($a_hosts as $i => $hostent) { - if (!isset($hostent['rr'])) { - $a_hosts[$i]['rr'] = is_ipaddrv6($hostent['ip']) ? 'AAAA' : 'A'; - } -} - -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - $pconfig = $_POST; - if (!empty($pconfig['apply'])) { - unbound_configure_do(); - clear_subsystem_dirty('unbound'); - header(url_safe('Location: /services_unbound_overrides.php')); - exit; - } elseif (!empty($pconfig['act']) && $pconfig['act'] == 'del') { - if (isset($pconfig['id']) && !empty($a_hosts[$pconfig['id']])) { - unset($a_hosts[$pconfig['id']]); - write_config(); - mark_subsystem_dirty('unbound'); - exit; - } - } elseif (!empty($pconfig['act']) && $pconfig['act'] == 'doverride') { - if (isset($pconfig['id']) && !empty($a_domains[$pconfig['id']])) { - unset($a_domains[$pconfig['id']]); - write_config(); - mark_subsystem_dirty('unbound'); - exit; - } - } -} - -$service_hook = 'unbound'; - -legacy_html_escape_form_data($a_hosts); -legacy_html_escape_form_data($a_domains); - -include_once("head.inc"); - -?> - - - - - -
-
-
- - - -
-
-
-
- - - - - - - - - - - - - - $hostent): ?> - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- -
- - - -
-
-
-
-
-
-
- - - - - - - - - - - - $doment): ?> - - - - - - - - - - - -
- -
- - -
- -
-
-
-
-
-
-
-
-