update 2023-03-02 16:26:13

This commit is contained in:
github-actions[bot] 2023-03-02 16:26:13 +08:00
parent 0ad1fa03db
commit 0672d5d452
20 changed files with 1070 additions and 86 deletions

View File

@ -46,7 +46,7 @@ remote_dns:value("tls://94.140.14.140", "94.140.14.140 (AdGuard)")
remote_dns:value("tls://94.140.14.141", "94.140.14.141 (AdGuard)")
remote_dns:depends( "configfile", "./def_config.yaml")
remote_dns = s:option(Value, "remote_dns2", " ")
remote_dns.default = "tls://1.0.0.1"
remote_dns.default = "tls://208.67.220.220"
remote_dns:value("tls://8.8.8.8", "8.8.8.8 (Google DNS)")
remote_dns:value("tls://8.8.4.4", "8.8.4.4 (Google DNS)")
remote_dns:value("tls://1.1.1.1", "1.1.1.1 (CloudFlare DNS)")

View File

@ -13,5 +13,5 @@ config mosdns 'mosdns'
option loglv 'info'
option logfile '/tmp/mosdns.txt'
option remote_dns1 'tls://8.8.4.4'
option remote_dns2 'tls://1.0.0.1'
option remote_dns2 'tls://208.67.220.220'
option listen_port '5335'

View File

@ -110,23 +110,19 @@ plugins:
- matches: has_resp
exec: accept
# fallback 用本地服务器 sequence
# 返回不包含本地 ip 则 reject
- tag: query_is_local_ip
type: sequence
args:
- exec: $local_sequence
- matches: resp_ip $geoip_cn
exec: accept
- exec: reject
- matches: "!resp_ip $geoip_cn"
exec: drop_resp
# fallback 用远程服务器 sequence
- tag: query_is_remote
type: sequence
args:
- exec: $remote_sequence
- exec: accept
# fallback 用远程服务器 sequence
- tag: fallback

View File

