From 9fcb30d870c15432ef89e622b175d1382c492030 Mon Sep 17 00:00:00 2001 From: William Chan Date: Sat, 11 Jan 2020 12:27:42 +0800 Subject: [PATCH] luci-app-ssr-plus: optimize subscribe script and support ssd subscribe (#2726) * luci-app-ssr-plus: optimize subscribe script and support ssd subscribe * luci-app-ssr-plus: optimize ping test and added socket test * luci-app-ssr-plus: fix script path * luci-app-ssr-plus: optimize script * luci-app-ssr-plus: optimize script and remove /tmp/ssrpro.log * luci-app-ssr-plus: adjust log function * luci-app-ssr-plus: fix index * luci-app-ssr-plus: adjust content --- .../luasrc/controller/shadowsocksr.lua | 200 ++++++------ .../luasrc/model/cbi/shadowsocksr/log.lua | 11 +- .../luasrc/model/cbi/shadowsocksr/servers.lua | 30 +- .../luasrc/view/shadowsocksr/server_list.htm | 58 +++- .../luasrc/view/shadowsocksr/socket.htm | 3 + .../luasrc/view/shadowsocksr/subscribe.htm | 23 ++ .../luci-app-ssr-plus/po/zh-cn/ssr-plus.po | 3 + .../root/etc/init.d/shadowsocksr | 96 +++--- .../root/usr/share/shadowsocksr/subscribe.lua | 295 ++++++++++++++++++ 9 files changed, 557 insertions(+), 162 deletions(-) create mode 100644 package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/socket.htm create mode 100644 package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm create mode 100755 package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua diff --git a/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua b/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua index 7ec5d37cf..88819f707 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua @@ -9,61 +9,81 @@ function index() end - entry({"admin", "services", "shadowsocksr"},alias("admin", "services", "shadowsocksr", "client"),_("ShadowSocksR Plus+"), 10).dependent = true + entry({"admin", "services", "shadowsocksr"}, alias("admin", "services", "shadowsocksr", "client"),_("ShadowSocksR Plus+"), 10).dependent = true + + entry({"admin", "services", "shadowsocksr", "client"}, cbi("shadowsocksr/client"),_("SSR Client"), 10).leaf = true - entry({"admin", "services", "shadowsocksr", "client"},cbi("shadowsocksr/client"),_("SSR Client"), 10).leaf = true - entry({"admin", "services", "shadowsocksr", "servers"}, arcombine(cbi("shadowsocksr/servers", {autoapply=true}), cbi("shadowsocksr/client-config")),_("Severs Nodes"), 20).leaf = true - - entry({"admin", "services", "shadowsocksr", "control"},cbi("shadowsocksr/control"),_("Access Control"), 30).leaf = true - + + entry({"admin", "services", "shadowsocksr", "control"},cbi("shadowsocksr/control"), _("Access Control"), 30).leaf = true + -- entry({"admin", "services", "shadowsocksr", "list"},form("shadowsocksr/list"),_("GFW List"), 40).leaf = true - + entry({"admin", "services", "shadowsocksr", "advanced"},cbi("shadowsocksr/advanced"),_("Advanced Settings"), 50).leaf = true - + if nixio.fs.access("/usr/bin/ssr-server") then - entry({"admin", "services", "shadowsocksr", "server"},arcombine(cbi("shadowsocksr/server"), cbi("shadowsocksr/server-config")),_("SSR Server"), 60).leaf = true + entry({"admin", "services", "shadowsocksr", "server"},arcombine(cbi("shadowsocksr/server"), cbi("shadowsocksr/server-config")),_("SSR Server"), 60).leaf = true end - + entry({"admin", "services", "shadowsocksr", "status"},form("shadowsocksr/status"),_("Status"), 70).leaf = true - + entry({"admin", "services", "shadowsocksr", "check"}, call("check_status")) entry({"admin", "services", "shadowsocksr", "refresh"}, call("refresh_data")) + entry({"admin", "services", "shadowsocksr", "subscribe"}, call("subscribe")) + entry({"admin", "services", "shadowsocksr", "checkport"}, call("check_port")) - + entry({"admin", "services", "shadowsocksr", "log"},form("shadowsocksr/log"),_("Log"), 80).leaf = true - + entry({"admin", "services", "shadowsocksr","run"},call("act_status")).leaf=true - + entry({"admin", "services", "shadowsocksr", "ping"}, call("act_ping")).leaf=true - + +end + +function subscribe() + luci.sys.call("/usr/bin/lua /usr/share/shadowsocksr/subscribe.lua >> /tmp/ssrplus.log 2>&1") + luci.http.prepare_content("application/json") + luci.http.write_json({ ret = 1 }) end function act_status() - local e={} - e.running=luci.sys.call("busybox ps -w | grep ssr-retcp | grep -v grep >/dev/null")==0 - luci.http.prepare_content("application/json") - luci.http.write_json(e) + local e={} + e.running=luci.sys.call("busybox ps -w | grep ssr-retcp | grep -v grep >/dev/null")==0 + luci.http.prepare_content("application/json") + luci.http.write_json(e) end function act_ping() - local e={} - e.index=luci.http.formvalue("index") - e.ping=luci.sys.exec("ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*.[0-9]' | awk -F '=' '{print$2}'"%luci.http.formvalue("domain")) - luci.http.prepare_content("application/json") - luci.http.write_json(e) + local e = {} + local domain = luci.http.formvalue("domain") + local port = luci.http.formvalue("port") + e.index = luci.http.formvalue("index") + e.ping = luci.sys.exec("ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*.[0-9]' | awk -F '=' '{print$2}'" % domain) + + local iret = luci.sys.call(" ipset add ss_spec_wan_ac " .. domain .. " 2>/dev/null") + local socket = nixio.socket("inet", "stream") + socket:setopt("socket", "rcvtimeo", 3) + socket:setopt("socket", "sndtimeo", 3) + e.socket = socket:connect(domain, port) + socket:close() + if (iret == 0) then + luci.sys.call(" ipset del ss_spec_wan_ac " .. domain) + end + luci.http.prepare_content("application/json") + 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) -if sret== 0 then - retstring ="0" -else - retstring ="1" -end -luci.http.prepare_content("application/json") -luci.http.write_json({ ret=retstring }) + local set = "/usr/bin/ssr-check www." .. luci.http.formvalue("set") .. ".com 80 3 1" + sret = luci.sys.call(set) + if sret == 0 then + retstring ="0" + else + retstring ="1" + end + luci.http.prepare_content("application/json") + luci.http.write_json({ ret=retstring }) end function refresh_data() @@ -72,84 +92,84 @@ local icount =0 if set == "gfw_data" then if nixio.fs.access("/usr/bin/wget-ssl") then - refresh_cmd="wget-ssl --no-check-certificate https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt -O /tmp/gfw.b64" + refresh_cmd="wget-ssl --no-check-certificate https://cdn.jsdelivr.net/gh/gfwlist/gfwlist/gfwlist.txt -O /tmp/gfw.b64" else - refresh_cmd="wget -O /tmp/gfw.b64 http://iytc.net/tools/list.b64" + refresh_cmd="wget -O /tmp/gfw.b64 http://iytc.net/tools/list.b64" end sret=luci.sys.call(refresh_cmd .. " 2>/dev/null") if sret== 0 then - luci.sys.call("/usr/bin/ssr-gfw") - icount = luci.sys.exec("cat /tmp/gfwnew.txt | wc -l") - if tonumber(icount)>1000 then - oldcount=luci.sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l") - if tonumber(icount) ~= tonumber(oldcount) then - luci.sys.exec("cp -f /tmp/gfwnew.txt /etc/dnsmasq.ssr/gfw_list.conf") - retstring=tostring(math.ceil(tonumber(icount)/2)) - else - retstring ="0" - end - else - retstring ="-1" - end - luci.sys.exec("rm -f /tmp/gfwnew.txt ") + luci.sys.call("/usr/bin/ssr-gfw") + icount = luci.sys.exec("cat /tmp/gfwnew.txt | wc -l") + if tonumber(icount)>1000 then + oldcount=luci.sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l") + if tonumber(icount) ~= tonumber(oldcount) then + luci.sys.exec("cp -f /tmp/gfwnew.txt /etc/dnsmasq.ssr/gfw_list.conf") + retstring=tostring(math.ceil(tonumber(icount)/2)) + else + retstring ="0" + end + else + retstring ="-1" + end + luci.sys.exec("rm -f /tmp/gfwnew.txt ") else - retstring ="-1" + retstring ="-1" end elseif set == "ip_data" then refresh_cmd="wget -O- 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' 2>/dev/null| awk -F\\| '/CN\\|ipv4/ { printf(\"%s/%d\\n\", $4, 32-log($5)/log(2)) }' > /tmp/china_ssr.txt" sret=luci.sys.call(refresh_cmd) icount = luci.sys.exec("cat /tmp/china_ssr.txt | wc -l") if sret== 0 and tonumber(icount)>1000 then - oldcount=luci.sys.exec("cat /etc/china_ssr.txt | wc -l") - if tonumber(icount) ~= tonumber(oldcount) then - luci.sys.exec("cp -f /tmp/china_ssr.txt /etc/china_ssr.txt") - retstring=tostring(tonumber(icount)) - else - retstring ="0" - end + oldcount=luci.sys.exec("cat /etc/china_ssr.txt | wc -l") + if tonumber(icount) ~= tonumber(oldcount) then + luci.sys.exec("cp -f /tmp/china_ssr.txt /etc/china_ssr.txt") + retstring=tostring(tonumber(icount)) + else + retstring ="0" + end else - retstring ="-1" + retstring ="-1" end luci.sys.exec("rm -f /tmp/china_ssr.txt ") else - local need_process = 0 - if nixio.fs.access("/usr/bin/wget-ssl") then - refresh_cmd="wget-ssl --no-check-certificate -O - https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt > /tmp/adnew.conf" - need_process = 1 + local need_process = 0 + if nixio.fs.access("/usr/bin/wget-ssl") then + refresh_cmd="wget-ssl --no-check-certificate -O - https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt > /tmp/adnew.conf" + need_process = 1 else - refresh_cmd="wget -O /tmp/ad.conf http://iytc.net/tools/ad.conf" + refresh_cmd="wget -O /tmp/ad.conf http://iytc.net/tools/ad.conf" end sret=luci.sys.call(refresh_cmd .. " 2>/dev/null") if sret== 0 then - if need_process == 1 then - luci.sys.call("/usr/bin/ssr-ad") - end - icount = luci.sys.exec("cat /tmp/ad.conf | wc -l") - if tonumber(icount)>1000 then - if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then - oldcount=luci.sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l") - else - oldcount=0 - end - - if tonumber(icount) ~= tonumber(oldcount) then - luci.sys.exec("cp -f /tmp/ad.conf /etc/dnsmasq.ssr/ad.conf") - retstring=tostring(math.ceil(tonumber(icount))) - if oldcount==0 then - luci.sys.call("/etc/init.d/dnsmasq restart") - end - else - retstring ="0" - end - else - retstring ="-1" - end - luci.sys.exec("rm -f /tmp/ad.conf ") + if need_process == 1 then + luci.sys.call("/usr/bin/ssr-ad") + end + icount = luci.sys.exec("cat /tmp/ad.conf | wc -l") + if tonumber(icount)>1000 then + if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then + oldcount=luci.sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l") + else + oldcount=0 + end + + if tonumber(icount) ~= tonumber(oldcount) then + luci.sys.exec("cp -f /tmp/ad.conf /etc/dnsmasq.ssr/ad.conf") + retstring=tostring(math.ceil(tonumber(icount))) + if oldcount==0 then + luci.sys.call("/etc/init.d/dnsmasq restart") + end + else + retstring ="0" + end + else + retstring ="-1" + end + luci.sys.exec("rm -f /tmp/ad.conf ") else - retstring ="-1" + retstring ="-1" end -end +end luci.http.prepare_content("application/json") luci.http.write_json({ ret=retstring ,retcount=icount}) end @@ -181,7 +201,7 @@ uci:foreach(shadowsocksr, "servers", function(s) retstring =retstring .. "[" .. server_name .. "] OK.
" else retstring =retstring .. "[" .. server_name .. "] Error.
" - end + end if iret== 0 then luci.sys.call(" ipset del ss_spec_wan_ac " .. s.server) end diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua index 914e7e1f6..06c26c5d1 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua @@ -1,6 +1,3 @@ -local fs = require "nixio.fs" -local conffile = "/tmp/ssrpro.log" - f = SimpleForm("logview") f.reset = false f.submit = false @@ -8,8 +5,12 @@ t = f:field(TextValue, "conf") t.rmempty = true t.rows = 20 function t.cfgvalue() - luci.sys.exec("[ -f /tmp/ssrplus.log ] && sed '1!G;h;$!d' /tmp/ssrplus.log > /tmp/ssrpro.log") - return fs.readfile(conffile) or "" + local logs = luci.util.execi("cat /tmp/ssrplus.log") + local s = "" + for line in logs do + s = line .. "\n" .. s + end + return s end t.readonly="readonly" diff --git a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua index fa0c336fa..f17ead5ab 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua +++ b/package/lean/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua @@ -37,7 +37,7 @@ o.rmempty = true o = s:option(Button,"update_Sub",translate("Update Subscribe List")) o.inputstyle = "reload" o.description = translate("Update subscribe url list first") -o.write = function() +o.write = function() luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) end @@ -45,12 +45,18 @@ o = s:option(Flag, "proxy", translate("Through proxy update")) o.rmempty = false o.description = translate("Through proxy update list, Not Recommended ") -o = s:option(Button,"update",translate("Update All Subscribe Severs")) -o.inputstyle = "apply" -o.write = function() - luci.sys.exec("bash /usr/share/shadowsocksr/subscribe.sh >>/tmp/ssrplus.log 2>&1") - luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) -end +o = s:option(Button,"subscribe", translate("Update All Subscribe Severs")) +o.rawhtml = true +o.template = "shadowsocksr/subscribe" + + +-- o.inputstyle = "apply" +-- o.write = function() +-- luci.sys.call("lua /root/subscribe.lua >>/tmp/ssrplus.log 2>&1") +-- -- luci.sys.call("echo 123 >>/tmp/ssrplus.log 2>&1") +-- --luci.sys.exec("bash /usr/share/shadowsocksr/subscribe.sh >>/tmp/ssrplus.log 2>&1") +-- luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) +-- end o = s:option(Button,"delete",translate("Delete all severs")) @@ -58,8 +64,8 @@ o.inputstyle = "reset" o.description = string.format(translate("Server Count") .. ": %d", server_count) o.write = function() uci:delete_all("shadowsocksr", "servers", function(s) return true end) - uci:save("shadowsocksr") - luci.sys.call("uci commit shadowsocksr && /etc/init.d/shadowsocksr stop") + uci:save("shadowsocksr") + luci.sys.call("uci commit shadowsocksr && /etc/init.d/shadowsocksr stop") luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers")) return end @@ -113,7 +119,11 @@ function o.cfgvalue(...) return Value.cfgvalue(...) or "0" end -o = s:option(DummyValue,"server",translate("Ping Latency")) +o = s:option(DummyValue, "server_port", translate("Socket Connected")) +o.template="shadowsocksr/socket" +o.width="10%" + +o = s:option(DummyValue, "server", translate("Ping Latency")) o.template="shadowsocksr/ping" o.width="10%" diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm index 9652837ef..bab0cfcf8 100644 --- a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/server_list.htm @@ -9,16 +9,56 @@ local dsp = require "luci.dispatcher" \ No newline at end of file diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/socket.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/socket.htm new file mode 100644 index 000000000..5c2d52760 --- /dev/null +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/socket.htm @@ -0,0 +1,3 @@ +<%+cbi/valueheader%> +connecting +<%+cbi/valuefooter%> \ No newline at end of file diff --git a/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm new file mode 100644 index 000000000..7c518544b --- /dev/null +++ b/package/lean/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe.htm @@ -0,0 +1,23 @@ +<%+cbi/valueheader%> + + + + + + + +<%+cbi/valuefooter%> \ No newline at end of file diff --git a/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po b/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po index f5f5cc06b..903ee4116 100644 --- a/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po +++ b/package/lean/luci-app-ssr-plus/po/zh-cn/ssr-plus.po @@ -512,6 +512,9 @@ msgstr "所有端口(默认)" msgid "Only Common Ports" msgstr "仅常用端口(不走P2P流量到代理)" +msgid "Socket Connected" +msgstr "连接测试" + msgid "Ping Latency" msgstr "Ping延迟" diff --git a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr index 32e6dd3f7..dbbe3cb7f 100755 --- a/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr +++ b/package/lean/luci-app-ssr-plus/root/etc/init.d/shadowsocksr @@ -45,7 +45,7 @@ add_cron() { sed -i '/shadowsocksr/d' $CRON_FILE sed -i '/ssrplus.log/d' $CRON_FILE && echo '0 1 * * * echo "" > /tmp/ssrplus.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/share/shadowsocksr/subscribe.sh" >> $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/shadowsocksr/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/share/shadowsocksr/update.sh" >> $CRON_FILE crontab $CRON_FILE } @@ -61,7 +61,7 @@ run_mode=$(uci_get_by_type global run_mode) gen_config_file() { local host=$(uci_get_by_name $1 server) - if echo $host|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null; then + if echo $host|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null; then hostip=${host} elif [ "$host" != "${host#*:[0-9a-fA-F]}" ] ;then hostip=${host} @@ -74,7 +74,7 @@ gen_config_file() { fi fi [ $2 = "0" -a $kcp_flag = "1" ] && hostip="127.0.0.1" - + if [ $2 = "0" ] ;then config_file=$CONFIG_FILE elif [ $2 = "1" ]; then @@ -105,7 +105,7 @@ EOF elif [ "$stype" == "ssr" ] ;then cat <<-EOF >$config_file { - + "server": "$hostip", "server_port": $(uci_get_by_name $1 server_port), "local_address": "0.0.0.0", @@ -140,7 +140,7 @@ get_arg_out() { start_rules() { local server=$(uci_get_by_name $GLOBAL_SERVER server) #resolve name - if echo $server|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null; then + if echo $server|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$">/dev/null; then server=${server} elif [ "$server" != "${server#*:[0-9a-fA-F]}" ] ;then server=${server} @@ -152,14 +152,14 @@ start_rules() { server=`cat /etc/ssr_ip` fi fi - + kcp_server=$server - + local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0) if [ $kcp_enable = "1" ] ;then kcp_flag=1 - fi - + fi + local local_port=$(uci_get_by_name $GLOBAL_SERVER local_port) local lan_ac_ips=$(uci_get_by_type access_control lan_ac_ips) local lan_ac_mode="b" @@ -171,15 +171,15 @@ start_rules() { local udp_server=$(uci_get_by_name $UDP_RELAY_SERVER server) local udp_local_port=$(uci_get_by_name $UDP_RELAY_SERVER local_port) fi - + if [ -n "$lan_ac_ips" ]; then case "$lan_ac_mode" in w|W|b|B) local ac_ips="$lan_ac_mode$lan_ac_ips";; esac fi - + #deal gfw firewall rule - local gfwmode="" + local gfwmode="" if [ "$run_mode" = "gfw" ]; then gfwmode="-g" elif [ "$run_mode" = "router" ]; then @@ -189,7 +189,7 @@ start_rules() { elif [ "$run_mode" = "all" ]; then gfwmode="-z" fi - + local dports=$(uci_get_by_type global dports 1) if [ $dports = "1" ] ;then proxyport=" " @@ -210,14 +210,14 @@ start_rules() { -G "$(uci_get_by_type access_control lan_gm_ips)" \ -D "$proxyport" \ $(get_arg_out) $gfwmode $ARG_UDP - + return $? } start_pdnsd() { local usr_dns="$1" local usr_port="$2" - + local tcp_dns_list="208.67.222.222, 208.67.220.220" [ -z "$usr_dns" ] && usr_dns="8.8.8.8" [ -z "$usr_port" ] && usr_port="53" @@ -229,7 +229,7 @@ start_pdnsd() { echo -ne "pd13\000\000\000\000" >/var/pdnsd/pdnsd.cache chown -R nobody:nogroup /var/pdnsd fi - + cat > /var/etc/pdnsd.conf </dev/null 2>&1 done - echo "$(date "+%Y-%m-%d %H:%M:%S") Shadowsocks/ShadowsocksR $threads Threads Started!" >> /tmp/ssrplus.log + echo "$(date "+%Y-%m-%d %H:%M:%S") Shadowsocks/ShadowsocksR $threads Threads Started!" >> /tmp/ssrplus.log elif [ "$stype" == "v2ray" ] ;then $sscmd -config /var/etc/v2-ssr-retcp.json >/dev/null 2>&1 & echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd -version | head -1) Started!" >> /tmp/ssrplus.log elif [ "$stype" == "trojan" ] ;then - $sscmd --config /var/etc/trojan-ssr-retcp.json >/dev/null 2>&1 & + $sscmd --config /var/etc/trojan-ssr-retcp.json >/dev/null 2>&1 & echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd --version 2>&1 | head -1) Started!" >> /tmp/ssrplus.log fi - + if [ -n "$UDP_RELAY_SERVER" ] ;then redir_udp=1 if [ "$utype" == "ss" -o "$utype" == "ssr" ] ;then case "$(uci_get_by_name $UDP_RELAY_SERVER auth_enable)" in 1|on|true|yes|enabled) ARG_OTA="-A";; *) ARG_OTA="";; - esac + esac gen_config_file $UDP_RELAY_SERVER 1 last_config_file=$CONFIG_UDP_FILE pid_file="/var/run/ssr-reudp.pid" @@ -355,11 +355,11 @@ start_redir() { elif [ "$utype" == "v2ray" ] ; then lua /usr/share/shadowsocksr/genv2config.lua $UDP_RELAY_SERVER udp $(uci_get_by_name $UDP_RELAY_SERVER local_port) > /var/etc/v2-ssr-reudp.json sed -i 's/\\//g' /var/etc/v2-ssr-reudp.json - $ucmd -config /var/etc/v2-ssr-reudp.json >/dev/null 2>&1 & + $ucmd -config /var/etc/v2-ssr-reudp.json >/dev/null 2>&1 & elif [ "$stype" == "trojan" ] ;then lua /usr/share/shadowsocksr/gentrojanconfig.lua $GLOBAL_SERVER client 10801 > /var/etc/trojan-ssr-reudp.json sed -i 's/\\//g' /var/etc/trojan-ssr-reudp.json - $ucmd --config /var/etc/trojan-ssr-reudp.json >/dev/null 2>&1 & + $ucmd --config /var/etc/trojan-ssr-reudp.json >/dev/null 2>&1 & ipt2socks -U -4 -b 0.0.0.0 -s 127.0.0.1 -p 10801 -l $(uci_get_by_name $UDP_RELAY_SERVER local_port) >/dev/null 2>&1 & fi fi @@ -367,7 +367,7 @@ start_redir() { #deal with dns - + if [ "$(uci_get_by_type global pdnsd_enable)" = "1" ] ;then local dnsstr="$(uci_get_by_type global tunnel_forward 8.8.4.4:53)" local dnsserver=`echo "$dnsstr"|awk -F ':' '{print $1}'` @@ -377,12 +377,12 @@ start_redir() { elif [ "$run_mode" = "oversea" ]; then ipset add oversea $dnsserver 2>/dev/null else - ipset add ss_spec_wan_ac $dnsserver nomatch 2>/dev/null + ipset add ss_spec_wan_ac $dnsserver nomatch 2>/dev/null fi start_pdnsd $dnsserver $dnsport pdnsd_enable_flag=1 fi - + if [ "$(uci_get_by_type global enable_switch)" = "1" ] ;then if [ "$(uci_get_by_name $GLOBAL_SERVER switch_enable)" = "1" ] ;then if [ -z "$switch_server" ] ;then @@ -403,7 +403,7 @@ gen_service_file() { fastopen="true"; else fastopen="false"; - fi + fi cat <<-EOF >$2 { "server": "0.0.0.0", @@ -435,14 +435,14 @@ iptables -t filter -A SSR-SERVER-RULE -p udp --dport $(uci_get_by_name $1 server return 0 } gen_serv_include() { -FWI=$(uci get firewall.shadowsocksr.path 2>/dev/null) +FWI=$(uci get firewall.shadowsocksr.path 2>/dev/null) [ -n "$FWI" ] || return 0 if [ ! -f $FWI ] ;then echo '#!/bin/sh' >$FWI fi extract_rules() { echo "*filter" -iptables-save -t filter | grep SSR-SERVER-RULE|sed -e "s/^-A INPUT/-I INPUT/" +iptables-save -t filter | grep SSR-SERVER-RULE|sed -e "s/^-A INPUT/-I INPUT/" echo 'COMMIT' } cat <<-EOF >>$FWI @@ -473,7 +473,7 @@ start_local() { -l $(uci_get_by_type socks5_proxy local_port 1080) \ -b $(uci_get_by_type socks5_proxy local_address 0.0.0.0) \ -f /var/run/ssr-local.pid >/dev/null 2>&1 - local_enable=1 + local_enable=1 } rules() { @@ -488,7 +488,7 @@ rules() { fi } -start() { +start() { if [ -z "$switch_server" ] ;then GLOBAL_SERVER=$(uci_get_by_type global global_server) else @@ -498,7 +498,7 @@ start() { if rules ;then start_redir - + mkdir -p /tmp/dnsmasq.d && cp -a /etc/dnsmasq.ssr /tmp/ && cp -a /etc/dnsmasq.oversea /tmp/ if ! [ "$run_mode" = "oversea" ] ;then cat > /tmp/dnsmasq.d/dnsmasq-ssr.conf </dev/null 2>&1 - + fi - start_server + start_server start_local - + if [ $(uci_get_by_type global monitor_enable) = 1 ] ;then let total_count=server_count+redir_tcp+redir_udp+tunnel_enable+kcp_enable_flag+local_enable+pdnsd_enable_flag+switch_enable if [ $total_count -gt 0 ] @@ -526,7 +526,7 @@ EOF service_start /usr/bin/ssr-monitor $server_count $redir_tcp $redir_udp $tunnel_enable $kcp_enable_flag $local_enable $pdnsd_enable_flag $switch_enable fi fi - + ENABLE_SERVER=$(uci_get_by_type global global_server) [ "$ENABLE_SERVER" = "nil" ] && return 1 } @@ -560,10 +560,10 @@ stop() { killall -q -9 ssr-local if [ -f /var/run/pdnsd.pid ] ;then kill $(cat /var/run/pdnsd.pid) >/dev/null 2>&1 - else - kill -9 $(busybox ps -w | grep pdnsd | grep -v grep | awk '{print $1}') >/dev/null 2>&1 + else + kill -9 $(busybox ps -w | grep pdnsd | grep -v grep | awk '{print $1}') >/dev/null 2>&1 fi - + if [ -f "/tmp/dnsmasq.d/dnsmasq-ssr.conf" ]; then rm -f /tmp/dnsmasq.d/dnsmasq-ssr.conf /etc/init.d/dnsmasq restart >/dev/null 2>&1 diff --git a/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua new file mode 100755 index 000000000..8a16192d8 --- /dev/null +++ b/package/lean/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua @@ -0,0 +1,295 @@ +#!/usr/bin/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' + +-- these global functions are accessed all the time by the event handler +-- so caching them is worth the effort +local tinsert = table.insert +local ssub, slen, schar, srep, sbyte, sformat, sgsub = + string.sub, string.len, string.char, string.rep, string.byte, string.format, string.gsub +local cache = {} +local nodeResult = setmetatable({}, { __index = cache }) -- update result +local name = 'shadowsocksr' +local uciType = 'servers' +local ucic = luci.model.uci.cursor() +local proxy = ucic:get_first(name, 'server_subscribe', 'proxy', '0') +local subscribe_url = ucic:get_first(name, 'server_subscribe', 'subscribe_url', {}) + +local log = function(...) + print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({ ... }, " ")) +end +-- 分割字符串 +local function split(full, sep) + full = full:gsub("%z", "") -- 这里不是很清楚 有时候结尾带个\0 + local off, result = 1, {} + while true do + local nEnd = full:find(sep, off) + if not nEnd then + local res = ssub(full, off, slen(full)) + if #res > 0 then -- 过滤掉 \0 + tinsert(result, res) + end + break + else + tinsert(result, ssub(full, off, nEnd - 1)) + off = nEnd + slen(sep) + end + end + return result +end +-- urlencode +local function get_urlencode(c) + return sformat("%%%02X", sbyte(c)) +end + +function urlEncode(szText) + local str = szText:gsub("([^0-9a-zA-Z ])", get_urlencode) + str = str:gsub(" ", "+") + return str +end +-- trim +local function trim(text) + if not text or text == "" then + return "" + end + return (sgsub(text, "^%s*(.-)%s*$", "%1")) +end +-- md5 +local function md5(content) + local stdout = luci.sys.exec('echo \"' .. urlEncode(content) .. '\" | md5sum | cut -d \" \" -f1') + -- assert(nixio.errno() == 0) + return trim(stdout) +end +-- base64 +local function base64Decode(text, safe) + if not text then return '' end + text = text:gsub("%z", "") + if safe then + text = text:gsub("_", "/") + text = text:gsub("-", "+") + local mod4 = #text % 4 + text = text .. string.sub('====', mod4 + 1) + end + return nixio.bin.b64decode(text):gsub("%z", "") +end +-- 处理数据 +local function processData(szType, content) + local result = { + auth_enable = '0', + switch_enable = '1', + type = szType, + local_port = 1234, + timeout = 60, -- 不太确定 好像是死的 + fast_open = 0, + kcp_enable = 0, + kcp_port = 0, + kcp_param = '--nocomp' + } + local hash + if type(content) == 'string' then + hash = md5(content) + else + hash = md5(luci.jsonc.stringify(content)) + end + result.hashkey = hash + if szType == 'ssr' then + local dat = split(content, "/\\?") + local hostInfo = split(dat[1], ':') + result.server = hostInfo[1] + result.server_port = hostInfo[2] + result.protocol = hostInfo[3] + result.encrypt_method = hostInfo[4] + result.obfs = hostInfo[5] + result.password = base64Decode(hostInfo[6], true) + local params = {} + for k, v in pairs(split(dat[2], '&')) do + local t = split(v, '=') + params[t[1]] = t[2] + end + result.obfs_param = base64Decode(params.bfsparam, true) + result.protocol_param = base64Decode(params.protoparam, true) + local group = base64Decode(params.group, true) + if group then + result.alias = "[" .. group .. "] " + end + result.alias = result.alias .. base64Decode(params.remarks, true) + elseif szType == 'vmess' then + local info = luci.jsonc.parse(content) + result.type = 'v2ray' + result.server = info.add + result.server_port = info.port + result.tcp_guise = "none" + result.transport = info.net + result.alter_id = info.aid + result.vmess_id = info.id + result.alias = info.ps + result.ws_host = info.host + result.ws_path = info.path + result.h2_host = info.host + result.h2_path = info.path + if not info.security then + result.security = 'auto' + end + if info.tls == 'tls' or info.tls == '1' then + result.tls = '1' + else + result.tls = '0' + end + elseif szType == 'ssd' then + result.type = 'ss' + result.server = content.server + result.server_port = content.port + result.password = content.password + result.encrypt_method_ss = content.encryption + result.alias = '[' .. content.airport .. '] ' .. content.remarks + end + return result, hash +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) + return trim(stdout) +end + +local execute = function() + -- exec + do + -- subscribe_url = {'https://www.google.comc'} + if proxy == '0' then -- 不使用代理更新的话先暂停 + log('服务正在暂停') + luci.sys.init.stop(name) + end + for k, url in ipairs(subscribe_url) do + local raw = wget(url) + if #raw > 0 then + local node, szType + local groupHash = md5(url) + cache[groupHash] = {} + tinsert(nodeResult, {}) + local index = #nodeResult + -- SSD 似乎是这种格式 ssd:// 开头的 不知道 SS 什么格式 没支持 不清楚其他机场是否这样 + if raw:find('ssd://') then + szType = 'ssd' + local nEnd = select(2, raw:find('ssd://')) + node = base64Decode(raw:sub(nEnd + 1, #raw), true) + node = luci.jsonc.parse(node) + local extra = { + airport = node.airport, + port = node.port, + encryption = node.encryption, + password = node.password + } + local servers = {} + -- SS里面包着 干脆直接这样 + for _, server in ipairs(node.servers) do + tinsert(servers, setmetatable(server, { __index = extra })) + end + node = servers + else + -- ssd 外的格式 + node = split(base64Decode(raw, true), "\n") + end + for _, v in ipairs(node) do + if v then + local result, hash + if szType == 'ssd' then + result, hash = processData(szType, v) + elseif not szType then + local dat = split(v, "://") + if dat and dat[1] and dat[2] then + result, hash = processData(dat[1], base64Decode( dat[2], true)) + end + else + log('跳过未知类型: ' .. szType) + end + -- log(hash, result) + if hash and result then + if result.alias:find("过期时间") or + result.alias:find("剩余流量") or + result.alias:find("QQ群") or + result.alias:find("官网") or + result.server == '' + then + log('丢弃无效节点: ' .. result.type ..' 节点, ' .. result.alias) + else + log('成功解析: ' .. result.type ..' 节点, ' .. result.alias) + result.grouphashkey = groupHash + tinsert(nodeResult[index], result) + cache[groupHash][hash] = nodeResult[index][#nodeResult[index]] + end + end + end + end + log('成功解析节点数量: ' ..#node) + end + end + end + -- diff + do + assert(next(nodeResult)) + local add, del = 0, 0 + ucic:foreach(name, uciType, function(old) + if old.grouphashkey or old.hashkey then -- 没有 hash 的不参与删除 + if not nodeResult[old.grouphashkey] or not nodeResult[old.grouphashkey][old.hashkey] then + ucic:delete(name, old['.name']) + del = del + 1 + else + local dat = nodeResult[old.grouphashkey][old.hashkey] + ucic:tset(name, old['.name'], dat) + -- 标记一下 + setmetatable(nodeResult[old.grouphashkey][old.hashkey], { __index = { _ignore = true } }) + end + else + log('忽略手动添加的节点: ' .. old.alias) + end + end) + for k, v in ipairs(nodeResult) do + for kk, vv in ipairs(v) do + if not vv._ignore then + local section = ucic:add(name, uciType) + ucic:tset(name, section, vv) + add = add + 1 + end + + end + end + ucic:commit(name) + -- 如果服务器已经不见了把帮换一个 + local globalServer = ucic:get_first(name, 'global', 'global_server', '') + local firstServer = 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('当前主服务器已更新,正在自动更换。') + end + end + if firstServer then + luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + else + luci.sys.call("/etc/init.d/" .. name .." stop > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + end + log('新增节点数量: ' ..add, '删除节点数量: ' .. del) + log('更新成功服务正在启动') + end +end + +if subscribe_url and #subscribe_url > 0 then + xpcall(execute, function() + log('发生错误, 正在恢复服务') + local firstServer = ucic:get_first(name, uciType) + if firstServer then + luci.sys.call("/etc/init.d/" .. name .." restart > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + else + luci.sys.call("/etc/init.d/" .. name .." stop > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早 + end + log('更新失败服务正在恢复') + log(debug.traceback()) + end) +end \ No newline at end of file