diff --git a/package/lean/luci-app-serverchan/Makefile b/package/lean/luci-app-serverchan/Makefile
new file mode 100644
index 000000000..861d55413
--- /dev/null
+++ b/package/lean/luci-app-serverchan/Makefile
@@ -0,0 +1,23 @@
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=luci-app-serverchan
+PKG_VERSION:=2.01.3
+PKG_RELEASE:=9
+
+PKG_MAINTAINER:=tty228
+
+LUCI_TITLE:=LuCI support for serverchan
+LUCI_PKGARCH:=all
+LUCI_DEPENDS:=+iputils-arping +curl +jq
+
+define Package/$(PKG_NAME)/conffiles
+/etc/config/serverchan
+/usr/bin/serverchan/api/diy.json
+/usr/bin/serverchan/api/logo.jpg
+/usr/bin/serverchan/api/ipv4.list
+/usr/bin/serverchan/api/ipv6.list
+endef
+
+include $(TOPDIR)/feeds/luci/luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/package/lean/luci-app-serverchan/README.md b/package/lean/luci-app-serverchan/README.md
new file mode 100644
index 000000000..4d60e2d0d
--- /dev/null
+++ b/package/lean/luci-app-serverchan/README.md
@@ -0,0 +1,50 @@
+# 简介
+- 用于 OpenWRT/LEDE 路由器上进行 微信/Telegram 推送的插件
+- 支持列表:
+- 微信推送/Server酱 https://sct.ftqq.com/
+- 企业微信/应用推送 https://work.weixin.qq.com/api/doc/90000/90135/90248
+- 微信推送/WxPusher https://wxpusher.zjiecode.com/docs
+- 微信推送/推送加 http://www.pushplus.plus/
+- Telegram/BotFather https://t.me/BotFather
+- 精力有限,如需要钉钉推送、飞书推送、Bark推送等请尝试 https://github.com/zzsj0928/luci-app-pushbot
+-
+- **基于X86 OpenWrt 19.07.8 制作,不同系统不同设备,请自行修改部分代码,无测试条件无法重现的 bug 不考虑修复**
+- 依赖 iputils-arping + curl + jq 命令,安装前请 `opkg update`,小内存路由谨慎安装
+- 使用主动探测设备连接的方式检测设备在线状态,以避免WiFi休眠机制,主动探测较为耗时,**如遇设备休眠频繁,请自行调整超时设置**
+- 流量统计功能依赖 wrtbwmon ,自行选装或编译,该插件与 Routing/NAT 、Flow Offloading 冲突,开启无法获取流量,自行选择
+
+#### 主要功能
+- 路由 ip/ipv6 变动推送
+- 设备别名
+- 设备上线推送
+- 设备离线推送及流量使用情况
+- CPU 负载、温度监视
+- 定时推送设备运行状态
+- MAC 白名单、黑名单、按接口检测设备
+- 免打扰
+- 无人值守任务
+
+#### 已知问题
+- 直接关闭接口时,该接口的离线设备会忽略检测
+- 部分设备无法读取到设备名,脚本使用 `cat /var/dhcp.leases` 命令读取设备名,如果 dhcp 中不存在设备名,则无法读取设备名(如二级路由设备、静态ip设备),请使用设备名备注.
+- 基于X86 OpenWrt 19.07.8 制作,不同系统不同设备,可能会遇到各种问题
+- 潘多拉系统、或不支持 sh 的系统,请将脚本开头 `#!/bin/sh` 改为 `#!/bin/bash`,或手动安装 `sh`
+
+# Download
+- [luci-app-serverchan](https://github.com/tty228/luci-app-serverchan/releases)
+- [wrtbwmon](https://github.com/brvphoenix/wrtbwmon)
+- [luci-app-wrtbwmon](https://github.com/brvphoenix/luci-app-wrtbwmon)
+- **L大版本直接编译 luci-app-wrtbwmon ,非原版 luci 如使用以上 wrtbwmon,请注意安装版本号**
+
+#### ps
+- 新功能看情况开发,忙得头晕眼花
+- 欢迎各种代码提交
+- 提交bug时请尽量带上设备信息,日志与描述
+(如执行 `/usr/bin/serverchan/serverchan` 后的提示、日志信息、/tmp/serverchan/ipAddress 文件信息、或尝试使用 sh -x /usr/bin/serverchan/serverchan 查看详细运行信息 )
+- 三言两句恕我无能为力
+
+# Donate
+如果你觉得此项目对你有帮助,请捐助我们,以使项目能持续发展,更加完善。
+
+
+
diff --git a/package/lean/luci-app-serverchan/luasrc/controller/serverchan.lua b/package/lean/luci-app-serverchan/luasrc/controller/serverchan.lua
new file mode 100644
index 000000000..abf76d01b
--- /dev/null
+++ b/package/lean/luci-app-serverchan/luasrc/controller/serverchan.lua
@@ -0,0 +1,33 @@
+module("luci.controller.serverchan",package.seeall)
+
+function index()
+
+ if not nixio.fs.access("/etc/config/serverchan")then
+ return
+ end
+
+ entry({"admin", "services", "serverchan"}, alias("admin", "services", "serverchan", "setting"),_("微信推送"), 30).dependent = true
+ entry({"admin", "services", "serverchan", "setting"}, cbi("serverchan/setting"),_("配置"), 40).leaf = true
+ entry({"admin", "services", "serverchan", "advanced"}, cbi("serverchan/advanced"),_("高级设置"), 50).leaf = true
+ entry({"admin", "services", "serverchan", "client"}, form("serverchan/client"), "在线设备", 80)
+ entry({"admin", "services", "serverchan", "log"}, form("serverchan/log"),_("日志"), 99).leaf = true
+ entry({"admin", "services", "serverchan", "get_log"}, call("get_log")).leaf = true
+ entry({"admin", "services", "serverchan", "clear_log"}, call("clear_log")).leaf = true
+ entry({"admin", "services", "serverchan", "status"}, call("act_status")).leaf=true
+end
+
+function act_status()
+ local e={}
+ e.running=luci.sys.call("busybox ps|grep -v grep|grep -c serverchan >/dev/null")==0
+ luci.http.prepare_content("application/json")
+ luci.http.write_json(e)
+end
+
+function get_log()
+ luci.http.write(luci.sys.exec(
+ "[ -f '/tmp/serverchan/serverchan.log' ] && cat /tmp/serverchan/serverchan.log"))
+end
+
+function clear_log()
+ luci.sys.call("echo '' > /tmp/serverchan/serverchan.log")
+end
diff --git a/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/advanced.lua b/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/advanced.lua
new file mode 100644
index 000000000..c593739de
--- /dev/null
+++ b/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/advanced.lua
@@ -0,0 +1,111 @@
+local nt = require "luci.sys".net
+local fs=require"nixio.fs"
+
+m=Map("serverchan",translate("提示:"),
+translate("如果你不了解这些选项的含义,请不要修改这些选项"))
+
+s = m:section(TypedSection, "serverchan", "高级设置")
+s.anonymous = true
+s.addremove = false
+
+a=s:option(Value,"up_timeout",translate('设备上线检测超时(s)'))
+a.default = "2"
+a.optional=false
+a.datatype="uinteger"
+
+a=s:option(Value,"down_timeout",translate('设备离线检测超时(s)'))
+a.default = "20"
+a.optional=false
+a.datatype="uinteger"
+
+a=s:option(Value,"timeout_retry_count",translate('离线检测次数'))
+a.default = "2"
+a.optional=false
+a.datatype="uinteger"
+a.description = translate("若无二级路由设备,信号强度良好,可以减少以上数值
因夜间 wifi 休眠较为玄学,遇到设备频繁推送断开,烦请自行调整参数
..╮(╯_╰)╭..")
+
+a=s:option(Value,"thread_num",translate('最大并发进程数'))
+a.default = "3"
+a.datatype="uinteger"
+
+a=s:option(Value, "soc_code", "自定义温度读取命令")
+a.rmempty = true
+a:value("",translate("默认"))
+a.description = translate("请尽量避免使用特殊符号,如双引号、$、!等,执行结果需为数字,用于温度对比")
+
+a=s:option(Button,"soc",translate("测试温度命令"))
+a.inputtitle = translate("输出信息")
+a.write = function()
+ luci.sys.call("/usr/bin/serverchan/serverchan soc")
+ luci.http.redirect(luci.dispatcher.build_url("admin","services","serverchan","advanced"))
+end
+
+if nixio.fs.access("/tmp/serverchan/soc_tmp") then
+e=s:option(TextValue,"soc_tmp")
+e.rows=2
+e.readonly=true
+e.cfgvalue = function()
+ return luci.sys.exec("cat /tmp/serverchan/soc_tmp && rm -f /tmp/serverchan/soc_tmp")
+end
+end
+
+a=s:option(Flag,"err_enable",translate("无人值守任务"))
+a.default=0
+a.rmempty=true
+a.description = translate("请确认脚本可以正常运行,否则可能造成频繁重启等错误!")
+
+a=s:option(Flag,"err_sheep_enable",translate("仅在免打扰时段重拨"))
+a.default=0
+a.rmempty=true
+a.description = translate("避免白天重拨 ddns 域名等待解析,此功能不影响断网检测
因夜间跑流量问题,该功能可能不稳定")
+a:depends({err_enable="1"})
+
+a= s:option(DynamicList, "err_device_aliases", translate("关注列表"))
+a.rmempty = true
+a.description = translate("只会在列表中设备都不在线时才会执行
免打扰时段一小时后,关注设备五分钟低流量(约100kb/m)将视为离线")
+nt.mac_hints(function(mac, name) a :value(mac, "%s (%s)" %{ mac, name }) end)
+a:depends({err_enable="1"})
+
+a=s:option(ListValue,"network_err_event",translate("网络断开时"))
+a.default=""
+a:depends({err_enable="1"})
+a:value("",translate("无操作"))
+a:value("1",translate("重启路由器"))
+a:value("2",translate("重新拨号"))
+a:value("3",translate("修改相关设置项,尝试自动修复网络"))
+a.description = translate("选项 1 选项 2 不会修改设置,并最多尝试 2 次。
选项 3 会将设置项备份于 /usr/bin/serverchan/configbak 目录,并在失败后还原。
【!!无法保证兼容性!!】不熟悉系统设置项,不会救砖请勿使用")
+
+a=s:option(ListValue,"system_time_event",translate("定时重启"))
+a.default=""
+a:depends({err_enable="1"})
+a:value("",translate("无操作"))
+a:value("1",translate("重启路由器"))
+a:value("2",translate("重新拨号"))
+
+a= s:option(Value, "autoreboot_time", "系统运行时间大于")
+a.rmempty = true
+a.default = "24"
+a.datatype="uinteger"
+a:depends({system_time_event="1"})
+a.description = translate("单位为小时")
+
+a=s:option(Value, "network_restart_time", "网络在线时间大于")
+a.rmempty = true
+a.default = "24"
+a.datatype="uinteger"
+a:depends({system_time_event="2"})
+a.description = translate("单位为小时")
+
+a=s:option(Flag,"public_ip_event",translate("重拨尝试获取公网 ip"))
+a.default=0
+a.rmempty=true
+a:depends({err_enable="1"})
+a.description = translate("重拨时不会推送 ip 变动通知,并会导致你的域名无法及时更新 ip 地址
请确认你可以通过重拨获取公网 ip,否则这不仅徒劳无功还会引起频繁断网
移动等大内网你就别挣扎了!!")
+
+a= s:option(Value, "public_ip_retry_count", "当天最大重试次数")
+a.rmempty = true
+a.default = "10"
+a.datatype="uinteger"
+a:depends({public_ip_event="1"})
+
+return m
diff --git a/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/client.lua b/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/client.lua
new file mode 100644
index 000000000..9c2dafd4f
--- /dev/null
+++ b/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/client.lua
@@ -0,0 +1,6 @@
+f = SimpleForm("serverchan")
+luci.sys.call("/usr/bin/serverchan/serverchan client")
+f.reset = false
+f.submit = false
+f:append(Template("serverchan/client"))
+return f
diff --git a/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/log.lua b/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/log.lua
new file mode 100644
index 000000000..9063c55c2
--- /dev/null
+++ b/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/log.lua
@@ -0,0 +1,5 @@
+f = SimpleForm("serverchan")
+f.reset = false
+f.submit = false
+f:append(Template("serverchan/log"))
+return f
diff --git a/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/setting.lua b/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/setting.lua
new file mode 100644
index 000000000..74ffc7a42
--- /dev/null
+++ b/package/lean/luci-app-serverchan/luasrc/model/cbi/serverchan/setting.lua
@@ -0,0 +1,503 @@
+
+local nt = require "luci.sys".net
+local fs=require"nixio.fs"
+local e=luci.model.uci.cursor()
+local net = require "luci.model.network".init()
+local sys = require "luci.sys"
+local ifaces = sys.net:devices()
+
+m=Map("serverchan",translate("ServerChan"),
+translate("「Server酱」,英文名「ServerChan」,是一款从服务器推送报警信息和日志到微信的工具。
如果你在使用中遇到问题,请到这里提交:")
+.. [[]]
+.. translate("github 项目地址")
+.. [[]]
+)
+
+m:section(SimpleSection).template = "serverchan/serverchan_status"
+
+s=m:section(NamedSection,"serverchan","serverchan",translate(""))
+s:tab("basic", translate("基本设置"))
+s:tab("content", translate("推送内容"))
+s:tab("crontab", translate("定时推送"))
+s:tab("disturb", translate("免打扰"))
+s.addremove = false
+s.anonymous = true
+
+--基本设置
+a=s:taboption("basic", Flag,"serverchan_enable",translate("启用"))
+a.rmempty = true
+
+a = s:taboption("basic", MultiValue, "lite_enable", translate("精简模式"))
+a:value("device", translate("精简当前设备列表"))
+a:value("nowtime", translate("精简当前时间"))
+a:value("content", translate("只推送标题"))
+a.widget = "checkbox"
+a.default = nil
+a.optional = true
+
+a=s:taboption("basic", ListValue,"jsonpath",translate("推送模式"))
+a.default="/usr/bin/serverchan/api/serverchan.json"
+a.rmempty = true
+a:value("/usr/bin/serverchan/api/serverchan.json",translate("微信 Server酱"))
+a:value("/usr/bin/serverchan/api/qywx_mpnews.json",translate("企业微信 图文消息"))
+a:value("/usr/bin/serverchan/api/qywx_markdown.json",translate("企业微信 markdown版(不支持公众号)"))
+a:value("/usr/bin/serverchan/api/wxpusher.json",translate("微信 wxpusher"))
+a:value("/usr/bin/serverchan/api/pushplus.json",translate("微信 pushplus"))
+a:value("/usr/bin/serverchan/api/telegram.json",translate("Telegram"))
+a:value("/usr/bin/serverchan/api/diy.json",translate("自定义推送"))
+
+a=s:taboption("basic", Value,"sckey",translate('微信推送/新旧共用'), translate("").."Server酱 sendkey 点击这里
")
+a.rmempty = true
+a:depends("jsonpath","/usr/bin/serverchan/api/serverchan.json")
+
+a=s:taboption("basic", Value,"corpid",translate('企业ID(corpid)'),translate("").."获取说明 点击这里")
+a.rmempty = true
+a:depends("jsonpath","/usr/bin/serverchan/api/qywx_mpnews.json")
+a:depends("jsonpath","/usr/bin/serverchan/api/qywx_markdown.json")
+a=s:taboption("basic", Value,"userid",translate('帐号(userid)'))
+a.rmempty = true
+a.description = translate("群发到应用请填入 @all ")
+a:depends("jsonpath","/usr/bin/serverchan/api/qywx_mpnews.json")
+a:depends("jsonpath","/usr/bin/serverchan/api/qywx_markdown.json")
+a=s:taboption("basic", Value,"agentid",translate('应用id(agentid)'))
+a.rmempty = true
+a:depends("jsonpath","/usr/bin/serverchan/api/qywx_mpnews.json")
+a:depends("jsonpath","/usr/bin/serverchan/api/qywx_markdown.json")
+a=s:taboption("basic", Value,"corpsecret",translate('应用密钥(Secret)'))
+a.rmempty = true
+a:depends("jsonpath","/usr/bin/serverchan/api/qywx_mpnews.json")
+a:depends("jsonpath","/usr/bin/serverchan/api/qywx_markdown.json")
+a=s:taboption("basic", Value,"mediapath",translate('图片缩略图文件路径'))
+a.rmempty = true
+a.default = "/usr/bin/serverchan/api/logo.jpg"
+a:depends("jsonpath","/usr/bin/serverchan/api/qywx_mpnews.json")
+a.description = translate("只支持 2MB 以内 JPG,PNG 格式
900*383 或 2.35:1 为佳 ")
+
+a=s:taboption("basic",Value,"wxpusher_apptoken",translate('appToken'),translate("").."获取 appToken 点击这里
")
+a.rmempty = true
+a:depends("jsonpath","/usr/bin/serverchan/api/wxpusher.json")
+a=s:taboption("basic", Value,"wxpusher_uids",translate('uids'))
+a.rmempty = true
+a:depends("jsonpath","/usr/bin/serverchan/api/wxpusher.json")
+a=s:taboption("basic",Value,"wxpusher_topicIds",translate('topicIds(群发)'),translate("").."接口说明 点击这里
")
+a.rmempty = true
+a:depends("jsonpath","/usr/bin/serverchan/api/wxpusher.json")
+
+a=s:taboption("basic",Value,"pushplus_token",translate('pushplus_token'),translate("").."获取pushplus_token 点击这里
")
+a.rmempty = true
+a:depends("jsonpath","/usr/bin/serverchan/api/pushplus.json")
+
+a=s:taboption("basic", Value, "tg_token", translate("TG_token"),translate("").."获取机器人点击这里
与创建的机器人发一条消息,开启对话
")
+a.rmempty = true
+a:depends("jsonpath","/usr/bin/serverchan/api/telegram.json")
+a=s:taboption("basic", Value,"chat_id",translate('TG_chatid'),translate("").."获取 chat_id 点击这里")
+a.rmempty = true
+a:depends("jsonpath","/usr/bin/serverchan/api/telegram.json")
+
+a=s:taboption("basic", TextValue, "diy_json", translate("自定义推送"))
+a.optional = false
+a.rows = 28
+a.wrap = "soft"
+a.cfgvalue = function(self, section)
+ return fs.readfile("/usr/bin/serverchan/api/diy.json")
+end
+a.write = function(self, section, value)
+ fs.writefile("/usr/bin/serverchan/api/diy.json", value:gsub("\r\n", "\n"))
+end
+a:depends("jsonpath","/usr/bin/serverchan/api/diy.json")
+
+a=s:taboption("basic", Button,"__add",translate("发送测试"))
+a.inputtitle=translate("发送")
+a.inputstyle = "apply"
+function a.write(self, section)
+ luci.sys.call("cbi.apply")
+ luci.sys.call("/usr/bin/serverchan/serverchan test &")
+end
+
+a=s:taboption("basic", Value,"device_name",translate('本设备名称'))
+a.rmempty = true
+a.description = translate("在推送信息标题中会标识本设备名称,用于区分推送信息的来源设备")
+
+a=s:taboption("basic", Value,"sleeptime",translate('检测时间间隔(s)'))
+a.rmempty = true
+a.optional = false
+a.default = "60"
+a.datatype="and(uinteger,min(10))"
+a.description = translate("越短的时间时间响应越及时,但会占用更多的系统资源")
+
+a=s:taboption("basic", ListValue,"oui_data",translate("MAC设备信息数据库"))
+a.rmempty = true
+a.default=""
+a:value("",translate("关闭"))
+a:value("1",translate("简化版"))
+a:value("2",translate("完整版"))
+a:value("3",translate("网络查询"))
+a.description = translate("需下载 4.36m 原始数据,处理后完整版约 1.2M,简化版约 250kb
若无梯子,请勿使用网络查询")
+
+a=s:taboption("basic", Flag,"oui_dir",translate("下载到内存"))
+a.rmempty = true
+a:depends("oui_data","1")
+a:depends("oui_data","2")
+a.description = translate("懒得做自动更新了,下载到内存中,重启会重新下载
若无梯子,还是下到机身吧")
+
+a=s:taboption("basic", Flag,"reset_regularly",translate("每天零点重置流量数据"))
+a.rmempty = true
+
+a=s:taboption("basic", Flag,"debuglevel",translate("开启日志"))
+a.rmempty = true
+
+a= s:taboption("basic", DynamicList, "device_aliases", translate("设备别名"))
+a.rmempty = true
+a.description = translate("
请输入设备 MAC 和设备别名,用“-”隔开,如:
XX:XX:XX:XX:XX:XX-我的手机")
+
+--设备状态
+a=s:taboption("content", ListValue,"serverchan_ipv4",translate("ipv4 变动通知"))
+a.rmempty = true
+a.default=""
+a:value("",translate("关闭"))
+a:value("1",translate("通过接口获取"))
+a:value("2",translate("通过URL获取"))
+
+a = s:taboption("content", ListValue, "ipv4_interface", translate("接口名称"))
+a.rmempty = true
+a:depends({serverchan_ipv4="1"})
+for _, iface in ipairs(ifaces) do
+ if not (iface == "lo" or iface:match("^ifb.*")) then
+ local nets = net:get_interface(iface)
+ nets = nets and nets:get_networks() or {}
+ for k, v in pairs(nets) do
+ nets[k] = nets[k].sid
+ end
+ nets = table.concat(nets, ",")
+ a:value(iface, ((#nets > 0) and "%s (%s)" % {iface, nets} or iface))
+ end
+end
+a.description = translate("
一般选择 wan 接口,多拨环境请自行选择")
+
+a=s:taboption("content", TextValue, "ipv4_list", translate("ipv4 api列表"))
+a.optional = false
+a.rows = 8
+a.wrap = "soft"
+a.cfgvalue = function(self, section)
+ return fs.readfile("/usr/bin/serverchan/api/ipv4.list")
+end
+a.write = function(self, section, value)
+ fs.writefile("/usr/bin/serverchan/api/ipv4.list", value:gsub("\r\n", "\n"))
+end
+a.description = translate("
会因服务器稳定性、连接频繁等原因导致获取失败
如接口可以正常获取 IP,不推荐使用
从以上列表中随机地址访问")
+a:depends({serverchan_ipv4="2"})
+
+a=s:taboption("content", ListValue,"serverchan_ipv6",translate("ipv6 变动通知"))
+a.rmempty = true
+a.default="disable"
+a:value("0",translate("关闭"))
+a:value("1",translate("通过接口获取"))
+a:value("2",translate("通过URL获取"))
+
+a = s:taboption("content", ListValue, "ipv6_interface", translate("接口名称"))
+a.rmempty = true
+a:depends({serverchan_ipv6="1"})
+for _, iface in ipairs(ifaces) do
+ if not (iface == "lo" or iface:match("^ifb.*")) then
+ local nets = net:get_interface(iface)
+ nets = nets and nets:get_networks() or {}
+ for k, v in pairs(nets) do
+ nets[k] = nets[k].sid
+ end
+ nets = table.concat(nets, ",")
+ a:value(iface, ((#nets > 0) and "%s (%s)" % {iface, nets} or iface))
+ end
+end
+a.description = translate("
一般选择 wan 接口,多拨环境请自行选择")
+
+a=s:taboption("content", TextValue, "ipv6_list", translate("ipv6 api列表"))
+a.optional = false
+a.rows = 8
+a.wrap = "soft"
+a.cfgvalue = function(self, section)
+ return fs.readfile("/usr/bin/serverchan/api/ipv6.list")
+end
+a.write = function(self, section, value)
+ fs.writefile("/usr/bin/serverchan/api/ipv6.list", value:gsub("\r\n", "\n"))
+end
+a.description = translate("
会因服务器稳定性、连接频繁等原因导致获取失败
如接口可以正常获取 IP,不推荐使用
从以上列表中随机地址访问")
+a:depends({serverchan_ipv6="2"})
+
+
+a=s:taboption("content", Flag,"serverchan_up",translate("设备上线通知"))
+a.default=1
+a.rmempty = true
+
+a=s:taboption("content", Flag,"serverchan_down",translate("设备下线通知"))
+a.default=1
+a.rmempty = true
+
+a=s:taboption("content", Flag,"cpuload_enable",translate("CPU 负载报警"))
+a.default=1
+a.rmempty = true
+
+a= s:taboption("content", Value, "cpuload", "负载报警阈值")
+a.default = 2
+a.rmempty = true
+a:depends({cpuload_enable="1"})
+
+a=s:taboption("content", Flag,"temperature_enable",translate("CPU 温度报警"))
+a.default=1
+a.rmempty = true
+a.description = translate("请确认设备可以获取温度,如需修改命令,请移步高级设置")
+
+a= s:taboption("content", Value, "temperature", "温度报警阈值")
+a.rmempty = true
+a.default = "80"
+a.datatype="and(uinteger,min(1))"
+a:depends({temperature_enable="1"})
+a.description = translate("
设备报警只会在连续五分钟超过设定值时才会推送
而且一个小时内不会再提醒第二次")
+
+a=s:taboption("content", Flag,"client_usage",translate("设备异常流量"))
+a.default=0
+a.rmempty = true
+
+a= s:taboption("content", Value, "client_usage_max", "每分钟流量限制")
+a.default = "10M"
+a.rmempty = true
+a:depends({client_usage="1"})
+a.description = translate("设备异常流量警报(byte),你可以追加 K 或者 M")
+
+a=s:taboption("content", Flag,"client_usage_disturb",translate("异常流量免打扰"))
+a.default=1
+a.rmempty = true
+a:depends({client_usage="1"})
+
+a = s:taboption("content", DynamicList, "client_usage_whitelist", translate("异常流量关注列表"))
+nt.mac_hints(function(mac, name) a:value(mac, "%s (%s)" %{ mac, name }) end)
+a.rmempty = true
+a:depends({client_usage_disturb="1"})
+a.description = translate("请输入设备 MAC")
+
+a=s:taboption("content", Flag,"web_logged",translate("web 登录提醒"))
+a.default=0
+a.rmempty = true
+
+a=s:taboption("content", Flag,"ssh_logged",translate("ssh 登录提醒"))
+a.default=0
+a.rmempty = true
+
+a=s:taboption("content", Flag,"web_login_failed",translate("web 错误尝试提醒"))
+a.default=0
+a.rmempty = true
+
+a=s:taboption("content", Flag,"ssh_login_failed",translate("ssh 错误尝试提醒"))
+a.default=0
+a.rmempty = true
+
+a= s:taboption("content", Value, "login_max_num", "错误尝试次数")
+a.default = "3"
+a.datatype="and(uinteger,min(1))"
+a:depends("web_login_failed","1")
+a:depends("ssh_login_failed","1")
+a.description = translate("超过次数后推送提醒")
+
+a=s:taboption("content", Flag,"web_login_black",translate("自动拉黑"))
+a.default=0
+a.rmempty = true
+a:depends("web_login_failed","1")
+a:depends("ssh_login_failed","1")
+a.description = translate("直到重启前都不会重置次数,请先添加白名单")
+
+a= s:taboption("content", Value, "ip_black_timeout", "拉黑时间(秒)")
+a.default = "86400"
+a.datatype="and(uinteger,min(0))"
+a:depends("web_login_black","1")
+a.description = translate("0 为永久拉黑,慎用
如不幸误操作,请更改设备 IP 进入 LUCI 界面清空规则")
+
+a=s:taboption("content", DynamicList, "ip_white_list", translate("白名单 IP 列表"))
+a.datatype = "ipaddr"
+a.rmempty = true
+luci.ip.neighbors({family = 4}, function(entry)
+ if entry.reachable then
+ a:value(entry.dest:string())
+ end
+end)
+a:depends("web_logged","1")
+a:depends("ssh_logged","1")
+a:depends("web_login_failed","1")
+a:depends("ssh_login_failed","1")
+a.description = translate("忽略白名单登陆提醒和拉黑操作,暂不支持掩码位表示")
+
+a=s:taboption("content", TextValue, "ip_black_list", translate("IP 黑名单列表"))
+a.optional = false
+a.rows = 8
+a.wrap = "soft"
+a.cfgvalue = function(self, section)
+ return fs.readfile("/usr/bin/serverchan/api/ip_blacklist")
+end
+a.write = function(self, section, value)
+ fs.writefile("/usr/bin/serverchan/api/ip_blacklist", value:gsub("\r\n", "\n"))
+end
+a:depends("web_login_black","1")
+
+--定时推送
+a=s:taboption("crontab", ListValue,"crontab",translate("定时任务设定"))
+a.rmempty = true
+a.default=""
+a:value("",translate("关闭"))
+a:value("1",translate("定时发送"))
+a:value("2",translate("间隔发送"))
+
+a=s:taboption("crontab", ListValue,"regular_time",translate("发送时间"))
+a.rmempty = true
+for t=0,23 do
+a:value(t,translate("每天"..t.."点"))
+end
+a.default=8
+a.datatype=uinteger
+a:depends("crontab","1")
+
+a=s:taboption("crontab", ListValue,"regular_time_2",translate("发送时间"))
+a.rmempty = true
+a:value("",translate("关闭"))
+for t=0,23 do
+a:value(t,translate("每天"..t.."点"))
+end
+a.default="关闭"
+a.datatype=uinteger
+a:depends("crontab","1")
+
+a=s:taboption("crontab", ListValue,"regular_time_3",translate("发送时间"))
+a.rmempty = true
+
+a:value("",translate("关闭"))
+for t=0,23 do
+a:value(t,translate("每天"..t.."点"))
+end
+a.default="关闭"
+a.datatype=uinteger
+a:depends("crontab","1")
+
+a=s:taboption("crontab", ListValue,"interval_time",translate("发送间隔"))
+a.rmempty = true
+for t=1,23 do
+a:value(t,translate(t.."小时"))
+end
+a.default=6
+a.datatype=uinteger
+a:depends("crontab","2")
+a.description = translate("
从 00:00 开始,每 * 小时发送一次")
+
+a= s:taboption("crontab", Value, "send_title", translate("微信推送标题"))
+a:depends("crontab","1")
+a:depends("crontab","2")
+a.placeholder = "OpenWrt By tty228 路由状态:"
+a.description = translate("
使用特殊符号可能会造成发送失败")
+
+a=s:taboption("crontab", Flag,"router_status",translate("系统运行情况"))
+a.default=1
+a:depends("crontab","1")
+a:depends("crontab","2")
+
+a=s:taboption("crontab", Flag,"router_temp",translate("设备温度"))
+a.default=1
+a:depends("crontab","1")
+a:depends("crontab","2")
+
+a=s:taboption("crontab", Flag,"router_wan",translate("WAN信息"))
+a.default=1
+a:depends("crontab","1")
+a:depends("crontab","2")
+
+a=s:taboption("crontab", Flag,"client_list",translate("客户端列表"))
+a.default=1
+a:depends("crontab","1")
+a:depends("crontab","2")
+
+e=s:taboption("crontab", Button,"_add",translate("手动发送"))
+e.inputtitle=translate("发送")
+e:depends("crontab","1")
+e:depends("crontab","2")
+e.inputstyle = "apply"
+function e.write(self, section)
+luci.sys.call("cbi.apply")
+ luci.sys.call("/usr/bin/serverchan/serverchan send &")
+end
+
+--免打扰
+a=s:taboption("disturb", ListValue,"serverchan_sheep",translate("免打扰时段设置"),translate("在指定整点时间段内,暂停推送消息
免打扰时间中,定时推送也会被阻止。"))
+a.rmempty = true
+
+a:value("",translate("关闭"))
+a:value("1",translate("模式一:脚本挂起"))
+a:value("2",translate("模式二:静默模式"))
+a.description = translate("模式一停止一切检测,包括无人值守。")
+a=s:taboption("disturb", ListValue,"starttime",translate("免打扰开始时间"))
+a.rmempty = true
+
+for t=0,23 do
+a:value(t,translate("每天"..t.."点"))
+end
+a.default=0
+a.datatype=uinteger
+a:depends({serverchan_sheep="1"})
+a:depends({serverchan_sheep="2"})
+a=s:taboption("disturb", ListValue,"endtime",translate("免打扰结束时间"))
+a.rmempty = true
+
+for t=0,23 do
+a:value(t,translate("每天"..t.."点"))
+end
+a.default=8
+a.datatype=uinteger
+a:depends({serverchan_sheep="1"})
+a:depends({serverchan_sheep="2"})
+
+a=s:taboption("disturb", ListValue,"macmechanism",translate("MAC过滤"))
+a:value("",translate("disable"))
+a:value("allow",translate("忽略列表内设备"))
+a:value("block",translate("仅通知列表内设备"))
+a:value("interface",translate("仅通知此接口设备"))
+a.rmempty = true
+
+a = s:taboption("disturb", DynamicList, "serverchan_whitelist", translate("忽略列表"))
+nt.mac_hints(function(mac, name) a :value(mac, "%s (%s)" %{ mac, name }) end)
+a.rmempty = true
+a:depends({macmechanism="allow"})
+a.description = translate("AA:AA:AA:AA:AA:AA\\|BB:BB:BB:BB:BB:B 可以将多个 MAC 视为同一用户
任一设备在线后不再推送,设备全部离线时才会推送,避免双 wifi 频繁推送")
+
+a = s:taboption("disturb", DynamicList, "serverchan_blacklist", translate("关注列表"))
+nt.mac_hints(function(mac, name) a:value(mac, "%s (%s)" %{ mac, name }) end)
+a.rmempty = true
+a:depends({macmechanism="block"})
+a.description = translate("AA:AA:AA:AA:AA:AA\\|BB:BB:BB:BB:BB:B 可以将多个 MAC 视为同一用户
任一设备在线后不再推送,设备全部离线时才会推送,避免双 wifi 频繁推送")
+
+a = s:taboption("disturb", ListValue, "serverchan_interface", translate("接口名称"))
+a:depends({macmechanism="interface"})
+a.rmempty = true
+
+for _, iface in ipairs(ifaces) do
+ if not (iface == "lo" or iface:match("^ifb.*")) then
+ local nets = net:get_interface(iface)
+ nets = nets and nets:get_networks() or {}
+ for k, v in pairs(nets) do
+ nets[k] = nets[k].sid
+ end
+ nets = table.concat(nets, ",")
+ a:value(iface, ((#nets > 0) and "%s (%s)" % {iface, nets} or iface))
+ end
+end
+
+a=s:taboption("disturb", ListValue,"macmechanism2",translate("MAC过滤2"))
+a:value("",translate("disable"))
+a:value("MAC_online",translate("列表内任意设备在线时免打扰"))
+a:value("MAC_offline",translate("列表内设备都离线后免打扰"))
+a.rmempty = true
+
+a = s:taboption("disturb", DynamicList, "MAC_online_list", translate("在线免打扰列表"))
+nt.mac_hints(function(mac, name) a:value(mac, "%s (%s)" %{ mac, name }) end)
+a.rmempty = true
+a:depends({macmechanism2="MAC_online"})
+
+a = s:taboption("disturb", DynamicList, "MAC_offline_list", translate("任意离线免打扰列表"))
+nt.mac_hints(function(mac, name) a:value(mac, "%s (%s)" %{ mac, name }) end)
+a.rmempty = true
+a:depends({macmechanism2="MAC_offline"})
+
+return m
diff --git a/package/lean/luci-app-serverchan/luasrc/view/serverchan/log.htm b/package/lean/luci-app-serverchan/luasrc/view/serverchan/log.htm
new file mode 100644
index 000000000..56fe70d65
--- /dev/null
+++ b/package/lean/luci-app-serverchan/luasrc/view/serverchan/log.htm
@@ -0,0 +1,33 @@
+<%
+local dsp = require "luci.dispatcher"
+-%>
+
+
+
diff --git a/package/lean/luci-app-serverchan/luasrc/view/serverchan/serverchan_status.htm b/package/lean/luci-app-serverchan/luasrc/view/serverchan/serverchan_status.htm
new file mode 100644
index 000000000..e36561dd0
--- /dev/null
+++ b/package/lean/luci-app-serverchan/luasrc/view/serverchan/serverchan_status.htm
@@ -0,0 +1,22 @@
+
+
+
diff --git a/package/lean/luci-app-serverchan/root/etc/config/serverchan b/package/lean/luci-app-serverchan/root/etc/config/serverchan
new file mode 100644
index 000000000..a9a53d9be
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/etc/config/serverchan
@@ -0,0 +1,11 @@
+
+config serverchan 'serverchan'
+ option serverchan_enable '0'
+ option sleeptime '60'
+ option serverchan_ipv6 '0'
+ option serverchan_up '1'
+ option serverchan_down '1'
+ option cpuload_enable '1'
+ option cpuload '2'
+ option temperature_enable '0'
+
diff --git a/package/lean/luci-app-serverchan/root/etc/init.d/serverchan b/package/lean/luci-app-serverchan/root/etc/init.d/serverchan
new file mode 100755
index 000000000..2631e4f61
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/etc/init.d/serverchan
@@ -0,0 +1,26 @@
+#!/bin/sh /etc/rc.common
+
+START=99
+STOP=10
+
+start() {
+ state=`pgrep -f "/usr/bin/serverchan/serverchan"`
+ if [ ! -z "$state" ]; then
+ restart
+ else
+ /usr/bin/serverchan/serverchan &
+ fi
+ echo "serverchan is starting now ..."
+}
+
+stop() {
+ kill -9 `pgrep -f "/usr/bin/serverchan/serverchan"` 2>/dev/null
+ echo "serverchan exit ..."
+}
+
+restart(){
+ stop
+ sleep 1
+ start
+ echo "restarted."
+}
diff --git a/package/lean/luci-app-serverchan/root/etc/uci-defaults/luci-serverchan b/package/lean/luci-app-serverchan/root/etc/uci-defaults/luci-serverchan
new file mode 100755
index 000000000..72ce46dd6
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/etc/uci-defaults/luci-serverchan
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+uci -q batch <<-EOF >/dev/null
+ delete ucitrack.@serverchan[-1]
+ add ucitrack serverchan
+ set ucitrack.@serverchan[-1].init=serverchan
+ commit ucitrack
+EOF
+
+rm -rf /tmp/luci-*
+exit 0
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/diy.json b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/diy.json
new file mode 100644
index 000000000..04339ef58
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/diy.json
@@ -0,0 +1,40 @@
+{
+ "_//": "-------------------------------------------------------------------------------",
+ "_readme": "这是 自定义 api 文件,这里以 telegram 为例",
+ "_readme": "特殊符号请使用斜杠转义,变量使用 ${var} 表示",
+ "_//": "-------------------------------------------------------------------------------",
+ "_api": "【DIY 推送】",
+ "_url": "api 地址",
+ "_data": "生成的 json 文件路径,一般不需要改,如 api 不支持 json,请参考 serverchan 推送接口",
+ "_content_type": "post 内容类型,这里为 json",
+ "_//": "-------------------------------------------------------------------------------",
+ "_str_title_start": "标题粗体字开始符号",
+ "_str_title_end": "标题粗体字结束符号",
+ "_str_linefeed": "换行符号",
+ "_str_splitline": "换行+分隔符",
+ "_str_space": "空格",
+ "_str_tab": "TAB(用在行首,生成文字区块)",
+ "_//": "-------------------------------------------------------------------------------",
+ "_type":
+ {
+ "_readme": "type 对象因为需要转义变量,前后必须使用 斜杠+双引号 转义",
+ "_readme": "参照上文说明,填写下文相关参数"
+ },
+ "_//": "-------------------------------------------------------------------------------",
+
+ "url": "https://api.telegram.org/bot${tg_token}/sendMessage",
+ "data": "@${tempjsonpath}",
+ "content_type": "Content-Type: application/json",
+ "str_title_start": "",
+ "str_title_end": "",
+ "str_linefeed": "\\n",
+ "str_splitline": "\\n----\\n",
+ "str_space": " ",
+ "str_tab": " ",
+ "type":
+ {
+ "text":"\"${str_title_start}${1}${str_title_end}${str_splitline}${nowtime}${2}\"",
+ "chat_id":"\"${chat_id}\"",
+ "parse_mode":"\"HTML\""
+ }
+}
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/ip_blacklist b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/ip_blacklist
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/ip_blacklist
@@ -0,0 +1 @@
+
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/ipv4.list b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/ipv4.list
new file mode 100644
index 000000000..72081532b
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/ipv4.list
@@ -0,0 +1,6 @@
+www.cip.cc
+ipv4.ddnspod.com
+ifcfg.cn
+speed.neu.edu.cn/getIP.php
+ddns.oray.com/checkip
+www.net.cn/static/customercare/yourip.asp
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/ipv6.list b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/ipv6.list
new file mode 100644
index 000000000..5f1ca230c
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/ipv6.list
@@ -0,0 +1,5 @@
+ip.sb
+ipv6.ddnspod.com
+api-ipv6.ip.sb/ip
+speed.neu6.edu.cn/getIP.php
+v6.myip.la/json
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/logo.jpg b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/logo.jpg
new file mode 100644
index 000000000..a89fa5cc2
Binary files /dev/null and b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/logo.jpg differ
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/pushplus.json b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/pushplus.json
new file mode 100644
index 000000000..5fea8cba1
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/pushplus.json
@@ -0,0 +1,21 @@
+{
+ "_api": "这是 pushplus api 文件",
+ "_api": "【pushplus】",
+
+ "url": "http://www.pushplus.plus/send",
+ "data": "@${tempjsonpath}",
+ "content_type": "Content-Type: application/json",
+ "str_title_start": "##### ",
+ "str_title_end": "",
+ "str_linefeed": "\\n",
+ "str_splitline": "\\n----\\n",
+ "str_space": " ",
+ "str_tab": " ",
+ "type":
+ {
+ "title": "\"${1}\"",
+ "content": "\"${2}\"",
+ "token": "\"${pushplus_token}\"",
+ "template":"\"markdown\""
+ }
+}
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/qywx_markdown.json b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/qywx_markdown.json
new file mode 100644
index 000000000..525116173
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/qywx_markdown.json
@@ -0,0 +1,23 @@
+{
+ "_api": "这是企业微信 markdown 模板信息 api 文件",
+ "_api": "【企业微信】",
+
+ "url": "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=$(curl -s \"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${corpsecret}\"|/usr/bin/jq '.access_token' | sed 's/\"//g')",
+ "data": "@${tempjsonpath}",
+ "content_type": "Content-Type: application/json",
+ "str_title_start": "#### ",
+ "str_title_end": "",
+ "str_linefeed": "\\n",
+ "str_splitline": "\\n\\n",
+ "str_space": " ",
+ "str_tab": "> ",
+ "type":
+ {
+ "touser": "\"${userid}\"",
+ "msgtype": "\"markdown\"",
+ "agentid": "\"${agentid}\"",
+ "markdown": {
+ "content": "\"${1}${str_linefeed}${nowtime}${2}\""
+ }
+ }
+}
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/qywx_mpnews.json b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/qywx_mpnews.json
new file mode 100644
index 000000000..4d452a4c6
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/qywx_mpnews.json
@@ -0,0 +1,33 @@
+{
+ "_api": "这是企业微信图文信息 api 文件",
+ "_api": "【企业微信】",
+
+ "url": "\"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=$(curl -s \"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${corpsecret}\"|/usr/bin/jq '.access_token'|sed 's/\"//g')\"",
+ "data": "@${tempjsonpath}",
+ "content_type": "Content-Type: application/json",
+ "str_title_start": "",
+ "str_title_end": "
",
+ "str_linefeed": "\\n",
+ "str_splitline": "
",
+ "str_space": " ",
+ "str_tab": "",
+ "type":
+ {
+ "touser": "\"${userid}\"",
+ "msgtype": "\"mpnews\"",
+ "agentid": "\"${agentid}\"",
+ "mpnews":{
+ "articles":[
+ {
+ "title": "\"${nowtime}${str_linefeed}${1}\"",
+ "thumb_media_id": "\"`curl \"https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=$(curl -s \"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${corpid}&corpsecret=${corpsecret}\"|/usr/bin/jq '.access_token'|sed 's/\"//g')&type=image\" -F \"file=@${mediapath}\"|/usr/bin/jq '.media_id'|sed 's/\"//g'`\"",
+ "author": "\"\"",
+ "content_source_url": "\"\"",
+ "content": "\"${2}\"",
+ "digest": "\"\""
+ }
+ ]
+ },
+ "safe":0
+ }
+}
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/serverchan.json b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/serverchan.json
new file mode 100644
index 000000000..116e3f208
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/serverchan.json
@@ -0,0 +1,17 @@
+{
+ "_api": "这是 serverchan api 文件",
+ "_api": "【serverchan】",
+
+ "url": "\"https://sctapi.ftqq.com/${sckey}.send\"",
+ "data": "\"text=${1}&desp=${nowtime}${str_linefeed}${2}\"",
+ "content_type": "Content-Type:application/x-www-form-urlencoded",
+ "str_title_start": "#### ",
+ "str_title_end": "",
+ "str_linefeed": "%0D%0A%0D%0A",
+ "str_splitline": "%0D%0A%0D%0A----%0D%0A%0D%0A",
+ "str_space": " ",
+ "str_tab": " ",
+ "type":
+ {
+ }
+}
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/telegram.json b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/telegram.json
new file mode 100644
index 000000000..a8c57b040
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/telegram.json
@@ -0,0 +1,20 @@
+{
+ "_api": "这是 telegram api 文件",
+ "_api": "【telegram】",
+
+ "url": "https://api.telegram.org/bot${tg_token}/sendMessage",
+ "data": "@${tempjsonpath}",
+ "content_type": "Content-Type: application/json",
+ "str_title_start": "",
+ "str_title_end": "",
+ "str_linefeed": "\\n",
+ "str_splitline": "\\n----\\n",
+ "str_space": " ",
+ "str_tab": " ",
+ "type":
+ {
+ "text":"\"${str_title_start}${1}${str_title_end}${str_splitline}${nowtime}${2}\"",
+ "chat_id":"\"${chat_id}\"",
+ "parse_mode":"\"HTML\""
+ }
+}
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/wxpusher.json b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/wxpusher.json
new file mode 100644
index 000000000..83e1a78ee
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/api/wxpusher.json
@@ -0,0 +1,23 @@
+{
+ "_api": "这是 wxpusher api 文件",
+ "_api": "【wxpusher】",
+
+ "url": "http://wxpusher.zjiecode.com/api/send/message",
+ "data": "@${tempjsonpath}",
+ "content_type": "Content-Type: application/json",
+ "str_title_start": "#### ",
+ "str_title_end": "",
+ "str_linefeed": "\\n",
+ "str_splitline": "\\n----\\n",
+ "str_space": " ",
+ "str_tab": " ",
+ "type":
+ {
+ "summary":"\"${1}\"",
+ "content":"\"${2}\"",
+ "appToken":"\"${wxpusher_apptoken}\"",
+ "topicIds":"[\"${wxpusher_topicIds}\"]",
+ "uids":"[\"${wxpusher_uids}\"]",
+ "contentType":3
+ }
+}
diff --git a/package/lean/luci-app-serverchan/root/usr/bin/serverchan/serverchan b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/serverchan
new file mode 100755
index 000000000..f0e9a60a4
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/bin/serverchan/serverchan
@@ -0,0 +1,1246 @@
+#!/bin/sh
+
+# 读取设置文件
+function get_config(){
+ while [[ "$*" != "" ]]; do
+ eval ${1}='`uci get serverchan.serverchan.$1`' 2>/dev/null
+ shift
+ done
+}
+
+# 初始化设置信息
+function read_config(){
+ get_config "serverchan_enable" "lite_enable" "device_name" "sleeptime" "oui_data" "oui_dir" "reset_regularly" "debuglevel" "device_aliases" \
+ "serverchan_ipv4" "ipv4_interface" "serverchan_ipv6" "ipv6_interface" "serverchan_up" "serverchan_down" "cpuload_enable" "cpuload" "temperature_enable" "temperature" "client_usage" "client_usage_max" "client_usage_disturb" "client_usage_whitelist" "web_logged" "ssh_logged" "web_login_failed" "ssh_login_failed" "login_max_num" "web_login_black" "ip_white_list" "ip_black_timeout"\
+ "regular_time" "regular_time_2" "regular_time_3" "interval_time" \
+ "serverchan_sheep" "starttime" "endtime" "serverchan_whitelist" "serverchan_blacklist" "serverchan_interface" "MAC_online_list" "MAC_offline_list" \
+ "up_timeout" "down_timeout" "timeout_retry_count" "thread_num" "soc_code" "err_enable" "err_sheep_enable" "err_device_aliases" "network_err_event" "system_time_event" "autoreboot_time" "network_restart_time" "public_ip_event" "public_ip_retry_count" \
+ "jsonpath" "sckey" "corpid" "userid" "agentid" "corpsecret" "mediapath" "wxpusher_apptoken" "wxpusher_uids" "wxpusher_topicIds" "pushplus_token" "tg_token" "chat_id"
+
+ for str_version in "wrtbwmon" "iputils-arping" "curl" "iw"; do
+ eval `echo ${str_version:0:2}"_version"`=`opkg list-installed|grep -w ^${str_version}|awk '{print $3}'` 2>/dev/null
+ done
+ dir="/tmp/serverchan/" && mkdir -p ${dir}
+ tempjsonpath="/tmp/serverchan/temp.json"
+ ip_blacklist_path="/usr/bin/serverchan/api/ip_blacklist"
+ [ ! -z "$oui_dir" ] && [ "$oui_dir" -eq "1" ] && oui_base="${dir}oui_base.txt" || oui_base="/usr/bin/serverchan/oui_base.txt"
+ debuglevel=`echo "$debuglevel"` && [ -z "$debuglevel" ] && logfile="/dev/null" || logfile="${dir}serverchan.log"
+ serverchan_blacklist=`echo "$serverchan_blacklist"|sed 's/ /\n/g'` 2>/dev/null
+ serverchan_whitelist=`echo "$serverchan_whitelist"|sed 's/ /\n/g'` 2>/dev/null
+ device_aliases=`echo "$device_aliases"|sed 's/ /\n/g'|sed 's/-/ /'` 2>/dev/null
+ err_device_aliases=`echo "$err_device_aliases"|sed 's/ /\n/g'` 2>/dev/null
+ client_usage_whitelist=`echo "$client_usage_whitelist"|sed 's/ /\n/g'` 2>/dev/null
+ ip_white_list=`echo "$ip_white_list"|sed 's/ /\n/g'` 2>/dev/null
+ mark_mac_list="${MAC_online_list} ${MAC_offline_list}"
+ mark_mac_list=`echo "$mark_mac_list"|sed 's/ /\n/g'|sed 's/-/ /'` 2>/dev/null
+ ipv4_urllist=`cat /usr/bin/serverchan/api/ipv4.list` 2>/dev/null
+ ipv6_urllist=`cat /usr/bin/serverchan/api/ipv6.list` 2>/dev/null
+ [ -z "$serverchan_ipv4" ] && serverchan_ipv4=0
+ [ -z "$serverchan_ipv6" ] && serverchan_ipv6=0
+ [ "$iw_version" ] && wlan_interface=`iw dev|grep Interface|awk '{print $2}'` >/dev/null 2>&1
+ [ -z "$up_timeout" ] || [ "$up_timeout" -eq "0" ] && up_timeout="2"
+ [ -z "$down_timeout" ] || [ "$down_timeout" -eq "0" ] && down_timeout="20";down_timeout=`expr ${down_timeout} / 2 + 1`
+ [ -z "$timeout_retry_count" ] && timeout_retry_count="2";[ "$timeout_retry_count" -eq "0" ] && timeout_retry_count="1"
+ str_title_start=`/usr/bin/jq -r '.str_title_start' ${jsonpath}`
+ str_title_end=`/usr/bin/jq -r '.str_title_end' ${jsonpath}`
+ str_linefeed=`/usr/bin/jq -r '.str_linefeed' ${jsonpath}`
+ str_splitline=`/usr/bin/jq -r '.str_splitline' ${jsonpath}`
+ str_space=`/usr/bin/jq -r '.str_space' ${jsonpath}`
+ str_tab=`/usr/bin/jq -r '.str_tab' ${jsonpath}`
+ ( echo "$lite_enable"|grep -q "content" ) && str_title_start="" && str_title_end="" && str_splitline="" && str_linefeed="" && str_tab=""
+}
+
+# 初始化
+function serverchan_init(){
+ enable_detection
+ if [ -f "/usr/bin/serverchan/errlog" ]; then
+ cat /usr/bin/serverchan/errlog > ${logfile}
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】载入上次重启前日志" >> ${logfile}
+ echo "--------------------------------------------------------" >> ${logfile}
+ fi
+ down_oui &
+ deltemp
+ get_syslog
+ add_ip_black
+
+ rm -f ${dir}fd1 ${dir}sheep_usage ${dir}old_sheep_usage ${dir}client_usage_aliases ${dir}old_client_usage_aliases /usr/bin/serverchan/errlog >/dev/null 2>&1
+ [ ! -f "/usr/sbin/wrtbwmon" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】未安装 wrtbwmon ,流量统计不可用" >> ${logfile}
+ [ -z "$ip_version" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】无法获取依赖项 iputils-arping 版本号,请确认插件是否正常运行" >> ${logfile}
+ [ -z "$cu_version" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】无法获取依赖项 curl 版本号,请确认插件是否正常运行" >> ${logfile}
+ [ -z "${sckey}${tg_token}${pushplus_token}${corpid}${wxpusher_apptoken}${wxpusher_uids}${wxpusher_topicIds}" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】请填写正确的 key " >> ${logfile} && return 1
+ local interfacelist=`getinterfacelist` && [ -z "$interfacelist" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】无法正确获取接口信息,请确认插件是否正常运行" >> ${logfile}
+ return 0
+}
+
+# 推送
+function diy_send(){
+ ( ! echo "$lite_enable"|grep -q "content" ) && ( ! echo "$lite_enable"|grep -q "nowtime" ) && local nowtime=`date "+%Y-%m-%d %H:%M:%S"`
+ local diyurl=`/usr/bin/jq -r .url ${3}` && local diyurl=`eval echo ${diyurl}`
+ local type=`/usr/bin/jq -r '.type' ${3}` && local type=`eval echo ${type}`
+ local data=`/usr/bin/jq -r '.data' ${3}` && local data=`eval echo ${data}`
+ local content_type=`/usr/bin/jq -r '.content_type' ${3}`
+ /usr/bin/jq ".type + $type" ${jsonpath} > ${tempjsonpath}
+
+ /usr/bin/jq -r '.[]' ${tempjsonpath}|grep -w "null" && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】参数值错误,请检查设置项 `/usr/bin/jq -r '.' ${tempjsonpath}|grep "null"`" >> ${logfile} && return 1
+ [ -f ${tempjsonpath} ] && local logrow=$(grep -c "" ${tempjsonpath}) || local logrow="0"
+ [ $logrow -eq "0" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】json 文件生成失败,请检查文件格式" >> ${logfile} && return 1
+ /usr/bin/jq -r '.[]' ${tempjsonpath}|grep "null" && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】参数变量生成失败,请检查设置项 `/usr/bin/jq -r '.' ${tempjsonpath}|grep "null"`" >> ${logfile}
+
+ curl -X POST -H "$content_type" -d "${data}" "${diyurl}"
+}
+
+# 下载设备MAC厂商信息
+function down_oui(){
+ [ -f ${oui_base} ] && local logrow=$(grep -c "" ${oui_base}) || local logrow="0"
+ [ $logrow -lt "10" ] && rm -f ${oui_base} >/dev/null 2>&1
+ if [ ! -z "$oui_data" ] && [ "$oui_data" -ne "3" ] && [ ! -f ${oui_base} ]; then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【初始化】设备MAC厂商信息不存在,重新下载" >> ${logfile}
+ wget --no-check-certificate -t 3 -T 15 -O ${dir}oui.txt https://linuxnet.ca/ieee/oui.txt >/dev/null 2>&1
+ if [ -f ${dir}oui.txt ] && [ "$oui_data" -eq "1" ]; then
+ cat ${dir}oui.txt|grep "base 16"|grep -i "apple\|aruba\|asus\|autelan\|belkin\|bhu\|buffalo\|cctf\|cisco\|comba\|datang\|dell\|dlink\|dowell\|ericsson\|fast\|feixun\|\
+fiberhome\|fujitsu\|grentech\|h3c\|hisense\|hiwifi\|honghai\|honghao\|hp\|htc\|huawei\|intel\|jinli\|jse\|lenovo\|lg\|liteon\|malata\|meizu\|mercury\|meru\|moto\|netcore\|\
+netgear\|nokia\|omron\|oneplus\|oppo\|philips\|router_unkown\|samsung\|shanzhai\|sony\|start_net\|sunyuanda\|tcl\|tenda\|texas\|tianyu\|tp-link\|ubq\|undefine\|VMware\|\
+utstarcom\|volans\|xerox\|xiaomi\|zdc\|zhongxing\|smartisan" > ${oui_base} && echo "`date "+%Y-%m-%d %H:%M:%S"` 【初始化】设备MAC厂商信息下载成功" >> ${logfile} || echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】设备MAC厂商信息下载失败" >> ${logfile}
+ fi
+ if [ -f ${dir}oui.txt ] && [ "$oui_data" -eq "2" ]; then
+ cat ${dir}oui.txt|grep "base 16" > ${oui_base} && echo "`date "+%Y-%m-%d %H:%M:%S"` 【初始化】设备MAC厂商信息下载成功" >> ${logfile} || echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】设备MAC厂商信息下载失败" >> ${logfile}
+ fi
+ rm -f ${dir}oui.txt >/dev/null 2>&1
+ fi
+}
+
+# 清理临时文件
+function deltemp(){
+ unset title content ipAddress_logrow online_list online_mac mac_online_status
+ rm -f ${dir}title ${dir}content ${dir}tmp_downlist ${dir}send_enable.lock ${tempjsonpath} >/dev/null 2>&1
+ LockFile unlock
+ [ -f ${logfile} ] && local logrow=$(grep -c "" ${logfile}) || local logrow="0"
+ [ $logrow -gt 500 ] && sed -i '1,100d' ${logfile} && echo "`date "+%Y-%m-%d %H:%M:%S"` 【清理】日志超出上限,删除前 100 条" >> ${logfile}
+}
+
+# 检测程序开关
+function enable_detection(){
+ [ ! "$1" ] && local time_n=1
+ for i in `seq 1 $time_n`; do
+ get_config serverchan_enable;[ -z "$serverchan_enable" ] || [ "$serverchan_enable" -eq "0" ] && `/etc/init.d/serverchan stop` || sleep 1
+ done
+}
+
+# 获取 ip
+function getip(){
+ [ ! "$1" ] && return
+ if [ $1 == "wanipv4" ] ;then
+ [ ! -z "$ipv4_interface" ] && local wanIP=$(/sbin/ifconfig ${ipv4_interface}|awk '/inet addr/ {print $2}'|awk -F: '{print $2}'|grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
+ [ -z "$ipv4_interface" ] && local wanIP=$(getinterfacelist|grep '\"address\"'|grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
+ echo "$wanIP"
+ elif [ $1 == "hostipv4" ] ;then
+ function get_hostipv4()
+ {
+ local url_number=`echo "$ipv4_urllist"|wc -l`
+ local ipv4_URL=`echo "$ipv4_urllist"| sed -n "$(rand 1 $url_number)p"|sed -e 's/\r//g'`
+ [ ! -z "$ipv4_interface" ] && local hostIP=$(curl -k -s -4 --interface ${ipv4_interface} -m 5 ${ipv4_URL}) || local hostIP=$(curl -k -s -4 -m 5 ${ipv4_URL})
+ echo $hostIP|grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'|head -n1
+ }
+ local hostIP=`get_hostipv4`
+ [ -z "$hostIP" ] && local hostIP=`get_hostipv4`
+ [ -z "$hostIP" ] && local hostIP=`get_hostipv4`
+ echo $hostIP # 重试,偷懒,有空再优化
+ elif [ $1 == "wanipv6" ] ;then
+ [ ! -z "$ipv6_interface" ] && local wanIPv6=$(ip addr show ${ipv6_interface}|grep -v deprecated|grep -A1 'inet6 [^f:]'|sed -nr ':a;N;s#^ +inet6 ([a-f0-9:]+)/.+? scope global .*? valid_lft ([0-9]+sec) .*#\2 \1#p;ta'|sort -nr|head -n1|awk '{print $2}')
+ [ -z "$ipv6_interface" ] && local wanIPv6=$(ip addr show|grep -v deprecated|grep -A1 'inet6 [^f:]'|sed -nr ':a;N;s#^ +inet6 ([a-f0-9:]+)/.+? scope global .*? valid_lft ([0-9]+sec) .*#\2 \1#p;ta'|sort -nr|head -n1|awk '{print $2}')
+ echo "$wanIPv6"
+ elif [ $1 == "hostipv6" ] ;then
+ function get_hostipv6()
+ {
+ local urlv6_number=`echo "$ipv6_urllist"|wc -l`
+ local ipv6_URL=`echo "$ipv6_urllist"| sed -n "$(rand 1 $urlv6_number)p"|sed -e 's/\r//g'`
+ [ ! -z "$ipv6_interface" ] && local hostIPv6=$(curl -k -s -6 --interface ${ipv6_interface} -m 5 ${ipv6_URL}) || local hostIPv6=$(curl -k -s -6 -m 5 ${ipv6_URL})
+ echo $hostIPv6|grep -oE '([\da-fA-F0-9]{1,4}(:{1,2})){1,15}[\da-fA-F0-9]{1,4}'|head -n1
+ }
+ local hostIPv6=`get_hostipv6`
+ [ -z "$hostIPv6" ] && local hostIPv6=`get_hostipv6`
+ [ -z "$hostIPv6" ] && local hostIPv6=`get_hostipv6`
+ echo $hostIPv6 # 重试,偷懒,有空再优化
+ fi
+}
+
+# 获取接口信息
+function getinterfacelist(){
+ [ `ubus list|grep -w -i "network.interface.wan"|wc -l` -ge "1" ] && ubus call network.interface.wan status && return
+ [ `ubus list|grep -i "network.interface."|grep -v "loopback"|grep -v "wan6"|wc -l` -eq "1" ] && ubus call `ubus list|grep "network.interface."|grep -v "loopback"` status && return
+}
+
+# 获取接口在线时间
+function getinterfaceuptime(){
+ getinterfacelist|grep \"uptime\"|sed $'s/\"uptime": //g'|sed $'s/\,//g'
+}
+
+# 查询 mac 地址
+function getmac(){
+ ( echo "$tmp_mac"|grep -q "unknown" ) && unset tmp_mac # 为unknown时重新读取
+ [ -f "${dir}ipAddress" ] && [ -z "$tmp_mac" ] && local tmp_mac=`cat ${dir}ipAddress|grep -w ${1}|awk '{print $2}'|grep -v "^$"|sort -u|head -n1`
+ [ -f "${dir}tmp_downlist" ] && [ -z "$tmp_mac" ] && local tmp_mac=`cat ${dir}tmp_downlist|grep -w ${1}|awk '{print $2}'|grep -v "^$"|sort -u|head -n1`
+ [ -f "/var/dhcp.leases" ] && [ -z "$tmp_mac" ] && local tmp_mac=`cat /var/dhcp.leases|grep -w ${1}|awk '{print $2}'|grep -v "^$"|sort -u|head -n1`
+ [ -z "$tmp_mac" ] && local tmp_mac=`cat /proc/net/arp|grep "0x2\|0x6"|grep -w ${1}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1`
+ [ -z "$tmp_mac" ] && local tmp_mac="unknown"
+ echo "$tmp_mac"
+}
+
+# 查询主机名
+function getname(){
+ [ -z "$tmp_name" ] && local tmp_name=`echo "$device_aliases"|grep -i $2|awk '{print $2}'|grep -v "^$"|sort -u|head -n1`
+ [ -f "${dir}ipAddress" ] && [ -z "$tmp_name" ] && local tmp_name=`cat ${dir}ipAddress|grep -w ${1}|awk '{print $3}'|grep -v "^$"|sort -u|head -n1`
+ [ -f "${dir}tmp_downlist" ] && [ -z "$tmp_name" ] && local tmp_name=`cat ${dir}tmp_downlist|grep -w ${1}|awk '{print $3}'|grep -v "^$"|sort -u|head -n1`
+ ( ! echo "$tmp_name"|grep -q -w "unknown\|*" ) && [ ! -z "$tmp_name" ] && echo "$tmp_name" && return || unset tmp_name # 为unknown时重新读取
+ [ -f "/var/dhcp.leases" ] && [ -z "$tmp_name" ] && local tmp_name=`cat /var/dhcp.leases|grep -w ${1}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1`
+ ( ! echo "$tmp_name"|grep -q -w "unknown\|*" ) && [ ! -z "$tmp_name" ] && echo "$tmp_name" && return || unset tmp_name # 为unknown时重新读取
+ [ -z "$dhcp_config" ] && dhcp_config=`uci show dhcp|grep "ip\|mac\|name"`
+ for dhcp_config_str in "host" "domain"; do
+ local dhcp_ip_n=`echo "$dhcp_config"|grep -w ^dhcp.@${dhcp_config_str}.*ip=.${1}|sed -nr 's#^dhcp.(.*).ip.*#\1#gp'` 2>/dev/null
+ [ ! -z "$dhcp_ip_n" ] && [ -z "$tmp_name" ] && local tmp_name=`uci get dhcp.${dhcp_ip_n}.name` 2>/dev/null
+ local dhcp_mac_n=`echo "$dhcp_config"|grep -i ^dhcp.@${dhcp_config_str}.*mac=.${2}|sed -nr 's#^dhcp.(.*).mac.*#\1#gp'` 2>/dev/null
+ [ ! -z "$dhcp_mac_n" ] && [ -z "$tmp_name" ] && local tmp_name=`uci get dhcp.${dhcp_ip_n}.name` 2>/dev/null
+ [ ! -z "$tmp_name" ] && break
+ done
+ ( ! echo "$tmp_name"|grep -q -w "unknown\|*" ) && [ ! -z "$tmp_name" ] && echo "$tmp_name" && return || unset tmp_name # 为unknown时重新读取
+ [ -f "$oui_base" ] && local tmp_name=$(cat $oui_base|grep -i $(echo "$2"|cut -c 1,2,4,5,7,8)|sed -nr 's#^.*16)..(.*)#\1#gp'|sed 's/ /_/g')
+ [ ! -z "$oui_data" ] && [ "$oui_data" -eq "4" ] && local tmp_name=$(curl -sS "http://standards-oui.ieee.org/oui.txt"|grep -i $(echo "$2"|cut -c 1,2,4,5,7,8)|sed -nr 's#^.*16)..(.*)#\1#gp'|sed 's/ /_/g')
+ [ -z "$tmp_name" ] && local tmp_name="unknown"
+ echo "$tmp_name"
+}
+
+# 查询设备接口
+function getinterface(){
+ [ -f "${dir}ipAddress" ] && local ip_interface=`cat ${dir}ipAddress|grep -w ${1}|awk '{print $5}'|grep -v "^$"|sort -u|head -n1`
+ [ -f "${dir}tmp_downlist" ] && [ -z "$ip_interface" ] && local ip_interface=`cat ${dir}tmp_downlist|grep -w ${1}|awk '{print $5}'|grep -v "^$"|sort -u|head -n1`
+ if [ -z "$ip_interface" ] && [ ! -z "$wlan_interface" ]; then
+ for interface in $wlan_interface; do
+ local ip_interface=`iw dev $interface station dump 2>/dev/null|grep Station|grep -i -w ${1}|sed -nr 's#^.*on (.*))#\1#gp'` >/dev/null 2>&1
+ [ ! -z "$ip_interface" ] && echo "$ip_interface" && return
+ done
+ fi
+ [ -z "$ip_interface" ] && local ip_interface=`cat /proc/net/arp|grep "0x2\|0x6"|grep -i -w ${1}|awk '{print $6}'|grep -v "^$"|sort -u|head -n1`
+ echo "$ip_interface"
+}
+
+# ping
+function getping(){
+ [ "$iw_version" ] && local wlan_online=`iw dev ${ip_interface} station dump|grep -i -w ${ip_mac}|grep Station` >/dev/null 2>&1
+ [ "$wlan_online" ] && return 0
+ for i in `seq 1 ${3}`; do
+ ( ! echo "$ip_ms"|grep -q "ms" ) && local ip_ms=$( arping -I `cat /proc/net/arp|grep -w ${1}|awk '{print $6}'|grep -v "^$"|sort -u|head -n1` -c 20 -f -w ${2} $1 ) 2>/dev/null
+ ( ! echo "$ip_ms"|grep -q "ms" ) && local ip_ms=`ping -c 5 -w ${2} ${1}|grep -v '100% packet loss'` 2>/dev/null
+ ( ! echo "$ip_ms"|grep -q "ms" ) && sleep 1
+ done
+ ( echo "$ip_ms"|grep -q "ms" )
+}
+
+# CPU 占用率
+function getcpu(){
+ local AT=$(cat /proc/stat|grep "^cpu "|awk '{print $2+$3+$4+$5+$6+$7+$8 " " $2+$3+$4+$7+$8}')
+ sleep 3
+ local BT=$(cat /proc/stat|grep "^cpu "|awk '{print $2+$3+$4+$5+$6+$7+$8 " " $2+$3+$4+$7+$8}')
+ printf "%.01f%%" $(echo ${AT} ${BT}|awk '{print (($4-$2)/($3-$1))*100}')
+}
+
+# 获取SOC温度 (取所有传感器温度最大值)
+function soc_temp(){
+ [ -z "$soc_code" ] && local soctemp=`sensors 2>/dev/null|grep °C|sed -nr 's#^.*:.*\+(.*)°C .*#\1#gp'|sort -nr|head -n1`
+ [ -z "$soc_code" ] && [ -z "$soctemp" ] && local soctemp=`cat /sys/class/thermal/thermal_zone*/temp 2>/dev/null|sort -nr|head -n1|cut -c-2`
+ [ ! -z "$soctemp" ] && echo "$soctemp" && return
+ [ ! -z "$soc_code" ] && echo "$soc_code"|awk '{run=$0;system(run)}' 2>/dev/null
+}
+
+# 流量数据
+function usage(){
+ [ ! -f "/usr/sbin/wrtbwmon" ] || [ ! "$1" ] && return
+ if [ $1 == "update" ] ;then
+ function version_le() { test "$(echo "$@"|tr " " "\n"|sort -n|head -n 1)" == "$1"; }
+ function version_ge() { test "$(echo "$@"|tr " " "\n"|sort -r|head -n 1)" == "$1"; }
+ [ ! -z "$wr_version" ] && ( version_ge "${wr_version}" "1.2.0" ) && wrtbwmon -f ${dir}usage.db 2>/dev/null && return
+ [ ! -z "$wr_version" ] && ( version_le "${wr_version}" "1.0.0" ) || [ -z "$wr_version" ] && wrtbwmon update ${dir}usage.db 2>/dev/null && return
+ elif [ $1 == "get" ] ;then
+ [ ! -f "${dir}usage.db" ] && [ ! "$3" ] && echo `bytes_for_humans 0` && return
+ [ ! -f "${dir}usage.db" ] && [ "$3" ] && echo 0 && return
+ [ -z "$total_n" ] && total_n=`cat ${dir}usage.db|head -n1|grep "total"|sed 's/,/\n/g'|awk '/total/{print NR}'` 2>/dev/null
+ [ -z "$total_n" ] && total_n="6"
+ [ "$2" ] && local tmptotal=`cat ${dir}usage.db|sed 's/,,,/,0,0,/g'|sed 's/,,/,0,/g'|sed 's/,/ /g'|grep -i -w ${2}|awk "{print "'$'$total_n"}"|grep -v "^$"|sort -u|head -n1` 2>/dev/null
+ [ -z "$tmptotal" ] && local tmptotal="0"
+ [ ! "$3" ] && echo `bytes_for_humans ${tmptotal}` || echo "$tmptotal"
+ elif [ $1 == "down" ] ;then
+ [ "$2" ] && sed -i "/,${2},/d" ${dir}usage.db 2>/dev/null
+ fi
+}
+
+# 流量数据单位换算
+function bytes_for_humans {
+ [ ! "$1" ] && return
+ [ "$1" -gt 1073741824 ] && echo "`awk 'BEGIN{printf "%.2f\n",'$1'/'1073741824'}'` GB" && return
+ [ "$1" -gt 1048576 ] && echo "`awk 'BEGIN{printf "%.2f\n",'$1'/'1048576'}'` MB" && return
+ [ "$1" -gt 1024 ] && echo "`awk 'BEGIN{printf "%.2f\n",'$1'/'1024'}'` KB" && return
+ echo "${1} bytes"
+}
+
+# 设备异常流量检测
+function get_client_usage(){
+ [ -z "$client_usage" ] && return
+ [ "$client_usage" -ne "1" ] && return
+ [ -z "$client_usage_max" ] && return
+ [ -z "$get_client_usage_time" ] && get_client_usage_time=`date +%s`
+ ( echo $client_usage_max|sed -r 's/.*(.)$/\1/'|grep -q "K\|k" ) && client_usage_max=`expr ${client_usage_max%?} \* 1024`
+ ( echo $client_usage_max|sed -r 's/.*(.)$/\1/'|grep -q "M\|m" ) && client_usage_max=`expr ${client_usage_max%?} \* 1048576`
+ ( echo $client_usage_max|sed -r 's/.*(.)$/\1/'|grep -q "G\|g" ) && client_usage_max=`expr ${client_usage_max%?} \* 1073741824`
+ [ -z "$client_usage_disturb" ] && client_usage_disturb="0"
+ [ "$client_usage_disturb" -eq "0" ] && [ -f "${dir}ipAddress" ] && local MACLIST=`cat ${dir}ipAddress|awk '{print $2}'|grep -v "^$"|sort -u`
+ [ "$client_usage_disturb" -eq "1" ] && [ ! -z "$client_usage_whitelist" ] && local MACLIST=`echo "$client_usage_whitelist"`
+ [ -z "$MACLIST" ] && return
+
+ if [ "$((`date +%s`-$get_client_usage_time))" -ge "60" ]; then
+ > ${dir}client_usage_aliases
+ for mac in $MACLIST; do
+ ( ! cat ${dir}ipAddress|grep -q -i -w $mac|grep -v "^$"|sort -u|head -n1 ) && continue
+ echo "$mac" `usage get ${mac} bytes` >> ${dir}client_usage_aliases
+ [ -f "${dir}old_client_usage_aliases" ] && get_client_usage_bytes=`cat ${dir}old_client_usage_aliases|grep -i -w $mac|awk '{print $2}'|grep -v "^$"|sort -u|head -n1` || continue
+ [ -z "$get_client_usage_bytes" ] && get_client_usage_bytes="0"
+ if [ "$((`usage get ${mac} bytes`-$get_client_usage_bytes))" -ge "$client_usage_max" ]; then
+ local ip=`cat ${dir}ipAddress|grep -i -w $mac|awk '{print $1}'|grep -v "^$"|sort -u|head -n1`
+ local ip_name=`getname ${ip} ${mac}`
+ local tmp_usage=$(bytes_for_humans $(expr `usage get ${mac} bytes` - ${get_client_usage_bytes}))
+ local time_up=`cat ${dir}ipAddress|grep -w ${ip}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1`
+ local ip_total=`usage get $mac` && [ ! -z "$ip_total" ] && local ip_total="${str_linefeed}${str_tab}总计流量: ${str_space}${str_space}${str_space}${str_space}${ip_total}"
+ local time1=`date +%s`
+ local time1=$(time_for_humans `expr ${time1} - ${time_up}`)
+ if [ -z "$title" ]; then
+ title="${ip_name} 流量异常"
+ content="${content}${str_splitline}${str_title_start} 设备流量异常${str_title_end}${str_linefeed}${str_tab}客户端名:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP: ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC:${str_space}${str_space}${str_space}${str_space}${mac}$ip_total${str_linefeed}${str_tab}一分钟内流量: ${str_space}${str_space}${tmp_usage}${str_linefeed}${str_tab}在线时间: ${str_space}${str_space}${str_space}${str_space}${time1}"
+ elif ( echo "$title"|grep -q "流量异常" ); then
+ title="${ip_name} ${title}"
+ content="${content}${str_splitline}${str_tab}客户端名:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP: ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC:${str_space}${str_space}${str_space}${str_space}${mac}$ip_total${str_linefeed}${str_tab}一分钟内流量: ${str_space}${str_space}${str_space}${tmp_usage}${str_linefeed}${str_tab}在线时间: ${str_space}${str_space}${str_space}${str_space}${time1}"
+ else
+ title="设备状态变化"
+ content="${content}${str_splitline}${str_title_start} 设备流量异常${str_title_end}${str_linefeed}${str_tab}客户端名:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP: ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC:${str_space}${str_space}${str_space}${str_space}${mac}$ip_total${str_linefeed}${str_tab}一分钟内流量: ${str_space}${str_space}${str_space}${tmp_usage}${str_linefeed}${str_tab}在线时间: ${str_space}${str_space}${str_space}${str_space}${time1}"
+ fi
+ fi
+ done
+ cat ${dir}client_usage_aliases > ${dir}old_client_usage_aliases
+ get_client_usage_time=`date +%s`
+ fi
+}
+
+# 时间单位换算
+function time_for_humans {
+ [ ! "$1" ] && return
+ if [ "$1" -lt 60 ]; then
+ echo "${1} 秒"
+ elif [ "$1" -lt 3600 ]; then
+ local usetime_min=`expr $1 / 60`
+ local usetime_sec=`expr $usetime_min \* 60`
+ local usetime_sec=`expr $1 - $usetime_sec`
+ echo "${usetime_min} 分 ${usetime_sec} 秒"
+ elif [ "$1" -lt 86400 ]; then
+ local usetime_hour=`expr $1 / 3600`
+ local usetime_min=`expr $usetime_hour \* 3600`
+ local usetime_min=`expr $1 - $usetime_min`
+ local usetime_min=`expr $usetime_min / 60`
+ echo "${usetime_hour} 小时 ${usetime_min} 分"
+ else
+ local usetime_day=`expr $1 / 86400`
+ local usetime_hour=`expr $usetime_day \* 86400`
+ local usetime_hour=`expr $1 - $usetime_hour`
+ local usetime_hour=`expr $usetime_hour / 3600`
+ echo "${usetime_day} 天 ${usetime_hour} 小时"
+ fi
+}
+
+# 计算字符真实长度
+function length_str {
+ [ ! "$1" ] && return
+ local length_zh=`echo "$1"|awk '{print gensub(/[\u4e00-\u9FA5A-Za-z0-9_]/,"","g",$0)}'|awk -F "" '{print NF}'`
+ local length_en=`echo "$1"|awk '{print gensub(/[^\u4e00-\u9FA5A-Za-z0-9_]/,"","g",$0)}'|awk -F "" '{print NF}'`
+ echo `expr $length_zh / 3 \* 2 + $length_en`
+}
+
+# 截取字符,避免中文乱码
+function cut_str {
+ [ ! "$1" ] && return
+ [ ! "$2" ] && return
+ [ `length_str $1` -le "$2" ] && echo "$1" && return
+ local temp_length=$2
+ while [ $(length_str `echo "$1"|cut -c -$temp_length`) -lt "$2" ]; do
+ temp_length=`expr $temp_length + 1`
+ done
+ while [ $(printf "%d" \'`echo "$1"|cut -c $temp_length`) -ge "128" ] && [ $(printf "%d" \'`echo "$1"|cut -c $temp_length`) -lt "224" ]; do
+ temp_length=`expr $temp_length + 1`
+ done
+ temp_length=`expr $temp_length - 1`
+ echo $(echo "$1"|cut -c -$temp_length)"*"
+}
+
+# 随机数
+function rand(){
+ local min=$1
+ local max=$(($2- $min + 1))
+ local num=$(date +%s%N)
+ echo $(($num % $max + $min))
+}
+
+# 在线设备列表
+function serverchan_first(){
+ [ -f "${dir}ipAddress" ] && local IPLIST=`cat ${dir}ipAddress|awk '{print $1}'|grep -v "^$"|sort -u`
+ for ip in $IPLIST; do
+ read -u 5
+ {
+ down $ip
+ echo "" >&5
+ }&
+ done
+ wait
+ unset ip IPLIST
+ local IPLIST=`cat /proc/net/arp|grep "0x2\|0x6"|awk '{print $1}'|grep -v "^169.254."|grep -v "^$"|sort -u|grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'`
+ for ip in $IPLIST; do
+ read -u 5
+ {
+ up $ip
+ echo "" >&5
+ }&
+ done
+ wait
+}
+
+# 创建计划任务
+function serverchan_cron(){
+ function del_cron(){
+ ( echo `crontab -l 2>/dev/null`|grep -q "serverchan" ) && crontab -l > conf && sed -i "/serverchan/d" conf && crontab conf && rm -f conf >/dev/null 2>&1
+ }
+ function re_cron(){
+ /etc/init.d/cron stop
+ /etc/init.d/cron start
+ }
+ del_cron
+ if [ -z "$serverchan_enable" ]; then
+ re_cron
+ return
+ fi
+
+ # 重置流量
+ if [ ! -z "$reset_regularly" ] && [ "$reset_regularly" -eq "1" ]; then
+ crontab -l 2>/dev/null > conf && echo -e "0 0 * * * rm /tmp/serverchan/usage.db >/dev/null 2>&1" >> conf && crontab conf && rm -f conf >/dev/null 2>&1
+ crontab -l 2>/dev/null > conf && echo -e "0 0 * * * rm /tmp/serverchan/usage6.db >/dev/null 2>&1" >> conf && crontab conf && rm -f conf >/dev/null 2>&1
+ fi
+ [ ! -z "$regular_time_2" ] && local regular_time_2=",${regular_time_2}"
+ [ ! -z "$regular_time_3" ] && local regular_time_3=",${regular_time_3}"
+ # 定时发送
+ if [ ! -z "$regular_time" ] || [ ! -z "$regular_time_2" ] || [ ! -z "$regular_time_3" ]; then
+ crontab -l 2>/dev/null > conf && echo -e "0 $regular_time$regular_time_2$regular_time_3 * * * /usr/bin/serverchan/serverchan send &" >> conf && crontab conf && rm -f conf >/dev/null 2>&1
+ # 间隔发送
+ elif [ ! -z "$interval_time" ]; then
+ crontab -l 2>/dev/null > conf && echo -e "0 */$interval_time * * * /usr/bin/serverchan/serverchan send &" >> conf && crontab conf && rm -f conf >/dev/null 2>&1
+ fi
+ re_cron
+}
+
+# 免打扰检测
+function serverchan_disturb(){
+ [ -z "$serverchan_sheep" ] || [ -z "$starttime" ] || [ -z "$endtime" ] && return 0
+ if [ `date +%H` -ge $endtime -a $starttime -lt $endtime ] || [ `date +%H` -lt $starttime -a $starttime -lt $endtime ] || [ `date +%H` -lt $starttime -a `date +%H` -ge $endtime -a $starttime -gt $endtime ]; then
+ unset sheep_starttime
+ rm -f ${dir}sheep_usage ${dir}old_sheep_usage 2>/dev/null
+ disturb_text=`/usr/bin/jq -r '._api' ${jsonpath}`
+ return 0
+ else
+ [ -z "$sheep_starttime" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【免打扰】夜深了,该休息了" >> ${logfile} && sheep_starttime=`date +%s`
+ if [ "$serverchan_sheep" -eq "1" ] ;then
+ while [ `date +%H` -lt "$endtime" ]; do
+ enable_detection
+ sleep $sleeptime
+ done
+ elif [ "$serverchan_sheep" -eq "2" ] ;then
+ disturb_text="【免打扰】"
+ return 1
+ fi
+ fi
+}
+
+# 文件锁
+function LockFile(){
+ if [ $1 = "lock" ] ;then
+ [ ! -f "${dir}serverchan.lock" ] && > ${dir}serverchan.lock && return
+ while [ -f "${dir}serverchan.lock" ]; do
+ enable_detection 1
+ done
+ LockFile lock
+ fi
+ [ $1 = "unlock" ] && rm -f ${dir}serverchan.lock >/dev/null 2>&1
+ return 0
+}
+
+# 检测黑白名单
+function blackwhitelist(){
+ [ ! "$1" ] && return 1
+ [ -z "$serverchan_whitelist" ] && [ -z "$serverchan_blacklist" ] && [ -z "$serverchan_interface" ] && [ -z "$MAC_online_list" ] && [ -z "$MAC_offline_list" ] && return 0
+ [ ! -z "$serverchan_whitelist" ] && ( echo "$serverchan_whitelist"|grep -q -i -w $1 ) && return 1
+ [ ! -z "$serverchan_blacklist" ] && ( ! echo "$serverchan_blacklist"|grep -q -i -w $1 ) && return 1
+ [ ! -z "$serverchan_interface" ] && ( ! echo `getinterface ${1}`|grep -q -i -w $serverchan_interface ) && return 1
+ [ ! -z "$MAC_online_list" ] && [ ! -z "$mac_online_status" ] && return 1
+ [ ! -z "$MAC_online_list" ] && ( echo "$MAC_online_list"|grep -q -i -w $1 ) && return 1
+ [ ! -z "$MAC_offline_list" ] && [ -z "$mac_online_status" ] && return 1
+ return 0
+}
+
+function get_client(){
+ if [ -f "${dir}ipAddress" ]; then
+ while read line; do
+ local js_str="${js_str}"
+ local js_str="${js_str}
<%:`echo "$line"|awk '{print $3}'`%>
"
+ local tmp_mac=`echo "$line"|awk '{print $2}'`
+ local js_str="${js_str}
<%:${tmp_mac}%>
"
+ local js_str="${js_str}
<%:`echo "$line"|awk '{print $1}'`%>
"
+ local tmp_usage=`usage get ${tmp_mac}`
+ local js_str="${js_str}
<%:${tmp_usage}%>
"
+ local tmp_uptime=`echo "$line"|awk '{print $4}'`
+ local tmp_timenow=`date +%s`
+ local tmp_uptime=$(time_for_humans `expr ${tmp_timenow} - ${tmp_uptime}`)
+ local js_str="${js_str}
<%:${tmp_uptime}%>
"
+ done < ${dir}ipAddress
+ fi
+cat>/usr/lib/lua/luci/view/serverchan/client.htm<<%:在线设备列表%><%:客户端名%>
<%:MAC%>
<%:IP%>
<%:总计流量%>
<%: 在线时间%>
+$js_str
+
+EOF
+}
+
+# 重启网络服务
+function network_restart(){
+cat>${dir}network_restart</dev/null 2>&1 &
+/etc/init.d/firewall restart >/dev/null 2>&1 &
+/etc/init.d/dnsmasq restart >/dev/null 2>&1 &
+EOF
+ chmod 0755 ${dir}network_restart && ${dir}network_restart
+ rm -f ${dir}network_restart >/dev/null 2>&1
+}
+
+# 查看无人值守任务设备是否在线
+function geterrdevicealiases(){
+ [ -z "$err_device_aliases" ] && return
+ [ -f ${dir}ipAddress ] && local logrow=$(grep -c "" ${dir}ipAddress) || local logrow="0";[ $logrow -eq "0" ] && return
+ local MACLIST=`cat ${dir}ipAddress|awk '{print $2}'|grep -v "^$"|sort -u`
+ for mac in $MACLIST; do
+ [ -z "$err_mac" ] && [ ! -z "$mac" ] && local err_mac=`echo "$err_device_aliases"|grep -i $mac|grep -v "^$"|sort -u|head -n1`
+ done
+ # 进入免打扰时间已经超过一小时
+ if [ ! -z "$sheep_starttime" ] && [ "$((`date +%s`-$sheep_starttime))" -ge "3600" ]; then
+ > ${dir}sheep_usage
+ local MACLIST=`echo "$err_device_aliases"|grep -v "^$"|sort -u`
+ for mac in $MACLIST; do
+ [ ! -z "$mac" ] && local tmptotal=`usage get ${mac} bytes`
+ [ ! -z "$tmptotal" ] && awk 'BEGIN{printf "%.0f\n",'$tmptotal'/'204800'}' 2>/dev/null >> ${dir}sheep_usage
+ done
+ old_sheep_usage=`cat ${dir}old_sheep_usage` 2>/dev/null
+ sheep_usage=`cat ${dir}sheep_usage` 2>/dev/null
+ [ "$old_sheep_usage" == "$sheep_usage" ] && [ -z "$sheep_nousage_starttime" ] && sheep_nousage_starttime=`date +%s`
+ [ "$old_sheep_usage" != "$sheep_usage" ] && unset sheep_nousage_starttime && cat ${dir}sheep_usage 2>/dev/null > ${dir}old_sheep_usage
+ [ ! -z "$sheep_nousage_starttime" ] && [ "$((`date +%s`-$sheep_nousage_starttime))" -ge "300" ] && unset err_mac
+ fi
+ [ -z "$err_mac" ]
+}
+
+# 无人值守任务
+function unattended(){
+ [ -z "$err_enable" ] || [ "$err_enable" -ne "1" ] && return
+ [ ! -z "$err_sheep_enable" ] && [ "$err_sheep_enable" -eq "1" ] && [ -z "$sheep_starttime" ] && return
+ geterrdevicealiases;[ $? -eq "1" ] && return
+
+ if [ ! -z "$system_time_event" ]; then
+ local interfaceuptime=`getinterfaceuptime`
+ if [ ! -z "$autoreboot_time" ] && [ `cat /proc/uptime|awk -F. '{run_hour=$1/3600;printf("%d",run_hour)}'` -ge "$autoreboot_time" ] && [ "$system_time_event" -eq "1" ]; then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【无人值守任务】重启路由器咯" >> ${logfile}
+ cat ${logfile} > /usr/bin/serverchan/errlog
+ sleep 2 && reboot && exit
+ elif [ ! -z "$network_restart_time" ] && [ ! -z "$interfaceuptime" ] && [ `echo "$interfaceuptime"|awk -F. '{run_hour=$1/3600;printf("%d",run_hour)}'` -ge "$network_restart_time" ] && [ "$system_time_event" -eq "2" ]; then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【无人值守任务】重新拨号咯" >> ${logfile}
+ ifup wan >/dev/null 2>&1
+ sleep 60
+ fi
+ fi
+
+ [ -z "$public_ip_today" ] && public_ip_today=`date +"%d"`
+ [ -z "$public_ip_count" ] && public_ip_count="0"
+ [ $public_ip_today -ne `date +"%d"` ] && public_ip_today=`date +"%d"` && public_ip_count=1
+ if [ ! -z "$public_ip_event" ] && [ ! -z "$public_ip_retry_count" ] && [ "$public_ip_count" -le "$public_ip_retry_count" ]; then
+ public_ip_count=`expr $public_ip_count + 1`
+ local wanIP=`getip wanipv4`
+ local hostIP=`getip hostipv4`
+ if [ ! -z "$wanIP" ] && [ ! -z "$hostIP" ] && ( ! echo "$wanIP"|grep -q -w ${hostIP} );then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【无人值守任务】重拨尝试获取公网 ip,当前第 $public_ip_count 次 " >> ${logfile}
+ ifup wan >/dev/null 2>&1
+ sleep 60
+ local wanIP=`getip wanipv4` && local hostIP=`getip hostipv4`
+ [ ! -z "$serverchan_ipv4" ] && [ "$serverchan_ipv4" -eq "1" ] && local IPv4=${wanIP}
+ [ ! -z "$serverchan_ipv4" ] && [ "$serverchan_ipv4" -eq "2" ] && local IPv4=${hostIP}
+ [ ! -z "$serverchan_ipv6" ] && [ "$serverchan_ipv6" -eq "1" ] && local IPv6=`getip wanipv6`
+ [ ! -z "$serverchan_ipv6" ] && [ "$serverchan_ipv6" -eq "2" ] && local IPv6=`getip hostipv6`
+ [ ! -z "$wanIP" ] && [ ! -z "$hostIP" ] && ( ! echo "$wanIP"|grep -q -w ${hostIP} ) && echo IPv4 $IPv4 > ${dir}ip && echo -e IPv6 $last_IPv6 >> ${dir}ip
+ fi
+ fi
+}
+
+# 检测网络状态
+function rand_geturl(){
+ function getcheck(){
+ local urllist="https://www.163.com https://www.qq.com https://www.baidu.com https://www.qidian.com https://www.douban.com"
+ local url_number=`expr $(echo "$urllist"|grep -o ' '|wc -l) + 1`
+ local url_str=`echo "$urllist"|awk -v i=$(rand 1 $url_number) '{print $i}'`
+ echo `curl -k -s -w "%{http_code}" -m 5 ${url_str} -A "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" -o /dev/null`
+ }
+ local check=`getcheck`
+ while [ -z "$check" ] || [ "$check" -ne "200" ]; do
+ local check=`getcheck`
+ if [ ! -z "$check" ] && [ "$check" -eq "200" ]; then
+ [ ! -z "$network_enable" ] && [ "$network_enable" -eq "404" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【网络状态】网络恢复正常.." >> ${logfile}
+ local network_enable="200"
+ else
+ [ -z "$network_enable" ] || [ "$network_enable" -eq "200" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!!】当前网络不通!停止检测! " >> ${logfile}
+ local network_enable="404"
+ [ -z "$network_err_time" ] && network_err_time=`date +%s`
+ if [ ! -z "$network_err_event" ] && [ "$((`date +%s`-$network_err_time))" -ge "600" ]; then
+ > ${dir}send_enable.lock && serverchan_first && deltemp
+ geterrdevicealiases
+ if [ "$?" -eq "0" ]; then
+ [ -f /usr/bin/serverchan/autoreboot_count ] && retry_count=`cat /usr/bin/serverchan/autoreboot_count` && rm -f /usr/bin/serverchan/autoreboot_count >/dev/null 2>&1
+ [ ! -z ${retry_count} ] && retry_count=0;retry_count=`expr $retry_count + 1`
+ if [ "$network_err_event" -eq "1" ] ;then
+ if [ "$retry_count" -lt "3" ] ;then
+ echo "$retry_count" > /usr/bin/serverchan/autoreboot_count
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!!】正在尝试重启路由,当前第 $retry_count 次 " >> ${logfile}
+ cat ${logfile} > /usr/bin/serverchan/errlog
+ sleep 2 && reboot && exit
+ fi
+ [ "$retry_count" -eq "3" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!!】已经重启路由2次,修复失败,请主人自行修复哦" >> ${logfile}
+ elif [ "$network_err_event" -eq "2" ] ;then
+ [ "$retry_count" -lt "3" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!!】正在尝试重启网络,当前第 $retry_count 次 " >> ${logfile} && ifup wan >/dev/null 2>&1
+ [ "$retry_count" -eq "3" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!!】已经重启网络2次,修复失败,请主人自行修复哦 " >> ${logfile}
+ elif [ "$network_err_event" -eq "3" ] ;then
+ if [ "$retry_count" -eq "1" ] ;then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!!】正在尝试修复网络,当前第 1 次,重启网络服务中 " >> ${logfile} && network_restart
+ elif [ "$retry_count" -eq "2" ] ;then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!!】正在尝试修复网络,当前第 2 次,关闭可能造成网络断开的软件" >> ${logfile}
+ [ `uci get koolproxy.@global[0].enabled 2>/dev/null` -eq "1" ] && [ `uci get koolproxy.@global[0].koolproxy_mode 2>/dev/null` -eq "1" ] && /etc/init.d/koolproxy stop >/dev/null 2>&1
+ [ `uci get adbyby.@adbyby[0].enable 2>/dev/null` -eq "1" ] && [ `uci get adbyby.@adbyby[0].wan_mode 2>/dev/null` -eq "0" ] && /etc/init.d/adbyby stop >/dev/null 2>&1
+ [ `uci get passwall.@global[0].enabled 2>/dev/null` -eq "1" ] && [ `uci get passwall.@global[0].proxy_mode 2>/dev/null|grep global` ] && /etc/init.d/koolproxy stop >/dev/null 2>&1
+ local shadowsocksr_enabled=`uci get shadowsocksr.@global[0].global_server 2>/dev/null|grep nil`
+ local shadowsocksr_run_mode=`uci get shadowsocksr.@global[0].run_mode 2>/dev/null|grep all`
+ [ -z "$shadowsocksr_enabled" ] && [ ! -z "$shadowsocksr_run_mode" ] && /etc/init.d/shadowsocksr stop >/dev/null 2>&1
+ sleep 60 && network_restart
+ elif [ "$retry_count" -eq "3" ] ;then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!!】正在尝试修复网络,当前第 3 次,备份设置项,并修改相关设置" >> ${logfile}
+ mkdir -p /usr/bin/serverchan/configbak
+ cp -p -f /etc/config/network /usr/bin/serverchan/configbak/network
+ cp -p -f /etc/config/dhcp /usr/bin/serverchan/configbak/dhcp
+ cp -p -f /etc/config/firewall /usr/bin/serverchan/configbak/firewall
+ cp -p -f /etc/firewall.user /usr/bin/serverchan/configbak/firewall.user
+ uci set network.wan.peerdns='0'
+ uci delete network.wan.dns
+ uci add_list network.wan.dns='223.5.5.5'
+ uci add_list network.wan.dns='119.29.29.29'
+ uci delete network.wan.mtu
+ uci commit network
+ uci set dhcp.@dnsmasq[0].port='53'
+ uci set dhcp.@dnsmasq[0].resolvfile='/tmp/resolv.conf.auto'
+ uci delete dhcp.@dnsmasq[0].server
+ uci delete dhcp.@dnsmasq[0].noresolv
+ uci commit dhcp
+ uci delete firewall.redirect
+ >/etc/firewall.user
+ uci commit firewall
+ sleep 60 && network_restart
+ elif [ "$retry_count" -eq "4" ] ;then
+ echo "$retry_count" > /usr/bin/serverchan/autoreboot_count
+ cat ${logfile} > /usr/bin/serverchan/errlog
+ sleep 2 && reboot && exit
+ elif [ "$retry_count" -eq "5" ] ;then
+ echo "$retry_count" > /usr/bin/serverchan/autoreboot_count
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!!】修复失败,还原设置中,请自行检查网络设置" >> ${logfile}
+ cp -p -f /usr/bin/serverchan/configbak/network /etc/config/network
+ cp -p -f /usr/bin/serverchan/configbak/dhcp /etc/config/dhcp
+ cp -p -f /usr/bin/serverchan/configbak/firewall /etc/config/firewall
+ cp -p -f /usr/bin/serverchan/configbak/firewall.user /etc/firewall.user
+ cat ${logfile} > /usr/bin/serverchan/errlog
+ sleep 2 && reboot && exit
+ fi
+ fi
+ fi
+ elif [ -f /usr/bin/serverchan/autoreboot_count ]; then
+ network_err_time=`expr $network_err_time - 600` && sleep 60
+ fi
+ enable_detection
+ sleep $sleeptime
+ fi
+ continue
+ done
+ rm -f /usr/bin/serverchan/autoreboot_count >/dev/null 2>&1
+}
+
+# 检测 ip 状况
+function ip_changes(){
+ [ ! -z "$serverchan_ipv4" ] && [ "$serverchan_ipv4" -eq "1" ] && local IPv4=`getip wanipv4`
+ [ ! -z "$serverchan_ipv4" ] && [ "$serverchan_ipv4" -eq "2" ] && local IPv4=`getip hostipv4`
+ [ ! -z "$serverchan_ipv6" ] && [ "$serverchan_ipv6" -eq "1" ] && local IPv6=`getip wanipv6`
+ [ ! -z "$serverchan_ipv6" ] && [ "$serverchan_ipv6" -eq "2" ] && local IPv6=`getip hostipv6`
+
+ if [ -f ${dir}ip ]; then
+ local last_IPv4=$(cat "${dir}ip"|grep IPv4|awk '{print $2}'|grep -v "^$"|sort -u|head -n1)
+ local last_IPv6=$(cat "${dir}ip"|grep IPv6|awk '{print $2}'|grep -v "^$"|sort -u|head -n1)
+ if [ ! -z "$serverchan_ipv4" ] && [ "$serverchan_ipv4" -ne "0" ] && [ ! -z "$IPv4" ] && ( ! echo ${IPv4}|grep -w -q ${last_IPv4} ); then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}当前IP:${IPv4}" >> ${logfile}
+ echo IPv4 $IPv4 > ${dir}ip && echo -e IPv6 $last_IPv6 >> ${dir}ip
+ title="IP 地址变化"
+ content="${content}${str_splitline}${str_title_start} IP 地址变化${str_title_end}${str_linefeed}${str_tab}当前 IP:${IPv4}"
+ elif [ ! -z "$serverchan_ipv4" ] && [ "$serverchan_ipv4" -ne "0" ] && [ -z "$IPv4" ]; then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】获取 IPv4 地址失败" >> ${logfile}
+ fi
+
+ if [ ! -z "$serverchan_ipv6" ] && [ "$serverchan_ipv6" -ne "0" ] && [ ! -z "$IPv6" ] && ( ! echo "$IPv6"|grep -w -q ${last_IPv6} ); then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}当前IPv6:${IPv6}" >> ${logfile}
+ echo IPv4 $IPv4 > ${dir}ip && echo -e IPv6 $IPv6 >> ${dir}ip
+ [ -z "$title" ] && title="IPv6 地址变化"
+ [ ! -z "$title" ] && title="IP 地址变化"
+ content="${content}${str_splitline}${str_title_start} IPv6 地址变化${str_title_end}${str_linefeed}${str_tab}当前 IPv6:${IPv6}"
+ elif [ ! -z "$serverchan_ipv6" ] && [ "$serverchan_ipv6" -ne "0" ] && [ -z "$IPv6" ]; then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】获取 IPv6 地址失败" >> ${logfile}
+ fi
+
+ else
+ echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}路由器已经重启!" >> ${logfile}
+ [ ! -z "$serverchan_ipv4" ] && [ "$serverchan_ipv4" -ne "0" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 当前IP: ${IPv4}" >> ${logfile}
+ [ ! -z "$serverchan_ipv6" ] && [ "$serverchan_ipv6" -ne "0" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 当前IPv6: ${IPv6}" >> ${logfile}
+ echo IPv4 $IPv4 > ${dir}ip && echo -e IPv6 $IPv6 >> ${dir}ip
+ title="路由器重新启动"
+ content="${content}${str_splitline}${str_title_start} 路由器重新启动"${str_title_end}
+ [ ! -z "$serverchan_ipv4" ] && [ "$serverchan_ipv4" -ne "0" ] && content="${content}${str_linefeed}${str_tab}当前IP:${IPv4}"
+ [ ! -z "$serverchan_ipv6" ] && [ "$serverchan_ipv6" -ne "0" ] && content="${content}${str_linefeed}${str_tab}当前IPv6:${IPv6}"
+ fi
+
+ if [ ! -z "$content" ] ;then
+ [ -z "$ddns_enabled" ] && ddns_enabled=$(uci show ddns|grep "enabled"|grep "1")
+ [ -z "$ddns_enabled" ] && ddns_logrow=0 || ddns_logrow=$(echo "$ddns_enabled"|wc -l)
+ if [ $ddns_logrow -ge 1 ]; then
+ /etc/init.d/ddns restart >/dev/null 2>&1
+ fi
+ [ -z "$zerotier_enabled" ] && zerotier_enabled=$(uci get zerotier.sample_config.enabled)
+ if [ ! -z "$zerotier_enabled" ] && [ $zerotier_enabled -eq "1" ] ; then
+ /etc/init.d/zerotier restart >/dev/null 2>&1
+ fi
+ fi
+}
+
+# 检测设备上线
+function up(){
+ [ -f ${dir}ipAddress ] && ( cat ${dir}ipAddress|grep -q -w $1 ) && return
+ local ip_mac=`getmac $1`
+ local ip_name=`getname ${1} ${ip_mac}`
+ local ip_interface=`getinterface ${ip_mac}`
+ getping ${1} ${up_timeout} "1";local ping_online=$?
+ if [ "$ping_online" -eq "0" ]; then
+ LockFile lock
+ [ ! -z "$serverchan_blacklist" ] && local tmp_mac=`echo "${serverchan_blacklist}"|grep -w -i ${ip_mac}`
+ [ ! -z "$serverchan_whitelist" ] && local tmp_mac=`echo "${serverchan_whitelist}"|grep -w -i ${ip_mac}`
+ if [ ! -z "$tmp_mac" ] && ( cat ${dir}ipAddress|grep -q -w -i ${tmp_mac} ); then
+ usage down $1
+ echo "$1 ${ip_mac} ${ip_name} `date +%s` ${ip_interface}" >> ${dir}ipAddress
+ LockFile unlock && return
+ elif [ ! -z "$tmp_mac" ] && [ -f "${dir}tmp_downlist" ] && ( cat ${dir}tmp_downip|grep -q -w -i ${tmp_mac} ); then
+ local tmp_downip=`cat ${dir}tmp_downlist|grep -w -i ${tmp_mac}|awk '{print $1}'|grep -v "^$"|sort -u|head -n1`
+ usage down $tmp_downip
+ sed -i "/^${tmp_downip} /d" ${dir}tmp_downlist
+ LockFile unlock && return
+ fi
+ [ -f "${dir}tmp_downlist" ] && local tmp_downip=`cat ${dir}tmp_downlist|grep -w ${1}|grep -v "^$"|sort -u|head -n1`
+ if [ ! -z "$tmp_downip" ]; then
+ cat ${dir}tmp_downlist|grep -w ${1}|grep -v "^$"|sort -u|head -n1 >> ${dir}ipAddress
+ sed -i "/^${1} /d" ${dir}tmp_downlist
+ else
+ usage down $1
+ echo "$1 ${ip_mac} ${ip_name} `date +%s` ${ip_interface}" >> ${dir}ipAddress
+ blackwhitelist ${ip_mac};local ip_blackwhite=$?
+ [ -f "${dir}send_enable.lock" ] || [ -z "$serverchan_up" ] || [ -z "$ip_blackwhite" ] && LockFile unlock && return
+ [ ! -z "$serverchan_up" ] && [ "$serverchan_up" -ne "1" ] && LockFile unlock && return
+ [ -z "$ip_blackwhite" ] || [ "$ip_blackwhite" -ne "0" ] && LockFile unlock && return
+ [ -f "${dir}title" ] && local title=`cat ${dir}title`
+ [ -f "${dir}content" ] && local content=`cat ${dir}content`
+ if [ -z "$title" ]; then
+ local title="$ip_name 连接了你的路由器"
+ local content="${str_splitline}${str_title_start} 新设备连接${str_title_end}${str_linefeed}${str_tab}客户端名:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP: ${str_space}${str_space}${str_space}${str_space}${1}${str_linefeed}${str_tab}客户端MAC:${str_space}${str_space}${str_space}${str_space}${ip_mac}${str_linefeed}${str_tab}网络接口:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_interface}"
+ elif ( echo ${title}|grep -q "连接了你的路由器" ); then
+ local title="${ip_name} ${title}"
+ local content="${str_splitline}${str_tab}客户端名:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP: ${str_space}${str_space}${str_space}${str_space}${1}${str_linefeed}${str_tab}客户端MAC:${str_space}${str_space}${str_space}${str_space}${ip_mac}${str_linefeed}${str_tab}网络接口:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_interface}"
+ else
+ local title="设备状态变化"
+ local content="${str_splitline}${str_title_start} 新设备连接${str_title_end}${str_linefeed}${str_tab}客户端名:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP: ${str_space}${str_space}${str_space}${str_space}${1}${str_linefeed}${str_tab}客户端MAC:${str_space}${str_space}${str_space}${str_space}${ip_mac}${str_linefeed}${str_tab}网络接口:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_interface}"
+ fi
+ echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}新设备 ${ip_name} ${1} 连接了">> ${logfile}
+ #[ ! -z "$serverchan_blacklist" ] && local title="你偷偷关注的设备上线了"
+ [ ! -z "$title" ] && echo "$title" >${dir}title
+ [ ! -z "$content" ] && echo -n "$content" >>${dir}content
+ fi
+ fi
+ LockFile unlock
+}
+
+# 检测设备离线
+function down(){
+ local ip_mac=`getmac $1`
+ local ip_name=`getname ${1} ${ip_mac}`
+ local ip_interface=`getinterface ${ip_mac}`
+ getping ${1} ${down_timeout} ${timeout_retry_count};local ping_online=$?
+ if [ "$ping_online" -eq "1" ]; then
+ LockFile lock
+ [ ! -f "${dir}send_enable.lock" ] && cat ${dir}ipAddress|grep -w ${1}|grep -v "^$"|sort -u|head -n1 >> ${dir}tmp_downlist
+ sed -i "/^${1} /d" ${dir}ipAddress
+ LockFile unlock
+ else
+ local tmp_name=`cat ${dir}ipAddress|grep -w ${1}|awk '{print $3}'|grep -v "^$"|sort -u|head -n1`
+ if [ "$ip_name" != "$tmp_name" ]; then
+ LockFile lock
+ local tmp_str=$(echo "$1 ${ip_mac} ${ip_name} `cat ${dir}ipAddress|grep -w ${1}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1` ${ip_interface}")
+ sed -i "/^${1} /d" ${dir}ipAddress
+ echo "$tmp_str" >> ${dir}ipAddress
+ LockFile unlock
+ fi
+ fi
+}
+
+# 设备离线通知
+function down_send(){
+ [ ! -f "${dir}tmp_downlist" ] && return
+ local IPLIST=`cat ${dir}tmp_downlist|awk '{print $1}'`
+ for ip in $IPLIST; do
+ local ip_mac=`getmac ${ip}`
+ blackwhitelist ${ip_mac};local ip_blackwhite=$?
+ [ -z "$serverchan_down" ] || [ -z "$ip_blackwhite" ] && continue
+ [ ! -z "$serverchan_down" ] && [ "$serverchan_down" -ne "1" ] && continue
+ [ -z "$ip_blackwhite" ] || [ "$ip_blackwhite" -ne "0" ] && continue
+ [ ! -z "$serverchan_blacklist" ] && local tmp_mac=`echo "${serverchan_blacklist}"|grep -w -i ${ip_mac}`
+ [ ! -z "$serverchan_whitelist" ] && local tmp_mac=`echo "${serverchan_whitelist}"|grep -w -i ${ip_mac}`
+ [ ! -z "$tmp_mac" ] && ( cat ${dir}ipAddress|grep -q -w -i ${tmp_mac} ) && continue
+ local ip_name=`getname ${ip} ${ip_mac}`
+ local time_up=`cat ${dir}tmp_downlist|grep -w ${ip}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1`
+ local ip_total=`usage get $ip_mac` && [ ! -z "$ip_total" ] && local ip_total="${str_linefeed}${str_tab}总计流量: ${str_space}${str_space}${str_space}${str_space}${ip_total}"
+ local time1=`date +%s`
+ local time1=$(time_for_humans `expr ${time1} - ${time_up}`)
+ if [ -z "$title" ]; then
+ title="${ip_name} 断开连接"
+ content="${content}${str_splitline}${str_title_start} 设备断开连接${str_title_end}${str_linefeed}${str_tab}客户端名:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP: ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC:${str_space}${str_space}${str_space}${str_space}${ip_mac}$ip_total${str_linefeed}${str_tab}在线时间: ${str_space}${str_space}${str_space}${str_space}${time1}"
+ elif ( echo "$title"|grep -q "断开连接" ); then
+ title="${ip_name} ${title}"
+ content="${content}${str_splitline}${str_tab}客户端名:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP: ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC:${str_space}${str_space}${str_space}${str_space}${ip_mac}$ip_total${str_linefeed}${str_tab}在线时间: ${str_space}${str_space}${str_space}${str_space}${time1}"
+ else
+ title="设备状态变化"
+ content="${content}${str_splitline}${str_title_start} 设备断开连接${str_title_end}${str_linefeed}${str_tab}客户端名:${str_space}${str_space}${str_space}${str_space}${str_space}${ip_name}${str_linefeed}${str_tab}客户端IP: ${str_space}${str_space}${str_space}${str_space}${ip}${str_linefeed}${str_tab}客户端MAC:${str_space}${str_space}${str_space}${str_space}${ip_mac}$ip_total${str_linefeed}${str_tab}在线时间: ${str_space}${str_space}${str_space}${str_space}${time1}"
+ fi
+ echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}设备 ${ip_name} ${ip} 断开连接 " >> ${logfile}
+ done
+ rm -f ${dir}tmp_downlist >/dev/null 2>&1
+}
+
+# 当前设备列表
+function current_device(){
+ ( echo "$lite_enable"|grep -q "content" ) || ( echo "$lite_enable"|grep -q "device" ) && return
+ [ -f ${dir}ipAddress ] && local logrow=$(grep -c "" ${dir}ipAddress) || local logrow="0";[ $logrow -eq "0" ] && return
+ [ -f ${dir}usage.db ] && local ip_total_db="总计流量${str_space}${str_space}${str_space}${str_space}"
+ content="${content}${str_splitline}${str_title_start} 现有在线设备 ${logrow} 台,具体如下${str_title_end}${str_linefeed}${str_tab}IP 地址${str_space}${str_space}${str_space}${str_space}${str_space}${str_space}${str_space}${str_space}${str_space}${ip_total_db}客户端名"
+ local IPLIST=`cat ${dir}ipAddress|awk '{print $1}'`
+ for ip in $IPLIST; do
+ local ip_mac=`getmac ${ip}`
+ local ip_total=`usage get ${ip_mac}`
+ local ip_name=`getname ${ip} ${ip_mac}`
+ local ip_name=`cut_str $ip_name 15`
+ if [ "${#ip}" -lt "15" ]; then
+ local n=`expr 15 - ${#ip}`
+ for i in `seq 1 $n`; do
+ local ip="${ip}${str_space}"
+ done
+ unset i n
+ fi
+ if [ ! -z "$ip_total" ]; then
+ local n=`expr 11 - ${#ip_total}`
+ for i in `seq 1 $n`; do
+ local ip_total="${ip_total}${str_space}"
+ done
+ fi
+ content="${content}${str_linefeed}${str_tab}${ip}${ip_total}${ip_name}"
+ unset i n ip_total ip_mac ip_name
+ done
+}
+
+# 检测 cpu 状态
+function cpu_load(){
+ if [ ! -z "$temperature_enable" ] && [ "$temperature_enable" -eq "1" ] && [ ! -z "$temperature" ]; then
+ [ -z "$temperature_time" ] && temperature_time=`date +%s`
+ local cpu_wendu=`soc_temp`;
+ [ -z "$cpu_wendu" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】无法读取设备温度,请检查命令" >> ${logfile}
+
+ if [ "$cpu_wendu" -gt "$temperature" ]; then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!警报!!】 CPU 温度过高: ${cpu_wendu}" >> ${logfile}
+ else
+ temperature_time=`date +%s`
+ fi
+
+ if [ "$((`date +%s`-$temperature_time))" -ge "300" ] && [ -z "$temperaturecd_time" ]; then
+ title="CPU 温度过高!"
+ temperaturecd_time=`date +%s`
+ echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text} CPU 温 度过高: ${cpu_wendu}" >> ${logfile}
+ content="${content}${str_splitline}${str_title_start} CPU 温度过高${str_title_end}${str_linefeed}${str_tab}CPU 温度已连续五分钟超过预设${str_linefeed}${str_tab}接下来一小 时不再提示${str_linefeed}${str_tab}当前温度:${cpu_wendu}℃"
+ elif [ ! -z "$temperaturecd_time" ] && [ "$((`date +%s`-$temperaturecd_time))" -ge "3300" ] ;then
+ unset temperaturecd_time
+ fi
+ fi
+
+ if [ ! -z "$cpuload_enable" ] && [ "$cpuload_enable" -eq "1" ] && [ ! -z "$cpuload" ]; then
+ [ -z "$cpuload_time" ] && cpuload_time=`date +%s`
+ local cpu_fuzai=`cat /proc/loadavg|awk '{print $1}'` 2>/dev/null
+ [ -z "$cpu_fuzai" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】无法读取设备负载,请检查命令" >> ${logfile}
+
+ if [ `expr $cpu_fuzai \> $cpuload` -eq "1" ]; then
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!警报!!】 CPU 负载过高: ${cpu_fuzai}" >> ${logfile}
+ cputop log
+ else
+ cpuload_time=`date +%s`
+ fi
+
+ if [ "$((`date +%s`-$cpuload_time))" -ge "300" ] && [ -z "$cpucd_time" ]; then
+ unset getlogtop
+ if [ ! -z "$title" ] && ( echo "$title"|grep -q "过高" ); then
+ title="设备报警!"
+ else
+ title="CPU 负载过高!"
+ fi
+ cpucd_time=`date +%s`
+ echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text} CPU 负 载过高: ${cpu_fuzai}" >> ${logfile}
+ content="${content}${str_splitline}${str_title_start} CPU 负载过高${str_title_end}${str_linefeed}${str_tab}CPU 负载已连续五分钟超过预设${str_linefeed}${str_tab}接下来一小 时不再提示${str_linefeed}${str_tab}当前负载:${cpu_fuzai}"
+ cputop
+ elif [ ! -z "$cpucd_time" ] && [ "$((`date +%s`-$cpucd_time))" -ge "3300" ] ;then
+ unset cpucd_time
+ fi
+ fi
+}
+
+function cputop(){
+ [ -z "$1" ] && content="${content}${str_splitline}${str_title_start} 当前 CPU 占用前三的进程${str_title_end}"
+ local gettop=`top -bn 1|grep -v "top -bn 1"`
+ for i in `seq 5 7`; do
+ local top_name=`echo "${gettop}"|awk 'NR=='${i}|awk '{print ($8 ~ /\/bin\/sh|\/bin\/bash/) ? $9 : $8}'`
+ local top_load=`echo "${gettop}"|awk 'NR=='${i}|awk '{print $7}'`
+ local temp_top="${top_name} ${top_load}"
+ [ ! -z "$1" ] && local logtop="$logtop $temp_top"
+ [ -z "$1" ] && content="${content}${str_linefeed}${str_tab}${temp_top}"
+ done
+ unset i
+ [ ! -z "$1" ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!警报!!】 CPU 占用前三: ${logtop}" >> ${logfile}
+}
+
+# 生成日志监控文件,避免后台影响 wait 语句
+function get_syslog(){
+ kill -9 `pgrep -f "logread -f -p notice"` 2>/dev/null
+ [ -z "$web_logged" ] && [ -z "$ssh_logged" ] && [ -z "$web_login_failed" ] && [ -z "$ssh_login_failed" ] && return
+ rm -f ${dir}login_monitor >/dev/null 2>&1
+
+cat>${dir}get_syslog<> ${dir}login_monitor &
+EOF
+ chmod 0755 ${dir}get_syslog && ${dir}get_syslog
+ rm -f ${dir}get_syslog >/dev/null 2>&1
+}
+
+# 登陆提醒通知
+function login_send(){
+ [ -z "$web_logged" ] && [ -z "$ssh_logged" ] && [ -z "$web_login_failed" ] && [ -z "$ssh_login_failed" ] && return
+ [ ! -f ${dir}login_monitor ] && return
+ cat ${dir}login_monitor|grep -i "accepted login"|awk '{print $4" "$NF}' >> ${dir}web_login
+ cat ${dir}login_monitor|grep -i "Password auth succeeded\|Pubkey auth succeeded"|grep -Eo "[0-9]{2}:[0-9]{2}:[0-9]{2}.*[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"|awk '{print $1" "$NF" "$5}' >> ${dir}ssh_login
+ cat ${dir}login_monitor|grep -i "failed login"|grep -Eo "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" >> ${dir}web_failed
+ cat ${dir}login_monitor|grep -i "Bad password attempt\|Login attempt for nonexistent user from"|grep -Eo "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" >> ${dir}ssh_failed
+ echo "" > ${dir}login_monitor
+ add_ip_black
+
+ local login_ip_list=`cat ${dir}web_login|awk '{print $2}'|grep -v "^$"|sort -u|head -n1`
+ for login_ip in $login_ip_list; do
+ [ -z "$login_ip" ] && continue
+ echo "$ip_white_list"|grep -w -q "$login_ip" && continue
+ local web_login_time=`cat ${dir}web_login|grep -w ${login_ip}|awk '{print $1}'|grep -v "^$"|sort -u|head -n1`
+ local web_login_mode=`cat ${dir}web_login|grep -w ${login_ip}|awk '{print $3}'|grep -v "^$"|sort -u|head -n1`
+ if [ ! -z "$web_logged" ] && [ "$web_logged" -eq "1" ]; then
+ if [ -z "$title" ]; then
+ title="${login_ip} 通过 web 登陆了路由器"
+ content="${content}${str_splitline}${str_title_start} 登陆信息${str_title_end}${str_linefeed}${str_tab}时间:${str_space}${str_space}${str_space}${str_space}${str_space}${web_login_time}${str_linefeed}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_mode}"
+ elif ( echo "$title"|grep -q "登陆了路由器" ); then
+ title="${login_ip} ${title}"
+ content="${content}${str_splitline}${str_tab}时间:${str_space}${str_space}${str_space}${str_space}${str_space}${web_login_time}${str_linefeed}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_mode}"
+ else
+ title="设备状态变化"
+ content="${content}${str_splitline}${str_title_start} 登陆信息${str_title_end}${str_linefeed}${str_tab}时间:${str_space}${str_space}${str_space}${str_space}${str_space}${web_login_time}${str_linefeed}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_mode}"
+ fi
+ fi
+ echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}设备 ${login_ip} 通过 web ${web_login_mode} 登陆了路由器 " >> ${logfile}
+ done
+ echo "" > ${dir}web_login
+ unset login_ip login_ip_list
+
+ local login_ip_list=`cat ${dir}ssh_login|awk '{print $2}'|grep -v "^$"|sort -u|head -n1`
+ for login_ip in $login_ip_list; do
+ [ -z "$login_ip" ] && continue
+ echo "$ip_white_list"|grep -w -q "$login_ip" && continue
+ local ssh_login_time=`cat ${dir}ssh_login|grep -w ${login_ip}|awk '{print $1}'|grep -v "^$"|sort -u|head -n1`
+ local ssh_login_mode=`cat ${dir}ssh_login|grep -w ${login_ip}|awk '{print $3}'|grep -v "^$"|sort -u|head -n1`
+ [ ! -z "$ssh_login_mode" ] && local content_mode="${str_linefeed}${str_tab}登录方式: ${str_space}${str_space}${str_space}${str_space}${ssh_login_mode}"
+ if [ ! -z "$ssh_logged" ] && [ "$ssh_logged" -eq "1" ]; then
+ if [ -z "$title" ]; then
+ title="${login_ip} 通过 ssh 登陆了路由器"
+ content="${content}${str_splitline}${str_title_start} 登陆信息${str_title_end}${str_linefeed}${str_tab}时间:${str_space}${str_space}${str_space}${str_space}${str_space}${ssh_login_time}${str_linefeed}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_mode}"
+ elif ( echo "$title"|grep -q "登陆了路由器" ); then
+ title="${login_ip} ${title}"
+ content="${content}${str_splitline}${str_tab}时间:${str_space}${str_space}${str_space}${str_space}${str_space}${ssh_login_time}${str_linefeed}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_mode}"
+ else
+ title="设备状态变化"
+ content="${content}${str_splitline}${str_title_start} 登陆信息${str_title_end}${str_linefeed}${str_tab}时间:${str_space}${str_space}${str_space}${str_space}${str_space}${ssh_login_time}${str_linefeed}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}${content_mode}"
+ fi
+ fi
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【info】设备 ${login_ip} 通过 ssh ${ssh_login_mode} 登陆了路由器 " >> ${logfile}
+ done
+ echo "" > ${dir}ssh_login
+ unset login_ip login_ip_list
+
+ local login_ip_list=`cat ${dir}web_failed|awk '{print $1}'|grep -v "^$"|sort -u|head -n1`
+ for login_ip in $login_ip_list; do
+ [ -z "$login_ip" ] && continue
+ echo "$ip_white_list"|grep -w -q "$login_ip" && continue
+ local web_login_sum=`cat ${dir}web_failed|grep -w "${login_ip}"|wc -l`
+ if [ "$web_login_sum" -ge "$login_max_num" ] ;then
+ if [ ! -z "$web_login_failed" ] && [ "$web_login_failed" -eq "1" ]; then
+ if [ -z "$title" ]; then
+ title="${login_ip} 通过 web 频繁尝试登陆"
+ content="${content}${str_splitline}${str_title_start} 登陆信息${str_title_end}${str_linefeed}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}"
+ elif ( echo "$title"|grep -q "频繁尝试登陆" ); then
+ title="${login_ip} ${title}"
+ content="${content}${str_splitline}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}"
+ else
+ title="设备状态变化"
+ content="${content}${str_splitline}${str_title_start} 登陆信息${str_title_end}${str_linefeed}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}"
+ fi
+ fi
+ sed -i "/^${login_ip}$/d" ${dir}web_failed
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】设备 ${login_ip} 通过 web 频繁尝试登陆" >> ${logfile}
+ add_ip_black $login_ip
+ fi
+ done
+ unset login_ip
+
+ local login_ip_list=`cat ${dir}ssh_failed|awk '{print $1}'|grep -v "^$"|sort -u|head -n1`
+ for login_ip in $login_ip_list; do
+ [ -z "$login_ip" ] && continue
+ echo "$ip_white_list"|grep -w -q "$login_ip" && continue
+ local ssh_login_sum=`cat ${dir}ssh_failed|grep -w "${login_ip}"|wc -l`
+ if [ "$ssh_login_sum" -ge "$login_max_num" ] ;then
+ if [ ! -z "$ssh_login_failed" ] && [ "$ssh_login_failed" -eq "1" ]; then
+ if [ -z "$title" ]; then
+ title="${login_ip} 通过 ssh 频繁尝试登陆"
+ content="${content}${str_splitline}${str_title_start} 登陆信息${str_title_end}${str_linefeed}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}"
+ elif ( echo "$title"|grep -q "频繁尝试登陆" ); then
+ title="${login_ip} ${title}"
+ content="${content}${str_splitline}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}"
+ else
+ title="设备状态变化"
+ content="${content}${str_splitline}${str_title_start} 登陆信息${str_title_end}${str_linefeed}${str_tab}设备 IP: ${str_space}${str_space}${str_space}${str_space}${login_ip}"
+ fi
+ fi
+ sed -i "/^${login_ip}$/d" ${dir}ssh_failed
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】设备 ${login_ip} 通过 ssh 频繁尝试登陆" >> ${logfile}
+ add_ip_black $login_ip
+ fi
+ done
+ unset login_ip
+
+}
+
+# 添加黑名单
+function add_ip_black(){
+ [ -f "${ip_blacklist_path}" ] && local logrow=$(grep -c "" ${ip_blacklist_path}) || local logrow="0"
+ [ ! -f "${ip_blacklist_path}" ] && local logrow="0"
+ [ ! -z "$web_login_black" ] && [ "$web_login_black" -eq "0" ] || [ -z "$web_login_black" ] && local logrow="0"
+ ipset flush ip_blacklist >/dev/null 2>&1
+
+ if [ $logrow -le "0" ]; then
+ iptables -D INPUT -m set --match-set ip_blacklist src -j DROP >/dev/null 2>&1
+ ipset destroy ip_blacklist >/dev/null 2>&1
+ return
+ fi
+
+ ipset list ip_blacklist >/dev/null 2>&1 || ipset create ip_blacklist hash:ip timeout ${ip_black_timeout} >/dev/null 2>&1
+ iptables -C INPUT -m set --match-set ip_blacklist src -j DROP >/dev/null 2>&1 || iptables -I INPUT -m set --match-set ip_blacklist src -j DROP >/dev/null 2>&1
+ echo "$1" >> ${ip_blacklist_path}
+ for ip_black in `cat ${ip_blacklist_path}`; do
+ ip_black=`echo "$ip_black"|grep -Eo "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"`
+ ipset -! add ip_blacklist $ip_black >/dev/null 2>&1
+ done
+ ipset list ip_blacklist|grep -Eo "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" > ${ip_blacklist_path}
+}
+
+
+# 发送定时数据
+function send(){
+ echo "`date "+%Y-%m-%d %H:%M:%S"` 【定时数据】创建定时任务" >> ${logfile}
+ serverchan_disturb;local send_disturb=$?
+ get_config "send_title" "router_status" "router_temp" "router_wan" "client_list"
+
+ [ -z "$send_title" ] && local send_title="路由状态:"
+ [ ! -z "$1" ] && local send_title="发送测试:" && local send_content="${str_splitline}${str_title_start}内容1${str_title_end}${str_linefeed}${str_tab}设备1${str_linefeed}${str_tab}设备2${str_splitline}${str_title_start}内容2${str_title_end}${str_linefeed}${str_tab}设备3${str_linefeed}${str_tab}设备4"
+ [ -z "$1" ] && [ ! -z "$client_list" ] && [ "$client_list" -eq "1" ] && > ${dir}send_enable.lock && serverchan_first &
+
+ if [ -z "$1" ] && [ ! -z "$router_status" ] && [ "$router_status" -eq "1" ]; then
+ local systemload=`cat /proc/loadavg|awk '{print $1" "$2" "$3}'`
+ local cpuload=`getcpu`
+ local ramload=`free -m|sed -n '2p'|awk '{printf "%.2f%%\n",($3/$2)*100}'`
+ local systemstatustime=`cat /proc/uptime|awk -F. '{run_days=$1 / 86400;run_hour=($1 % 86400)/3600;run_minute=($1 % 3600)/60;run_second=$1 % 60;printf("运行时间:%d天%d时%d分%d秒",run_days,run_hour,run_minute,run_second)}'`;unset run_days run_hour run_minute run_second
+ local send_content="${send_content}${str_splitline}${str_title_start} 系统运行状态"${str_title_end}
+ local send_content="${send_content}${str_linefeed}${str_tab}平均负载:${systemload}"
+ local send_content="${send_content}${str_linefeed}${str_tab}CPU占用:${cpuload}"
+ local send_content="${send_content}${str_linefeed}${str_tab}内存占用:${ramload}"
+ local send_content="${send_content}${str_linefeed}${str_tab}${systemstatustime}"
+ fi
+
+ if [ -z "$1" ] && [ ! -z "$router_temp" ] && [ "$router_temp" -eq "1" ]; then
+ local cputemp=`soc_temp`
+ [ ! -z "$cputemp" ] && local send_content="${send_content}${str_splitline}${str_title_start} 设备温度${str_title_end}${str_linefeed}${str_tab}CPU:${cputemp}℃"
+ [ -z "$cputemp" ] && local send_content="${send_content}${str_splitline}${str_title_start} 设备温度${str_title_end}${str_linefeed}${str_tab}无法获取设备温度"
+ fi
+
+ if [ -z "$1" ] && [ ! -z "$router_wan" ] && [ "$router_wan" -eq "1" ]; then
+ local send_wanIP=`getip wanipv4`;local send_hostIP=`getip hostipv4`
+ local send_content="${send_content}${str_splitline}${str_title_start} WAN 口信息${str_title_end}${str_linefeed}${str_tab}接口ip:${send_wanIP}"
+ local send_content="${send_content}${str_linefeed}${str_tab}外网ip:${send_hostIP}"
+ if [ ! -z "$serverchan_ipv6" ] && [ "$serverchan_ipv6" -ne "0" ]; then
+ local send_wanIPv6=`getip wanipv6`;local send_hostIPv6=`getip hostipv6`
+ local send_content="${send_content}${str_linefeed}${str_tab}ipv6 :${send_wanIPv6}"
+ local send_content="${send_content}${str_linefeed}${str_tab}外网v6:${send_hostIPv6}"
+ fi
+ ( ! echo "$send_wanIP"|grep -q -w ${send_hostIP} ) && local send_content="${send_content}${str_linefeed}${str_tab}外网 ip 与接口 ip 不一致,你的 ip 不是公网 ip"
+ local interfaceuptime=`getinterfaceuptime`
+ [ ! -z "$interfaceuptime" ] && local wanstatustime=`getinterfaceuptime|awk -F. '{run_days=$1 / 86400;run_hour=($1 % 86400)/3600;run_minute=($1 % 3600)/60;run_second=$1 % 60;printf("在线时间:%d天%d时%d分%d秒",run_days,run_hour,run_minute,run_second)}'` && unset run_days run_hour run_minute run_second
+ local send_content="${send_content}${str_linefeed}${str_tab}${wanstatustime}"
+ fi
+
+ if [ -z "$1" ] && [ ! -z "$client_list" ] && [ "$client_list" -eq "1" ]; then
+ wait
+ local IPLIST=`cat ${dir}ipAddress 2>/dev/null|awk '{print $1}'`
+ [ -f ${dir}ipAddress ] && local logrow=$(grep -c "" ${dir}ipAddress) || local logrow="0"
+ [ "$logrow" -eq "0" ] && local send_content="${send_content}${str_splitline}${str_title_start} 当前无在线设备${str_title_end}" || local send_content="${send_content}${str_splitline}${str_title_start} 现有在线设备 ${logrow} 台${str_title_end}"
+ for ip in $IPLIST; do
+ local time_up=`cat ${dir}ipAddress|grep -w ${ip}|awk '{print $4}'|grep -v "^$"|sort -u|head -n1`
+ local time1=`date +%s`
+ local time1=$(time_for_humans `expr ${time1} - ${time_up}`)
+ local ip_mac=`getmac ${ip}`
+ local ip_name=`getname ${ip} ${ip_mac}`
+ local ip_total=`usage get ${ip_mac}`;[ ! -z "$ip_total" ] && local ip_total="总计流量:${ip_total} "
+ local ip_name=`cut_str $ip_name 18`
+ local send_content="${send_content}${str_linefeed}${str_tab}【${ip_name}】 ${ip}${str_linefeed}${str_tab}${ip_total}在线 ${time1}"
+ unset ip_total time_down time_up time1 ip_mac ip_name
+ done
+ fi
+ [ ! -z "$device_name" ] && local send_title="【$device_name】${send_title}"
+ [ -z "$send_content" ] && local send_content="${str_splitline}${str_title_start} 我遇到了一个难题${str_title_end}${str_linefeed}${str_tab}定时发送选项错误,你没有选择需要发送的项目,该怎 么办呢${str_splitline}"
+ [ "$send_disturb" -eq "0" ] && diy_send "${send_title}" "${send_content}" "${jsonpath}" >/dev/null 2>&1
+ [ $? -eq 1 ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】定时推送失败,请检查网络或设置信息" >> ${logfile} || echo "`date "+%Y-%m-%d %H:%M:%S"` ${disturb_text}定时推送任务完成" >> ${logfile}
+ deltemp
+}
+
+# 初始化
+read_config
+deltemp
+serverchan_cron
+
+# 限制并发进程
+[ -z "$thread_num" ] || [ "$thread_num" -eq "0" ] && thread_num=5
+[ -e ${dir}fd1 ] || mkfifo ${dir}fd1
+exec 5<>${dir}fd1
+rm -f ${dir}fd1 >/dev/null 2>&1
+for i in `seq 1 $thread_num`; do
+ echo >&5
+done
+unset i
+
+# 启动参数
+if [ "$1" ] ;then
+ [ $1 == "send" ] && send
+ [ $1 == "soc" ] && echo `soc_temp` > ${dir}soc_tmp
+ [ $1 == "client" ] && get_client
+ [ $1 == "test" ] && send test
+ exit
+fi
+
+# 载入在线设备
+serverchan_init;[ $? -eq 1 ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】读取设置出错,请检查设置项 " >> ${logfile} && exit
+echo "`date "+%Y-%m-%d %H:%M:%S"` 【初始化】载入在线设备" >> ${logfile}
+> ${dir}send_enable.lock && serverchan_first && deltemp
+echo "`date "+%Y-%m-%d %H:%M:%S"` 【初始化】初始化完成" >> ${logfile}
+
+# 循环
+while [ "$serverchan_enable" -eq "1" ]; do
+ deltemp
+ usage update
+ serverchan_disturb;disturb=$?
+
+ [ -f ${dir}ipAddress ] && ipAddress_logrow=$(grep -c "" ${dir}ipAddress) || ipAddress_logrow="0";
+ if [ $ipAddress_logrow -ne "0" ]; then
+ online_list=`cat ${dir}ipAddress|awk '{print $2}'|grep -v "^$"|sort -u`
+ for online_mac in $online_list; do
+ [ ! -z "$online_mac" ] && mac_online_status="`echo "$mark_mac_list"|grep -i $online_mac|grep -v "^$"|sort -u|head -n1`${mac_online_status}"
+ done
+ fi
+
+ if [ "$serverchan_ipv4" -ne "0" ] || [ "$serverchan_ipv6" -ne "0" ]; then
+ rand_geturl
+ ip_changes
+ fi
+
+ # 设备列表
+ if [ ! -f "${dir}send_enable.lock" ]; then
+ [ ! -z "$title" ] && echo "$title" > ${dir}title
+ [ ! -z "$content" ] && echo "$content" > ${dir}content
+ serverchan_first
+ [ -f "${dir}title" ] && title=`cat ${dir}title` && rm -f ${dir}title >/dev/null 2>&1
+ [ -f "${dir}content" ] && content=`cat ${dir}content` && rm -f ${dir}content >/dev/null 2>&1
+ fi
+
+ # 离线缓存区推送
+ [ ! -f "${dir}send_enable.lock" ] && down_send
+
+ # 当前设备列表
+ [ ! -z "$content" ] && [ ! -f "${dir}send_enable.lock" ] && current_device
+
+ # 无人值守任务
+ [ ! -f "${dir}send_enable.lock" ] && unattended
+
+ # CPU 检测
+ [ ! -f "${dir}send_enable.lock" ] && cpu_load
+
+ # 异常流量检测
+ [ ! -f "${dir}send_enable.lock" ] && get_client_usage
+
+ # 登陆提醒通知
+ [ ! -f "${dir}send_enable.lock" ] && login_send
+
+ if [ ! -f "${dir}send_enable.lock" ] && [ ! -z "$title" ] && [ ! -z "$content" ]; then
+ [ ! -z "$device_name" ] && title="【$device_name】$title"
+ ( echo "$lite_enable"|grep -q "content" ) && content="$title"
+ [ "$disturb" -eq "0" ] && diy_send "${title}" "${content}" "${jsonpath}" >/dev/null 2>&1
+ [ $? -eq 1 ] && echo "`date "+%Y-%m-%d %H:%M:%S"` 【!!!】推送失败,请检查网络或设置信息 " >> ${logfile}
+ fi
+
+ while [ -f "${dir}send_enable.lock" ]; do
+ sleep $sleeptime
+ done
+ sleep $sleeptime
+done
diff --git a/package/lean/luci-app-serverchan/root/usr/share/rpcd/acl.d/luci-app-serverchan.json b/package/lean/luci-app-serverchan/root/usr/share/rpcd/acl.d/luci-app-serverchan.json
new file mode 100644
index 000000000..200ccd56f
--- /dev/null
+++ b/package/lean/luci-app-serverchan/root/usr/share/rpcd/acl.d/luci-app-serverchan.json
@@ -0,0 +1,11 @@
+{
+ "luci-app-serverchan": {
+ "description": "Grant UCI access for luci-app-serverchan",
+ "read": {
+ "uci": [ "serverchan" ]
+ },
+ "write": {
+ "uci": [ "serverchan" ]
+ }
+ }
+}