@ -1180,7 +1180,6 @@
139wanke.com
139y.com
139zhuti.com
13cg.com
13cr.com
13ejob.com
13gm.com
@ -1925,7 +1924,6 @@
20z.com
21-rent.com
21-sun.com
210166.com
210997.com
210z.com
2113.net
@ -2578,12 +2576,9 @@
3323399.com
332831.com
333-555.com
3331909.com
3332025.com
3332219.com
3332235.com
3332358.com
3332600.com
333333.com
3335665.com
33360.com
@ -4841,6 +4836,7 @@
5earena.com
5earenacdn.com
5eplay.com
5eplaycdn.com
5etv.com
5ewin.com
5fen.com
@ -5724,7 +5720,6 @@
7hon.com
7huang.org
7i2.com
7icp.com
7ipr.com
7jia.com
7jia2.com
@ -6842,7 +6837,6 @@
98t.net
98weixin.com
98znz.com
99-ss.com
99.com
99083.com
99114.com
@ -13939,7 +13933,6 @@ chinaaet.com
chinaagrisci.com
chinaagv.com
chinaairer.com
chinaalex.com
chinaamc.com
chinaamuse.com
chinaanonymous.com
@ -15415,7 +15408,6 @@ cn360cn.com
cn365c.com
cn365d.com
cn365e.com
cn3k5.com
cn3wm.com
cn486.com
cn4e.com
@ -17466,7 +17458,6 @@ dangbei.net
dangbeiprojector.com
dangcdn.com
dangdang.com
dangfudh.xyz
dangguai.com
danghongyun.com
danghuan.com
@ -19501,7 +19492,6 @@ duobiji.com
duocaitou.com
duochang.cc
duodaa.com
duodada.com
duodanke.com
duodaoertong.com
duodian.com
@ -21823,7 +21813,6 @@ fengeek.com
fengeini.com
fengex.com
fengfeng.cc
fenggeba.com
fenghenever.com
fenghong.tech
fenghuaju.cc
@ -23622,6 +23611,7 @@ ggac.net
ggcida.com
ggcj.com
ggcykf.com
ggdata.com
ggemo.com
ggerg.com
ggeye.com
@ -28319,7 +28309,6 @@ huomao.com
huomaqun.com
huoming.com
huopinyuan.com
huoqiuapp.com
huosdk.com
huoshan.cc
huoshan.club
@ -28337,7 +28326,6 @@ huotan.com
huowan.com
huoxing24.com
huoxingba.com
huoxingtan66.com
huoxingzi.com
huoxun.com
huoyan.com
@ -28617,6 +28605,7 @@ hzamcare.com
hzapuqi.com
hzbenet.com
hzbh.com
hzbianqing.com
hzbike.com
hzbook.com
hzbxm.com
@ -28665,7 +28654,6 @@ hzjmjl.com
hzjqhy.com
hzjs56.com
hzjunglepay.com
hzjunxing.com
hzkayo.com
hzkshx.com
hzkuangxiangzi.com
@ -30341,7 +30329,6 @@ iraoping.com
ircmnr.com
ireader.com
ireadercity.com
ireaderm.net
ireadweek.com
ireadyit.com
irealbest.com
@ -31363,7 +31350,6 @@ jhrdqx.com
jhsbggw.com
jhscm.com
jhscrm.com
jhsctv.com
jhsfojiao.com
jhsjtxx.com
jhssapp.com
@ -32206,7 +32192,6 @@ jiuzhang.com
jiuzheng.com
jiuzhilan.com
jiuzhinews.com
jiuzhu999.com
jiuzungame.com
jiwa123.com
jiwanjiwan.com
@ -32770,7 +32755,6 @@ jshrconsult.com
jshsoft.com
jshuachen.com
jshy.com
jsielxo.com
jsifaja.com
jsimg.cc
jsinfo.net
@ -33522,6 +33506,7 @@ kamenwang.com
kamidm.com
kamidox.com
kamopos.com
kan.cc
kan0512.com
kan300.com
kanbaobei.com
@ -35860,6 +35845,7 @@ lib520.com
liba.com
libaclub.com
libai.com
libaidns.com
libaopay.com
libinx.com
libisky.com
@ -40055,7 +40041,6 @@ mywood.cc
myworld6.com
myxypt.com
myyishu.com
myyj.net
myyoudao.com
myypark.com
myyx618.com
@ -40599,7 +40584,6 @@ nfschina.com
nfwin.com
nfyk.com
nfzhouyi.com
nfzmbrand.com
ng-alain.com
nga.wiki
ngabbs.com
@ -44527,7 +44511,6 @@ qq933.com
qqaiqin.com
qqaku.com
qqan.com
qqapk.com
qqba.com
qqbiaoqing.com
qqbiaoqing8.com
@ -44822,6 +44805,7 @@ quegame.com
quegoo.com
quegui.run
queji.tw
queniuaa.com
queniubg.com
queniubm.com
queniucf.com
@ -44833,6 +44817,7 @@ queniuhy.com
queniuiq.com
queniukr.com
queniukw.com
queniupl.com
queniuqy.com
queniurc.com
queniusa.com
@ -46567,7 +46552,6 @@ sd5g.com
sdailong.com
sdbao.com
sdbeta.com
sdbykqn.com
sdbys.com
sdca119.com
sdchem.net
@ -50934,7 +50918,6 @@ tb888.net
tbadc.com
tbankw.com
tbcache.com
tbdazhe.com
tbh5.com
tbhcc.com
tbhelper.com
@ -55167,7 +55150,6 @@ webpackjs.com
webpiaoliang.com
webportal.cc
webpowerchina.com
webppd.com
webqxs.com
webrtc.win
webs.so
@ -56376,7 +56358,6 @@ wm18.com
wmc-bj.net
wmcloud.com
wmcn.com
wmedias.com
wmiao.com
wming.com
wmiyx.com
@ -56739,6 +56720,7 @@ wqop2018.com
wqqwmw.com
wqrlink.tech
wqxuetang.com
wqycq.com
wqyunpan.com
wqzx.net
wrating.com
@ -57219,7 +57201,6 @@ wxt2020.com
wxthe.com
wxtj10086.com
wxtpb.com
wxuse.com
wxw120.com
wxwzt.com
wxy1314.com
@ -58326,6 +58307,7 @@ xifu120.com
xifumi.com
xifuquan.com
xigeweb.com
xigou100.com
xigua110.com
xiguabook.com
xiguaimg.com
@ -60090,7 +60072,6 @@ yatiwang.com
yatsenglobal.com
yatsoft.com
yawancaiwu.com
yawenb.com
yaxi.net
yaxige.com
yaxinde.com
@ -60686,6 +60667,7 @@ yimin.biz
yimin168.com
yimincaifu.com
yiminchaoshi.com
yimingkeji.net
yimingzhi.net
yimininfo.com
yiminjiayuan.com
@ -61409,6 +61391,7 @@ youchejiuxing.com
youchent.com
youcheyihou.com
youchuhuodong.com
youcloud.com
youda8.com
youdaili.net
youdaiw.com
@ -61547,7 +61530,6 @@ yousenjiaoyu.com
youshang.com
youshanmeishi.com
yousheng.shop
yousheng8.com
youshenhudong.com
yousheyoujia.com
youshifu.com
@ -61692,7 +61674,6 @@ youzibuy.com
youzijie.com
youziku.com
youzikuaibao.com
youziqk.com
youzu.com
yovisun.com
yovocloud.com
@ -64736,6 +64717,7 @@ znyp.com
znyseo.com
znyshurufa.com
znznet.net
zo-station.com
zoassetmanagement.com
zocai.com
zodiac.wang
@ -64835,7 +64817,6 @@ zpidc.com
zpjiashuo.com
zplayworld.com
zpm.so
zppop.com
zppxba.com
zptong.com
zptq.com

View File

@ -3006,6 +3006,7 @@ aeasyshop.com
aebn.com
aebn.net
aeg
aei.org
aenhancers.com
aeon-pool.com
aerogardcn.com
@ -30273,7 +30274,6 @@ www.adultcamweb.com
www.advertisergleam.com
www.advertstream.com
www.advisen.com
www.aei.org
www.aerilon.com
www.aeromatasia.com
www.aevpn.com

