mirror of
https://github.com/padavanonly/immortalwrt-mt798x.git
synced 2025-12-16 16:56:38 +00:00
use wrtbwmon to replace rtbwmon
This commit is contained in:
parent
3aca68674b
commit
95998b024c
21
package/mtk/applications/luci-app-wrtbwmon/Makefile
Normal file
21
package/mtk/applications/luci-app-wrtbwmon/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
#
|
||||
# Copyright (C) 2020 xxx <xxx@xxx.com>
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-wrtbwmon
|
||||
PKG_VERSION:=2.0.13
|
||||
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
PKG_MAINTAINER:=
|
||||
|
||||
LUCI_TITLE:=A Luci module that uses wrtbwmon to track bandwidth usage
|
||||
LUCI_DEPENDS:=+wrtbwmon
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
'require form';
|
||||
'require rpc';
|
||||
'require view';
|
||||
|
||||
var callChangeDatabasePath = rpc.declare({
|
||||
object: 'luci.wrtbwmon',
|
||||
method: 'change_db_path',
|
||||
params: [ 'state' ]
|
||||
});
|
||||
|
||||
return view.extend({
|
||||
render: function() {
|
||||
var m, s, o;
|
||||
|
||||
m = new form.Map('wrtbwmon', _('Usage - Configuration'));
|
||||
|
||||
s = m.section(form.NamedSection, 'general', 'wrtbwmon', _('General settings'));
|
||||
s.addremove = false;
|
||||
|
||||
o = s.option(form.Flag, 'enabled', _('Keep running in the background'));
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.option(form.Value, 'path', _('Database path'), _('This box is used to select the Database path, which is /tmp/usage.db by default.'));
|
||||
o.value('/tmp/usage.db');
|
||||
o.value('/etc/usage.db');
|
||||
o.default = '/tmp/usage.db';
|
||||
o.rmempty = false;
|
||||
|
||||
return m.render();
|
||||
},
|
||||
|
||||
handleSaveApply: function(ev, mode) {
|
||||
return callChangeDatabasePath('before')
|
||||
.then(this.super.bind(this, 'handleSaveApply', arguments))
|
||||
.then(callChangeDatabasePath.bind(this, 'after'));
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,37 @@
|
||||
'use strict';
|
||||
'require fs';
|
||||
'require ui';
|
||||
'require view';
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return fs.trimmed('/etc/wrtbwmon.user').catch(function(err) {
|
||||
ui.addNotification(null, E('p', {}, _('Unable to load the customized hostname file: ' + err.message)));
|
||||
return '';
|
||||
});
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
return E('div', {'class': 'cbi-map'}, [
|
||||
E('h2', {'name': 'content'}, [ _('Usage - Custom User File') ]),
|
||||
E('div', {'class': 'cbi-map-descr'}, [
|
||||
_('Each line must have the following format:'),
|
||||
E('em', {'style': 'color:red'}, '00:aa:bb:cc:ee:ff,hostname')
|
||||
]),
|
||||
E('div', {'class': 'cbi-section'}, [
|
||||
E('textarea', {
|
||||
'id': 'custom_hosts',
|
||||
'style': 'width: 100%;padding: .5em;',
|
||||
'rows': 20
|
||||
}, data)
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
handleSave: function(ev) {
|
||||
var map = document.querySelector('#custom_hosts');
|
||||
return fs.write('/etc/wrtbwmon.user', map.value.trim().replace(/\r\n/g, '\n') + '\n');
|
||||
},
|
||||
handleSaveApply: null,
|
||||
handleReset: null
|
||||
});
|
||||
@ -0,0 +1,639 @@
|
||||
'use strict';
|
||||
'require dom';
|
||||
'require fs';
|
||||
'require poll';
|
||||
'require rpc';
|
||||
'require ui';
|
||||
'require validation';
|
||||
'require view';
|
||||
|
||||
var cachedData = [];
|
||||
var luciConfig = '/etc/luci-wrtbwmon.conf';
|
||||
var hostNameFile = '/etc/wrtbwmon.user';
|
||||
var columns = {
|
||||
thClient: _('Clients'),
|
||||
thMAC: _('MAC'),
|
||||
thDownload: _('Download'),
|
||||
thUpload: _('Upload'),
|
||||
thTotalDown: _('Total Down'),
|
||||
thTotalUp: _('Total Up'),
|
||||
thTotal: _('Total'),
|
||||
thFirstSeen: _('First Seen'),
|
||||
thLastSeen: _('Last Seen')
|
||||
};
|
||||
|
||||
var callLuciDHCPLeases = rpc.declare({
|
||||
object: 'luci-rpc',
|
||||
method: 'getDHCPLeases',
|
||||
expect: { '': {} }
|
||||
});
|
||||
|
||||
var callLuciDSLStatus = rpc.declare({
|
||||
object: 'luci-rpc',
|
||||
method: 'getDSLStatus',
|
||||
expect: { '': {} }
|
||||
});
|
||||
|
||||
var callGetDatabaseRaw = rpc.declare({
|
||||
object: 'luci.wrtbwmon',
|
||||
method: 'get_db_raw',
|
||||
params: [ 'protocol' ]
|
||||
});
|
||||
|
||||
var callGetDatabasePath = rpc.declare({
|
||||
object: 'luci.wrtbwmon',
|
||||
method: 'get_db_path',
|
||||
params: [ 'protocol' ]
|
||||
});
|
||||
|
||||
var callRemoveDatabase = rpc.declare({
|
||||
object: 'luci.wrtbwmon',
|
||||
method: 'remove_db',
|
||||
params: [ 'protocol' ]
|
||||
});
|
||||
|
||||
function $(tid) {
|
||||
return document.getElementById(tid);
|
||||
}
|
||||
|
||||
function clickToResetDatabase(settings, table, updated, updating, ev) {
|
||||
if (confirm(_('This will delete the database file. Are you sure?'))) {
|
||||
return callRemoveDatabase(settings.protocol)
|
||||
.then(function() {
|
||||
updateData(settings, table, updated, updating, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function clickToSaveConfig(keylist, cstrs) {
|
||||
var data = {};
|
||||
|
||||
for (var i = 0; i < keylist.length; i++) {
|
||||
data[keylist[i]] = cstrs[keylist[i]].getValue();
|
||||
}
|
||||
|
||||
ui.showModal(_('Configuration'), [
|
||||
E('p', { 'class': 'spinning' }, _('Saving configuration data...'))
|
||||
]);
|
||||
|
||||
return fs.write(luciConfig, JSON.stringify(data, undefined, '\t') + '\n')
|
||||
.catch(function(err) {
|
||||
ui.addNotification(null, E('p', {}, [ _('Unable to save %s: %s').format(luciConfig, err) ]));
|
||||
})
|
||||
.then(ui.hideModal)
|
||||
.then(function() { document.location.reload(); });
|
||||
}
|
||||
|
||||
function clickToSelectInterval(settings, updating, ev) {
|
||||
if (ev.target.value > 0) {
|
||||
settings.interval = parseInt(ev.target.value);
|
||||
if (!poll.active()) poll.start();
|
||||
}
|
||||
else {
|
||||
poll.stop();
|
||||
setUpdateMessage(updating, -1);
|
||||
}
|
||||
}
|
||||
|
||||
function clickToSelectProtocol(settings, table, updated, updating, ev) {
|
||||
settings.protocol = ev.target.value;
|
||||
updateData(settings, table, updated, updating, true);
|
||||
}
|
||||
|
||||
function createOption(args, val) {
|
||||
var cstr = args[0], title = args[1], desc = args.slice(-1), widget, frame;
|
||||
widget = args.length == 4 ? new cstr(val, args[2]) : new cstr(val, args[2], args[3]);
|
||||
|
||||
frame = E('div', {'class': 'cbi-value'}, [
|
||||
E('label', {'class': 'cbi-value-title'}, title),
|
||||
E('div', {'class': 'cbi-value-field'}, E('div', {}, widget.render()))
|
||||
]);
|
||||
|
||||
if (desc && desc != '')
|
||||
dom.append(frame.lastChild, E('div', { 'class': 'cbi-value-description' }, desc));
|
||||
|
||||
return [widget, frame];
|
||||
}
|
||||
|
||||
function displayTable(tb, settings) {
|
||||
var elm, elmID, col, sortedBy, flag, IPVer;
|
||||
|
||||
elm = tb.querySelector('.th.sorted');
|
||||
elmID = elm ? elm.id : 'thTotal';
|
||||
sortedBy = elm && elm.classList.contains('ascent') ? 'asc' : 'desc';
|
||||
|
||||
col = Object.keys(columns).indexOf(elmID);
|
||||
IPVer = col == 0 ? settings.protocol : null;
|
||||
flag = sortedBy == 'desc' ? 1 : -1;
|
||||
|
||||
cachedData[0].sort(sortTable.bind(this, col, IPVer, flag));
|
||||
|
||||
//console.time('show');
|
||||
updateTable(tb, cachedData, '<em>%s</em>'.format(_('Collecting data...')), settings);
|
||||
//console.timeEnd('show');
|
||||
progressbar('downstream', cachedData[1][0], settings.downstream, settings.useBits, settings.useMultiple);
|
||||
progressbar('upstream', cachedData[1][1], settings.upstream, settings.useBits, settings.useMultiple);
|
||||
}
|
||||
|
||||
function formatSize(size, useBits, useMultiple) {
|
||||
// String.format automatically adds the i for KiB if the multiple is 1024
|
||||
return String.format('%%%s.2m%s'.format(useMultiple, (useBits ? 'bit' : 'B')), useBits ? size * 8 : size);
|
||||
}
|
||||
|
||||
function formatSpeed(speed, useBits, useMultiple) {
|
||||
return formatSize(speed, useBits, useMultiple) + '/s';
|
||||
}
|
||||
|
||||
function formatDate(d) {
|
||||
var Y = d.getFullYear(), M = d.getMonth() + 1, D = d.getDate(),
|
||||
hh = d.getHours(), mm = d.getMinutes(), ss = d.getSeconds();
|
||||
return '%04d/%02d/%02d %02d:%02d:%02d'.format(Y, M, D, hh, mm, ss);
|
||||
}
|
||||
|
||||
function getDSLBandwidth() {
|
||||
return callLuciDSLStatus().then(function(res) {
|
||||
return {
|
||||
upstream : res.max_data_rate_up || null,
|
||||
downstream : res.max_data_rate_down || null
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function handleConfig(ev) {
|
||||
ui.showModal(_('Configuration'), [
|
||||
E('p', { 'class': 'spinning' }, _('Loading configuration data...'))
|
||||
]);
|
||||
|
||||
parseDefaultSettings(luciConfig)
|
||||
.then(function(settings) {
|
||||
var arglist, keylist = Object.keys(settings), res, cstrs = {}, node = [], body;
|
||||
|
||||
arglist = [
|
||||
[ui.Select, _('Default Protocol'), {'ipv4': _('ipv4'), 'ipv6': _('ipv6')}, {}, ''],
|
||||
[ui.Select, _('Default Refresh Interval'), {'-1': _('Disabled'), '2': _('2 seconds'), '5': _('5 seconds'), '10': _('10 seconds'), '30': _('30 seconds')}, {sort: ['-1', '2', '5', '10', '30']}, ''],
|
||||
[ui.Dropdown, _('Default Columns'), columns, {multiple: true, sort: false, custom_placeholder: '', dropdown_items: 3}, ''],
|
||||
[ui.Checkbox, _('Show Zeros'), {value_enabled: true, value_disabled: false}, ''],
|
||||
[ui.Checkbox, _('Transfer Speed in Bits'), {value_enabled: true, value_disabled: false}, ''],
|
||||
[ui.Select, _('Multiple of Unit'), {'1000': _('SI - 1000'), '1024': _('IEC - 1024')}, {}, ''],
|
||||
[ui.Checkbox, _('Use DSL Bandwidth'), {value_enabled: true, value_disabled: false}, ''],
|
||||
[ui.Textfield, _('Upstream Bandwidth'), {datatype: 'ufloat'}, 'Mbps'],
|
||||
[ui.Textfield, _('Downstream Bandwidth'), {datatype: 'ufloat'}, 'Mbps'],
|
||||
[ui.DynamicList, _('Hide MAC Addresses'), '', {datatype: 'macaddr'}, '']
|
||||
]; // [constructor, label(, all_choices), options, description]
|
||||
|
||||
for (var i = 0; i < keylist.length; i++) {
|
||||
res = createOption(arglist[i], settings[keylist[i]]);
|
||||
cstrs[keylist[i]] = res[0];
|
||||
node.push(res[1]);
|
||||
}
|
||||
|
||||
body = [
|
||||
E('p', {}, _('Configure the default values for luci-app-wrtbwmon.')),
|
||||
E('div', {}, node),
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('div', {
|
||||
'class': 'btn cbi-button-neutral',
|
||||
'click': ui.hideModal
|
||||
}, _('Cancel')),
|
||||
' ',
|
||||
E('div', {
|
||||
'class': 'btn cbi-button-positive',
|
||||
'click': clickToSaveConfig.bind(this, keylist, cstrs),
|
||||
'disabled': (L.hasViewPermission ? !L.hasViewPermission() : null) || null
|
||||
}, _('Save'))
|
||||
])
|
||||
];
|
||||
ui.showModal(_('Configuration'), body);
|
||||
})
|
||||
}
|
||||
|
||||
function loadCss(path) {
|
||||
var head = document.head || document.getElementsByTagName('head')[0];
|
||||
var link = E('link', {
|
||||
'rel': 'stylesheet',
|
||||
'href': path,
|
||||
'type': 'text/css'
|
||||
});
|
||||
|
||||
head.appendChild(link);
|
||||
}
|
||||
|
||||
function parseDatabase(raw, hosts, showZero, hideMACs) {
|
||||
var values = [],
|
||||
totals = [0, 0, 0, 0, 0],
|
||||
rows = raw.trim().split(/\r?\n|\r/g),
|
||||
rowIndex = [1, 0, 3, 4, 5, 6, 7, 8, 9, 0];
|
||||
|
||||
rows.shift();
|
||||
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var row = rows[i].split(',');
|
||||
if ((!showZero && row[7] == 0) || hideMACs.indexOf(row[0]) >= 0) continue;
|
||||
|
||||
for (var j = 0; j < totals.length; j++) {
|
||||
totals[j] += parseInt(row[3 + j]);
|
||||
}
|
||||
|
||||
var newRow = rowIndex.map(function(i) { return row[i] });
|
||||
if (newRow[1].toLowerCase() in hosts) {
|
||||
newRow[9] = hosts[newRow[1].toLowerCase()];
|
||||
}
|
||||
values.push(newRow);
|
||||
}
|
||||
|
||||
return [values, totals];
|
||||
}
|
||||
|
||||
function parseDefaultSettings(file) {
|
||||
var defaultColumns = ['thClient', 'thDownload', 'thUpload', 'thTotalDown', 'thTotalUp', 'thTotal'],
|
||||
keylist = ['protocol', 'interval', 'showColumns', 'showZero', 'useBits', 'useMultiple', 'useDSL', 'upstream', 'downstream', 'hideMACs'],
|
||||
valuelist = ['ipv4', '5', defaultColumns, true, false, '1000', false, '100', '100', []];
|
||||
|
||||
return fs.read_direct(file, 'json').then(function(oldSettings) {
|
||||
var settings = {};
|
||||
for (var i = 0; i < keylist.length; i++) {
|
||||
if (!(keylist[i] in oldSettings))
|
||||
settings[keylist[i]] = valuelist[i];
|
||||
else
|
||||
settings[keylist[i]] = oldSettings[keylist[i]];
|
||||
}
|
||||
|
||||
if (settings.useDSL) {
|
||||
return getDSLBandwidth().then(function(dsl) {
|
||||
for (var s in dsl)
|
||||
settings[s] = dsl[s];
|
||||
return settings;
|
||||
});
|
||||
}
|
||||
else {
|
||||
return settings;
|
||||
}
|
||||
})
|
||||
.catch(function() { return {} });
|
||||
}
|
||||
|
||||
function progressbar(query, v, m, useBits, useMultiple) {
|
||||
// v = B/s, m = Mb/s
|
||||
var pg = $(query),
|
||||
vn = (v * 8) || 0,
|
||||
mn = (m || 100) * Math.pow(1000, 2),
|
||||
fv = formatSpeed(v, useBits, useMultiple),
|
||||
pc = '%.2f'.format((100 / mn) * vn),
|
||||
wt = Math.floor(pc > 100 ? 100 : pc),
|
||||
bgc = (pc >= 95 ? 'red' : (pc >= 80 ? 'darkorange' : (pc >= 60 ? 'yellow' : 'lime')));
|
||||
if (pg) {
|
||||
pg.firstElementChild.style.width = wt + '%';
|
||||
pg.firstElementChild.style.background = bgc;
|
||||
pg.setAttribute('title', '%s (%f%%)'.format(fv, pc));
|
||||
}
|
||||
}
|
||||
|
||||
function setupThisDOM(settings, table) {
|
||||
document.addEventListener('poll-stop', function() {
|
||||
$('selectInterval').value = -1;
|
||||
});
|
||||
|
||||
document.addEventListener('poll-start', function() {
|
||||
$('selectInterval').value = settings.interval;
|
||||
});
|
||||
|
||||
table.querySelectorAll('.th').forEach(function(e) {
|
||||
if (e) {
|
||||
e.addEventListener('click', function (ev) {
|
||||
setSortedColumn(ev.target);
|
||||
displayTable(table, settings);
|
||||
});
|
||||
|
||||
if (settings.showColumns.indexOf(e.id) >= 0)
|
||||
e.classList.remove('hide');
|
||||
else
|
||||
e.classList.add('hide');
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renameFile(str, tag) {
|
||||
var n = str.lastIndexOf('/'), fn = n > -1 ? str.slice(n + 1) : str, dir = n > -1 ? str.slice(0, n + 1) : '';
|
||||
var n = fn.lastIndexOf('.'), bn = n > -1 ? fn.slice(0, n) : fn;
|
||||
var n = fn.lastIndexOf('.'), en = n > -1 ? fn.slice(n + 1) : '';
|
||||
return dir + bn + '.' + tag + (en ? '.' + en : '');
|
||||
}
|
||||
|
||||
function resolveCustomizedHostName() {
|
||||
return fs.stat(hostNameFile).then(function() {
|
||||
return fs.read_direct(hostNameFile).then(function(raw) {
|
||||
var arr = raw.trim().split(/\r?\n/), hosts = {}, row;
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
row = arr[i].split(',');
|
||||
if (row.length == 2 && row[0])
|
||||
hosts[row[0].toLowerCase()] = row[1];
|
||||
}
|
||||
return hosts;
|
||||
})
|
||||
})
|
||||
.catch(function() { return []; });
|
||||
}
|
||||
|
||||
function resolveHostNameByMACAddr() {
|
||||
return Promise.all([
|
||||
resolveCustomizedHostName(),
|
||||
callLuciDHCPLeases()
|
||||
]).then(function(res) {
|
||||
var hosts = res[0];
|
||||
for (var key in res[1]) {
|
||||
var leases = Array.isArray(res[1][key]) ? res[1][key] : [];
|
||||
for (var i = 0; i < leases.length; i++) {
|
||||
if(leases[i].macaddr) {
|
||||
var macaddr = leases[i].macaddr.toLowerCase();
|
||||
if (!(macaddr in hosts) && Boolean(leases[i].hostname))
|
||||
hosts[macaddr] = leases[i].hostname;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hosts;
|
||||
});
|
||||
}
|
||||
|
||||
function setSortedColumn(sorting) {
|
||||
var sorted = document.querySelector('.th.sorted') || $('thTotal');
|
||||
|
||||
if (sorting.isSameNode(sorted)) {
|
||||
sorting.classList.toggle('ascent');
|
||||
}
|
||||
else {
|
||||
sorting.classList.add('sorted');
|
||||
sorted.classList.remove('sorted', 'ascent');
|
||||
}
|
||||
}
|
||||
|
||||
function setUpdateMessage(e, sec) {
|
||||
e.innerHTML = sec < 0 ? '' : _('Updating again in %s second(s).').format('<b>' + sec + '</b>');
|
||||
}
|
||||
|
||||
function sortTable(col, IPVer, flag, x, y) {
|
||||
var byCol = x[col] == y[col] ? 1 : col;
|
||||
var a = x[byCol], b = y[byCol];
|
||||
|
||||
if (!IPVer || byCol != 0) {
|
||||
if (!(a.match(/\D/g) || b.match(/\D/g)))
|
||||
a = parseInt(a), b = parseInt(b);
|
||||
}
|
||||
else {
|
||||
IPVer == 'ipv4'
|
||||
? (a = validation.parseIPv4(a) || [0, 0, 0, 0], b = validation.parseIPv4(b) || [0, 0, 0, 0])
|
||||
: (a = validation.parseIPv6(a) || [0, 0, 0, 0, 0, 0, 0, 0], b = validation.parseIPv6(b) || [0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
}
|
||||
|
||||
if (Array.isArray(a) && Array.isArray(b)) {
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
if (a[i] != b[i]) {
|
||||
return (b[i] - a[i]) * flag;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return a == b ? 0 : (a < b ? 1 : -1) * flag;
|
||||
}
|
||||
|
||||
function updateData(settings, table, updated, updating, once) {
|
||||
var tick = poll.tick,
|
||||
interval = settings.interval,
|
||||
sec = (interval - tick % interval) % interval;
|
||||
if (!sec || once) {
|
||||
callGetDatabasePath()
|
||||
.then(function(res) {
|
||||
var params = settings.protocol == 'ipv4' ? '-4' : '-6';
|
||||
return fs.exec_direct('/usr/sbin/wrtbwmon', [params, '-f', res.file_4])
|
||||
})
|
||||
.then(function() {
|
||||
return Promise.all([
|
||||
callGetDatabaseRaw(settings.protocol),
|
||||
resolveHostNameByMACAddr()
|
||||
]);
|
||||
})
|
||||
.then(function(res) {
|
||||
//console.time('start');
|
||||
cachedData = parseDatabase(res[0].data || '', res[1], settings.showZero, settings.hideMACs);
|
||||
displayTable(table, settings);
|
||||
updated.textContent = _('Last updated at %s.').format(formatDate(new Date(document.lastModified)));
|
||||
//console.timeEnd('start');
|
||||
});
|
||||
}
|
||||
|
||||
setUpdateMessage(updating, sec);
|
||||
if (!sec)
|
||||
setTimeout(setUpdateMessage.bind(this, updating, interval), 100);
|
||||
}
|
||||
|
||||
function updateTable(tb, values, placeholder, settings) {
|
||||
var fragment = document.createDocumentFragment(), nodeLen = tb.childElementCount - 2;
|
||||
var formData = values[0], tbTitle = tb.firstElementChild, newNode, childTD;
|
||||
|
||||
// Update the table data.
|
||||
for (var i = 0; i < formData.length; i++) {
|
||||
if (i < nodeLen) {
|
||||
newNode = tbTitle.nextElementSibling;
|
||||
}
|
||||
else {
|
||||
if (nodeLen > 0) {
|
||||
newNode = fragment.firstChild.cloneNode(true);
|
||||
}
|
||||
else {
|
||||
newNode = document.createElement('tr');
|
||||
childTD = document.createElement('td');
|
||||
for (var j = 0; j < tbTitle.children.length; j++) {
|
||||
childTD.className = 'td' + (settings.showColumns.indexOf(tbTitle.children[j].id) >= 0 ? '' : ' hide');
|
||||
childTD.setAttribute('data-title', tbTitle.children[j].textContent);
|
||||
newNode.appendChild(childTD.cloneNode(true));
|
||||
}
|
||||
}
|
||||
newNode.className = 'tr cbi-rowstyle-%d'.format(i % 2 ? 2 : 1);
|
||||
}
|
||||
|
||||
childTD = newNode.firstElementChild;
|
||||
childTD.title = formData[i].slice(-1);
|
||||
for (var j = 0; j < tbTitle.childElementCount; j++, childTD = childTD.nextElementSibling) {
|
||||
switch (j) {
|
||||
case 2:
|
||||
case 3:
|
||||
childTD.textContent = formatSpeed(formData[i][j], settings.useBits, settings.useMultiple);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
childTD.textContent = formatSize(formData[i][j], settings.useBits, settings.useMultiple);
|
||||
break;
|
||||
case 7:
|
||||
case 8:
|
||||
childTD.textContent = formatDate(new Date(formData[i][j] * 1000));
|
||||
break;
|
||||
default:
|
||||
childTD.textContent = formData[i][j];
|
||||
}
|
||||
}
|
||||
fragment.appendChild(newNode);
|
||||
}
|
||||
|
||||
// Remove the table data which has been deleted from the database.
|
||||
while (tb.childElementCount > 1) {
|
||||
tb.removeChild(tbTitle.nextElementSibling);
|
||||
}
|
||||
|
||||
//Append the totals or placeholder row.
|
||||
if (formData.length == 0) {
|
||||
newNode = document.createElement('tr');
|
||||
newNode.className = 'tr placeholder';
|
||||
childTD = document.createElement('td');
|
||||
childTD.className = 'td';
|
||||
childTD.innerHTML = placeholder;
|
||||
newNode.appendChild(childTD);
|
||||
}
|
||||
else{
|
||||
newNode = fragment.firstChild.cloneNode(true);
|
||||
newNode.className = 'tr table-totals';
|
||||
|
||||
newNode.children[0].textContent = _('TOTAL') + (settings.showColumns.indexOf('thMAC') >= 0 ? '' : ': ' + formData.length);
|
||||
newNode.children[1].textContent = formData.length + ' ' + _('Clients');
|
||||
|
||||
for (var j = 0; j < tbTitle.childElementCount; j++) {
|
||||
switch(j) {
|
||||
case 0:
|
||||
case 1:
|
||||
newNode.children[j].removeAttribute('title');
|
||||
newNode.children[j].style.fontWeight = 'bold';
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
newNode.children[j].textContent = formatSpeed(values[1][j - 2], settings.useBits, settings.useMultiple);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
newNode.children[j].textContent = formatSize(values[1][j - 2], settings.useBits, settings.useMultiple);
|
||||
break;
|
||||
default:
|
||||
newNode.children[j].textContent = '';
|
||||
newNode.children[j].removeAttribute('data-title');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment.appendChild(newNode);
|
||||
tb.appendChild(fragment);
|
||||
}
|
||||
|
||||
function initOption(options, selected) {
|
||||
var res = [], attr = {};
|
||||
for (var idx in options) {
|
||||
attr.value = idx;
|
||||
attr.selected = idx == selected ? '' : null;
|
||||
res.push(E('option', attr, options[idx]));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
parseDefaultSettings(luciConfig),
|
||||
loadCss(L.resource('view/wrtbwmon/wrtbwmon.css'))
|
||||
]);
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var settings = data[0],
|
||||
labelUpdated = E('label'),
|
||||
labelUpdating = E('label'),
|
||||
table = E('table', { 'class': 'table', 'id': 'traffic' }, [
|
||||
E('tr', { 'class': 'tr table-titles' }, [
|
||||
E('th', { 'class': 'th', 'id': 'thClient' }, _('Clients')),
|
||||
E('th', { 'class': 'th hide', 'id': 'thMAC' }, _('MAC')),
|
||||
E('th', { 'class': 'th', 'id': 'thDownload' }, _('Download')),
|
||||
E('th', { 'class': 'th', 'id': 'thUpload' }, _('Upload')),
|
||||
E('th', { 'class': 'th', 'id': 'thTotalDown' }, _('Total Down')),
|
||||
E('th', { 'class': 'th', 'id': 'thTotalUp' }, _('Total Up')),
|
||||
E('th', { 'class': 'th sorted', 'id': 'thTotal' }, _('Total')),
|
||||
E('th', { 'class': 'th hide', 'id': 'thFirstSeen' }, _('First Seen')),
|
||||
E('th', { 'class': 'th hide', 'id': 'thLastSeen' }, _('Last Seen'))
|
||||
]),
|
||||
E('tr', {'class': 'tr placeholder'}, [
|
||||
E('td', { 'class': 'td' }, E('em', {}, _('Collecting data...')))
|
||||
])
|
||||
]);
|
||||
|
||||
poll.add(updateData.bind(this, settings, table, labelUpdated, labelUpdating, false), 1);
|
||||
setupThisDOM(settings, table);
|
||||
return E('div', { 'class': 'cbi-map' }, [
|
||||
E('h2', {}, _('Usage - Details')),
|
||||
E('div', { 'class': 'cbi-section' }, [
|
||||
E('div', { 'id': 'control_panel' }, [
|
||||
E('div', {}, [
|
||||
E('label', {}, _('Protocol:')),
|
||||
E('select', {
|
||||
'id': 'selectProtocol',
|
||||
'change': clickToSelectProtocol.bind(this, settings, table, labelUpdated, labelUpdating)
|
||||
}, initOption({
|
||||
'ipv4': 'ipv4',
|
||||
'ipv6': 'ipv6'
|
||||
}, settings.protocol))
|
||||
]),
|
||||
E('div', {}, [
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cbi-button-reset important',
|
||||
'id': 'resetDatabase',
|
||||
'click': clickToResetDatabase.bind(this, settings, table, labelUpdated, labelUpdating)
|
||||
}, _('Reset Database')),
|
||||
' ',
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cbi-button-neutral',
|
||||
'click': handleConfig
|
||||
}, _('Configure Options'))
|
||||
])
|
||||
]),
|
||||
E('div', {}, [
|
||||
E('div', {}, [ labelUpdated, labelUpdating ]),
|
||||
E('div', {}, [
|
||||
E('label', { 'for': 'selectInterval' }, _('Auto update every:')),
|
||||
E('select', {
|
||||
'id': 'selectInterval',
|
||||
'change': clickToSelectInterval.bind(this, settings, labelUpdating)
|
||||
}, initOption({
|
||||
'-1': _('Disabled'),
|
||||
'2': _('2 seconds'),
|
||||
'5': _('5 seconds'),
|
||||
'10': _('10 seconds'),
|
||||
'30': _('30 seconds')
|
||||
}, settings.interval))
|
||||
])
|
||||
]),
|
||||
E('div', { 'id': 'progressbar_panel' }, [
|
||||
E('div', {}, [
|
||||
E('label', {}, _('Downstream:')),
|
||||
E('div', {
|
||||
'id': 'downstream',
|
||||
'class': 'cbi-progressbar',
|
||||
'title': '-'
|
||||
}, E('div')
|
||||
)
|
||||
]),
|
||||
E('div', {}, [
|
||||
E('label', {}, _('Upstream:')),
|
||||
E('div', {
|
||||
'id': 'upstream',
|
||||
'class': 'cbi-progressbar',
|
||||
'title': '-'
|
||||
}, E('div')
|
||||
)
|
||||
]),
|
||||
]),
|
||||
table
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null
|
||||
});
|
||||
@ -0,0 +1,66 @@
|
||||
.th.sorted::after {
|
||||
content: '\25bc';
|
||||
}
|
||||
.th.sorted.ascent::after {
|
||||
content: '\25b2';
|
||||
}
|
||||
.hide {
|
||||
display: none !important;
|
||||
}
|
||||
#control_panel {
|
||||
display: flex;
|
||||
margin-bottom: 1rem;
|
||||
padding: .5rem;
|
||||
line-height: 2rem;
|
||||
}
|
||||
#control_panel > :nth-child(1) {
|
||||
display: inline-block;
|
||||
flex: 1 1 50%;
|
||||
}
|
||||
#control_panel > :nth-child(2) {
|
||||
flex: 1 1 50%;
|
||||
text-align: right;
|
||||
}
|
||||
#control_panel > * > * {
|
||||
vertical-align: middle;
|
||||
}
|
||||
#control_panel > div > label {
|
||||
margin-right: .5rem;
|
||||
}
|
||||
div > label + select {
|
||||
min-width: unset;
|
||||
width: auto;
|
||||
}
|
||||
#control_panel + div {
|
||||
display: flex;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
#control_panel + div > div:nth-of-type(1) {
|
||||
flex: 1 1 65%;
|
||||
}
|
||||
#control_panel + div > div:nth-of-type(2) {
|
||||
flex: 1 1 35%;
|
||||
text-align: right;
|
||||
}
|
||||
#thClient {
|
||||
width: 17%;
|
||||
}
|
||||
#thMAC {
|
||||
width: 10%;
|
||||
}
|
||||
#thDownload, #thUpload {
|
||||
width: 8%;
|
||||
}
|
||||
#thTotalDown, #thTotalUp, #thTotal {
|
||||
width: 9%;
|
||||
}
|
||||
#thFirstSeen, #thLastSeen {
|
||||
width: 15%;
|
||||
}
|
||||
.tr.table-totals {
|
||||
font-weight: bold;
|
||||
}
|
||||
#traffic .tr:not(.table-totals):not(.placeholder) > .td:not(.th):first-child::before {
|
||||
content: attr(title)'\a';
|
||||
white-space: pre-line;
|
||||
}
|
||||
@ -0,0 +1,259 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:611
|
||||
msgid "10 seconds"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:609
|
||||
msgid "2 seconds"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:612
|
||||
msgid "30 seconds"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:610
|
||||
msgid "5 seconds"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:603
|
||||
msgid "Auto update every:"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:201
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:14
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:503
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:556
|
||||
msgid "Clients"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:132
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:567
|
||||
msgid "Collecting data..."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:75
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:167
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:210
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:25
|
||||
msgid "Configuration"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:597
|
||||
msgid "Configure Options"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:195
|
||||
msgid "Configure the default values for luci-app-wrtbwmon."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:24
|
||||
msgid "Database path"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:178
|
||||
msgid "Default Columns"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:176
|
||||
msgid "Default Protocol"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
msgid "Default Refresh Interval"
|
||||
msgstr ""
|
||||
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:16
|
||||
msgid "Details"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:608
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:16
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:558
|
||||
msgid "Download"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:184
|
||||
msgid "Downstream Bandwidth"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:618
|
||||
msgid "Downstream:"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/custom.js:18
|
||||
msgid "Each line must have the following format:"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:21
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:563
|
||||
msgid "First Seen"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:18
|
||||
msgid "General settings"
|
||||
msgstr ""
|
||||
|
||||
#: root/usr/share/rpcd/acl.d/luci-app-wrtbwmon.json:3
|
||||
msgid "Grant access to LuCI app wrtbwmon"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:185
|
||||
msgid "Hide MAC Addresses"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:181
|
||||
msgid "IEC - 1024"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:21
|
||||
msgid "Keep running in the background"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:22
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:564
|
||||
msgid "Last Seen"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:425
|
||||
msgid "Last updated at %s."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:168
|
||||
msgid "Loading configuration data..."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:15
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:557
|
||||
msgid "MAC"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:181
|
||||
msgid "Multiple of Unit"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:578
|
||||
msgid "Protocol:"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:592
|
||||
msgid "Reset Database"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:181
|
||||
msgid "SI - 1000"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:207
|
||||
msgid "Save"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:76
|
||||
msgid "Saving configuration data..."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:179
|
||||
msgid "Show Zeros"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:502
|
||||
msgid "TOTAL"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:24
|
||||
msgid ""
|
||||
"This box is used to select the Database path, which is /tmp/usage.db by "
|
||||
"default."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:60
|
||||
msgid "This will delete the database file. Are you sure?"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:20
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:562
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:18
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:560
|
||||
msgid "Total Down"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:19
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:561
|
||||
msgid "Total Up"
|
||||
msgstr ""
|
||||
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:3
|
||||
msgid "Traffic Status"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:180
|
||||
msgid "Transfer Speed in Bits"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/custom.js:9
|
||||
msgid "Unable to load the customized hostname file:"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:81
|
||||
msgid "Unable to save %s: %s"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:376
|
||||
msgid "Updating again in %s second(s)."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:17
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:559
|
||||
msgid "Upload"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:183
|
||||
msgid "Upstream Bandwidth"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:627
|
||||
msgid "Upstream:"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:16
|
||||
msgid "Usage - Configuration"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/custom.js:16
|
||||
msgid "Usage - Custom User File"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:574
|
||||
msgid "Usage - Details"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:182
|
||||
msgid "Use DSL Bandwidth"
|
||||
msgstr ""
|
||||
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:34
|
||||
msgid "User file"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:176
|
||||
msgid "ipv4"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:176
|
||||
msgid "ipv6"
|
||||
msgstr ""
|
||||
@ -0,0 +1,265 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:611
|
||||
msgid "10 seconds"
|
||||
msgstr "10秒"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:609
|
||||
msgid "2 seconds"
|
||||
msgstr "2秒"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:612
|
||||
msgid "30 seconds"
|
||||
msgstr "30秒"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:610
|
||||
msgid "5 seconds"
|
||||
msgstr "5秒"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:603
|
||||
msgid "Auto update every:"
|
||||
msgstr "自动刷新:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:201
|
||||
msgid "Cancel"
|
||||
msgstr "取消"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:14
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:503
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:556
|
||||
msgid "Clients"
|
||||
msgstr "客户端"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:132
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:567
|
||||
msgid "Collecting data..."
|
||||
msgstr "收集数据中..."
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:75
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:167
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:210
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:25
|
||||
msgid "Configuration"
|
||||
msgstr "配置"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:597
|
||||
msgid "Configure Options"
|
||||
msgstr "配置选项"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:195
|
||||
msgid "Configure the default values for luci-app-wrtbwmon."
|
||||
msgstr "配置luci-app-wrtbwmon的默认值。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:24
|
||||
msgid "Database path"
|
||||
msgstr "数据路径"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:178
|
||||
msgid "Default Columns"
|
||||
msgstr "默认显示的列"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:176
|
||||
msgid "Default Protocol"
|
||||
msgstr "默认协议"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
msgid "Default Refresh Interval"
|
||||
msgstr "默认刷新间隔"
|
||||
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:16
|
||||
msgid "Details"
|
||||
msgstr "流量信息"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:608
|
||||
msgid "Disabled"
|
||||
msgstr "禁用"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:16
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:558
|
||||
msgid "Download"
|
||||
msgstr "下载"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:184
|
||||
msgid "Downstream Bandwidth"
|
||||
msgstr "下行带宽"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:618
|
||||
msgid "Downstream:"
|
||||
msgstr "下行:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/custom.js:18
|
||||
msgid "Each line must have the following format:"
|
||||
msgstr "每行需要满足以下格式:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:21
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:563
|
||||
msgid "First Seen"
|
||||
msgstr "初次记录"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:18
|
||||
msgid "General settings"
|
||||
msgstr "通用设置"
|
||||
|
||||
#: root/usr/share/rpcd/acl.d/luci-app-wrtbwmon.json:3
|
||||
msgid "Grant access to LuCI app wrtbwmon"
|
||||
msgstr "授予访问LuCI应用程序wrtbwmon的权限"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:185
|
||||
msgid "Hide MAC Addresses"
|
||||
msgstr "隐藏MAC地址"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:181
|
||||
msgid "IEC - 1024"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:21
|
||||
msgid "Keep running in the background"
|
||||
msgstr "保持后台运行"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:22
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:564
|
||||
msgid "Last Seen"
|
||||
msgstr "最后记录"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:425
|
||||
msgid "Last updated at %s."
|
||||
msgstr "最后更新于%s。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:168
|
||||
msgid "Loading configuration data..."
|
||||
msgstr "载入配置数据..."
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:15
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:557
|
||||
msgid "MAC"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:181
|
||||
msgid "Multiple of Unit"
|
||||
msgstr "单位之间倍数"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:578
|
||||
msgid "Protocol:"
|
||||
msgstr "协议:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:592
|
||||
msgid "Reset Database"
|
||||
msgstr "重置"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:181
|
||||
msgid "SI - 1000"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:207
|
||||
msgid "Save"
|
||||
msgstr "保存"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:76
|
||||
msgid "Saving configuration data..."
|
||||
msgstr "保存配置数据..."
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:179
|
||||
msgid "Show Zeros"
|
||||
msgstr "显示0流量"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:502
|
||||
msgid "TOTAL"
|
||||
msgstr "总共"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:24
|
||||
msgid ""
|
||||
"This box is used to select the Database path, which is /tmp/usage.db by "
|
||||
"default."
|
||||
msgstr "该选项用于选择数据存储路径,默认路径为/tmp/usage.db。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:60
|
||||
msgid "This will delete the database file. Are you sure?"
|
||||
msgstr "该操作将删除数据统计文件,确定执行该操作?"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:20
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:562
|
||||
msgid "Total"
|
||||
msgstr "总计"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:18
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:560
|
||||
msgid "Total Down"
|
||||
msgstr "总下载"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:19
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:561
|
||||
msgid "Total Up"
|
||||
msgstr "总上传"
|
||||
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:3
|
||||
msgid "Traffic Status"
|
||||
msgstr "流量监控"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:180
|
||||
msgid "Transfer Speed in Bits"
|
||||
msgstr "以bits显示传输速度"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/custom.js:9
|
||||
msgid "Unable to load the customized hostname file:"
|
||||
msgstr "不能载入自定义用户名文件:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:81
|
||||
msgid "Unable to save %s: %s"
|
||||
msgstr "不能保存%s: %s"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:376
|
||||
msgid "Updating again in %s second(s)."
|
||||
msgstr "下次更新将于%s秒之后。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:17
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:559
|
||||
msgid "Upload"
|
||||
msgstr "上传"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:183
|
||||
msgid "Upstream Bandwidth"
|
||||
msgstr "上传带宽"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:627
|
||||
msgid "Upstream:"
|
||||
msgstr "上行:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:16
|
||||
msgid "Usage - Configuration"
|
||||
msgstr "文件设置"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/custom.js:16
|
||||
msgid "Usage - Custom User File"
|
||||
msgstr "用户文件配置"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:574
|
||||
msgid "Usage - Details"
|
||||
msgstr "流量详情"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:182
|
||||
msgid "Use DSL Bandwidth"
|
||||
msgstr "使用DSL带宽"
|
||||
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:34
|
||||
msgid "User file"
|
||||
msgstr "用户文件"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:176
|
||||
msgid "ipv4"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:176
|
||||
msgid "ipv6"
|
||||
msgstr ""
|
||||
|
||||
#~ msgid "Show More Columns:"
|
||||
#~ msgstr "显示更多列:"
|
||||
|
||||
#~ msgid "This will revert the changes. Are you sure?"
|
||||
#~ msgstr "更改将会重置,确定吗?"
|
||||
@ -0,0 +1,276 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2023-04-26 18:31+0800\n"
|
||||
"Last-Translator: Victor Tseng (palatis@gmail.com)\n"
|
||||
"Language-Team: \n"
|
||||
"Language: zh_TW\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Poedit 3.2.2\n"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:611
|
||||
msgid "10 seconds"
|
||||
msgstr "10 秒"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:609
|
||||
msgid "2 seconds"
|
||||
msgstr "2 秒"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:612
|
||||
msgid "30 seconds"
|
||||
msgstr "30 秒"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:610
|
||||
msgid "5 seconds"
|
||||
msgstr "5 秒"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:603
|
||||
msgid "Auto update every:"
|
||||
msgstr "重新整理間隔:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:201
|
||||
msgid "Cancel"
|
||||
msgstr "取消"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:14
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:503
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:556
|
||||
msgid "Clients"
|
||||
msgstr "用戶端"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:132
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:567
|
||||
msgid "Collecting data..."
|
||||
msgstr "蒐集資料中…"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:75
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:167
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:210
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:25
|
||||
msgid "Configuration"
|
||||
msgstr "設定"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:597
|
||||
msgid "Configure Options"
|
||||
msgstr "設定選項"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:195
|
||||
msgid "Configure the default values for luci-app-wrtbwmon."
|
||||
msgstr "設定 luci-app-wrtbwmon 的預設值。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:24
|
||||
msgid "Database path"
|
||||
msgstr "資料庫路徑"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:178
|
||||
msgid "Default Columns"
|
||||
msgstr "預設顯示的欄位"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:176
|
||||
msgid "Default Protocol"
|
||||
msgstr "預設協定"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
msgid "Default Refresh Interval"
|
||||
msgstr "預設重新整理間隔"
|
||||
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:16
|
||||
msgid "Details"
|
||||
msgstr "詳細"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:177
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:608
|
||||
msgid "Disabled"
|
||||
msgstr "已停用"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:16
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:558
|
||||
msgid "Download"
|
||||
msgstr "下載"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:184
|
||||
msgid "Downstream Bandwidth"
|
||||
msgstr "下行頻寬"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:618
|
||||
msgid "Downstream:"
|
||||
msgstr "下行:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/custom.js:18
|
||||
msgid "Each line must have the following format:"
|
||||
msgstr "每一行皆必須使用以下格式:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:21
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:563
|
||||
msgid "First Seen"
|
||||
msgstr "初次發現"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:18
|
||||
msgid "General settings"
|
||||
msgstr "通用設定"
|
||||
|
||||
#: root/usr/share/rpcd/acl.d/luci-app-wrtbwmon.json:3
|
||||
msgid "Grant access to LuCI app wrtbwmon"
|
||||
msgstr "授權給 LuCI app wrtbwmon"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:185
|
||||
msgid "Hide MAC Addresses"
|
||||
msgstr "隱藏 MAC 地址"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:181
|
||||
msgid "IEC - 1024"
|
||||
msgstr "IEC - 1024"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:21
|
||||
msgid "Keep running in the background"
|
||||
msgstr "保持背景執行"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:22
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:564
|
||||
msgid "Last Seen"
|
||||
msgstr "最後發現"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:425
|
||||
msgid "Last updated at %s."
|
||||
msgstr "最後於 %s 發現。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:168
|
||||
msgid "Loading configuration data..."
|
||||
msgstr "載入設定資料…"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:15
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:557
|
||||
msgid "MAC"
|
||||
msgstr "MAC"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:181
|
||||
msgid "Multiple of Unit"
|
||||
msgstr "速率計量單位格式"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:578
|
||||
msgid "Protocol:"
|
||||
msgstr "協定:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:592
|
||||
msgid "Reset Database"
|
||||
msgstr "重置資料庫"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:181
|
||||
msgid "SI - 1000"
|
||||
msgstr "SI - 1000"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:207
|
||||
msgid "Save"
|
||||
msgstr "儲存"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:76
|
||||
msgid "Saving configuration data..."
|
||||
msgstr "正在保存設定資料…"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:179
|
||||
msgid "Show Zeros"
|
||||
msgstr "顯示無流量的紀錄"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:502
|
||||
msgid "TOTAL"
|
||||
msgstr "總計"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:24
|
||||
msgid ""
|
||||
"This box is used to select the Database path, which is /tmp/usage.db by "
|
||||
"default."
|
||||
msgstr "選擇資料庫路徑,預設為 /tmp/usage.db。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:60
|
||||
msgid "This will delete the database file. Are you sure?"
|
||||
msgstr "這會刪除目前的資料庫檔案,您確定嗎?"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:20
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:562
|
||||
msgid "Total"
|
||||
msgstr "總頻寬"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:18
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:560
|
||||
msgid "Total Down"
|
||||
msgstr "總下載"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:19
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:561
|
||||
msgid "Total Up"
|
||||
msgstr "總上傳"
|
||||
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:3
|
||||
msgid "Traffic Status"
|
||||
msgstr "頻寬使用狀況"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:180
|
||||
msgid "Transfer Speed in Bits"
|
||||
msgstr "以位元表示傳輸速率"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/custom.js:9
|
||||
msgid "Unable to load the customized hostname file:"
|
||||
msgstr "無法載入自訂的主機名稱檔案:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:81
|
||||
msgid "Unable to save %s: %s"
|
||||
msgstr "無法保存 %s:%s"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:376
|
||||
msgid "Updating again in %s second(s)."
|
||||
msgstr "於 %s 秒後更新。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:17
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:559
|
||||
msgid "Upload"
|
||||
msgstr "上傳"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:183
|
||||
msgid "Upstream Bandwidth"
|
||||
msgstr "上行頻寬"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:627
|
||||
msgid "Upstream:"
|
||||
msgstr "上行:"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/config.js:16
|
||||
msgid "Usage - Configuration"
|
||||
msgstr "頻寬使用狀況 - 設定"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/custom.js:16
|
||||
msgid "Usage - Custom User File"
|
||||
msgstr "頻寬使用狀況 - 自訂主機名稱列表"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:574
|
||||
msgid "Usage - Details"
|
||||
msgstr "頻寬使用狀況 - 詳細資料"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:182
|
||||
msgid "Use DSL Bandwidth"
|
||||
msgstr "使用 DSL 頻寬"
|
||||
|
||||
#: root/usr/share/luci/menu.d/luci-app-wrtbwmon.json:34
|
||||
msgid "User file"
|
||||
msgstr "使用者檔案"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:176
|
||||
msgid "ipv4"
|
||||
msgstr "ipv4"
|
||||
|
||||
#: htdocs/luci-static/resources/view/wrtbwmon/details.js:176
|
||||
msgid "ipv6"
|
||||
msgstr "ipv6"
|
||||
|
||||
#~ msgid "Default More Columns"
|
||||
#~ msgstr "預設顯示更多欄位"
|
||||
|
||||
#~ msgid "Show More Columns:"
|
||||
#~ msgstr "顯示更多欄位:"
|
||||
@ -0,0 +1,12 @@
|
||||
{
|
||||
"protocol": "ipv4",
|
||||
"interval": "5",
|
||||
"showMore": false,
|
||||
"showZero": true,
|
||||
"useBits": false,
|
||||
"useMultiple": "1000",
|
||||
"useDSL": false,
|
||||
"upstream": "100",
|
||||
"downstream": "1000",
|
||||
"hideMACs": []
|
||||
}
|
||||
124
package/mtk/applications/luci-app-wrtbwmon/root/usr/libexec/rpcd/luci.wrtbwmon
Executable file
124
package/mtk/applications/luci-app-wrtbwmon/root/usr/libexec/rpcd/luci.wrtbwmon
Executable file
@ -0,0 +1,124 @@
|
||||
#!/bin/sh
|
||||
|
||||
. "$IPKG_INSTROOT/usr/share/libubox/jshn.sh"
|
||||
|
||||
renamefile() {
|
||||
local base=$(basename -- "$1")
|
||||
local ext=$([ -z "${base/*.*/}" ] && echo ".${base##*.}" || echo '')
|
||||
local base="${base%.*}"
|
||||
echo "$(dirname $1)/${base}$2$ext" && return
|
||||
}
|
||||
|
||||
_get_db_path() {
|
||||
local db db_4 db_6 db_46
|
||||
db="$(uci -q get wrtbwmon.general.path)"
|
||||
db_4=$(renamefile "${db:-/tmp/usage.db}" "")
|
||||
db_6=$(renamefile "${db:-/tmp/usage.db}" ".6")
|
||||
db_46=$(renamefile "${db:-/tmp/usage.db}" ".46")
|
||||
json_init
|
||||
json_add_string file_4 "$db_4"
|
||||
json_add_string file_6 "$db_6"
|
||||
json_add_string file_46 "$db_46"
|
||||
json_dump
|
||||
json_cleanup
|
||||
}
|
||||
|
||||
_get_db_raw() {
|
||||
json_init
|
||||
json_add_string file "$1"
|
||||
json_add_string data "$(cat "$1")"
|
||||
json_dump
|
||||
json_cleanup
|
||||
}
|
||||
|
||||
_remove_db() {
|
||||
local result
|
||||
rm "$1" && result=1 || result=0
|
||||
json_init
|
||||
json_add_boolean result "$result"
|
||||
json_dump
|
||||
json_cleanup
|
||||
}
|
||||
|
||||
_change_db_path() {
|
||||
json_init
|
||||
json_load "$(_get_db_path)"
|
||||
json_get_var db_4 'file_4'
|
||||
json_get_var db_6 'file_6'
|
||||
json_get_var db_46 'file_46'
|
||||
json_cleanup
|
||||
if [ "$1" = "before" ]; then
|
||||
mv "$db_4" /tmp/usage.db.tmp
|
||||
mv "$db_6" /tmp/usage.6.db.tmp
|
||||
mv "$db_46" /tmp/usage.46.db.tmp
|
||||
elif [ "$1" = "after" ]; then
|
||||
mv -f /tmp/usage.db.tmp "$db_4"
|
||||
mv -f /tmp/usage.6.db.tmp "$db_6"
|
||||
mv -f /tmp/usage.46.db.tmp "$db_46"
|
||||
fi
|
||||
json_init
|
||||
json_add_boolean result $([ "$?" = 0 ] && echo 1 || echo 0 )
|
||||
json_dump
|
||||
json_cleanup
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
list)
|
||||
json_init
|
||||
json_add_object remove_db
|
||||
json_add_string protocol "protocol"
|
||||
json_close_object
|
||||
json_add_object get_db_raw
|
||||
json_add_string protocol "protocol"
|
||||
json_close_object
|
||||
json_add_object get_db_path
|
||||
json_close_object
|
||||
json_add_object change_db_path
|
||||
json_add_string state "state"
|
||||
json_close_object
|
||||
json_dump
|
||||
json_cleanup
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
remove_db)
|
||||
read -r input
|
||||
json_init
|
||||
json_load "$input"
|
||||
json_get_var protocol 'protocol'
|
||||
json_cleanup
|
||||
json_load "$(_get_db_path)"
|
||||
json_get_var db_s $([ "$protocol" = "ipv4" ] && echo file_4 || echo file_6)
|
||||
json_cleanup
|
||||
_remove_db "$db_s"
|
||||
;;
|
||||
get_db_raw)
|
||||
read -r input
|
||||
json_init
|
||||
json_load "$input"
|
||||
json_get_var protocol 'protocol'
|
||||
json_cleanup
|
||||
json_load "$(_get_db_path)"
|
||||
json_get_var db_s $([ "$protocol" = "ipv4" ] && echo file_4 || echo file_6)
|
||||
json_cleanup
|
||||
_get_db_raw "$db_s"
|
||||
;;
|
||||
get_db_path)
|
||||
read -r input
|
||||
json_init
|
||||
json_load "$input"
|
||||
json_get_var protocol 'protocol'
|
||||
json_cleanup
|
||||
_get_db_path
|
||||
;;
|
||||
change_db_path)
|
||||
read -r input
|
||||
json_init
|
||||
json_load "$input"
|
||||
json_get_var state 'state'
|
||||
json_cleanup
|
||||
_change_db_path "$state"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
@ -0,0 +1,41 @@
|
||||
{
|
||||
"admin/network/usage": {
|
||||
"title": "Traffic Status",
|
||||
"order": 60,
|
||||
"action": {
|
||||
"type": "alias",
|
||||
"path": "admin/network/usage/details"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [ "luci-app-wrtbwmon" ],
|
||||
"uci": { "wrtbwmon": true }
|
||||
}
|
||||
},
|
||||
|
||||
"admin/network/usage/details": {
|
||||
"title": "Details",
|
||||
"order": 10,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "wrtbwmon/details"
|
||||
}
|
||||
},
|
||||
|
||||
"admin/network/usage/config": {
|
||||
"title": "Configuration",
|
||||
"order": 20,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "wrtbwmon/config"
|
||||
}
|
||||
},
|
||||
|
||||
"admin/network/usage/custom": {
|
||||
"title": "User file",
|
||||
"order": 30,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "wrtbwmon/custom"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
{
|
||||
"luci-app-wrtbwmon": {
|
||||
"description": "Grant access to LuCI app wrtbwmon",
|
||||
"read": {
|
||||
"ubus": {
|
||||
"luci.wrtbwmon": [
|
||||
"get_db_raw",
|
||||
"get_db_path"
|
||||
],
|
||||
"luci-rpc": [
|
||||
"getDHCPLeases",
|
||||
"getDSLStatus"
|
||||
]
|
||||
},
|
||||
"file": {
|
||||
"/etc/wrtbwmon.user": [ "read" ],
|
||||
"/usr/sbin/wrtbwmon": [ "exec" ],
|
||||
"/etc/luci-wrtbwmon.conf": [ "read" ]
|
||||
},
|
||||
"uci": [ "wrtbwmon" ]
|
||||
},
|
||||
"write": {
|
||||
"ubus": {
|
||||
"luci.wrtbwmon": [
|
||||
"remove_db",
|
||||
"change_db_path"
|
||||
]
|
||||
},
|
||||
"file": {
|
||||
"/etc/luci-wrtbwmon.conf": [ "write" ],
|
||||
"/etc/wrtbwmon.user": [ "write" ]
|
||||
},
|
||||
"uci": [ "wrtbwmon" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
50
package/mtk/applications/wrtbwmon/Makefile
Executable file
50
package/mtk/applications/wrtbwmon/Makefile
Executable file
@ -0,0 +1,50 @@
|
||||
#
|
||||
# Copyright (C) 2006-2011 Xmlad.com
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=wrtbwmon
|
||||
PKG_VERSION:=1.2.1
|
||||
PKG_RELEASE:=3
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/wrtbwmon
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
DEPENDS:=+iptables +@BUSYBOX_CONFIG_IP
|
||||
TITLE:=A Traffic Usage Monitor
|
||||
SUBMENU:=Tools
|
||||
PKGARCH:=all
|
||||
endef
|
||||
|
||||
define Package/wrtbwmon/description
|
||||
An CERNET client daemon,
|
||||
Most usually used in China collages.
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/wrtbwmon/install
|
||||
$(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/wrtbwmon
|
||||
$(INSTALL_BIN) ./net/usr/sbin/* $(1)/usr/sbin/
|
||||
$(INSTALL_BIN) ./net/usr/share/wrtbwmon/* $(1)/usr/share/wrtbwmon/
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/config $(1)/etc/init.d $(1)/etc/hotplug.d/iface
|
||||
$(INSTALL_BIN) ./net/etc/init.d/wrtbwmon $(1)/etc/init.d/wrtbwmon
|
||||
$(INSTALL_BIN) ./net/etc/config/wrtbwmon $(1)/etc/config/wrtbwmon
|
||||
$(INSTALL_BIN) ./net/etc/hotplug.d/iface/99-wrtbwmon $(1)/etc/hotplug.d/iface/99-wrtbwmon
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,wrtbwmon))
|
||||
5
package/mtk/applications/wrtbwmon/net/etc/config/wrtbwmon
Executable file
5
package/mtk/applications/wrtbwmon/net/etc/config/wrtbwmon
Executable file
@ -0,0 +1,5 @@
|
||||
|
||||
config wrtbwmon 'general'
|
||||
option enabled '1'
|
||||
option path '/tmp/usage.db'
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
[ "$ACTION" = ifup -o "$ACTION" = ifupdate ] || exit 0
|
||||
[ "$ACTION" = ifupdate -a -z "$IFUPDATE_ADDRESSES" -a -z "$IFUPDATE_DATA" ] && exit 0
|
||||
|
||||
/etc/init.d/wrtbwmon restart
|
||||
|
||||
logger -t wrtbwmon "Restart for $ACTION of $INTERFACE ($DEVICE)"
|
||||
|
||||
44
package/mtk/applications/wrtbwmon/net/etc/init.d/wrtbwmon
Normal file
44
package/mtk/applications/wrtbwmon/net/etc/init.d/wrtbwmon
Normal file
@ -0,0 +1,44 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2019 OpenWrt.org
|
||||
|
||||
START=99
|
||||
USE_PROCD=1
|
||||
|
||||
NAME=wrtbwmon
|
||||
PID_FILE=/var/run/wrtbwmon.pid
|
||||
args=/usr/sbin/wrtbwmon
|
||||
|
||||
create_instance() {
|
||||
procd_open_instance
|
||||
procd_set_param command $args
|
||||
procd_set_param respawn
|
||||
procd_set_param user root
|
||||
# procd_set_param pidfile $PID_FILE
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_triggers()
|
||||
{
|
||||
procd_add_reload_trigger "$NAME"
|
||||
}
|
||||
|
||||
start_service() {
|
||||
local db enabled
|
||||
config_load $NAME
|
||||
|
||||
config_get db general path
|
||||
[ -z "$db" ] && db="/tmp/usage.db"
|
||||
append args " -46"
|
||||
append args "-f $db"
|
||||
append args "-p /tmp/usage.htm"
|
||||
append args "-u /etc/wrtbwmon.user"
|
||||
append args "-d"
|
||||
|
||||
config_get enabled general enabled
|
||||
[ "$enabled"0 -eq 0 ] || create_instance
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
procd_kill wrtbwmon
|
||||
kill -CONT $(cat $PID_FILE)
|
||||
}
|
||||
213
package/mtk/applications/wrtbwmon/net/usr/sbin/readDB.awk
Normal file
213
package/mtk/applications/wrtbwmon/net/usr/sbin/readDB.awk
Normal file
@ -0,0 +1,213 @@
|
||||
#!/usr/bin/awk
|
||||
|
||||
function inInterfaces(host) {
|
||||
return(interfaces ~ "(^| )" host "($| )")
|
||||
}
|
||||
|
||||
function newRule(arp_ip, ipt_cmd) {
|
||||
# checking for existing rules shouldn't be necessary if newRule is
|
||||
# always called after db is read, arp table is read, and existing
|
||||
# iptables rules are read.
|
||||
ipt_cmd=iptKey " -t mangle -j RETURN -s " arp_ip
|
||||
system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD")
|
||||
ipt_cmd=iptKey " -t mangle -j RETURN -d " arp_ip
|
||||
system(ipt_cmd " -C RRDIPT_FORWARD 2>/dev/null || " ipt_cmd " -A RRDIPT_FORWARD")
|
||||
}
|
||||
|
||||
function delRule(arp_ip, ipt_cmd) {
|
||||
ipt_cmd=iptKey " -t mangle -D RRDIPT_FORWARD -j RETURN "
|
||||
system(ipt_cmd "-s " arp_ip " 2>/dev/null")
|
||||
system(ipt_cmd "-d " arp_ip " 2>/dev/null")
|
||||
}
|
||||
|
||||
function total(i) {
|
||||
return(bw[i "/in"] + bw[i "/out"])
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
if (ipv6) {
|
||||
iptNF = 8
|
||||
iptKey = "ip6tables"
|
||||
} else {
|
||||
iptNF = 9
|
||||
iptKey = "iptables"
|
||||
}
|
||||
}
|
||||
|
||||
/^#/ { # get DB filename
|
||||
FS = ","
|
||||
dbFile = FILENAME
|
||||
next
|
||||
}
|
||||
|
||||
# data from database; first file
|
||||
ARGIND==1 { #!@todo this doesn't help if the DB file is empty.
|
||||
lb=$1
|
||||
|
||||
if (lb !~ "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$") next
|
||||
|
||||
if (!(lb in mac)) {
|
||||
mac[lb] = $1
|
||||
ip[lb] = $2
|
||||
inter[lb] = $3
|
||||
speed[lb "/in"] = 0
|
||||
speed[lb "/out"]= 0
|
||||
bw[lb "/in"] = $6
|
||||
bw[lb "/out"] = $7
|
||||
firstDate[lb] = $9
|
||||
lastDate[lb] = $10
|
||||
ignore[lb] = 1
|
||||
} else {
|
||||
if ($9 < firstDate[lb])
|
||||
firstDate[lb] = $9
|
||||
if ($10 > lastDate[lb]) {
|
||||
ip[lb] = $2
|
||||
inter[lb] = $3
|
||||
lastDate[lb] = $10
|
||||
}
|
||||
bw[lb "/in"] += $6
|
||||
bw[lb "/out"] += $7
|
||||
ignore[lb] = 0
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
# not triggered on the first file
|
||||
FNR==1 {
|
||||
FS=" "
|
||||
if(ARGIND == 2) next
|
||||
}
|
||||
|
||||
# arp: ip hw flags hw_addr mask device
|
||||
ARGIND==2 {
|
||||
#!@todo regex match IPs and MACs for sanity
|
||||
if (ipv6) {
|
||||
statFlag= ($4 != "FAILED" && $4 != "INCOMPLETE")
|
||||
macAddr = $5
|
||||
hwIF = $3
|
||||
} else {
|
||||
statFlag= ($3 != "0x0")
|
||||
macAddr = $4
|
||||
hwIF = $6
|
||||
}
|
||||
|
||||
lb=$1
|
||||
if (hwIF != wanIF && statFlag && macAddr ~ "^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$") {
|
||||
hosts[lb] = 1
|
||||
arp_mac[lb] = macAddr
|
||||
arp_ip[lb] = $1
|
||||
arp_inter[lb] = hwIF
|
||||
arp_bw[lb "/in"] = 0
|
||||
arp_bw[lb "/out"] = 0
|
||||
arp_firstDate[lb] = systime()
|
||||
arp_lastDate[lb] = arp_firstDate[lb]
|
||||
arp_ignore[lb] = 1
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
#!@todo could use mangle chain totals or tailing "unnact" rules to
|
||||
# account for data for new hosts from their first presence on the
|
||||
# network to rule creation. The "unnact" rules would have to be
|
||||
# maintained at the end of the list, and new rules would be inserted
|
||||
# at the top.
|
||||
ARGIND==3 && NF==iptNF && $1!="pkts" { # iptables input
|
||||
if (ipv6) {
|
||||
lfn = 5
|
||||
tag = "::/0"
|
||||
} else {
|
||||
lfn = 6
|
||||
tag = "0.0.0.0/0"
|
||||
}
|
||||
|
||||
if ($(lfn) != "*") {
|
||||
m = $(lfn)
|
||||
n = m "/in"
|
||||
} else if ($(++lfn) != "*") {
|
||||
m = $(lfn)
|
||||
n = m "/out"
|
||||
} else if ($(++lfn) != tag) {
|
||||
m = $(lfn)
|
||||
n = m "/out"
|
||||
} else { # $(++lfn) != tag
|
||||
m = $(++lfn)
|
||||
n = m "/in"
|
||||
}
|
||||
|
||||
if (mode == "diff" || mode == "noUpdate") print n, $2
|
||||
if (mode != "noUpdate") {
|
||||
if (inInterfaces(m)) { # if label is an interface
|
||||
if (!(m in arp_mac)) {
|
||||
cmd = "cat /sys/class/net/" m "/address"
|
||||
cmd | getline arp_mac[m]
|
||||
close(cmd)
|
||||
|
||||
if (length(arp_mac[m]) == 0) arp_mac[m] = "00:00:00:00:00:00"
|
||||
|
||||
arp_ip[m] = "NA"
|
||||
arp_inter[m] = m
|
||||
arp_bw[m "/in"] = 0
|
||||
arp_bw[m "/out"] = 0
|
||||
arp_firstDate[m] = systime()
|
||||
arp_lastDate[m] = arp_firstDate[m]
|
||||
arp_ignore[lb] = 1
|
||||
}
|
||||
} else {
|
||||
if (!(m in arp_mac)) hosts[m] = 0
|
||||
else delete hosts[m]
|
||||
}
|
||||
|
||||
if ($2 > 0) {
|
||||
arp_bw[n] = $2
|
||||
arp_lastDate[m] = systime()
|
||||
arp_ignore[m] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
END {
|
||||
if (mode == "noUpdate") exit
|
||||
|
||||
for (i in arp_ip) {
|
||||
lb = arp_mac[i]
|
||||
if (!arp_ignore[i] || !(lb in mac)) {
|
||||
ignore[lb] = 0
|
||||
|
||||
if (lb in mac) {
|
||||
bw[lb "/in"] += arp_bw[i "/in"]
|
||||
bw[lb "/out"] += arp_bw[i "/out"]
|
||||
lastDate[lb] = arp_lastDate[i]
|
||||
} else {
|
||||
bw[lb "/in"] = arp_bw[i "/in"]
|
||||
bw[lb "/out"] = arp_bw[i "/out"]
|
||||
firstDate[lb] = arp_firstDate[i]
|
||||
lastDate[lb] = arp_lastDate[i]
|
||||
}
|
||||
mac[lb] = arp_mac[i]
|
||||
ip[lb] = arp_ip[i]
|
||||
inter[lb] = arp_inter[i]
|
||||
|
||||
if (interval != 0) {
|
||||
speed[lb "/in"] = int(arp_bw[i "/in"] / interval)
|
||||
speed[lb "/out"]= int(arp_bw[i "/out"] / interval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(dbFile)
|
||||
for (i in mac) {
|
||||
if (!ignore[i]) {
|
||||
print "#mac,ip,iface,speed_in,speed_out,in,out,total,first_date,last_date" > dbFile
|
||||
OFS=","
|
||||
for (i in mac)
|
||||
print mac[i], ip[i], inter[i], speed[i "/in"], speed[i "/out"], bw[i "/in"], bw[i "/out"], total(i), firstDate[i], lastDate[i] > dbFile
|
||||
close(dbFile)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# for hosts without rules
|
||||
for (i in hosts)
|
||||
if (hosts[i]) newRule(i)
|
||||
else delRule(i)
|
||||
}
|
||||
460
package/mtk/applications/wrtbwmon/net/usr/sbin/wrtbwmon
Normal file
460
package/mtk/applications/wrtbwmon/net/usr/sbin/wrtbwmon
Normal file
@ -0,0 +1,460 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
|
||||
# Default input parameters for wrtbwmon.
|
||||
runMode=0
|
||||
Monitor46=4
|
||||
|
||||
# Some parameters for monitor process.
|
||||
for46=
|
||||
updatePID=
|
||||
logFile=/var/log/wrtbwmon.log
|
||||
lockFile=/var/lock/wrtbwmon.lock
|
||||
pidFile=/var/run/wrtbwmon.pid
|
||||
tmpDir=/var/tmp/wrtbwmon
|
||||
interval4=0
|
||||
interval6=0
|
||||
|
||||
# Debug parameters for readDB.awk.
|
||||
mode=
|
||||
DEBUG=
|
||||
|
||||
# Constant parameter for wrtbwmon.
|
||||
binDir=/usr/sbin
|
||||
dataDir=/usr/share/wrtbwmon
|
||||
|
||||
networkFuncs=/lib/functions/network.sh
|
||||
uci=`which uci 2>/dev/null`
|
||||
nslookup=`which nslookup 2>/dev/null`
|
||||
nvram=`which nvram 2>/dev/null`
|
||||
|
||||
chains='INPUT OUTPUT FORWARD'
|
||||
interfaces='eth0 tun0 br-lan' # in addition to detected WAN
|
||||
|
||||
# DNS server for reverse lookups provided in "DNS".
|
||||
# don't perform reverse DNS lookups by default
|
||||
DO_RDNS=${DNS-}
|
||||
|
||||
header="#mac,ip,iface,speed_in,speed_out,in,out,total,first_date,last_date"
|
||||
|
||||
createDbIfMissing() {
|
||||
[ ! -f "$DB" ] && echo $header > "$DB"
|
||||
[ ! -f "$DB6" ] && echo $header > "$DB6"
|
||||
}
|
||||
|
||||
checkDbArg() {
|
||||
[ -z "$DB" ] && echo "ERROR: Missing argument 2 (database file)" && exit 1
|
||||
}
|
||||
|
||||
checkDB() {
|
||||
[ ! -f "$DB" ] && echo "ERROR: $DB does not exist" && exit 1
|
||||
[ ! -w "$DB" ] && echo "ERROR: $DB is not writable" && exit 1
|
||||
[ ! -f "$DB6" ] && echo "ERROR: $DB6 does not exist" && exit 1
|
||||
[ ! -w "$DB6" ] && echo "ERROR: $DB6 is not writable" && exit 1
|
||||
}
|
||||
|
||||
checkWAN() {
|
||||
[ -z "$1" ] && echo "Warning: failed to detect WAN interface."
|
||||
}
|
||||
|
||||
lookup() {
|
||||
local MAC=$1
|
||||
local IP=$2
|
||||
local userDB=$3
|
||||
local USERSFILE=
|
||||
local USER=
|
||||
for USERSFILE in $userDB /tmp/dhcp.leases /tmp/dnsmasq.conf /etc/dnsmasq.conf /etc/hosts; do
|
||||
[ -e "$USERSFILE" ] || continue
|
||||
|
||||
case $USERSFILE in
|
||||
/tmp/dhcp.leases )
|
||||
USER=$(grep -i "$MAC" $USERSFILE | cut -f4 -s -d' ')
|
||||
;;
|
||||
/etc/hosts )
|
||||
USER=$(grep "^$IP " $USERSFILE | cut -f2 -s -d' ')
|
||||
;;
|
||||
* )
|
||||
USER=$(grep -i "$MAC" "$USERSFILE" | cut -f2 -s -d,)
|
||||
;;
|
||||
esac
|
||||
|
||||
[ "$USER" = "*" ] && USER=
|
||||
[ -n "$USER" ] && break
|
||||
|
||||
done
|
||||
|
||||
if [ -n "$DO_RDNS" -a -z "$USER" -a "$IP" != "NA" -a -n "$nslookup" ]; then
|
||||
USER=`$nslookup $IP $DNS | awk '!/server can/{if($4){print $4; exit}}' | sed -re 's/[.]$//'`
|
||||
fi
|
||||
|
||||
[ -z "$USER" ] && USER=${MAC}
|
||||
echo $USER
|
||||
}
|
||||
|
||||
detectIF() {
|
||||
local IF=
|
||||
if [ -f "$networkFuncs" ]; then
|
||||
IF=`. $networkFuncs; network_get_device netdev $1; echo $netdev`
|
||||
[ -n "$IF" ] && echo $IF && return
|
||||
fi
|
||||
|
||||
if [ -n "$uci" -a -x "$uci" ]; then
|
||||
IF=`$uci get network.${1}.ifname 2>/dev/null`
|
||||
[ $? -eq 0 -a -n "$IF" ] && echo $IF && return
|
||||
fi
|
||||
|
||||
if [ -n "$nvram" -a -x "$nvram" ]; then
|
||||
IF=`$nvram get ${1}_ifname 2>/dev/null`
|
||||
[ $? -eq 0 -a -n "$IF" ] && echo $IF && return
|
||||
fi
|
||||
}
|
||||
|
||||
detectLAN() {
|
||||
[ -e /sys/class/net/br-lan ] && echo br-lan && return
|
||||
local lan=$(detectIF lan)
|
||||
[ -n "$lan" ] && echo $lan && return
|
||||
}
|
||||
|
||||
detectWAN() {
|
||||
local wan=$(detectIF wan)
|
||||
[ -n "$wan" ] && echo $wan && return
|
||||
wan=$(ip route show 2>/dev/null | grep default | sed -re '/^default/ s/default.*dev +([^ ]+).*/\1/')
|
||||
[ -n "$wan" ] && echo $wan && return
|
||||
[ -f "$networkFuncs" ] && wan=$(. $networkFuncs; network_find_wan wan; echo $wan)
|
||||
[ -n "$wan" ] && echo $wan && return
|
||||
}
|
||||
|
||||
lockFunc() {
|
||||
#Realize the lock function by busybox lock or flock command.
|
||||
# if !(lock -n $lockFile) >/dev/null 2>&1; then
|
||||
# exit 1
|
||||
# fi
|
||||
#The following lock method is realized by other's function.
|
||||
|
||||
local attempts=0
|
||||
local flag=0
|
||||
|
||||
while [ "$flag" = 0 ]; do
|
||||
local tempfile=$(mktemp $tmpDir/lock.XXXXXX)
|
||||
ln $tempfile $lockFile >/dev/null 2>&1 && flag=1
|
||||
rm $tempfile
|
||||
|
||||
if [ "$flag" = 1 ]; then
|
||||
[ -n "$DEBUG" ] && echo ${updatePID} "got lock after $attempts attempts"
|
||||
flag=1
|
||||
else
|
||||
sleep 1
|
||||
attempts=$(($attempts+1))
|
||||
[ -n "$DEBUG" ] && echo ${updatePID} "The $attempts attempts."
|
||||
[ "$attempts" -ge 10 ] && exit
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
unlockFunc() {
|
||||
#Realize the lock function by busybox lock or flock command.
|
||||
# lock -u $lockFile
|
||||
# rm -f $lockFile
|
||||
# [ -n "$DEBUG" ] && echo ${updatePID} "released lock"
|
||||
#The following lock method is realized by other's function.
|
||||
|
||||
rm -f $lockFile
|
||||
[ -n "$DEBUG" ] && echo ${updatePID} "released lock"
|
||||
}
|
||||
|
||||
# chain
|
||||
newChain() {
|
||||
local chain=$1
|
||||
local ipt=$2
|
||||
# Create the RRDIPT_$chain chain (it doesn't matter if it already exists).
|
||||
|
||||
$ipt -t mangle -N RRDIPT_$chain 2> /dev/null
|
||||
|
||||
# Add the RRDIPT_$chain CHAIN to the $chain chain if not present
|
||||
$ipt -t mangle -C $chain -j RRDIPT_$chain 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
[ -n "$DEBUG" ] && echo "DEBUG: $ipt chain misplaced, recreating it..."
|
||||
$ipt -t mangle -I $chain -j RRDIPT_$chain
|
||||
fi
|
||||
}
|
||||
|
||||
# chain tun
|
||||
newRuleIF() {
|
||||
local chain=$1
|
||||
local IF=$2
|
||||
local ipt=$3
|
||||
local cmd=
|
||||
|
||||
if [ "$chain" = "OUTPUT" ]; then
|
||||
cmd="$ipt -t mangle -o $IF -j RETURN"
|
||||
elif [ "$chain" = "INPUT" ]; then
|
||||
cmd="$ipt -t mangle -i $IF -j RETURN"
|
||||
fi
|
||||
[ -n "$cmd" ] && eval $cmd " -C RRDIPT_$chain 2>/dev/null" || eval $cmd " -A RRDIPT_$chain"
|
||||
}
|
||||
|
||||
publish() {
|
||||
# sort DB
|
||||
# busybox sort truncates numbers to 32 bits
|
||||
grep -v '^#' $DB | awk -F, '{OFS=","; a=sprintf("%f",$6/1e6); $6=""; print a,$0}' | tr -s ',' | sort -rn | awk -F, '{OFS=",";$1=sprintf("%f",$1*1e6);print}' > $tmpDir/sorted_${updatePID}.tmp
|
||||
|
||||
# create HTML page
|
||||
local htmPage="$tmpDir/${pb_html##*/}"
|
||||
rm -f $htmPage
|
||||
cp $dataDir/usage.htm1 $htmPage
|
||||
|
||||
while IFS=, read PEAKUSAGE_IN MAC IP IFACE SPEED_IN SPEED_OUT PEAKUSAGE_OUT TOTAL FIRSTSEEN LASTSEEN
|
||||
do
|
||||
echo "
|
||||
new Array(\"$(lookup $MAC $IP $user_def)\",\"$MAC\",\"$IP\",$SPEED_IN,$SPEED_OUT,
|
||||
$PEAKUSAGE_IN,$PEAKUSAGE_OUT,$TOTAL,\"$FIRSTSEEN\",\"$LASTSEEN\")," >> $htmPage
|
||||
done < $tmpDir/sorted_${updatePID}.tmp
|
||||
echo "0);" >> $htmPage
|
||||
|
||||
sed "s/(date)/`date`/" < $dataDir/usage.htm2 >> $htmPage
|
||||
mv $htmPage "$pb_html"
|
||||
}
|
||||
|
||||
updatePrepare() {
|
||||
checkDbArg
|
||||
createDbIfMissing
|
||||
checkDB
|
||||
[ -e $tmpDir ] || mkdir -p $tmpDir
|
||||
|
||||
for46="$Monitor46"
|
||||
local timeNow=$(cat /proc/uptime | awk '{print $1}')
|
||||
|
||||
if [ -e "$logFile" ]; then
|
||||
local timeLast4=$(awk -F'[: ]+' '/ipv4/{print $2}' "$logFile")
|
||||
local timeLast6=$(awk -F'[: ]+' '/ipv6/{print $2}' "$logFile")
|
||||
interval4=$(awk -v now=$timeNow -v last=$timeLast4 'BEGIN{print (now-last)}');
|
||||
interval6=$(awk -v now=$timeNow -v last=$timeLast6 'BEGIN{print (now-last)}');
|
||||
|
||||
for ii in 4 6; do
|
||||
[[ -n "$(echo $for46 | grep ${ii})" ]] && {
|
||||
if [[ "$(eval echo \$interval${ii})" \> "0.9" ]]; then
|
||||
sed -i "s/^ipv${ii}: [0-9\.]\{1,\}/ipv${ii}: $timeNow/ig" "$logFile"
|
||||
else
|
||||
for46=`echo "$for46" | sed "s/${ii}//g"`
|
||||
fi
|
||||
}
|
||||
done
|
||||
else
|
||||
echo -e "ipv4: $timeNow\nipv6: $timeNow" >"$logFile"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
update() {
|
||||
updatePID=$( sh -c 'echo $PPID' )
|
||||
|
||||
lockFunc
|
||||
|
||||
local wan=$(detectWAN)
|
||||
checkWAN $wan
|
||||
interfaces="$interfaces $wan"
|
||||
|
||||
[ "$for46" = 4 ] && IPT='iptables'
|
||||
[ "$for46" = 6 ] && IPT='ip6tables'
|
||||
[ "$for46" = 46 ] && IPT='iptables ip6tables'
|
||||
|
||||
for ii in $IPT ; do
|
||||
if [ -z "$( ${ii}-save | grep RRDIPT )" ]; then
|
||||
|
||||
for chain in $chains; do
|
||||
newChain $chain $ii
|
||||
done
|
||||
|
||||
# track local data
|
||||
for chain in INPUT OUTPUT; do
|
||||
for interface in $interfaces; do
|
||||
[ -n "$interface" ] && [ -e "/sys/class/net/$interface" ] && newRuleIF $chain $interface $ii
|
||||
done
|
||||
done
|
||||
fi
|
||||
# this will add rules for hosts in arp table
|
||||
> $tmpDir/${ii}_${updatePID}.tmp
|
||||
|
||||
for chain in $chains; do
|
||||
$ii -nvxL RRDIPT_$chain -t mangle -Z >> $tmpDir/${ii}_${updatePID}.tmp
|
||||
done
|
||||
done
|
||||
|
||||
[ -f $tmpDir/iptables_${updatePID}.tmp ] && (
|
||||
awk -v mode="$mode" -v interfaces="$interfaces" -v wanIF="$wan" -v interval=$interval4 \
|
||||
-v ipv6="0" -f $binDir/readDB.awk \
|
||||
$DB \
|
||||
/proc/net/arp \
|
||||
$tmpDir/iptables_${updatePID}.tmp
|
||||
)
|
||||
|
||||
[ -f $tmpDir/ip6tables_${updatePID}.tmp ] && (
|
||||
echo "This file is geneated by 'ip -6 neigh'" > $tmpDir/ip6addr_${updatePID}.tmp
|
||||
`ip -6 neigh >> $tmpDir/ip6addr_${updatePID}.tmp`;
|
||||
|
||||
awk -v mode="$mode" -v interfaces="$interfaces" -v wanIF="$wan" -v interval=$interval6 \
|
||||
-v ipv6="1" -f $binDir/readDB.awk \
|
||||
"$DB6" \
|
||||
$tmpDir/ip6addr_${updatePID}.tmp \
|
||||
$tmpDir/ip6tables_${updatePID}.tmp
|
||||
)
|
||||
|
||||
[ "$Monitor46" = 46 ] && (
|
||||
cp $DB $DB46
|
||||
cat $DB6 >> $DB46
|
||||
awk -f $binDir/readDB.awk "$DB46"
|
||||
)
|
||||
|
||||
[ -n "$pb_html" ] && publish
|
||||
|
||||
rm -f $tmpDir/*_${updatePID}.tmp
|
||||
unlockFunc
|
||||
}
|
||||
|
||||
renamefile() {
|
||||
local base=$(basename -- "$1")
|
||||
local ext=$([ -z "${base/*.*/}" ] && echo ".${base##*.}" || echo '')
|
||||
local base="${base%.*}"
|
||||
echo "$(dirname $1)/${base}$2$ext" && return
|
||||
}
|
||||
|
||||
ending() {
|
||||
iptables-save | grep -v RRDIPT | iptables-restore
|
||||
ip6tables-save | grep -v RRDIPT | ip6tables-restore
|
||||
|
||||
if checkPid $pidFile; then
|
||||
local pid=$( cat $pidFile )
|
||||
rm -rf $lockFile $logFile $pidFile $tmpDir/*
|
||||
kill -9 $pid >> /dev/null 2>&1
|
||||
fi
|
||||
echo "exit!!"
|
||||
}
|
||||
|
||||
checkPid() {
|
||||
[ -e "$1" ] && local pid=$(cat $1) || return 1
|
||||
[ -d "/proc/$pid" ] && {
|
||||
[ -n "$( cat /proc/$pid/cmdline | grep wrtbwmon )" ] && return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
sleepProcess() {
|
||||
sleep 1m
|
||||
kill -CONT $1 >>/dev/null 2>&1
|
||||
}
|
||||
|
||||
loop() {
|
||||
trap 'ending' INT TERM HUP QUIT
|
||||
if checkPid $pidFile; then
|
||||
echo "Another wrtbwmon is on running!!!"
|
||||
else
|
||||
local loopPID=$( sh -c 'echo $PPID' )
|
||||
local SPID=
|
||||
echo $loopPID > $pidFile
|
||||
while true ;do
|
||||
[ -n "$SPID" ] && kill -9 $SPID >>/dev/null 2>&1
|
||||
sleepProcess $loopPID &
|
||||
SPID=$!
|
||||
updatePrepare && update
|
||||
kill -STOP $loopPID >>/dev/null 2>&1
|
||||
done
|
||||
fi
|
||||
trap INT TERM HUP QUIT
|
||||
}
|
||||
|
||||
tips() {
|
||||
echo \
|
||||
"Usage: $0 [options...]
|
||||
Options:
|
||||
-k Exit the wrtbwmon!
|
||||
-f dbfile Set the DB file path
|
||||
-u usrfile Set the user_def file path
|
||||
-p htmlfile Set the publish htm file path
|
||||
-d Enter the foreground mode.
|
||||
-D Enter the daemo mode.
|
||||
-4 Listen to ipv4 only.
|
||||
-6 Listen to ipv6 only.
|
||||
-46 Listen to ipv4 and ipv6.
|
||||
|
||||
Note: [user_file] is an optional file to match users with MAC addresses.
|
||||
Its format is \"00:MA:CA:DD:RE:SS,username\", with one entry per line."
|
||||
}
|
||||
|
||||
############################################################
|
||||
|
||||
while [ $# != 0 ];do
|
||||
case $1 in
|
||||
"-k" )
|
||||
/etc/init.d/wrtbwmon stop
|
||||
exit 0
|
||||
;;
|
||||
"-f" )
|
||||
shift
|
||||
if [ $# -gt 0 ];then
|
||||
DB=$1
|
||||
DB6="$(renamefile $DB .6)"
|
||||
DB46="$(renamefile $DB .46)"
|
||||
else
|
||||
echo "No db file path seted, exit!!"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"-u")
|
||||
shift
|
||||
if [ $# -gt 0 ];then
|
||||
user_def=$1
|
||||
else
|
||||
echo "No user define file path seted, exit!!"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
"-p")
|
||||
shift
|
||||
if [ $# -gt 0 ];then
|
||||
pb_html=$1
|
||||
else
|
||||
echo "No publish html file path seted, exit!!"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
"-d")
|
||||
runMode=1
|
||||
;;
|
||||
|
||||
"-D")
|
||||
runMode=2
|
||||
;;
|
||||
|
||||
"-4")
|
||||
Monitor46=4
|
||||
;;
|
||||
|
||||
"-6")
|
||||
Monitor46=6
|
||||
;;
|
||||
|
||||
"-46")
|
||||
Monitor46=46
|
||||
;;
|
||||
|
||||
"&&" | "||" | ";")
|
||||
break
|
||||
;;
|
||||
|
||||
"*")
|
||||
tips
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "$runMode" = '1' ]; then
|
||||
loop
|
||||
elif [ "$runMode" = '2' ]; then
|
||||
loop >>/dev/null 2>&1 &
|
||||
else
|
||||
updatePrepare && update
|
||||
fi
|
||||
@ -0,0 +1,34 @@
|
||||
<html><head><title>Traffic</title>
|
||||
<script type="text/javascript">
|
||||
function getSize(size) {
|
||||
if (size === 0) return '0 ';
|
||||
var prefix=["","k","M","G","T","P","E","Z"];
|
||||
var base=1024, precision = 1;
|
||||
var pos=Math.floor(Math.log(size)/Math.log(base));
|
||||
if (pos > 2) precision=100;
|
||||
return (Math.round(size/Math.pow(base,pos)*precision)/precision)+' '+prefix[pos];
|
||||
}
|
||||
function padstr(str) {
|
||||
return str < 10 ? '0' + str : str;
|
||||
}
|
||||
function dateToString(date) {
|
||||
var d = new Date((/\W/g).test(date) ? date : date * 1000);
|
||||
var Y = d.getFullYear(), M = d.getMonth(), D = d.getDate();
|
||||
var hh = d.getHours(), mm = d.getMinutes(), ss = d.getSeconds();
|
||||
return Y + '/' + padstr(M) + '/' + padstr(D) + ' ' + padstr(hh) + ':' + padstr(mm) + ':' + padstr(ss);
|
||||
}
|
||||
</script></head>
|
||||
<body><h1>Total Usage:</h1>
|
||||
<table border="1">
|
||||
<tr bgcolor=silver>
|
||||
<th>User</th>
|
||||
<th>Down Speed</th>
|
||||
<th>Up Speed</th>
|
||||
<th>Download</th>
|
||||
<th>Upload</th>
|
||||
<th>Total</th>
|
||||
<th>First seen</th>
|
||||
<th>Last seen</th>
|
||||
</tr>
|
||||
<script type="text/javascript">
|
||||
var values = new Array(
|
||||
@ -0,0 +1,18 @@
|
||||
var speedIn = 0;
|
||||
var speedOut = 0;
|
||||
var totalIn = 0;
|
||||
var totalOut = 0;
|
||||
for (i=0; i < values.length-1; i++) {
|
||||
speedIn += values[i][3];
|
||||
speedOut += values[i][4]
|
||||
totalIn += values[i][5];
|
||||
totalOut += values[i][6];
|
||||
document.write("<tr><td><div title=\"" + values[i][1] + " (" + values[i][2] + ")" + "\">" + values[i][0] + "</div></td>");
|
||||
for (j=3; j < 8; j++)
|
||||
document.write("<td>" + getSize(values[i][j]) + ((j == 3) || (j ==4) ? 'B/s' : 'B') + "</td>");
|
||||
document.write("<td>" + dateToString(values[i][8]) + "</td><td>" + dateToString(values[i][9]) + "</td></tr>");
|
||||
}
|
||||
document.write("<tr><td>TOTAL</td><td>" + getSize(speedIn) + "B/s" + "</td><td>" + getSize(speedOut) + "B/s" + "</td><td>" + getSize(totalIn) + "</td><td>" + getSize(totalOut) + "</td><td>" + getSize(totalIn + totalOut) + "</td><td></td><td></td></tr>");
|
||||
</script></table>
|
||||
<br /><small>This page was generated on (date)</small>
|
||||
</body></html>
|
||||
@ -14,6 +14,6 @@ KERNEL_TESTING_PATCHVER:=5.4
|
||||
include $(INCLUDE_DIR)/target.mk
|
||||
DEFAULT_PACKAGES += \
|
||||
kmod-leds-gpio kmod-gpio-button-hotplug \
|
||||
autocore-arm uboot-envtools luci-app-quickstart luci-app-rtbwmon
|
||||
autocore-arm uboot-envtools luci-app-quickstart luci-app-wrtbwmon
|
||||
|
||||
$(eval $(call BuildTarget))
|
||||
|
||||
@ -554,6 +554,7 @@ unsigned int do_hnat_ge_to_ext(struct sk_buff *skb, const char *func)
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct hnat_accounting diffglobal[2][32769];
|
||||
|
||||
static void mtk_hnat_nf_update_ipt(struct sk_buff *skb)
|
||||
{
|
||||
@ -564,8 +565,6 @@ static void mtk_hnat_nf_update_ipt(struct sk_buff *skb)
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct hnat_accounting diff;
|
||||
|
||||
if (hnat_priv->data->per_flow_accounting && hnat_priv->nf_stat_en)
|
||||
return ;
|
||||
if (skb->protocol == htons(ETH_P_IPV6) && !hnat_priv->ipv6_en) {
|
||||
return ;
|
||||
}
|
||||
@ -588,14 +587,15 @@ static void mtk_hnat_nf_update_ipt(struct sk_buff *skb)
|
||||
if (ct) {
|
||||
if (!hnat_get_count(hnat_priv, skb_hnat_ppe(skb), skb_hnat_entry(skb), &diff))
|
||||
return;
|
||||
|
||||
if ((skb_hnat_entry(skb) <= hnat_priv->foe_etry_num) && (skb_hnat_entry(skb) >0))
|
||||
diffglobal[skb_hnat_ppe(skb)][skb_hnat_entry(skb)]= diff;
|
||||
|
||||
acct = nf_conn_acct_find(ct);
|
||||
if (acct) {
|
||||
counter = acct->counter;
|
||||
atomic64_set(&counter[CTINFO2DIR(ctinfo)].diff_packets, diff.packets);
|
||||
atomic64_set(&counter[CTINFO2DIR(ctinfo)].diff_bytes, diff.bytes);
|
||||
atomic64_add(diff.packets, &counter[CTINFO2DIR(ctinfo)].packets);
|
||||
atomic64_add(diff.bytes, &counter[CTINFO2DIR(ctinfo)].bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -850,7 +850,6 @@ static unsigned int is_ppe_support_type(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* update hnat count to nf_conntrack and iptables by keepalive */
|
||||
static unsigned int
|
||||
mtk_hnat_nf_conntrack(void *priv, struct sk_buff *skb,
|
||||
const struct nf_hook_state *state)
|
||||
@ -2147,6 +2146,29 @@ static void mtk_hnat_dscp_update(struct sk_buff *skb, struct foe_entry *entry)
|
||||
|
||||
|
||||
|
||||
static void mtk_hnat_nf_update(struct sk_buff *skb)
|
||||
{
|
||||
struct nf_conn *ct;
|
||||
struct nf_conn_acct *acct;
|
||||
struct nf_conn_counter *counter;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct hnat_accounting diff;
|
||||
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (ct) {
|
||||
if ((skb_hnat_entry(skb) <= hnat_priv->foe_etry_num) && (skb_hnat_entry(skb) >0))
|
||||
diff= diffglobal[skb_hnat_ppe(skb)][skb_hnat_entry(skb)];
|
||||
else return;
|
||||
|
||||
|
||||
acct = nf_conn_acct_find(ct);
|
||||
if (acct) {
|
||||
counter = acct->counter;
|
||||
atomic64_add(diff.packets, &counter[CTINFO2DIR(ctinfo)].packets);
|
||||
atomic64_add(diff.bytes, &counter[CTINFO2DIR(ctinfo)].bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int mtk_hnat_nf_post_routing(
|
||||
struct sk_buff *skb, const struct net_device *out,
|
||||
@ -2205,6 +2227,10 @@ static unsigned int mtk_hnat_nf_post_routing(
|
||||
skb_to_hnat_info(skb, out, entry, &hw_path);
|
||||
break;
|
||||
case HIT_BIND_KEEPALIVE_DUP_OLD_HDR:
|
||||
/* update hnat count to nf_conntrack by keepalive */
|
||||
if (hnat_priv->data->per_flow_accounting && hnat_priv->nf_stat_en)
|
||||
mtk_hnat_nf_update(skb);
|
||||
|
||||
if (fn && !mtk_hnat_accel_type(skb))
|
||||
break;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user