mirror of
https://github.com/openwrt/luci.git
synced 2025-10-12 20:35:22 +00:00
301 lines
11 KiB
JavaScript
301 lines
11 KiB
JavaScript
'use strict';
|
|
'require fs';
|
|
'require form';
|
|
'require rpc';
|
|
'require uci';
|
|
'require ui';
|
|
'require view';
|
|
'require tools.widgets as widgets';
|
|
|
|
const UBNET = 'https://nlnetlabs.nl/projects/unbound/about/';
|
|
const README = 'https://github.com/openwrt/packages/blob/master/net/unbound/files/README.md';
|
|
|
|
const callRcInit = rpc.declare({
|
|
object: 'rc',
|
|
method: 'init',
|
|
params: [ 'name', 'action' ],
|
|
expect: { result: false }
|
|
});
|
|
|
|
return view.extend({
|
|
load() {
|
|
return Promise.all([
|
|
uci.load('unbound'),
|
|
uci.load('dhcp'),
|
|
]);
|
|
},
|
|
|
|
render([unboundCfg, dhcpCfg]) {
|
|
const m = new form.Map('unbound', _('Recursive DNS'),
|
|
_("Unbound <a href=\"%s\" target=\"_blank\">(NLnet Labs)</a> is a validating, recursive, and caching DNS resolver <a href=\"%s\" target=\"_blank\">(help)</a>.".format(UBNET, README)));
|
|
|
|
const s = m.section(form.NamedSection, 'ub_main', 'unbound');
|
|
s.anonymous = true;
|
|
s.addremove = false;
|
|
|
|
const manual = uci.get('unbound', 'ub_main', 'manual_conf');
|
|
const dhcpLink = uci.get('unbound', 'ub_main', 'dhcp_link');
|
|
const leasetrig = uci.get('dhcp', 'odhcpd', 'leasetrigger') || 'undefined';
|
|
|
|
if (manual === '0' && dhcpLink === 'odhcpd' && leasetrig !== '/usr/lib/unbound/odhcpd.sh') {
|
|
ui.addTimeLimitedNotification(null, E('p', _('Note: local DNS is configured to look at odhpcd, but odhpcd UCI lease trigger is incorrectly set:') +
|
|
"dhcp.odhcpd.leasetrigger='" + leasetrig + "'"), 15000, 'note');
|
|
}
|
|
|
|
// Tabs
|
|
s.tab('basic', _('Basic'));
|
|
if (manual === '0') {
|
|
s.tab('advanced', _('Advanced'));
|
|
s.tab('dhcp', _('DHCP'));
|
|
s.tab('resource', _('Resource'));
|
|
}
|
|
|
|
// Basic tab items
|
|
const ena = s.taboption('basic', form.Flag, 'enabled', _('Enable Unbound'),
|
|
_('Enable the initialization scripts for Unbound'));
|
|
ena.rmempty = false;
|
|
|
|
const mcf = s.taboption('basic', form.Flag, 'manual_conf', _('Manual Conf'),
|
|
_('Skip UCI and use /etc/unbound/unbound.conf'));
|
|
mcf.rmempty = false;
|
|
|
|
if (manual === '0') {
|
|
s.taboption('basic', form.Flag, 'localservice', _('Local Service'),
|
|
_('Accept queries only from local subnets')).rmempty = false;
|
|
|
|
s.taboption('basic', form.Flag, 'validator', _('Enable DNSSEC'),
|
|
_('Enable the DNSSEC validator module')).rmempty = false;
|
|
|
|
const nvd = s.taboption('basic', form.Flag, 'validator_ntp', _('DNSSEC NTP Fix'),
|
|
_('Break the loop where DNSSEC needs NTP and NTP needs DNS'));
|
|
nvd.optional = true;
|
|
nvd.default = '1';
|
|
nvd.depends('validator', '1');
|
|
|
|
const prt = s.taboption('basic', form.Value, 'listen_port', _('Listening Port'),
|
|
_('Choose Unbounds listening port'));
|
|
prt.datatype = 'port';
|
|
prt.placeholder = '53';
|
|
} else {
|
|
const ag2b = s.taboption('basic', form.Value, 'root_age', _('Root DSKEY Age'),
|
|
_('Limit days between RFC5011 copies to reduce flash writes'));
|
|
ag2b.datatype = 'and(uinteger,min(1),max(99))';
|
|
ag2b.value('3', '3');
|
|
ag2b.value('9', '9 (' + _('default') + ')');
|
|
ag2b.value('12', '12');
|
|
ag2b.value('24', '24');
|
|
ag2b.value('99', '99 (' + _('never') + ')');
|
|
|
|
const tgrb = s.taboption('basic', widgets.NetworkSelect, 'trigger_interface', _('Trigger Networks'),
|
|
_('Networks that may trigger Unbound to reload (avoid wan6)'));
|
|
tgrb.multiple = true;
|
|
tgrb.rmempty = true;
|
|
tgrb.nocreate = true;
|
|
}
|
|
|
|
// Advanced, DHCP & Resource tabs only if manual===0
|
|
if (manual === '0') {
|
|
const rlh = s.taboption('advanced', form.Flag, 'rebind_localhost', _('Filter Localhost Rebind'),
|
|
_('Protect against upstream response of 127.0.0.0/8'));
|
|
rlh.rmempty = false;
|
|
|
|
const rpv = s.taboption('advanced', form.ListValue, 'rebind_protection', _('Filter Private Rebind'),
|
|
_('Protect against upstream responses within local subnets'));
|
|
rpv.rmempty = false;
|
|
rpv.value('0', _('No Filter'));
|
|
rpv.value('1', _('Filter Private Address'));
|
|
rpv.value('2', _('Filter Entire Subnet'));
|
|
|
|
const d64 = s.taboption('advanced', form.Flag, 'dns64', _('Enable DNS64'),
|
|
_('Enable the DNS64 module'));
|
|
d64.rmempty = false;
|
|
|
|
const pfx = s.taboption('advanced', form.Value, 'dns64_prefix', _('DNS64 Prefix'),
|
|
_('Prefix for generated DNS64 addresses'));
|
|
pfx.datatype = 'ip6addr';
|
|
pfx.placeholder = '64:ff9b::/96';
|
|
pfx.optional = true;
|
|
pfx.depends('dns64', '1');
|
|
|
|
const exga = s.taboption('advanced', form.Flag, 'exclude_ipv6_ga', _('Exclude IPv6 GA'));
|
|
|
|
const din = s.taboption('advanced', form.DynamicList, 'domain_insecure', _('Domain Insecure'),
|
|
_('List domains to bypass checks of DNSSEC'));
|
|
din.depends('validator', '1');
|
|
|
|
const ag2 = s.taboption('advanced', form.Value, 'root_age', _('Root DSKEY Age'));
|
|
ag2.datatype = 'and(uinteger,min(1),max(99))';
|
|
ag2.value('3', '3');
|
|
ag2.value('9', '9 (' + _('default') + ')');
|
|
ag2.value('12', '12');
|
|
ag2.value('24', '24');
|
|
ag2.value('99', '99 (' + _('never') + ')');
|
|
|
|
const ifc = s.taboption('advanced', widgets.NetworkSelect, 'iface_lan', _('LAN Networks'),
|
|
_('Networks to consider LAN (served) beyond those served by DHCP'));
|
|
ifc.multiple = true;
|
|
ifc.rmempty = true;
|
|
ifc.nocreate = true;
|
|
const wfc = s.taboption('advanced', widgets.NetworkSelect, 'iface_wan', _('WAN Networks'),
|
|
_('Networks to consider WAN (unserved)'));
|
|
wfc.multiple = true;
|
|
wfc.rmempty = true;
|
|
wfc.nocreate = true;
|
|
const tgr = s.taboption('advanced', widgets.NetworkSelect, 'iface_trig', _('Trigger Networks'),
|
|
_('Networks that may trigger Unbound to reload (avoid wan6)'));
|
|
tgr.multiple = true;
|
|
tgr.rmempty = true;
|
|
tgr.nocreate = true;
|
|
|
|
const bindhide = s.taboption('advanced', form.Flag, 'hide_binddata', _('Refuse possible attack queries'));
|
|
|
|
const verb = s.taboption('advanced', form.ListValue, 'verbosity', _('Verbosity'));
|
|
verb.datatype = 'and(uinteger,min(0),max(5))';
|
|
verb.value('0');
|
|
verb.value('1');
|
|
verb.value('2');
|
|
verb.value('3');
|
|
verb.value('4');
|
|
verb.value('5');
|
|
|
|
// DHCP tab
|
|
const dlk = s.taboption('dhcp', form.ListValue, 'dhcp_link', _('DHCP Link'),
|
|
_('Link to supported programs to load DHCP into DNS'));
|
|
dlk.rmempty = false;
|
|
['none','dnsmasq','odhcpd'].forEach(v => dlk.value(v, v === 'none' ? _('(none)') : v));
|
|
|
|
const dp6 = s.taboption('dhcp', form.Flag, 'dhcp4_slaac6', _('DHCPv4 to SLAAC'),
|
|
_('Use DHCPv4 MAC to discover IP6 hosts SLAAC (EUI64)'));
|
|
dp6.optional = true;
|
|
dp6.depends('dhcp_link', 'odhcpd');
|
|
|
|
const dom = s.taboption('dhcp', form.Value, 'domain', _('Local Domain'),
|
|
_('Domain suffix for this router and DHCP clients'));
|
|
dom.placeholder = 'lan';
|
|
dom.optional = true;
|
|
|
|
const dty = s.taboption('dhcp', form.ListValue, 'domain_type', _('Local Domain Type'),
|
|
_('How to treat queries of this local domain'));
|
|
dty.optional = true;
|
|
dty.value('deny', _('Denied (nxdomain)'));
|
|
dty.value('refuse', _('Refused'));
|
|
dty.value('static', _('Static (local only)'));
|
|
dty.value('transparent', _('Transparent (local/global)'));
|
|
dty.depends('dhcp_link', 'none');
|
|
dty.depends('dhcp_link', 'odhcpd');
|
|
|
|
const addDnsOpts = [
|
|
['add_local_fqdn', _('LAN DNS'), _('How to enter the LAN or local network router in DNS')],
|
|
['add_wan_fqdn', _('WAN DNS'), _('Override the WAN side router entry in DNS')],
|
|
];
|
|
const addDnsValues = [
|
|
['1', _('Hostname, Primary Address')],
|
|
['2', _('Hostname, All Addresses')],
|
|
['3', _('Host FQDN, All Addresses')],
|
|
['4', _('Interface FQDN, All Addresses')]
|
|
];
|
|
|
|
addDnsOpts.forEach(([optName,label]) => {
|
|
const opt = s.taboption('dhcp', form.ListValue, optName, label, '');
|
|
opt.optional = true;
|
|
opt.value('0', (optName == 'add_local_fqdn') ? _('No Entry') : _('Use Upstream'));
|
|
addDnsValues.forEach(([val,text]) => opt.value(val, text));
|
|
opt.depends('dhcp_link', 'none');
|
|
opt.depends('dhcp_link', 'odhcpd');
|
|
});
|
|
|
|
const exa = s.taboption('dhcp', form.ListValue, 'add_extra_dns', _('Extra DNS'),
|
|
_('Use extra DNS entries found in /etc/config/dhcp'));
|
|
exa.optional = true;
|
|
exa.value('0', _('Ignore'));
|
|
exa.value('1', _('Host Records'));
|
|
exa.value('2', _('Host/MX/SRV RR'));
|
|
exa.value('3', _('Host/MX/SRV/CNAME RR'));
|
|
|
|
// Resource tab
|
|
const ctl = s.taboption('resource', form.ListValue, 'unbound_control', _('Unbound Control App'),
|
|
_('Enable access for unbound-control'));
|
|
ctl.value('0', _('No Remote Control'));
|
|
ctl.value('1', _('Local Host, No Encryption'));
|
|
ctl.value('2', _('Local Host, Encrypted'));
|
|
ctl.value('3', _('Local Subnet, Encrypted'));
|
|
ctl.value('4', _('Local Subnet, Static Encryption'));
|
|
ctl.rmempty = false;
|
|
|
|
const pro = s.taboption('resource', form.ListValue, 'protocol', _('Recursion Protocol'),
|
|
_('Choose the IP versions used upstream and downstream'));
|
|
pro.value('default', _('Default'));
|
|
pro.value('ip4_only', _('IP4 Only'));
|
|
pro.value('ip6_local', _('IP4 All and IP6 Local'));
|
|
pro.value('ip6_only', _('IP6 Only*'));
|
|
pro.value('ip6_prefer', _('IP6 Preferred'));
|
|
pro.value('mixed', _('IP4 and IP6'));
|
|
pro.rmempty = false;
|
|
|
|
const rsc = s.taboption('resource', form.ListValue, 'resource', _('Memory Resource'),
|
|
_('Use menu System/Processes to observe any memory growth'));
|
|
rsc.value('default', _('Default'));
|
|
rsc.value('tiny', _('Tiny'));
|
|
rsc.value('small', _('Small'));
|
|
rsc.value('medium', _('Medium'));
|
|
rsc.value('large', _('Large'));
|
|
rsc.rmempty = false;
|
|
|
|
const rsn = s.taboption('resource', form.ListValue, 'recursion', _('Recursion Strength'),
|
|
_('Recursion activity affects memory growth and CPU load'));
|
|
rsn.value('default', _('Default'));
|
|
rsn.value('passive', _('Passive'));
|
|
rsn.value('aggressive', _('Aggressive'));
|
|
rsn.rmempty = false;
|
|
|
|
const qry = s.taboption('resource', form.Flag, 'query_minimize', _('Query Minimize'),
|
|
_('Break down query components for limited added privacy'));
|
|
qry.optional = true;
|
|
qry.depends('recursion', 'passive');
|
|
qry.depends('recursion', 'aggressive');
|
|
|
|
const qrs = s.taboption('resource', form.Flag, 'query_min_strict', _('Strict Minimize'),
|
|
_("Strict version of 'query minimize' but it can break DNS"));
|
|
qrs.taboptional = true;
|
|
qrs.depends('query_minimize', '1');
|
|
|
|
const eds = s.taboption('resource', form.Value, 'edns_size', _('EDNS Size'),
|
|
_('Limit extended DNS packet size'));
|
|
eds.datatype = 'and(uinteger,min(512),max(4096))';
|
|
eds.placeholder = '1280';
|
|
|
|
const tlm = s.taboption('resource', form.Value, 'ttl_min', _('TTL Minimum'),
|
|
_('Prevent excessively short cache periods'));
|
|
tlm.datatype = 'and(uinteger,min(0),max(1200))';
|
|
tlm.placeholder = '120';
|
|
|
|
const tlnm = s.taboption('resource', form.Value, 'ttl_neg_max', _('TTL Neg Max'));
|
|
tlm.datatype = 'and(uinteger,min(0),max(1200))';
|
|
tlm.placeholder = '1000';
|
|
|
|
const rtt = s.taboption('resource', form.Value, 'rate_limit', _('Query Rate Limit'),
|
|
_('Prevent client query overload; zero is off'));
|
|
rtt.datatype = 'and(uinteger,min(0),max(5000))';
|
|
rtt.placeholder = '0';
|
|
|
|
const stt = s.taboption('resource', form.Flag, 'extended_stats', _('Extended Statistics'),
|
|
_('Extended statistics are printed from unbound-control'));
|
|
stt.rmempty = false;
|
|
}
|
|
|
|
return m.render();
|
|
},
|
|
|
|
handleSaveApply(ev, mode) {
|
|
const enabled = uci.get('unbound', 'ub_main', 'enabled');
|
|
const cmd = enabled ? 'reload' : 'stop';
|
|
|
|
const Fn = L.bind(() => {
|
|
callRcInit('unbound', cmd);
|
|
document.removeEventListener('uci-applied', Fn);
|
|
});
|
|
document.addEventListener('uci-applied', Fn);
|
|
this.super('handleSaveApply', [ev, mode]);
|
|
}
|
|
});
|