mirror of
https://github.com/openwrt/packages.git
synced 2025-12-22 21:14:32 +04:00
`ubus.call(sprintf('network.interface.%s', ifname), 'status', {})`
returns null if the interface `ifname` doesn't exists (yet).
For pppoe interfaces using `option ipv6 auto`, a virtual interface suffixed `_6`
is automatically created once the connection is established,
but until then it doesn't exists.
Fixes: 6423781254 ("mwan3: reimplement rpcd plugin using ucode")
Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>
203 lines
4.8 KiB
Plaintext
203 lines
4.8 KiB
Plaintext
'use strict';
|
|
|
|
import { popen, readfile } from 'fs';
|
|
import { cursor } from 'uci';
|
|
|
|
const ubus = require('ubus').connect();
|
|
|
|
function get_str_raw(iface, property) {
|
|
return readfile(sprintf('/var/run/mwan3track/%s/%s', iface, property));
|
|
}
|
|
|
|
function get_str(iface, property) {
|
|
return rtrim(get_str_raw(iface, property), '\n');
|
|
}
|
|
|
|
function get_int(iface, property) {
|
|
return int(get_str(iface, property));
|
|
}
|
|
|
|
function get_uptime() {
|
|
return int(split(readfile('/proc/uptime'), '.', 2)[0]);
|
|
}
|
|
|
|
function get_x_time(uptime, iface, property) {
|
|
let t = get_int(iface, property);
|
|
if (t > 0) {
|
|
t = uptime - t;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
function ucibool(val) {
|
|
switch (val) {
|
|
case 'yes':
|
|
case 'on':
|
|
case 'true':
|
|
case 'enabled':
|
|
return true;
|
|
default:
|
|
return !!int(val);
|
|
}
|
|
}
|
|
|
|
function get_mwan3track_status(iface, uci_track_ips, procd) {
|
|
if (length(uci_track_ips) == 0) {
|
|
return 'disabled';
|
|
}
|
|
if (procd?.[sprintf('track_%s', iface)]?.running) {
|
|
const started = get_str(iface, 'STARTED');
|
|
switch (started) {
|
|
case '0':
|
|
return 'paused';
|
|
case '1':
|
|
return 'active';
|
|
default:
|
|
return 'down';
|
|
}
|
|
}
|
|
return 'down';
|
|
}
|
|
|
|
const connected_check_cmd = {
|
|
'4': 'iptables -t mangle -w -S mwan3_connected_ipv4',
|
|
'6': 'ip6tables -t mangle -w -S mwan3_connected_ipv6',
|
|
};
|
|
const ipset_save_re = regexp('^add mwan3_connected_ipv[46] (.*)\n$');
|
|
|
|
function get_connected_ips(version) {
|
|
const check = popen(connected_check_cmd[version], 'r');
|
|
check.read('all');
|
|
if (check.close() != 0) {
|
|
return [];
|
|
}
|
|
const ipset = popen(sprintf('ipset -o save list mwan3_connected_ipv%s', version), 'r');
|
|
const ips = [];
|
|
for (let line = ipset.read('line'); length(line); line = ipset.read('line')) {
|
|
const m = match(line, ipset_save_re);
|
|
if (length(m) == 2) {
|
|
push(ips, m[1]);
|
|
}
|
|
}
|
|
ipset.close();
|
|
return ips;
|
|
}
|
|
|
|
const policies_cmd = {
|
|
'4': 'iptables -t mangle -w -S',
|
|
'6': 'ip6tables -t mangle -w -S'
|
|
};
|
|
const policies_re = regexp('^-A mwan3_policy_([^ ]+) .*?--comment "([^"]+)"');
|
|
|
|
function get_policies(version) {
|
|
const ipt = popen(policies_cmd[version], 'r');
|
|
const policies = {};
|
|
for (let line = ipt.read('line'); length(line); line = ipt.read('line')) {
|
|
const m = match(line, policies_re);
|
|
if (m == null) {
|
|
continue;
|
|
}
|
|
const policy = m[1];
|
|
if (!exists(policies, policy)) {
|
|
policies[policy] = [];
|
|
}
|
|
const intfw = split(m[2], ' ', 3);
|
|
const weight = int(intfw[1]);
|
|
const total = int(intfw[2]);
|
|
if (weight >= 0 && total > 0) {
|
|
push(policies[policy], {
|
|
'interface': intfw[0],
|
|
'percent': weight / total * 100,
|
|
})
|
|
}
|
|
}
|
|
ipt.close();
|
|
return policies;
|
|
}
|
|
|
|
function interfaces_status(request) {
|
|
const uci = cursor();
|
|
const procd = ubus.call('service', 'list', { 'name': 'mwan3' })?.mwan3?.instances;
|
|
const interfaces = {};
|
|
uci.foreach('mwan3', 'interface', intf => {
|
|
const ifname = intf['.name'];
|
|
if (request.args.interface != null && request.args.interface != ifname) {
|
|
return;
|
|
}
|
|
const netstatus = ubus.call(sprintf('network.interface.%s', ifname), 'status', {});
|
|
const uptime = get_uptime();
|
|
const uci_track_ips = intf['track_ip'];
|
|
const track_status = get_mwan3track_status(ifname, uci_track_ips, procd);
|
|
const track_ips = [];
|
|
for (let ip in uci_track_ips) {
|
|
push(track_ips, {
|
|
'ip': ip,
|
|
'status': get_str(ifname, sprintf('TRACK_%s', ip)) || 'unknown',
|
|
'latency': get_int(ifname, sprintf('LATENCY_%s', ip)),
|
|
'packetloss': get_int(ifname, sprintf('LOSS_%s', ip)),
|
|
});
|
|
}
|
|
interfaces[ifname] = {
|
|
'age': get_x_time(uptime, ifname, 'TIME'),
|
|
'online': get_x_time(uptime, ifname, 'ONLINE'),
|
|
'offline': get_x_time(uptime, ifname, 'OFFLINE'),
|
|
'uptime': netstatus?.uptime || 0,
|
|
'score': get_int(ifname, 'SCORE'),
|
|
'lost': get_int(ifname, 'LOST'),
|
|
'turn': get_int(ifname, 'TURN'),
|
|
'status': get_str(ifname, 'STATUS') || 'unknown',
|
|
'enabled': ucibool(intf['enabled']),
|
|
'running': track_status == 'active',
|
|
'tracking': track_status,
|
|
'up': netstatus?.up || false,
|
|
'track_ip': track_ips,
|
|
};
|
|
});
|
|
return interfaces;
|
|
}
|
|
|
|
const methods = {
|
|
status: {
|
|
args: {
|
|
section: 'section',
|
|
interface: 'interface'
|
|
},
|
|
call: function (request) {
|
|
switch (request.args.section) {
|
|
case 'connected':
|
|
return {
|
|
'connected': {
|
|
'ipv4': get_connected_ips('4'),
|
|
'ipv6': get_connected_ips('6'),
|
|
},
|
|
};
|
|
case 'policies':
|
|
return {
|
|
'policies': {
|
|
'ipv4': get_policies('4'),
|
|
'ipv6': get_policies('6'),
|
|
},
|
|
};
|
|
case 'interfaces':
|
|
return {
|
|
'interfaces': interfaces_status(request),
|
|
};
|
|
default:
|
|
return {
|
|
'interfaces': interfaces_status(request),
|
|
'connected': {
|
|
'ipv4': get_connected_ips('4'),
|
|
'ipv6': get_connected_ips('6'),
|
|
},
|
|
'policies': {
|
|
'ipv4': get_policies('4'),
|
|
'ipv6': get_policies('6'),
|
|
},
|
|
};
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
return { 'mwan3': methods };
|