dns/bind: full zone management (#1276)

This commit is contained in:
Michael
2019-03-27 19:16:50 +01:00
committed by Franco Fichtner
parent d256219276
commit 363069a983
15 changed files with 728 additions and 7 deletions
@@ -0,0 +1,74 @@
<?php
/**
* Copyright (C) 2019 Michael Muenz <m.muenz@gmail.com>
* Copyright (C) 2019 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.
*
*/
namespace OPNsense\Bind\Api;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Core\Backend;
class DomainController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'domain';
protected static $internalModelClass = '\OPNsense\Bind\Domain';
public function searchDomainAction()
{
return $this->searchBase('domains.domain', array(
"enabled", "type", "masterip", "domainname", "allowtransfer", "allowquery", "ttl",
"refresh", "retry", "expire", "negative", "mailadmin", "dnsserver"
));
}
public function getDomainAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('domain', 'domains.domain', $uuid);
}
public function addDomainAction($uuid = null)
{
return $this->addBase('domain', 'domains.domain');
}
public function delDomainAction($uuid)
{
return $this->delBase('domains.domain', $uuid);
}
public function setDomainAction($uuid = null)
{
return $this->setBase('domain', 'domains.domain', $uuid);
}
public function toggleDomainAction($uuid)
{
return $this->toggleBase('domains.domain', $uuid);
}
}
@@ -0,0 +1,127 @@
<?php
/**
* Copyright (C) 2019 Michael Muenz <m.muenz@gmail.com>
* Copyright (C) 2019 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.
*
*/
namespace OPNsense\Bind\Api;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Bind\Domain;
use \OPNsense\Core\Config;
class RecordController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'record';
protected static $internalModelClass = '\OPNsense\Bind\Record';
/**
* update parent domain serial
* @param $uuid string
* @throws \OPNsense\Base\ModelException
* @throws \ReflectionException
*/
private function setDomainSerial($uuid)
{
if ($this->request->isPost()) {
$record = $this->getModel()->getRecord($uuid);
if ($record !== null) {
(new Domain)->updateSerial((string)$record->domain)->serializeToConfig();
Config::getInstance()->save();
}
}
}
public function searchRecordAction()
{
$domain = $this->request->get('domain');
$filter_funct = null;
if (!empty($domain)) {
$filter_funct = function($record) use ($domain) {
return $record->domain == $domain;
};
}
return $this->searchBase('records.record',
array("enabled", "domain", "name", "type", "value"), null, $filter_funct
);
}
public function getRecordAction($uuid = null)
{
$this->sessionClose();
$domain = $this->request->get('domain');
$result = $this->getBase('record', 'records.record', $uuid);
if ($uuid == null && !empty($result['record']['domain'])) {
// set domain selection
foreach ($result['record']['domain'] as $key => &$value) {
if ($key == $domain) {
$value['selected'] = 1;
} else {
$value['selected'] = 0;
}
}
}
return $result;
}
public function addRecordAction()
{
$result = $this->addBase('record', 'records.record');
if (!empty($result['uuid'])) {
$this->setDomainSerial($result['uuid']);
}
return $result;
}
public function delRecordAction($uuid)
{
$result = $this->delBase('records.record', $uuid);
if ($result['result'] == 'deleted') {
$this->setDomainSerial($uuid);
}
return $result;
}
public function setRecordAction($uuid = null)
{
$result = $this->setBase('record', 'records.record', $uuid);
if ($result['result'] == 'saved') {
$this->setDomainSerial($uuid);
}
return $result;
}
public function toggleRecordAction($uuid)
{
$result = $this->toggleBase('records.record', $uuid);
if (!empty($result['changed'])) {
$this->setDomainSerial($uuid);
}
return $result;
}
}
@@ -1,7 +1,7 @@
<?php
/*
Copyright (C) 2018 Michael Muenz <m.muenz@gmail.com>
Copyright (C) 2018-2019 Michael Muenz <m.muenz@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,8 @@ class GeneralController extends \OPNsense\Base\IndexController
$this->view->generalForm = $this->getForm("general");
$this->view->dnsblForm = $this->getForm("dnsbl");
$this->view->formDialogEditBindAcl = $this->getForm("dialogEditBindAcl");
$this->view->formDialogEditBindDomain = $this->getForm("dialogEditBindDomain");
$this->view->formDialogEditBindRecord = $this->getForm("dialogEditBindRecord");
$this->view->pick('OPNsense/Bind/general');
}
}
@@ -0,0 +1,80 @@
<form>
<field>
<id>domain.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>This will enable or disable the ACL.</help>
</field>
<field>
<id>domain.type</id>
<label>Type</label>
<type>dropdown</type>
<help>Set the type for this domain.</help>
</field>
<field>
<id>domain.masterip</id>
<label>Master IP</label>
<type>text</type>
<help>Set the IP address of master server when using slave mode.</help>
</field>
<field>
<id>domain.domainname</id>
<label>Domain Name</label>
<type>text</type>
<help>Set the name for this ACL.</help>
</field>
<field>
<id>domain.allowtransfer</id>
<label>Allow Transfer</label>
<type>dropdown</type>
<help>Define an ACL where you allow which server can retrieve your zone.</help>
</field>
<field>
<id>domain.allowquery</id>
<label>Allow Query</label>
<type>dropdown</type>
<help>Define an ACL where you allow which client are allowed to query this domain.</help>
</field>
<field>
<id>domain.ttl</id>
<label>TTL</label>
<type>text</type>
<help>Set the general TTL for this domain.</help>
</field>
<field>
<id>domain.refresh</id>
<label>Refresh Time</label>
<type>text</type>
<help>Set the time in seconds.</help>
</field>
<field>
<id>domain.retry</id>
<label>Retry Time</label>
<type>text</type>
<help>Set the time in seconds.</help>
</field>
<field>
<id>domain.expire</id>
<label>Expire Time</label>
<type>text</type>
<help>Set the time in seconds.</help>
</field>
<field>
<id>domain.negative</id>
<label>Negative TTL</label>
<type>text</type>
<help>Set the time in seconds.</help>
</field>
<field>
<id>domain.mailadmin</id>
<label>Mail Admin</label>
<type>text</type>
<help>Set the mail address of domain admin. Please replace @ with a dot.</help>
</field>
<field>
<id>domain.dnsserver</id>
<label>DNS Server</label>
<type>text</type>
<help>Set the DNS Server hosting this file. This should be the FQDN of your Firewall.</help>
</field>
</form>
@@ -0,0 +1,32 @@
<form>
<field>
<id>record.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>This will enable or disable the ACL.</help>
</field>
<field>
<id>record.domain</id>
<label>Domain</label>
<type>dropdown</type>
<help>Set the type for this record.</help>
</field>
<field>
<id>record.name</id>
<label>Name</label>
<type>text</type>
<help>Set the name for this ACL.</help>
</field>
<field>
<id>record.type</id>
<label>Type</label>
<type>dropdown</type>
<help>Set the time in seconds.</help>
</field>
<field>
<id>record.value</id>
<label>Value</label>
<type>text</type>
<help>Set the time in seconds.</help>
</field>
</form>
@@ -0,0 +1,67 @@
<?php
/*
Copyright (C) 2019 Michael Muenz <m.muenz@gmail.com>
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\Bind;
use OPNsense\Base\BaseModel;
class Domain extends BaseModel
{
/**
* {@inheritdoc}
*/
public function serializeToConfig($validateFullModel = false, $disable_validation = false)
{
$serialsToSet = array();
// collected changed records
foreach ($this->getFlatNodes() as $key => $node) {
if ($node->isFieldChanged() && (string)$node !== "") {
$domain = $node->getParentNode();
if (empty($serialsToSet[$domain->getAttribute('uuid')])) {
$serialsToSet[$domain->getAttribute('uuid')] = $domain;
}
}
}
// new serials on changed records
foreach ($serialsToSet as $domain) {
$domain->serial = (string)date("YmdHis");
}
return parent::serializeToConfig($validateFullModel, $disable_validation);
}
/**
* @param $uuid string domain uuid to update
* @return Domain
*/
public function updateSerial($uuid)
{
foreach ($this->domains->domain->iterateItems() as $domain) {
if ($domain->getAttribute('uuid') == $uuid) {
$domain->serial = (string)date("YmdHis");
return $this;
}
}
return $this;
}
}
@@ -0,0 +1,98 @@
<model>
<mount>//OPNsense/bind/domain</mount>
<description>BIND domain configuration</description>
<version>1.0.0</version>
<items>
<domains>
<domain type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<type type="OptionField">
<default>master</default>
<Required>Y</Required>
<OptionValues>
<master>master</master>
<slave>slave</slave>
</OptionValues>
</type>
<masterip type="HostnameField">
<Required>N</Required>
</masterip>
<domainname type="TextField">
<default></default>
<Required>Y</Required>
</domainname>
<allowtransfer type="ModelRelationField">
<Model>
<template>
<source>OPNsense.Bind.Acl</source>
<items>acls.acl</items>
<display>name</display>
</template>
</Model>
<Multiple>N</Multiple>
<Required>N</Required>
</allowtransfer>
<allowquery type="ModelRelationField">
<Model>
<template>
<source>OPNsense.Bind.Acl</source>
<items>acls.acl</items>
<display>name</display>
</template>
</Model>
<Multiple>N</Multiple>
<Required>N</Required>
</allowquery>
<serial type="TextField">
<Required>N</Required>
</serial>
<ttl type="IntegerField">
<default>86400</default>
<Required>Y</Required>
<MinimumValue>60</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>Set a value between 60 and 86400.</ValidationMessage>
</ttl>
<refresh type="IntegerField">
<default>21600</default>
<Required>Y</Required>
<MinimumValue>60</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>Set a value between 60 and 86400.</ValidationMessage>
</refresh>
<retry type="IntegerField">
<default>3600</default>
<Required>Y</Required>
<MinimumValue>60</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>Set a value between 60 and 86400.</ValidationMessage>
</retry>
<expire type="IntegerField">
<default>3542400</default>
<Required>Y</Required>
<MinimumValue>60</MinimumValue>
<MaximumValue>10000000</MaximumValue>
<ValidationMessage>Set a value between 60 and 10000000.</ValidationMessage>
</expire>
<negative type="IntegerField">
<default>3600</default>
<Required>Y</Required>
<MinimumValue>60</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>Set a value between 60 and 86400.</ValidationMessage>
</negative>
<mailadmin type="TextField">
<default>mail.opnsense.localdomain</default>
<Required>Y</Required>
</mailadmin>
<dnsserver type="HostnameField">
<default>opnsense.localdomain</default>
<Required>Y</Required>
</dnsserver>
</domain>
</domains>
</items>
</model>
@@ -0,0 +1,46 @@
<?php
/*
Copyright (C) 2019 Michael Muenz <m.muenz@gmail.com>
Copyright (C) 2019 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.
*/
namespace OPNsense\Bind;
use OPNsense\Base\BaseModel;
class Record extends BaseModel
{
/**
* @param $uuid string record uuid
* @return mixed record
*/
public function getRecord($uuid)
{
foreach ($this->records->record->iterateItems() as $record) {
if ($record->getAttribute('uuid') == $uuid) {
return $record;
}
}
return null;
}
}
@@ -0,0 +1,46 @@
<model>
<mount>//OPNsense/bind/record</mount>
<description>BIND record configuration</description>
<version>1.0.0</version>
<items>
<records>
<record type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<domain type="ModelRelationField">
<Required>Y</Required>
<Model>
<template>
<source>OPNsense.Bind.Domain</source>
<items>domains.domain</items>
<display>domainname</display>
</template>
</Model>
</domain>
<name type="TextField">
<default></default>
<Required>N</Required>
</name>
<type type="OptionField">
<default>A</default>
<Required>Y</Required>
<OptionValues>
<A>A</A>
<AAAA>AAAA</AAAA>
<CNAME>CNAME</CNAME>
<MX>MX</MX>
<NS>NS</NS>
<PTR>PTR</PTR>
<SRV>SRV</SRV>
<TXT>TXT</TXT>
</OptionValues>
</type>
<value type="TextField">
<Required>Y</Required>
</value>
</record>
</records>
</items>
</model>
@@ -1,7 +1,7 @@
{#
OPNsense® is Copyright © 2014 2018 by Deciso B.V.
This file is Copyright © 2018 by Michael Muenz <m.muenz@gmail.com>
OPNsense® is Copyright © 2014 2019 by Deciso B.V.
This file is Copyright © 2018 - 2019 by Michael Muenz <m.muenz@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
@@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
<li class="active"><a data-toggle="tab" href="#general">{{ lang._('General') }}</a></li>
<li><a data-toggle="tab" href="#dnsbl">{{ lang._('DNSBL') }}</a></li>
<li><a data-toggle="tab" href="#acls">{{ lang._('ACLs') }}</a></li>
<li><a data-toggle="tab" href="#domains">{{ lang._('Domains') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
@@ -81,19 +82,80 @@ POSSIBILITY OF SUCH DAMAGE.
<br /><br />
</div>
</div>
<div id="domains" class="tab-pane fade in">
<table id="grid-domains" class="table table-responsive" data-editDialog="dialogEditBindDomain">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="type" data-type="string" data-visible="true">{{ lang._('Type') }}</th>
<th data-column-id="domainname" data-type="string" data-visible="true">{{ lang._('Domain') }}</th>
<th data-column-id="ttl" data-type="string" data-visible="true">{{ lang._('TTL') }}</th>
<th data-column-id="refresh" data-type="string" data-visible="true">{{ lang._('Refresh') }}</th>
<th data-column-id="retry" data-type="string" data-visible="true">{{ lang._('Retry') }}</th>
<th data-column-id="expire" data-type="string" data-visible="true">{{ lang._('Expire') }}</th>
<th data-column-id="negative" data-type="string" data-visible="true">{{ lang._('Negative TTL') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
</td>
</tr>
</tfoot>
</table>
<hr/>
<div id="record-area">
<table id="grid-records" class="table table-responsive" data-editDialog="dialogEditBindRecord">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="domain" data-type="string" data-visible="true">{{ lang._('Domain') }}</th>
<th data-column-id="name" data-type="string" data-visible="true">{{ lang._('Name') }}</th>
<th data-column-id="type" data-type="string" data-visible="true">{{ lang._('Type') }}</th>
<th data-column-id="value" data-type="string" data-visible="true">{{ lang._('Value') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button id="recordAddBtn" data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct_domain" type="button"><b>{{ lang._('Save') }}</b> <i id="saveAct_domain_progress"></i></button>
<br /><br />
</div>
</div>
</div>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBindAcl,'id':'dialogEditBindAcl','label':lang._('Edit ACL')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBindDomain,'id':'dialogEditBindDomain','label':lang._('Edit Domains')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBindRecord,'id':'dialogEditBindRecord','label':lang._('Edit Records')])}}
<script>
$( document ).ready(function() {
var data_get_map = {'frm_general_settings':"/api/bind/general/get"};
let data_get_map = {'frm_general_settings':"/api/bind/general/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
var data_get_map2 = {'frm_dnsbl_settings':"/api/bind/dnsbl/get"};
let data_get_map2 = {'frm_dnsbl_settings':"/api/bind/dnsbl/get"};
mapDataToFormUI(data_get_map2).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
@@ -110,6 +172,53 @@ $( document ).ready(function() {
'toggle':'/api/bind/acl/toggleAcl/'
}
);
$("#grid-domains").UIBootgrid({
'search':'/api/bind/domain/searchDomain',
'get':'/api/bind/domain/getDomain/',
'set':'/api/bind/domain/setDomain/',
'add':'/api/bind/domain/addDomain/',
'del':'/api/bind/domain/delDomain/',
'toggle':'/api/bind/domain/toggleDomain/',
options:{
selection: true,
multiSelect: false,
rowSelect: true,
}
}).on("selected.rs.jquery.bootgrid", function(e, rows) {
$("#grid-records").bootgrid('reload');
}).on("deselected.rs.jquery.bootgrid", function(e, rows) {
$("#grid-records").bootgrid('reload');
}).on("loaded.rs.jquery.bootgrid", function (e) {
let ids = $("#grid-domains").bootgrid("getCurrentRows");
if (ids.length > 0) {
$("#grid-domains").bootgrid('select', [ids[0].uuid]);
}
});
$("#grid-records").UIBootgrid({
'search':'/api/bind/record/searchRecord',
'get':'/api/bind/record/getRecord/',
'set':'/api/bind/record/setRecord/',
'add':'/api/bind/record/addRecord/',
'del':'/api/bind/record/delRecord/',
'toggle':'/api/bind/record/toggleRecord/',
options:{
useRequestHandlerOnGet: true,
requestHandler: function() {
let request = {'domain': 'not_found'};
let ids = $("#grid-domains").bootgrid("getSelectedRows");
if (ids.length > 0) {
request['domain'] = ids[0];
$("#recordAddBtn").show();
$("#record-area").show();
} else {
$("#recordAddBtn").hide();
$("#record-area").hide();
}
return request;
}
}
});
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/bind/general/set", formid='frm_general_settings',callback_ok=function(){
@@ -143,5 +252,12 @@ $( document ).ready(function() {
});
});
$("#saveAct_domain").click(function(){
$("#saveAct_domain_progress").addClass("fa fa-spinner fa-pulse");
ajaxCall("/api/bind/service/reconfigure", {}, function(data,status) {
updateServiceControlUI('bind');
$("#saveAct_domain_progress").removeClass("fa fa-spinner fa-pulse");
});
});
});
</script>
@@ -1,5 +1,6 @@
bing.db:/usr/local/etc/namedb/master/bing.db
blacklist.db:/usr/local/etc/namedb/master/blacklist.db
domain.db:/usr/local/etc/namedb/master/[OPNsense.bind.domain.domains.domain.%.domainname].db
duckduckgo.db:/usr/local/etc/namedb/master/duckduckgo.db
google.db:/usr/local/etc/namedb/master/google.db
named:/etc/rc.conf.d/named
@@ -0,0 +1,17 @@
{% if helpers.exists('OPNsense.bind.general.enabled') and OPNsense.bind.general.enabled == '1' %}
{% if helpers.exists('OPNsense.bind.domain.domains.domain') %}
{% for domaindb in helpers.toList('OPNsense.bind.domain.domains.domain') %}
{% if TARGET_FILTERS['OPNsense.bind.domain.domains.domain.' ~ loop.index0] %}
{% if domaindb.enabled == '1' and domaindb.type == 'master' %}
$TTL {{ domaindb.ttl }}
@ IN SOA {{ domaindb.dnsserver }}. {{ domaindb.mailadmin }}. ( {{ domaindb.serial|trim }} {{ domaindb.refresh }} {{ domaindb.retry }} {{ domaindb.expire }} {{ domaindb.negative }} )
{% for record in helpers.sortDictList(OPNsense.bind.record.records.record, 'name', 'type' ) %}
{% if record.domain == domaindb['@uuid'] %}
{{ record.name }} {{ record.type }} {{ record.value }}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
@@ -103,6 +103,18 @@ zone "rpzyoutube" { type master; file "/usr/local/etc/namedb/master/youtube.db";
zone "rpzbing" { type master; file "/usr/local/etc/namedb/master/bing.db"; notify no; check-names ignore; };
{% endif %}
{% endif %}
{% if helpers.exists('OPNsense.bind.domain.domains.domain') %}
{% for domain in helpers.toList('OPNsense.bind.domain.domains.domain') %}
{% if domain.enabled == '1' %}
{% set allow_transfer = helpers.getUUID(domain.allowtransfer) %}
{% set allow_query = helpers.getUUID(domain.allowquery) %}
zone "{{ domain.domainname }}" { type {{ domain.type }}; {% if domain.type == 'slave' %}masters { {{ domain.masterip }}; }; file "/usr/local/etc/namedb/slave/{{ domain.domainname }}.db"; {% else %}file "/usr/local/etc/namedb/master/{{ domain.domainname }}.db"; {% endif %}{% if domain.allowtransfer is defined %} allow-transfer { {{ allow_transfer.name }}; };{% endif %}{% if domain.allowquery is defined %} allow-query { {{ allow_query.name }}; };{% endif %} };
{% endif %}
{% endfor %}
{% endif %}
logging {
channel default_log {
file "/var/log/named/named.log" versions 3 size {{ OPNsense.bind.general.logsize }}m;