Skip to content

Commit eb3d445

Browse files
committed
luci-mod-status: move getConntrackList from ubus to fs.exec
to prevent procd from being kicked off by ubusd due to large amounts of data. See openwrt/openwrt#9747 Fixes #6360 Signed-off-by: Liangbin Lian <jjm2473@gmail.com>
1 parent ba00517 commit eb3d445

3 files changed

Lines changed: 148 additions & 10 deletions

File tree

modules/luci-mod-status/htdocs/luci-static/resources/view/status/connections.js

Lines changed: 131 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,6 @@ const callLuciRealtimeStats = rpc.declare({
1212
expect: { result: [] }
1313
});
1414

15-
const callLuciConntrackList = rpc.declare({
16-
object: 'luci',
17-
method: 'getConntrackList',
18-
expect: { result: [] }
19-
});
20-
2115
const callNetworkRrdnsLookup = rpc.declare({
2216
object: 'network.rrdns',
2317
method: 'lookup',
@@ -56,10 +50,61 @@ const recheck_lookup_queue = {};
5650

5751
Math.log2 = Math.log2 || function(x) { return Math.log(x) * Math.LOG2E; };
5852

53+
/*
54+
* Convert an full IPv6 address string to a shortened format
55+
* Examples:
56+
[
57+
compressIpv6('2620:01ec:0029:0001:0000:0000:0000:0049') === '2620:1ec:29:1::49',
58+
compressIpv6('fe80:0000:0000:0000:d86d:2fff:fe24:f6ea') === 'fe80::d86d:2fff:fe24:f6ea',
59+
compressIpv6('fe80:0000:0000:0000:d86d:2fff:0000:f6ea') === 'fe80::d86d:2fff:0:f6ea',
60+
compressIpv6('fe80:0100:0010:0001:d86d:2fff:0000:f6ea') === 'fe80:100:10:1:d86d:2fff::f6ea',
61+
compressIpv6('fe80:0000:d86d:2fff:0000:0000:0000:f6ea') === 'fe80:0:d86d:2fff::f6ea',
62+
compressIpv6('ff02:0000:0000:0000:0000:0000:0001:0002') === 'ff02::1:2',
63+
compressIpv6('0000:0000:0000:0000:0000:0000:0000:0001') === '::1',
64+
compressIpv6('0000:0000:0000:0000:0000:0000:0000:0000') === '::',
65+
compressIpv6('0001:0000:0000:0000:0000:0000:0000:0000') === '1::',
66+
compressIpv6('0000:0001:0001:0001:0001:0001:0001:0001') === '::1:1:1:1:1:1:1',
67+
compressIpv6('0001:0000:0001:0001:0001:0001:0001:0001') === '1::1:1:1:1:1:1',
68+
compressIpv6('0001:0001:0001:0001:0001:0001:0001:0001') === '1:1:1:1:1:1:1:1',
69+
]
70+
*/
71+
const compressIpv6 = function(addr) {
72+
if (addr.indexOf(':') === -1)
73+
return addr;
74+
75+
const parts = addr.split(':');
76+
let best_start = 0, best_len = 0, cur_start = 0, cur_len = 0;
77+
for (let i = 0; i < parts.length; i++) {
78+
if (parts[i].startsWith('0'))
79+
parts[i] = parts[i].replace(/^0+/, '').replace(/^$/, '0');
80+
81+
if (parts[i] === '0') {
82+
if (cur_len === 0)
83+
cur_start = i;
84+
cur_len++;
85+
} else {
86+
if (cur_len > best_len) {
87+
best_start = cur_start;
88+
best_len = cur_len;
89+
}
90+
cur_len = 0;
91+
}
92+
}
93+
if (cur_len > best_len) {
94+
best_start = cur_start;
95+
best_len = cur_len;
96+
}
97+
if (best_len > 0) {
98+
parts.splice(best_start, best_len, '');
99+
}
100+
return (best_start===0&&best_len>0?':':'')+parts.join(':')+(best_start+best_len===8?':':'');
101+
};
102+
59103
return view.extend({
60104
load() {
61105
return Promise.all([
62-
this.loadSVG(L.resource('svg/connections.svg'))
106+
this.loadSVG(L.resource('svg/connections.svg')),
107+
fs.lines('/etc/protocols')
63108
]);
64109
},
65110

@@ -282,10 +327,79 @@ return view.extend({
282327
}
283328
},
284329

330+
/*
331+
* Replace the conntrack ubus call with a fs.exec_direct to prevent
332+
* procd from being kicked off by ubusd due to large amounts of data. See https://github.com/openwrt/openwrt/issues/9747
333+
*
334+
* Copy from modules/luci-base/ucode/sys.uc:conntrack_list with adjustments for js
335+
*/
336+
conntrackList: function() {
337+
const protos = this.protos;
338+
return fs.exec_direct('/usr/libexec/luci-status-call', ['conntrack']).then(function(data){
339+
const connt = [];
340+
341+
data.split('\n').forEach(function(line) {
342+
let m = line.match(/^(ipv[46]) +([0-9]+) +\S+ +([0-9]+)( +.+)$/);
343+
if (!m)
344+
return;
345+
346+
const fam = m[1];
347+
const l4 = m[3];
348+
let tuples = m[4];
349+
let timeout = null;
350+
351+
m = tuples.match(/^ +([0-9]+)( .+)$/);
352+
353+
if (m) {
354+
timeout = m[1];
355+
tuples = m[2];
356+
}
357+
358+
const e = {
359+
bytes: 0,
360+
packets: 0,
361+
layer3: fam,
362+
layer4: protos[l4] || 'unknown',
363+
timeout: +timeout
364+
};
365+
366+
tuples.split(' ').forEach(function(tuple) {
367+
const kv = tuple.match(/^(\w+)=(\S+)$/);
368+
369+
if (!kv)
370+
return;
371+
372+
switch (kv[1]) {
373+
case 'bytes':
374+
case 'packets':
375+
e[kv[1]] += +kv[2];
376+
break;
377+
378+
case 'src':
379+
case 'dst':
380+
if (undefined === e[kv[1]])
381+
e[kv[1]] = compressIpv6(kv[2]);
382+
break;
383+
384+
case 'sport':
385+
case 'dport':
386+
if (undefined === e[kv[1]])
387+
e[kv[1]] = +kv[2];
388+
break;
389+
}
390+
});
391+
392+
connt.push(e);
393+
});
394+
return connt;
395+
396+
});
397+
},
398+
285399
async pollData() {
286400
poll.add(L.bind(async function() {
287401
const tasks = [
288-
L.resolveDefault(callLuciConntrackList(), [])
402+
L.resolveDefault(this.conntrackList(), [])
289403
];
290404

291405
graphPolls.forEach(() => {
@@ -415,7 +529,15 @@ return view.extend({
415529
});
416530
},
417531

418-
render([svg]) {
532+
render([svg, protocols]) {
533+
const protos = {};
534+
protocols.forEach(function(line) {
535+
const m = line.match(/^([^# \t\n]+)\s+([0-9]+)\s+/);
536+
537+
if (m)
538+
protos[m[2]] = m[1];
539+
});
540+
this.protos = protos;
419541

420542
const v = E('div', { 'class': 'cbi-map', 'id': 'map' }, [
421543
E('h2', _('Connections')),
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/sh
2+
3+
action=$1
4+
shift
5+
6+
case "$action" in
7+
conntrack)
8+
if [[ -f /proc/net/nf_conntrack ]]; then
9+
/bin/grep -vF TIME_WAIT /proc/net/nf_conntrack
10+
elif [[ -x /usr/sbin/conntrack ]]; then
11+
/usr/sbin/conntrack -L -o extended | /bin/grep -vF TIME_WAIT
12+
fi
13+
;;
14+
esac

modules/luci-mod-status/root/usr/share/rpcd/acl.d/luci-mod-status.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
"description": "Grant access to realtime statistics",
44
"read": {
55
"file": {
6-
"/etc/services": [ "read" ]
6+
"/etc/protocols": [ "read" ],
7+
"/etc/services": [ "read" ],
8+
"/usr/libexec/luci-status-call": [ "exec" ]
79
},
810
"ubus": {
911
"luci": [ "getConntrackList", "getRealtimeStats" ],

0 commit comments

Comments
 (0)