update 2023-03-02 16:26:13
This commit is contained in:
parent
0ad1fa03db
commit
0672d5d452
|
@ -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)")
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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等。因为有你们珠玉在前!
|
||||
|
||||
## 捐助
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
LuCI realtime traffic monitor, inspired by luci-app-wrtbwmon
|
|
@ -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 = " ";
|
||||
th = th.nextElementSibling;
|
||||
}
|
||||
let el = document.getElementById(wrt.sortData.elId);
|
||||
if (el) {
|
||||
el.firstElementChild.innerHTML = (wrt.sortData.dir === 'desc' ? '▼' : '▲');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
|
@ -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
|
|
@ -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%>
|
|
@ -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 "上传包"
|
|
@ -0,0 +1 @@
|
|||
zh-cn
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue