parent
b93f2ac709
commit
1061f7eb38
@ -378,22 +378,23 @@ return view.extend({
|
|||||||
|
|
||||||
so = ss.option(form.ListValue, 'node', _('Node'),
|
so = ss.option(form.ListValue, 'node', _('Node'),
|
||||||
_('Outbound node'));
|
_('Outbound node'));
|
||||||
|
so.value('urltest', _('URLTest'));
|
||||||
for (var i in proxy_nodes)
|
for (var i in proxy_nodes)
|
||||||
so.value(i, proxy_nodes[i]);
|
so.value(i, proxy_nodes[i]);
|
||||||
so.validate = L.bind(hp.validateUniqueValue, this, data[0], 'routing_node', 'node');
|
|
||||||
so.editable = true;
|
so.editable = true;
|
||||||
|
|
||||||
so = ss.option(form.ListValue, 'domain_strategy', _('Domain strategy'),
|
so = ss.option(form.ListValue, 'domain_strategy', _('Domain strategy'),
|
||||||
_('If set, the server domain name will be resolved to IP before connecting.<br/>'));
|
_('If set, the server domain name will be resolved to IP before connecting.<br/>'));
|
||||||
for (var i in hp.dns_strategy)
|
for (var i in hp.dns_strategy)
|
||||||
so.value(i, hp.dns_strategy[i]);
|
so.value(i, hp.dns_strategy[i]);
|
||||||
|
so.depends({'node': 'urltest', '!reverse': true});
|
||||||
so.modalonly = true;
|
so.modalonly = true;
|
||||||
|
|
||||||
so = ss.option(widgets.DeviceSelect, 'bind_interface', _('Bind interface'),
|
so = ss.option(widgets.DeviceSelect, 'bind_interface', _('Bind interface'),
|
||||||
_('The network interface to bind to.'));
|
_('The network interface to bind to.'));
|
||||||
so.multiple = false;
|
so.multiple = false;
|
||||||
so.noaliases = true;
|
so.noaliases = true;
|
||||||
so.depends('outbound', '');
|
so.depends({'outbound': '', 'node': /^((?!urltest$).)+$/});
|
||||||
so.modalonly = true;
|
so.modalonly = true;
|
||||||
|
|
||||||
so = ss.option(form.ListValue, 'outbound', _('Outbound'),
|
so = ss.option(form.ListValue, 'outbound', _('Outbound'),
|
||||||
@ -416,9 +417,12 @@ return view.extend({
|
|||||||
|
|
||||||
var conflict = false;
|
var conflict = false;
|
||||||
uci.sections(data[0], 'routing_node', (res) => {
|
uci.sections(data[0], 'routing_node', (res) => {
|
||||||
if (res['.name'] !== section_id)
|
if (res['.name'] !== section_id) {
|
||||||
if (res.outbound === section_id && res['.name'] == value)
|
if (res.outbound === section_id && res['.name'] == value)
|
||||||
conflict = true;
|
conflict = true;
|
||||||
|
else if (res?.urltest_nodes?.includes(node) && res['.name'] == value)
|
||||||
|
conflict = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (conflict)
|
if (conflict)
|
||||||
return _('Recursive outbound detected!');
|
return _('Recursive outbound detected!');
|
||||||
@ -426,6 +430,66 @@ return view.extend({
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
so.depends({'node': 'urltest', '!reverse': true});
|
||||||
|
|
||||||
|
so = ss.option(hp.CBIStaticList, 'urltest_nodes', _('URLTest nodes'),
|
||||||
|
_('List of nodes to test.'));
|
||||||
|
for (var i in proxy_nodes)
|
||||||
|
so.value(i, proxy_nodes[i]);
|
||||||
|
so.depends('node', 'urltest');
|
||||||
|
so.modalonly = true;
|
||||||
|
|
||||||
|
so = ss.option(form.Value, 'urltest_url', _('Test URL'),
|
||||||
|
_('The URL to test. <code>https://www.gstatic.com/generate_204</code> will be used if empty.'));
|
||||||
|
so.validate = function(section_id, value) {
|
||||||
|
if (section_id && value) {
|
||||||
|
try {
|
||||||
|
var url = new URL(value);
|
||||||
|
if (!url.hostname)
|
||||||
|
return _('Expecting: %s').format(_('valid URL'));
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
return _('Expecting: %s').format(_('valid URL'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
so.depends('node', 'urltest');
|
||||||
|
so.modalonly = true;
|
||||||
|
|
||||||
|
so = ss.option(form.Value, 'urltest_interval', _('Test interval'),
|
||||||
|
_('The test interval in seconds. <code>180</code> will be used if empty.'));
|
||||||
|
so.datatype = 'uinteger';
|
||||||
|
so.validate = function(section_id, value) {
|
||||||
|
if (section_id && value) {
|
||||||
|
var idle_timeout = this.map.lookupOption('urltest_idle_timeout', section_id)[0].formvalue(section_id) || '1800';
|
||||||
|
if (parseInt(value) > parseInt(idle_timeout))
|
||||||
|
return _('Test interval must be less or equal than idle timeout.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
so.depends('node', 'urltest');
|
||||||
|
so.modalonly = true;
|
||||||
|
|
||||||
|
so = ss.option(form.Value, 'urltest_tolerance', _('Test tolerance'),
|
||||||
|
_('The test tolerance in milliseconds. <code>50</code> will be used if empty.'));
|
||||||
|
so.datatype = 'uinteger';
|
||||||
|
so.depends('node', 'urltest');
|
||||||
|
so.modalonly = true;
|
||||||
|
|
||||||
|
so = ss.option(form.Value, 'urltest_idle_timeout', _('Idle timeout'),
|
||||||
|
_('The idle timeout in seconds. <code>1800</code> will be used if empty.'));
|
||||||
|
so.datatype = 'uinteger';
|
||||||
|
so.depends('node', 'urltest');
|
||||||
|
so.modalonly = true;
|
||||||
|
|
||||||
|
so = ss.option(form.Flag, 'urltest_interrupt_exist_connections', _('Interrupt existing connections'),
|
||||||
|
_('Interrupt existing connections when the selected outbound has changed.'));
|
||||||
|
so.default = so.disabled;
|
||||||
|
so.depends('node', 'urltest');
|
||||||
|
so.modalonly = true;
|
||||||
/* Routing nodes end */
|
/* Routing nodes end */
|
||||||
|
|
||||||
/* Routing rules start */
|
/* Routing rules start */
|
||||||
@ -580,13 +644,12 @@ return view.extend({
|
|||||||
_('Match user name.'));
|
_('Match user name.'));
|
||||||
so.modalonly = true;
|
so.modalonly = true;
|
||||||
|
|
||||||
so = ss.taboption('field_other', form.MultiValue, 'rule_set', _('Rule set'),
|
so = ss.taboption('field_other', hp.CBIStaticList, 'rule_set', _('Rule set'),
|
||||||
_('Match rule set.'));
|
_('Match rule set.'));
|
||||||
so.load = function(section_id) {
|
so.load = function(section_id) {
|
||||||
delete this.keylist;
|
delete this.keylist;
|
||||||
delete this.vallist;
|
delete this.vallist;
|
||||||
|
|
||||||
this.value('', _('-- Please choose --'));
|
|
||||||
uci.sections(data[0], 'ruleset', (res) => {
|
uci.sections(data[0], 'ruleset', (res) => {
|
||||||
if (res.enabled === '1')
|
if (res.enabled === '1')
|
||||||
this.value(res['.name'], res.label);
|
this.value(res['.name'], res.label);
|
||||||
@ -920,13 +983,12 @@ return view.extend({
|
|||||||
_('Match user name.'));
|
_('Match user name.'));
|
||||||
so.modalonly = true;
|
so.modalonly = true;
|
||||||
|
|
||||||
so = ss.taboption('field_other', form.MultiValue, 'rule_set', _('Rule set'),
|
so = ss.taboption('field_other', hp.CBIStaticList, 'rule_set', _('Rule set'),
|
||||||
_('Match rule set.'));
|
_('Match rule set.'));
|
||||||
so.load = function(section_id) {
|
so.load = function(section_id) {
|
||||||
delete this.keylist;
|
delete this.keylist;
|
||||||
delete this.vallist;
|
delete this.vallist;
|
||||||
|
|
||||||
this.value('', _('-- Please choose --'));
|
|
||||||
uci.sections(data[0], 'ruleset', (res) => {
|
uci.sections(data[0], 'ruleset', (res) => {
|
||||||
if (res.enabled === '1')
|
if (res.enabled === '1')
|
||||||
this.value(res['.name'], res.label);
|
this.value(res['.name'], res.label);
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -300,6 +300,8 @@ function get_outbound(cfg) {
|
|||||||
const node = uci.get(uciconfig, cfg, 'node');
|
const node = uci.get(uciconfig, cfg, 'node');
|
||||||
if (isEmpty(node))
|
if (isEmpty(node))
|
||||||
die(sprintf("%s's node is missing, please check your configuration.", cfg));
|
die(sprintf("%s's node is missing, please check your configuration.", cfg));
|
||||||
|
else if (node === 'urltest')
|
||||||
|
return 'cfg-' + cfg + '-out';
|
||||||
else
|
else
|
||||||
return 'cfg-' + node + '-out';
|
return 'cfg-' + node + '-out';
|
||||||
}
|
}
|
||||||
@ -571,17 +573,39 @@ if (!isEmpty(main_node)) {
|
|||||||
push(config.outbounds, generate_outbound(main_udp_node_cfg));
|
push(config.outbounds, generate_outbound(main_udp_node_cfg));
|
||||||
config.outbounds[length(config.outbounds)-1].tag = 'main-udp-out';
|
config.outbounds[length(config.outbounds)-1].tag = 'main-udp-out';
|
||||||
}
|
}
|
||||||
} else if (!isEmpty(default_outbound))
|
} else if (!isEmpty(default_outbound)) {
|
||||||
|
let urltest_nodes = [],
|
||||||
|
routing_nodes = [];
|
||||||
|
|
||||||
uci.foreach(uciconfig, uciroutingnode, (cfg) => {
|
uci.foreach(uciconfig, uciroutingnode, (cfg) => {
|
||||||
if (cfg.enabled !== '1')
|
if (cfg.enabled !== '1')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const outbound = uci.get_all(uciconfig, cfg.node) || {};
|
if (cfg.node === 'urltest') {
|
||||||
push(config.outbounds, generate_outbound(outbound));
|
push(config.outbounds, {
|
||||||
config.outbounds[length(config.outbounds)-1].domain_strategy = cfg.domain_strategy;
|
type: 'urltest',
|
||||||
config.outbounds[length(config.outbounds)-1].bind_interface = cfg.bind_interface;
|
tag: 'cfg-' + cfg['.name'] + '-out',
|
||||||
config.outbounds[length(config.outbounds)-1].detour = get_outbound(cfg.outbound);
|
outbounds: map(cfg.urltest_nodes, (k) => `cfg-${k}-out`),
|
||||||
|
url: cfg.urltest_url,
|
||||||
|
interval: cfg.urltest_interval ? (cfg.urltest_interval + 's') : null,
|
||||||
|
tolerance: strToInt(cfg.urltest_tolerance),
|
||||||
|
idle_timeout: cfg.urltest_idle_timeout ? (cfg.urltest_idle_timeout + 's') : null,
|
||||||
|
interrupt_exist_connections: (cfg.urltest_interrupt_exist_connections === '1')
|
||||||
|
});
|
||||||
|
urltest_nodes = [...urltest_nodes, ...filter(cfg.urltest_nodes, ((l) => !~index(urltest_nodes, l)))];
|
||||||
|
} else {
|
||||||
|
const outbound = uci.get_all(uciconfig, cfg.node) || {};
|
||||||
|
push(config.outbounds, generate_outbound(outbound));
|
||||||
|
config.outbounds[length(config.outbounds)-1].domain_strategy = cfg.domain_strategy;
|
||||||
|
config.outbounds[length(config.outbounds)-1].bind_interface = cfg.bind_interface;
|
||||||
|
config.outbounds[length(config.outbounds)-1].detour = get_outbound(cfg.outbound);
|
||||||
|
push(routing_nodes, cfg.node);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (let i in filter(urltest_nodes, ((l) => !~index(routing_nodes, l))))
|
||||||
|
push(config.outbounds, generate_outbound(uci.get_all(uciconfig, i)));
|
||||||
|
}
|
||||||
/* Outbound end */
|
/* Outbound end */
|
||||||
|
|
||||||
/* Routing rules start */
|
/* Routing rules start */
|
||||||
@ -593,7 +617,6 @@ config.route = {
|
|||||||
outbound: 'dns-out'
|
outbound: 'dns-out'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
rule_set: [],
|
|
||||||
auto_detect_interface: isEmpty(default_interface) ? true : null,
|
auto_detect_interface: isEmpty(default_interface) ? true : null,
|
||||||
default_interface: default_interface
|
default_interface: default_interface
|
||||||
};
|
};
|
||||||
@ -654,6 +677,7 @@ if (!isEmpty(main_node)) {
|
|||||||
|
|
||||||
/* Rule set */
|
/* Rule set */
|
||||||
if (routing_mode === 'custom') {
|
if (routing_mode === 'custom') {
|
||||||
|
config.route.rule_set = [];
|
||||||
uci.foreach(uciconfig, uciruleset, (cfg) => {
|
uci.foreach(uciconfig, uciruleset, (cfg) => {
|
||||||
if (cfg.enabled !== '1')
|
if (cfg.enabled !== '1')
|
||||||
return null;
|
return null;
|
||||||
|
Loading…
Reference in New Issue
Block a user