File diff suppressed because it is too large Load Diff

View File

@ -11,8 +11,8 @@ PKG_NAME:=luci-app-netspeedtest
LUCI_TITLE:=LuCI Support for netspeedtest
LUCI_DEPENDS:=+python3 +iperf3 +homebox +netperf
LUCI_PKGARCH:=all
PKG_VERSION:=2.1.2
PKG_RELEASE:=20230121
PKG_VERSION:=2.1.3
PKG_RELEASE:=20230302
PKG_MAINTAINER:=<https://github.com/sirpdboy/netspeedtest>
include $(TOPDIR)/feeds/luci/luci.mk

View File

@ -46,7 +46,19 @@ luci-app-netspeedtest 网络速度诊断测试(包括:内网网页版测速
## 版本说明
### 2022.10.18 网速测试V2.0.2
### 2023.3.2 网速测试V2.1.3
- 修复测速Speedtest看不到测试报名问题。
- 重新调试IPERF3测试页面代码解决某些主题显示不优雅的问题。
- 修复取消服务自动启用的问题
### 2023.1.15 网速测试V2.1
- 内网测试速度WEB页采用homebox。
- 修复WEB页内网测试自动启用问题。
- 外网测速加入Netperf测试。
- 外网测速Speedtest某些节点会禁止测速。要测速建议关了留国的插件。
### 2022.10.18 网速测试V2.0.3
- 代码基本重写和优化。
- Iperf3可实时体现服务状态。
- 增加内网测试网页版。
@ -60,26 +72,7 @@ luci-app-netspeedtest 网络速度诊断测试(包括:内网网页版测速
将NetSpeedTest 主题添加至 LEDE/OpenWRT 源码的方法。
### 下载源码方法一:
- 编辑源码文件夹根目录feeds.conf.default并加入如下内容:
```Brach
# feeds获取源码
src-git netspeedtest https://github.com/sirpdboy/netspeedtest
```
```Brach
# 更新feeds并安装主题
scripts/feeds update netspeedtest
scripts/feeds install netspeedtest
```
### 下载源码方法二:
```Brach
### 下载源码:
# 下载源码
@ -136,7 +129,7 @@ luci-app-netspeedtest 网络速度诊断测试(包括:内网网页版测速
## 感谢
感谢superspeed、user1121114685、ZeaKyX、佐须之男、lean等。因为有你们珠玉在前
感谢sivel、superspeed、user1121114685、ZeaKyX、佐须之男、lean等。因为有你们珠玉在前
## 捐助

View File

@ -1,7 +1,7 @@
#!/bin/sh /etc/rc.common
#
# Copyright (C) 2020-2022 sirpdboy <herboy2008@gmail.com> https://github.com/sirpdboy/netspeedtest
# Copyright (C) 2020-2023 sirpdboy <herboy2008@gmail.com> https://github.com/sirpdboy/netspeedtest
# This is free software, licensed under the Apache License, Version 2.0 .
#
@ -40,7 +40,7 @@ nstest() {
limit_log $LOG 200
init_env
touch $LOCK
echo -ne "\n speedtest测速" | tee -a $LOG
echo -ne "\n speedtest测速" >> $LOG
/usr/bin/speedtest --share > $TMP_T
echo -ne "\n 测服信息:$(cat $TMP_T | grep 'Hosted by'| cut -c10- | awk -F: '{printf $1}') 延时:$(cat $TMP_T | grep 'Hosted by' | awk -F: '{printf $2}')" >> $LOG
echo -ne "\n 下行速率:$(cat $TMP_T | grep 'Download:' |awk -F: '{printf $2}' )" >> $LOG
@ -71,7 +71,7 @@ start_service() {
procd_open_instance
procd_set_param command $PROG
[ "x$logger" == x1 ] && procd_set_param stderr 1
procd_set_param respawn
# procd_set_param respawn
procd_close_instance
}

15
luci-app-rtbwmon/Makefile Normal file
View File

@ -0,0 +1,15 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.0.0-1
PKG_RELEASE:=
PKG_MAINTAINER:=jjm2473 <jjm2473@gmail.com>
LUCI_TITLE:=LuCI realtime client bandwidth monitor
LUCI_PKGARCH:=all
LUCI_DEPENDS:=+iptables
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -0,0 +1 @@
LuCI realtime traffic monitor, inspired by luci-app-wrtbwmon

View File

@ -0,0 +1,526 @@
(function () {
const numberCol = 3;
const wrt = {
// variables for auto-update, interval is in seconds
scheduleTimeout: undefined,
interval: 5,
// option on whether to show per host sub-totals
perHostTotals: false,
paused: false,
headers: [],
// variables for sorting
sortData: {
column: numberCol,
elId: 'thDlb',
dir: 'desc',
},
filter: '',
ifaceFilter: '',
cache: {},
};
let oldDate, oldValues, oldValuesSeconds;
const basePath = "/cgi-bin/luci/admin/status/rtbwmon"
//----------------------
// HELPER FUNCTIONS
//----------------------
/**
* Human readable text for size
* @param size
* @returns {string}
*/
const getSize = function(size, suffix) {
let prefix = [' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z'];
let precision, base = 1000, pos = 0;
while (size > base) {
size /= base;
pos++;
}
if (pos > 2) precision = 1000; else precision = 1;
return (Math.round(size * precision) / precision) + ' ' + prefix[pos] + suffix;
};
/**
* Human readable text for date
* @param date
* @returns {string}
*/
const dateToString = function(date) {
return date.toString().substring(0, 24);
};
/**
* Gets the string representation of the date received from BE
* @param value
* @returns {*}
*/
const getDateString = function(value) {
let tmp = value.split('_'),
str = tmp[0].split('-').reverse().join('-') + 'T' + tmp[1];
return dateToString(new Date(str));
};
/**
* Create a `tr` element with content
* @param content
* @returns {string}
*/
const createTR = function(content) {
let res = document.createElement('tr');
res.classList.add("tr");
res.replaceChildren(...content)
return res;
};
/**
* Create a `td` element with content and options
* @param content
* @param opts
* @returns {string}
*/
const createTD = function(content, opts) {
opts = opts || {};
let res = document.createElement('td');
if (opts.right) {
res.align="right";
}
if (opts.dataTitle) {
res.setAttribute("data-title", opts.dataTitle);
}
res.classList.add("td");
if (opts.title) {
res.title=opts.title;
res.classList.add("more_info");
}
res.innerHTML = content;
return res;
};
const createTH = function(content, opts) {
opts = opts || {};
let res = document.createElement('th');
if (opts.right) {
res.align = "right";
}
if (opts.id) {
res.id = opts.id;
}
res.classList.add("th");
res.innerHTML = content;
return res;
};
/**
* Returns true if obj is instance of Array
* @param obj
* @returns {boolean}
*/
const isArray = function(obj) {
return obj instanceof Array;
};
//----------------------
// END HELPER FUNCTIONS
//----------------------
// UI
// TABLE
const rowToTr = function(row) {
let iptitle = undefined;
if (wrt.perHostTotals && row[numberCol+5].length>1) {
iptitle = row[numberCol+5].join('\n');
}
// create displayData
let displayData = [
createTD(row[0] + '<br>' + row[7], {title: iptitle, dataTitle: wrt.headers[0].title}),
createTD(row[1], {dataTitle: wrt.headers[1].title}),
createTD(getSize(row[numberCol], 'Bps'), {right: true, dataTitle: wrt.headers[2].title}),
createTD(getSize(row[numberCol+1], 'pps'), {right: true, dataTitle: wrt.headers[3].title}),
createTD(getSize(row[numberCol+2], 'Bps'), {right: true, dataTitle: wrt.headers[4].title}),
createTD(getSize(row[numberCol+3], 'pps'), {right: true, dataTitle: wrt.headers[5].title}),
];
// display row data
return createTR(displayData);
};
const filterData = function(data) {
if (wrt.filter == '') {
return data;
}
let value = wrt.filter;
return data.filter(row=>
(row[numberCol+4] && row[numberCol+4].toLowerCase().indexOf(value.toLowerCase()) > -1) || (row[0].indexOf(value) > -1) || (row[1].toLowerCase().indexOf(value.toLowerCase()) > -1) ||
(wrt.perHostTotals && row[numberCol+5].length>1 && row[numberCol+5].some(ip=>ip.indexOf(value) > -1))
)
};
const filterIface = function(data) {
if (wrt.ifaceFilter == '') {
return data;
}
let value = wrt.ifaceFilter;
return data.filter(row=>value==row[2]);
};
/**
* Calculates per host sub-totals and adds them in the data input
* @param data The data input
*/
const aggregateHostTotals = function(data) {
if (!wrt.perHostTotals) return data;
let m = data.reduce((m, row)=>{
let mac = row[1];
let ary = m[mac];
if (ary) {
ary.push(row);
} else {
m[mac] = [row];
}
return m;
}, {});
let merged = [];
for (let mac in m) {
if (m.hasOwnProperty(mac)) {
let rows = m[mac];
rows.sort(sortingFunction);
let mrow = rows[0].slice(); // clone
mrow.push([mrow[0]]); // ip s
rows.slice(1).reduce((m, row)=>{
if (!m[numberCol+4] && row[numberCol+4]) {
m[numberCol+4] = row[numberCol+4]; // hostname
}
m[m.length-1].push(row[0]);
for (let i=0; i<4; ++i) {
m[numberCol+i] += row[numberCol+i];
}
return m;
}, mrow);
merged.push(mrow);
}
}
return merged;
};
/**
* Sorting function used to sort the `data`. Uses the global sort settings
* @param x first item to compare
* @param y second item to compare
* @returns {number} 1 for desc, -1 for asc, 0 for equal
*/
const sortingFunction = function(x, y) {
// get data from global variable
let sortColumn = wrt.sortData.column, sortDirection = wrt.sortData.dir;
let a = x[sortColumn];
let b = y[sortColumn];
if (a === b) {
return 0;
} else if (sortDirection === 'desc') {
return a < b ? 1 : -1;
} else {
return a > b ? 1 : -1;
}
};
/**
* Renders the table body
* @param data
* @param totals
*/
const renderTableData = function(data) {
if (!isArray(data)) data=[];
// sort data
data = filterData(aggregateHostTotals(filterIface(data)))
data.sort(sortingFunction);
// display data
let table = document.getElementById('clients');
table.replaceChildren(...data.map(rowToTr));
};
// HEADER
const updateHeader = function() {
// set sorting arrows
let th = document.getElementById('theader').firstElementChild;
while(th) {
th.firstElementChild.innerHTML = "&#x3000;";
th = th.nextElementSibling;
}
let el = document.getElementById(wrt.sortData.elId);
if (el) {
el.firstElementChild.innerHTML = (wrt.sortData.dir === 'desc' ? '&#x25BC;' : '&#x25B2;');
}
};
/**
* Sets the relevant global sort variables and re-renders the table to apply the new sorting
* @param elId
* @param column
*/
const setSortColumn = function(elId, column) {
if (column === wrt.sortData.column) {
// same column clicked, switch direction
wrt.sortData.dir = wrt.sortData.dir === 'desc' ? 'asc' : 'desc';
} else {
// change sort column
wrt.sortData.column = column;
// reset sort direction
wrt.sortData.dir = 'desc';
}
wrt.sortData.elId = elId;
updateHeader();
// render table data from cache
renderTableData(wrt.cache.data);
};
/**
* Registers the table events handlers for sorting when clicking the column headers
*/
const registerTableEventHandlers = function() {
// note these ordinals are into the data array, not the table output
document.getElementById('thIp').addEventListener('click', function () {
setSortColumn(this.id, 0); // ip
});
document.getElementById('thMac').addEventListener('click', function () {
setSortColumn(this.id, 1); // mac
});
document.getElementById('thDlb').addEventListener('click', function () {
setSortColumn(this.id, numberCol); // dl speed
});
document.getElementById('thDlp').addEventListener('click', function () {
setSortColumn(this.id, numberCol+1); // dl pps
});
document.getElementById('thUpb').addEventListener('click', function () {
setSortColumn(this.id, numberCol+2); // ul speed
});
document.getElementById('thUpp').addEventListener('click', function () {
setSortColumn(this.id, numberCol+3); // ul pps
});
};
const initHeader = function() {
// set sorting arrows
let theader = document.getElementById('theader');
theader.replaceChildren(...wrt.headers.map(h=>createTH(h.title, h)).map(th=>{
th.appendChild(document.createElement("span"));
return th;
}));
};
// TOOLBAR
/**
* Registers DOM event listeners for user interaction
*/
const addEventListeners = function() {
document.getElementById('perHostTotals').addEventListener('change', function () {
wrt.perHostTotals = this.checked;
renderTableData(wrt.cache.data);
});
document.getElementById('pause_checkbox').addEventListener('change', function () {
wrt.paused = this.checked;
});
document.getElementById('iface_select').addEventListener('change', function () {
wrt.ifaceFilter = this.value;
renderTableData(wrt.cache.data);
});
const submitFilter = function(value) {
if (wrt.filter != value) {
wrt.filter = value;
renderTableData(wrt.cache.data);
}
};
let filterInput = document.getElementById('filter_input');
filterInput.addEventListener('keypress', function(event){
if (event.key === 'Enter')
submitFilter(this.value);
});
filterInput.addEventListener('blur', function(){
submitFilter(this.value);
});
};
// model
/**
* Handle the error that happened during the call to the BE
*/
const handleError = function() {
// TODO handle errors
// let message = 'Something went wrong...';
};
/**
* Handle the new `values` that were received from the BE
* @param values
* @returns {string}
*/
const handleValues = function(values) {
if (!isArray(values)) return;
// find data and totals
let data = parseValues(values);
// store them in cache for quicker re-rendering
wrt.cache.data = data;
renderTableData(data);
};
/**
* Parses the values and returns a data array, where each element in the data array is an array with two elements,
* and a totals array, that holds aggregated values for each column.
* The first element of each row in the data array, is the HTML output of the row as a `tr` element
* and the second is the actual data:
* [ result, data ]
* @param values The `values` array
* @returns {Array}
*/
const parseValues = function(values) {
return values.map(parseValueRow).filter(a=>a!=null);
};
/**
* Parse each row in the `values` array and return an array with two elements.
* The first element is the HTML output of the row as a `tr` element and the second is the actual data
* [ result, data ]
* @param data A row from the `values` array
* @returns {[ string, [] ]}
*/
const parseValueRow = function(data) {
// check if data is array
if (!isArray(data)) return null;
// find download and upload speeds
let dlSpeed = 0, upSpeed = 0;
let dlPs = 0, upPs = 0;
let seconds = oldValuesSeconds;
if (typeof(seconds) !== 'undefined') {
// find old data
let oldData;
for (let i = 0; i < oldValues.length; i++) {
let cur = oldValues[i];
// compare mac addresses and ip addresses
if (oldValues[i][0] === data[0] && oldValues[i][1] === data[1]) {
oldData = cur;
break;
}
}
if (typeof(oldData) === 'undefined') {
// new ip
oldData = [0,0,0,0,0,0,0,0,0,0,0,0,0];
}
upPs = Math.max(0, data[numberCol] - oldData[numberCol]) / seconds;
upSpeed = Math.max(0, data[numberCol+1] - oldData[numberCol+1]) / seconds;
dlPs = Math.max(0, data[numberCol+2] - oldData[numberCol+2]) / seconds;
dlSpeed = Math.max(0, data[numberCol+3] - oldData[numberCol+3]) / seconds;
}
// create rowData [ip, mac, iface, dlSpeed, dlPs, upSpeed, upPs, hostname]
let rowData = [data[0], data[1], data[2], dlSpeed, dlPs, upSpeed, upPs, data[numberCol+4]];
return rowData;
};
const httpGet = function(url, cb, onerror) {
let ajax = new XMLHttpRequest();
ajax.onreadystatechange = function () {
// noinspection EqualityComparisonWithCoercionJS
if (this.readyState === XMLHttpRequest.DONE) {
cb(this.status, this.responseText);
}
};
ajax.open('GET', url, true);
try {
ajax.send();
} catch (err) {
onerror && onerror(err)
}
};
/**
* Fetches and handles the updated `values` from the BE
*/
const receiveData = function() {
if (wrt.paused) {
reschedule();
return
}
httpGet(basePath + '/data?t='+parseInt(new Date().getTime()/1000), function (status, responseText) {
if (status == 200) {
if (!wrt.paused) {
let v = responseText.trimEnd().split('\n')
.filter(line=>line).map(line=>{
let a = line.split(',');
for (let i=0;i<4;++i) {
a[numberCol+i] = parseInt(a[numberCol+i])
}
return a;
});
let now = new Date().getTime();
oldValuesSeconds = undefined;
if (typeof(oldValues) !== 'undefined') {
let seconds = (now - oldDate) / 1000;
if (seconds < 600) {
oldValuesSeconds = seconds;
}
}
handleValues(v);
// set old values
oldValues = v;
// set old date
oldDate = now;
}
reschedule();
}
});
};
//----------------------
// AUTO-UPDATE
//----------------------
/**
* Start auto-update schedule
*/
const reschedule = function() {
let seconds = wrt.interval || 60;
wrt.scheduleTimeout = window.setTimeout(receiveData, seconds * 1000);
};
//----------------------
// END AUTO-UPDATE
//----------------------
window.rtbwmon_init = function(headers){
wrt.headers = headers;
initHeader();
updateHeader();
// register events
addEventListeners();
// register table events
registerTableEventHandlers();
// Main entry point
httpGet(basePath + '/ifaces?t='+parseInt(new Date().getTime()/1000), function (status, responseText) {
receiveData();
let iface_select = document.getElementById('iface_select');
let selected = iface_select.value;
let ifaces = responseText.trimEnd().split('\n').filter(line=>line).map(iface=>{
let option = document.createElement('option');
option.value = iface;
option.innerHTML = iface;
if (selected == iface) {
option.selected = true;
}
return option;
});
let first = iface_select.firstElementChild;
iface_select.replaceChildren(first, ...ifaces);
}, function(err) {
alert(err);
});
};
})();

View File

@ -0,0 +1,17 @@
module("luci.controller.rtbwmon", package.seeall)
function index()
entry({"admin", "status", "rtbwmon"}, template("rtbwmon/rtbwmon"), _("Realtime Bandwidth"), 90)
entry({"admin", "status", "rtbwmon", "data"}, call("data"))
entry({"admin", "status", "rtbwmon", "ifaces"}, call("ifaces"))
end
function data()
luci.http.prepare_content("text/csv")
luci.http.write(luci.sys.exec("/usr/libexec/rtbwmon.sh update"))
end
function ifaces()
luci.http.prepare_content("text/csv")
luci.http.write(luci.sys.exec("/usr/libexec/rtbwmon.sh ifaces"))
end

View File

@ -0,0 +1,49 @@
<%+header%>
<div id="view">
<h2><%:Realtime Bandwidth%></h2>
<div class="cbi-map-descr"><%:Display the network speed of the client, and only count the external traffic%></div>
<div class="right">
<label for="pause_checkbox"><%:Pause refresh%></label>
<input id="pause_checkbox" type="checkbox">
<select id="iface_select" title="<%:Only display clients of specific network interface%>">
<option value="" selected><%:Interface...%></option>
</select>
<label for="perHostTotals"><%:Merge by MAC address%></label>
<input id="perHostTotals" type="checkbox">
<input id="filter_input" placeholder="<%:Filter...%>" class="cbi-input-text" type="text"
title="<%:Filter the data according to the hostname, IP, MAC%>">
</div>
<div class="cbi-section-node">
<table class="table">
<thead>
<tr class="tr table-titles" id="theader">
</tr>
</thead>
<tbody id="clients">
</tbody>
</table>
<style>
#theader th {
user-select: none;
cursor: pointer;
}
#clients td.more_info {
text-decoration: underline;
cursor: help;
}
</style>
</div>
</div>
<script src="/luci-static/rtbwmon/rtbwmon.js<%# ?v=PKG_VERSION %>"></script>
<script type="text/javascript">
rtbwmon_init([
{id:"thIp", title:"<%:Client IP%>"},
{id:"thMac", title:"<%:Client MAC%>"},
{id:"thDlb", title:"<%:Download speed%>"},
{id:"thDlp", title:"<%:Download packets%>"},
{id:"thUpb", title:"<%:Upload speed%>"},
{id:"thUpp", title:"<%:Upload packets%>"},
]);
</script>
<%+footer%>

View File

@ -0,0 +1,41 @@
msgid "Realtime Bandwidth"
msgstr "实时流量"
msgid "Display the network speed of the client, and only count the external traffic"
msgstr "显示客户端网速,只统计外连流量"
msgid "Pause refresh"
msgstr "暂停刷新"
msgid "Only display clients of specific network interface"
msgstr "只显示特定网络接口的客户端"
msgid "Interface..."
msgstr "接口..."
msgid "Merge by MAC address"
msgstr "按MAC地址合并"
msgid "Filter..."
msgstr "过滤..."
msgid "Filter the data according to the hostname, IP, MAC"
msgstr "按主机名、IP、MAC过滤数据"
msgid "Client IP"
msgstr "客户端 IP"
msgid "Client MAC"
msgstr "客户端 MAC"
msgid "Download speed"
msgstr "下载速度"
msgid "Download packets"
msgstr "下载包"
msgid "Upload speed"
msgstr "上传速度"
msgid "Upload packets"
msgstr "上传包"

1
luci-app-rtbwmon/po/zh_Hans Symbolic link
View File

@ -0,0 +1 @@
zh-cn

View File

@ -0,0 +1,13 @@
#!/bin/sh /etc/rc.common
USE_PROCD=1
boot() {
return 0
}
start_service() {
procd_open_instance
procd_set_param command /usr/libexec/rtbwmon.sh gc
procd_close_instance
}

View File

@ -0,0 +1,198 @@
#!/bin/sh
lookup() {
local MAC=$1
local IP=$2
local USERSFILE
local USER
for USERSFILE in /tmp/dhcp.leases /tmp/hosts /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' ')
;;
/tmp/hosts)
USER=$(grep -rhm1 "^$IP " $USERSFILE | head -1 | cut -f2 -s -d' ')
;;
*)
USER=$(grep -i "$MAC" "$USERSFILE" | cut -f2 -s -d,)
;;
esac
[ "$USER" = "*" ] && USER=
[ -n "$USER" ] && break
done
[ -z "$USER" ] && return 1
echo $USER
}
get_wan_iface() {
tail -n +2 /proc/net/route | sed -n -e 's/^\([^\t]\+\)\t00000000\t[^\t]\+\t[^\t]\+\t[^\t]\+\t[^\t]\+\t[^\t]\+\t00000000\t.*$/\1/p'
}
get_arp_excluded() {
tail -n +2 /proc/net/arp | grep -v " ${1//\./\\\.}\$" | sed -n -e 's/^\([^ ]\+\) \+0x[^ ]\+ \+0x2 \+\([^ ]\+\) .* \([^ ]\+\)$/\1\t\2\t\3/p'
}
merge() {
local arpfile="$1"
local countfile="$2"
local outfile="$3"
local pkts bytes src dest ip mac iface up down
while read pkts bytes src dest; do
if [[ "$dest" = '0.0.0.0/0' ]]; then
eval "local up_${src//[.:]/_}=\"$pkts,$bytes\""
else
eval "local down_${dest//[.:]/_}=\"$pkts,$bytes\""
fi
done < "$countfile"
while read ip mac iface; do
eval "up=\$up_${ip//[.:]/_}"
eval "down=\$down_${ip//[.:]/_}"
printf "%s,%s,%s,%s,%s,%s\n" "$ip" "$mac" "$iface" "${up:-0,0}" "${down:-0,0}" "`lookup $mac $ip`"
done < "$arpfile" > "$outfile"
}
do_clean() {
iptables -t mangle -D FORWARD -j RTBWMON_IFACE 2>/dev/null
iptables -t mangle -F RTBWMON_IFACE 2>/dev/null
iptables -t mangle -F RTBWMON_IP 2>/dev/null
iptables -t mangle -X RTBWMON_IFACE 2>/dev/null
iptables -t mangle -X RTBWMON_IP 2>/dev/null
rm -f /var/run/rtbwmon.tmp.* /var/run/rtbwmon.csv
}
do_update() {
local ip
local INTERFACE="$1"
find /var/run/rtbwmon.csv -mmin +30 2>/dev/null | grep -q . && do_clean
# init iptable
iptables -t mangle -C FORWARD -j RTBWMON_IFACE 2>/dev/null || {
iptables -t mangle -N RTBWMON_IFACE 2>/dev/null
iptables -t mangle -N RTBWMON_IP 2>/dev/null
iptables -t mangle -I FORWARD -j RTBWMON_IFACE
# iptables -t mangle -I FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j RTBWMON_IFACE
}
# if interface changed, clean chain
iptables -t mangle -C RTBWMON_IFACE -o "$INTERFACE" -j RTBWMON_IP 2>/dev/null || {
iptables -t mangle -F RTBWMON_IP
iptables -t mangle -F RTBWMON_IFACE
# iptables -t mangle -A RTBWMON_IFACE -m addrtype --dst-type LOCAL -j RETURN
iptables -t mangle -A RTBWMON_IFACE -i "$INTERFACE" -j RTBWMON_IP
iptables -t mangle -A RTBWMON_IFACE -o "$INTERFACE" -j RTBWMON_IP
}
# schedule cleaning task
/etc/init.d/rtbwmon start
# save system state
iptables -t mangle -nvxL RTBWMON_IP | tail -n +3 | grep -Fv 'Zeroing chain' | sed -e 's/ \+/\t/g' | cut -f2,3,9,10 >/var/run/rtbwmon.tmp.count
get_arp_excluded "$INTERFACE" >/var/run/rtbwmon.tmp.arp
# get ip
cut -f3 /var/run/rtbwmon.tmp.count | grep -Fv '0.0.0.0/0' >/var/run/rtbwmon.tmp.oips
cut -f1 /var/run/rtbwmon.tmp.arp >/var/run/rtbwmon.tmp.nips
# delete offline ip
grep -Fvf /var/run/rtbwmon.tmp.nips /var/run/rtbwmon.tmp.oips | while read ip; do
iptables -t mangle -D RTBWMON_IP -s "$ip" -j RETURN
iptables -t mangle -D RTBWMON_IP -d "$ip" -j RETURN
done
# add new ip
grep -Fvf /var/run/rtbwmon.tmp.oips /var/run/rtbwmon.tmp.nips | while read ip; do
iptables -t mangle -A RTBWMON_IP -s "$ip" -j RETURN
iptables -t mangle -A RTBWMON_IP -d "$ip" -j RETURN
done
merge /var/run/rtbwmon.tmp.arp /var/run/rtbwmon.tmp.count /var/run/rtbwmon.csv
rm -f /var/run/rtbwmon.tmp.*
return 0
}
update() {
local WAN_INTERFACE=`get_wan_iface`
exec 1000>/var/run/rtbwmon.lock
flock -n 1000 2>/dev/null || {
flock 1000 2>/dev/null
[ -f /var/run/rtbwmon.csv ] && {
cat /var/run/rtbwmon.csv
flock -u 1000 2>/dev/null
return 1
}
}
if [ -z "$WAN_INTERFACE" ]; then
do_clean
> /var/run/rtbwmon.csv
else
do_update "$WAN_INTERFACE" 2>/dev/null
cat /var/run/rtbwmon.csv
fi
flock -u 1000 2>/dev/null
return 0
}
clean() {
exec 1000>/var/run/rtbwmon.lock
flock 1000
do_clean
flock -u 1000
}
run_gc() {
local pid
exec 1001>/var/run/rtbwmon_gc.lock
flock -n 1001 2>/dev/null || return 0
while :; do
sleep 360 </dev/null >/dev/null 2>&1 1000>/dev/null 1001>/dev/null &
pid=$!
trap "kill $pid;trap TERM;kill -TERM $$" TERM
wait $pid
trap TERM
if ! find /var/run/rtbwmon.csv -mmin -5 2>/dev/null | grep -q .; then
break
fi
done
clean
flock -u 1001
return 0
}
show_ifaces() {
local WAN_INTERFACE=`get_wan_iface`
[ -z "$WAN_INTERFACE" ] && return 1
ip addr show scope global up | grep '^ \+inet ' | sed -n -e 's/^.* \([^ ]\+\)$/\1/p' | grep -Fv "$WAN_INTERFACE" | sort -u
}
case $1 in
"clean")
clean
;;
"update")
update
;;
"ifaces")
show_ifaces
;;
"gc")
run_gc
;;
*)
echo \
"Usage: $0 {update|clean|ifaces}
Actions:
update update and get
clean clean iptables and temp files
ifaces show up interfaces
"
;;
esac

View File

@ -21,13 +21,13 @@ define Download/geoip
HASH:=958b34017682aa28d2bf7f0368cdb62934c5623bf405d96ab12e54e320adfea0
endef
GEOSITE_VER:=20230301231917
GEOSITE_VER:=20230302073658
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
define Download/geosite
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
URL_FILE:=dlc.dat
FILE:=$(GEOSITE_FILE)
HASH:=8001890d73de401f637b28e4bb58d27431885a699251ba742ca368fb2fdaff3b
HASH:=c3cf5719a72284a43ed291039ccf93ea4455e30a2446540014926b652a792974
endef
define Package/v2ray-geodata/template

View File

@ -9,12 +9,12 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=xunyou
PKG_VERSION:=2.0.1.7
PKG_VERSION:=2.0.1.8
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)_v$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://partnerdownload.xunyou.com/routerplugin/koolshare/
PKG_HASH:=d8e084349fa0fccbeaf95b40243f47b019ac7647a2cccf16efd82368141cf37c
PKG_HASH:=1c12efb943afdd1f93a8644b6da7000209b80f6247241919119c408ee31b687f
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)_v$(PKG_VERSION)