mirror of
https://github.com/Ysurac/openmptcprouter-feeds.git
synced 2025-03-09 15:40:03 +00:00
fix network
This commit is contained in:
parent
ebf0639cbc
commit
ce0298b9a7
11 changed files with 546 additions and 1137 deletions
4
luci-mod-network/Makefile
Normal file → Executable file
4
luci-mod-network/Makefile
Normal file → Executable file
|
@ -1,13 +1,15 @@
|
||||||
#
|
#
|
||||||
# Copyright (C) 2008-2014 The LuCI Team <luci@lists.subsignal.org>
|
# Copyright (C) 2008-2014 The LuCI Team <luci@lists.subsignal.org>
|
||||||
|
# Copyright (C) 2020-2021 Ycarus (Yannick Chabanois) <ycarus@zugaina.org> for OpenMPTCProuter
|
||||||
#
|
#
|
||||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||||
#
|
#
|
||||||
|
# From https://github.com/openwrt/luci/commit/b88157e69a060ade618e48b30947729310935d61
|
||||||
|
|
||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
LUCI_TITLE:=LuCI Network Administration
|
LUCI_TITLE:=LuCI Network Administration
|
||||||
LUCI_DEPENDS:=+luci-base +rpcd-mod-iwinfo
|
LUCI_DEPENDS:=+luci-base +libiwinfo-lua +rpcd-mod-iwinfo
|
||||||
|
|
||||||
PKG_LICENSE:=Apache-2.0
|
PKG_LICENSE:=Apache-2.0
|
||||||
|
|
||||||
|
|
202
luci-mod-network/htdocs/luci-static/resources/tools/network.js
Normal file → Executable file
202
luci-mod-network/htdocs/luci-static/resources/tools/network.js
Normal file → Executable file
|
@ -1,5 +1,4 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
'require fs';
|
|
||||||
'require ui';
|
'require ui';
|
||||||
'require dom';
|
'require dom';
|
||||||
'require uci';
|
'require uci';
|
||||||
|
@ -150,77 +149,25 @@ function updatePlaceholders(opt, section_id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cbiFlagTristate = form.ListValue.extend({
|
|
||||||
__init__: function(/* ... */) {
|
|
||||||
this.super('__init__', arguments);
|
|
||||||
this.keylist = [ '', '0!', '1!' ];
|
|
||||||
this.vallist = [ _('automatic'), _('disabled'), _('enabled') ];
|
|
||||||
},
|
|
||||||
|
|
||||||
load: function(section_id) {
|
|
||||||
var invert = false, sysfs = this.sysfs;
|
|
||||||
|
|
||||||
if (sysfs) {
|
|
||||||
if (sysfs.charAt(0) == '!') {
|
|
||||||
invert = true;
|
|
||||||
sysfs = sysfs.substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return L.resolveDefault(fs.read(sysfs), '').then(L.bind(function(res) {
|
|
||||||
res = (res || '').trim();
|
|
||||||
|
|
||||||
if (res == '0')
|
|
||||||
this.sysfs_default = invert;
|
|
||||||
else if (res == '1')
|
|
||||||
this.sysfs_default = !invert;
|
|
||||||
|
|
||||||
return this.super('load', [section_id]);
|
|
||||||
}, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.super('load', [section_id]);
|
|
||||||
},
|
|
||||||
|
|
||||||
write: function(section_id, formvalue) {
|
|
||||||
if (formvalue == '1!')
|
|
||||||
return this.super('write', [section_id, '1']);
|
|
||||||
else if (formvalue == '0!')
|
|
||||||
return this.super('write', [section_id, '0']);
|
|
||||||
else
|
|
||||||
return this.super('remove', [section_id]);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
|
||||||
var sysdef = this.sysfs_default;
|
|
||||||
|
|
||||||
if (this.sysfs_default !== null) {
|
|
||||||
this.keylist[0] = sysdef ? '1' : '0';
|
|
||||||
this.vallist[0] = sysdef ? _('automatic (enabled)') : _('automatic (disabled)');
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.super('renderWidget', [section_id, option_index, cfgvalue]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var cbiTagValue = form.Value.extend({
|
var cbiTagValue = form.Value.extend({
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
renderWidget: function(section_id, option_index, cfgvalue) {
|
||||||
var widget = new ui.Dropdown(cfgvalue || ['-'], {
|
var widget = new ui.Dropdown(cfgvalue || ['-'], {
|
||||||
'-': E([], [
|
'-': E([], [
|
||||||
E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ '—' ]),
|
E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ '—' ]),
|
||||||
E('span', { 'class': 'hide-close' }, [ _('Not Member', 'VLAN port state') ])
|
E('span', { 'class': 'hide-close' }, [ _('Do not participate', 'VLAN port state') ])
|
||||||
]),
|
]),
|
||||||
'u': E([], [
|
'u': E([], [
|
||||||
E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ 'U' ]),
|
E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ 'u' ]),
|
||||||
E('span', { 'class': 'hide-close' }, [ _('Untagged', 'VLAN port state') ])
|
E('span', { 'class': 'hide-close' }, [ _('Egress untagged', 'VLAN port state') ])
|
||||||
]),
|
]),
|
||||||
't': E([], [
|
't': E([], [
|
||||||
E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ 'T' ]),
|
E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ 't' ]),
|
||||||
E('span', { 'class': 'hide-close' }, [ _('Tagged', 'VLAN port state') ])
|
E('span', { 'class': 'hide-close' }, [ _('Egress tagged', 'VLAN port state') ])
|
||||||
]),
|
]),
|
||||||
'*': E([], [
|
'*': E([], [
|
||||||
E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ '*' ]),
|
E('span', { 'class': 'hide-open', 'style': 'font-family:monospace' }, [ '*' ]),
|
||||||
E('span', { 'class': 'hide-close' }, [ _('Is Primary VLAN', 'VLAN port state') ])
|
E('span', { 'class': 'hide-close' }, [ _('Primary VLAN ID', 'VLAN port state') ])
|
||||||
])
|
])
|
||||||
}, {
|
}, {
|
||||||
id: this.cbid(section_id),
|
id: this.cbid(section_id),
|
||||||
|
@ -327,7 +274,7 @@ var cbiTagValue = form.Value.extend({
|
||||||
|
|
||||||
var t = /t/.test(s[1] || '') ? 't' : 'u';
|
var t = /t/.test(s[1] || '') ? 't' : 'u';
|
||||||
|
|
||||||
return /\x2a/.test(s[1] || '') ? [t, '*'] : [t];
|
return /\*/.test(s[1] || '') ? [t, '*'] : [t];
|
||||||
}
|
}
|
||||||
|
|
||||||
return ['-'];
|
return ['-'];
|
||||||
|
@ -357,7 +304,7 @@ var cbiTagValue = form.Value.extend({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uci.set('network', section_id, 'ports', ports.length ? ports : null);
|
uci.set('network', section_id, 'ports', ports);
|
||||||
},
|
},
|
||||||
|
|
||||||
remove: function() {}
|
remove: function() {}
|
||||||
|
@ -384,7 +331,6 @@ return baseclass.extend({
|
||||||
|
|
||||||
addDeviceOptions: function(s, dev, isNew) {
|
addDeviceOptions: function(s, dev, isNew) {
|
||||||
var parent_dev = dev ? dev.getParent() : null,
|
var parent_dev = dev ? dev.getParent() : null,
|
||||||
devname = dev ? dev.getName() : null,
|
|
||||||
o, ss;
|
o, ss;
|
||||||
|
|
||||||
s.tab('devgeneral', _('General device options'));
|
s.tab('devgeneral', _('General device options'));
|
||||||
|
@ -475,7 +421,7 @@ return baseclass.extend({
|
||||||
vid = this.section.formvalue(section_id, 'vid'),
|
vid = this.section.formvalue(section_id, 'vid'),
|
||||||
name = this.section.getUIElement(section_id, 'name_complex');
|
name = this.section.getUIElement(section_id, 'name_complex');
|
||||||
|
|
||||||
if (base && vid && name && !name.isChanged() && isNew) {
|
if (base && vid && name && !name.isChanged()) {
|
||||||
name.setValue('%s.%d'.format(base, vid));
|
name.setValue('%s.%d'.format(base, vid));
|
||||||
name.triggerValidation();
|
name.triggerValidation();
|
||||||
}
|
}
|
||||||
|
@ -673,16 +619,48 @@ return baseclass.extend({
|
||||||
o.placeholder = dev ? dev._devstate('qlen') : '';
|
o.placeholder = dev ? dev._devstate('qlen') : '';
|
||||||
o.datatype = 'uinteger';
|
o.datatype = 'uinteger';
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devadvanced', cbiFlagTristate, 'promisc', _('Enable promiscuous mode'));
|
o = this.replaceOption(s, 'devadvanced', form.Flag, 'promisc', _('Enable promiscuous mode'));
|
||||||
o.sysfs_default = (dev && dev.dev && dev.dev.flags) ? dev.dev.flags.promisc : null;
|
o.default = o.disabled;
|
||||||
|
|
||||||
|
o = this.replaceOption(s, 'devadvanced', form.Flag, 'autoneg', _('Autonegociation'));
|
||||||
|
o.default = o.enabled;
|
||||||
|
|
||||||
|
o = this.replaceOption(s, 'devadvanced', form.Flag, 'gro', _('Generic Receive Offload (GRO)'));
|
||||||
|
o.default = o.enabled;
|
||||||
|
|
||||||
|
o = this.replaceOption(s, 'devadvanced', form.Flag, 'gso', _('Generic Segmentation Offload (GSO)'));
|
||||||
|
o.default = o.enabled;
|
||||||
|
|
||||||
|
o = this.replaceOption(s, 'devadvanced', form.Flag, 'tso', _('TCP Segmentation Offload (TSO)'));
|
||||||
|
o.default = o.enabled;
|
||||||
|
|
||||||
|
o = this.replaceOption(s, 'devadvanced', form.Flag, 'lro', _('Large Receive Offload (LRO)'));
|
||||||
|
o.default = o.enabled;
|
||||||
|
|
||||||
|
o = this.replaceOption(s, 'devadvanced', form.Flag, 'ufo', _('UDP Fragmentation Offload (UFO)'));
|
||||||
|
o.default = o.enabled;
|
||||||
|
|
||||||
|
o = this.replaceOption(s, 'devadvanced', form.Value, 'speed', _('Speed'));
|
||||||
|
o.placeholder = dev ? dev.getSpeed() : '';
|
||||||
|
o.default = '';
|
||||||
|
o.rmempty = true;
|
||||||
|
o.datatype = 'uinteger';
|
||||||
|
o.depends('autoneg', '0');
|
||||||
|
|
||||||
|
o = this.replaceOption(s, 'devadvanced', form.ListValue, 'duplex', _('Duplex'));
|
||||||
|
o.default = '';
|
||||||
|
o.value('', _('unknown'));
|
||||||
|
o.value('half', _('half'));
|
||||||
|
o.value('full', _('full'));
|
||||||
|
o.depends('autoneg', '0');
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devadvanced', form.ListValue, 'rpfilter', _('Reverse path filter'));
|
o = this.replaceOption(s, 'devadvanced', form.ListValue, 'rpfilter', _('Reverse path filter'));
|
||||||
o.default = '';
|
o.default = '';
|
||||||
o.value('', _('disabled'));
|
o.value('', _('disabled'));
|
||||||
o.value('loose', _('Loose filtering'));
|
o.value('loose', _('Loose filtering'));
|
||||||
o.value('strict', _('Strict filtering'));
|
o.value('strict', _('Strict filtering'));
|
||||||
o.cfgvalue = function(/* ... */) {
|
o.cfgvalue = function(section_id) {
|
||||||
var val = form.ListValue.prototype.cfgvalue.apply(this, arguments);
|
var val = form.ListValue.prototype.cfgvalue.apply(this, [section_id]);
|
||||||
|
|
||||||
switch (val || '') {
|
switch (val || '') {
|
||||||
case 'loose':
|
case 'loose':
|
||||||
|
@ -698,17 +676,11 @@ return baseclass.extend({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devadvanced', cbiFlagTristate, 'acceptlocal', _('Accept local'), _('Accept packets with local source addresses'));
|
o = this.replaceOption(s, 'devadvanced', form.Flag, 'acceptlocal', _('Accept local'), _('Accept packets with local source addresses'));
|
||||||
o.sysfs = '/proc/sys/net/ipv4/conf/%s/accept_local'.format(devname || 'default');
|
o.default = o.disabled;
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devadvanced', cbiFlagTristate, 'sendredirects', _('Send ICMP redirects'));
|
o = this.replaceOption(s, 'devadvanced', form.Flag, 'sendredirects', _('Send ICMP redirects'));
|
||||||
o.sysfs = '/proc/sys/net/ipv4/conf/%s/send_redirects'.format(devname || 'default');
|
o.default = o.enabled;
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devadvanced', cbiFlagTristate, 'arp_accept ', _('Honor gratuitous ARP'), _('When enabled, new ARP table entries are added from received gratuitous APR requests or replies, otherwise only preexisting table entries are updated, but no new hosts are learned.'));
|
|
||||||
o.sysfs = '/proc/sys/net/ipv4/conf/%s/arp_accept'.format(devname || 'default');
|
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devadvanced', cbiFlagTristate, 'drop_gratuitous_arp', _('Drop gratuitous ARP'), _('Drop all gratuitous ARP frames, for example if there’s a known good ARP proxy on the network and such frames need not be used or in the case of 802.11, must not be used to prevent attacks.'));
|
|
||||||
o.sysfs = '/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp'.format(devname || 'default');
|
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devadvanced', form.Value, 'neighreachabletime', _('Neighbour cache validity'), _('Time in milliseconds'));
|
o = this.replaceOption(s, 'devadvanced', form.Value, 'neighreachabletime', _('Neighbour cache validity'), _('Time in milliseconds'));
|
||||||
o.placeholder = '30000';
|
o.placeholder = '30000';
|
||||||
|
@ -722,75 +694,63 @@ return baseclass.extend({
|
||||||
o.placeholder = '0';
|
o.placeholder = '0';
|
||||||
o.datatype = 'uinteger';
|
o.datatype = 'uinteger';
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devgeneral', cbiFlagTristate, 'ipv6', _('Enable IPv6'));
|
o = this.replaceOption(s, 'devadvanced', form.Value, 'ttl', _('Force TTL'), _('Some LTE providers detect tethering by inspecting packet TTL values'));
|
||||||
o.sysfs = '!/proc/sys/net/ipv6/conf/%s/disable_ipv6'.format(devname || 'default');
|
o.placeholder = '65';
|
||||||
|
o.datatype = 'uinteger';
|
||||||
|
|
||||||
|
o = this.replaceOption(s, 'devgeneral', form.Flag, 'ipv6', _('Enable IPv6'));
|
||||||
o.migrate = false;
|
o.migrate = false;
|
||||||
|
o.default = o.enabled;
|
||||||
o = this.replaceOption(s, 'devadvanced', cbiFlagTristate, 'ip6segmentrouting', _('Enable IPv6 segment routing'));
|
|
||||||
o.sysfs = '/proc/sys/net/ipv6/conf/%s/seg6_enabled'.format(devname || 'default');
|
|
||||||
o.depends('ipv6', /1/);
|
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devadvanced', cbiFlagTristate, 'drop_unsolicited_na', _('Drop unsolicited NA'), _('Drop all unsolicited neighbor advertisements, for example if there’s a known good NA proxy on the network and such frames need not be used or in the case of 802.11, must not be used to prevent attacks.'));
|
|
||||||
o.sysfs = '/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na'.format(devname || 'default');
|
|
||||||
o.depends('ipv6', /1/);
|
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devgeneral', form.Value, 'mtu6', _('IPv6 MTU'));
|
o = this.replaceOption(s, 'devgeneral', form.Value, 'mtu6', _('IPv6 MTU'));
|
||||||
o.datatype = 'max(9200)';
|
o.datatype = 'max(9200)';
|
||||||
o.depends('ipv6', /1/);
|
o.depends('ipv6', '1');
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devgeneral', form.Value, 'dadtransmits', _('DAD transmits'), _('Amount of Duplicate Address Detection probes to send'));
|
o = this.replaceOption(s, 'devgeneral', form.Value, 'dadtransmits', _('DAD transmits'), _('Amount of Duplicate Address Detection probes to send'));
|
||||||
o.placeholder = '1';
|
o.placeholder = '1';
|
||||||
o.datatype = 'uinteger';
|
o.datatype = 'uinteger';
|
||||||
o.depends('ipv6', /1/);
|
o.depends('ipv6', '1');
|
||||||
|
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devadvanced', cbiFlagTristate, 'multicast', _('Enable multicast support'));
|
o = this.replaceOption(s, 'devadvanced', form.Flag, 'multicast', _('Enable multicast support'));
|
||||||
o.sysfs_default = (dev && dev.dev && dev.dev.flags) ? dev.dev.flags.multicast : null;
|
o.default = o.enabled;
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devadvanced', form.ListValue, 'igmpversion', _('Force IGMP version'));
|
o = this.replaceOption(s, 'devadvanced', form.ListValue, 'igmpversion', _('Force IGMP version'));
|
||||||
o.value('', _('No enforcement'));
|
o.value('', _('No enforcement'));
|
||||||
o.value('1', _('Enforce IGMPv1'));
|
o.value('1', _('Enforce IGMPv1'));
|
||||||
o.value('2', _('Enforce IGMPv2'));
|
o.value('2', _('Enforce IGMPv2'));
|
||||||
o.value('3', _('Enforce IGMPv3'));
|
o.value('3', _('Enforce IGMPv3'));
|
||||||
o.depends('multicast', /1/);
|
o.depends('multicast', '1');
|
||||||
|
|
||||||
o = this.replaceOption(s, 'devadvanced', form.ListValue, 'mldversion', _('Force MLD version'));
|
o = this.replaceOption(s, 'devadvanced', form.ListValue, 'mldversion', _('Force MLD version'));
|
||||||
o.value('', _('No enforcement'));
|
o.value('', _('No enforcement'));
|
||||||
o.value('1', _('Enforce MLD version 1'));
|
o.value('1', _('Enforce MLD version 1'));
|
||||||
o.value('2', _('Enforce MLD version 2'));
|
o.value('2', _('Enforce MLD version 2'));
|
||||||
o.depends('multicast', /1/);
|
o.depends('multicast', '1');
|
||||||
|
|
||||||
if (isBridgePort(dev)) {
|
if (isBridgePort(dev)) {
|
||||||
o = this.replaceOption(s, 'brport', cbiFlagTristate, 'learning', _('Enable MAC address learning'));
|
o = this.replaceOption(s, 'brport', form.Flag, 'learning', _('Enable MAC address learning'));
|
||||||
o.sysfs = '/sys/class/net/%s/brport/learning'.format(devname || 'default');
|
o.default = o.enabled;
|
||||||
|
|
||||||
o = this.replaceOption(s, 'brport', cbiFlagTristate, 'unicast_flood', _('Enable unicast flooding'));
|
o = this.replaceOption(s, 'brport', form.Flag, 'unicast_flood', _('Enable unicast flooding'));
|
||||||
o.sysfs = '/sys/class/net/%s/brport/unicast_flood'.format(devname || 'default');
|
o.default = o.enabled;
|
||||||
|
|
||||||
o = this.replaceOption(s, 'brport', cbiFlagTristate, 'isolate', _('Port isolation'), _('Only allow communication with non-isolated bridge ports when enabled'));
|
o = this.replaceOption(s, 'brport', form.Flag, 'isolated', _('Port isolation'), _('Only allow communication with non-isolated bridge ports when enabled'));
|
||||||
o.sysfs = '/sys/class/net/%s/brport/isolated'.format(devname || 'default');
|
o.default = o.disabled;
|
||||||
|
|
||||||
o = this.replaceOption(s, 'brport', form.ListValue, 'multicast_router', _('Multicast routing'));
|
o = this.replaceOption(s, 'brport', form.ListValue, 'multicast_router', _('Multicast routing'));
|
||||||
o.value('', _('Never'));
|
o.value('', _('Never'));
|
||||||
o.value('1', _('Learn'));
|
o.value('1', _('Learn'));
|
||||||
o.value('2', _('Always'));
|
o.value('2', _('Always'));
|
||||||
o.depends('multicast', /1/);
|
o.depends('multicast', '1');
|
||||||
|
|
||||||
o = this.replaceOption(s, 'brport', cbiFlagTristate, 'multicast_to_unicast', _('Multicast to unicast'), _('Forward multicast packets as unicast packets on this device.'));
|
o = this.replaceOption(s, 'brport', form.Flag, 'multicast_to_unicast', _('Multicast to unicast'), _('Forward multicast packets as unicast packets on this device.'));
|
||||||
o.sysfs = '/sys/class/net/%s/brport/multicast_to_unicast'.format(devname || 'default');
|
o.default = o.disabled;
|
||||||
o.depends('multicast', /1/);
|
o.depends('multicast', '1');
|
||||||
|
|
||||||
o = this.replaceOption(s, 'brport', cbiFlagTristate, 'multicast_fast_leave', _('Enable multicast fast leave'));
|
o = this.replaceOption(s, 'brport', form.Flag, 'multicast_fast_leave', _('Enable multicast fast leave'));
|
||||||
o.sysfs = '/sys/class/net/%s/brport/multicast_fast_leave'.format(devname || 'default');
|
o.default = o.disabled;
|
||||||
o.depends('multicast', /1/);
|
o.depends('multicast', '1');
|
||||||
|
|
||||||
o = this.replaceOption(s, 'brport', cbiFlagTristate, 'drop_v4_unicast_in_l2_multicast', _('Drop nested IPv4 unicast'), _('Drop layer 2 multicast frames containing IPv4 unicast packets.'));
|
|
||||||
o.sysfs = '/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast'.format(devname || 'default');
|
|
||||||
o.depends('multicast', /1/);
|
|
||||||
|
|
||||||
o = this.replaceOption(s, 'brport', cbiFlagTristate, 'drop_v6_unicast_in_l2_multicast', _('Drop nested IPv6 unicast'), _('Drop layer 2 multicast frames containing IPv6 unicast packets.'));
|
|
||||||
o.sysfs = '/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast'.format(devname || 'default');
|
|
||||||
o.depends('multicast', /1/);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
o = this.replaceOption(s, 'bridgevlan', form.Flag, 'vlan_filtering', _('Enable VLAN filtering'));
|
o = this.replaceOption(s, 'bridgevlan', form.Flag, 'vlan_filtering', _('Enable VLAN filtering'));
|
||||||
|
@ -856,8 +816,6 @@ return baseclass.extend({
|
||||||
return network.instantiateDevice(port)
|
return network.instantiateDevice(port)
|
||||||
}).filter(function(dev) {
|
}).filter(function(dev) {
|
||||||
return dev.getType() != 'wifi' || dev.isUp();
|
return dev.getType() != 'wifi' || dev.isUp();
|
||||||
}).sort(function(a, b) {
|
|
||||||
return L.naturalCompare(a.getName(), b.getName());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.children = this.children.filter(function(opt) { return !opt.option.match(/^port_/) });
|
this.children = this.children.filter(function(opt) { return !opt.option.match(/^port_/) });
|
||||||
|
@ -971,6 +929,18 @@ return baseclass.extend({
|
||||||
for (var port_name in seen_ports)
|
for (var port_name in seen_ports)
|
||||||
ports.push(port_name);
|
ports.push(port_name);
|
||||||
|
|
||||||
|
ports.sort(function(a, b) {
|
||||||
|
var m1 = a.match(/^(.+?)([0-9]*)$/),
|
||||||
|
m2 = b.match(/^(.+?)([0-9]*)$/);
|
||||||
|
|
||||||
|
if (m1[1] < m2[1])
|
||||||
|
return -1;
|
||||||
|
else if (m1[1] > m2[1])
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return +(m1[2] || 0) - +(m2[2] || 0);
|
||||||
|
});
|
||||||
|
|
||||||
ss.updatePorts(ports);
|
ss.updatePorts(ports);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
727
luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js
Normal file → Executable file
727
luci-mod-network/htdocs/luci-static/resources/view/network/dhcp.js
Normal file → Executable file
|
@ -5,9 +5,7 @@
|
||||||
'require rpc';
|
'require rpc';
|
||||||
'require uci';
|
'require uci';
|
||||||
'require form';
|
'require form';
|
||||||
'require network';
|
|
||||||
'require validation';
|
'require validation';
|
||||||
'require tools.widgets as widgets';
|
|
||||||
|
|
||||||
var callHostHints, callDUIDHints, callDHCPLeases, CBILeaseStatus, CBILease6Status;
|
var callHostHints, callDUIDHints, callDHCPLeases, CBILeaseStatus, CBILease6Status;
|
||||||
|
|
||||||
|
@ -67,58 +65,6 @@ CBILease6Status = form.DummyValue.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function calculateNetwork(addr, mask) {
|
|
||||||
addr = validation.parseIPv4(String(addr));
|
|
||||||
|
|
||||||
if (!isNaN(mask))
|
|
||||||
mask = validation.parseIPv4(network.prefixToMask(+mask));
|
|
||||||
else
|
|
||||||
mask = validation.parseIPv4(String(mask));
|
|
||||||
|
|
||||||
if (addr == null || mask == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return [
|
|
||||||
[
|
|
||||||
addr[0] & (mask[0] >>> 0 & 255),
|
|
||||||
addr[1] & (mask[1] >>> 0 & 255),
|
|
||||||
addr[2] & (mask[2] >>> 0 & 255),
|
|
||||||
addr[3] & (mask[3] >>> 0 & 255)
|
|
||||||
].join('.'),
|
|
||||||
mask.join('.')
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDHCPPools() {
|
|
||||||
return uci.load('dhcp').then(function() {
|
|
||||||
let sections = uci.sections('dhcp', 'dhcp'),
|
|
||||||
tasks = [], pools = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < sections.length; i++) {
|
|
||||||
if (sections[i].ignore == '1' || !sections[i].interface)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
tasks.push(network.getNetwork(sections[i].interface).then(L.bind(function(section_id, net) {
|
|
||||||
var cidr = net ? (net.getIPAddrs()[0] || '').split('/') : null;
|
|
||||||
|
|
||||||
if (cidr && cidr.length == 2) {
|
|
||||||
var net_mask = calculateNetwork(cidr[0], cidr[1]);
|
|
||||||
|
|
||||||
pools.push({
|
|
||||||
section_id: section_id,
|
|
||||||
network: net_mask[0],
|
|
||||||
netmask: net_mask[1]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, null, sections[i]['.name'])));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all(tasks).then(function() {
|
|
||||||
return pools;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateHostname(sid, s) {
|
function validateHostname(sid, s) {
|
||||||
if (s == null || s == '')
|
if (s == null || s == '')
|
||||||
return true;
|
return true;
|
||||||
|
@ -126,7 +72,7 @@ function validateHostname(sid, s) {
|
||||||
if (s.length > 256)
|
if (s.length > 256)
|
||||||
return _('Expecting: %s').format(_('valid hostname'));
|
return _('Expecting: %s').format(_('valid hostname'));
|
||||||
|
|
||||||
var labels = s.replace(/^\*?\.?|\.$/g, '').split(/\./);
|
var labels = s.replace(/^\.+|\.$/g, '').split(/\./);
|
||||||
|
|
||||||
for (var i = 0; i < labels.length; i++)
|
for (var i = 0; i < labels.length; i++)
|
||||||
if (!labels[i].match(/^[a-z0-9_](?:[a-z0-9-]{0,61}[a-z0-9])?$/i))
|
if (!labels[i].match(/^[a-z0-9_](?:[a-z0-9-]{0,61}[a-z0-9])?$/i))
|
||||||
|
@ -156,15 +102,13 @@ function validateServerSpec(sid, s) {
|
||||||
if (s == null || s == '')
|
if (s == null || s == '')
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var m = s.match(/^(\/.*\/)?(.*)$/);
|
var m = s.match(/^(?:\/(.+)\/)?(.*)$/);
|
||||||
if (!m)
|
if (!m)
|
||||||
return _('Expecting: %s').format(_('valid hostname'));
|
return _('Expecting: %s').format(_('valid hostname'));
|
||||||
|
|
||||||
if (m[1] != '//' && m[1] != '/#/') {
|
var res = validateAddressList(sid, m[1]);
|
||||||
var res = validateAddressList(sid, m[1]);
|
if (res !== true)
|
||||||
if (res !== true)
|
return res;
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m[2] == '' || m[2] == '#')
|
if (m[2] == '' || m[2] == '#')
|
||||||
return true;
|
return true;
|
||||||
|
@ -194,552 +138,274 @@ function validateServerSpec(sid, s) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateMACAddr(pools, sid, s) {
|
|
||||||
if (s == null || s == '')
|
|
||||||
return true;
|
|
||||||
|
|
||||||
var leases = uci.sections('dhcp', 'host'),
|
|
||||||
this_macs = L.toArray(s).map(function(m) { return m.toUpperCase() });
|
|
||||||
|
|
||||||
for (var i = 0; i < pools.length; i++) {
|
|
||||||
var this_net_mask = calculateNetwork(this.section.formvalue(sid, 'ip'), pools[i].netmask);
|
|
||||||
|
|
||||||
if (!this_net_mask)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (var j = 0; j < leases.length; j++) {
|
|
||||||
if (leases[j]['.name'] == sid || !leases[j].ip)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var lease_net_mask = calculateNetwork(leases[j].ip, pools[i].netmask);
|
|
||||||
|
|
||||||
if (!lease_net_mask || this_net_mask[0] != lease_net_mask[0])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var lease_macs = L.toArray(leases[j].mac).map(function(m) { return m.toUpperCase() });
|
|
||||||
|
|
||||||
for (var k = 0; k < lease_macs.length; k++)
|
|
||||||
for (var l = 0; l < this_macs.length; l++)
|
|
||||||
if (lease_macs[k] == this_macs[l])
|
|
||||||
return _('The MAC address %h is already used by another static lease in the same DHCP pool').format(this_macs[l]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return view.extend({
|
return view.extend({
|
||||||
load: function() {
|
load: function() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
callHostHints(),
|
callHostHints(),
|
||||||
callDUIDHints(),
|
callDUIDHints()
|
||||||
getDHCPPools(),
|
|
||||||
network.getDevices()
|
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function(hosts_duids_pools) {
|
render: function(hosts_duids) {
|
||||||
var has_dhcpv6 = L.hasSystemFeature('dnsmasq', 'dhcpv6') || L.hasSystemFeature('odhcpd'),
|
var has_dhcpv6 = L.hasSystemFeature('dnsmasq', 'dhcpv6') || L.hasSystemFeature('odhcpd'),
|
||||||
hosts = hosts_duids_pools[0],
|
hosts = hosts_duids[0],
|
||||||
duids = hosts_duids_pools[1],
|
duids = hosts_duids[1],
|
||||||
pools = hosts_duids_pools[2],
|
|
||||||
ndevs = hosts_duids_pools[3],
|
|
||||||
m, s, o, ss, so;
|
m, s, o, ss, so;
|
||||||
|
|
||||||
m = new form.Map('dhcp', _('DHCP and DNS'),
|
m = new form.Map('dhcp', _('DHCP and DNS'), _('Dnsmasq is a combined <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr>-Server and <abbr title="Domain Name System">DNS</abbr>-Forwarder for <abbr title="Network Address Translation">NAT</abbr> firewalls'));
|
||||||
_('Dnsmasq is a lightweight <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr> server and <abbr title="Domain Name System">DNS</abbr> forwarder.'));
|
|
||||||
|
|
||||||
s = m.section(form.TypedSection, 'dnsmasq');
|
s = m.section(form.TypedSection, 'dnsmasq', _('Server Settings'));
|
||||||
s.anonymous = true;
|
s.anonymous = true;
|
||||||
s.addremove = false;
|
s.addremove = false;
|
||||||
|
|
||||||
s.tab('general', _('General Settings'));
|
s.tab('general', _('General Settings'));
|
||||||
s.tab('relay', _('Relay'));
|
|
||||||
s.tab('files', _('Resolv and Hosts Files'));
|
s.tab('files', _('Resolv and Hosts Files'));
|
||||||
s.tab('pxe_tftp', _('PXE/TFTP Settings'));
|
s.tab('tftp', _('TFTP Settings'));
|
||||||
s.tab('advanced', _('Advanced Settings'));
|
s.tab('advanced', _('Advanced Settings'));
|
||||||
s.tab('leases', _('Static Leases'));
|
s.tab('leases', _('Static Leases'));
|
||||||
s.tab('hosts', _('Hostnames'));
|
|
||||||
s.tab('srvhosts', _('SRV'));
|
|
||||||
s.tab('mxhosts', _('MX'));
|
|
||||||
s.tab('ipsets', _('IP Sets'));
|
|
||||||
|
|
||||||
s.taboption('general', form.Flag, 'domainneeded',
|
s.taboption('general', form.Flag, 'domainneeded',
|
||||||
_('Domain required'),
|
_('Domain required'),
|
||||||
_('Do not forward DNS queries without dots or domain parts.'));
|
_('Don\'t forward <abbr title="Domain Name System">DNS</abbr>-Requests without <abbr title="Domain Name System">DNS</abbr>-Name'));
|
||||||
|
|
||||||
s.taboption('general', form.Flag, 'authoritative',
|
s.taboption('general', form.Flag, 'authoritative',
|
||||||
_('Authoritative'),
|
_('Authoritative'),
|
||||||
_('This is the only DHCP server in the local network.'));
|
_('This is the only <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr> in the local network'));
|
||||||
|
|
||||||
s.taboption('general', form.Value, 'local',
|
|
||||||
_('Local server'),
|
|
||||||
_('Never forward matching domains and subdomains, resolve from DHCP or hosts files only.'));
|
|
||||||
|
|
||||||
s.taboption('general', form.Value, 'domain',
|
|
||||||
_('Local domain'),
|
|
||||||
_('Local domain suffix appended to DHCP names and hosts file entries.'));
|
|
||||||
|
|
||||||
o = s.taboption('general', form.Flag, 'logqueries',
|
|
||||||
_('Log queries'),
|
|
||||||
_('Write received DNS queries to syslog.'));
|
|
||||||
o.optional = true;
|
|
||||||
|
|
||||||
o = s.taboption('general', form.DynamicList, 'server',
|
|
||||||
_('DNS forwardings'),
|
|
||||||
_('List of upstream resolvers to forward queries to.'));
|
|
||||||
o.optional = true;
|
|
||||||
o.placeholder = '/example.org/10.1.2.3';
|
|
||||||
o.validate = validateServerSpec;
|
|
||||||
|
|
||||||
o = s.taboption('general', form.DynamicList, 'address',
|
|
||||||
_('Addresses'),
|
|
||||||
_('Resolve specified FQDNs to an IP.') + '<br />' +
|
|
||||||
_('Syntax: <code>/fqdn[/fqdn…]/[ipaddr]</code>.') + '<br />' +
|
|
||||||
_('<code>/#/</code> matches any domain. <code>/example.com/</code> returns NXDOMAIN.') + '<br />' +
|
|
||||||
_('<code>/example.com/#</code> returns NULL addresses (<code>0.0.0.0</code> and <code>::</code>) for example.com and its subdomains.'));
|
|
||||||
o.optional = true;
|
|
||||||
o.placeholder = '/router.local/router.lan/192.168.0.1';
|
|
||||||
|
|
||||||
o = s.taboption('general', form.DynamicList, 'ipset',
|
|
||||||
_('IP sets'),
|
|
||||||
_('List of IP sets to populate with the IPs of DNS lookup results of the FQDNs also specified here.'));
|
|
||||||
o.optional = true;
|
|
||||||
o.placeholder = '/example.org/ipset,ipset6';
|
|
||||||
|
|
||||||
o = s.taboption('general', form.Flag, 'rebind_protection',
|
|
||||||
_('Rebind protection'),
|
|
||||||
_('Discard upstream responses containing <a href="%s">RFC1918</a> addresses.').format('https://datatracker.ietf.org/doc/html/rfc1918'));
|
|
||||||
o.rmempty = false;
|
|
||||||
|
|
||||||
o = s.taboption('general', form.Flag, 'rebind_localhost',
|
|
||||||
_('Allow localhost'),
|
|
||||||
_('Exempt <code>127.0.0.0/8</code> and <code>::1</code> from rebinding checks, e.g. for RBL services.'));
|
|
||||||
o.depends('rebind_protection', '1');
|
|
||||||
|
|
||||||
o = s.taboption('general', form.DynamicList, 'rebind_domain',
|
|
||||||
_('Domain whitelist'),
|
|
||||||
_('List of domains to allow RFC1918 responses for.'));
|
|
||||||
o.depends('rebind_protection', '1');
|
|
||||||
o.optional = true;
|
|
||||||
o.placeholder = 'ihost.netflix.com';
|
|
||||||
o.validate = validateAddressList;
|
|
||||||
|
|
||||||
o = s.taboption('general', form.Flag, 'localservice',
|
|
||||||
_('Local service only'),
|
|
||||||
_('Accept DNS queries only from hosts whose address is on a local subnet.'));
|
|
||||||
o.optional = false;
|
|
||||||
o.rmempty = false;
|
|
||||||
|
|
||||||
o = s.taboption('general', form.Flag, 'nonwildcard',
|
|
||||||
_('Non-wildcard'),
|
|
||||||
_('Bind dynamically to interfaces rather than wildcard address.'));
|
|
||||||
o.default = o.enabled;
|
|
||||||
o.optional = false;
|
|
||||||
o.rmempty = true;
|
|
||||||
|
|
||||||
o = s.taboption('general', form.DynamicList, 'interface',
|
|
||||||
_('Listen interfaces'),
|
|
||||||
_('Listen only on the specified interfaces, and loopback if not excluded explicitly.'));
|
|
||||||
o.optional = true;
|
|
||||||
o.placeholder = 'lan';
|
|
||||||
|
|
||||||
o = s.taboption('general', form.DynamicList, 'notinterface',
|
|
||||||
_('Exclude interfaces'),
|
|
||||||
_('Do not listen on the specified interfaces.'));
|
|
||||||
o.optional = true;
|
|
||||||
o.placeholder = 'loopback';
|
|
||||||
|
|
||||||
o = s.taboption('relay', form.SectionValue, '__relays__', form.TableSection, 'relay', null,
|
|
||||||
_('Relay DHCP requests elsewhere. OK: v4↔v4, v6↔v6. Not OK: v4↔v6, v6↔v4.')
|
|
||||||
+ '<br />' + _('Note: you may also need a DHCP Proxy (currently unavailable) when specifying a non-standard Relay To port(<code>addr#port</code>).')
|
|
||||||
+ '<br />' + _('You may add multiple unique Relay To on the same Listen addr.'));
|
|
||||||
|
|
||||||
ss = o.subsection;
|
|
||||||
|
|
||||||
ss.addremove = true;
|
|
||||||
ss.anonymous = true;
|
|
||||||
ss.sortable = true;
|
|
||||||
ss.rowcolors = true;
|
|
||||||
ss.nodescriptions = true;
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'id', _('ID'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.optional = true;
|
|
||||||
|
|
||||||
so = ss.option(widgets.NetworkSelect, 'interface', _('Interface'));
|
|
||||||
so.optional = true;
|
|
||||||
so.rmempty = false;
|
|
||||||
so.placeholder = 'lan';
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'local_addr', _('Listen address'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.datatype = 'ipaddr';
|
|
||||||
|
|
||||||
for (var family = 4; family <= 6; family += 2) {
|
|
||||||
for (var i = 0; i < ndevs.length; i++) {
|
|
||||||
var addrs = (family == 6) ? ndevs[i].getIP6Addrs() : ndevs[i].getIPAddrs();
|
|
||||||
for (var j = 0; j < addrs.length; j++)
|
|
||||||
so.value(addrs[j].split('/')[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'server_addr', _('Relay To address'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.optional = false;
|
|
||||||
so.placeholder = '192.168.10.1#535';
|
|
||||||
|
|
||||||
so.validate = function(section, value) {
|
|
||||||
var m = this.section.formvalue(section, 'local_addr'),
|
|
||||||
n = this.section.formvalue(section, 'server_addr'),
|
|
||||||
p;
|
|
||||||
if (n != null && n != '')
|
|
||||||
p = n.split('#');
|
|
||||||
if (p.length > 1 && !/^[0-9]+$/.test(p[1]))
|
|
||||||
return _('Expected port number.');
|
|
||||||
else
|
|
||||||
n = p[0];
|
|
||||||
|
|
||||||
if ((m == null || m == '') && (n == null || n == ''))
|
|
||||||
return _('Both Listen addr and Relay To must be specified.');
|
|
||||||
|
|
||||||
if ((validation.parseIPv6(m) && validation.parseIPv6(n)) ||
|
|
||||||
validation.parseIPv4(m) && validation.parseIPv4(n))
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return _('Listen and Relay To IP family must be homogeneous.')
|
|
||||||
};
|
|
||||||
|
|
||||||
s.taboption('files', form.Flag, 'readethers',
|
s.taboption('files', form.Flag, 'readethers',
|
||||||
_('Use <code>/etc/ethers</code>'),
|
_('Use <code>/etc/ethers</code>'),
|
||||||
_('Read <code>/etc/ethers</code> to configure the DHCP server.'));
|
_('Read <code>/etc/ethers</code> to configure the <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr>-Server'));
|
||||||
|
|
||||||
s.taboption('files', form.Value, 'leasefile',
|
s.taboption('files', form.Value, 'leasefile',
|
||||||
_('Lease file'),
|
_('Leasefile'),
|
||||||
_('File to store DHCP lease information.'));
|
_('file where given <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr>-leases will be stored'));
|
||||||
|
|
||||||
o = s.taboption('files', form.Flag, 'noresolv',
|
s.taboption('files', form.Flag, 'noresolv',
|
||||||
_('Ignore resolv file'));
|
_('Ignore resolve file')).optional = true;
|
||||||
o.optional = true;
|
|
||||||
|
|
||||||
o = s.taboption('files', form.Value, 'resolvfile',
|
o = s.taboption('files', form.Value, 'resolvfile',
|
||||||
_('Resolv file'),
|
_('Resolve file'),
|
||||||
_('File with upstream resolvers.'));
|
_('local <abbr title="Domain Name System">DNS</abbr> file'));
|
||||||
|
|
||||||
o.depends('noresolv', '0');
|
o.depends('noresolv', '0');
|
||||||
o.placeholder = '/tmp/resolv.conf.d/resolv.conf.auto';
|
o.placeholder = '/tmp/resolv.conf.d/resolv.conf.auto';
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
|
|
||||||
o = s.taboption('files', form.Flag, 'nohosts',
|
|
||||||
_('Ignore <code>/etc/hosts</code>'));
|
|
||||||
o.optional = true;
|
|
||||||
|
|
||||||
o = s.taboption('files', form.DynamicList, 'addnhosts',
|
s.taboption('files', form.Flag, 'nohosts',
|
||||||
_('Additional hosts files'));
|
_('Ignore <code>/etc/hosts</code>')).optional = true;
|
||||||
o.optional = true;
|
|
||||||
o.placeholder = '/etc/dnsmasq.hosts';
|
s.taboption('files', form.DynamicList, 'addnhosts',
|
||||||
|
_('Additional Hosts files')).optional = true;
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'quietdhcp',
|
o = s.taboption('advanced', form.Flag, 'quietdhcp',
|
||||||
_('Suppress logging'),
|
_('Suppress logging'),
|
||||||
_('Suppress logging of the routine operation for the DHCP protocol.'));
|
_('Suppress logging of the routine operation of these protocols'));
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'sequential_ip',
|
o = s.taboption('advanced', form.Flag, 'sequential_ip',
|
||||||
_('Allocate IPs sequentially'),
|
_('Allocate IP sequentially'),
|
||||||
_('Allocate IP addresses sequentially, starting from the lowest available address.'));
|
_('Allocate IP addresses sequentially, starting from the lowest available address'));
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'boguspriv',
|
o = s.taboption('advanced', form.Flag, 'boguspriv',
|
||||||
_('Filter private'),
|
_('Filter private'),
|
||||||
_('Do not forward reverse lookups for local networks.'));
|
_('Do not forward reverse lookups for local networks'));
|
||||||
o.default = o.enabled;
|
o.default = o.enabled;
|
||||||
|
|
||||||
s.taboption('advanced', form.Flag, 'filterwin2k',
|
s.taboption('advanced', form.Flag, 'filterwin2k',
|
||||||
_('Filter SRV/SOA service discovery'),
|
_('Filter useless'),
|
||||||
_('Filters SRV/SOA service discovery, to avoid triggering dial-on-demand links.') + '<br />' +
|
_('Do not forward requests that cannot be answered by public name servers'));
|
||||||
_('May prevent VoIP or other services from working.'));
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'filter_aaaa',
|
|
||||||
_('Filter IPv6 AAAA records'),
|
|
||||||
_('Remove IPv6 addresses from the results and only return IPv4 addresses.') + '<br />' +
|
|
||||||
_('Can be useful if ISP has IPv6 nameservers but does not provide IPv6 routing.'));
|
|
||||||
o.optional = true;
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'filter_a',
|
|
||||||
_('Filter IPv4 A records'),
|
|
||||||
_('Remove IPv4 addresses from the results and only return IPv6 addresses.'));
|
|
||||||
o.optional = true;
|
|
||||||
|
|
||||||
s.taboption('advanced', form.Flag, 'localise_queries',
|
s.taboption('advanced', form.Flag, 'localise_queries',
|
||||||
_('Localise queries'),
|
_('Localise queries'),
|
||||||
_('Return answers to DNS queries matching the subnet from which the query was received if multiple IPs are available.'));
|
_('Localise hostname depending on the requesting subnet if multiple IPs are available'));
|
||||||
|
|
||||||
if (L.hasSystemFeature('dnsmasq', 'dnssec')) {
|
if (L.hasSystemFeature('dnsmasq', 'dnssec')) {
|
||||||
o = s.taboption('advanced', form.Flag, 'dnssec',
|
o = s.taboption('advanced', form.Flag, 'dnssec',
|
||||||
_('DNSSEC'),
|
_('DNSSEC'));
|
||||||
_('Validate DNS replies and cache DNSSEC data, requires upstream to support DNSSEC.'));
|
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'dnsseccheckunsigned',
|
o = s.taboption('advanced', form.Flag, 'dnsseccheckunsigned',
|
||||||
_('DNSSEC check unsigned'),
|
_('DNSSEC check unsigned'),
|
||||||
_('Verify unsigned domain responses really come from unsigned domains.'));
|
_('Requires upstream supports DNSSEC; verify unsigned domain responses really come from unsigned domains'));
|
||||||
o.default = o.enabled;
|
o.default = o.enabled;
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.taboption('general', form.Value, 'local',
|
||||||
|
_('Local server'),
|
||||||
|
_('Local domain specification. Names matching this domain are never forwarded and are resolved from DHCP or hosts files only'));
|
||||||
|
|
||||||
|
s.taboption('general', form.Value, 'domain',
|
||||||
|
_('Local domain'),
|
||||||
|
_('Local domain suffix appended to DHCP names and hosts file entries'));
|
||||||
|
|
||||||
s.taboption('advanced', form.Flag, 'expandhosts',
|
s.taboption('advanced', form.Flag, 'expandhosts',
|
||||||
_('Expand hosts'),
|
_('Expand hosts'),
|
||||||
_('Add local domain suffix to names served from hosts files.'));
|
_('Add local domain suffix to names served from hosts files'));
|
||||||
|
|
||||||
s.taboption('advanced', form.Flag, 'nonegcache',
|
s.taboption('advanced', form.Flag, 'nonegcache',
|
||||||
_('No negative cache'),
|
_('No negative cache'),
|
||||||
_('Do not cache negative replies, e.g. for non-existent domains.'));
|
_('Do not cache negative replies, e.g. for not existing domains'));
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'serversfile',
|
s.taboption('advanced', form.Value, 'serversfile',
|
||||||
_('Additional servers file'),
|
_('Additional servers file'),
|
||||||
_('File listing upstream resolvers, optionally domain-specific, e.g. <code>server=1.2.3.4</code>, <code>server=/domain/1.2.3.4</code>.'));
|
_('This file may contain lines like \'server=/domain/1.2.3.4\' or \'server=1.2.3.4\' for domain-specific or full upstream <abbr title="Domain Name System">DNS</abbr> servers.'));
|
||||||
o.placeholder = '/etc/dnsmasq.servers';
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'strictorder',
|
s.taboption('advanced', form.Flag, 'strictorder',
|
||||||
_('Strict order'),
|
_('Strict order'),
|
||||||
_('Upstream resolvers will be queried in the order of the resolv file.'));
|
_('<abbr title="Domain Name System">DNS</abbr> servers will be queried in the order of the resolvfile')).optional = true;
|
||||||
|
|
||||||
|
s.taboption('advanced', form.Flag, 'allservers',
|
||||||
|
_('All Servers'),
|
||||||
|
_('Query all available upstream <abbr title="Domain Name System">DNS</abbr> servers')).optional = true;
|
||||||
|
|
||||||
|
o = s.taboption('advanced', form.DynamicList, 'bogusnxdomain', _('Bogus NX Domain Override'),
|
||||||
|
_('List of hosts that supply bogus NX domain results'));
|
||||||
|
|
||||||
|
o.optional = true;
|
||||||
|
o.placeholder = '67.215.65.132';
|
||||||
|
|
||||||
|
|
||||||
|
s.taboption('general', form.Flag, 'logqueries',
|
||||||
|
_('Log queries'),
|
||||||
|
_('Write received DNS requests to syslog')).optional = true;
|
||||||
|
|
||||||
|
o = s.taboption('general', form.DynamicList, 'server', _('DNS forwardings'),
|
||||||
|
_('List of <abbr title="Domain Name System">DNS</abbr> servers to forward requests to'));
|
||||||
|
|
||||||
|
o.optional = true;
|
||||||
|
o.placeholder = '/example.org/10.1.2.3';
|
||||||
|
o.validate = validateServerSpec;
|
||||||
|
|
||||||
|
|
||||||
|
o = s.taboption('general', form.DynamicList, 'address', _('Addresses'),
|
||||||
|
_('List of domains to force to an IP address.'));
|
||||||
|
|
||||||
|
o.optional = true;
|
||||||
|
o.placeholder = '/router.local/192.168.0.1';
|
||||||
|
|
||||||
|
|
||||||
|
o = s.taboption('general', form.Flag, 'rebind_protection',
|
||||||
|
_('Rebind protection'),
|
||||||
|
_('Discard upstream RFC1918 responses'));
|
||||||
|
|
||||||
|
o.rmempty = false;
|
||||||
|
|
||||||
|
|
||||||
|
o = s.taboption('general', form.Flag, 'rebind_localhost',
|
||||||
|
_('Allow localhost'),
|
||||||
|
_('Allow upstream responses in the 127.0.0.0/8 range, e.g. for RBL services'));
|
||||||
|
|
||||||
|
o.depends('rebind_protection', '1');
|
||||||
|
|
||||||
|
|
||||||
|
o = s.taboption('general', form.DynamicList, 'rebind_domain',
|
||||||
|
_('Domain whitelist'),
|
||||||
|
_('List of domains to allow RFC1918 responses for'));
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'allservers',
|
o.depends('rebind_protection', '1');
|
||||||
_('All servers'),
|
o.placeholder = 'ihost.netflix.com';
|
||||||
_('Query all available upstream resolvers.'));
|
o.validate = validateAddressList;
|
||||||
o.optional = true;
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.DynamicList, 'bogusnxdomain',
|
|
||||||
_('IPs to override with NXDOMAIN'),
|
|
||||||
_('List of IP addresses to convert into NXDOMAIN responses.'));
|
|
||||||
o.optional = true;
|
|
||||||
o.placeholder = '64.94.110.11';
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'port',
|
o = s.taboption('advanced', form.Value, 'port',
|
||||||
_('DNS server port'),
|
_('<abbr title="Domain Name System">DNS</abbr> server port'),
|
||||||
_('Listening port for inbound DNS queries.'));
|
_('Listening port for inbound DNS queries'));
|
||||||
|
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
o.datatype = 'port';
|
o.datatype = 'port';
|
||||||
o.placeholder = 53;
|
o.placeholder = 53;
|
||||||
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'queryport',
|
o = s.taboption('advanced', form.Value, 'queryport',
|
||||||
_('DNS query port'),
|
_('<abbr title="Domain Name System">DNS</abbr> query port'),
|
||||||
_('Fixed source port for outbound DNS queries.'));
|
_('Fixed source port for outbound DNS queries'));
|
||||||
|
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
o.datatype = 'port';
|
o.datatype = 'port';
|
||||||
o.placeholder = _('any');
|
o.placeholder = _('any');
|
||||||
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'dhcpleasemax',
|
o = s.taboption('advanced', form.Value, 'dhcpleasemax',
|
||||||
_('Max. DHCP leases'),
|
_('<abbr title="maximal">Max.</abbr> <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr> leases'),
|
||||||
_('Maximum allowed number of active DHCP leases.'));
|
_('Maximum allowed number of active DHCP leases'));
|
||||||
|
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
o.datatype = 'uinteger';
|
o.datatype = 'uinteger';
|
||||||
o.placeholder = _('unlimited');
|
o.placeholder = _('unlimited');
|
||||||
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'ednspacket_max',
|
o = s.taboption('advanced', form.Value, 'ednspacket_max',
|
||||||
_('Max. EDNS0 packet size'),
|
_('<abbr title="maximal">Max.</abbr> <abbr title="Extension Mechanisms for Domain Name System">EDNS0</abbr> packet size'),
|
||||||
_('Maximum allowed size of EDNS0 UDP packets.'));
|
_('Maximum allowed size of EDNS.0 UDP packets'));
|
||||||
|
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
o.datatype = 'uinteger';
|
o.datatype = 'uinteger';
|
||||||
o.placeholder = 1280;
|
o.placeholder = 1280;
|
||||||
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'dnsforwardmax',
|
o = s.taboption('advanced', form.Value, 'dnsforwardmax',
|
||||||
_('Max. concurrent queries'),
|
_('<abbr title="maximal">Max.</abbr> concurrent queries'),
|
||||||
_('Maximum allowed number of concurrent DNS queries.'));
|
_('Maximum allowed number of concurrent DNS queries'));
|
||||||
|
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
o.datatype = 'uinteger';
|
o.datatype = 'uinteger';
|
||||||
o.placeholder = 150;
|
o.placeholder = 150;
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'cachesize',
|
o = s.taboption('advanced', form.Value, 'cachesize',
|
||||||
_('Size of DNS query cache'),
|
_('Size of DNS query cache'),
|
||||||
_('Number of cached DNS entries, 10000 is maximum, 0 is no caching.'));
|
_('Number of cached DNS entries (max is 10000, 0 is no caching)'));
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
o.datatype = 'range(0,10000)';
|
o.datatype = 'range(0,10000)';
|
||||||
o.placeholder = 1000;
|
o.placeholder = 150;
|
||||||
|
|
||||||
o = s.taboption('pxe_tftp', form.Flag, 'enable_tftp',
|
s.taboption('tftp', form.Flag, 'enable_tftp',
|
||||||
_('Enable TFTP server'),
|
_('Enable TFTP server')).optional = true;
|
||||||
_('Enable the built-in single-instance TFTP server.'));
|
|
||||||
o.optional = true;
|
|
||||||
|
|
||||||
o = s.taboption('pxe_tftp', form.Value, 'tftp_root',
|
o = s.taboption('tftp', form.Value, 'tftp_root',
|
||||||
_('TFTP server root'),
|
_('TFTP server root'),
|
||||||
_('Root directory for files served via TFTP. <em>Enable TFTP server</em> and <em>TFTP server root</em> turn on the TFTP server and serve files from <em>TFTP server root</em>.'));
|
_('Root directory for files served via TFTP'));
|
||||||
o.depends('enable_tftp', '1');
|
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
|
o.depends('enable_tftp', '1');
|
||||||
o.placeholder = '/';
|
o.placeholder = '/';
|
||||||
|
|
||||||
o = s.taboption('pxe_tftp', form.Value, 'dhcp_boot',
|
|
||||||
|
o = s.taboption('tftp', form.Value, 'dhcp_boot',
|
||||||
_('Network boot image'),
|
_('Network boot image'),
|
||||||
_('Filename of the boot image advertised to clients.'));
|
_('Filename of the boot image advertised to clients'));
|
||||||
o.depends('enable_tftp', '1');
|
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
|
o.depends('enable_tftp', '1');
|
||||||
o.placeholder = 'pxelinux.0';
|
o.placeholder = 'pxelinux.0';
|
||||||
|
|
||||||
/* PXE - https://openwrt.org/docs/guide-user/base-system/dhcp#booting_options */
|
o = s.taboption('general', form.Flag, 'localservice',
|
||||||
o = s.taboption('pxe_tftp', form.SectionValue, '__pxe__', form.GridSection, 'boot', null,
|
_('Local Service Only'),
|
||||||
_('Special <abbr title="Preboot eXecution Environment">PXE</abbr> boot options for Dnsmasq.'));
|
_('Limit DNS service to subnets interfaces on which we are serving DNS.'));
|
||||||
ss = o.subsection;
|
o.optional = false;
|
||||||
ss.addremove = true;
|
o.rmempty = false;
|
||||||
ss.anonymous = true;
|
|
||||||
ss.nodescriptions = true;
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'filename',
|
o = s.taboption('general', form.Flag, 'nonwildcard',
|
||||||
_('Filename'),
|
_('Non-wildcard'),
|
||||||
_('Host requests this filename from the boot server.'));
|
_('Bind dynamically to interfaces rather than wildcard address (recommended as linux default)'));
|
||||||
so.optional = false;
|
o.default = o.enabled;
|
||||||
so.placeholder = 'pxelinux.0';
|
o.optional = false;
|
||||||
|
o.rmempty = true;
|
||||||
|
|
||||||
so = ss.option(form.Value, 'servername',
|
o = s.taboption('general', form.DynamicList, 'interface',
|
||||||
_('Server name'),
|
_('Listen Interfaces'),
|
||||||
_('The hostname of the boot server'));
|
_('Limit listening to these interfaces, and loopback.'));
|
||||||
so.optional = false;
|
o.optional = true;
|
||||||
so.placeholder = 'myNAS';
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'serveraddress',
|
o = s.taboption('general', form.DynamicList, 'notinterface',
|
||||||
_('Server address'),
|
_('Exclude interfaces'),
|
||||||
_('The IP address of the boot server'));
|
_('Prevent listening on these interfaces.'));
|
||||||
so.optional = false;
|
o.optional = true;
|
||||||
so.placeholder = '192.168.1.2';
|
|
||||||
|
|
||||||
so = ss.option(form.DynamicList, 'dhcp_option',
|
|
||||||
_('DHCP Options'),
|
|
||||||
_('Options for the Network-ID. (Note: needs also Network-ID.) E.g. "<code>42,192.168.1.4</code>" for NTP server, "<code>3,192.168.4.4</code>" for default route. <code>0.0.0.0</code> means "the address of the system running dnsmasq".'));
|
|
||||||
so.optional = true;
|
|
||||||
so.placeholder = '42,192.168.1.4';
|
|
||||||
|
|
||||||
so = ss.option(widgets.DeviceSelect, 'networkid',
|
|
||||||
_('Network-ID'),
|
|
||||||
_('Apply DHCP Options to this net. (Empty = all clients).'));
|
|
||||||
so.optional = true;
|
|
||||||
so.noaliases = true;
|
|
||||||
|
|
||||||
so = ss.option(form.Flag, 'force',
|
|
||||||
_('Force'),
|
|
||||||
_('Always send DHCP Options. Sometimes needed, with e.g. PXELinux.'));
|
|
||||||
so.optional = true;
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'instance',
|
|
||||||
_('Instance'),
|
|
||||||
_('Dnsmasq instance to which this boot section is bound. If unspecified, the section is valid for all dnsmasq instances.'));
|
|
||||||
so.optional = true;
|
|
||||||
|
|
||||||
Object.values(L.uci.sections('dhcp', 'dnsmasq')).forEach(function(val, index) {
|
|
||||||
so.value(index, '%s (Domain: %s, Local: %s)'.format(index, val.domain || '?', val.local || '?'));
|
|
||||||
});
|
|
||||||
|
|
||||||
o = s.taboption('srvhosts', form.SectionValue, '__srvhosts__', form.TableSection, 'srvhost', null,
|
|
||||||
_('Bind service records to a domain name: specify the location of services. See <a href="%s">RFC2782</a>.').format('https://datatracker.ietf.org/doc/html/rfc2782')
|
|
||||||
+ '<br />' + _('_service: _sip, _ldap, _imap, _stun, _xmpp-client, … . (Note: while _http is possible, no browsers support SRV records.)')
|
|
||||||
+ '<br />' + _('_proto: _tcp, _udp, _sctp, _quic, … .')
|
|
||||||
+ '<br />' + _('You may add multiple records for the same Target.')
|
|
||||||
+ '<br />' + _('Larger weights (of the same prio) are given a proportionately higher probability of being selected.'));
|
|
||||||
|
|
||||||
ss = o.subsection;
|
|
||||||
|
|
||||||
ss.addremove = true;
|
|
||||||
ss.anonymous = true;
|
|
||||||
ss.sortable = true;
|
|
||||||
ss.rowcolors = true;
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'srv', _('SRV'), _('Syntax: <code>_service._proto.example.com</code>.'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.datatype = 'hostname';
|
|
||||||
so.placeholder = '_sip._tcp.example.com';
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'target', _('Target'), _('CNAME or fqdn'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.datatype = 'hostname';
|
|
||||||
so.placeholder = 'sip.example.com';
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'port', _('Port'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.datatype = 'port';
|
|
||||||
so.placeholder = '5060';
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'class', _('Priority'), _('Ordinal: lower comes first.'));
|
|
||||||
so.rmempty = true;
|
|
||||||
so.datatype = 'range(0,65535)';
|
|
||||||
so.placeholder = '10';
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'weight', _('Weight'));
|
|
||||||
so.rmempty = true;
|
|
||||||
so.datatype = 'range(0,65535)';
|
|
||||||
so.placeholder = '50';
|
|
||||||
|
|
||||||
o = s.taboption('mxhosts', form.SectionValue, '__mxhosts__', form.TableSection, 'mxhost', null,
|
|
||||||
_('Bind service records to a domain name: specify the location of services.')
|
|
||||||
+ '<br />' + _('You may add multiple records for the same domain.'));
|
|
||||||
|
|
||||||
ss = o.subsection;
|
|
||||||
|
|
||||||
ss.addremove = true;
|
|
||||||
ss.anonymous = true;
|
|
||||||
ss.sortable = true;
|
|
||||||
ss.rowcolors = true;
|
|
||||||
ss.nodescriptions = true;
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'domain', _('Domain'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.datatype = 'hostname';
|
|
||||||
so.placeholder = 'example.com';
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'relay', _('Relay'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.datatype = 'hostname';
|
|
||||||
so.placeholder = 'relay.example.com';
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'pref', _('Priority'), _('Ordinal: lower comes first.'));
|
|
||||||
so.rmempty = true;
|
|
||||||
so.datatype = 'range(0,65535)';
|
|
||||||
so.placeholder = '0';
|
|
||||||
|
|
||||||
o = s.taboption('hosts', form.SectionValue, '__hosts__', form.GridSection, 'domain', null,
|
|
||||||
_('Hostnames are used to bind a domain name to an IP address. This setting is redundant for hostnames already configured with static leases, but it can be useful to rebind an FQDN.'));
|
|
||||||
|
|
||||||
ss = o.subsection;
|
|
||||||
|
|
||||||
ss.addremove = true;
|
|
||||||
ss.anonymous = true;
|
|
||||||
ss.sortable = true;
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'name', _('Hostname'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.datatype = 'hostname';
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'ip', _('IP address'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.datatype = 'ipaddr';
|
|
||||||
|
|
||||||
var ipaddrs = {};
|
|
||||||
|
|
||||||
Object.keys(hosts).forEach(function(mac) {
|
|
||||||
var addrs = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4);
|
|
||||||
|
|
||||||
for (var i = 0; i < addrs.length; i++)
|
|
||||||
ipaddrs[addrs[i]] = hosts[mac].name || mac;
|
|
||||||
});
|
|
||||||
|
|
||||||
L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) {
|
|
||||||
so.value(ipv4, '%s (%s)'.format(ipv4, ipaddrs[ipv4]));
|
|
||||||
});
|
|
||||||
|
|
||||||
o = s.taboption('ipsets', form.SectionValue, '__ipsets__', form.GridSection, 'ipset', null,
|
|
||||||
_('List of IP sets to populate with the IPs of DNS lookup results of the FQDNs also specified here.'));
|
|
||||||
|
|
||||||
ss = o.subsection;
|
|
||||||
|
|
||||||
ss.addremove = true;
|
|
||||||
ss.anonymous = true;
|
|
||||||
ss.sortable = true;
|
|
||||||
|
|
||||||
so = ss.option(form.DynamicList, 'name', _('IP set'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.datatype = 'string';
|
|
||||||
|
|
||||||
so = ss.option(form.DynamicList, 'domain', _('Domain'));
|
|
||||||
so.rmempty = false;
|
|
||||||
so.datatype = 'hostname';
|
|
||||||
|
|
||||||
o = s.taboption('leases', form.SectionValue, '__leases__', form.GridSection, 'host', null,
|
o = s.taboption('leases', form.SectionValue, '__leases__', form.GridSection, 'host', null,
|
||||||
_('Static leases are used to assign fixed IP addresses and symbolic hostnames to DHCP clients. They are also required for non-dynamic interface configurations where only hosts with a corresponding lease are served.') + '<br />' +
|
_('Static leases are used to assign fixed IP addresses and symbolic hostnames to DHCP clients. They are also required for non-dynamic interface configurations where only hosts with a corresponding lease are served.') + '<br />' +
|
||||||
|
@ -749,7 +415,6 @@ return view.extend({
|
||||||
|
|
||||||
ss.addremove = true;
|
ss.addremove = true;
|
||||||
ss.anonymous = true;
|
ss.anonymous = true;
|
||||||
ss.sortable = true;
|
|
||||||
|
|
||||||
so = ss.option(form.Value, 'name', _('Hostname'));
|
so = ss.option(form.Value, 'name', _('Hostname'));
|
||||||
so.validate = validateHostname;
|
so.validate = validateHostname;
|
||||||
|
@ -763,8 +428,8 @@ return view.extend({
|
||||||
uci.unset('dhcp', section, 'dns');
|
uci.unset('dhcp', section, 'dns');
|
||||||
};
|
};
|
||||||
|
|
||||||
so = ss.option(form.Value, 'mac', _('MAC address'));
|
so = ss.option(form.Value, 'mac', _('<abbr title="Media Access Control">MAC</abbr>-Address'));
|
||||||
so.datatype = 'list(macaddr)';
|
so.datatype = 'list(unique(macaddr))';
|
||||||
so.rmempty = true;
|
so.rmempty = true;
|
||||||
so.cfgvalue = function(section) {
|
so.cfgvalue = function(section) {
|
||||||
var macs = L.toArray(uci.get('dhcp', section, 'mac')),
|
var macs = L.toArray(uci.get('dhcp', section, 'mac')),
|
||||||
|
@ -803,54 +468,75 @@ return view.extend({
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
};
|
};
|
||||||
so.validate = validateMACAddr.bind(so, pools);
|
|
||||||
Object.keys(hosts).forEach(function(mac) {
|
Object.keys(hosts).forEach(function(mac) {
|
||||||
var hint = hosts[mac].name || L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0];
|
var hint = hosts[mac].name || L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4)[0];
|
||||||
so.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac);
|
so.value(mac, hint ? '%s (%s)'.format(mac, hint) : mac);
|
||||||
});
|
});
|
||||||
|
|
||||||
so = ss.option(form.Value, 'ip', _('IPv4 address'));
|
so.write = function(section, value) {
|
||||||
so.datatype = 'or(ip4addr,"ignore")';
|
var ip = this.map.lookupOption('ip', section)[0].formvalue(section);
|
||||||
so.validate = function(section, value) {
|
var hosts = uci.sections('dhcp', 'host');
|
||||||
var m = this.section.formvalue(section, 'mac'),
|
var section_removed = false;
|
||||||
n = this.section.formvalue(section, 'name');
|
|
||||||
|
|
||||||
if ((m == null || m == '') && (n == null || n == ''))
|
for (var i = 0; i < hosts.length; i++) {
|
||||||
return _('One of hostname or MAC address must be specified!');
|
if (ip == hosts[i].ip) {
|
||||||
|
uci.set('dhcp', hosts[i]['.name'], 'mac', [hosts[i].mac, value].join(' '));
|
||||||
if (value == null || value == '' || value == 'ignore')
|
uci.remove('dhcp', section);
|
||||||
return true;
|
section_removed = true;
|
||||||
|
break;
|
||||||
var leases = uci.sections('dhcp', 'host');
|
}
|
||||||
|
|
||||||
for (var i = 0; i < leases.length; i++)
|
|
||||||
if (leases[i]['.name'] != section && leases[i].ip == value)
|
|
||||||
return _('The IP address %h is already used by another static lease').format(value);
|
|
||||||
|
|
||||||
for (var i = 0; i < pools.length; i++) {
|
|
||||||
var net_mask = calculateNetwork(value, pools[i].netmask);
|
|
||||||
|
|
||||||
if (net_mask && net_mask[0] == pools[i].network)
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return _('The IP address is outside of any DHCP pool address range');
|
if (!section_removed) {
|
||||||
|
uci.set('dhcp', section, 'mac', value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
so = ss.option(form.Value, 'ip', _('<abbr title="Internet Protocol Version 4">IPv4</abbr>-Address'));
|
||||||
|
so.datatype = 'or(ip4addr,"ignore")';
|
||||||
|
so.validate = function(section, value) {
|
||||||
|
var mac = this.map.lookupOption('mac', section),
|
||||||
|
name = this.map.lookupOption('name', section),
|
||||||
|
m = mac ? mac[0].formvalue(section) : null,
|
||||||
|
n = name ? name[0].formvalue(section) : null;
|
||||||
|
|
||||||
|
if ((m == null || m == '') && (n == null || n == ''))
|
||||||
|
return _('One of hostname or mac address must be specified!');
|
||||||
|
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var ipaddrs = {};
|
||||||
|
|
||||||
|
Object.keys(hosts).forEach(function(mac) {
|
||||||
|
var addrs = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4);
|
||||||
|
|
||||||
|
for (var i = 0; i < addrs.length; i++)
|
||||||
|
ipaddrs[addrs[i]] = hosts[mac].name;
|
||||||
|
});
|
||||||
|
|
||||||
L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) {
|
L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) {
|
||||||
so.value(ipv4, ipaddrs[ipv4] ? '%s (%s)'.format(ipv4, ipaddrs[ipv4]) : ipv4);
|
so.value(ipv4, ipaddrs[ipv4] ? '%s (%s)'.format(ipv4, ipaddrs[ipv4]) : ipv4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
so = ss.option(form.Value, 'gw', _('Gateway IPv4 Address'));
|
||||||
|
so.rmempty = true;
|
||||||
|
so.datatype = 'or(ip4addr,"ignore")';
|
||||||
|
Object.keys(hosts).forEach(function(mac) {
|
||||||
|
if (hosts[mac].ipv4)
|
||||||
|
so.value(hosts[mac].ipv4);
|
||||||
|
});
|
||||||
|
|
||||||
so = ss.option(form.Value, 'leasetime', _('Lease time'));
|
so = ss.option(form.Value, 'leasetime', _('Lease time'));
|
||||||
so.rmempty = true;
|
so.rmempty = true;
|
||||||
|
|
||||||
so = ss.option(form.Value, 'duid', _('DUID'));
|
so = ss.option(form.Value, 'duid', _('<abbr title="The DHCP Unique Identifier">DUID</abbr>'));
|
||||||
so.datatype = 'and(rangelength(20,36),hexstring)';
|
so.datatype = 'and(rangelength(20,36),hexstring)';
|
||||||
Object.keys(duids).forEach(function(duid) {
|
Object.keys(duids).forEach(function(duid) {
|
||||||
so.value(duid, '%s (%s)'.format(duid, duids[duid].hostname || duids[duid].macaddr || duids[duid].ip6addr || '?'));
|
so.value(duid, '%s (%s)'.format(duid, duids[duid].hostname || duids[duid].macaddr || duids[duid].ip6addr || '?'));
|
||||||
});
|
});
|
||||||
|
|
||||||
so = ss.option(form.Value, 'hostid', _('IPv6 suffix (hex)'));
|
so = ss.option(form.Value, 'hostid', _('<abbr title="Internet Protocol Version 6">IPv6</abbr>-Suffix (hex)'));
|
||||||
|
|
||||||
o = s.taboption('leases', CBILeaseStatus, '__status__');
|
o = s.taboption('leases', CBILeaseStatus, '__status__');
|
||||||
|
|
||||||
|
@ -874,17 +560,8 @@ return view.extend({
|
||||||
else
|
else
|
||||||
exp = '%t'.format(lease.expires);
|
exp = '%t'.format(lease.expires);
|
||||||
|
|
||||||
var hint = lease.macaddr ? hosts[lease.macaddr] : null,
|
|
||||||
name = hint ? hint.name : null,
|
|
||||||
host = null;
|
|
||||||
|
|
||||||
if (name && lease.hostname && lease.hostname != name)
|
|
||||||
host = '%s (%s)'.format(lease.hostname, name);
|
|
||||||
else if (lease.hostname)
|
|
||||||
host = lease.hostname;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
host || '-',
|
lease.hostname || '?',
|
||||||
lease.ipaddr,
|
lease.ipaddr,
|
||||||
lease.macaddr,
|
lease.macaddr,
|
||||||
exp
|
exp
|
||||||
|
|
64
luci-mod-network/htdocs/luci-static/resources/view/network/diagnostics.js
Normal file → Executable file
64
luci-mod-network/htdocs/luci-static/resources/view/network/diagnostics.js
Normal file → Executable file
|
@ -4,7 +4,6 @@
|
||||||
'require fs';
|
'require fs';
|
||||||
'require ui';
|
'require ui';
|
||||||
'require uci';
|
'require uci';
|
||||||
'require network';
|
|
||||||
|
|
||||||
return view.extend({
|
return view.extend({
|
||||||
handleCommand: function(exec, args) {
|
handleCommand: function(exec, args) {
|
||||||
|
@ -14,7 +13,8 @@ return view.extend({
|
||||||
buttons[i].setAttribute('disabled', 'true');
|
buttons[i].setAttribute('disabled', 'true');
|
||||||
|
|
||||||
return fs.exec(exec, args).then(function(res) {
|
return fs.exec(exec, args).then(function(res) {
|
||||||
var out = document.querySelector('textarea');
|
var out = document.querySelector('.command-output');
|
||||||
|
out.style.display = '';
|
||||||
|
|
||||||
dom.content(out, [ res.stdout || '', res.stderr || '' ]);
|
dom.content(out, [ res.stdout || '', res.stderr || '' ]);
|
||||||
}).catch(function(err) {
|
}).catch(function(err) {
|
||||||
|
@ -36,7 +36,7 @@ return view.extend({
|
||||||
handleTraceroute: function(ev, cmd) {
|
handleTraceroute: function(ev, cmd) {
|
||||||
var exec = cmd || 'traceroute',
|
var exec = cmd || 'traceroute',
|
||||||
addr = ev.currentTarget.parentNode.previousSibling.value,
|
addr = ev.currentTarget.parentNode.previousSibling.value,
|
||||||
args = (exec == 'traceroute') ? [ '-4', '-q', '1', '-w', '1', '-n', '-m', String(L.env.rpctimeout || 20), addr ] : [ '-q', '1', '-w', '2', '-n', addr ];
|
args = (exec == 'traceroute') ? [ '-q', '1', '-w', '1', '-n', addr ] : [ '-q', '1', '-w', '2', '-n', addr ];
|
||||||
|
|
||||||
return this.handleCommand(exec, args);
|
return this.handleCommand(exec, args);
|
||||||
},
|
},
|
||||||
|
@ -47,20 +47,12 @@ return view.extend({
|
||||||
return this.handleCommand('nslookup', [ addr ]);
|
return this.handleCommand('nslookup', [ addr ]);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleArpScan: function(ev, cmd) {
|
|
||||||
var addr = ev.currentTarget.parentNode.previousSibling.value;
|
|
||||||
|
|
||||||
return this.handleCommand('arp-scan', [ '-l', '-I', addr ]);
|
|
||||||
},
|
|
||||||
|
|
||||||
load: function() {
|
load: function() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
L.resolveDefault(fs.stat('/bin/ping6'), {}),
|
L.resolveDefault(fs.stat('/bin/ping6'), {}),
|
||||||
L.resolveDefault(fs.stat('/usr/bin/ping6'), {}),
|
L.resolveDefault(fs.stat('/usr/bin/ping6'), {}),
|
||||||
L.resolveDefault(fs.stat('/bin/traceroute6'), {}),
|
L.resolveDefault(fs.stat('/bin/traceroute6'), {}),
|
||||||
L.resolveDefault(fs.stat('/usr/bin/traceroute6'), {}),
|
L.resolveDefault(fs.stat('/usr/bin/traceroute6'), {}),
|
||||||
L.resolveDefault(fs.stat('/usr/bin/arp-scan'), {}),
|
|
||||||
network.getDevices(),
|
|
||||||
uci.load('luci')
|
uci.load('luci')
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
@ -68,15 +60,15 @@ return view.extend({
|
||||||
render: function(res) {
|
render: function(res) {
|
||||||
var has_ping6 = res[0].path || res[1].path,
|
var has_ping6 = res[0].path || res[1].path,
|
||||||
has_traceroute6 = res[2].path || res[3].path,
|
has_traceroute6 = res[2].path || res[3].path,
|
||||||
has_arpscan = res[4].path,
|
|
||||||
devices = res[5],
|
|
||||||
dns_host = uci.get('luci', 'diag', 'dns') || 'openwrt.org',
|
dns_host = uci.get('luci', 'diag', 'dns') || 'openwrt.org',
|
||||||
ping_host = uci.get('luci', 'diag', 'ping') || 'openwrt.org',
|
ping_host = uci.get('luci', 'diag', 'ping') || 'openwrt.org',
|
||||||
route_host = uci.get('luci', 'diag', 'route') || 'openwrt.org';
|
route_host = uci.get('luci', 'diag', 'route') || 'openwrt.org';
|
||||||
|
|
||||||
var table = E('table', { 'class': 'table' }, [
|
return E([], [
|
||||||
|
E('h2', {}, [ _('Network Utilities') ]),
|
||||||
|
E('table', { 'class': 'table' }, [
|
||||||
E('tr', { 'class': 'tr' }, [
|
E('tr', { 'class': 'tr' }, [
|
||||||
E('td', { 'class': 'td left', 'style': 'overflow:initial' }, [
|
E('td', { 'class': 'td left' }, [
|
||||||
E('input', {
|
E('input', {
|
||||||
'style': 'margin:5px 0',
|
'style': 'margin:5px 0',
|
||||||
'type': 'text',
|
'type': 'text',
|
||||||
|
@ -99,7 +91,7 @@ return view.extend({
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
|
|
||||||
E('td', { 'class': 'td left', 'style': 'overflow:initial' }, [
|
E('td', { 'class': 'td left' }, [
|
||||||
E('input', {
|
E('input', {
|
||||||
'style': 'margin:5px 0',
|
'style': 'margin:5px 0',
|
||||||
'type': 'text',
|
'type': 'text',
|
||||||
|
@ -134,45 +126,11 @@ return view.extend({
|
||||||
'click': ui.createHandlerFn(this, 'handleNslookup')
|
'click': ui.createHandlerFn(this, 'handleNslookup')
|
||||||
}, [ _('Nslookup') ])
|
}, [ _('Nslookup') ])
|
||||||
])
|
])
|
||||||
]),
|
])
|
||||||
|
|
||||||
has_arpscan ? E('td', { 'class': 'td left' }, [
|
|
||||||
E('select', {
|
|
||||||
'style': 'margin:5px 0'
|
|
||||||
}, devices.map(function(device) {
|
|
||||||
if (!device.isUp())
|
|
||||||
return E([]);
|
|
||||||
|
|
||||||
return E('option', { 'value': device.getName() }, [ device.getI18n() ]);
|
|
||||||
})),
|
|
||||||
E('span', { 'class': 'diag-action' }, [
|
|
||||||
E('button', {
|
|
||||||
'class': 'cbi-button cbi-button-action',
|
|
||||||
'click': ui.createHandlerFn(this, 'handleArpScan')
|
|
||||||
}, [ _('Arp-scan') ])
|
|
||||||
])
|
|
||||||
]) : E([]),
|
|
||||||
])
|
])
|
||||||
]);
|
]),
|
||||||
|
E('pre', { 'class': 'command-output', 'style': 'display:none' })
|
||||||
var view = E('div', { 'class': 'cbi-map'}, [
|
|
||||||
E('h2', {}, [ _('Diagnostics') ]),
|
|
||||||
E('div', { 'class': 'cbi-map-descr'}, _('Execution of various network commands to check the connection and name resolution to other systems.')),
|
|
||||||
table,
|
|
||||||
E('div', {'class': 'cbi-section'}, [
|
|
||||||
E('div', { 'id' : 'command-output'},
|
|
||||||
E('textarea', {
|
|
||||||
'id': 'widget.command-output',
|
|
||||||
'style': 'width: 100%; font-family:monospace; white-space:pre',
|
|
||||||
'readonly': true,
|
|
||||||
'wrap': 'off',
|
|
||||||
'rows': '20'
|
|
||||||
})
|
|
||||||
)
|
|
||||||
])
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return view;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSaveApply: null,
|
handleSaveApply: null,
|
||||||
|
|
50
luci-mod-network/htdocs/luci-static/resources/view/network/hosts.js
Executable file
50
luci-mod-network/htdocs/luci-static/resources/view/network/hosts.js
Executable file
|
@ -0,0 +1,50 @@
|
||||||
|
'use strict';
|
||||||
|
'require view';
|
||||||
|
'require rpc';
|
||||||
|
'require form';
|
||||||
|
|
||||||
|
return view.extend({
|
||||||
|
callHostHints: rpc.declare({
|
||||||
|
object: 'luci-rpc',
|
||||||
|
method: 'getHostHints',
|
||||||
|
expect: { '': {} }
|
||||||
|
}),
|
||||||
|
|
||||||
|
load: function() {
|
||||||
|
return this.callHostHints();
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function(hosts) {
|
||||||
|
var m, s, o;
|
||||||
|
|
||||||
|
m = new form.Map('dhcp', _('Hostnames'));
|
||||||
|
|
||||||
|
s = m.section(form.GridSection, 'domain', _('Host entries'));
|
||||||
|
s.addremove = true;
|
||||||
|
s.anonymous = true;
|
||||||
|
s.sortable = true;
|
||||||
|
|
||||||
|
o = s.option(form.Value, 'name', _('Hostname'));
|
||||||
|
o.datatype = 'hostname';
|
||||||
|
o.rmempty = true;
|
||||||
|
|
||||||
|
o = s.option(form.Value, 'ip', _('IP address'));
|
||||||
|
o.datatype = 'ipaddr';
|
||||||
|
o.rmempty = true;
|
||||||
|
|
||||||
|
var ipaddrs = {};
|
||||||
|
|
||||||
|
Object.keys(hosts).forEach(function(mac) {
|
||||||
|
var addrs = L.toArray(hosts[mac].ipaddrs || hosts[mac].ipv4);
|
||||||
|
|
||||||
|
for (var i = 0; i < addrs.length; i++)
|
||||||
|
ipaddrs[addrs[i]] = hosts[mac].name || mac;
|
||||||
|
});
|
||||||
|
|
||||||
|
L.sortedKeys(ipaddrs, null, 'addr').forEach(function(ipv4) {
|
||||||
|
o.value(ipv4, '%s (%s)'.format(ipv4, ipaddrs[ipv4]));
|
||||||
|
});
|
||||||
|
|
||||||
|
return m.render();
|
||||||
|
}
|
||||||
|
});
|
128
luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js
Normal file → Executable file
128
luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js
Normal file → Executable file
|
@ -228,23 +228,6 @@ function get_netmask(s, use_cfgvalue) {
|
||||||
return subnetmask;
|
return subnetmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
function has_peerdns(proto) {
|
|
||||||
switch (proto) {
|
|
||||||
case 'dhcp':
|
|
||||||
case 'dhcpv6':
|
|
||||||
case 'qmi':
|
|
||||||
case 'ppp':
|
|
||||||
case 'pppoe':
|
|
||||||
case 'pppoa':
|
|
||||||
case 'pptp':
|
|
||||||
case 'openvpn':
|
|
||||||
case 'sstp':
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var cbiRichListValue = form.ListValue.extend({
|
var cbiRichListValue = form.ListValue.extend({
|
||||||
renderWidget: function(section_id, option_index, cfgvalue) {
|
renderWidget: function(section_id, option_index, cfgvalue) {
|
||||||
var choices = this.transformChoices();
|
var choices = this.transformChoices();
|
||||||
|
@ -505,7 +488,7 @@ return view.extend({
|
||||||
};
|
};
|
||||||
|
|
||||||
s.modaltitle = function(section_id) {
|
s.modaltitle = function(section_id) {
|
||||||
return _('Interfaces') + ' » ' + section_id;
|
return _('Interfaces') + ' » ' + section_id.toUpperCase();
|
||||||
};
|
};
|
||||||
|
|
||||||
s.renderRowActions = function(section_id) {
|
s.renderRowActions = function(section_id) {
|
||||||
|
@ -552,7 +535,7 @@ return view.extend({
|
||||||
var protocols = network.getProtocols();
|
var protocols = network.getProtocols();
|
||||||
|
|
||||||
protocols.sort(function(a, b) {
|
protocols.sort(function(a, b) {
|
||||||
return L.naturalCompare(a.getProtocol(), b.getProtocol());
|
return a.getProtocol() > b.getProtocol();
|
||||||
});
|
});
|
||||||
|
|
||||||
o = s.taboption('general', form.DummyValue, '_ifacestat_modal', _('Status'));
|
o = s.taboption('general', form.DummyValue, '_ifacestat_modal', _('Status'));
|
||||||
|
@ -660,7 +643,7 @@ return view.extend({
|
||||||
E('p', _('No DHCP Server configured for this interface') + '   '),
|
E('p', _('No DHCP Server configured for this interface') + '   '),
|
||||||
E('button', {
|
E('button', {
|
||||||
'class': 'cbi-button cbi-button-add',
|
'class': 'cbi-button cbi-button-add',
|
||||||
'title': _('Set up DHCP Server'),
|
'title': _('Setup DHCP Server'),
|
||||||
'click': ui.createHandlerFn(this, function(section_id, ev) {
|
'click': ui.createHandlerFn(this, function(section_id, ev) {
|
||||||
this.map.save(function() {
|
this.map.save(function() {
|
||||||
uci.add('dhcp', 'dhcp', section_id);
|
uci.add('dhcp', 'dhcp', section_id);
|
||||||
|
@ -676,7 +659,7 @@ return view.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, ifc.getName())
|
}, ifc.getName())
|
||||||
}, _('Set up DHCP Server'))
|
}, _('Setup DHCP Server'))
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -822,14 +805,7 @@ return view.extend({
|
||||||
return flags.length ? flags : [ 'other-config' ];
|
return flags.length ? flags : [ 'other-config' ];
|
||||||
};
|
};
|
||||||
so.remove = function(section_id) {
|
so.remove = function(section_id) {
|
||||||
var existing = L.toArray(uci.get('dhcp', section_id, 'ra_flags'));
|
uci.set('dhcp', section_id, 'ra_flags', [ 'none' ]);
|
||||||
if (this.isActive(section_id)) {
|
|
||||||
if (existing.length != 1 || existing[0] != 'none')
|
|
||||||
uci.set('dhcp', section_id, 'ra_flags', [ 'none' ]);
|
|
||||||
}
|
|
||||||
else if (existing.length) {
|
|
||||||
uci.unset('dhcp', section_id, 'ra_flags');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
so = ss.taboption('ipv6-ra', form.Value, 'ra_maxinterval', _('Max <abbr title="Router Advertisement">RA</abbr> interval'), _('Maximum time allowed between sending unsolicited <abbr title="Router Advertisement, ICMPv6 Type 134">RA</abbr>. Default is 600 seconds.'));
|
so = ss.taboption('ipv6-ra', form.Value, 'ra_maxinterval', _('Max <abbr title="Router Advertisement">RA</abbr> interval'), _('Maximum time allowed between sending unsolicited <abbr title="Router Advertisement, ICMPv6 Type 134">RA</abbr>. Default is 600 seconds.'));
|
||||||
|
@ -859,17 +835,15 @@ return view.extend({
|
||||||
so.depends('ra', 'server');
|
so.depends('ra', 'server');
|
||||||
so.depends({ ra: 'hybrid', master: '0' });
|
so.depends({ ra: 'hybrid', master: '0' });
|
||||||
so.load = function(section_id) {
|
so.load = function(section_id) {
|
||||||
var dev = ifc.getL3Device(),
|
var dev = ifc.getL3Device();
|
||||||
path = dev ? "/proc/sys/net/ipv6/conf/%s/mtu".format(dev.getName()) : null;
|
|
||||||
|
|
||||||
return Promise.all([
|
if (dev) {
|
||||||
dev ? L.resolveDefault(fs.read(path), dev.getMTU()) : null,
|
var path = "/proc/sys/net/ipv6/conf/%s/mtu".format(dev.getName());
|
||||||
this.super('load', [section_id])
|
|
||||||
]).then(L.bind(function(res) {
|
|
||||||
this.placeholder = +res[0];
|
|
||||||
|
|
||||||
return res[1];
|
return L.resolveDefault(fs.read(path), dev.getMTU()).then(L.bind(function(data) {
|
||||||
}, this));
|
this.placeholder = data;
|
||||||
|
}, this));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
so = ss.taboption('ipv6-ra', form.Value, 'ra_hoplimit', _('<abbr title="Router Advertisement">RA</abbr> Hop Limit'), _('The maximum hops to be published in <abbr title="Router Advertisement">RA</abbr> messages. Maximum is 255 hops.'));
|
so = ss.taboption('ipv6-ra', form.Value, 'ra_hoplimit', _('<abbr title="Router Advertisement">RA</abbr> Hop Limit'), _('The maximum hops to be published in <abbr title="Router Advertisement">RA</abbr> messages. Maximum is 255 hops.'));
|
||||||
|
@ -878,17 +852,15 @@ return view.extend({
|
||||||
so.depends('ra', 'server');
|
so.depends('ra', 'server');
|
||||||
so.depends({ ra: 'hybrid', master: '0' });
|
so.depends({ ra: 'hybrid', master: '0' });
|
||||||
so.load = function(section_id) {
|
so.load = function(section_id) {
|
||||||
var dev = ifc.getL3Device(),
|
var dev = ifc.getL3Device();
|
||||||
path = dev ? "/proc/sys/net/ipv6/conf/%s/hop_limit".format(dev.getName()) : null;
|
|
||||||
|
|
||||||
return Promise.all([
|
if (dev) {
|
||||||
dev ? L.resolveDefault(fs.read(path), 64) : null,
|
var path = "/proc/sys/net/ipv6/conf/%s/hop_limit".format(dev.getName());
|
||||||
this.super('load', [section_id])
|
|
||||||
]).then(L.bind(function(res) {
|
|
||||||
this.placeholder = +res[0];
|
|
||||||
|
|
||||||
return res[1];
|
return L.resolveDefault(fs.read(path), 64).then(L.bind(function(data) {
|
||||||
}, this));
|
this.placeholder = data;
|
||||||
|
}, this));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -906,24 +878,18 @@ return view.extend({
|
||||||
so = ss.taboption('ipv6', form.DynamicList, 'dns', _('Announced IPv6 DNS servers'),
|
so = ss.taboption('ipv6', form.DynamicList, 'dns', _('Announced IPv6 DNS servers'),
|
||||||
_('Specifies a fixed list of IPv6 DNS server addresses to announce via DHCPv6. If left unspecified, the device will announce itself as IPv6 DNS server unless the <em>Local IPv6 DNS server</em> option is disabled.'));
|
_('Specifies a fixed list of IPv6 DNS server addresses to announce via DHCPv6. If left unspecified, the device will announce itself as IPv6 DNS server unless the <em>Local IPv6 DNS server</em> option is disabled.'));
|
||||||
so.datatype = 'ip6addr("nomask")'; /* restrict to IPv6 only for now since dnsmasq (DHCPv4) does not honour this option */
|
so.datatype = 'ip6addr("nomask")'; /* restrict to IPv6 only for now since dnsmasq (DHCPv4) does not honour this option */
|
||||||
so.depends('ra', 'server');
|
|
||||||
so.depends({ ra: 'hybrid', master: '0' });
|
|
||||||
so.depends('dhcpv6', 'server');
|
so.depends('dhcpv6', 'server');
|
||||||
so.depends({ dhcpv6: 'hybrid', master: '0' });
|
so.depends({ dhcpv6: 'hybrid', master: '0' });
|
||||||
|
|
||||||
so = ss.taboption('ipv6', form.Flag, 'dns_service', _('Local IPv6 DNS server'),
|
so = ss.taboption('ipv6', form.Flag, 'dns_service', _('Local IPv6 DNS server'),
|
||||||
_('Announce this device as IPv6 DNS server.'));
|
_('Announce this device as IPv6 DNS server.'));
|
||||||
so.default = so.enabled;
|
so.default = so.enabled;
|
||||||
so.depends({ ra: 'server', dns: /^$/ });
|
|
||||||
so.depends({ ra: 'hybrid', dns: /^$/, master: '0' });
|
|
||||||
so.depends({ dhcpv6: 'server', dns: /^$/ });
|
so.depends({ dhcpv6: 'server', dns: /^$/ });
|
||||||
so.depends({ dhcpv6: 'hybrid', dns: /^$/, master: '0' });
|
so.depends({ dhcpv6: 'hybrid', dns: /^$/, master: '0' });
|
||||||
|
|
||||||
so = ss.taboption('ipv6', form.DynamicList, 'domain', _('Announced DNS domains'),
|
so = ss.taboption('ipv6', form.DynamicList, 'domain', _('Announced DNS domains'),
|
||||||
_('Specifies a fixed list of DNS search domains to announce via DHCPv6. If left unspecified, the local device DNS search domain will be announced.'));
|
_('Specifies a fixed list of DNS search domains to announce via DHCPv6. If left unspecified, the local device DNS search domain will be announced.'));
|
||||||
so.datatype = 'hostname';
|
so.datatype = 'hostname';
|
||||||
so.depends('ra', 'server');
|
|
||||||
so.depends({ ra: 'hybrid', master: '0' });
|
|
||||||
so.depends('dhcpv6', 'server');
|
so.depends('dhcpv6', 'server');
|
||||||
so.depends({ dhcpv6: 'hybrid', master: '0' });
|
so.depends({ dhcpv6: 'hybrid', master: '0' });
|
||||||
|
|
||||||
|
@ -953,13 +919,13 @@ return view.extend({
|
||||||
o = nettools.replaceOption(s, 'advanced', form.Flag, 'defaultroute', _('Use default gateway'), _('If unchecked, no default route is configured'));
|
o = nettools.replaceOption(s, 'advanced', form.Flag, 'defaultroute', _('Use default gateway'), _('If unchecked, no default route is configured'));
|
||||||
o.default = o.enabled;
|
o.default = o.enabled;
|
||||||
|
|
||||||
if (has_peerdns(protoval)) {
|
if (protoval != 'static') {
|
||||||
o = nettools.replaceOption(s, 'advanced', form.Flag, 'peerdns', _('Use DNS servers advertised by peer'), _('If unchecked, the advertised DNS server addresses are ignored'));
|
o = nettools.replaceOption(s, 'advanced', form.Flag, 'peerdns', _('Use DNS servers advertised by peer'), _('If unchecked, the advertised DNS server addresses are ignored'));
|
||||||
o.default = o.enabled;
|
o.default = o.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
o = nettools.replaceOption(s, 'advanced', form.DynamicList, 'dns', _('Use custom DNS servers'));
|
o = nettools.replaceOption(s, 'advanced', form.DynamicList, 'dns', _('Use custom DNS servers'));
|
||||||
if (has_peerdns(protoval))
|
if (protoval != 'static')
|
||||||
o.depends('peerdns', '0');
|
o.depends('peerdns', '0');
|
||||||
o.datatype = 'ipaddr';
|
o.datatype = 'ipaddr';
|
||||||
|
|
||||||
|
@ -975,6 +941,17 @@ return view.extend({
|
||||||
o = nettools.replaceOption(s, 'advanced', form.Value, 'metric', _('Use gateway metric'));
|
o = nettools.replaceOption(s, 'advanced', form.Value, 'metric', _('Use gateway metric'));
|
||||||
o.datatype = 'uinteger';
|
o.datatype = 'uinteger';
|
||||||
o.placeholder = '0';
|
o.placeholder = '0';
|
||||||
|
|
||||||
|
o = nettools.replaceOption(s,'advanced', form.ListValue, 'multipath', _('Multipath setting'), _('Only one interface must be set as Master.'));
|
||||||
|
o.value('on',_('Enabled'));
|
||||||
|
o.value('off',_('Disabled'));
|
||||||
|
o.value('master',_('Master'));
|
||||||
|
o.value('backup',_('Backup'));
|
||||||
|
o.default = 'off';
|
||||||
|
|
||||||
|
o = nettools.replaceOption(s,'advanced', form.Value, 'addlatency', _('Additional latency'));
|
||||||
|
o.datatype = 'uinteger';
|
||||||
|
o.default = '0';
|
||||||
|
|
||||||
o = nettools.replaceOption(s, 'advanced', form.Value, 'ip4table', _('Override IPv4 routing table'));
|
o = nettools.replaceOption(s, 'advanced', form.Value, 'ip4table', _('Override IPv4 routing table'));
|
||||||
o.datatype = 'or(uinteger, string)';
|
o.datatype = 'or(uinteger, string)';
|
||||||
|
@ -984,12 +961,7 @@ return view.extend({
|
||||||
o = nettools.replaceOption(s, 'advanced', form.Value, 'ip6table', _('Override IPv6 routing table'));
|
o = nettools.replaceOption(s, 'advanced', form.Value, 'ip6table', _('Override IPv6 routing table'));
|
||||||
o.datatype = 'or(uinteger, string)';
|
o.datatype = 'or(uinteger, string)';
|
||||||
for (var i = 0; i < rtTables.length; i++)
|
for (var i = 0; i < rtTables.length; i++)
|
||||||
o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][1], rtTables[i][0]));
|
o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][0], rtTables[i][1]));
|
||||||
|
|
||||||
if (protoval == 'dhcpv6') {
|
|
||||||
o = nettools.replaceOption(s, 'advanced', form.Flag, 'sourcefilter', _('IPv6 source routing'), _('Automatically handle multiple uplink interfaces using source-based policy routing.'));
|
|
||||||
o.default = o.enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
o = nettools.replaceOption(s, 'advanced', form.Flag, 'delegate', _('Delegate IPv6 prefixes'), _('Enable downstream delegation of IPv6 prefixes available on this interface'));
|
o = nettools.replaceOption(s, 'advanced', form.Flag, 'delegate', _('Delegate IPv6 prefixes'), _('Enable downstream delegation of IPv6 prefixes available on this interface'));
|
||||||
o.default = o.enabled;
|
o.default = o.enabled;
|
||||||
|
@ -1108,7 +1080,7 @@ return view.extend({
|
||||||
proto, name, device;
|
proto, name, device;
|
||||||
|
|
||||||
protocols.sort(function(a, b) {
|
protocols.sort(function(a, b) {
|
||||||
return L.naturalCompare(a.getProtocol(), b.getProtocol());
|
return a.getProtocol() > b.getProtocol();
|
||||||
});
|
});
|
||||||
|
|
||||||
s2.render = function() {
|
s2.render = function() {
|
||||||
|
@ -1182,9 +1154,6 @@ return view.extend({
|
||||||
protoclass.addDevice(device.formvalue('_new_'));
|
protoclass.addDevice(device.formvalue('_new_'));
|
||||||
|
|
||||||
m.children[0].addedSection = section_id;
|
m.children[0].addedSection = section_id;
|
||||||
|
|
||||||
ui.hideModal();
|
|
||||||
ui.showModal(null, E('p', { 'class': 'spinning' }, [ _('Loading data…') ]));
|
|
||||||
}).then(L.bind(m.children[0].renderMoreOptionsModal, m.children[0], nameval));
|
}).then(L.bind(m.children[0].renderMoreOptionsModal, m.children[0], nameval));
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -1214,9 +1183,9 @@ return view.extend({
|
||||||
var node = E('div', { 'class': 'ifacebox' }, [
|
var node = E('div', { 'class': 'ifacebox' }, [
|
||||||
E('div', {
|
E('div', {
|
||||||
'class': 'ifacebox-head',
|
'class': 'ifacebox-head',
|
||||||
'style': firewall.getZoneColorStyle(zone),
|
'style': 'background-color:%s'.format(zone ? zone.getColor() : '#EEEEEE'),
|
||||||
'title': zone ? _('Part of zone %q').format(zone.getName()) : _('No zone assigned')
|
'title': zone ? _('Part of zone %q').format(zone.getName()) : _('No zone assigned')
|
||||||
}, E('strong', net.getName())),
|
}, E('strong', net.getName().toUpperCase())),
|
||||||
E('div', {
|
E('div', {
|
||||||
'class': 'ifacebox-body',
|
'class': 'ifacebox-body',
|
||||||
'id': '%s-ifc-devices'.format(section_id),
|
'id': '%s-ifc-devices'.format(section_id),
|
||||||
|
@ -1270,7 +1239,7 @@ return view.extend({
|
||||||
|
|
||||||
s.cfgsections = function() {
|
s.cfgsections = function() {
|
||||||
var sections = uci.sections('network', 'device'),
|
var sections = uci.sections('network', 'device'),
|
||||||
section_ids = sections.sort(function(a, b) { return L.naturalCompare(a.name, b.name) }).map(function(s) { return s['.name'] });
|
section_ids = sections.sort(function(a, b) { return a.name > b.name }).map(function(s) { return s['.name'] });
|
||||||
|
|
||||||
for (var i = 0; i < netDevs.length; i++) {
|
for (var i = 0; i < netDevs.length; i++) {
|
||||||
if (sections.filter(function(s) { return s.name == netDevs[i].getName() }).length)
|
if (sections.filter(function(s) { return s.name == netDevs[i].getName() }).length)
|
||||||
|
@ -1315,7 +1284,7 @@ return view.extend({
|
||||||
var trEl = this.super('renderRowActions', [ section_id, _('Configure…') ]),
|
var trEl = this.super('renderRowActions', [ section_id, _('Configure…') ]),
|
||||||
deleteBtn = trEl.querySelector('button:last-child');
|
deleteBtn = trEl.querySelector('button:last-child');
|
||||||
|
|
||||||
deleteBtn.firstChild.data = _('Unconfigure');
|
deleteBtn.firstChild.data = _('Reset');
|
||||||
deleteBtn.setAttribute('title', _('Remove related device settings from the configuration'));
|
deleteBtn.setAttribute('title', _('Remove related device settings from the configuration'));
|
||||||
deleteBtn.disabled = section_id.match(/^dev:/) ? true : null;
|
deleteBtn.disabled = section_id.match(/^dev:/) ? true : null;
|
||||||
|
|
||||||
|
@ -1348,26 +1317,9 @@ return view.extend({
|
||||||
for (var i = 0; i < map.addedVLANs.length; i++)
|
for (var i = 0; i < map.addedVLANs.length; i++)
|
||||||
uci.remove('network', map.addedVLANs[i]);
|
uci.remove('network', map.addedVLANs[i]);
|
||||||
|
|
||||||
if (this.addedSection)
|
|
||||||
uci.remove('network', this.addedSection);
|
|
||||||
|
|
||||||
return form.GridSection.prototype.handleModalCancel.apply(this, arguments);
|
return form.GridSection.prototype.handleModalCancel.apply(this, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
s.handleRemove = function(section_id /*, ... */) {
|
|
||||||
var name = uci.get('network', section_id, 'name'),
|
|
||||||
type = uci.get('network', section_id, 'type');
|
|
||||||
|
|
||||||
if (name != null && type == 'bridge') {
|
|
||||||
uci.sections('network', 'bridge-vlan', function(bvs) {
|
|
||||||
if (bvs.device == name)
|
|
||||||
uci.remove('network', bvs['.name']);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return form.GridSection.prototype.handleRemove.apply(this, arguments);
|
|
||||||
};
|
|
||||||
|
|
||||||
function getDevice(section_id) {
|
function getDevice(section_id) {
|
||||||
var m = section_id.match(/^dev:(.+)$/),
|
var m = section_id.match(/^dev:(.+)$/),
|
||||||
name = m ? m[1] : uci.get('network', section_id, 'name');
|
name = m ? m[1] : uci.get('network', section_id, 'name');
|
||||||
|
@ -1470,7 +1422,7 @@ return view.extend({
|
||||||
mac = dev ? dev.getMAC() : null;
|
mac = dev ? dev.getMAC() : null;
|
||||||
|
|
||||||
return val ? E('strong', {
|
return val ? E('strong', {
|
||||||
'data-tooltip': _('The value is overridden by configuration.')
|
'data-tooltip': _('The value is overridden by configuration. Original: %s').format(mac || _('unknown'))
|
||||||
}, [ val.toUpperCase() ]) : (mac || '-');
|
}, [ val.toUpperCase() ]) : (mac || '-');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1482,7 +1434,7 @@ return view.extend({
|
||||||
mtu = dev ? dev.getMTU() : null;
|
mtu = dev ? dev.getMTU() : null;
|
||||||
|
|
||||||
return val ? E('strong', {
|
return val ? E('strong', {
|
||||||
'data-tooltip': _('The value is overridden by configuration.')
|
'data-tooltip': _('The value is overridden by configuration. Original: %s').format(mtu || _('unknown'))
|
||||||
}, [ val ]) : (mtu || '-').toString();
|
}, [ val ]) : (mtu || '-').toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
230
luci-mod-network/htdocs/luci-static/resources/view/network/routes.js
Normal file → Executable file
230
luci-mod-network/htdocs/luci-static/resources/view/network/routes.js
Normal file → Executable file
|
@ -1,35 +1,22 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
'require view';
|
'require view';
|
||||||
'require fs';
|
|
||||||
'require uci';
|
|
||||||
'require form';
|
'require form';
|
||||||
'require network';
|
'require network';
|
||||||
'require tools.widgets as widgets';
|
'require tools.widgets as widgets';
|
||||||
|
|
||||||
return view.extend({
|
return view.extend({
|
||||||
load: function() {
|
load: function() {
|
||||||
return Promise.all([
|
return network.getDevices();
|
||||||
network.getDevices(),
|
|
||||||
fs.lines('/etc/iproute2/rt_tables')
|
|
||||||
]);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function(data) {
|
render: function(netdevs) {
|
||||||
var netDevs = data[0],
|
var m, s, o;
|
||||||
m, s, o;
|
|
||||||
|
|
||||||
var rtTables = data[1].map(function(l) {
|
m = new form.Map('network', _('Routes'), _('Routes specify over which interface and gateway a certain host or network can be reached.'));
|
||||||
var m = l.trim().match(/^(\d+)\s+(\S+)$/);
|
|
||||||
return m ? [ +m[1], m[2] ] : null;
|
|
||||||
}).filter(function(e) {
|
|
||||||
return e && e[0] > 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
m = new form.Map('network', _('Routing'), _('Routing defines over which interface and gateway a certain host or network can be reached.'));
|
|
||||||
m.tabbed = true;
|
m.tabbed = true;
|
||||||
|
|
||||||
for (var family = 4; family <= 6; family += 2) {
|
for (var i = 4; i <= 6; i += 2) {
|
||||||
s = m.section(form.GridSection, (family == 6) ? 'route6' : 'route', (family == 6) ? _('Static IPv6 Routes') : _('Static IPv4 Routes'));
|
s = m.section(form.GridSection, (i == 4) ? 'route' : 'route6', (i == 4) ? _('Static IPv4 Routes') : _('Static IPv6 Routes'));
|
||||||
s.anonymous = true;
|
s.anonymous = true;
|
||||||
s.addremove = true;
|
s.addremove = true;
|
||||||
s.sortable = true;
|
s.sortable = true;
|
||||||
|
@ -38,12 +25,44 @@ return view.extend({
|
||||||
s.tab('general', _('General Settings'));
|
s.tab('general', _('General Settings'));
|
||||||
s.tab('advanced', _('Advanced Settings'));
|
s.tab('advanced', _('Advanced Settings'));
|
||||||
|
|
||||||
o = s.taboption('general', widgets.NetworkSelect, 'interface', _('Interface'), _('Specifies the logical interface name of the parent (or master) interface this route belongs to'));
|
o = s.taboption('general', widgets.NetworkSelect, 'interface', _('Interface'));
|
||||||
o.loopback = true;
|
o.rmempty = false;
|
||||||
o.nocreate = true;
|
o.nocreate = true;
|
||||||
|
|
||||||
o = s.taboption('general', form.ListValue, 'type', _('Route type'), _('Specifies the route type to be created'));
|
o = s.taboption('general', form.Flag, 'disabled', _('Disable'), _('Disable this route'));
|
||||||
|
o.rmempty = true;
|
||||||
|
o.default = o.disabled;
|
||||||
|
|
||||||
|
o = s.taboption('general', form.Value, 'target', _('Target'), (i == 4) ? _('Host-<abbr title="Internet Protocol Address">IP</abbr> or Network') : _('<abbr title="Internet Protocol Version 6">IPv6</abbr>-Address or Network (CIDR)'));
|
||||||
|
o.datatype = (i == 4) ? 'ip4addr' : 'ip6addr';
|
||||||
|
o.rmempty = false;
|
||||||
|
|
||||||
|
if (i == 4) {
|
||||||
|
o = s.taboption('general', form.Value, 'netmask', _('<abbr title="Internet Protocol Version 4">IPv4</abbr>-Netmask'), _('if target is a network'));
|
||||||
|
o.placeholder = '255.255.255.255';
|
||||||
|
o.datatype = 'ip4addr';
|
||||||
|
o.rmempty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
o = s.taboption('general', form.Value, 'gateway', (i == 4) ? _('<abbr title="Internet Protocol Version 4">IPv4</abbr>-Gateway') : _('<abbr title="Internet Protocol Version 6">IPv6</abbr>-Gateway'));
|
||||||
|
o.datatype = (i == 4) ? 'ip4addr' : 'ip6addr';
|
||||||
|
o.rmempty = true;
|
||||||
|
|
||||||
|
o = s.taboption('advanced', form.Value, 'metric', _('Metric'));
|
||||||
|
o.placeholder = 0;
|
||||||
|
o.datatype = (i == 4) ? 'range(0,255)' : 'range(0,65535)';
|
||||||
|
o.rmempty = true;
|
||||||
|
o.textvalue = function(section_id) {
|
||||||
|
return this.cfgvalue(section_id) || 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
o = s.taboption('advanced', form.Value, 'mtu', _('MTU'));
|
||||||
|
o.placeholder = 1500;
|
||||||
|
o.datatype = 'range(64,9000)';
|
||||||
|
o.rmempty = true;
|
||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
|
|
||||||
|
o = s.taboption('advanced', form.ListValue, 'type', _('Route type'));
|
||||||
o.value('', 'unicast');
|
o.value('', 'unicast');
|
||||||
o.value('local');
|
o.value('local');
|
||||||
o.value('broadcast');
|
o.value('broadcast');
|
||||||
|
@ -52,155 +71,36 @@ return view.extend({
|
||||||
o.value('prohibit');
|
o.value('prohibit');
|
||||||
o.value('blackhole');
|
o.value('blackhole');
|
||||||
o.value('anycast');
|
o.value('anycast');
|
||||||
|
o.default = '';
|
||||||
|
o.rmempty = true;
|
||||||
|
o.modalonly = true;
|
||||||
|
|
||||||
o = s.taboption('general', form.Value, 'target', _('Target'), _('Network address'));
|
o = s.taboption('advanced', form.Value, 'table', _('Route table'));
|
||||||
o.rmempty = false;
|
o.value('local', 'local (255)');
|
||||||
o.datatype = (family == 6) ? 'cidr6' : 'cidr4';
|
o.value('main', 'main (254)');
|
||||||
o.placeholder = (family == 6) ? '::/0' : '0.0.0.0/0';
|
o.value('default', 'default (253)');
|
||||||
|
o.rmempty = true;
|
||||||
|
o.modalonly = true;
|
||||||
o.cfgvalue = function(section_id) {
|
o.cfgvalue = function(section_id) {
|
||||||
var section_type = uci.get('network', section_id, '.type'),
|
var cfgvalue = this.map.data.get('network', section_id, 'table');
|
||||||
target = uci.get('network', section_id, 'target'),
|
return cfgvalue || 'main';
|
||||||
mask = uci.get('network', section_id, 'netmask'),
|
};
|
||||||
v6 = (section_type == 'route6') ? true : false,
|
|
||||||
bits = mask ? network.maskToPrefix(mask, v6) : (v6 ? 128 : 32);
|
o = s.taboption('advanced', form.Value, 'source', _('Source Address'));
|
||||||
if (target) {
|
o.placeholder = E('em', _('automatic'));
|
||||||
return target.split('/')[1] ? target : target + '/' + bits;
|
for (var j = 0; j < netdevs.length; j++) {
|
||||||
}
|
var addrs = netdevs[j].getIPAddrs();
|
||||||
|
for (var k = 0; k < addrs.length; k++)
|
||||||
|
o.value(addrs[k].split('/')[0]);
|
||||||
}
|
}
|
||||||
o.write = function(section_id, formvalue) {
|
o.datatype = (i == 4) ? 'ip4addr' : 'ip6addr';
|
||||||
uci.set('network', section_id, 'target', formvalue);
|
o.default = '';
|
||||||
uci.unset('network', section_id, 'netmask');
|
o.rmempty = true;
|
||||||
}
|
|
||||||
|
|
||||||
o = s.taboption('general', form.Value, 'gateway', _('Gateway'), _('Specifies the network gateway. If omitted, the gateway from the parent interface is taken if any, otherwise creates a link scope route. If set to 0.0.0.0 no gateway will be specified for the route'));
|
|
||||||
o.datatype = (family == 6) ? 'ip6addr("nomask")' : 'ip4addr("nomask")';
|
|
||||||
o.placeholder = (family == 6) ? 'fe80::1' : '192.168.0.1';
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'metric', _('Metric'), _('Specifies the route metric to use'));
|
|
||||||
o.datatype = 'uinteger';
|
|
||||||
o.placeholder = 0;
|
|
||||||
o.textvalue = function(section_id) {
|
|
||||||
return this.cfgvalue(section_id) || 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'mtu', _('MTU'), _('Defines a specific MTU for this route'));
|
|
||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
o.datatype = 'and(uinteger,range(64,9000))';
|
|
||||||
o.placeholder = 1500;
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'table', _('Table'), _('The rule target is a table lookup ID: a numeric table index ranging from 0 to 65535 or symbol alias declared in /etc/iproute2/rt_tables. Special aliases local (255), main (254) and default (253) are also valid'));
|
o = s.taboption('advanced', form.Flag, 'onlink', _('On-Link route'));
|
||||||
o.datatype = 'or(uinteger, string)';
|
|
||||||
for (var i = 0; i < rtTables.length; i++)
|
|
||||||
o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][1], rtTables[i][0]));
|
|
||||||
o.textvalue = function(section_id) {
|
|
||||||
return this.cfgvalue(section_id) || 'main';
|
|
||||||
};
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'source', _('Source'), _('Specifies the preferred source address when sending to destinations covered by the target'));
|
|
||||||
o.modalonly = true;
|
|
||||||
o.datatype = (family == 6) ? 'ip6addr' : 'ip4addr';
|
|
||||||
o.placeholder = E('em', _('auto'));
|
|
||||||
for (var i = 0; i < netDevs.length; i++) {
|
|
||||||
var addrs = (family == 6) ? netDevs[i].getIP6Addrs() : netDevs[i].getIPAddrs();
|
|
||||||
for (var j = 0; j < addrs.length; j++)
|
|
||||||
o.value(addrs[j].split('/')[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'onlink', _('On-link'), _('When enabled, gateway is on-link even if the gateway does not match any interface prefix'));
|
|
||||||
o.modalonly = true;
|
|
||||||
o.default = o.disabled;
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'disabled', _('Disable'));
|
|
||||||
o.modalonly = false;
|
|
||||||
o.editable = true;
|
|
||||||
o.default = o.disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var family = 4; family <= 6; family += 2) {
|
|
||||||
s = m.section(form.GridSection, (family == 6) ? 'rule6' : 'rule', (family == 6) ? _('IPv6 Rules') : _('IPv4 Rules'));
|
|
||||||
s.anonymous = true;
|
|
||||||
s.addremove = true;
|
|
||||||
s.sortable = true;
|
|
||||||
s.nodescriptions = true;
|
|
||||||
|
|
||||||
s.tab('general', _('General Settings'));
|
|
||||||
s.tab('advanced', _('Advanced Settings'));
|
|
||||||
|
|
||||||
o = s.taboption('general', form.Value, 'priority', _('Priority'), _('Specifies the ordering of the IP rules'));
|
|
||||||
o.datatype = 'uinteger';
|
|
||||||
o.placeholder = 30000;
|
|
||||||
o.textvalue = function(section_id) {
|
|
||||||
return this.cfgvalue(section_id) || E('em', _('auto'));
|
|
||||||
};
|
|
||||||
|
|
||||||
o = s.taboption('general', form.ListValue, 'action', _('Rule type'), _('Specifies the rule target routing action'));
|
|
||||||
o.modalonly = true;
|
|
||||||
o.value('', 'unicast');
|
|
||||||
o.value('unreachable');
|
|
||||||
o.value('prohibit');
|
|
||||||
o.value('blackhole');
|
|
||||||
o.value('throw');
|
|
||||||
|
|
||||||
o = s.taboption('general', widgets.NetworkSelect, 'in', _('Incoming interface'), _('Specifies the incoming logical interface name'));
|
|
||||||
o.loopback = true;
|
|
||||||
o.nocreate = true;
|
|
||||||
|
|
||||||
o = s.taboption('general', form.Value, 'src', _('Source'), _('Specifies the source subnet to match (CIDR notation)'));
|
|
||||||
o.datatype = (family == 6) ? 'cidr6' : 'cidr4';
|
|
||||||
o.placeholder = (family == 6) ? '::/0' : '0.0.0.0/0';
|
|
||||||
o.textvalue = function(section_id) {
|
|
||||||
return this.cfgvalue(section_id) || E('em', _('any'));
|
|
||||||
};
|
|
||||||
|
|
||||||
o = s.taboption('general', widgets.NetworkSelect, 'out', _('Outgoing interface'), _('Specifies the outgoing logical interface name'));
|
|
||||||
o.loopback = true;
|
|
||||||
o.nocreate = true;
|
|
||||||
|
|
||||||
o = s.taboption('general', form.Value, 'dest', _('Destination'), _('Specifies the destination subnet to match (CIDR notation)'));
|
|
||||||
o.datatype = (family == 6) ? 'cidr6' : 'cidr4';
|
|
||||||
o.placeholder = (family == 6) ? '::/0' : '0.0.0.0/0';
|
|
||||||
o.textvalue = function(section_id) {
|
|
||||||
return this.cfgvalue(section_id) || E('em', _('any'));
|
|
||||||
};
|
|
||||||
|
|
||||||
o = s.taboption('general', form.Value, 'lookup', _('Table'), _('The rule target is a table lookup ID: a numeric table index ranging from 0 to 65535 or symbol alias declared in /etc/iproute2/rt_tables. Special aliases local (255), main (254) and default (253) are also valid'));
|
|
||||||
o.datatype = 'or(uinteger, string)';
|
|
||||||
for (var i = 0; i < rtTables.length; i++)
|
|
||||||
o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][1], rtTables[i][0]));
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'goto', _('Jump to rule'), _('The rule target is a jump to another rule specified by its priority value'));
|
|
||||||
o.modalonly = true;
|
|
||||||
o.datatype = 'uinteger';
|
|
||||||
o.placeholder = 80000;
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'mark', _('Firewall mark'), _('Specifies the fwmark and optionally its mask to match, e.g. 0xFF to match mark 255 or 0x0/0x1 to match any even mark value'));
|
|
||||||
o.modalonly = true;
|
|
||||||
o.datatype = 'string';
|
|
||||||
o.placeholder = '0x1/0xf';
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'tos', _('Type of service'), _('Specifies the TOS value to match in IP headers'));
|
|
||||||
o.modalonly = true;
|
|
||||||
o.datatype = 'uinteger';
|
|
||||||
o.placeholder = 10;
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'uidrange', _('User identifier'), _('Specifies an individual UID or range of UIDs to match, e.g. 1000 to match corresponding UID or 1000-1005 to inclusively match all UIDs within the corresponding range'));
|
|
||||||
o.modalonly = true;
|
|
||||||
o.datatype = 'string';
|
|
||||||
o.placeholder = '1000-1005';
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Value, 'suppress_prefixlength', _('Prefix suppressor'), _('Reject routing decisions that have a prefix length less than or equal to the specified value'));
|
|
||||||
o.modalonly = true;
|
|
||||||
o.datatype = (family == 6) ? 'ip6prefix' : 'ip4prefix';
|
|
||||||
o.placeholder = (family == 6) ? 64 : 24;
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'invert', _('Invert match'), _('If set, the meaning of the match options is inverted'));
|
|
||||||
o.modalonly = true;
|
|
||||||
o.default = o.disabled;
|
|
||||||
|
|
||||||
o = s.taboption('advanced', form.Flag, 'disabled', _('Disable'));
|
|
||||||
o.modalonly = false;
|
|
||||||
o.editable = true;
|
|
||||||
o.default = o.disabled;
|
o.default = o.disabled;
|
||||||
|
o.rmempty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.render();
|
return m.render();
|
||||||
|
|
26
luci-mod-network/htdocs/luci-static/resources/view/network/switch.js
Normal file → Executable file
26
luci-mod-network/htdocs/luci-static/resources/view/network/switch.js
Normal file → Executable file
|
@ -180,10 +180,8 @@ return view.extend({
|
||||||
s = m.section(form.NamedSection, sid, 'switch', switch_title);
|
s = m.section(form.NamedSection, sid, 'switch', switch_title);
|
||||||
s.addremove = false;
|
s.addremove = false;
|
||||||
|
|
||||||
if (feat.vlan_option) {
|
if (feat.vlan_option)
|
||||||
o = s.option(form.Flag, feat.vlan_option, _('Enable VLAN functionality'));
|
s.option(form.Flag, feat.vlan_option, _('Enable VLAN functionality'));
|
||||||
o.rmempty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (feat.learning_option) {
|
if (feat.learning_option) {
|
||||||
o = s.option(form.Flag, feat.learning_option, _('Enable learning and aging'));
|
o = s.option(form.Flag, feat.learning_option, _('Enable learning and aging'));
|
||||||
|
@ -224,7 +222,7 @@ return view.extend({
|
||||||
|
|
||||||
s.filter = function(section_id) {
|
s.filter = function(section_id) {
|
||||||
var device = uci.get('network', section_id, 'device');
|
var device = uci.get('network', section_id, 'device');
|
||||||
return (device == this.device);
|
return (device == switch_name);
|
||||||
};
|
};
|
||||||
|
|
||||||
s.cfgsections = function() {
|
s.cfgsections = function() {
|
||||||
|
@ -248,7 +246,7 @@ return view.extend({
|
||||||
max_vid = 0;
|
max_vid = 0;
|
||||||
|
|
||||||
for (var j = 0; j < sections.length; j++) {
|
for (var j = 0; j < sections.length; j++) {
|
||||||
if (sections[j].device != this.device)
|
if (sections[j].device != s.device)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var vlan = +sections[j].vlan,
|
var vlan = +sections[j].vlan,
|
||||||
|
@ -261,7 +259,7 @@ return view.extend({
|
||||||
max_vid = vid;
|
max_vid = vid;
|
||||||
}
|
}
|
||||||
|
|
||||||
uci.set('network', section_id, 'device', this.device);
|
uci.set('network', section_id, 'device', s.device);
|
||||||
uci.set('network', section_id, 'vlan', max_vlan + 1);
|
uci.set('network', section_id, 'vlan', max_vlan + 1);
|
||||||
|
|
||||||
if (feat.vid_option)
|
if (feat.vid_option)
|
||||||
|
@ -270,6 +268,8 @@ return view.extend({
|
||||||
return this.map.save(null, true);
|
return this.map.save(null, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var port_opts = [];
|
||||||
|
|
||||||
o = s.option(form.Value, feat.vid_option || 'vlan', 'VLAN ID');
|
o = s.option(form.Value, feat.vid_option || 'vlan', 'VLAN ID');
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
o.forcewrite = true;
|
o.forcewrite = true;
|
||||||
|
@ -297,23 +297,21 @@ return view.extend({
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
var port_opts = o.port_opts = [];
|
|
||||||
|
|
||||||
o.write = function(section_id, value) {
|
o.write = function(section_id, value) {
|
||||||
var topology = this.section.topology,
|
var topology = this.section.topology,
|
||||||
values = [];
|
values = [];
|
||||||
|
|
||||||
for (var i = 0; i < this.port_opts.length; i++) {
|
for (var i = 0; i < port_opts.length; i++) {
|
||||||
var tagging = this.port_opts[i].formvalue(section_id),
|
var tagging = port_opts[i].formvalue(section_id),
|
||||||
portspec = Array.isArray(topology.ports) ? topology.ports[i] : null;
|
portspec = Array.isArray(topology.ports) ? topology.ports[i] : null;
|
||||||
|
|
||||||
if (tagging == 't')
|
if (tagging == 't')
|
||||||
values.push(this.port_opts[i].option + tagging);
|
values.push(port_opts[i].option + tagging);
|
||||||
else if (tagging == 'u')
|
else if (tagging == 'u')
|
||||||
values.push(this.port_opts[i].option);
|
values.push(port_opts[i].option);
|
||||||
|
|
||||||
if (portspec && portspec.device) {
|
if (portspec && portspec.device) {
|
||||||
var old_tag = this.port_opts[i].cfgvalue(section_id),
|
var old_tag = port_opts[i].cfgvalue(section_id),
|
||||||
old_vid = this.cfgvalue(section_id);
|
old_vid = this.cfgvalue(section_id);
|
||||||
|
|
||||||
if (old_tag != tagging || old_vid != value) {
|
if (old_tag != tagging || old_vid != value) {
|
||||||
|
|
199
luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js
Normal file → Executable file
199
luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js
Normal file → Executable file
|
@ -314,15 +314,23 @@ var CBIWifiFrequencyValue = form.Value.extend({
|
||||||
this.channels = {
|
this.channels = {
|
||||||
'2g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', true ] : [],
|
'2g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', true ] : [],
|
||||||
'5g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', true ] : [],
|
'5g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', true ] : [],
|
||||||
'6g': L.hasSystemFeature('hostapd', 'acs') ? [ 'auto', 'auto', true ] : [],
|
'6g': [],
|
||||||
'60g': []
|
'60g': []
|
||||||
};
|
};
|
||||||
|
|
||||||
for (var i = 0; i < data[1].length; i++) {
|
for (var i = 0; i < data[1].length; i++) {
|
||||||
if (!data[1][i].band)
|
var band;
|
||||||
continue;
|
|
||||||
|
|
||||||
var band = '%dg'.format(data[1][i].band);
|
if (data[1][i].mhz >= 2412 && data[1][i].mhz <= 2484)
|
||||||
|
band = '2g';
|
||||||
|
else if (data[1][i].mhz >= 5160 && data[1][i].mhz <= 5885)
|
||||||
|
band = '5g';
|
||||||
|
else if (data[1][i].mhz >= 5925 && data[1][i].mhz <= 7125)
|
||||||
|
band = '6g';
|
||||||
|
else if (data[1][i].mhz >= 58329 && data[1][i].mhz <= 69120)
|
||||||
|
band = '60g';
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
this.channels[band].push(
|
this.channels[band].push(
|
||||||
data[1][i].channel,
|
data[1][i].channel,
|
||||||
|
@ -335,10 +343,10 @@ var CBIWifiFrequencyValue = form.Value.extend({
|
||||||
.reduce(function(o, v) { o[v] = true; return o }, {});
|
.reduce(function(o, v) { o[v] = true; return o }, {});
|
||||||
|
|
||||||
this.modes = [
|
this.modes = [
|
||||||
'', 'Legacy', hwmodelist.a || hwmodelist.b || hwmodelist.g,
|
'', 'Legacy', true,
|
||||||
'n', 'N', hwmodelist.n,
|
'n', 'N', hwmodelist.n,
|
||||||
'ac', 'AC', L.hasSystemFeature('hostapd', '11ac') && hwmodelist.ac,
|
'ac', 'AC', hwmodelist.ac,
|
||||||
'ax', 'AX', L.hasSystemFeature('hostapd', '11ax') && hwmodelist.ax
|
'ax', 'AX', hwmodelist.ax
|
||||||
];
|
];
|
||||||
|
|
||||||
var htmodelist = L.toArray(data[0] ? data[0].getHTModes() : null)
|
var htmodelist = L.toArray(data[0] ? data[0].getHTModes() : null)
|
||||||
|
@ -367,8 +375,7 @@ var CBIWifiFrequencyValue = form.Value.extend({
|
||||||
this.bands = {
|
this.bands = {
|
||||||
'': [
|
'': [
|
||||||
'2g', '2.4 GHz', this.channels['2g'].length > 3,
|
'2g', '2.4 GHz', this.channels['2g'].length > 3,
|
||||||
'5g', '5 GHz', this.channels['5g'].length > 3,
|
'5g', '5 GHz', this.channels['5g'].length > 3
|
||||||
'60g', '60 GHz', this.channels['60g'].length > 0
|
|
||||||
],
|
],
|
||||||
'n': [
|
'n': [
|
||||||
'2g', '2.4 GHz', this.channels['2g'].length > 3,
|
'2g', '2.4 GHz', this.channels['2g'].length > 3,
|
||||||
|
@ -379,8 +386,7 @@ var CBIWifiFrequencyValue = form.Value.extend({
|
||||||
],
|
],
|
||||||
'ax': [
|
'ax': [
|
||||||
'2g', '2.4 GHz', this.channels['2g'].length > 3,
|
'2g', '2.4 GHz', this.channels['2g'].length > 3,
|
||||||
'5g', '5 GHz', this.channels['5g'].length > 3,
|
'5g', '5 GHz', this.channels['5g'].length > 3
|
||||||
'6g', '6 GHz', this.channels['6g'].length > 3
|
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
}, this));
|
}, this));
|
||||||
|
@ -473,7 +479,7 @@ var CBIWifiFrequencyValue = form.Value.extend({
|
||||||
this.toggleWifiBand(elem);
|
this.toggleWifiBand(elem);
|
||||||
|
|
||||||
bwdt.value = htval;
|
bwdt.value = htval;
|
||||||
chan.value = chval || (chan.options[0] ? chan.options[0].value : 'auto');
|
chan.value = chval || chan.options[0].value;
|
||||||
|
|
||||||
return elem;
|
return elem;
|
||||||
},
|
},
|
||||||
|
@ -735,8 +741,7 @@ return view.extend({
|
||||||
load: function() {
|
load: function() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
uci.changes(),
|
uci.changes(),
|
||||||
uci.load('wireless'),
|
uci.load('wireless')
|
||||||
uci.load('system')
|
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -936,7 +941,7 @@ return view.extend({
|
||||||
|
|
||||||
if (hwtype == 'mac80211') {
|
if (hwtype == 'mac80211') {
|
||||||
o = ss.taboption('general', form.Flag, 'legacy_rates', _('Allow legacy 802.11b rates'), _('Legacy or badly behaving devices may require legacy 802.11b rates to interoperate. Airtime efficiency may be significantly reduced where these are used. It is recommended to not allow 802.11b rates where possible.'));
|
o = ss.taboption('general', form.Flag, 'legacy_rates', _('Allow legacy 802.11b rates'), _('Legacy or badly behaving devices may require legacy 802.11b rates to interoperate. Airtime efficiency may be significantly reduced where these are used. It is recommended to not allow 802.11b rates where possible.'));
|
||||||
o.depends({'_freq': '2g', '!contains': true});
|
o.depends({'_freq': '11g', '!contains': true});
|
||||||
|
|
||||||
o = ss.taboption('general', CBIWifiTxPowerValue, 'txpower', _('Maximum transmit power'), _('Specifies the maximum transmit power the wireless radio may use. Depending on regulatory requirements and wireless usage, the actual transmit power may be reduced by the driver.'));
|
o = ss.taboption('general', CBIWifiTxPowerValue, 'txpower', _('Maximum transmit power'), _('Specifies the maximum transmit power the wireless radio may use. Depending on regulatory requirements and wireless usage, the actual transmit power may be reduced by the driver.'));
|
||||||
o.wifiNetwork = radioNet;
|
o.wifiNetwork = radioNet;
|
||||||
|
@ -980,7 +985,6 @@ return view.extend({
|
||||||
ss.tab('encryption', _('Wireless Security'));
|
ss.tab('encryption', _('Wireless Security'));
|
||||||
ss.tab('macfilter', _('MAC-Filter'));
|
ss.tab('macfilter', _('MAC-Filter'));
|
||||||
ss.tab('advanced', _('Advanced Settings'));
|
ss.tab('advanced', _('Advanced Settings'));
|
||||||
ss.tab('roaming', _('WLAN roaming'), _('Settings for assisting wireless clients in roaming between multiple APs: 802.11r, 802.11k and 802.11v'));
|
|
||||||
|
|
||||||
o = ss.taboption('general', form.ListValue, 'mode', _('Mode'));
|
o = ss.taboption('general', form.ListValue, 'mode', _('Mode'));
|
||||||
o.value('ap', _('Access Point'));
|
o.value('ap', _('Access Point'));
|
||||||
|
@ -1085,7 +1089,6 @@ return view.extend({
|
||||||
|
|
||||||
o = ss.taboption('macfilter', form.DynamicList, 'maclist', _('MAC-List'));
|
o = ss.taboption('macfilter', form.DynamicList, 'maclist', _('MAC-List'));
|
||||||
o.datatype = 'macaddr';
|
o.datatype = 'macaddr';
|
||||||
o.retain = true;
|
|
||||||
o.depends('macfilter', 'allow');
|
o.depends('macfilter', 'allow');
|
||||||
o.depends('macfilter', 'deny');
|
o.depends('macfilter', 'deny');
|
||||||
o.load = function(section_id) {
|
o.load = function(section_id) {
|
||||||
|
@ -1141,27 +1144,16 @@ return view.extend({
|
||||||
o.depends('mode', 'ap-wds');
|
o.depends('mode', 'ap-wds');
|
||||||
o.default = o.enabled;
|
o.default = o.enabled;
|
||||||
|
|
||||||
/* https://w1.fi/cgit/hostap/commit/?id=34f7c699a6bcb5c45f82ceb6743354ad79296078 */
|
|
||||||
/* multicast_to_unicast https://github.com/openwrt/openwrt/commit/7babb978ad9d7fc29acb1ff86afb1eb343af303a */
|
|
||||||
o = ss.taboption('advanced', form.Flag, 'multicast_to_unicast', _('Multi To Unicast'), _('ARP, IPv4 and IPv6 (even 802.1Q) with multicast destination MACs are unicast to the STA MAC address. Note: This is not Directed Multicast Service (DMS) in 802.11v. Note: might break receiver STA multicast expectations.'));
|
|
||||||
o.rmempty = true;
|
|
||||||
|
|
||||||
o = ss.taboption('advanced', form.Flag, 'isolate', _('Isolate Clients'), _('Prevents client-to-client communication'));
|
o = ss.taboption('advanced', form.Flag, 'isolate', _('Isolate Clients'), _('Prevents client-to-client communication'));
|
||||||
o.depends('mode', 'ap');
|
o.depends('mode', 'ap');
|
||||||
o.depends('mode', 'ap-wds');
|
o.depends('mode', 'ap-wds');
|
||||||
|
|
||||||
o = ss.taboption('advanced', form.Value, 'ifname', _('Interface name'), _('Override default interface name'));
|
o = ss.taboption('advanced', form.Value, 'ifname', _('Interface name'), _('Override default interface name'));
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
o.datatype = 'netdevname';
|
|
||||||
o.placeholder = radioNet.getIfname();
|
o.placeholder = radioNet.getIfname();
|
||||||
if (/^radio\d+\.network/.test(o.placeholder))
|
if (/^radio\d+\.network/.test(o.placeholder))
|
||||||
o.placeholder = '';
|
o.placeholder = '';
|
||||||
|
|
||||||
o = ss.taboption('advanced', form.Value, 'macaddr', _('MAC address'), _('Override default MAC address - the range of usable addresses might be limited by the driver'));
|
|
||||||
o.optional = true;
|
|
||||||
o.placeholder = radioNet.getActiveBSSID();
|
|
||||||
o.datatype = 'macaddr';
|
|
||||||
|
|
||||||
o = ss.taboption('advanced', form.Flag, 'short_preamble', _('Short Preamble'));
|
o = ss.taboption('advanced', form.Flag, 'short_preamble', _('Short Preamble'));
|
||||||
o.default = o.enabled;
|
o.default = o.enabled;
|
||||||
|
|
||||||
|
@ -1179,7 +1171,7 @@ return view.extend({
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
o.datatype = 'uinteger';
|
o.datatype = 'uinteger';
|
||||||
|
|
||||||
o = ss.taboption('advanced', form.Value, 'max_inactivity', _('Station inactivity limit'), _('802.11v: BSS Max Idle. Units: seconds.'));
|
o = ss.taboption('advanced', form.Value, 'max_inactivity', _('Station inactivity limit'), _('sec'));
|
||||||
o.optional = true;
|
o.optional = true;
|
||||||
o.placeholder = 300;
|
o.placeholder = 300;
|
||||||
o.datatype = 'uinteger';
|
o.datatype = 'uinteger';
|
||||||
|
@ -1282,7 +1274,7 @@ return view.extend({
|
||||||
if (has_hostapd || has_supplicant) {
|
if (has_hostapd || has_supplicant) {
|
||||||
crypto_modes.push(['psk2', 'WPA2-PSK', 35]);
|
crypto_modes.push(['psk2', 'WPA2-PSK', 35]);
|
||||||
crypto_modes.push(['psk-mixed', 'WPA-PSK/WPA2-PSK Mixed Mode', 22]);
|
crypto_modes.push(['psk-mixed', 'WPA-PSK/WPA2-PSK Mixed Mode', 22]);
|
||||||
crypto_modes.push(['psk', 'WPA-PSK', 12]);
|
crypto_modes.push(['psk', 'WPA-PSK', 21]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
encr.description = _('WPA-Encryption requires wpa_supplicant (for client mode) or hostapd (for AP and ad-hoc mode) to be installed.');
|
encr.description = _('WPA-Encryption requires wpa_supplicant (for client mode) or hostapd (for AP and ad-hoc mode) to be installed.');
|
||||||
|
@ -1382,7 +1374,7 @@ return view.extend({
|
||||||
else if (hwtype == 'broadcom') {
|
else if (hwtype == 'broadcom') {
|
||||||
crypto_modes.push(['psk2', 'WPA2-PSK', 33]);
|
crypto_modes.push(['psk2', 'WPA2-PSK', 33]);
|
||||||
crypto_modes.push(['psk+psk2', 'WPA-PSK/WPA2-PSK Mixed Mode', 22]);
|
crypto_modes.push(['psk+psk2', 'WPA-PSK/WPA2-PSK Mixed Mode', 22]);
|
||||||
crypto_modes.push(['psk', 'WPA-PSK', 12]);
|
crypto_modes.push(['psk', 'WPA-PSK', 21]);
|
||||||
crypto_modes.push(['wep-open', _('WEP Open System'), 11]);
|
crypto_modes.push(['wep-open', _('WEP Open System'), 11]);
|
||||||
crypto_modes.push(['wep-shared', _('WEP Shared Key'), 10]);
|
crypto_modes.push(['wep-shared', _('WEP Shared Key'), 10]);
|
||||||
}
|
}
|
||||||
|
@ -1400,90 +1392,51 @@ return view.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, 'auth_server', _('RADIUS Authentication Server'));
|
o = ss.taboption('encryption', form.Value, 'auth_server', _('Radius-Authentication-Server'));
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.datatype = 'host(0)';
|
o.datatype = 'host(0)';
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, 'auth_port', _('RADIUS Authentication Port'));
|
o = ss.taboption('encryption', form.Value, 'auth_port', _('Radius-Authentication-Port'), _('Default %d').format(1812));
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.datatype = 'port';
|
o.datatype = 'port';
|
||||||
o.placeholder = '1812';
|
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, 'auth_secret', _('RADIUS Authentication Secret'));
|
o = ss.taboption('encryption', form.Value, 'auth_secret', _('Radius-Authentication-Secret'));
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.password = true;
|
o.password = true;
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, 'acct_server', _('RADIUS Accounting Server'));
|
o = ss.taboption('encryption', form.Value, 'acct_server', _('Radius-Accounting-Server'));
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.datatype = 'host(0)';
|
o.datatype = 'host(0)';
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, 'acct_port', _('RADIUS Accounting Port'));
|
o = ss.taboption('encryption', form.Value, 'acct_port', _('Radius-Accounting-Port'), _('Default %d').format(1813));
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.datatype = 'port';
|
o.datatype = 'port';
|
||||||
o.placeholder = '1813';
|
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, 'acct_secret', _('RADIUS Accounting Secret'));
|
o = ss.taboption('encryption', form.Value, 'acct_secret', _('Radius-Accounting-Secret'));
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.password = true;
|
o.password = true;
|
||||||
|
|
||||||
/* extra RADIUS settings start */
|
o = ss.taboption('encryption', form.Value, 'dae_client', _('DAE-Client'));
|
||||||
o = ss.taboption('encryption', form.ListValue, 'dynamic_vlan', _('RADIUS Dynamic VLAN Assignment'), _('Required: Rejects auth if RADIUS server does not provide appropriate VLAN attributes.'));
|
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
|
||||||
o.value('0', _('Disabled'));
|
|
||||||
o.value('1', _('Optional'));
|
|
||||||
o.value('2', _('Required'));
|
|
||||||
o.write = function (section_id, value) {
|
|
||||||
return this.super('write', [section_id, (value == 0) ? null: value]);
|
|
||||||
}
|
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Flag, 'per_sta_vif', _('RADIUS Per STA VLAN'), _('Each STA is assigned its own AP_VLAN interface.'));
|
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
|
||||||
|
|
||||||
//hostapd internally defaults to vlan_naming=1 even with dynamic VLAN off
|
|
||||||
o = ss.taboption('encryption', form.Flag, 'vlan_naming', _('RADIUS VLAN Naming'), _('Off: <code>vlanXXX</code>, e.g., <code>vlan1</code>. On: <code>vlan_tagged_interface.XXX</code>, e.g. <code>eth0.1</code>.'));
|
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
|
||||||
|
|
||||||
o = ss.taboption('encryption', widgets.DeviceSelect, 'vlan_tagged_interface', _('RADIUS VLAN Tagged Interface'), _('E.g. eth0, eth1'));
|
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
|
||||||
o.size = 1;
|
|
||||||
o.rmempty = true;
|
|
||||||
o.multiple = false;
|
|
||||||
o.noaliases = true;
|
|
||||||
o.nobridges = true;
|
|
||||||
o.nocreate = true;
|
|
||||||
o.noinactive = true;
|
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, 'vlan_bridge', _('RADIUS VLAN Bridge Naming Scheme'), _('E.g. <code>br-vlan</code> or <code>brvlan</code>.'));
|
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
|
||||||
o.rmempty = true;
|
|
||||||
/* extra RADIUS settings end */
|
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, 'dae_client', _('DAE-Client'), _('Dynamic Authorization Extension client.'));
|
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.datatype = 'host(0)';
|
o.datatype = 'host(0)';
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, 'dae_port', _('DAE-Port'), _('Dynamic Authorization Extension port.'));
|
o = ss.taboption('encryption', form.Value, 'dae_port', _('DAE-Port'), _('Default %d').format(3799));
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.datatype = 'port';
|
o.datatype = 'port';
|
||||||
o.placeholder = '3799';
|
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, 'dae_secret', _('DAE-Secret'), _('Dynamic Authorization Extension secret.'));
|
o = ss.taboption('encryption', form.Value, 'dae_secret', _('DAE-Secret'));
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.password = true;
|
o.password = true;
|
||||||
|
|
||||||
//WPA(1) has only WPA IE. Only >= WPA2 has RSN IE Preauth frames.
|
|
||||||
o = ss.taboption('encryption', form.Flag, 'rsn_preauth', _('RSN Preauth'), _('Robust Security Network (RSN): Allow roaming preauth for WPA2-EAP networks (and advertise it in WLAN beacons). Only works if the specified network interface is a bridge. Shortens the time-critical reassociation process.'));
|
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa2', 'wpa3', 'wpa3-mixed'] });
|
|
||||||
|
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, '_wpa_key', _('Key'));
|
o = ss.taboption('encryption', form.Value, '_wpa_key', _('Key'));
|
||||||
o.depends('encryption', 'psk');
|
o.depends('encryption', 'psk');
|
||||||
|
@ -1547,117 +1500,66 @@ return view.extend({
|
||||||
// Probe 802.11r support (and EAP support as a proxy for Openwrt)
|
// Probe 802.11r support (and EAP support as a proxy for Openwrt)
|
||||||
var has_80211r = L.hasSystemFeature('hostapd', '11r') || L.hasSystemFeature('hostapd', 'eap');
|
var has_80211r = L.hasSystemFeature('hostapd', '11r') || L.hasSystemFeature('hostapd', 'eap');
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Flag, 'ieee80211r', _('802.11r Fast Transition'), _('Enables fast roaming among access points that belong to the same Mobility Domain'));
|
o = ss.taboption('encryption', form.Flag, 'ieee80211r', _('802.11r Fast Transition'), _('Enables fast roaming among access points that belong to the same Mobility Domain'));
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
if (has_80211r)
|
if (has_80211r)
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['psk', 'psk2', 'psk-mixed', 'sae', 'sae-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['psk', 'psk2', 'psk-mixed', 'sae', 'sae-mixed'] });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Value, 'nasid', _('NAS ID'), _('Used for two different purposes: RADIUS NAS ID and 802.11r R0KH-ID. Not needed with normal WPA(2)-PSK.'));
|
o = ss.taboption('encryption', form.Value, 'nasid', _('NAS ID'), _('Used for two different purposes: RADIUS NAS ID and 802.11r R0KH-ID. Not needed with normal WPA(2)-PSK.'));
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['wpa', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
o.depends({ ieee80211r: '1' });
|
o.depends({ ieee80211r: '1' });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Value, 'mobility_domain', _('Mobility Domain'), _('4-character hexadecimal ID'));
|
o = ss.taboption('encryption', form.Value, 'mobility_domain', _('Mobility Domain'), _('4-character hexadecimal ID'));
|
||||||
o.depends({ ieee80211r: '1' });
|
o.depends({ ieee80211r: '1' });
|
||||||
o.placeholder = '4f57';
|
o.placeholder = '4f57';
|
||||||
o.datatype = 'and(hexstring,length(4))';
|
o.datatype = 'and(hexstring,length(4))';
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Value, 'reassociation_deadline', _('Reassociation Deadline'), _('time units (TUs / 1.024 ms) [1000-65535]'));
|
o = ss.taboption('encryption', form.Value, 'reassociation_deadline', _('Reassociation Deadline'), _('time units (TUs / 1.024 ms) [1000-65535]'));
|
||||||
o.depends({ ieee80211r: '1' });
|
o.depends({ ieee80211r: '1' });
|
||||||
o.placeholder = '1000';
|
o.placeholder = '1000';
|
||||||
o.datatype = 'range(1000,65535)';
|
o.datatype = 'range(1000,65535)';
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.ListValue, 'ft_over_ds', _('FT protocol'));
|
o = ss.taboption('encryption', form.ListValue, 'ft_over_ds', _('FT protocol'));
|
||||||
o.depends({ ieee80211r: '1' });
|
o.depends({ ieee80211r: '1' });
|
||||||
o.value('0', _('FT over the Air'));
|
|
||||||
o.value('1', _('FT over DS'));
|
o.value('1', _('FT over DS'));
|
||||||
|
o.value('0', _('FT over the Air'));
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Flag, 'ft_psk_generate_local', _('Generate PMK locally'), _('When using a PSK, the PMK can be automatically generated. When enabled, the R0/R1 key options below are not applied. Disable this to use the R0 and R1 key options.'));
|
o = ss.taboption('encryption', form.Flag, 'ft_psk_generate_local', _('Generate PMK locally'), _('When using a PSK, the PMK can be automatically generated. When enabled, the R0/R1 key options below are not applied. Disable this to use the R0 and R1 key options.'));
|
||||||
o.depends({ ieee80211r: '1' });
|
o.depends({ ieee80211r: '1' });
|
||||||
o.default = o.enabled;
|
o.default = o.enabled;
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Value, 'r0_key_lifetime', _('R0 Key Lifetime'), _('minutes'));
|
o = ss.taboption('encryption', form.Value, 'r0_key_lifetime', _('R0 Key Lifetime'), _('minutes'));
|
||||||
o.depends({ ieee80211r: '1' });
|
o.depends({ ieee80211r: '1' });
|
||||||
o.placeholder = '10000';
|
o.placeholder = '10000';
|
||||||
o.datatype = 'uinteger';
|
o.datatype = 'uinteger';
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Value, 'r1_key_holder', _('R1 Key Holder'), _('6-octet identifier as a hex string - no colons'));
|
o = ss.taboption('encryption', form.Value, 'r1_key_holder', _('R1 Key Holder'), _('6-octet identifier as a hex string - no colons'));
|
||||||
o.depends({ ieee80211r: '1' });
|
o.depends({ ieee80211r: '1' });
|
||||||
o.placeholder = '00004f577274';
|
o.placeholder = '00004f577274';
|
||||||
o.datatype = 'and(hexstring,length(12))';
|
o.datatype = 'and(hexstring,length(12))';
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Flag, 'pmk_r1_push', _('PMK R1 Push'));
|
o = ss.taboption('encryption', form.Flag, 'pmk_r1_push', _('PMK R1 Push'));
|
||||||
o.depends({ ieee80211r: '1' });
|
o.depends({ ieee80211r: '1' });
|
||||||
o.placeholder = '0';
|
o.placeholder = '0';
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.DynamicList, 'r0kh', _('External R0 Key Holder List'), _('List of R0KHs in the same Mobility Domain. <br />Format: MAC-address,NAS-Identifier,128-bit key as hex string. <br />This list is used to map R0KH-ID (NAS Identifier) to a destination MAC address when requesting PMK-R1 key from the R0KH that the STA used during the Initial Mobility Domain Association.'));
|
o = ss.taboption('encryption', form.DynamicList, 'r0kh', _('External R0 Key Holder List'), _('List of R0KHs in the same Mobility Domain. <br />Format: MAC-address,NAS-Identifier,128-bit key as hex string. <br />This list is used to map R0KH-ID (NAS Identifier) to a destination MAC address when requesting PMK-R1 key from the R0KH that the STA used during the Initial Mobility Domain Association.'));
|
||||||
o.depends({ ieee80211r: '1' });
|
o.depends({ ieee80211r: '1' });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.DynamicList, 'r1kh', _('External R1 Key Holder List'), _ ('List of R1KHs in the same Mobility Domain. <br />Format: MAC-address,R1KH-ID as 6 octets with colons,128-bit key as hex string. <br />This list is used to map R1KH-ID to a destination MAC address when sending PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD that can request PMK-R1 keys.'));
|
o = ss.taboption('encryption', form.DynamicList, 'r1kh', _('External R1 Key Holder List'), _ ('List of R1KHs in the same Mobility Domain. <br />Format: MAC-address,R1KH-ID as 6 octets with colons,128-bit key as hex string. <br />This list is used to map R1KH-ID to a destination MAC address when sending PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD that can request PMK-R1 keys.'));
|
||||||
o.depends({ ieee80211r: '1' });
|
o.depends({ ieee80211r: '1' });
|
||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
// End of 802.11r options
|
// End of 802.11r options
|
||||||
|
|
||||||
// Probe 802.11k and 802.11v support via EAP support (full hostapd has EAP)
|
|
||||||
if (L.hasSystemFeature('hostapd', 'eap')) {
|
|
||||||
/* 802.11k settings start */ o =
|
|
||||||
ss.taboption('roaming', form.Flag, 'ieee80211k', _('802.11k RRM'), _('Radio Resource Measurement - Sends beacons to assist roaming. Not all clients support this.'));
|
|
||||||
// add_dependency_permutations(o, { mode: ['ap', 'ap-wds'], encryption: ['psk', 'psk2', 'psk-mixed', 'sae', 'sae-mixed'] });
|
|
||||||
o.depends('mode', 'ap');
|
|
||||||
o.depends('mode', 'ap-wds');
|
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Flag, 'rrm_neighbor_report', _('Neighbour Report'), _('802.11k: Enable neighbor report via radio measurements.'));
|
|
||||||
o.depends({ ieee80211k: '1' });
|
|
||||||
o.default = o.enabled;
|
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Flag, 'rrm_beacon_report', _('Beacon Report'), _('802.11k: Enable beacon report via radio measurements.'));
|
|
||||||
o.depends({ ieee80211k: '1' });
|
|
||||||
o.default = o.enabled;
|
|
||||||
/* 802.11k settings end */
|
|
||||||
|
|
||||||
/* 802.11v settings start */
|
|
||||||
o = ss.taboption('roaming', form.ListValue, 'time_advertisement', _('Time advertisement'), _('802.11v: Time Advertisement in management frames.'));
|
|
||||||
o.value('0', _('Disabled'));
|
|
||||||
o.value('2', _('Enabled'));
|
|
||||||
o.write = function (section_id, value) {
|
|
||||||
return this.super('write', [section_id, (value == 2) ? value: null]);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Pull current System TZ setting
|
|
||||||
var tz = uci.get('system', '@system[0]', 'timezone');
|
|
||||||
o = ss.taboption('roaming', form.Value, 'time_zone', _('Time zone'), _('802.11v: Local Time Zone Advertisement in management frames.'));
|
|
||||||
o.value(tz);
|
|
||||||
o.rmempty = true;
|
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Flag, 'wnm_sleep_mode', _('WNM Sleep Mode'), _('802.11v: Wireless Network Management (WNM) Sleep Mode (extended sleep mode for stations).'));
|
|
||||||
o.rmempty = true;
|
|
||||||
|
|
||||||
/* wnm_sleep_mode_no_keys: https://git.openwrt.org/?p=openwrt/openwrt.git;a=commitdiff;h=bf98faaac8ed24cf7d3d93dd4fcd7304d109363b */
|
|
||||||
o = ss.taboption('roaming', form.Flag, 'wnm_sleep_mode_no_keys', _('WNM Sleep Mode Fixes'), _('802.11v: Wireless Network Management (WNM) Sleep Mode Fixes: Prevents reinstallation attacks.'));
|
|
||||||
o.rmempty = true;
|
|
||||||
|
|
||||||
o = ss.taboption('roaming', form.Flag, 'bss_transition', _('BSS Transition'), _('802.11v: Basic Service Set (BSS) transition management.'));
|
|
||||||
o.rmempty = true;
|
|
||||||
|
|
||||||
/* in master, but not 21.02.1: proxy_arp */
|
|
||||||
o = ss.taboption('roaming', form.Flag, 'proxy_arp', _('ProxyARP'), _('802.11v: Proxy ARP enables non-AP STA to remain in power-save for longer.'));
|
|
||||||
o.rmempty = true;
|
|
||||||
|
|
||||||
/* TODO: na_mcast_to_ucast is missing: needs adding to hostapd.sh - nice to have */
|
|
||||||
}
|
|
||||||
/* 802.11v settings end */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hwtype == 'mac80211') {
|
|
||||||
o = ss.taboption('encryption', form.ListValue, 'eap_type', _('EAP-Method'));
|
o = ss.taboption('encryption', form.ListValue, 'eap_type', _('EAP-Method'));
|
||||||
o.value('tls', 'TLS');
|
o.value('tls', 'TLS');
|
||||||
o.value('ttls', 'TTLS');
|
o.value('ttls', 'TTLS');
|
||||||
|
@ -1774,7 +1676,7 @@ return view.extend({
|
||||||
if (hwtype == 'mac80211') {
|
if (hwtype == 'mac80211') {
|
||||||
// ieee802.11w options
|
// ieee802.11w options
|
||||||
o = ss.taboption('encryption', form.ListValue, 'ieee80211w', _('802.11w Management Frame Protection'), _("Note: Some wireless drivers do not fully support 802.11w. E.g. mwlwifi may have problems"));
|
o = ss.taboption('encryption', form.ListValue, 'ieee80211w', _('802.11w Management Frame Protection'), _("Note: Some wireless drivers do not fully support 802.11w. E.g. mwlwifi may have problems"));
|
||||||
o.value('0', _('Disabled'));
|
o.value('', _('Disabled'));
|
||||||
o.value('1', _('Optional'));
|
o.value('1', _('Optional'));
|
||||||
o.value('2', _('Required'));
|
o.value('2', _('Required'));
|
||||||
add_dependency_permutations(o, { mode: ['ap', 'ap-wds', 'sta', 'sta-wds'], encryption: ['owe', 'psk2', 'psk-mixed', 'sae', 'sae-mixed', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
add_dependency_permutations(o, { mode: ['ap', 'ap-wds', 'sta', 'sta-wds'], encryption: ['owe', 'psk2', 'psk-mixed', 'sae', 'sae-mixed', 'wpa2', 'wpa3', 'wpa3-mixed'] });
|
||||||
|
@ -1782,14 +1684,7 @@ return view.extend({
|
||||||
o.defaults = {
|
o.defaults = {
|
||||||
'2': [{ encryption: 'sae' }, { encryption: 'owe' }, { encryption: 'wpa3' }, { encryption: 'wpa3-mixed' }],
|
'2': [{ encryption: 'sae' }, { encryption: 'owe' }, { encryption: 'wpa3' }, { encryption: 'wpa3-mixed' }],
|
||||||
'1': [{ encryption: 'sae-mixed'}],
|
'1': [{ encryption: 'sae-mixed'}],
|
||||||
'0': []
|
'': []
|
||||||
};
|
|
||||||
|
|
||||||
o.write = function(section_id, value) {
|
|
||||||
if (value != this.default)
|
|
||||||
return form.ListValue.prototype.write.call(this, section_id, value);
|
|
||||||
else
|
|
||||||
return form.ListValue.prototype.remove.call(this, section_id);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
o = ss.taboption('encryption', form.Value, 'ieee80211w_max_timeout', _('802.11w maximum timeout'), _('802.11w Association SA Query maximum timeout'));
|
o = ss.taboption('encryption', form.Value, 'ieee80211w_max_timeout', _('802.11w maximum timeout'), _('802.11w Association SA Query maximum timeout'));
|
||||||
|
@ -2061,8 +1956,6 @@ return view.extend({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).then(L.bind(function() {
|
}).then(L.bind(function() {
|
||||||
ui.showModal(null, E('p', { 'class': 'spinning' }, [ _('Loading data…') ]));
|
|
||||||
|
|
||||||
return this.renderMoreOptionsModal(section_id);
|
return this.renderMoreOptionsModal(section_id);
|
||||||
}, this));
|
}, this));
|
||||||
};
|
};
|
||||||
|
|
46
luci-mod-network/root/usr/share/luci/menu.d/luci-mod-network.json
Normal file → Executable file
46
luci-mod-network/root/usr/share/luci/menu.d/luci-mod-network.json
Normal file → Executable file
|
@ -46,9 +46,35 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"admin/network/routes": {
|
"admin/network/dhcp": {
|
||||||
"title": "Routing",
|
"title": "DHCP and DNS",
|
||||||
"order": 30,
|
"order": 30,
|
||||||
|
"action": {
|
||||||
|
"type": "view",
|
||||||
|
"path": "network/dhcp"
|
||||||
|
},
|
||||||
|
"depends": {
|
||||||
|
"acl": [ "luci-mod-network-dhcp" ],
|
||||||
|
"uci": { "dhcp": true }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"admin/network/hosts": {
|
||||||
|
"title": "Hostnames",
|
||||||
|
"order": 40,
|
||||||
|
"action": {
|
||||||
|
"type": "view",
|
||||||
|
"path": "network/hosts"
|
||||||
|
},
|
||||||
|
"depends": {
|
||||||
|
"acl": [ "luci-mod-network-dhcp" ],
|
||||||
|
"uci": { "dhcp": true }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"admin/network/routes": {
|
||||||
|
"title": "Static Routes",
|
||||||
|
"order": 50,
|
||||||
"action": {
|
"action": {
|
||||||
"type": "view",
|
"type": "view",
|
||||||
"path": "network/routes"
|
"path": "network/routes"
|
||||||
|
@ -58,23 +84,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"admin/network/dhcp": {
|
|
||||||
"title": "DHCP and DNS",
|
|
||||||
"order": 40,
|
|
||||||
"action": {
|
|
||||||
"type": "view",
|
|
||||||
"path": "network/dhcp"
|
|
||||||
},
|
|
||||||
"depends": {
|
|
||||||
"acl": [ "luci-mod-network-dhcp" ],
|
|
||||||
"fs": { "/usr/sbin/dnsmasq": "executable" },
|
|
||||||
"uci": { "dhcp": true }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"admin/network/diagnostics": {
|
"admin/network/diagnostics": {
|
||||||
"title": "Diagnostics",
|
"title": "Diagnostics",
|
||||||
"order": 50,
|
"order": 60,
|
||||||
"action": {
|
"action": {
|
||||||
"type": "view",
|
"type": "view",
|
||||||
"path": "network/diagnostics"
|
"path": "network/diagnostics"
|
||||||
|
|
7
luci-mod-network/root/usr/share/rpcd/acl.d/luci-mod-network.json
Normal file → Executable file
7
luci-mod-network/root/usr/share/rpcd/acl.d/luci-mod-network.json
Normal file → Executable file
|
@ -8,9 +8,7 @@
|
||||||
"/proc/sys/net/ipv6/conf/*/mtu": [ "read" ],
|
"/proc/sys/net/ipv6/conf/*/mtu": [ "read" ],
|
||||||
"/proc/sys/net/ipv6/conf/*/hop_limit": [ "read" ],
|
"/proc/sys/net/ipv6/conf/*/hop_limit": [ "read" ],
|
||||||
"/usr/libexec/luci-peeraddr": [ "exec" ],
|
"/usr/libexec/luci-peeraddr": [ "exec" ],
|
||||||
"/usr/lib/opkg/info/netifd.control": [ "read" ],
|
"/usr/lib/opkg/info/netifd.control": [ "read" ]
|
||||||
"/proc/sys/net/ipv[46]/conf/*": [ "read" ],
|
|
||||||
"/sys/class/net/*/brport/*": [ "read" ]
|
|
||||||
},
|
},
|
||||||
"ubus": {
|
"ubus": {
|
||||||
"file": [ "exec" ],
|
"file": [ "exec" ],
|
||||||
|
@ -60,8 +58,7 @@
|
||||||
"/usr/bin/ping": [ "exec" ],
|
"/usr/bin/ping": [ "exec" ],
|
||||||
"/usr/bin/ping6": [ "exec", "list" ],
|
"/usr/bin/ping6": [ "exec", "list" ],
|
||||||
"/usr/bin/traceroute": [ "exec" ],
|
"/usr/bin/traceroute": [ "exec" ],
|
||||||
"/usr/bin/traceroute6": [ "exec", "list" ],
|
"/usr/bin/traceroute6": [ "exec", "list" ]
|
||||||
"/usr/bin/arp-scan": [ "exec", "list" ]
|
|
||||||
},
|
},
|
||||||
"ubus": {
|
"ubus": {
|
||||||
"file": [ "exec", "stat" ]
|
"file": [ "exec", "stat" ]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue