From 38e1b193ea72231dfd8308ae12685cf8185cc3c8 Mon Sep 17 00:00:00 2001 From: CN_SZTL Date: Thu, 19 Mar 2020 20:34:46 +0800 Subject: [PATCH] luci-app-vssr: sync with upstream source --- package/ctcgfw/luci-app-vssr/Makefile | 18 +- .../luci-app-vssr/luasrc/controller/vssr.lua | 395 ++++++++---------- .../luasrc/model/cbi/vssr/client.lua | 14 +- .../luasrc/model/cbi/vssr/status.lua | 16 +- .../luasrc/model/cbi/vssr/subscription.lua | 11 +- .../luci-app-vssr/luasrc/view/vssr/ping1.htm | 28 -- .../luci-app-vssr/luasrc/view/vssr/ssrurl.htm | 21 +- .../luasrc/view/vssr/subscribe.htm | 18 - .../luasrc/view/vssr/tblsection.htm | 193 +++++---- .../luasrc/view/vssr/update_subscribe.htm | 2 +- .../ctcgfw/luci-app-vssr/po/zh_Hans/vssr.po | 8 +- .../ctcgfw/luci-app-vssr/root/etc/init.d/vssr | 29 +- .../root/etc/uci-defaults/luci-vssr | 4 + .../luci-app-vssr/root/usr/bin/vssr-monitor | 20 +- .../luci-app-vssr/root/usr/bin/vssr-switch | 1 - .../root/usr/share/vssr/subscribe.lua | 53 ++- .../root/usr/share/vssr/subscribe.sh | 275 ------------ .../root/usr/share/vssr/update.sh | 25 -- .../root/www/luci-static/vssr/img/switch.png | Bin 0 -> 3771 bytes 19 files changed, 385 insertions(+), 746 deletions(-) delete mode 100644 package/ctcgfw/luci-app-vssr/luasrc/view/vssr/ping1.htm delete mode 100644 package/ctcgfw/luci-app-vssr/luasrc/view/vssr/subscribe.htm delete mode 100644 package/ctcgfw/luci-app-vssr/root/usr/share/vssr/subscribe.sh delete mode 100644 package/ctcgfw/luci-app-vssr/root/usr/share/vssr/update.sh create mode 100644 package/ctcgfw/luci-app-vssr/root/www/luci-static/vssr/img/switch.png diff --git a/package/ctcgfw/luci-app-vssr/Makefile b/package/ctcgfw/luci-app-vssr/Makefile index 4d04169f0e..7ba186e03c 100644 --- a/package/ctcgfw/luci-app-vssr/Makefile +++ b/package/ctcgfw/luci-app-vssr/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-vssr -PKG_VERSION:=1.24 -PKG_RELEASE:=20200315-4 +PKG_VERSION:=1.26 +PKG_RELEASE:=20200319-4 PKG_CONFIG_DEPENDS:= CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_V2ray \ @@ -13,6 +13,8 @@ PKG_CONFIG_DEPENDS:= CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Socks \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Socks \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ipt2socks \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_microsocks \ + CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_dns2socks \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_dnscrypt_proxy \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_dnsforwarder \ CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS \ @@ -63,7 +65,15 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Socks config PACKAGE_$(PKG_NAME)_INCLUDE_ipt2socks bool "Include ipt2socks" - default y + default y + +config PACKAGE_$(PKG_NAME)_INCLUDE_microsocks + bool "Include microsocks" + default n + +config PACKAGE_$(PKG_NAME)_INCLUDE_dns2socks + bool "Include dns2socks" + default n config PACKAGE_$(PKG_NAME)_INCLUDE_dnscrypt_proxy bool "Include dnscrypt-proxy-full" @@ -130,6 +140,8 @@ define Package/luci-app-vssr +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Socks:shadowsocksr-libev-ssr-local \ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Socks:shadowsocks-libev-ss-local \ +PACKAGE_$(PKG_NAME)_INCLUDE_ipt2socks:ipt2socks \ + +PACKAGE_$(PKG_NAME)_INCLUDE_microsocks:microsocks \ + +PACKAGE_$(PKG_NAME)_INCLUDE_dns2socks:dns2socks \ +PACKAGE_$(PKG_NAME)_INCLUDE_dnscrypt_proxy:dnscrypt-proxy-full \ +PACKAGE_$(PKG_NAME)_INCLUDE_dnsforwarder:dnsforwarder \ +PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS:openwrt_chinadns \ diff --git a/package/ctcgfw/luci-app-vssr/luasrc/controller/vssr.lua b/package/ctcgfw/luci-app-vssr/luasrc/controller/vssr.lua index 976b77b13a..55a754c79f 100644 --- a/package/ctcgfw/luci-app-vssr/luasrc/controller/vssr.lua +++ b/package/ctcgfw/luci-app-vssr/luasrc/controller/vssr.lua @@ -3,271 +3,209 @@ module("luci.controller.vssr", package.seeall) function index() - if not nixio.fs.access("/etc/config/vssr") then - return + if not nixio.fs.access("/etc/config/vssr") then + return end if nixio.fs.access("/usr/bin/ssr-redir") then - entry({"admin", "vpn"}, firstchild(), "VPN", 45).dependent = false - entry({"admin", "vpn", "vssr"}, - alias("admin", "vpn", "vssr", "client"), _("Hello World"), 10).dependent = - true -- 首页 - entry({"admin", "vpn", "vssr", "client"}, cbi("vssr/client"), - _("SSR Client"), 10).leaf = true -- 基本设置 - entry({"admin", "vpn", "vssr", "servers"}, cbi("vssr/servers"), - _("Node List"), 11).leaf = true -- 服务器节点 - entry({"admin", "vpn", "vssr", "servers"}, - arcombine(cbi("vssr/servers"), cbi("vssr/client-config")), - _("Node List"), 11).leaf = true -- 编辑节点 - entry({"admin", "vpn", "vssr", "subscription"},cbi("vssr/subscription"), - _("Subscription"),12).leaf = true - entry({"admin", "vpn", "vssr", "control"}, cbi("vssr/control"), - _("Access Control"), 13).leaf = true -- 访问控制 - entry({"admin", "vpn", "vssr", "servers-list"}, cbi("vssr/servers-list"), - _("Severs Nodes"), 14).leaf = true - entry({"admin", "vpn", "vssr", "appointlist"},form("vssr/appointlist"), - _("Appointlist List"), 15).leaf = true + entry({"admin", "vpn"}, firstchild(), "VPN", 45).dependent = false + entry({"admin", "vpn", "vssr"},alias("admin", "vpn", "vssr", "client"), _("Hello World"), 10).dependent=true + entry({"admin", "vpn", "vssr", "client"}, cbi("vssr/client"), _("SSR Client"), 10).leaf=true + entry({"admin", "vpn", "vssr", "servers"}, cbi("vssr/servers"), _("Node List"), 20).leaf=true + entry({"admin", "vpn", "vssr", "servers"}, arcombine(cbi("vssr/servers"), cbi("vssr/client-config")), _("Node List"), 20).leaf =true + entry({"admin", "vpn", "vssr", "subscription"},cbi("vssr/subscription"),_("Subscription"),30).leaf=true + entry({"admin", "vpn", "vssr", "control"}, cbi("vssr/control"), _("Access Control"), 40).leaf=true + entry({"admin", "vpn", "vssr", "servers-list"}, cbi("vssr/servers-list"), _("Severs Nodes"), 50).leaf =true + entry({"admin", "vpn", "vssr", "appointlist"},form("vssr/appointlist"),_("Appointlist List"),60).leaf =true + entry({"admin", "vpn", "vssr", "udp2raw"},cbi("vssr/udp2raw"),_("udp2raw tunnel"),70).leaf = true + entry({"admin", "vpn", "vssr", "advanced"}, cbi("vssr/advanced"),_("Advanced Settings"), 80).leaf =true + elseif nixio.fs.access("/usr/bin/ssr-server") then + entry({"admin", "vpn", "vssr"}, alias("admin", "vpn", "vssr", "server"), _("vssr"), 10).dependent =true + else + return + end + if nixio.fs.access("/usr/bin/ssr-server") then + entry({"admin", "vpn", "vssr", "server"},arcombine(cbi("vssr/server"), cbi("vssr/server-config")), _("SSR Server"), 85).leaf = true + end + entry({"admin", "vpn", "vssr", "status"},form("vssr/status"),_("Status"), 90).leaf = true + entry({"admin", "vpn", "vssr", "logview"}, cbi("vssr/logview", {hideapplybtn=true, hidesavebtn=true, hideresetbtn=true}), _("Log") ,100).leaf=true + entry({"admin", "vpn", "vssr", "refresh"}, call("refresh_data")) + entry({"admin", "vpn", "vssr", "checkport"}, call("check_port")) + entry({"admin", "vpn", "vssr", "checkports"}, call("check_ports")) + entry({"admin", "vpn", "vssr", "ping"}, call("act_ping")).leaf=true + entry({"admin", "vpn", "vssr", "fileread"}, call("act_read"), nil).leaf=true + entry({"admin", "vpn", "vssr", "switch"}, call("switch")) + entry({"admin", "vpn", "vssr", "run"}, call("act_status")) + entry({"admin", "vpn", "vssr", "change"}, call("change_node")) + entry({"admin", "vpn", "vssr", "allserver"}, call("get_servers")) + entry({"admin", "vpn", "vssr", "subscribe"}, call("get_subscribe")) + entry({"admin", "vpn", "vssr", "flag"}, call("get_flag")) + entry({"admin", "vpn", "vssr", "ip"}, call("check_ip")) - entry({"admin", "vpn", "vssr", "udp2raw"},cbi("vssr/udp2raw"), - _("udp2raw tunnel"),16).leaf = true - - entry({"admin", "vpn", "vssr", "advanced"}, cbi("vssr/advanced"), - _("Advanced Settings"), 17).leaf = true -- 高级设置 - elseif nixio.fs.access("/usr/bin/ssr-server") then - entry({"admin", "vpn", "vssr"}, - alias("admin", "vpn", "vssr", "server"), _("vssr"), 10).dependent = - true - else - return end - if nixio.fs.access("/usr/bin/ssr-server") then - entry({"admin", "vpn", "vssr", "server"}, - arcombine(cbi("vssr/server"), cbi("vssr/server-config")), - _("SSR Server"), 20).leaf = true - end -entry({"admin", "vpn", "vssr", "status"},form("vssr/status"),_("Status"), 23).leaf = true - -entry({"admin", "vpn", "vssr", "logview"}, cbi("vssr/logview", {hideapplybtn=true, hidesavebtn=true, hideresetbtn=true}), _("Log") ,80).leaf=true - - - entry({"admin", "vpn", "vssr", "refresh"}, call("refresh_data")) -- 更新白名单和GFWLIST - entry({"admin", "vpn", "vssr", "checkport"}, call("check_port")) -- 检测单个端口并返回Ping - entry({"admin", "vpn", "vssr", "checkports"}, call("check_ports")) - entry({"admin", "vpn", "vssr", "ping"}, call("act_ping")).leaf=true - entry({"admin", "vpn", "vssr", "fileread"}, call("act_read"), nil).leaf=true - entry({"admin", "vpn", "vssr", "run"}, call("act_status")) -- 检测全局服务器状态 - entry({"admin", "vpn", "vssr", "change"}, call("change_node")) -- 切换节点 - entry({"admin", "vpn", "vssr", "allserver"}, call("get_servers")) -- 获取所有节点Json - entry({"admin", "vpn", "vssr", "subscribe"}, call("get_subscribe")) -- 执行订阅 - entry({"admin", "vpn", "vssr", "flag"}, call("get_flag")) -- 获取节点国旗 iso code - entry({"admin", "vpn", "vssr", "ip"}, call("check_ip")) -- 获取ip情况 - -end - -- 执行订阅 function get_subscribe() - - local cjson = require "cjson" - local e = {} - local uci = luci.model.uci.cursor() - local auto_update = luci.http.formvalue("auto_update") - local auto_update_time = luci.http.formvalue("auto_update_time") - local proxy = luci.http.formvalue("proxy") - local subscribe_url = luci.http.formvalue("subscribe_url") - if subscribe_url ~= "[]" then - local cmd1 = 'uci set vssr.@server_subscribe[0].auto_update="' .. + local cjson = require "cjson" + local e = {} + local uci = luci.model.uci.cursor() + local auto_update = luci.http.formvalue("auto_update") + local auto_update_time = luci.http.formvalue("auto_update_time") + local proxy = luci.http.formvalue("proxy") + local subscribe_url = luci.http.formvalue("subscribe_url") + if subscribe_url ~= "[]" then + local cmd1 = 'uci set vssr.@server_subscribe[0].auto_update="' .. auto_update .. '"' - local cmd2 = 'uci set vssr.@server_subscribe[0].auto_update_time="' .. + local cmd2 = 'uci set vssr.@server_subscribe[0].auto_update_time="' .. auto_update_time .. '"' - local cmd3 = 'uci set vssr.@server_subscribe[0].proxy="' .. proxy .. '"' - luci.sys.call('uci delete vssr.@server_subscribe[0].subscribe_url ') - luci.sys.call(cmd1) - luci.sys.call(cmd2) - luci.sys.call(cmd3) - for k, v in ipairs(cjson.decode(subscribe_url)) do - luci.sys.call( - 'uci add_list vssr.@server_subscribe[0].subscribe_url="' .. v .. - '"') - end - luci.sys.call('uci commit vssr') - luci.sys.call( + local cmd3 = 'uci set vssr.@server_subscribe[0].proxy="' .. proxy .. '"' + luci.sys.call('uci delete vssr.@server_subscribe[0].subscribe_url ') + luci.sys.call(cmd1) + luci.sys.call(cmd2) + luci.sys.call(cmd3) + for k, v in ipairs(cjson.decode(subscribe_url)) do + luci.sys.call( + 'uci add_list vssr.@server_subscribe[0].subscribe_url="' .. v .. '"') + end + luci.sys.call('uci commit vssr') + luci.sys.call( "nohup /usr/bin/lua /usr/share/vssr/subscribe.lua >/www/check_update.htm 2>/dev/null &") - - e.error = 0 - else - e.error = 1 + + e.error = 0 + else + e.error = 1 end - luci.http.prepare_content("application/json") - luci.http.write_json(e) - -end + luci.http.prepare_content("application/json") + luci.http.write_json(e) + end -- 获取所有节点 function get_servers() - local uci = luci.model.uci.cursor() - local server_table = {} - uci:foreach("vssr", "servers", function(s) - local e = {} - e["name"] = s[".name"] - local t1 = luci.sys.exec( + local uci = luci.model.uci.cursor() + local server_table = {} + uci:foreach("vssr", "servers", function(s) + local e = {} + e["name"] = s[".name"] + local t1 = luci.sys.exec( "ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*.[0-9]' | awk -F '=' '{print$2}'" % s["server"]) - e["t1"] = t1 - table.insert(server_table, e) + e["t1"] = t1 + table.insert(server_table, e) end) - luci.http.prepare_content("application/json") - luci.http.write_json(server_table) + luci.http.prepare_content("application/json") + luci.http.write_json(server_table) end -- 切换节点 function change_node() - local e = {} - local uci = luci.model.uci.cursor() - local sid = luci.http.formvalue("set") - local name = "" - uci:foreach("vssr", "global", function(s) name = s[".name"] end) - e.status = false - e.sid = sid - if sid ~= "" then - uci:set("vssr", name, "global_server", sid) - uci:commit("vssr") - luci.sys.call("/etc/init.d/vssr restart") - e.status = true + local e = {} + local uci = luci.model.uci.cursor() + local sid = luci.http.formvalue("set") + local name = "" + uci:foreach("vssr", "global", function(s) name = s[".name"] end) + e.status = false + e.sid = sid + if sid ~= "" then + uci:set("vssr", name, "global_server", sid) + uci:commit("vssr") + luci.sys.call("/etc/init.d/vssr restart") + e.status = true end - luci.http.prepare_content("application/json") - luci.http.write_json(e) + luci.http.prepare_content("application/json") + luci.http.write_json(e) end +function switch() + local e = {} + local uci = luci.model.uci.cursor() + local sid = luci.http.formvalue("node") + local isSwitch = uci:get("vssr", sid, "switch_enable") + if isSwitch == "1" then + uci:set("vssr", sid, "switch_enable","0") + e.switch = false + else + uci:set("vssr", sid, "switch_enable","1") + e.switch = true + end + uci:commit("vssr") + e.status = true + luci.http.prepare_content("application/json") + luci.http.write_json(e) + end + + -- 检测全局服务器状态 function act_status() - math.randomseed(os.time()) - local e = {} - -- 全局服务器 - e.global=luci.sys.call("ps -w | grep ssr-retcp | grep -v grep >/dev/null") == 0 + math.randomseed(os.time()) + local e = {} +-- 全局服务器 + e.global=luci.sys.call("ps -w | grep ssr-retcp | grep -v grep >/dev/null") == 0 +-- 检测Socks5 ---检测负载均衡状态 - if tonumber(luci.sys.exec("ps -w | grep haproxy |grep -v grep| wc -l"))>0 then - e.haproxy= true - end ---检测kcptun状态 - if tonumber(luci.sys.exec("ps -w | grep kcptun-client |grep -v grep| wc -l"))>0 then - e.kcptun= true - end ---检测HTTP代理状态 - if luci.sys.call("pidof privoxy >/dev/null") == 0 then - e.privoxy= true - end - --检测chinadns状态 - if tonumber(luci.sys.exec("ps -w | grep chinadns |grep -v grep| wc -l"))>0 then - e.chinadns= true - elseif tonumber(luci.sys.exec("ps -w | grep dnsparsing |grep -v grep| wc -l"))>0 then - e.chinadns= true - elseif tonumber(luci.sys.exec("ps -w | grep dnscrypt-proxy |grep -v grep| wc -l"))>0 then - e.chinadns= true - elseif tonumber(luci.sys.exec("ps -w | grep pdnsd |grep -v grep| wc -l"))>0 then - e.chinadns= true - - elseif tonumber(luci.sys.exec("ps -w | grep dnsforwarder |grep -v grep| wc -l"))>0 then - e.chinadns= true - - end - --检测SOCKS5状态 - if tonumber(luci.sys.exec("ps -w | grep ssr-local |grep -v grep| wc -l"))>0 then - e.SOCKS5= true - elseif tonumber(luci.sys.exec("ps -w | grep ss-local |grep -v grep| wc -l"))>0 then - e.SOCKS5= true - elseif tonumber(luci.sys.exec("ps -w | grep v2-ssr-local |grep -v grep| wc -l"))>0 then - e.SOCKS5= true - elseif tonumber(luci.sys.exec("ps -w | grep trojan-ssr-local |grep -v grep| wc -l"))>0 then - e.SOCKS5= true - end ---检测UDP2RAW状态 - if tonumber(luci.sys.exec("ps -w | grep udp2raw |grep -v grep| wc -l"))>0 then - e.udp2raw= true + if tonumber(luci.sys.exec("ps -w | grep ssr-local |grep -v grep| wc -l"))>0 then + e.socks5 = true + elseif tonumber(luci.sys.exec("ps -w | grep ss-local |grep -v grep| wc -l"))>0 then + e.socks5 = true + elseif tonumber(luci.sys.exec("ps -w | grep v2-ssr-local |grep -v grep| wc -l"))>0 then + end +--检测chinadns状态 + if tonumber(luci.sys.exec("ps -w | grep chinadns |grep -v grep| wc -l"))>0 then + e.chinadns= true + elseif tonumber(luci.sys.exec("ps -w | grep dnsparsing |grep -v grep| wc -l"))>0 then + e.chinadns= true + elseif tonumber(luci.sys.exec("ps -w | grep dnscrypt-proxy |grep -v grep| wc -l"))>0 then + e.chinadns= true + elseif tonumber(luci.sys.exec("ps -w | grep pdnsd |grep -v grep| wc -l"))>0 then + e.chinadns= true + elseif tonumber(luci.sys.exec("ps -w | grep dns2socks |grep -v grep| wc -l"))>0 then + e.chinadns= true + + elseif tonumber(luci.sys.exec("ps -w | grep dnsforwarder |grep -v grep| wc -l"))>0 then + e.chinadns= true end ---检测UDPspeeder状态 - if tonumber(luci.sys.exec("ps -w | grep udpspeeder |grep -v grep| wc -l"))>0 then - e.udpspeeder= true - end - --检测服务端状态 - if tonumber(luci.sys.exec("ps -w | grep ssr-server |grep -v grep| wc -l"))>0 then - e.server= true - end - if luci.sys.call("pidof ssr-server >/dev/null") == 0 then - e.ssr_server= true - end - if luci.sys.call("pidof ss-server >/dev/null") == 0 then - e.ss_server= true +--检测服务端状态 + if tonumber(luci.sys.exec("ps -w | grep ssr-server |grep -v grep| wc -l"))>0 then + e.server= true +end + if luci.sys.call("pidof ssr-server >/dev/null") == 0 then + e.ssr_server= true +end + if luci.sys.call("pidof ss-server >/dev/null") == 0 then + e.ss_server= true - end -if luci.sys.call("ps -w | grep trojan-server | grep -v grep >/dev/null") == 0 then - e.trojan_server= true +end + + if luci.sys.call("ps -w | grep v2ray-server | grep -v grep >/dev/null") == 0 then + e.v2_server= true + +end + + -- 检测国内通道 + e.baidu = false + sret = luci.sys.call("/usr/bin/ssr-check www.baidu.com 80 3 1") + if sret == 0 then + e.baidu = true +end + + -- 检测国外通道 + e.google = false + sret = luci.sys.call("/usr/bin/ssr-check www.google.com 80 3 1") + if sret == 0 then + e.google = true +end - end - if luci.sys.call("ps -w | grep v2ray-server | grep -v grep >/dev/null") == 0 then - e.v2_server= true - - - end - -- 检测游戏模式状态 +-- 检测游戏模式状态 e.game = false if tonumber(luci.sys.exec("ps -w | grep ssr-reudp |grep -v grep| wc -l"))>0 then - e.game= true + e.game= true else if tonumber(luci.sys.exec("ps -w | grep ssr-retcp |grep \"\\-u\"|grep -v grep| wc -l"))>0 then e.game= true end end - - -- 检测国外通道 - --[[ http=require("socket.http") - http.TIMEOUT = 1 - result=http.request("http://ip111cn.appspot.com/?z="..math.random(1,100000)) - if result then - e.google = result - else - e.google = false - end - - result1=http.request("http://45.32.164.128/ip.php?z="..math.random(1,100000)) - if result1 then - e.outboard = result1 - else - e.outboard = false - end - --]] - - -- 检测国内通道 - e.baidu = false - sret = luci.sys.call("/usr/bin/ssr-check www.baidu.com 80 3 1") - if sret == 0 then - e.baidu = true - end - - -- 检测国外通道 - e.google = false - sret = luci.sys.call("/usr/bin/ssr-check www.google.com 80 3 1") - if sret == 0 then - e.google = true - end - - - -- 检测Socks5 - - if tonumber(luci.sys.exec("ps -w | grep ssr-local |grep -v grep| wc -l"))>0 then - e.socks5 = true - elseif tonumber(luci.sys.exec("ps -w | grep ss-local |grep -v grep| wc -l"))>0 then - e.socks5 = true - elseif tonumber(luci.sys.exec("ps -w | grep v2-ssr-local |grep -v grep| wc -l"))>0 then - e.socks5 = true - elseif tonumber(luci.sys.exec("ps -w | grep trojan-ssr-local |grep -v grep| wc -l"))>0 then - e.socks5 = true - end - luci.http.prepare_content("application/json") luci.http.write_json(e) end @@ -291,9 +229,6 @@ function act_ping() luci.http.write_json(e) end - - - function check_status() local set ="/usr/bin/ssr-check www." .. luci.http.formvalue("set") .. ".com 80 3 1" sret=luci.sys.call(set) @@ -301,7 +236,7 @@ function check_status() retstring ="0" else retstring ="1" - end + end luci.http.prepare_content("application/json") luci.http.write_json({ ret=retstring }) @@ -389,8 +324,6 @@ luci.http.prepare_content("application/json") luci.http.write_json({ ret=retstring ,retcount=icount}) end - - -- 检测所有服务器 function check_ports() local set = "" @@ -431,7 +364,6 @@ function check_ports() luci.http.write_json({ret = retstring}) end - -- 检测单个节点状态并返回连接速度 function check_port() @@ -500,7 +432,6 @@ function check_ip() else e.outboard = false end - -- 检测国内通道 e.baidu = false sret1 = luci.sys.call("/usr/bin/ssr-check www.baidu.com 80 3 1") diff --git a/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/client.lua b/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/client.lua index 789aad0cb7..87c4b6139f 100644 --- a/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/client.lua +++ b/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/client.lua @@ -95,8 +95,6 @@ o:value("16", translate("16 Threads")) o:value("32", translate("32 Threads")) o:value("64", translate("64 Threads")) o:value("128", translate("128 Threads")) -o:value("256", translate("256 Threads")) -o:value("512", translate("512 Threads")) o.default = "0" o.rmempty = false @@ -125,7 +123,9 @@ end if nixio.fs.access("/usr/bin/chinadns") then o:value("6", translate("Use chinadns query and cache")) end - +if nixio.fs.access("/usr/bin/dns2socks") then +o:value("7", translate("Use DNS2SOCKS query and cache")) +end o.default = 1 o = s:option(ListValue, "chinadns_enable", translate("Chiadns Resolve Dns Mode")) @@ -138,13 +138,6 @@ if nixio.fs.access("/usr/bin/dnscrypt-proxy") then o:value("5", translate("Use dnscrypt-proxy query and cache")) end -if nixio.fs.access("/usr/sbin/smartdns") then -o:value("6", translate("Use smartdns query and cache")) -end - -if nixio.fs.access("/usr/sbin/https_dns_proxy") then -o:value("7", translate("Use https_dns_proxy query and cache")) -end o.default = 1 o:depends("pdnsd_enable", "6") @@ -170,6 +163,7 @@ o:depends("pdnsd_enable", "3") o:depends("pdnsd_enable", "4") o:depends("pdnsd_enable", "5") o:depends("pdnsd_enable", "6") +o:depends("pdnsd_enable", "7") o.default = "8.8.4.4:53" diff --git a/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/status.lua b/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/status.lua index 47a5ec218d..1d3b5f7a35 100644 --- a/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/status.lua +++ b/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/status.lua @@ -1,7 +1,7 @@ -- Copyright (C) 2017 yushi studio -- Licensed to the public under the GNU General Public License v3. -local IPK_Version="20200315.1.24" +local IPK_Version="20200319.1.26" local m, s, o local redir_run=0 local reudp_run=0 @@ -23,6 +23,7 @@ local pdnsd_run=0 local dnsforwarder_run=0 local dnscrypt_proxy_run=0 local chinadns_run=0 +local dns2socks_run=0 local haproxy_run=0 local privoxy_run=0 @@ -259,6 +260,9 @@ if luci.sys.call("pidof dnscrypt-proxy >/dev/null") == 0 then dnscrypt_proxy_run=1 end +if luci.sys.call("pidof dns2socks >/dev/null") == 0 then +dns2socks_run=1 +end if luci.sys.call("pidof haproxy >/dev/null") == 0 then haproxy_run=1 @@ -317,6 +321,16 @@ else s.value = translate("Not Running") end +if nixio.fs.access("/usr/bin/dns2socks") then +s=m:field(DummyValue,"dns2socks_run",translate("DNS2SOCKS")) +s.rawhtml = true +if dns2socks_run == 1 then +s.value =font_blue .. bold_on .. translate("Running") .. bold_off .. font_off +else +s.value = translate("Not Running") +end +end + s=m:field(DummyValue,"dnsforwarder_run",translate("dnsforwarder")) s.rawhtml = true if dnsforwarder_run == 1 then diff --git a/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/subscription.lua b/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/subscription.lua index 49a957ab87..c4857495dd 100644 --- a/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/subscription.lua +++ b/package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/subscription.lua @@ -56,21 +56,12 @@ o.description = translate("Through proxy update list, Not Recommended ") o = s:option(Flag, "switch", translate("Subscribe Default Auto-Switch")) o.rmempty = false o.description = translate("Subscribe new add server default Auto-Switch on") -o.default="1" +o.default="0" o = s:option(DummyValue, "", "") o.rawhtml = true o.template = "vssr/update_subscribe" - -o = s:option(Button,"update",translate("Update All Subscribe Severs"), "" .. translate("No special needs, please click here to subscribe to update") .."") -o.inputstyle = "reload" -o.write = function() - luci.sys.call("bash /usr/share/vssr/subscribe.sh >>/tmp/vssr.log 2>&1") - luci.http.redirect(luci.dispatcher.build_url("admin", "vpn", "vssr", "servers")) -end - - o = s:option(Button,"delete",translate("Delete All Subscribe Severs")) o.inputstyle = "reset" o.description = string.format(translate("Server Count") .. ": %d", server_count) diff --git a/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/ping1.htm b/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/ping1.htm deleted file mode 100644 index 5281070999..0000000000 --- a/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/ping1.htm +++ /dev/null @@ -1,28 +0,0 @@ -<%+cbi/valueheader%> --- ms -<%+cbi/valuefooter%> - - - diff --git a/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/ssrurl.htm b/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/ssrurl.htm index 5991e3d02b..818961674b 100644 --- a/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/ssrurl.htm +++ b/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/ssrurl.htm @@ -202,7 +202,7 @@ s.innerHTML = "导入Shadowsocks配置信息成功"; } return false; - } else if (ssu[0] == "trojan") { + } else if (ssu[0] == "trojan") { var url0, param = ""; var ploc = ssu[1].indexOf("#"); if (ploc > 0) { @@ -212,15 +212,32 @@ url0 = ssu[1] } var sstr = url0; + document.getElementById('cbid.vssr.' + sid + '.type').value = "trojan"; document.getElementById('cbid.vssr.' + sid + '.type').dispatchEvent(event); var team = sstr.split('@'); var password = team[0] var serverPart = team[1].split(':'); - var port = serverPart[1].split('?')[0]; + var others = serverPart[1].split('?'); + var port = others[0] + var queryParam = {} + if(others.length > 1) { + var queryParams = others[1] + var queryArray = queryParams.split('&') + for (i = 0; i < queryArray.length; i++) { + var params = queryArray[i].split('='); + queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || ''); + } + } + document.getElementById('cbid.vssr.' + sid + '.server').value = serverPart[0]; document.getElementById('cbid.vssr.' + sid + '.server_port').value = port; document.getElementById('cbid.vssr.' + sid + '.password').value = password; + document.getElementById('cbid.vssr.' + sid + '.tls').checked = true; + document.getElementById('cbid.vssr.' + sid + '.tls').dispatchEvent(event); + document.getElementById('cbid.vssr.' + sid + '.tls_host').value = queryParam.peer || ''; + document.getElementById('cbid.vssr.' + sid + '.insecure').checked = queryParam.allowInsecure === '1'; + if (param != undefined) { document.getElementById('cbid.vssr.' + sid + '.alias').value = decodeURI(param); } diff --git a/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/subscribe.htm b/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/subscribe.htm deleted file mode 100644 index 45cb43aa80..0000000000 --- a/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/subscribe.htm +++ /dev/null @@ -1,18 +0,0 @@ -<%+cbi/valueheader%> - - - -<%+cbi/valuefooter%> diff --git a/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/tblsection.htm b/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/tblsection.htm index b5b3b849be..3c842a75da 100644 --- a/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/tblsection.htm +++ b/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/tblsection.htm @@ -1,11 +1,11 @@
- <%:Node list%> (<%:total%> + <%:Node list%> (<%:total%>   <%- print(self.des)-%><%:Nodes%>)
<%- local count = 0 -%> @@ -20,22 +20,17 @@
-
- -
+ \ No newline at end of file diff --git a/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/update_subscribe.htm b/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/update_subscribe.htm index 15932c2ff7..a2f2e4da3d 100644 --- a/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/update_subscribe.htm +++ b/package/ctcgfw/luci-app-vssr/luasrc/view/vssr/update_subscribe.htm @@ -1,6 +1,6 @@ <%+cbi/valueheader%> - +
"> diff --git a/package/ctcgfw/luci-app-vssr/po/zh_Hans/vssr.po b/package/ctcgfw/luci-app-vssr/po/zh_Hans/vssr.po index c0e904ef6a..6cd2bda08b 100644 --- a/package/ctcgfw/luci-app-vssr/po/zh_Hans/vssr.po +++ b/package/ctcgfw/luci-app-vssr/po/zh_Hans/vssr.po @@ -516,8 +516,6 @@ msgstr "通过代理更新" msgid "GFW List" msgstr "GFW列表" -msgid "ShadowSocksR Plus+ Settings" -msgstr "ShadowSocksR Plus+ 设置(支持SS/SSR/V2RAY/Trojan)" msgid "Main Server" msgstr "主服务器" @@ -862,8 +860,8 @@ msgstr "删除所有订阅服务器节点" msgid "Update All Subscribe Severs" msgstr "更新所有订阅服务器节点" -msgid "No special needs, please click here to subscribe to update" -msgstr "没有特殊需要,请点击这里订阅更新" +msgid "Use DNS2SOCKS query and cache" +msgstr "使用 DNS2SOCKS 查询并缓存" msgid "Running Details:" msgstr "进程详情:" @@ -884,4 +882,4 @@ msgid "Join the white list of domain names will not go agent." msgstr "加入的域名不走代理通道,对所有模式有效。且优先于黑名单。" msgid "These had been joined websites will use proxy.Please input the domain names of websites,every line can input only one website domain.For example,google.com." -msgstr "加入的域名将走代理,对所有模式有效。输入网站域名,如:google.com,每个地址段一行。" \ No newline at end of file +msgstr "加入的域名将走代理,对所有模式有效。输入网站域名,如:google.com,每个地址段一行。" diff --git a/package/ctcgfw/luci-app-vssr/root/etc/init.d/vssr b/package/ctcgfw/luci-app-vssr/root/etc/init.d/vssr index ff3cf09081..154e0996cb 100755 --- a/package/ctcgfw/luci-app-vssr/root/etc/init.d/vssr +++ b/package/ctcgfw/luci-app-vssr/root/etc/init.d/vssr @@ -27,7 +27,6 @@ kcp_flag=0 pdnsd_enable_flag=0 dnsforwarder_enable_flag=0 chinadns_enable_flag=0 -dnscrypt-proxy_enable_flag=0 switch_enable=0 ssserver_enable=0 ssrserver_enable=0 @@ -50,13 +49,9 @@ uci_get_by_type() { } add_cron() { - sed -i '/vssr/d' $CRON_FILE - sed -i '/vssr.log/d' $CRON_FILE && echo '0 1 * * * echo "" > /tmp/vssr.log' >>$CRON_FILE -# [ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/bin/lua /usr/share/vssr/subscribe.lua" >>$CRON_FILE - [ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 5 * * * /usr/bin/lua /usr/share/vssr/update.lua" >>$CRON_FILE - [ -n "$(grep -w "/usr/share/vssr/subscribe.sh" $CRON_FILE)" ] && sed -i '/\/usr\/share\/vssr\/subscribe.sh/d' $CRON_FILE - [ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/share/vssr/subscribe.sh" >> $CRON_FILE - [ -z "$(grep -w "/usr/share/vssr/update.sh" $CRON_FILE)" ] && echo "0 5 * * 0 /usr/share/vssr/update.sh" >> $CRON_FILE + sed -i '/vssr.log/d' $CRON_FILE && echo '0 1 * * * echo "" > /tmp/vssr.log' >> $CRON_FILE + [ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/bin/lua /usr/share/vssr/subscribe.lua" >> $CRON_FILE + [ $(uci_get_by_type server_subscribe auto_update 0) -eq 1 ] && echo "0 $(uci_get_by_type server_subscribe auto_update_time) * * * /usr/bin/lua /usr/share/vssr/update.lua" >> $CRON_FILE crontab $CRON_FILE } @@ -709,6 +704,7 @@ fi #deal with dns if [ "$(uci_get_by_type global pdnsd_enable)" -ne "0" ] ;then + local ssr_dns="$(uci_get_by_type global pdnsd_enable 0)" local dnsstr="$(uci_get_by_type global tunnel_forward 8.8.4.4:53)" local dnsserver=`echo "$dnsstr"|awk -F ':' '{print $1}'` local dnsport=`echo "$dnsstr"|awk -F ':' '{print $2}'` @@ -753,6 +749,10 @@ fi fi nohup /usr/bin/chinadns -p 5335 -c /etc/china_ssr.txt -m -d -s $dnsstrs >/dev/null 2>&1 & chinadns_enable_flag=1 + elif [ "$ssr_dns" == "7" ]; then + microsocks -i 127.0.0.1 -p 10802 ssr-dns >/dev/null 2>&1 & + dns2socks 127.0.0.1:10802 $dnsserver:$dnsport 127.0.0.1:5335 -q >/dev/null 2>&1 & + pdnsd_enable_flag=1 fi fi @@ -1020,11 +1020,11 @@ start() { start_server start_local if [ $(uci_get_by_type global monitor_enable 0) == "1" ]; then - let total_count=server_count+redir_tcp+redir_udp+tunnel_enable+kcp_enable_flag+local_enable+pdnsd_enable_flag+dnsforwarder_enable_flag+switch_enable+ssserver_enable+ssrserver_enable+v2rayserver_enable+haproxy_enable+privoxy_enable+chinadns_enable_flag+dnscrypt-proxy_enable_flag + let total_count=server_count+redir_tcp+redir_udp+tunnel_enable+kcp_enable_flag+local_enable+pdnsd_enable_flag+dnsforwarder_enable_flag+switch_enable+ssserver_enable+ssrserver_enable+v2rayserver_enable+haproxy_enable+privoxy_enable+chinadns_enable_flag if [ $total_count -gt 0 ] ;then #param:server(count) redir_tcp(0:no,1:yes) redir_udp tunnel kcp local gfw - service_start /usr/bin/vssr-monitor $server_count $redir_tcp $redir_udp $tunnel_enable $kcp_enable_flag $local_enable $pdnsd_enable_flag $dnsforwarder_enable_flag $switch_enable $ssserver_enable $ssrserver_enable $v2rayserver_enable $haproxy_enable $privoxy_enable $chinadns_enable_flag $dnscrypt-proxy_enable_flag + service_start /usr/bin/vssr-monitor $server_count $redir_tcp $redir_udp $tunnel_enable $kcp_enable_flag $local_enable $pdnsd_enable_flag $dnsforwarder_enable_flag $switch_enable $ssserver_enable $ssrserver_enable $v2rayserver_enable $haproxy_enable $privoxy_enable $chinadns_enable_flag fi fi ENABLE_SERVER=$(uci_get_by_type global global_server nil) @@ -1052,7 +1052,7 @@ stop() { killall -q -9 vssr-monitor killall -q -9 ss-redir killall -q -9 ssr-redir - killall -q -9 trojan + killall -q -9 trojan killall -q -9 v2ray killall -q -9 ssr-server killall -q -9 ss-server @@ -1061,15 +1061,16 @@ stop() { killall -q -9 ss-local killall -q -9 haproxy killall -q -9 privoxy - killall -q -9 ipt2socks + killall -q -9 ipt2socks + killall -q -9 dns2socks killall -q -9 v2ray-plugin killall -q -9 gq-client killall -q -9 gq-server killall -q -9 obfs-local killall -q -9 obfs-server killall -q -9 chinadns - killall -q -9 udp2raw - killall -q -9 udpspeeder + killall -q -9 udp2raw + killall -q -9 udpspeeder if [ -f /var/run/pdnsd.pid ]; then kill $(cat /var/run/pdnsd.pid) >/dev/null 2>&1 else diff --git a/package/ctcgfw/luci-app-vssr/root/etc/uci-defaults/luci-vssr b/package/ctcgfw/luci-app-vssr/root/etc/uci-defaults/luci-vssr index 5128a475e4..dcb6b38e69 100755 --- a/package/ctcgfw/luci-app-vssr/root/etc/uci-defaults/luci-vssr +++ b/package/ctcgfw/luci-app-vssr/root/etc/uci-defaults/luci-vssr @@ -13,6 +13,10 @@ uci -q batch <<-EOF >/dev/null commit firewall EOF +/etc/init.d/dnscrypt-proxy stop +/etc/init.d/dnscrypt-proxy disable +/etc/init.d/privoxy stop +/etc/init.d/privoxy disable killall -q -9 v2ray-plugin /usr/share/vssr/gfw2ipset.sh diff --git a/package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-monitor b/package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-monitor index 6fe8a7bec0..dee5d92591 100755 --- a/package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-monitor +++ b/package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-monitor @@ -29,6 +29,7 @@ kcp_process=$5 local_process=$6 pdnsd_process=$7 dnsforwarder_process=$8 +dns2socks_process=$9 ssserver_process=$10 ssrserver_process=$11 v2rayserver_process=$12 @@ -219,7 +220,6 @@ do if [ $icount -lt $pdnsd_process ] #如果进程挂掉就重启它 then logger -t "$NAME" "pdnsd tunnel error.restart!" - echo "$(date "+%Y-%m-%d %H:%M:%S") pdnsd tunnel error.restart!" >> ${logfile} if [ -f /var/run/pdnsd.pid ] ;then kill $(cat /var/run/pdnsd.pid) >/dev/null 2>&1 else @@ -229,6 +229,22 @@ do ( /usr/sbin/pdnsd -c /var/etc/pdnsd.conf -d &) fi fi + +#dns2socks + if [ "$pdnsd_process" -eq 2 ]; then + icount=$(busybox ps -w | grep -e ssr-dns -e dns2socks | grep -v grep | wc -l) + if [ "$icount" -lt 2 ]; then #如果进程挂掉就重启它 + logger -t "$NAME" "dns2socks $dnsstr tunnel error.restart!" + echo "$(date "+%Y-%m-%d %H:%M:%S") dns2socks tunnel error.restart!" >> ${logfile} + dnsstr=$(uci_get_by_type global tunnel_forward 8.8.4.4:53) + dnsserver=$(echo "$dnsstr" | awk -F ':' '{print $1}') + dnsport=$(echo "$dnsstr" | awk -F ':' '{print $2}') + killall -q -9 dns2socks + kill -9 $(busybox ps -w | grep ssr-dns | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + microsocks -i 127.0.0.1 -p 10802 ssr-dns >/dev/null 2>&1 & + dns2socks 127.0.0.1:10802 $dnsserver:$dnsport 127.0.0.1:5335 -q >/dev/null 2>&1 & + fi + fi #chiandns if [ $chinadns_process -gt 0 ] ;then icount=`ps -w | grep chinadns |grep -v grep| wc -l` @@ -275,3 +291,5 @@ do fi done + + diff --git a/package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-switch b/package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-switch index 108c921aca..b08e010026 100755 --- a/package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-switch +++ b/package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-switch @@ -166,4 +166,3 @@ start() { fi done } - diff --git a/package/ctcgfw/luci-app-vssr/root/usr/share/vssr/subscribe.lua b/package/ctcgfw/luci-app-vssr/root/usr/share/vssr/subscribe.lua index 8c6f99095e..9c2cb7a976 100644 --- a/package/ctcgfw/luci-app-vssr/root/usr/share/vssr/subscribe.lua +++ b/package/ctcgfw/luci-app-vssr/root/usr/share/vssr/subscribe.lua @@ -1,13 +1,13 @@ #!/usr/bin/lua ------------------------------------------------ --- This file is part of the luci-app-vssr subscribe.lua +-- This file is part of the luci-app-ssr-plus subscribe.lua -- @author William Chan ------------------------------------------------ require 'nixio' require 'luci.util' require 'luci.jsonc' require 'luci.sys' - +require 'uci' -- these global functions are accessed all the time by the event handler -- so caching them is worth the effort local luci = luci @@ -262,8 +262,6 @@ local function processData(szType, content) if not result.alias then result.alias = result.server .. ':' .. result.server_port end - local flag = luci.sys.exec('/usr/share/'..name..'/getflag.sh "'..result.alias..'" '..result.server) - result.flag = string.gsub(flag, '\n', '') -- alias 不参与 hashkey 计算 local alias = result.alias result.alias = nil @@ -272,11 +270,13 @@ local function processData(szType, content) result.hashkey = md5(jsonStringify(result)) result.alias = alias result.switch_enable = switch_enable + local flag = luci.sys.exec('/usr/share/'..name..'/getflag.sh "'..result.alias..'" '..result.server) + result.flag = string.gsub(flag, '\n', '') return result end -- wget local function wget(url) - local stdout = luci.sys.exec('wget-ssl --user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36" --no-check-certificate -t 3 -T 10 -O- "' .. url .. '"') + local stdout = luci.sys.exec('wget-ssl --user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36" --no-check-certificate -t 3 -T 10 -O- "' .. url .. '"') return trim(stdout) end @@ -356,17 +356,13 @@ local execute = function() end end log('成功解析节点数量: ' ..#nodes) - else - log(url .. ': 获取内容为空') + end end end -- diff do - if next(nodeResult) == nil then - log("更新失败,没有可用的节点信息") - return - end + assert(next(nodeResult), "node result is empty") local add, del = 0, 0 ucic:foreach(name, uciType, function(old) if old.grouphashkey or old.hashkey then -- 没有 hash 的不参与删除 @@ -380,10 +376,11 @@ local execute = function() setmetatable(nodeResult[old.grouphashkey][old.hashkey], { __index = { _ignore = true } }) end else - if not old.alias then - old.alias = old.server .. ':' .. old.server_port - end - log('忽略手动添加的节点: ' .. old.alias) + if (old.alias ~= nil) then + log('忽略手动添加的节点: ' .. old.alias) + else + log('忽略手动添加的无效节点') + end end end) @@ -401,25 +398,23 @@ local execute = function() -- 如果原有服务器节点已经不见了就尝试换为第一个节点 local globalServer = ucic:get_first(name, 'global', 'global_server', '') local firstServer = ucic:get_first(name, uciType) - if firstServer then - if not ucic:get(name, globalServer) then - luci.sys.call("/etc/init.d/" .. name .. " stop > /dev/null 2>&1 &") - ucic:commit(name) - ucic:set(name, ucic:get_first(name, 'global'), 'global_server', ucic:get_first(name, uciType)) + if not ucic:get(name, globalServer) then + if firstServer then + ucic:set(name, ucic:get_first(name, 'global'), 'global_server', firstServer) ucic:commit(name) log('当前主服务器节点已被删除,正在自动更换为第一个节点。') - luci.sys.call("/etc/init.d/" .. name .. " start > /dev/null 2>&1 &") - else - log('维持当前主服务器节点。') - luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") - end + + end + end + if firstServer then + luci.sys.call("/etc/init.d/" .. name .. " restart > /dev/null 2>&1 &") + else - log('没有服务器节点了,停止服务') - luci.sys.call("/etc/init.d/" .. name .. " stop > /dev/null 2>&1 &") + luci.sys.call("/etc/init.d/" .. name .. " stop > /dev/null 2>&1 &") end log('新增节点数量: ' ..add, '删除节点数量: ' .. del) - log("END SUBSCRIBE") log('订阅更新成功') + log("END SUBSCRIBE") end end @@ -427,8 +422,8 @@ if subscribe_url and #subscribe_url > 0 then xpcall(execute, function(e) log(e) log(debug.traceback()) - log("END SUBSCRIBE") log('发生错误, 正在恢复服务') + log("END SUBSCRIBE") local firstServer = ucic:get_first(name, uciType) if firstServer then luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 diff --git a/package/ctcgfw/luci-app-vssr/root/usr/share/vssr/subscribe.sh b/package/ctcgfw/luci-app-vssr/root/usr/share/vssr/subscribe.sh deleted file mode 100644 index b6825c6a66..0000000000 --- a/package/ctcgfw/luci-app-vssr/root/usr/share/vssr/subscribe.sh +++ /dev/null @@ -1,275 +0,0 @@ -#!/bin/bash -# Copyright (C) 2017 XiaoShan https://www.mivm.cn - -. /usr/share/libubox/jshn.sh - -urlsafe_b64decode() { - local d="====" data=$(echo $1 | sed 's/_/\//g; s/-/+/g') - local mod4=$((${#data} % 4)) - [ $mod4 -gt 0 ] && data=${data}${d:mod4} - echo $data | base64 -d -} - -urldecode() { - : "${*//+/ }" - echo -e "${_//%/\\x}" -} - -echo_date() { - echo $(TZ=UTC-8 date -R +%Y-%m-%d\ %X):$1 -} - - -Server_Update() { - local uci_set="uci -q set $name.$1." - local flag=$(/usr/share/$name/getflag.sh "$ssr_remarks" $ssr_host) - ${uci_set}grouphashkey="$ssr_grouphashkey" - ${uci_set}hashkey="$ssr_hashkey" - ${uci_set}alias="[$ssr_group] $ssr_remarks" - ${uci_set}auth_enable="0" - ${uci_set}switch_enable="1" - ${uci_set}type="$ssr_type" - ${uci_set}flag="$flag" - ${uci_set}server="$ssr_host" - ${uci_set}server_port="$ssr_port" - ${uci_set}local_port="1234" - uci -q get $name.@servers[$1].timeout >/dev/null || ${uci_set}timeout="60" - ${uci_set}password="$ssr_passwd" - ${uci_set}encrypt_method="$ssr_method" - ${uci_set}protocol="$ssr_protocol" - ${uci_set}protocol_param="$ssr_protoparam" - ${uci_set}obfs="$ssr_obfs" - ${uci_set}obfs_param="$ssr_obfsparam" - ${uci_set}fast_open="0" - ${uci_set}kcp_enable="0" - ${uci_set}kcp_port="0" - ${uci_set}kcp_param="--nocomp" - - if [ "$ssr_type" = "v2ray" ]; then - #v2ray - ${uci_set}alter_id="$ssr_alter_id" - ${uci_set}vmess_id="$ssr_vmess_id" - ${uci_set}transport="$ssr_transport" - if [ "$ssr_transport" = "tcp" ]; then - ${uci_set}tcp_guise="$ssr_tcp_guise" - fi - - if [ "$ssr_transport" = "ws" ]; then - ${uci_set}ws_host="$ssr_ws_host" - ${uci_set}ws_path="$ssr_ws_path" - fi - - if [ "$ssr_transport" = "h2" ]; then - ${uci_set}h2_host="$ssr_ws_host" - ${uci_set}h2_path="$ssr_ws_path" - fi - - ${uci_set}tls="$ssr_tls" - ${uci_set}insecure="$ssr_insecure" - ${uci_set}security="auto" - ${uci_set}alias="$ssr_remarks" - fi - - if [ "$ssr_type" = "ss" ]; then - ${uci_set}encrypt_method_ss="$ss_method" - ${uci_set}alias="$ssr_remarks" - fi - -} - -name=vssr -subscribe_url=($(uci get $name.@server_subscribe[0].subscribe_url)) #订阅服务器地址 -[ ${#subscribe_url[@]} -eq 0 ] && exit 1 -[ $(uci -q get $name.@server_subscribe[0].proxy || echo 0) -eq 0 ] && /etc/init.d/$name stop >/dev/null 2>&1 -log_name=${name}_subscribe -for ((o = 0; o < ${#subscribe_url[@]}; o++)); do - echo_date "从 ${subscribe_url[o]} 获取订阅" - echo_date "开始更新在线订阅列表..." - echo_date "开始下载订阅链接到本地临时文件,请稍等..." - subscribe_data=$(wget-ssl --user-agent="User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" --no-check-certificate -t 10 -T 10 -O- ${subscribe_url[o]}) - curl_code=$? - # 计算group的hashkey - ssr_grouphashkey=$(echo "${subscribe_url[o]}" | md5sum | cut -d ' ' -f1) - if [ ! $curl_code -eq 0 ]; then - - subscribe_data=$(wget-ssl --no-check-certificate -t 10 -T 10 -O- ${subscribe_url[o]}) - curl_code=$? - fi - if [ $curl_code -eq 0 ]; then - echo_date "下载订阅成功..." - echo_date "开始解析节点信息..." - ssr_url=($(echo $subscribe_data | base64 -d | sed 's/\r//g')) # 解码数据并删除 \r 换行符 - subscribe_max=$(echo ${ssr_url[0]} | grep -i MAX= | awk -F = '{print $2}') - subscribe_max_x=() - if [ -n "$subscribe_max" ]; then - while [ ${#subscribe_max_x[@]} -ne $subscribe_max ]; do - if [ ${#ssr_url[@]} -ge 10 ]; then - if [ $((${RANDOM:0:2} % 2)) -eq 0 ]; then - temp_x=${RANDOM:0:1} - else - temp_x=${RANDOM:0:2} - fi - else - temp_x=${RANDOM:0:1} - fi - [ $temp_x -lt ${#ssr_url[@]} -a -z "$(echo "${subscribe_max_x[*]}" | grep -w $temp_x)" ] && subscribe_max_x[${#subscribe_max_x[@]}]="$temp_x" - done - else - subscribe_max=${#ssr_url[@]} - fi - echo_date "共计$subscribe_max个节点" - - ssr_group=$(urlsafe_b64decode $(urlsafe_b64decode ${ssr_url[$((${#ssr_url[@]} - 1))]//ssr:\/\//} | sed 's/&/\n/g' | grep group= | awk -F = '{print $2}')) - if [ -z "$ssr_group" ]; then - ssr_group="default" - fi - if [ -n "$ssr_group" ]; then - subscribe_i=0 - subscribe_n=0 - subscribe_o=0 - subscribe_x="" - temp_host_o=() - curr_ssr=$(uci show $name | grep @servers | grep -c server=) - for ((x = 0; x < $curr_ssr; x++)); do # 循环已有服务器信息,匹配当前订阅群组 - temp_alias=$(uci -q get $name.@servers[$x].grouphashkey | grep "$ssr_grouphashkey") - [ -n "$temp_alias" ] && temp_host_o[${#temp_host_o[@]}]=$(uci get $name.@servers[$x].hashkey) - done - - for ((x = 0; x < $subscribe_max; x++)); do # 循环链接 - [ ${#subscribe_max_x[@]} -eq 0 ] && temp_x=$x || temp_x=${subscribe_max_x[x]} - result=$(echo ${ssr_url[temp_x]} | grep "ss") - subscribe_url_type=$(echo "$ssr_url" | awk -F ':' '{print $1}') - - if [ "$subscribe_url_type" = "ss" ]; then - temp_info=${ssr_url[temp_x]//ss:\/\//} # 解码 SS 链接 - # 计算hashkey - ssr_hashkey=$(echo "$temp_info" | md5sum | cut -d ' ' -f1) - - info=$(urlsafe_b64decode $(echo "$temp_info" | awk -F '@' '{print $1}')) - temp_info_array=(${info//:/ }) - ssr_type="ss" - ss_method=${temp_info_array[0]} - ssr_passwd=${temp_info_array[1]} - info=$(echo "$temp_info" | awk -F '@' '{print $2}' | awk -F '#' '{print $1}') - temp_info_array=(${info//:/ }) - ssr_host=${temp_info_array[0]} - ssr_port=${temp_info_array[1]} - ssr_remarks=$(urldecode $(echo "$temp_info" | awk -F '#' '{print $2}')) - fi - - if [ "$subscribe_url_type" = "ssr" ]; then - temp_info=$(urlsafe_b64decode ${ssr_url[temp_x]//ssr:\/\//}) # 解码 SSR 链接 - # 计算hashkey - ssr_hashkey=$(echo "$temp_info" | md5sum | cut -d ' ' -f1) - - info=${temp_info///?*/} - temp_info_array=(${info//:/ }) - ssr_type="ssr" - ssr_host=${temp_info_array[0]} - ssr_port=${temp_info_array[1]} - ssr_protocol=${temp_info_array[2]} - ssr_method=${temp_info_array[3]} - ssr_obfs=${temp_info_array[4]} - ssr_passwd=$(urlsafe_b64decode ${temp_info_array[5]}) - info=${temp_info:$((${#info} + 2))} - info=(${info//&/ }) - ssr_protoparam="" - ssr_obfsparam="" - ssr_remarks="$temp_x" - for ((i = 0; i < ${#info[@]}; i++)); do # 循环扩展信息 - temp_info=($(echo ${info[i]} | sed 's/=/ /g')) - case "${temp_info[0]}" in - protoparam) - ssr_protoparam=$(urlsafe_b64decode ${temp_info[1]}) - ;; - obfsparam) - ssr_obfsparam=$(urlsafe_b64decode ${temp_info[1]}) - ;; - remarks) - ssr_remarks=$(urlsafe_b64decode ${temp_info[1]}) - ;; - esac - done - fi - - if [ "$subscribe_url_type" = "vmess" ]; then - temp_info=$(urlsafe_b64decode ${ssr_url[temp_x]//vmess:\/\//}) # 解码 Vmess 链接 - # 计算hashkey - ssr_hashkey=$(echo "$temp_info" | md5sum | cut -d ' ' -f1) - - ssr_type="v2ray" - json_load "$temp_info" - json_get_var ssr_host add - json_get_var ssr_port port - json_get_var ssr_alter_id aid - json_get_var ssr_vmess_id id - json_get_var ssr_transport net - json_get_var ssr_remarks ps - ssr_tcp_guise="none" - json_get_var ssr_ws_host host - json_get_var ssr_ws_path path - json_get_var ssr_h2_host host - json_get_var ssr_h2_path path - json_get_var ssr_tls tls - if [ "$ssr_tls" == "tls" -o "$ssr_tls" == "1" ]; then - ssr_tls="1" - ssr_insecure="1" - else - ssr_tls="0" - fi - fi - - if [ -z "ssr_remarks" ]; then # 没有备注的话则生成一个 - ssr_remarks="$ssr_host:$ssr_port" - fi - # 丢弃没有host的无效服务器信息,例如:剩余流量xxx - if [[ "$ssr_remarks" =~ "过期时间" ]] || [[ "$ssr_remarks" =~ "剩余流量" ]] || [[ "$ssr_remarks" =~ "最新域名" ]] || [[ "$ssr_remarks" =~ "防失联QQ群" ]] || [ -z "$ssr_host" ];then - echo_date "丢弃无效节点:【$ssr_remarks】" - continue - fi - uci_name_tmp=$(uci show $name | grep -w "$ssr_hashkey" | awk -F . '{print $2}') - if [ -z "$uci_name_tmp" ]; then # 判断当前服务器信息是否存在 - uci_name_tmp=$(uci add $name servers) - subscribe_n=$(($subscribe_n + 1)) - fi - Server_Update $uci_name_tmp - subscribe_x=$subscribe_x$ssr_hashkey" " - ssrtype=$(echo $ssr_type | tr '[a-z]' '[A-Z]') - echo_date "$ssrtype节点:【$ssr_remarks】" - - # SSR - # echo "服务器地址: $ssr_host" - # echo "服务器端口 $ssr_port" - # echo "密码: $ssr_passwd" - # echo "SS加密: $ss_method" - # echo "加密: $ssr_method" - # echo "协议: $ssr_protocol" - # echo "协议参数: $ssr_protoparam" - # echo "混淆: $ssr_obfs" - # echo "混淆参数: $ssr_obfsparam" - # echo "备注: $ssr_remarks" - - done - for ((x = 0; x < ${#temp_host_o[@]}; x++)); do # 新旧服务器信息匹配,如果旧服务器信息不存在于新服务器信息则删除 - if [ -z "$(echo "$subscribe_x" | grep -w ${temp_host_o[x]})" ]; then - uci_name_tmp=$(uci show $name | grep ${temp_host_o[x]} | awk -F . '{print $2}') - uci delete $name.$uci_name_tmp - subscribe_o=$(($subscribe_o + 1)) - fi - done - echo_date "本次更新订阅来源 【$ssr_group】 服务器数量: ${#ssr_url[@]} 新增服务器: $subscribe_n 删除服务器: $subscribe_o" - echo_date "在线订阅列表更新完成!请等待网页自动刷新!" - subscribe_log="$ssr_group 服务器订阅更新成功 服务器数量: ${#ssr_url[@]} 新增服务器: $subscribe_n 删除服务器: $subscribe_o" - logger -st $log_name[$$] -p6 "$subscribe_log" - uci commit $name - else - echo_date "${subscribe_url[$o]} 订阅数据解析失败 无法获取 Group" - logger -st $log_name[$$] -p3 "${subscribe_url[$o]} 订阅数据解析失败 无法获取 Group" - fi - else - echo_date "${subscribe_url[$o]} 订阅数据获取失败 错误代码: $curl_code" - logger -st $log_name[$$] -p3 "${subscribe_url[$o]} 订阅数据获取失败 错误代码: $curl_code" - fi -done -echo "END SUBSCRIBE" -/etc/init.d/$name restart >/dev/null 2>&1 diff --git a/package/ctcgfw/luci-app-vssr/root/usr/share/vssr/update.sh b/package/ctcgfw/luci-app-vssr/root/usr/share/vssr/update.sh deleted file mode 100644 index be6dd981a1..0000000000 --- a/package/ctcgfw/luci-app-vssr/root/usr/share/vssr/update.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -chnroute_data=$(wget -O- -t 3 -T 3 http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest) -[ $? -eq 0 ] && { - echo "$chnroute_data" | grep ipv4 | grep CN | awk -F\| '{ printf("%s/%d\n", $4, 32-log($5)/log(2)) }' > /tmp/china_ssr.txt -} - -if [ -s "/tmp/china_ssr.txt" ];then - if ( ! cmp -s /tmp/china_ssr.txt /etc/china_ssr.txt );then - mv /tmp/china_ssr.txt /etc/china_ssr.txt - fi -fi - -/usr/share/vssr/chinaipset.sh - -wget-ssl --no-check-certificate https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt -O /tmp/gfw.b64 -/usr/bin/ssr-gfw - -if [ -s "/tmp/gfwnew.txt" ];then - if ( ! cmp -s /tmp/gfwnew.txt /etc/dnsmasq.ssr/gfw_list.conf );then - mv /tmp/gfwnew.txt /etc/dnsmasq.ssr/gfw_list.conf - echo "copy" - fi -fi - -/etc/init.d/vssr restart diff --git a/package/ctcgfw/luci-app-vssr/root/www/luci-static/vssr/img/switch.png b/package/ctcgfw/luci-app-vssr/root/www/luci-static/vssr/img/switch.png new file mode 100644 index 0000000000000000000000000000000000000000..901e2d75aa156233e7ae0ec30554951556cef069 GIT binary patch literal 3771 zcmaJ^dpwiv8%J|amP8hr8R^9~bI2x#*(|5UmRF^Nuwf0;Hs_qrB}@sSNR$dW6pC_; z5~)ZMIYdM`O`-66^j7chk6*v%^Ld{8e(vY`Ue|SBhx@voc-wt@CBz_Ne0+Qo7Ul#B zFjCiV5h38|J)CL>400T^gPi?LSB{?(i^hkeGM#Bq3r{CE8inRW4LJFjwug^zgDTzb zAm<>-8tcOJL^!R}ApAYO0W=@q9%FxRCl>~d19hgk(Y*{|)At|3pmeGs?0_x_Me@ee z-09|lEZY9SeReK^3>OR)W^4rA>s5Ll5C-PCW{8uMd)d|XzA!ecViG*dfGY|j0O~q($Ytw^pRTHnp%2T9TXOghW@-@ zfHW4>6-yxyf64;h3}NmZjyD#G^z-vW_-P}UEH|VU27^JO&`2~|6QIy!2Y7Lu{58GU z%D*@eXlxf2-J3&adO_DYIyp0aIEFAl(|@+$>HV9n7yGA~0D~d@oxG7+2-NzPei4#L z|DV*;^EWk{L!tev@Bd`XwhQp4At^LA(}(2(IL=jhU6eN#&!RbTm@GRc)8m&FZQYq1 zCfl9q4aMWvt%iZB9iV$rnSShDKQJT`*20U;aq@DZSr80i02c(EPQ{vGPY( z$7yMq;V@{78ODsLtF4PSMH6&)|H2ZOETE?#<>r5ir;)Kk; zM~)(!`;8OCe#KNccPz#?J- za(q{&u6=Fq4bY5h?qGoCvXx#loK2>5L30W^;Un$pefkEjJx?VcWY8PjQo7}7#+@SQ zK`|~7KSZd&haH!qr$k>luP=fLO%huz5szbind)6VdGcgqLqkK1kdRPdpud0BU(#aL zf>*1ntIO}+y_;WC^L=DtvS*UTW;4zbU1a4MQLmaeY+kkOIL}plK#o93>wsPm&q791 zGcquGMn*=|nZbImT0Bpt*(GP6wRH^$Lfg zZx4dMg;<)KZXY{zgEWUC`;N@rNT{Ja*l3{RGl6lN2#i)9L0vN zo>DMg6x!T=JI-Asvrz;WG5LLIK337dSHp4!$ycMUr}yQ1d*<%Y$ja>Ry5mPi*X;4P zB!pUrCno4&y&8w_aVG8nQGyLg9>3n|(Q+g{m2|H@^7~Z@fpD90*LE@3MbkN16x}$? z{y~_|Bf>(OQZllgVrR!&of&F;cC5xY&tPt$dlgRqm0(A?CsmX8~|yYmihk ze}ZpkO47T|8h&P3)sE9KUrt9EZk72&x2&w=uW0-<)EGNEG&B@)b-pD@(FcrPQ)u|$ z`($s1f<*HnNQ3Kp(>&a5*Z2id4m#$Bp{(k)gi!jXw3`P?9=YFngCmp4Yf+tdvv@|Pj@lJWNx%6e#=Tg91o7dmYGhu zE5gzhaOz#jw@G3AiBLy@^c(5v=?uHYU16IO$!>0LdrczrODkpHJ`7!3QL(yko;;+{ z;@Ee?iSO^1U0pij=paV6hK9zJGmSR7b9D!=D>z-AtAmvi`Lv-`!!DAz==k7NfNCL5 zG#koBgm1hT@mN&)RPJ*i!}UhLO3PW0wV=>JP@&T-7b0BU+UnVNcSQhfM`(mTVMPYr zKJn(mv&#$bw_TxWYHEH`x4%{8J3HL$2fO%UI#}dr32Sy{rZcR1F**iEeOW-_=H}+& z)%uXHPc~Pb9H|LqHmC7+wmk1J($dm`qfnihb}2x%>I!Ux4Gatvzt^5S>g|2ow?0Bp zDUqkd5^l&@2@@+Dy}UPJ+fcJF$ItITHiqpAS(Mp2`o3uM7Ov4sE3&0mh&Nat`3x|1 zVAe#ArUIjI$YQav|&Zl}#apMfe8Io&%u((=wWq;XHDPSan94jme)+xN8!WOb_Tg63fuq3pBK zuJ~Ku3WW1|J@nuzD*bTrqaJRZr^hNPDuS$|baQl?^wh4|Tn<_K*sU%S2;sm#K*7&*)!@l|tF&X!H;86b6eDG0M&3~S{c@7s+e{kzo<4ngpW`@u_{GbY%nIO$ z*4EWIlV|;yD13A;&cH{B7ae!P-OS9art{>|+^8fpBS;k4x8yn~+yp@w2lB?5BP~gi zMx5)d@W16rp#uiYv)z-mz&9T_AsG|$~!YVTZp76uN7KP)I1(=Jg8JYg^1!rk*|>&4Sa zIrmcg>f1x|AA^uQ>R!#a?&rsw z2h__SV%=5MgQ<0WZ{A>YeL6!QAJbSohMauR9$N%q`^rCvpP24ET~huEKYsB7q>L`1 zKOhK{tIwv@$}rfl;vf<-=qapwdnzz43#$k?E4Q$cfsolNEv2&g3p(=nol(BJxgya1}tC8mHeqynNfGB~i2sgUJ9j z_1@n%UQe;f#&$mhikzx@jA!=PRBw4|a$SEoAyG5BJX5~usnq@LF9f9?aD_L?$Hg$z z2D4m|$P)SCpl#*jUHn|kA*(2Gmo0@tk&JiP)vp93An(hkzS5A8kgMQ{M~pMaS>vgO zvIV_55%R+I5kjm4V+9QBeF-SWmIInsD{NW5S~l5KP@12gPr7vJ(pYP&`Qf>}J22)X z(#mGjBO`$O9a;nRx0Jm|(&%h!uvbgwEp3&NA>!b&ree+w0YeVmKv$lM7M(hHUMjf+ z21gy1K;ATByL>d z_%P&3NlA%8FuAqk=J4=vF;Jvy^V*atUz9vvT+b1D<wSGIdyf9e+ z99E$b@G`S&FMYW3Ld*9Ag@q+|82H}0Fa>u?QjXuLKVRlE`O1(RTuWdOp~JQwuEHq< zzw}XK{;ai$B`{2K$DTzSBJt7D#lE_zR@bg%CZ4OkS|{lGeNdP2Dj_;qx2dra-`}?- z1wIdi-n8%Zz|ju3HQtUP#IE{e7`XIeS_+zGIhU+NIK~guh!B@Y3A3UiA~R8)f0Is0 z5K3hz`wB}+m^W|SfCUwQWV6}t>c4Fg3wz!>%3T#ASRW3YmqzTQtfI(Hcj6yA!k6I1 z=M~S$2t6T4e6GB-|3fqxtjedZYQ9{Lj7U#Ird^ bejz>)j!K47g5=Wr@1%vkS@reHb@qu`g literal 0 HcmV?d00001