184 lines
4.7 KiB
JavaScript
184 lines
4.7 KiB
JavaScript
'use strict';
|
|
'require form';
|
|
'require fs';
|
|
'require uci';
|
|
'require ui';
|
|
'require rpc';
|
|
'require poll';
|
|
'require view';
|
|
'require network';
|
|
'require tools.widgets as widgets';
|
|
|
|
const conf = 'einat';
|
|
const instance = 'einat';
|
|
|
|
const callServiceList = rpc.declare({
|
|
object: 'service',
|
|
method: 'list',
|
|
params: ['name'],
|
|
expect: { '': {} }
|
|
});
|
|
|
|
const callRcInit = rpc.declare({
|
|
object: 'rc',
|
|
method: 'init',
|
|
params: ['name', 'action']
|
|
});
|
|
|
|
const callGetFeatures = rpc.declare({
|
|
object: 'luci.einat',
|
|
method: 'get_features',
|
|
expect: { '': {} }
|
|
});
|
|
|
|
function getServiceStatus() {
|
|
return L.resolveDefault(callServiceList(conf), {})
|
|
.then((res) => {
|
|
let isrunning = false;
|
|
try {
|
|
isrunning = res[conf]['instances'][instance]['running'];
|
|
} catch (e) { }
|
|
return isrunning;
|
|
});
|
|
}
|
|
|
|
function handleAction(action, ev) {
|
|
return callRcInit("einat", action).then((ret) => {
|
|
if (ret)
|
|
throw _('Command failed');
|
|
|
|
return true;
|
|
}).catch((e) => {
|
|
ui.addNotification(null, E('p', _('Failed to execute "/etc/init.d/%s %s" action: %s').format("einat", action, e)));
|
|
});
|
|
}
|
|
|
|
return view.extend({
|
|
load() {
|
|
return Promise.all([
|
|
getServiceStatus(),
|
|
L.resolveDefault(fs.stat('/usr/bin/einat'), null),
|
|
callGetFeatures(),
|
|
uci.load('einat')
|
|
]);
|
|
},
|
|
|
|
poll_status(nodes, stat) {
|
|
const isRunning = stat[0];
|
|
let view = nodes.querySelector('#service_status');
|
|
|
|
if (isRunning) {
|
|
view.innerHTML = "<span style=\"color:green;font-weight:bold\">" + instance + " - " + _("SERVER RUNNING") + "</span>";
|
|
} else {
|
|
view.innerHTML = "<span style=\"color:red;font-weight:bold\">" + instance + " - " + _("SERVER NOT RUNNING") + "</span>";
|
|
}
|
|
return;
|
|
},
|
|
|
|
render(res) {
|
|
const isRunning = res[0];
|
|
const has_einat = res[1] ? res[1].path : null;
|
|
const features = res[2];
|
|
|
|
let m, s, o;
|
|
|
|
m = new form.Map('einat', _('einat-ebpf'), _('eBPF-based Endpoint-Independent NAT'));
|
|
|
|
s = m.section(form.NamedSection, '_status');
|
|
s.anonymous = true;
|
|
s.render = function(section_id) {
|
|
return E('div', { class: 'cbi-section' }, [
|
|
E('div', { id: 'service_status' }, _('Collecting data ...'))
|
|
]);
|
|
};
|
|
|
|
s = m.section(form.NamedSection, 'config', instance);
|
|
s.anonymous = true;
|
|
|
|
o = s.option(form.Button, '_reload', _('Reload'));
|
|
o.inputtitle = _('Reload');
|
|
o.inputstyle = 'apply';
|
|
o.onclick = function() {
|
|
return handleAction('reload');
|
|
};
|
|
|
|
o = s.option(form.Flag, 'enabled', _('Enable'));
|
|
o.default = o.disabled;
|
|
o.rmempty = false;
|
|
if (! has_einat) {
|
|
o.description = _('To enable you need install <b>einat-ebpf</b> first');
|
|
o.readonly = true;
|
|
}
|
|
|
|
o = s.option(form.ListValue, 'bpf_log_level', _('BPF tracing log level'));
|
|
o.default = '0';
|
|
o.value('0', 'disable - ' + _('Disable'));
|
|
o.value('1', 'error - ' + _('Error'));
|
|
o.value('2', 'warn - ' + _('Warn'));
|
|
o.value('3', 'info - ' + _('Info'));
|
|
o.value('4', 'debug - ' + _('Debug'));
|
|
o.value('5', 'trace - ' + _('Trace'));
|
|
|
|
o = s.option(form.ListValue, 'bpf_loader', _('BPF loading backend'));
|
|
o.value('', _('Default'));
|
|
if (features.features.includes('aya'))
|
|
o.value('aya', _('aya'));
|
|
if (features.features.includes('libbpf'))
|
|
o.value('libbpf', _('libbpf'));
|
|
|
|
o = s.option(form.Flag, 'nat44', _('NAT44'));
|
|
o.default = o.disabled;
|
|
o.rmempty = false;
|
|
|
|
//o = s.option(form.Flag, 'nat66', _('NAT66'));
|
|
//o.default = o.disabled;
|
|
//o.rmempty = false;
|
|
|
|
o = s.option(widgets.DeviceSelect, 'ifname', _('External interface'));
|
|
o.multiple = false;
|
|
o.noaliases = true;
|
|
o.nobridges = true;
|
|
o.nocreate = true;
|
|
|
|
o = s.option(form.Value, 'ports', _('External TCP/UDP port ranges'),
|
|
_('Please avoid conflicts with external ports used by other applications'));
|
|
o.datatype = 'portrange';
|
|
o.placeholder = '20000-29999';
|
|
o.rmempty = true;
|
|
|
|
o = s.option(widgets.NetworkSelect, 'internal_ifaces', _('Internal interfaces'),
|
|
_('Perform source NAT for these internal networks only.'));
|
|
o.multiple = true;
|
|
o.nocreate = true;
|
|
|
|
o = s.option(form.DynamicList, 'internal_subnets', _('Internal subnets'),
|
|
_('Perform source NAT for these internal networks only.'));
|
|
o.datatype = 'cidr';
|
|
o.placeholder = '192.168.0.0/16';
|
|
|
|
o = s.option(form.Flag, 'hairpin_enabled', _('Enable hairpin'),
|
|
_('May conflict with other policy routing-based applications'));
|
|
o.default = o.disabled;
|
|
o.rmempty = false;
|
|
|
|
o = s.option(widgets.DeviceSelect, 'hairpinif', _('Hairpin internal interfaces'));
|
|
o.multiple = true;
|
|
o.noaliases = true;
|
|
o.nobridges = false;
|
|
o.nocreate = true;
|
|
o.depends('hairpin_enabled', '1');
|
|
o.rmempty = true;
|
|
o.retain = true;
|
|
|
|
return m.render()
|
|
.then(L.bind(function(m, nodes) {
|
|
poll.add(L.bind(function() {
|
|
return Promise.all([
|
|
getServiceStatus()
|
|
]).then(L.bind(this.poll_status, this, nodes));
|
|
}, this), 3);
|
|
return nodes;
|
|
}, this, m));
|
|
}
|
|
});
|