luci-app-vssr: add package
@ -40,7 +40,8 @@ MT-Wifi 5.0.4.0: [MeIsReallyBa/mt7615-dbdc-linux5.4](https://github.com/MeIsReal
|
||||
node-request source: [jerrykuku/node-request](https://github.com/jerrykuku/node-request).<br/>
|
||||
luci-app-jd-dailybonus source: [jerrykuku/luci-app-jd-dailybonus](https://github.com/jerrykuku/luci-app-jd-dailybonus).<br/>
|
||||
luci-app-oled source: [NateLol/luci-app-oled](https://github.com/NateLol/luci-app-oled).<br/>
|
||||
luci-app-beardropper source: [NateLol/natelol](https://github.com/NateLol/natelol).
|
||||
luci-app-beardropper source: [NateLol/natelol](https://github.com/NateLol/natelol).<br/>
|
||||
luci-app-vssr source: [jerrykuku/luci-app-vssr](https://github.com/jerrykuku/luci-app-vssr).
|
||||
|
||||
## License
|
||||
### Depend on their own License.
|
||||
|
91
package/ctcgfw/luci-app-vssr/Makefile
Normal file
@ -0,0 +1,91 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-vssr
|
||||
PKG_VERSION:=1.11
|
||||
PKG_RELEASE:=20200719
|
||||
|
||||
PKG_CONFIG_DEPENDS:= CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_V2ray \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Server \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Socks
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/$(PKG_NAME)/config
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray
|
||||
bool "Include V2ray"
|
||||
default y
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Trojan
|
||||
bool "Include Trojan"
|
||||
default y
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Server
|
||||
bool "Include ShadowsocksR Server"
|
||||
default n
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Socks
|
||||
bool "Include ShadowsocksR Socks and Tunnel"
|
||||
default y
|
||||
endef
|
||||
|
||||
define Package/luci-app-vssr
|
||||
SECTION:=luci
|
||||
CATEGORY:=LuCI
|
||||
SUBMENU:=3. Applications
|
||||
TITLE:=A New SS/SSR/V2Ray/Trojan LuCI interface
|
||||
PKGARCH:=all
|
||||
DEPENDS:=+shadowsocksr-libev-alt +ipset +ip-full +iptables-mod-tproxy +dnsmasq-full +coreutils +coreutils-base64 +bash +pdnsd-alt +wget +luasocket +jshn +lua-cjson +coreutils-nohup +lua-maxminddb \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:trojan \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Trojan:ipt2socks \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Server:shadowsocksr-libev-server \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Socks:shadowsocksr-libev-ssr-local
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/luci-app-vssr/conffiles
|
||||
/etc/ssr_ip
|
||||
/etc/dnsmasq.ssr/gfw_list.conf
|
||||
/etc/china_ssr.txt
|
||||
/etc/dnsmasq.ssr/gfw_list.conf
|
||||
/etc/dnsmasq.ssr/gfw_base.conf
|
||||
/etc/dnsmasq.oversea/oversea_list.conf
|
||||
endef
|
||||
|
||||
define Package/luci-app-vssr/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib/lua/luci
|
||||
cp -pR ./luasrc/* $(1)/usr/lib/lua/luci
|
||||
$(INSTALL_DIR) $(1)/
|
||||
cp -pR ./root/* $(1)/
|
||||
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n
|
||||
po2lmo ./po/zh-cn/vssr.po $(1)/usr/lib/lua/luci/i18n/vssr.zh-cn.lmo
|
||||
endef
|
||||
|
||||
define Package/luci-app-vssr/postinst
|
||||
#!/bin/sh
|
||||
if [ -z "$${IPKG_INSTROOT}" ]; then
|
||||
( . /etc/uci-defaults/luci-vssr ) && rm -f /etc/uci-defaults/luci-vssr
|
||||
rm -rf /tmp/luci-indexcache
|
||||
rm -rf /tmp/luci-modulecache/*
|
||||
chmod 755 /etc/init.d/vssr >/dev/null 2>&1
|
||||
/etc/init.d/vssr enable >/dev/null 2>&1
|
||||
fi
|
||||
exit 0
|
||||
endef
|
||||
|
||||
define Package/luci-app-vssr/prerm
|
||||
#!/bin/sh
|
||||
if [ -z "$${IPKG_INSTROOT}" ]; then
|
||||
/etc/init.d/vssr disable
|
||||
/etc/init.d/vssr stop
|
||||
fi
|
||||
exit 0
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,luci-app-vssr))
|
383
package/ctcgfw/luci-app-vssr/luasrc/controller/vssr.lua
Normal file
@ -0,0 +1,383 @@
|
||||
-- Copyright (C) 2018 jerrykuku <jerrykuku@qq.com>
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
module("luci.controller.vssr", package.seeall)
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/vssr") then return end
|
||||
|
||||
if nixio.fs.access("/usr/bin/ssr-redir") then
|
||||
entry({"admin", "services", "vssr"},
|
||||
alias("admin", "services", "vssr", "client"), _("Hello World"), 10).dependent =
|
||||
true -- 首页
|
||||
entry({"admin", "services", "vssr", "client"}, cbi("vssr/client"),
|
||||
_("SSR Client"), 10).leaf = true -- 基本设置
|
||||
entry({"admin", "services", "vssr", "servers"}, cbi("vssr/servers"),
|
||||
_("Severs Nodes"), 11).leaf = true -- 服务器节点
|
||||
entry({"admin", "services", "vssr", "servers"},
|
||||
arcombine(cbi("vssr/servers"), cbi("vssr/client-config")),
|
||||
_("Severs Nodes"), 11).leaf = true -- 编辑节点
|
||||
entry({"admin", "services", "vssr", "control"}, cbi("vssr/control"),
|
||||
_("Access Control"), 12).leaf = true -- 访问控制
|
||||
if nixio.fs.access("/usr/bin/v2ray/v2ray") then
|
||||
entry({"admin", "services", "vssr", "socks5"}, cbi("vssr/socks5"),
|
||||
_("Socks5"), 13).leaf = true -- Socks5代理
|
||||
end
|
||||
entry({"admin", "services", "vssr", "advanced"}, cbi("vssr/advanced"),
|
||||
_("Advanced Settings"), 14).leaf = true -- 高级设置
|
||||
elseif nixio.fs.access("/usr/bin/ssr-server") then
|
||||
entry({"admin", "services", "vssr"},
|
||||
alias("admin", "services", "vssr", "server"), _("vssr"), 10).dependent =
|
||||
true
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
if nixio.fs.access("/usr/bin/ssr-server") then
|
||||
entry({"admin", "services", "vssr", "server"},
|
||||
arcombine(cbi("vssr/server"), cbi("vssr/server-config")),
|
||||
_("SSR Server"), 20).leaf = true
|
||||
end
|
||||
|
||||
entry({"admin", "services", "vssr", "log"}, cbi("vssr/log"), _("Log"), 30).leaf =
|
||||
true
|
||||
entry({"admin", "services", "vssr", "licence"}, template("vssr/licence"),
|
||||
_("Licence"), 40).leaf = true
|
||||
|
||||
entry({"admin", "services", "vssr", "refresh"}, call("refresh_data")) -- 更新白名单和GFWLIST
|
||||
entry({"admin", "services", "vssr", "checkport"}, call("check_port")) -- 检测单个端口并返回Ping
|
||||
entry({"admin", "services", "vssr", "run"}, call("act_status")) -- 检测全局服务器状态
|
||||
entry({"admin", "services", "vssr", "change"}, call("change_node")) -- 切换节点
|
||||
entry({"admin", "services", "vssr", "allserver"}, call("get_servers")) -- 获取所有节点Json
|
||||
entry({"admin", "services", "vssr", "subscribe"}, call("get_subscribe")) -- 执行订阅
|
||||
entry({"admin", "services", "vssr", "flag"}, call("get_flag")) -- 获取节点国旗 iso code
|
||||
entry({"admin", "services", "vssr", "ip"}, call("check_ip")) -- 获取ip情况
|
||||
entry({"admin", "services", "vssr", "switch"}, call("switch")) -- 设置节点为自动切换
|
||||
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="' ..
|
||||
auto_update .. '"'
|
||||
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(
|
||||
"nohup /usr/bin/lua /usr/share/vssr/subscribe.lua >/www/check_update.htm 2>/dev/null &")
|
||||
e.error = 0
|
||||
else
|
||||
e.error = 1
|
||||
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(
|
||||
"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)
|
||||
end)
|
||||
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
|
||||
end
|
||||
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(
|
||||
"busybox ps -w | grep vssr_t | grep -v grep >/dev/null") == 0
|
||||
-- 检测PDNSD状态
|
||||
e.pdnsd = luci.sys.call("pidof pdnsd >/dev/null") == 0
|
||||
-- 检测游戏模式状态
|
||||
e.game = luci.sys.call(
|
||||
"busybox ps -w | grep vssr_u | grep -v grep >/dev/null") == 0
|
||||
|
||||
-- 检测Socks5
|
||||
e.socks5 = luci.sys.call(
|
||||
"busybox ps -w | grep vssr_s | grep -v grep >/dev/null") == 0
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
-- 刷新检测文件
|
||||
function refresh_data()
|
||||
local set = luci.http.formvalue("set")
|
||||
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"
|
||||
else
|
||||
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/vssr-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"
|
||||
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
|
||||
else
|
||||
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
|
||||
else
|
||||
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/vssr-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"
|
||||
end
|
||||
end
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({ret = retstring, retcount = icount})
|
||||
end
|
||||
|
||||
-- 检测单个节点状态并返回连接速度
|
||||
function check_port()
|
||||
|
||||
local sockets = require "socket"
|
||||
local set = luci.http.formvalue("host")
|
||||
local port = luci.http.formvalue("port")
|
||||
local retstring = ""
|
||||
local iret = 1
|
||||
iret = luci.sys.call(" ipset add ss_spec_wan_ac " .. set .. " 2>/dev/null")
|
||||
socket = nixio.socket("inet", "stream")
|
||||
socket:setopt("socket", "rcvtimeo", 2)
|
||||
socket:setopt("socket", "sndtimeo", 2)
|
||||
local t0 = sockets.gettime()
|
||||
ret = socket:connect(set, port)
|
||||
socket:close()
|
||||
local t1 = sockets.gettime()
|
||||
if tostring(ret) == "true" then
|
||||
retstring = "1"
|
||||
else
|
||||
retstring = "0"
|
||||
end
|
||||
if iret == 0 then
|
||||
luci.sys.call(" ipset del ss_spec_wan_ac " .. set)
|
||||
end
|
||||
|
||||
local tt = t1 - t0
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json({ret = retstring , used = math.floor(tt*1000 + 0.5)})
|
||||
|
||||
end
|
||||
|
||||
function JudgeIPString(ipStr)
|
||||
if type(ipStr) ~= "string" then return false end
|
||||
|
||||
-- 判断长度
|
||||
local len = string.len(ipStr)
|
||||
if len < 7 or len > 15 then -- 长度不对
|
||||
return false
|
||||
end
|
||||
|
||||
-- 判断出现的非数字字符
|
||||
local point = string.find(ipStr, "%p", 1) -- 字符"."出现的位置
|
||||
local pointNum = 0 -- 字符"."出现的次数 正常ip有3个"."
|
||||
while point ~= nil do
|
||||
if string.sub(ipStr, point, point) ~= "." then -- 得到非数字符号不是字符"."
|
||||
return false
|
||||
end
|
||||
pointNum = pointNum + 1
|
||||
point = string.find(ipStr, "%p", point + 1)
|
||||
if pointNum > 3 then return false end
|
||||
end
|
||||
if pointNum ~= 3 then -- 不是正确的ip格式
|
||||
return false
|
||||
end
|
||||
|
||||
-- 判断数字对不对
|
||||
local num = {}
|
||||
for w in string.gmatch(ipStr, "%d+") do
|
||||
num[#num + 1] = w
|
||||
local kk = tonumber(w)
|
||||
if kk == nil or kk > 255 then -- 不是数字或超过ip正常取值范围了
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if #num ~= 4 then -- 不是4段数字
|
||||
return false
|
||||
end
|
||||
|
||||
return ipStr
|
||||
end
|
||||
|
||||
-- 检测 当前节点ip 和 网站访问情况
|
||||
function check_ip()
|
||||
|
||||
-- 获取当前的ip和国家
|
||||
local e = {}
|
||||
local d = {}
|
||||
local mm = require 'maxminddb'
|
||||
local db = mm.open('/usr/share/vssr/GeoLite2-Country.mmdb')
|
||||
local ip = string.gsub(luci.sys.exec("content=`wget --no-check-certificate -q -O - https://api.ip.sb/ip`;echo $content"), "\n", "")
|
||||
local res = db:lookup(ip)
|
||||
d.flag = string.lower(res:get("country", "iso_code"))
|
||||
d.country = res:get("country", "names", "zh-CN")
|
||||
e.outboard = ip
|
||||
e.outboardip = d
|
||||
|
||||
-- 检测国内通道
|
||||
e.baidu = false
|
||||
sret1 = luci.sys.call("/usr/bin/ssr-check www.baidu.com 80 3 1")
|
||||
if sret1 == 0 then e.baidu = true end
|
||||
|
||||
e.taobao = false
|
||||
sret2 = luci.sys.call("/usr/bin/ssr-check www.taobao.com 80 3 1")
|
||||
if sret2 == 0 then e.taobao = true end
|
||||
|
||||
-- 检测国外通道
|
||||
e.google = false
|
||||
sret3 = luci.sys.call("/usr/bin/ssr-check www.google.com 80 3 1")
|
||||
if sret3 == 0 then e.google = true end
|
||||
|
||||
e.youtube = false
|
||||
sret4 = luci.sys.call("/usr/bin/ssr-check www.youtube.com 80 3 1")
|
||||
if sret4 == 0 then e.youtube = true end
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
|
||||
-- 获取节点国旗 iso code
|
||||
function get_flag()
|
||||
local e = {}
|
||||
local host = luci.http.formvalue("host")
|
||||
local remark = luci.http.formvalue("remark")
|
||||
local cmd = '/usr/share/vssr/getflag.sh "' .. remark .. '" ' .. host
|
||||
e.host = host
|
||||
e.flag = luci.sys.exec(cmd)
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
140
package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/advanced.lua
Normal file
@ -0,0 +1,140 @@
|
||||
local vssr = "vssr"
|
||||
local uci = luci.model.uci.cursor()
|
||||
local server_table = {}
|
||||
|
||||
local gfwmode = 0
|
||||
local gfw_count = 0
|
||||
local ip_count = 0
|
||||
local ad_count = 0
|
||||
|
||||
if nixio.fs.access("/etc/dnsmasq.ssr/gfw_list.conf") then gfwmode = 1 end
|
||||
|
||||
local sys = require "luci.sys"
|
||||
|
||||
if gfwmode == 1 then
|
||||
gfw_count =
|
||||
tonumber(sys.exec("cat /etc/dnsmasq.ssr/gfw_list.conf | wc -l")) / 2
|
||||
if nixio.fs.access("/etc/dnsmasq.ssr/ad.conf") then
|
||||
ad_count = tonumber(sys.exec("cat /etc/dnsmasq.ssr/ad.conf | wc -l"))
|
||||
end
|
||||
end
|
||||
|
||||
if nixio.fs.access("/etc/china_ssr.txt") then
|
||||
ip_count = sys.exec("cat /etc/china_ssr.txt | wc -l")
|
||||
end
|
||||
|
||||
uci:foreach(vssr, "servers", function(s)
|
||||
if s["type"] == "v2ray" then
|
||||
if s.alias then
|
||||
server_table[s[".name"]] = "[%s]:%s" %
|
||||
{string.upper(s.type), s.alias}
|
||||
elseif s.server and s.server_port then
|
||||
server_table[s[".name"]] = "[%s]:%s:%s" %
|
||||
{
|
||||
string.upper(s.type), s.server, s.server_port
|
||||
}
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local key_table = {}
|
||||
for key, _ in pairs(server_table) do table.insert(key_table, key) end
|
||||
|
||||
table.sort(key_table)
|
||||
m = Map(vssr)
|
||||
|
||||
-- [[ 服务器节点故障自动切换设置 ]]--
|
||||
|
||||
s = m:section(TypedSection, "global",
|
||||
translate("Server failsafe auto swith settings"))
|
||||
s.anonymous = true
|
||||
|
||||
o = s:option(Flag, "monitor_enable", translate("Enable Process Deamon"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, "enable_switch", translate("Enable Auto Switch"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "switch_time", translate("Switch check cycly(second)"))
|
||||
o.datatype = "uinteger"
|
||||
o:depends("enable_switch", "1")
|
||||
o.default = 3600
|
||||
|
||||
o = s:option(Value, "switch_timeout", translate("Check timout(second)"))
|
||||
o.datatype = "uinteger"
|
||||
o:depends("enable_switch", "1")
|
||||
o.default = 5
|
||||
|
||||
o = s:option(Value, "switch_try_count", translate("Check Try Count"))
|
||||
o.datatype = "uinteger"
|
||||
o:depends("enable_switch", "1")
|
||||
o.default = 3
|
||||
|
||||
-- [[ 节点订阅 ]]--
|
||||
|
||||
s = m:section(TypedSection, "server_subscribe",
|
||||
translate("Servers subscription and manage"))
|
||||
s.anonymous = true
|
||||
|
||||
o = s:option(Flag, "auto_update", translate("Auto Update"))
|
||||
o.rmempty = false
|
||||
o.description = translate(
|
||||
"Auto Update Server subscription, GFW list and CHN route")
|
||||
|
||||
o =
|
||||
s:option(ListValue, "auto_update_time", translate("Update time (every day)"))
|
||||
for t = 0, 23 do o:value(t, t .. ":00") end
|
||||
o.default = 2
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(DynamicList, "subscribe_url", translate("Subscribe URL"))
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Flag, "proxy", translate("Through proxy update"))
|
||||
o.rmempty = false
|
||||
o.description = translate("Through proxy update list, Not Recommended ")
|
||||
|
||||
o = s:option(DummyValue, "", "")
|
||||
o.rawhtml = true
|
||||
o.template = "vssr/update_subscribe"
|
||||
|
||||
o = s:option(Button, "delete", translate("Delete all severs"))
|
||||
o.inputstyle = "reset"
|
||||
o.write = function()
|
||||
uci:delete_all("vssr", "servers", function(s) return true end)
|
||||
uci:commit("vssr")
|
||||
luci.sys.call("/etc/init.d/vssr stop")
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "vssr",
|
||||
"advanced"))
|
||||
end
|
||||
|
||||
-- [[ adblock ]]--
|
||||
s = m:section(TypedSection, "global", translate("adblock settings"))
|
||||
s.anonymous = true
|
||||
|
||||
o = s:option(Flag, "adblock", translate("Enable adblock"))
|
||||
o.rmempty = false
|
||||
|
||||
-- [[ 更新设置 ]]--
|
||||
|
||||
s = m:section(TypedSection, "socks5_proxy", translate("Update Setting"))
|
||||
s.anonymous = true
|
||||
|
||||
o = s:option(Button, "gfw_data", translate("GFW List Data"))
|
||||
o.rawhtml = true
|
||||
o.template = "vssr/refresh"
|
||||
o.value = tostring(math.ceil(gfw_count)) .. " " .. translate("Records")
|
||||
|
||||
o = s:option(Button, "ip_data", translate("China IP Data"))
|
||||
o.rawhtml = true
|
||||
o.template = "vssr/refresh"
|
||||
o.value = ip_count .. " " .. translate("Records")
|
||||
|
||||
if uci:get_first('vssr', 'global', 'adblock', '') == '1' then
|
||||
o = s:option(Button, "ad_data", translate("Advertising Data"))
|
||||
o.rawhtml = true
|
||||
o.template = "vssr/refresh"
|
||||
o.value = ad_count .. " " .. translate("Records")
|
||||
end
|
||||
|
||||
return m
|
@ -0,0 +1,387 @@
|
||||
-- Copyright (C) 2017 yushi studio <ywb94@qq.com> github.com/ywb94
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
local m, s, o, kcp_enable
|
||||
local vssr = "vssr"
|
||||
local uci = luci.model.uci.cursor()
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
local sys = require "luci.sys"
|
||||
local sid = arg[1]
|
||||
local uuid = luci.sys.exec("cat /proc/sys/kernel/random/uuid")
|
||||
|
||||
local function isKcptun(file)
|
||||
if not fs.access(file, "rwx", "rx", "rx") then fs.chmod(file, 755) end
|
||||
|
||||
local str = sys.exec(file .. " -v | awk '{printf $1}'")
|
||||
return (str:lower() == "kcptun")
|
||||
end
|
||||
|
||||
local server_table = {}
|
||||
local encrypt_methods = {
|
||||
"none", "table", "rc4", "rc4-md5-6", "rc4-md5", "aes-128-cfb",
|
||||
"aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr",
|
||||
"bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb",
|
||||
"cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "salsa20",
|
||||
"chacha20", "chacha20-ietf"
|
||||
}
|
||||
|
||||
local encrypt_methods_ss = {
|
||||
-- aead
|
||||
"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305", -- stream
|
||||
"table", "rc4", "rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb",
|
||||
"aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "bf-cfb", "camellia-128-cfb",
|
||||
"camellia-192-cfb", "camellia-256-cfb", "salsa20", "chacha20",
|
||||
"chacha20-ietf"
|
||||
}
|
||||
|
||||
local protocol = {
|
||||
"origin", "verify_deflate", "auth_sha1_v4", "auth_aes128_sha1",
|
||||
"auth_aes128_md5", "auth_chain_a", "auth_chain_b", "auth_chain_c",
|
||||
"auth_chain_d", "auth_chain_e", "auth_chain_f"
|
||||
}
|
||||
|
||||
obfs = {
|
||||
"plain", "http_simple", "http_post", "random_head", "tls1.2_ticket_auth"
|
||||
}
|
||||
|
||||
local securitys = {"auto", "none", "aes-128-gcm", "chacha20-poly1305"}
|
||||
|
||||
m = Map(vssr, translate("Edit vssr Server"))
|
||||
m.redirect = luci.dispatcher.build_url("admin/services/vssr/servers")
|
||||
if m.uci:get(vssr, sid) ~= "servers" then
|
||||
luci.http.redirect(m.redirect)
|
||||
return
|
||||
end
|
||||
|
||||
-- [[ Servers Setting ]]--
|
||||
s = m:section(NamedSection, sid, "servers")
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
o = s:option(DummyValue, "ssr_url", translate("Configuration Url"))
|
||||
o.rawhtml = true
|
||||
o.template = "vssr/ssrurl"
|
||||
o.value = sid
|
||||
|
||||
o = s:option(ListValue, "type", translate("Server Node Type"))
|
||||
o:value("ssr", translate("ShadowsocksR"))
|
||||
|
||||
if nixio.fs.access("/usr/bin/v2ray/v2ray") or nixio.fs.access("/usr/bin/v2ray") then
|
||||
o:value("ss", translate("Shadowsocks New Version"))
|
||||
o:value("v2ray", translate("V2Ray"))
|
||||
end
|
||||
|
||||
if nixio.fs.access("/usr/sbin/trojan") then
|
||||
o:value("trojan", translate("Trojan"))
|
||||
end
|
||||
|
||||
o.description = translate(
|
||||
"Using incorrect encryption mothod may causes service fail to start")
|
||||
|
||||
o = s:option(Value, "alias", translate("Alias(optional)"))
|
||||
|
||||
o = s:option(Value, "flag", translate("Area"))
|
||||
o.description = translate("请自己指定。格式:cn us hk 等")
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Value, "server", translate("Server Address"))
|
||||
o.datatype = "host"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "server_port", translate("Server Port"))
|
||||
o.datatype = "port"
|
||||
o.rmempty = false
|
||||
|
||||
-- o = s:option(Value, "timeout", translate("Connection Timeout"))
|
||||
-- o.datatype = "uinteger"
|
||||
-- o.default = 60
|
||||
-- o.rmempty = false
|
||||
|
||||
o = s:option(Value, "password", translate("Password"))
|
||||
o.password = true
|
||||
o.rmempty = true
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
o:depends("type", "trojan")
|
||||
|
||||
o = s:option(Value, "peer", translate("Peer"))
|
||||
o.datatype = "host"
|
||||
o.rmempty = true
|
||||
o:depends("type", "trojan")
|
||||
|
||||
o = s:option(ListValue, "encrypt_method", translate("Encrypt Method"))
|
||||
for _, v in ipairs(encrypt_methods) do o:value(v) end
|
||||
o.rmempty = true
|
||||
o:depends("type", "ssr")
|
||||
|
||||
o = s:option(ListValue, "encrypt_method_ss", translate("Encrypt Method"))
|
||||
for _, v in ipairs(encrypt_methods_ss) do o:value(v) end
|
||||
o.rmempty = true
|
||||
o:depends("type", "ss")
|
||||
|
||||
o = s:option(ListValue, "protocol", translate("Protocol"))
|
||||
for _, v in ipairs(protocol) do o:value(v) end
|
||||
o.rmempty = true
|
||||
o:depends("type", "ssr")
|
||||
|
||||
o = s:option(Value, "protocol_param", translate("Protocol param(optional)"))
|
||||
o:depends("type", "ssr")
|
||||
|
||||
o = s:option(ListValue, "obfs", translate("Obfs"))
|
||||
for _, v in ipairs(obfs) do o:value(v) end
|
||||
o.rmempty = true
|
||||
o:depends("type", "ssr")
|
||||
|
||||
o = s:option(Flag, "v2ray_plugin", translate("V2ray-plugin"))
|
||||
o.rmempty = false
|
||||
o:depends("type", "ss")
|
||||
|
||||
o = s:option(Value, "obfs_transport", translate("V2ray-plugin-transport"))
|
||||
o.rmempty = true
|
||||
o.default = "ws"
|
||||
o:depends("v2ray_plugin", "1")
|
||||
|
||||
o = s:option(Value, "obfs_host", translate("V2ray-plugin-host"))
|
||||
o.rmempty = true
|
||||
o:depends("v2ray_plugin", "1")
|
||||
|
||||
o = s:option(Value, "obfs_path", translate("V2ray-plugin-path"))
|
||||
o.rmempty = true
|
||||
o:depends("v2ray_plugin", "1")
|
||||
|
||||
o = s:option(Flag, "obfs_opts", translate("TLS"))
|
||||
o.rmempty = false
|
||||
o:depends("v2ray_plugin", "1")
|
||||
|
||||
o = s:option(Value, "obfs_param", translate("Obfs param(optional)"))
|
||||
o:depends("type", "ssr")
|
||||
|
||||
-- AlterId
|
||||
o = s:option(Value, "alter_id", translate("AlterId"))
|
||||
o.datatype = "port"
|
||||
o.default = 16
|
||||
o.rmempty = true
|
||||
o:depends("type", "v2ray")
|
||||
|
||||
-- VmessId
|
||||
o = s:option(Value, "vmess_id", translate("VmessId (UUID)"))
|
||||
o.rmempty = true
|
||||
o.default = uuid
|
||||
o:depends("type", "v2ray")
|
||||
|
||||
-- 加密方式
|
||||
o = s:option(ListValue, "security", translate("Encrypt Method"))
|
||||
for _, v in ipairs(securitys) do o:value(v, v:upper()) end
|
||||
o.rmempty = true
|
||||
o:depends("type", "v2ray")
|
||||
|
||||
-- 传输协议
|
||||
o = s:option(ListValue, "transport", translate("Transport"))
|
||||
o:value("tcp", "TCP")
|
||||
o:value("kcp", "mKCP")
|
||||
o:value("ws", "WebSocket")
|
||||
o:value("h2", "HTTP/2")
|
||||
o:value("quic", "QUIC")
|
||||
o.rmempty = true
|
||||
o:depends("type", "v2ray")
|
||||
|
||||
-- [[ TCP部分 ]]--
|
||||
|
||||
-- TCP伪装
|
||||
o = s:option(ListValue, "tcp_guise", translate("Camouflage Type"))
|
||||
o:depends("transport", "tcp")
|
||||
o:value("none", translate("None"))
|
||||
o:value("http", "HTTP")
|
||||
o.rmempty = true
|
||||
|
||||
-- HTTP域名
|
||||
o = s:option(DynamicList, "http_host", translate("HTTP Host"))
|
||||
o:depends("tcp_guise", "http")
|
||||
o.rmempty = true
|
||||
|
||||
-- HTTP路径
|
||||
o = s:option(DynamicList, "http_path", translate("HTTP Path"))
|
||||
o:depends("tcp_guise", "http")
|
||||
o.rmempty = true
|
||||
|
||||
-- [[ WS部分 ]]--
|
||||
|
||||
-- WS域名
|
||||
o = s:option(Value, "ws_host", translate("WebSocket Host"))
|
||||
o:depends("transport", "ws")
|
||||
o.rmempty = true
|
||||
|
||||
-- WS路径
|
||||
o = s:option(Value, "ws_path", translate("WebSocket Path"))
|
||||
o:depends("transport", "ws")
|
||||
o.rmempty = true
|
||||
|
||||
-- [[ H2部分 ]]--
|
||||
|
||||
-- H2域名
|
||||
o = s:option(DynamicList, "h2_host", translate("HTTP/2 Host"))
|
||||
o:depends("transport", "h2")
|
||||
o.rmempty = true
|
||||
|
||||
-- H2路径
|
||||
o = s:option(Value, "h2_path", translate("HTTP/2 Path"))
|
||||
o:depends("transport", "h2")
|
||||
o.rmempty = true
|
||||
|
||||
-- [[ QUIC部分 ]]--
|
||||
|
||||
o = s:option(ListValue, "quic_security", translate("QUIC Security"))
|
||||
o:depends("transport", "quic")
|
||||
o.rmempty = true
|
||||
o:value("none", translate("None"))
|
||||
o:value("aes-128-gcm", translate("aes-128-gcm"))
|
||||
o:value("chacha20-poly1305", translate("chacha20-poly1305"))
|
||||
|
||||
o = s:option(Value, "quic_key", translate("QUIC Key"))
|
||||
o:depends("transport", "quic")
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(ListValue, "quic_guise", translate("Header"))
|
||||
o:depends("transport", "quic")
|
||||
o.rmempty = true
|
||||
o:value("none", translate("None"))
|
||||
o:value("srtp", translate("VideoCall (SRTP)"))
|
||||
o:value("utp", translate("BitTorrent (uTP)"))
|
||||
o:value("wechat-video", translate("WechatVideo"))
|
||||
o:value("dtls", "DTLS 1.2")
|
||||
o:value("wireguard", "WireGuard")
|
||||
-- [[ mKCP部分 ]]--
|
||||
|
||||
o = s:option(ListValue, "kcp_guise", translate("Camouflage Type"))
|
||||
o:depends("transport", "kcp")
|
||||
o:value("none", translate("None"))
|
||||
o:value("srtp", translate("VideoCall (SRTP)"))
|
||||
o:value("utp", translate("BitTorrent (uTP)"))
|
||||
o:value("wechat-video", translate("WechatVideo"))
|
||||
o:value("dtls", "DTLS 1.2")
|
||||
o:value("wireguard", "WireGuard")
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Value, "mtu", translate("MTU"))
|
||||
o.datatype = "uinteger"
|
||||
o:depends("transport", "kcp")
|
||||
o.default = 1350
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Value, "tti", translate("TTI"))
|
||||
o.datatype = "uinteger"
|
||||
o:depends("transport", "kcp")
|
||||
o.default = 50
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Value, "uplink_capacity", translate("Uplink Capacity"))
|
||||
o.datatype = "uinteger"
|
||||
o:depends("transport", "kcp")
|
||||
o.default = 5
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Value, "downlink_capacity", translate("Downlink Capacity"))
|
||||
o.datatype = "uinteger"
|
||||
o:depends("transport", "kcp")
|
||||
o.default = 20
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Value, "read_buffer_size", translate("Read Buffer Size"))
|
||||
o.datatype = "uinteger"
|
||||
o:depends("transport", "kcp")
|
||||
o.default = 2
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Value, "write_buffer_size", translate("Write Buffer Size"))
|
||||
o.datatype = "uinteger"
|
||||
o:depends("transport", "kcp")
|
||||
o.default = 2
|
||||
o.rmempty = true
|
||||
|
||||
o = s:option(Flag, "congestion", translate("Congestion"))
|
||||
o:depends("transport", "kcp")
|
||||
o.rmempty = true
|
||||
|
||||
-- [[ allowInsecure ]]--
|
||||
o = s:option(Flag, "insecure", translate("allowInsecure"))
|
||||
o.rmempty = true
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "trojan")
|
||||
|
||||
-- [[ TLS ]]--
|
||||
o = s:option(Flag, "tls", translate("TLS"))
|
||||
o.rmempty = true
|
||||
o.default = "0"
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("type", "trojan")
|
||||
|
||||
-- [[ Mux ]]--
|
||||
o = s:option(Flag, "mux", translate("Mux"))
|
||||
o.rmempty = true
|
||||
o.default = "0"
|
||||
o:depends("type", "v2ray")
|
||||
o:depends("v2ray_plugin", "1")
|
||||
|
||||
o = s:option(Value, "concurrency", translate("Concurrency"))
|
||||
o.datatype = "uinteger"
|
||||
o.rmempty = true
|
||||
o.default = "8"
|
||||
o:depends("mux", "1")
|
||||
o = s:option(Flag, "fast_open", translate("TCP Fast Open"))
|
||||
o.rmempty = true
|
||||
o.default = "0"
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
o:depends("type", "trojan")
|
||||
|
||||
o = s:option(Flag, "switch_enable", translate("Enable Auto Switch"))
|
||||
o.rmempty = false
|
||||
o.default = "1"
|
||||
|
||||
o = s:option(Value, "local_port", translate("Local Port"))
|
||||
o.datatype = "port"
|
||||
o.default = 1234
|
||||
o.rmempty = false
|
||||
|
||||
if nixio.fs.access("/usr/bin/kcptun-client") then
|
||||
|
||||
kcp_enable = s:option(Flag, "kcp_enable", translate("KcpTun Enable"),
|
||||
translate("bin:/usr/bin/kcptun-client"))
|
||||
kcp_enable.rmempty = true
|
||||
kcp_enable.default = "0"
|
||||
kcp_enable:depends("type", "ssr")
|
||||
kcp_enable:depends("type", "ss")
|
||||
|
||||
o = s:option(Value, "kcp_port", translate("KcpTun Port"))
|
||||
o.datatype = "port"
|
||||
o.default = 4000
|
||||
function o.validate(self, value, section)
|
||||
local kcp_file = "/usr/bin/kcptun-client"
|
||||
local enable = kcp_enable:formvalue(section) or kcp_enable.disabled
|
||||
if enable == kcp_enable.enabled then
|
||||
if not fs.access(kcp_file) then
|
||||
return nil, translate("Haven't a Kcptun executable file")
|
||||
elseif not isKcptun(kcp_file) then
|
||||
return nil, translate("Not a Kcptun executable file")
|
||||
end
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
|
||||
o = s:option(Value, "kcp_password", translate("KcpTun Password"))
|
||||
o.password = true
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
|
||||
o = s:option(Value, "kcp_param", translate("KcpTun Param"))
|
||||
o.default = "--nocomp"
|
||||
o:depends("type", "ssr")
|
||||
o:depends("type", "ss")
|
||||
|
||||
end
|
||||
|
||||
return m
|
148
package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/client.lua
Normal file
@ -0,0 +1,148 @@
|
||||
-- Copyright (C) 2017 yushi studio <ywb94@qq.com> github.com/ywb94
|
||||
-- Copyright (C) 2018 lean <coolsnowwolf@gmail.com> github.com/coolsnowwolf
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
local m, s, sec, o, kcp_enable
|
||||
local vssr = "vssr"
|
||||
local gfwmode=0
|
||||
|
||||
if nixio.fs.access("/etc/dnsmasq.ssr/gfw_list.conf") then
|
||||
gfwmode=1
|
||||
end
|
||||
|
||||
local uci = luci.model.uci.cursor()
|
||||
|
||||
m = Map(vssr)
|
||||
|
||||
m:section(SimpleSection).template = "vssr/status_top"
|
||||
|
||||
local server_table = {}
|
||||
local v2ray_table = {}
|
||||
uci:foreach(vssr, "servers", function(s)
|
||||
if s.alias then
|
||||
server_table[s[".name"]] = "[%s]:%s" %{string.upper(s.type), s.alias}
|
||||
elseif s.server and s.server_port then
|
||||
server_table[s[".name"]] = "[%s]:%s:%s" %{string.upper(s.type), s.server, s.server_port}
|
||||
end
|
||||
|
||||
if s.type == "v2ray" then
|
||||
if s.alias then
|
||||
v2ray_table[s[".name"]] = "[%s]:%s" %{string.upper(s.type), s.alias}
|
||||
elseif s.server and s.server_port then
|
||||
v2ray_table[s[".name"]] = "[%s]:%s:%s" %{string.upper(s.type), s.server, s.server_port}
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local key_table = {}
|
||||
for key,_ in pairs(server_table) do
|
||||
table.insert(key_table,key)
|
||||
end
|
||||
|
||||
table.sort(key_table)
|
||||
|
||||
local key_table_v2 = {}
|
||||
for key,_ in pairs(v2ray_table) do
|
||||
table.insert(key_table_v2,key)
|
||||
end
|
||||
|
||||
table.sort(key_table_v2)
|
||||
|
||||
-- [[ Global Setting ]]--
|
||||
s = m:section(TypedSection, "global",translate("Basic Settings [SS(R)|V2ray|Trojan]"))
|
||||
s.anonymous = true
|
||||
|
||||
o = s:option(ListValue, "global_server", translate("Main Server"))
|
||||
o:value("nil", translate("Disable"))
|
||||
for _,key in pairs(key_table) do o:value(key,server_table[key]) end
|
||||
o.default = "nil"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, "udp_relay_server", translate("Game Mode UDP Server"))
|
||||
o:value("", translate("Disable"))
|
||||
o:value("same", translate("Same as Global Server"))
|
||||
for _,key in pairs(key_table) do o:value(key,server_table[key]) end
|
||||
|
||||
o = s:option(Flag, "v2ray_flow", translate("Open v2ray split-flow"))
|
||||
o.rmempty = false
|
||||
o.description = translate("When open v2ray split-flow,your main server must be a v2ray server")
|
||||
|
||||
o = s:option(ListValue, "youtube_server", translate("Youtube Proxy"))
|
||||
o:value("nil", translate("Same as Global Server"))
|
||||
for _,key in pairs(key_table_v2) do o:value(key,v2ray_table[key]) end
|
||||
o:depends("v2ray_flow", "1")
|
||||
o.default = "nil"
|
||||
|
||||
|
||||
|
||||
o = s:option(ListValue, "tw_video_server", translate("TaiWan Video Proxy"))
|
||||
o:value("nil", translate("Same as Global Server"))
|
||||
for _,key in pairs(key_table_v2) do o:value(key,v2ray_table[key]) end
|
||||
o:depends("v2ray_flow", "1")
|
||||
o.default = "nil"
|
||||
|
||||
|
||||
o = s:option(ListValue, "netflix_server", translate("Netflix Proxy"))
|
||||
o:value("nil", translate("Same as Global Server"))
|
||||
for _,key in pairs(key_table_v2) do o:value(key,v2ray_table[key]) end
|
||||
o:depends("v2ray_flow", "1")
|
||||
o.default = "nil"
|
||||
|
||||
|
||||
o = s:option(ListValue, "disney_server", translate("Diseny+ Proxy"))
|
||||
o:value("nil", translate("Same as Global Server"))
|
||||
for _,key in pairs(key_table_v2) do o:value(key,v2ray_table[key]) end
|
||||
o:depends("v2ray_flow", "1")
|
||||
o.default = "nil"
|
||||
|
||||
|
||||
o = s:option(ListValue, "prime_server", translate("Prime Video Proxy"))
|
||||
o:value("nil", translate("Same as Global Server"))
|
||||
for _,key in pairs(key_table_v2) do o:value(key,v2ray_table[key]) end
|
||||
o:depends("v2ray_flow", "1")
|
||||
o.default = "nil"
|
||||
|
||||
|
||||
o = s:option(ListValue, "threads", translate("Multi Threads Option"))
|
||||
o:value("0", translate("Auto Threads"))
|
||||
o:value("1", translate("1 Thread"))
|
||||
o:value("2", translate("2 Threads"))
|
||||
o:value("4", translate("4 Threads"))
|
||||
o:value("8", translate("8 Threads"))
|
||||
o.default = "0"
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, "run_mode", translate("Running Mode"))
|
||||
o:value("gfw", translate("GFW List Mode"))
|
||||
o:value("router", translate("IP Route Mode"))
|
||||
o:value("all", translate("Global Mode"))
|
||||
o:value("oversea", translate("Oversea Mode"))
|
||||
o.default = "router"
|
||||
o = s:option(ListValue, "dports", translate("Proxy Ports"))
|
||||
o:value("1", translate("All Ports"))
|
||||
o:value("2", translate("Only Common Ports"))
|
||||
o.default = 1
|
||||
|
||||
o = s:option(ListValue, "pdnsd_enable", translate("Resolve Dns Mode"))
|
||||
o:value("1", translate("Use Pdnsd tcp query and cache"))
|
||||
o:value("0", translate("Use Local DNS Service listen port 5335"))
|
||||
o.default = 1
|
||||
|
||||
o = s:option(Value, "tunnel_forward", translate("Anti-pollution DNS Server"))
|
||||
o:value("8.8.4.4:53", translate("Google Public DNS (8.8.4.4)"))
|
||||
o:value("8.8.8.8:53", translate("Google Public DNS (8.8.8.8)"))
|
||||
o:value("208.67.222.222:53", translate("OpenDNS (208.67.222.222)"))
|
||||
o:value("208.67.220.220:53", translate("OpenDNS (208.67.220.220)"))
|
||||
o:value("209.244.0.3:53", translate("Level 3 Public DNS (209.244.0.3)"))
|
||||
o:value("209.244.0.4:53", translate("Level 3 Public DNS (209.244.0.4)"))
|
||||
o:value("4.2.2.1:53", translate("Level 3 Public DNS (4.2.2.1)"))
|
||||
o:value("4.2.2.2:53", translate("Level 3 Public DNS (4.2.2.2)"))
|
||||
o:value("4.2.2.3:53", translate("Level 3 Public DNS (4.2.2.3)"))
|
||||
o:value("4.2.2.4:53", translate("Level 3 Public DNS (4.2.2.4)"))
|
||||
o:value("1.1.1.1:53", translate("Cloudflare DNS (1.1.1.1)"))
|
||||
o:value("114.114.114.114:53", translate("Oversea Mode DNS-1 (114.114.114.114)"))
|
||||
o:value("114.114.115.115:53", translate("Oversea Mode DNS-2 (114.114.115.115)"))
|
||||
o:depends("pdnsd_enable", "1")
|
||||
|
||||
m:section(SimpleSection).template = "vssr/status_bottom"
|
||||
return m
|
@ -0,0 +1,88 @@
|
||||
local m, s, o
|
||||
local NXFS = require "nixio.fs"
|
||||
|
||||
m = Map("vssr", translate("IP black-and-white list"))
|
||||
|
||||
s = m:section(TypedSection, "access_control")
|
||||
s.anonymous = true
|
||||
|
||||
-- Part of WAN
|
||||
s:tab("wan_ac", translate("WAN IP AC"))
|
||||
|
||||
o = s:taboption("wan_ac", DynamicList, "wan_bp_ips", translate("WAN White List IP"))
|
||||
o.datatype = "ip4addr"
|
||||
|
||||
o = s:taboption("wan_ac", DynamicList, "wan_fw_ips", translate("WAN Force Proxy IP"))
|
||||
o.datatype = "ip4addr"
|
||||
|
||||
-- Part of LAN
|
||||
s:tab("lan_ac", translate("LAN IP AC"))
|
||||
|
||||
o = s:taboption("lan_ac", DynamicList, "lan_ac_ips", translate("LAN Bypassed Host List"))
|
||||
o.datatype = "ipaddr"
|
||||
luci.ip.neighbors({ family = 4 }, function(entry)
|
||||
if entry.reachable then
|
||||
o:value(entry.dest:string())
|
||||
end
|
||||
end)
|
||||
|
||||
o = s:taboption("lan_ac", DynamicList, "lan_fp_ips", translate("LAN Force Proxy Host List"))
|
||||
o.datatype = "ipaddr"
|
||||
luci.ip.neighbors({ family = 4 }, function(entry)
|
||||
if entry.reachable then
|
||||
o:value(entry.dest:string())
|
||||
end
|
||||
end)
|
||||
|
||||
o = s:taboption("lan_ac", DynamicList, "lan_gm_ips", translate("Game Mode Host List"))
|
||||
o.datatype = "ipaddr"
|
||||
luci.ip.neighbors({ family = 4 }, function(entry)
|
||||
if entry.reachable then
|
||||
o:value(entry.dest:string())
|
||||
end
|
||||
end)
|
||||
|
||||
-- Part of Self
|
||||
-- s:tab("self_ac", translate("Router Self AC"))
|
||||
-- o = s:taboption("self_ac",ListValue, "router_proxy", translate("Router Self Proxy"))
|
||||
-- o:value("1", translatef("Normal Proxy"))
|
||||
-- o:value("0", translatef("Bypassed Proxy"))
|
||||
-- o:value("2", translatef("Forwarded Proxy"))
|
||||
-- o.rmempty = false
|
||||
|
||||
s:tab("esc", translate("Bypass Domain List"))
|
||||
|
||||
local escconf = "/etc/config/white.list"
|
||||
o = s:taboption("esc", TextValue, "escconf")
|
||||
o.rows = 13
|
||||
o.wrap = "off"
|
||||
o.rmempty = true
|
||||
o.cfgvalue = function(self, section)
|
||||
return NXFS.readfile(escconf) or ""
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
NXFS.writefile(escconf, value:gsub("\r\n", "\n"))
|
||||
end
|
||||
o.remove = function(self, section, value)
|
||||
NXFS.writefile(escconf, "")
|
||||
end
|
||||
|
||||
|
||||
s:tab("block", translate("Black Domain List"))
|
||||
|
||||
local blockconf = "/etc/config/black.list"
|
||||
o = s:taboption("block", TextValue, "blockconf")
|
||||
o.rows = 13
|
||||
o.wrap = "off"
|
||||
o.rmempty = true
|
||||
o.cfgvalue = function(self, section)
|
||||
return NXFS.readfile(blockconf) or " "
|
||||
end
|
||||
o.write = function(self, section, value)
|
||||
NXFS.writefile(blockconf, value:gsub("\r\n", "\n"))
|
||||
end
|
||||
o.remove = function(self, section, value)
|
||||
NXFS.writefile(blockconf, "")
|
||||
end
|
||||
|
||||
return m
|
15
package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/log.lua
Normal file
@ -0,0 +1,15 @@
|
||||
local fs = require "nixio.fs"
|
||||
local conffile = "/tmp/ssrpro.log"
|
||||
|
||||
f = SimpleForm("logview")
|
||||
|
||||
t = f:field(TextValue, "conf")
|
||||
t.rmempty = true
|
||||
t.rows = 20
|
||||
function t.cfgvalue()
|
||||
luci.sys.exec("[ -f /tmp/vssr.log ] && sed '1!G;h;$!d' /tmp/vssr.log > /tmp/ssrpro.log")
|
||||
return fs.readfile(conffile) or ""
|
||||
end
|
||||
t.readonly="readonly"
|
||||
|
||||
return f
|
@ -0,0 +1,95 @@
|
||||
-- Copyright (C) 2017 yushi studio <ywb94@qq.com>
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
local m, s, o
|
||||
local vssr = "vssr"
|
||||
local sid = arg[1]
|
||||
|
||||
local encrypt_methods = {
|
||||
"rc4-md5",
|
||||
"rc4-md5-6",
|
||||
"rc4",
|
||||
"table",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"cast5-cfb",
|
||||
"des-cfb",
|
||||
"idea-cfb",
|
||||
"rc2-cfb",
|
||||
"seed-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf",
|
||||
}
|
||||
|
||||
local protocol = {
|
||||
"origin",
|
||||
}
|
||||
|
||||
obfs = {
|
||||
"plain",
|
||||
"http_simple",
|
||||
"http_post",
|
||||
}
|
||||
|
||||
m = Map(vssr, translate("Edit vssr Server"))
|
||||
|
||||
m.redirect = luci.dispatcher.build_url("admin/services/vssr/server")
|
||||
if m.uci:get(vssr, sid) ~= "server_config" then
|
||||
luci.http.redirect(m.redirect)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
-- [[ Server Setting ]]--
|
||||
s = m:section(NamedSection, sid, "server_config")
|
||||
s.anonymous = true
|
||||
s.addremove = false
|
||||
|
||||
o = s:option(Flag, "enable", translate("Enable"))
|
||||
o.default = 1
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "server_port", translate("Server Port"))
|
||||
o.datatype = "port"
|
||||
o.default = 8388
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "timeout", translate("Connection Timeout"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 60
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "password", translate("Password"))
|
||||
o.password = true
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, "encrypt_method", translate("Encrypt Method"))
|
||||
for _, v in ipairs(encrypt_methods) do o:value(v) end
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(ListValue, "protocol", translate("Protocol"))
|
||||
for _, v in ipairs(protocol) do o:value(v) end
|
||||
o.rmempty = false
|
||||
|
||||
|
||||
o = s:option(ListValue, "obfs", translate("Obfs"))
|
||||
for _, v in ipairs(obfs) do o:value(v) end
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "obfs_param", translate("Obfs param(optional)"))
|
||||
|
||||
o = s:option(Flag, "fast_open", translate("TCP Fast Open"))
|
||||
o.rmempty = false
|
||||
|
||||
return m
|
114
package/ctcgfw/luci-app-vssr/luasrc/model/cbi/vssr/server.lua
Normal file
@ -0,0 +1,114 @@
|
||||
-- Copyright (C) 2017 yushi studio <ywb94@qq.com>
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
|
||||
local m, sec, o
|
||||
local vssr = "vssr"
|
||||
local uci = luci.model.uci.cursor()
|
||||
local ipkg = require("luci.model.ipkg")
|
||||
|
||||
|
||||
m = Map(vssr, translate("vssr Server"))
|
||||
|
||||
local encrypt_methods = {
|
||||
"table",
|
||||
"rc4",
|
||||
"rc4-md5",
|
||||
"rc4-md5-6",
|
||||
"aes-128-cfb",
|
||||
"aes-192-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-128-ctr",
|
||||
"aes-192-ctr",
|
||||
"aes-256-ctr",
|
||||
"bf-cfb",
|
||||
"camellia-128-cfb",
|
||||
"camellia-192-cfb",
|
||||
"camellia-256-cfb",
|
||||
"cast5-cfb",
|
||||
"des-cfb",
|
||||
"idea-cfb",
|
||||
"rc2-cfb",
|
||||
"seed-cfb",
|
||||
"salsa20",
|
||||
"chacha20",
|
||||
"chacha20-ietf",
|
||||
}
|
||||
|
||||
local protocol = {
|
||||
"origin",
|
||||
"verify_deflate",
|
||||
"auth_sha1_v4",
|
||||
"auth_aes128_sha1",
|
||||
"auth_aes128_md5",
|
||||
"auth_chain_a",
|
||||
}
|
||||
|
||||
obfs = {
|
||||
"plain",
|
||||
"http_simple",
|
||||
"http_post",
|
||||
"random_head",
|
||||
"tls1.2_ticket_auth",
|
||||
"tls1.2_ticket_fastauth",
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- [[ Global Setting ]]--
|
||||
sec = m:section(TypedSection, "server_global", translate("Global Setting"))
|
||||
sec.anonymous = true
|
||||
|
||||
|
||||
|
||||
o = sec:option(Flag, "enable_server", translate("Enable Server"))
|
||||
o.rmempty = false
|
||||
|
||||
-- [[ Server Setting ]]--
|
||||
sec = m:section(TypedSection, "server_config", translate("Server Setting"))
|
||||
sec.anonymous = true
|
||||
sec.addremove = true
|
||||
sec.template = "cbi/tblsection"
|
||||
sec.extedit = luci.dispatcher.build_url("admin/services/vssr/server/%s")
|
||||
function sec.create(...)
|
||||
local sid = TypedSection.create(...)
|
||||
if sid then
|
||||
luci.http.redirect(sec.extedit % sid)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
o = sec:option(Flag, "enable", translate("Enable"))
|
||||
function o.cfgvalue(...)
|
||||
return Value.cfgvalue(...) or translate("0")
|
||||
end
|
||||
o.rmempty = false
|
||||
|
||||
o = sec:option(DummyValue, "server_port", translate("Server Port"))
|
||||
function o.cfgvalue(...)
|
||||
return Value.cfgvalue(...) or "?"
|
||||
end
|
||||
|
||||
|
||||
o = sec:option(DummyValue, "encrypt_method", translate("Encrypt Method"))
|
||||
function o.cfgvalue(...)
|
||||
local v = Value.cfgvalue(...)
|
||||
return v and v:upper() or "?"
|
||||
end
|
||||
|
||||
o = sec:option(DummyValue, "protocol", translate("Protocol"))
|
||||
function o.cfgvalue(...)
|
||||
return Value.cfgvalue(...) or "?"
|
||||
end
|
||||
|
||||
|
||||
|
||||
o = sec:option(DummyValue, "obfs", translate("Obfs"))
|
||||
function o.cfgvalue(...)
|
||||
return Value.cfgvalue(...) or "?"
|
||||
end
|
||||
|
||||
|
||||
|
||||
return m
|
@ -0,0 +1,43 @@
|
||||
-- Licensed to the public under the GNU General Public License v3.
|
||||
local m, s, o
|
||||
local vssr = "vssr"
|
||||
local cjson = require("cjson")
|
||||
|
||||
local uci = luci.model.uci.cursor()
|
||||
local server_count = 0
|
||||
local server_table = {}
|
||||
uci:foreach("vssr", "servers", function(s)
|
||||
server_count = server_count + 1
|
||||
s["name"] = s[".name"]
|
||||
table.insert(server_table, s)
|
||||
end)
|
||||
|
||||
local name = ""
|
||||
uci:foreach("vssr", "global", function(s) name = s[".name"] end)
|
||||
|
||||
m = Map(vssr)
|
||||
|
||||
m:section(SimpleSection).template = "vssr/status_top"
|
||||
|
||||
-- [[ Servers List ]]--
|
||||
s = m:section(TypedSection, "servers")
|
||||
s.anonymous = true
|
||||
s.addremove = true
|
||||
s.sortable = false
|
||||
|
||||
s.des = server_count
|
||||
s.current = uci:get("vssr", name, "global_server")
|
||||
s.servers = cjson.encode(server_table)
|
||||
s.template = "vssr/tblsection"
|
||||
s.extedit = luci.dispatcher.build_url("admin/services/vssr/servers/%s")
|
||||
function s.create(...)
|
||||
local sid = TypedSection.create(...)
|
||||
if sid then
|
||||
luci.http.redirect(s.extedit % sid)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
m:section(SimpleSection).template = "vssr/status_bottom"
|
||||
|
||||
return m
|
@ -0,0 +1,41 @@
|
||||
local vssr = "vssr"
|
||||
local uci = luci.model.uci.cursor()
|
||||
local server_table = {}
|
||||
|
||||
|
||||
local sys = require "luci.sys"
|
||||
|
||||
m = Map(vssr)
|
||||
|
||||
-- [[ SOCKS5 Proxy ]]--
|
||||
if nixio.fs.access("/usr/bin/v2ray/v2ray") then
|
||||
s = m:section(TypedSection, "socks5_proxy", translate("V2ray SOCKS5 Proxy"))
|
||||
s.anonymous = true
|
||||
|
||||
o = s:option(Flag, "enable_server", translate("Enable Servers"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Flag, "enable_auth", translate("Enable Auth"))
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "Socks_user", translate("Socks user"))
|
||||
o.default="user"
|
||||
o.rmempty = true
|
||||
o:depends("enable_auth", "1")
|
||||
|
||||
o = s:option(Value, "Socks_pass", translate("Socks pass"))
|
||||
o.default="password"
|
||||
o.password = true
|
||||
o.rmempty = true
|
||||
o:depends("enable_auth", "1")
|
||||
|
||||
o = s:option(Value, "local_port", translate("Local Port"))
|
||||
o.datatype = "port"
|
||||
o.default = 1080
|
||||
o.rmempty = false
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
return m
|
@ -0,0 +1 @@
|
||||
</div>
|
@ -0,0 +1,2 @@
|
||||
|
||||
<div id="cbi-<%=self.config.."-"..section.."-"..self.option%>" data-index="<%=self.index%>" class="incon<%=subcount%>" data-depends="<%=pcdata(self:deplist2json(section))%>">
|
21
package/ctcgfw/luci-app-vssr/luasrc/view/vssr/licence.htm
Normal file
@ -0,0 +1,21 @@
|
||||
<%+header%>
|
||||
<link rel="stylesheet" href="/luci-static/vssr/css/vssr.css?v=<%=math.random(1,100000)%>">
|
||||
|
||||
<div class="pure-g status">
|
||||
<div class="pure-u-1">
|
||||
<div class="block pure-g">
|
||||
<div class="pure-u-1">
|
||||
<h4 id="vssr_status"><span class="green" style="color: #404040;">GeoLite2</span></h4>
|
||||
<p style="margin: 1rem; line-height: 1.8em;">This product includes GeoLite2 data created by MaxMind,
|
||||
available from
|
||||
<a href="https://www.maxmind.com">https://www.maxmind.com</a>.</p>
|
||||
|
||||
<h4 id="vssr_status"><span class="green" style="color: #404040;">Flag-icon-css</span></h4>
|
||||
<p style="margin: 1rem; line-height: 1.8em;">A collection of all country flags in SVG — plus the CSS for easier integration <a href="https://flagicons.lipis.dev">https://flagicons.lipis.dev</a></p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<%+footer%>
|
35
package/ctcgfw/luci-app-vssr/luasrc/view/vssr/refresh.htm
Normal file
@ -0,0 +1,35 @@
|
||||
<%+cbi/valueheader%>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
|
||||
function refresh_data(btn, dataname) {
|
||||
btn.disabled = true;
|
||||
btn.value = '<%:Refresh...%> ';
|
||||
murl = dataname;
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "vssr","refresh")%>',
|
||||
{ set: murl },
|
||||
function (x, rv) {
|
||||
var s = document.getElementById(dataname + '-status');
|
||||
if (s) {
|
||||
if (rv.ret == "0")
|
||||
s.innerHTML = "<font color='green'>" + "<%:No new data!%> " + "</font>";
|
||||
else if (rv.ret == "-1") {
|
||||
s.innerHTML = "<font color='red'>" + "<%:Refresh Error!%> " + "</font>";
|
||||
}
|
||||
else {
|
||||
s.innerHTML = "<font color='green'>" + "<%:Refresh OK!%> " + "<%:Total Records:%>" + rv.ret + "</font>";
|
||||
}
|
||||
}
|
||||
btn.disabled = false;
|
||||
btn.value = '<%:Refresh Data %>';
|
||||
}
|
||||
);
|
||||
return false;
|
||||
}
|
||||
//]]></script>
|
||||
|
||||
<input type="button" class="cbi-button cbi-input-reload" value="<%:Refresh Data%> "
|
||||
onclick="return refresh_data(this,'<%=self.option%>')" />
|
||||
<span id="<%=self.option%>-status"><em><%=self.value%></em></span>
|
||||
|
||||
<%+cbi/valuefooter%>
|
275
package/ctcgfw/luci-app-vssr/luasrc/view/vssr/ssrurl.htm
Normal file
@ -0,0 +1,275 @@
|
||||
<%+cbi/valueheader%>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
|
||||
const GET_FLAG_URL = '<%=luci.dispatcher.build_url("admin", "services", "vssr","flag")%>';
|
||||
var sid;
|
||||
|
||||
|
||||
function getFlag(remark, hosts, sid) {
|
||||
XHR.get(GET_FLAG_URL,
|
||||
{ host: hosts, remark: remark },
|
||||
function (x, rv) {
|
||||
el('.flag').value = rv.flag.replace(/[\r\n]/g, "");
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
function padright(str, cnt, pad) {
|
||||
return str + Array(cnt + 1).join(pad);
|
||||
}
|
||||
function b64EncodeUnicode(str) {
|
||||
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
|
||||
return String.fromCharCode('0x' + p1);
|
||||
}));
|
||||
}
|
||||
function b64encutf8safe(str) {
|
||||
return b64EncodeUnicode(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, '');
|
||||
}
|
||||
function b64DecodeUnicode(str) {
|
||||
return decodeURIComponent(Array.prototype.map.call(atob(str), function (c) {
|
||||
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
}).join(''));
|
||||
}
|
||||
function b64decutf8safe(str) {
|
||||
var l;
|
||||
str = str.replace(/-/g, "+").replace(/_/g, "/");
|
||||
l = str.length;
|
||||
l = (4 - l % 4) % 4;
|
||||
if (l)
|
||||
str = padright(str, l, "=");
|
||||
return b64DecodeUnicode(str);
|
||||
}
|
||||
function b64encsafe(str) {
|
||||
return btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, '')
|
||||
}
|
||||
function b64decsafe(str) {
|
||||
var l;
|
||||
str = str.replace(/-/g, "+").replace(/_/g, "/");
|
||||
l = str.length;
|
||||
l = (4 - l % 4) % 4;
|
||||
if (l)
|
||||
str = padright(str, l, "=");
|
||||
try {
|
||||
return atob(str);
|
||||
}catch(err) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
function dictvalue(d, key) {
|
||||
var v = d[key];
|
||||
if (typeof (v) == 'undefined' || v == '')
|
||||
return '';
|
||||
return b64decsafe(v);
|
||||
}
|
||||
|
||||
function el(id) {
|
||||
return document.getElementById('cbid.vssr.' + sid + id);
|
||||
}
|
||||
|
||||
|
||||
function import_ssr_url(btn, urlname, sids) {
|
||||
sid = sids;
|
||||
var s = document.getElementById(urlname + '-status');
|
||||
if (!s)
|
||||
return false;
|
||||
var ssrurl = prompt("<%:Paste Node Link Here%> ssr:// | ss:// | vmess:// | trojan://", "");
|
||||
if (ssrurl == null || ssrurl == "") {
|
||||
s.innerHTML = "<font color='red'><%:User Cancel%></font>";
|
||||
return false;
|
||||
}
|
||||
s.innerHTML = "";
|
||||
//var ssu = ssrurl.match(/ssr:\/\/([A-Za-z0-9_-]+)/i);
|
||||
var ssu = ssrurl.split('://');
|
||||
console.log(ssu.length);
|
||||
if ((ssu[0] != "ssr" && ssu[0] != "ss" && ssu[0] != "vmess" && ssu[0] != "trojan") || ssu[1] == "") {
|
||||
s.innerHTML = "<font color='red'><%:Invalid Format%></font>";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var event = document.createEvent("HTMLEvents");
|
||||
event.initEvent("change", true, true);
|
||||
var rema = "";
|
||||
if (ssu[0] == "ssr") {
|
||||
var sstr = b64decsafe(ssu[1]);
|
||||
var ploc = sstr.indexOf("/?");
|
||||
|
||||
el('.type').value = "ssr";
|
||||
el('.type').dispatchEvent(event);
|
||||
var url0, param = "";
|
||||
if (ploc > 0) {
|
||||
url0 = sstr.substr(0, ploc);
|
||||
param = sstr.substr(ploc + 2);
|
||||
}
|
||||
var ssm = url0.match(/^(.+):([^:]+):([^:]*):([^:]+):([^:]*):([^:]+)/);
|
||||
if (!ssm || ssm.length < 7)
|
||||
return false;
|
||||
var pdict = {};
|
||||
if (param.length > 2) {
|
||||
var a = param.split('&');
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
var b = a[i].split('=');
|
||||
pdict[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || '');
|
||||
}
|
||||
}
|
||||
el('.server').value = ssm[1];
|
||||
el('.server_port').value = ssm[2];
|
||||
el('.protocol').value = ssm[3];
|
||||
el('.encrypt_method').value = ssm[4];
|
||||
el('.obfs').value = ssm[5];
|
||||
el('.password').value = b64decsafe(ssm[6]);
|
||||
el('.obfs_param').value = dictvalue(pdict, 'obfsparam');
|
||||
el('.protocol_param').value = dictvalue(pdict, 'protoparam');
|
||||
|
||||
var rem = pdict['remarks'];
|
||||
if (typeof (rem) != 'undefined' && rem != '' && rem.length > 0)
|
||||
rema = b64decutf8safe(rem);
|
||||
el('.alias').value = b64decutf8safe(rem);
|
||||
getFlag(rema, ssm[1], sid); //get flag iso code
|
||||
s.innerHTML = "<font color='green'><%:Import%>ShadowsocksR<%:Configuration Succeeded%></font>";
|
||||
return false;
|
||||
} else if (ssu[0] == "ss") {
|
||||
var ploc = ssu[1].indexOf("#");
|
||||
if (ploc > 0) {
|
||||
url0 = ssu[1].substr(0, ploc);
|
||||
param = ssu[1].substr(ploc + 1);
|
||||
} else {
|
||||
url0 = ssu[1]
|
||||
}
|
||||
var sstr = b64decsafe(url0);
|
||||
|
||||
|
||||
el('.type').value = "ss";
|
||||
|
||||
el('.type').dispatchEvent(event);
|
||||
var team = sstr.split('@');
|
||||
console.log(param);
|
||||
var part1 = team[0].split(':');
|
||||
var part2 = team[1].split(':');
|
||||
el('.server').value = part2[0];
|
||||
el('.server_port').value = part2[1];
|
||||
el('.password').value = part1[1];
|
||||
el('.encrypt_method_ss').value = part1[0];
|
||||
|
||||
if (param != undefined) {
|
||||
rema = decodeURI(param)
|
||||
el('.alias').value = decodeURI(param);
|
||||
}
|
||||
getFlag(rema, part2[0], sid); //get flag iso code
|
||||
s.innerHTML = "<font color='green'><%:Import%>Shadowsocks<%:Configuration Succeeded%></font>";
|
||||
return false;
|
||||
} else if (ssu[0] == "trojan") {
|
||||
var ploc = ssu[1].indexOf("#");
|
||||
if (ploc > 0) {
|
||||
url0 = ssu[1].substr(0, ploc);
|
||||
param = ssu[1].substr(ploc + 1);
|
||||
} else {
|
||||
url0 = ssu[1]
|
||||
}
|
||||
var sstr = b64decsafe(url0);
|
||||
el('.type').value = "trojan";
|
||||
el('.type').dispatchEvent(event);
|
||||
var team = sstr.split('@');
|
||||
console.log(team);
|
||||
var part1 = team[0].split(':');
|
||||
var part2 = team[1].split(':');
|
||||
var others = part2[1].split('?');
|
||||
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] || '');
|
||||
}
|
||||
}
|
||||
el('.server').value = part2[0];
|
||||
el('.server_port').value = others[0];
|
||||
el('.password').value = part1[1];
|
||||
if(queryParam.peer || queryParam.sni){
|
||||
el('.tls').checked = true;
|
||||
el('.peer').value = queryParam.peer || queryParam.sni;
|
||||
}
|
||||
|
||||
if (param != undefined) {
|
||||
rema = decodeURI(param)
|
||||
el('.alias').value = decodeURI(param);
|
||||
}
|
||||
getFlag(rema, part2[0], sid); //get flag iso code
|
||||
|
||||
s.innerHTML = "<font color='green'>导入Trojan<%:Configuration Succeeded%></font>";
|
||||
return false;
|
||||
} else if (ssu[0] == "vmess") {
|
||||
var sstr = b64DecodeUnicode(ssu[1]);
|
||||
var ploc = sstr.indexOf("/?");
|
||||
el('.type').value = "v2ray";
|
||||
el('.type').dispatchEvent(event);
|
||||
var url0, param = "";
|
||||
if (ploc > 0) {
|
||||
url0 = sstr.substr(0, ploc);
|
||||
param = sstr.substr(ploc + 2);
|
||||
}
|
||||
var ssm = JSON.parse(sstr);
|
||||
el('.alias').value = ssm.ps;
|
||||
el('.server').value = ssm.add;
|
||||
el('.server_port').value = ssm.port;
|
||||
el('.alter_id').value = ssm.aid;
|
||||
el('.vmess_id').value = ssm.id;
|
||||
el('.transport').value = ssm.net;
|
||||
el('.transport').dispatchEvent(event);
|
||||
if (ssm.net == "tcp") {
|
||||
try {
|
||||
el('.http_host').value = ssm.host;
|
||||
el('.http_path').value = ssm.path;
|
||||
} catch (err) { }
|
||||
|
||||
}
|
||||
if (ssm.net == "ws") {
|
||||
try {
|
||||
el('.ws_host').value = ssm.host;
|
||||
el('.ws_path').value = ssm.path;
|
||||
} catch (err) { }
|
||||
}
|
||||
if (ssm.net == "h2") {
|
||||
try {
|
||||
el('.h2_host').value = ssm.host;
|
||||
el('.h2_path').value = ssm.path;
|
||||
} catch (err) { }
|
||||
}
|
||||
if (ssm.net == "quic") {
|
||||
try {
|
||||
el('.quic_security').value = ssm.securty;
|
||||
el('.quic_key').value = ssm.key;
|
||||
} catch (err) { }
|
||||
}
|
||||
if (ssm.net == "kcp") {
|
||||
try {
|
||||
el('.kcp_guise').value = ssm.type;
|
||||
} catch (err) { }
|
||||
}
|
||||
if (ssm.tls == "tls") {
|
||||
try {
|
||||
el('.tls').checked = true;
|
||||
el('.tls').dispatchEvent(event);
|
||||
el('.tls_host').value = ssm.host;
|
||||
} catch (err) { }
|
||||
}
|
||||
el('.mux').checked = true;
|
||||
el('.mux').dispatchEvent(event);
|
||||
|
||||
getFlag(ssm.ps, ssm.add, sid); //get flag iso code
|
||||
|
||||
s.innerHTML = "<font color='green'><%:Import%>V2ray<%:Configuration Succeeded%></font>";
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//]]></script>
|
||||
|
||||
<input type="button" class="cbi-button cbi-button-apply" value="<%:Import Configuration%>"
|
||||
onclick="return import_ssr_url(this, '<%=self.option%>', '<%=self.value%>')" />
|
||||
<span id="<%=self.option%>-status"></span>
|
||||
|
||||
<%+cbi/valuefooter%>
|
@ -0,0 +1,67 @@
|
||||
<div class="status-bar">
|
||||
<div class="inner">
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-1-2">
|
||||
<span class="flag"><img src="/luci-static/vssr/flags/4x3/un.svg" class="pure-img"></span> <span
|
||||
class="status-info">获取中...</span>
|
||||
</div>
|
||||
<div class="pure-u-1-2">
|
||||
<div class="icon-con">
|
||||
<img src="/luci-static/vssr/img/site_icon1_01.png" class="pure-img i1">
|
||||
<img src="/luci-static/vssr/img/site_icon1_02.png" class="pure-img i2">
|
||||
<img src="/luci-static/vssr/img/site_icon1_03.png" class="pure-img i3">
|
||||
<img src="/luci-static/vssr/img/site_icon1_04.png" class="pure-img i4">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
const CHECK_IP_URL = '<%=url([[admin]], [[services]], [[vssr]], [[ip]])%>';
|
||||
var wW = $(window).width();
|
||||
|
||||
function resize() {
|
||||
wW = $(window).width();
|
||||
lw = $(".main-left").width()
|
||||
$(".status-bar").width(wW - lw);
|
||||
$(".status-bar .flag").width($(".status-bar .flag").height() / 3 * 4);
|
||||
|
||||
$(".flag-icon").each(function (index, el) {
|
||||
if ($(el).height < 60) {
|
||||
$(el).parent.height(60);
|
||||
$(el).width(60)
|
||||
} else {
|
||||
$(el).width($(el).height());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function wirte_status(data) {
|
||||
if (data.outboard) {
|
||||
json = data.outboardip;
|
||||
country = (json.flag == "tw") ? "中国 台湾" : json.country;
|
||||
$(".flag img").attr("src", VSSR_ASSETS + "flags/4x3/" + json.flag + ".svg");
|
||||
$(".status-info").html(data.outboard + "<br>" + country);
|
||||
}
|
||||
data.baidu ? $(".i1").attr("src", VSSR_ASSETS + "img/site_icon_01.png") : $(".i1").attr("src", VSSR_ASSETS + "img/site_icon1_01.png");
|
||||
data.taobao ? $(".i2").attr("src", VSSR_ASSETS + "img/site_icon_02.png") : $(".i2").attr("src", VSSR_ASSETS + "img/site_icon1_02.png");
|
||||
data.google ? $(".i3").attr("src", VSSR_ASSETS + "img/site_icon_03.png") : $(".i3").attr("src", VSSR_ASSETS + "img/site_icon1_03.png");
|
||||
data.youtube ? $(".i4").attr("src", VSSR_ASSETS + "img/site_icon_04.png") : $(".i4").attr("src", VSSR_ASSETS + "img/site_icon1_04.png");
|
||||
}
|
||||
XHR.poll(5, CHECK_IP_URL, null,
|
||||
function (x, data) {
|
||||
wirte_status(data);
|
||||
}
|
||||
);
|
||||
|
||||
$(document).ready(function () {
|
||||
resize();
|
||||
$.getJSON(CHECK_IP_URL, wirte_status);
|
||||
});
|
||||
|
||||
$(window).resize(resize);
|
||||
|
||||
</script>
|
91
package/ctcgfw/luci-app-vssr/luasrc/view/vssr/status_top.htm
Normal file
@ -0,0 +1,91 @@
|
||||
<link rel="stylesheet" href="/luci-static/vssr/css/vssr.css?v=202000427-1">
|
||||
<script src="<%=media%>/js/jquery.min.js"></script>
|
||||
|
||||
<div class="pure-g status">
|
||||
<div class="pure-u-1-4">
|
||||
<div class="block pure-g">
|
||||
<div class="pure-u-3-5">
|
||||
<h4 id="vssr_status"><%:Client%><br /><span class="red"><%:Not Running%></span></h4>
|
||||
</div>
|
||||
<div class="pure-u-2-5">
|
||||
<div class="img-con">
|
||||
<img src="/luci-static/vssr/img/client.svg">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1-4">
|
||||
<div class="block pure-g">
|
||||
<div class="pure-u-3-5">
|
||||
<h4 id="game_status"><%:Game Mode%><br /><span class="red"><%:Not Running%></span></h4>
|
||||
</div>
|
||||
<div class="pure-u-2-5">
|
||||
<div class="img-con">
|
||||
<img src="/luci-static/vssr/img/udp.svg">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1-4">
|
||||
<div class="block pure-g">
|
||||
<div class="pure-u-3-5">
|
||||
<h4 id="pdnsd_status">PDNSD<br /><span class="red"><%:Not Running%></span></h4>
|
||||
</div>
|
||||
<div class="pure-u-2-5">
|
||||
<div class="img-con">
|
||||
<img src="/luci-static/vssr/img/pdnsd.svg">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1-4">
|
||||
<div class="block pure-g">
|
||||
<div class="pure-u-3-5">
|
||||
<h4 id="socks5_status">SOCKS5<br /><span class="red"><%:Not Running%></span></h4>
|
||||
</div>
|
||||
<div class="pure-u-2-5">
|
||||
<div class="img-con">
|
||||
<img src="/luci-static/vssr/img/socks5.svg">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const VSSR_ASSETS = '/luci-static/vssr/';
|
||||
const STATUS1_URL = '<%=url([[admin]], [[services]], [[vssr]], [[run]])%>';
|
||||
const CLIENT = '<%:Client%>';
|
||||
const GAME_MODE = '<%:Game Mode%>';
|
||||
const RUNNING = '<%:Running%>';
|
||||
const NOT_RUNNING = '<%:Not Running%>';
|
||||
|
||||
XHR.poll(5, STATUS1_URL, null,
|
||||
function (x, data) {
|
||||
if (data) {
|
||||
if (data.global) {
|
||||
$("#vssr_status").html(CLIENT + '<br><span class="green">' + RUNNING + '</span>');
|
||||
} else {
|
||||
$("#vssr_status").html(CLIENT + '<br><span class="red">' + NOT_RUNNING + '</span>');
|
||||
}
|
||||
if (data.game) {
|
||||
$("#game_status").html(GAME_MODE + '<br><span class="green">' + RUNNING + '</span>');
|
||||
} else {
|
||||
$("#game_status").html(GAME_MODE + '<br><span class="red">' + NOT_RUNNING + '</span>');
|
||||
}
|
||||
if (data.pdnsd) {
|
||||
$("#pdnsd_status").html('PDNSD<br><span class="green">' + RUNNING + '</span>');
|
||||
} else {
|
||||
$("#pdnsd_status").html('PDNSD<br><span class="red">' + NOT_RUNNING + '</span>');
|
||||
}
|
||||
if (data.socks5) {
|
||||
$("#socks5_status").html('SOCKS5<br><span class="green">' + RUNNING + '</span>');
|
||||
} else {
|
||||
$("#socks5_status").html('SOCKS5<br><span class="red">' + NOT_RUNNING + '</span>');
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
//]]>
|
||||
</script>
|
216
package/ctcgfw/luci-app-vssr/luasrc/view/vssr/tblsection.htm
Normal file
@ -0,0 +1,216 @@
|
||||
<script type="text/javascript" src="/luci-static/vssr/emoji.js"></script>
|
||||
<fieldset class="cbi-section" id="cbi-apply-vssr1" style="display: none;">
|
||||
<span class="panel-title">正在切换节点</span>
|
||||
<img src="/luci-static/resources/icons/loading.gif" alt="载入中" style="vertical-align:middle">
|
||||
</fieldset>
|
||||
<!-- tblsection -->
|
||||
<fieldset class="cbi-section" id="cbi-<%=self.config%>-<%=self.sectiontype%>">
|
||||
<button class="cbi-button cbi-button-check "><%:Ping All Servers%></button><span class="panel-title">总计
|
||||
<%- print(self.des)-%>个节点</span>
|
||||
<div class="cbi-section-node">
|
||||
<%- local count = 0 -%>
|
||||
<div class="cbi-section-table pure-g p-in5">
|
||||
|
||||
<%- local isempty = true
|
||||
for i, k in ipairs(self:cfgsections()) do
|
||||
section = k
|
||||
isempty = false
|
||||
scope = { valueheader = "cbi/cell_valueheader", valuefooter = "cbi/cell_valuefooter" }
|
||||
-%>
|
||||
|
||||
<div class="pure-u-1-5">
|
||||
<div class="cbi-section-table-row " id="cbi-<%=self.config%>-<%=section%>">
|
||||
<div class="loadings hide"></div>
|
||||
<div class="incon type flag-icon <%=self.flag%>" data-setction="<%=section%>">
|
||||
<img class="pure-imgw hidden" src="/luci-static/vssr/img/switch.png">
|
||||
<div class="tp"></div>
|
||||
</div>
|
||||
<div class="incon alias"></div>
|
||||
<%- if self.extedit or self.addremove then -%>
|
||||
<div class="cbi-section-table-cell">
|
||||
<div class="host_con"></div>
|
||||
<a class="cbi-button ssr-button" type="button" value="" onclick="apply_node('<%=section%>')"
|
||||
alt="<%:Apply%>" title="<%:Apply%>"><span class="icon-ok"></span> <%:Apply%></a>
|
||||
<%- if self.extedit then -%>
|
||||
<a class="cbi-button ssr-button " type="button" value="" <%- if type(self.extedit) == "string" then
|
||||
%> onclick="location.href='<%=self.extedit:format(section)%>'" <%- elseif type(self.extedit) == "function" then
|
||||
%> onclick="location.href='<%=self:extedit(section)%>'" <%- end
|
||||
%> alt="<%:Edit%>" title="<%:Edit%>"><span class="icon-edit"></span> <%:Edit%></a>
|
||||
<%- end; if self.addremove then %>
|
||||
<button class="cbi-button ssr-button" type="submit" value=""
|
||||
onclick="this.form.cbi_state = 'del-section'; return true"
|
||||
name="cbi.rts.<%=self.config%>.<%=k%>" alt="<%:Delete%>" title="<%:Delete%>" /><span
|
||||
class="icon-delete"></span> <%:Delete%></button>
|
||||
<%- end -%>
|
||||
</div>
|
||||
<%- end -%>
|
||||
</div>
|
||||
</div>
|
||||
<%- end -%>
|
||||
|
||||
<%- if isempty then -%>
|
||||
<div class="cbi-section-table-row">
|
||||
<div colspan="<%=count%>"><em><br /><%:This section contains no values yet%></em></div>
|
||||
</div>
|
||||
<%- end -%>
|
||||
</div>
|
||||
|
||||
<% if self.error then %>
|
||||
<div class="cbi-section-error">
|
||||
<ul><% for _, c in pairs(self.error) do for _, e in ipairs(c) do -%>
|
||||
<li><%=pcdata(e):gsub("\n","<br />")%></li>
|
||||
<%- end end %></ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%- if self.addremove then -%>
|
||||
<% if self.template_addremove then include(self.template_addremove) else -%>
|
||||
<div class="cbi-section-create cbi-tblsection-create">
|
||||
<% if self.anonymous then %>
|
||||
<input class="cbi-button cbi-button-add" type="submit" value="<%:Add%>"
|
||||
name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" title="<%:Add%>" />
|
||||
<% else %>
|
||||
<% if self.invalid_cts then -%><div class="cbi-section-error"><% end %>
|
||||
<input type="text" class="cbi-section-create-name"
|
||||
id="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>"
|
||||
name="cbi.cts.<%=self.config%>.<%=self.sectiontype%>.<%=section%>" data-type="uciname"
|
||||
data-optional="true" />
|
||||
<input class="cbi-button cbi-button-add" type="submit"
|
||||
onclick="this.form.cbi_state = 'add-section'; return true" value="<%:Add%>" title="<%:Add%>" />
|
||||
<% if self.invalid_cts then -%>
|
||||
<br /><%:Invalid%></div>
|
||||
<%- end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<%- end %>
|
||||
<%- end -%>
|
||||
</div>
|
||||
</fieldset>
|
||||
<!-- /tblsection -->
|
||||
<script type="text/javascript">
|
||||
const CONFIG = '<%=self.config%>';
|
||||
const CURRENT = '<%=self.current%>';
|
||||
const CHANGE_NODE_URL = '<%=luci.dispatcher.build_url("admin", "services", "vssr","change")%>';
|
||||
const CHECK_PING_URL = '<%=luci.dispatcher.build_url("admin", "services", "vssr","checkport")%>';
|
||||
const SWITCH_NODE_URL = '<%=luci.dispatcher.build_url("admin", "services", "vssr","switch")%>';
|
||||
|
||||
var servers = JSON.parse('<%= self.servers%>'.replace(/\t/g, ""));
|
||||
var ajaxArray = new Array();
|
||||
|
||||
//渲染节点列表
|
||||
$.each(servers, function (i, val) {
|
||||
var id = '#cbi-' + CONFIG + '-' + val.name;
|
||||
if (val.name == CURRENT) {
|
||||
$(id).addClass("fast");
|
||||
}
|
||||
val.flag = (val.flag == undefined) ? "un" : val.flag;
|
||||
$(id).find(".type .tp").text(val.type);
|
||||
$(id).find(".type").addClass("flag-icon-" + val.flag);
|
||||
$(id).find(".alias").text(val.alias);
|
||||
$(id).attr("server", val.server);
|
||||
$(id).attr("server_port", val.server_port);
|
||||
if (val.switch_enable == "1") {
|
||||
$(id).find(".pure-imgw").removeClass("hidden");
|
||||
} else {
|
||||
$(id).find(".pure-imgw").addClass("hidden");
|
||||
}
|
||||
});
|
||||
|
||||
//转换节点名称的Emoji显示
|
||||
$(".alias").emoji();
|
||||
//适配方框的大小
|
||||
$(".flag-icon").each(function (index, el) {
|
||||
if ($(el).height < 60) {
|
||||
$(el).parent.height(60);
|
||||
$(el).width(60)
|
||||
} else {
|
||||
$(el).width($(el).height());
|
||||
}
|
||||
});
|
||||
//切换节点
|
||||
function apply_node(node) {
|
||||
$("#cbi-apply-vssr1").show(); //显示应用中
|
||||
$.each(ajaxArray, function (n, value) { value.abort(); }) //中断所有的ajax请求
|
||||
$.get(CHANGE_NODE_URL, { set: node },
|
||||
function (data, status) {
|
||||
$("#cbi-apply-vssr1").hide(); //隐藏应用中
|
||||
if (data.status) {
|
||||
var id = '#cbi-<%=self.config%>-' + node;
|
||||
$(".cbi-section-table-row").removeClass("fast");
|
||||
$(id).addClass("fast");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//设定自动切换台
|
||||
$(".incon").click(function () {
|
||||
$.each(ajaxArray, function (n, value) { value.abort(); }) //中断所有的ajax请求
|
||||
$node_switch_icon = $(this).find(".pure-imgw");
|
||||
$node_target = $(this).attr("data-setction");
|
||||
$.post(SWITCH_NODE_URL, { node: $node_target }, function (data) {
|
||||
if(data.status){
|
||||
if(data.switch){
|
||||
$node_switch_icon.removeClass("hidden");
|
||||
}else{
|
||||
$node_switch_icon.addClass("hidden");
|
||||
}
|
||||
}else{
|
||||
alert("请求出错!")
|
||||
}
|
||||
}, "json");
|
||||
})
|
||||
|
||||
//检测所有节点延迟
|
||||
function check() {
|
||||
$(".host_con").html("");
|
||||
ajaxArray = [];
|
||||
$(".pure-u-1-5").each(function () {
|
||||
host = $(this).find(".cbi-section-table-row ").attr("server");
|
||||
port = $(this).find(".cbi-section-table-row ").attr("server_port");
|
||||
$(".host_con").text("");
|
||||
check_port(host, port, this);
|
||||
});
|
||||
}
|
||||
|
||||
//检测单个节点延迟
|
||||
function check_port(hosts, ports, target) {
|
||||
$.ajaxSettings.async = true;
|
||||
var axhr = $.get(CHECK_PING_URL, { host: hosts, port: ports },
|
||||
function (data, status) {
|
||||
var host_con = $(target).find(".host_con");
|
||||
host_con.removeClass("fast");
|
||||
host_con.removeClass("middle");
|
||||
host_con.removeClass("slow");
|
||||
host_con.removeClass("nopass");
|
||||
if (data.ret == 1) {
|
||||
if (data.used == "") {
|
||||
host_con.addClass("nopass");
|
||||
host_con.text("Error");
|
||||
} else if (data.used <= 80) {
|
||||
host_con.addClass("fast");
|
||||
host_con.text(data.used + "ms");
|
||||
} else if (data.used > 80 && data.used <= 200) {
|
||||
host_con.addClass("middle");
|
||||
host_con.text(data.used + "ms");
|
||||
} else if (data.used > 200) {
|
||||
host_con.addClass("slow");
|
||||
host_con.text(data.used + "ms");
|
||||
}
|
||||
} else {
|
||||
host_con.addClass("nopass");
|
||||
host_con.text("Error");
|
||||
}
|
||||
});
|
||||
ajaxArray.push(axhr);
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
setTimeout(function () { check(); }, 500); //延迟500MS开始检测
|
||||
$(".cbi-page-actions").hide(); //隐藏底部保存提交按钮
|
||||
$(".cbi-button-check").click(function () {
|
||||
check();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
@ -0,0 +1,108 @@
|
||||
<%+cbi/valueheader%>
|
||||
<link rel="stylesheet" href="/luci-static/vssr/css/vssr.css?v=72883">
|
||||
<label class="cbi-value-title"><%= translate("Update") %></label>
|
||||
<div class="cbi-value-field">
|
||||
<input class="cbi-button cbi-button-reload" id="update_subscribe" type="button"
|
||||
size="0" value="<%= translate("Save And Start Subscribe") %>">
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
const SAVE_SUBSCRIBE_URL = '<%=luci.dispatcher.build_url("admin", "services", "vssr","subscribe")%>';
|
||||
const SERVERS_URL = '<%=luci.dispatcher.build_url("admin", "services", "vssr","servers")%>';
|
||||
|
||||
var _responseLen;
|
||||
var noChange = 0;
|
||||
var modal = '<div class="modals-bg">' +
|
||||
'<div class="modals">' +
|
||||
'<h2><%:Subscription%></h2>' +
|
||||
'<h3 style="margin-left:0;"><%:Subscribing,Please do not refresh!%></h3>' +
|
||||
'<textarea cols="63" rows="28" wrap="on" readonly="readonly" id="log_content3" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"></textarea>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
//显示并开始刷新订阅
|
||||
function update_subscribe() {
|
||||
$("body").append(modal);
|
||||
$(".modals-bg").show();
|
||||
setTimeout("get_realtime_log();", 500);
|
||||
}
|
||||
//保存订阅按钮
|
||||
$("#update_subscribe").click(function () {
|
||||
prefix_array = $("#cbi-vssr-server_subscribe .cbi-section-node").attr("id").split("-");
|
||||
prefix_array[0] = "cbid";
|
||||
prefix = prefix_array.join(".");
|
||||
if ($("[name='" + prefix + ".auto_update']").is(":checked")) {
|
||||
var auto_update = "1";
|
||||
} else {
|
||||
var auto_update = "0";
|
||||
}
|
||||
var auto_update_time = $("[name='" + prefix + ".auto_update_time']").val();
|
||||
var subscribe_url = [];
|
||||
$("[name='" + prefix + ".subscribe_url']").each(function () {
|
||||
if ($(this).val() != "") {
|
||||
subscribe_url.push($(this).val());
|
||||
}
|
||||
});
|
||||
if ($("[name='" + prefix + ".proxy']").is(":checked")) {
|
||||
var proxy = "1";
|
||||
} else {
|
||||
var proxy = "0";
|
||||
}
|
||||
|
||||
var data = {
|
||||
auto_update: auto_update,
|
||||
auto_update_time: auto_update_time,
|
||||
subscribe_url: JSON.stringify(subscribe_url),
|
||||
proxy: proxy
|
||||
}
|
||||
//console.log(data);
|
||||
$.ajax({
|
||||
type: "post",
|
||||
url: SAVE_SUBSCRIBE_URL,
|
||||
dataType: "json",
|
||||
data: data,
|
||||
success: function (d) {
|
||||
if (d.error == 0) {
|
||||
update_subscribe();
|
||||
} else {
|
||||
alert("请至少填写一个订阅链接");
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
function get_realtime_log() {
|
||||
$.ajax({
|
||||
url: '/check_update.htm?v=' + parseInt(Math.random() * 100000000),
|
||||
dataType: 'html',
|
||||
error: function (xhr) {
|
||||
setTimeout("get_realtime_log();", 1000);
|
||||
},
|
||||
success: function (response) {
|
||||
var retArea = document.getElementById("log_content3");
|
||||
if (response.search("END SUBSCRIBE") != -1) {
|
||||
noChange++;
|
||||
}
|
||||
console.log(noChange);
|
||||
if (noChange > 10) {
|
||||
window.location.href = SERVERS_URL;
|
||||
return false;
|
||||
} else {
|
||||
setTimeout("get_realtime_log();", 250);
|
||||
}
|
||||
retArea.value = response;
|
||||
retArea.scrollTop = retArea.scrollHeight;
|
||||
_responseLen = response.length;
|
||||
},
|
||||
error: function () {
|
||||
setTimeout("get_realtime_log();", 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<%+cbi/valuefooter%>
|
649
package/ctcgfw/luci-app-vssr/po/zh_Hans/vssr.po
Normal file
@ -0,0 +1,649 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
msgid "vssr"
|
||||
msgstr "Hello World"
|
||||
|
||||
msgid "Client"
|
||||
msgstr "客户端"
|
||||
|
||||
msgid "Enable"
|
||||
msgstr "启用"
|
||||
|
||||
msgid "Disable"
|
||||
msgstr "停用"
|
||||
|
||||
msgid "Log"
|
||||
msgstr "日志"
|
||||
|
||||
msgid "Running"
|
||||
msgstr "运行中"
|
||||
|
||||
msgid "Not Running"
|
||||
msgstr "未运行"
|
||||
|
||||
msgid "Game Mode"
|
||||
msgstr "游戏模式"
|
||||
|
||||
msgid "Global Setting"
|
||||
msgstr "全局设置"
|
||||
|
||||
msgid "Global Server"
|
||||
msgstr "全局服务器"
|
||||
|
||||
msgid "vssr SOCK5 Proxy is running"
|
||||
msgstr "vssr SOCK5代理运行中"
|
||||
|
||||
msgid "UDP Relay Server"
|
||||
msgstr "UDP中继服务器"
|
||||
|
||||
msgid "Same as Global Server"
|
||||
msgstr "与全局服务器相同"
|
||||
|
||||
msgid "Servers Setting"
|
||||
msgstr "服务器配置"
|
||||
|
||||
msgid "Alias(optional)"
|
||||
msgstr "别名(可选)"
|
||||
|
||||
msgid "Onetime Authentication"
|
||||
msgstr "一次验证"
|
||||
|
||||
msgid "Server Address"
|
||||
msgstr "服务器地址"
|
||||
|
||||
msgid "Server Port"
|
||||
msgstr "服务器端口"
|
||||
|
||||
msgid "Local Port"
|
||||
msgstr "本地端口"
|
||||
|
||||
msgid "Connection Timeout"
|
||||
msgstr "连接超时"
|
||||
|
||||
msgid "Password"
|
||||
msgstr "密码"
|
||||
|
||||
msgid "Encrypt Method"
|
||||
msgstr "加密方式"
|
||||
|
||||
msgid "Protocol"
|
||||
msgstr "传输协议"
|
||||
|
||||
msgid "Protocol param(optional)"
|
||||
msgstr "传输协议参数(可选)"
|
||||
|
||||
msgid "Obfs"
|
||||
msgstr "混淆插件"
|
||||
|
||||
msgid "Obfs param(optional)"
|
||||
msgstr "混淆参数(可选)"
|
||||
|
||||
msgid "Enable Tunnel(DNS)"
|
||||
msgstr "启用隧道(DNS)转发"
|
||||
|
||||
msgid "Tunnel Port"
|
||||
msgstr "隧道(DNS)本地端口"
|
||||
|
||||
msgid "Forwarding Tunnel"
|
||||
msgstr "隧道(DNS)转发地址"
|
||||
|
||||
msgid "Access Control"
|
||||
msgstr "访问控制"
|
||||
|
||||
msgid "Interfaces - WAN"
|
||||
msgstr "接口 - WAN"
|
||||
|
||||
msgid "Bypassed IP List"
|
||||
msgstr "被忽略IP列表"
|
||||
|
||||
msgid "NULL - As Global Proxy"
|
||||
msgstr "留空 - 作为全局代理"
|
||||
|
||||
msgid "Bypassed IP"
|
||||
msgstr "额外被忽略IP"
|
||||
|
||||
msgid "Forwarded IP"
|
||||
msgstr "强制走代理IP"
|
||||
|
||||
msgid "Interfaces - LAN"
|
||||
msgstr "接口 - LAN"
|
||||
|
||||
msgid "LAN Access Control"
|
||||
msgstr "内网访问控制"
|
||||
|
||||
msgid "Allow listed only"
|
||||
msgstr "仅允许列表内"
|
||||
|
||||
msgid "Allow all except listed"
|
||||
msgstr "仅允许列表外"
|
||||
|
||||
msgid "LAN Host List"
|
||||
msgstr "内网主机列表"
|
||||
|
||||
msgid "SSR Client"
|
||||
msgstr "基本设置"
|
||||
|
||||
msgid "SSR Server"
|
||||
msgstr "服务端"
|
||||
|
||||
msgid "vssr Server"
|
||||
msgstr "vssr 服务端"
|
||||
|
||||
msgid "vssr Server is running"
|
||||
msgstr "vssr 服务端运行中"
|
||||
|
||||
msgid "vssr Server is not running"
|
||||
msgstr "vssr 服务端未运行"
|
||||
|
||||
msgid "Enable Server"
|
||||
msgstr "启动服务端"
|
||||
|
||||
msgid "Server Setting"
|
||||
msgstr "服务端配置"
|
||||
|
||||
msgid "KcpTun Enable"
|
||||
msgstr "KcpTun 启用"
|
||||
|
||||
msgid "bin:/usr/bin/kcptun-client"
|
||||
msgstr "二进制文件:/usr/bin/kcptun-client"
|
||||
|
||||
msgid "KcpTun Port"
|
||||
msgstr "KcpTun 端口"
|
||||
|
||||
msgid "KcpTun Param"
|
||||
msgstr "KcpTun 参数"
|
||||
|
||||
msgid "KcpTun Password"
|
||||
msgstr "KcpTun 密码"
|
||||
|
||||
msgid "Haven't a Kcptun executable file"
|
||||
msgstr "不存在Kcptun可执行文件,请下载Kcptun可执行文件并改名放入/usr/bin/kcptun-client"
|
||||
|
||||
msgid "Not a Kcptun executable file"
|
||||
msgstr "Kcptun可执行文件格式不正确,请确认是否正确下载了路由器对应的可执行文件"
|
||||
|
||||
msgid "Enable Process Monitor"
|
||||
msgstr "启用进程监控"
|
||||
|
||||
msgid "Edit vssr Server"
|
||||
msgstr "编辑服务器配置"
|
||||
|
||||
msgid "Alias"
|
||||
msgstr "别名"
|
||||
|
||||
msgid "V2ray SOCKS5 Proxy"
|
||||
msgstr "V2ray SOCKS5代理"
|
||||
|
||||
msgid "Server"
|
||||
msgstr "服务器"
|
||||
|
||||
msgid "TCP Fast Open"
|
||||
msgstr "TCP快速打开"
|
||||
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "未知"
|
||||
|
||||
msgid "Running Status"
|
||||
msgstr "运行状态"
|
||||
|
||||
msgid "Global Client"
|
||||
msgstr "TCP透明代理"
|
||||
|
||||
msgid "Global SSR Server"
|
||||
msgstr "SSR服务端"
|
||||
|
||||
msgid "DNS Tunnel"
|
||||
msgstr "DNS 隧道"
|
||||
|
||||
msgid "IPK Version"
|
||||
msgstr "IPK 版本号"
|
||||
|
||||
msgid "KcpTun Version"
|
||||
msgstr "KcpTun 版本号"
|
||||
|
||||
msgid "Not exist"
|
||||
msgstr "未安装可执行文件"
|
||||
|
||||
msgid "IPK Installation Time"
|
||||
msgstr "IPK 安装时间"
|
||||
|
||||
msgid "Project"
|
||||
msgstr "项目地址"
|
||||
|
||||
msgid "Not Running"
|
||||
msgstr "未运行"
|
||||
|
||||
msgid "Running"
|
||||
msgstr "运行中"
|
||||
|
||||
msgid "Enable GFW mode"
|
||||
msgstr "启用 GFW 模式"
|
||||
|
||||
msgid "Running Mode"
|
||||
msgstr "运行模式"
|
||||
|
||||
msgid "IP Route Mode"
|
||||
msgstr "绕过中国大陆IP模式"
|
||||
|
||||
msgid "GFW List Mode"
|
||||
msgstr "GFW列表模式"
|
||||
|
||||
msgid "Global Mode"
|
||||
msgstr "全局模式"
|
||||
|
||||
msgid "Oversea Mode"
|
||||
msgstr "海外用户回国模式"
|
||||
|
||||
msgid "Router Proxy"
|
||||
msgstr "路由器访问控制"
|
||||
|
||||
msgid "Normal Proxy"
|
||||
msgstr "正常代理"
|
||||
|
||||
msgid "Bypassed Proxy"
|
||||
msgstr "不走代理"
|
||||
|
||||
msgid "Forwarded Proxy"
|
||||
msgstr "强制走代理"
|
||||
|
||||
msgid "UDP Relay"
|
||||
msgstr "UDP中继"
|
||||
|
||||
msgid "Google Connectivity"
|
||||
msgstr "【谷歌】连通性检查"
|
||||
|
||||
msgid "Baidu Connectivity"
|
||||
msgstr "【百度】连通性检查"
|
||||
|
||||
msgid "No Check"
|
||||
msgstr "未检查"
|
||||
|
||||
msgid "Check"
|
||||
msgstr "检查"
|
||||
|
||||
msgid "Connect OK"
|
||||
msgstr "连接正常"
|
||||
|
||||
msgid "Connect Error"
|
||||
msgstr "连接错误"
|
||||
|
||||
msgid "Check..."
|
||||
msgstr "正在检查.."
|
||||
|
||||
msgid "Proxy Check"
|
||||
msgstr "代理检查"
|
||||
|
||||
|
||||
msgid "GFW List Data"
|
||||
msgstr "【GFW列表】数据库"
|
||||
|
||||
msgid "China IP Data"
|
||||
msgstr "【国内IP段】数据库"
|
||||
|
||||
msgid "Records"
|
||||
msgstr "条记录"
|
||||
|
||||
msgid "Refresh Data"
|
||||
msgstr "更新数据库"
|
||||
|
||||
msgid "Refresh..."
|
||||
msgstr "正在更新,请稍候.."
|
||||
|
||||
msgid "Refresh OK!"
|
||||
msgstr "更新成功!"
|
||||
|
||||
msgid "Refresh Error!"
|
||||
msgstr "更新失败!"
|
||||
|
||||
msgid "No new data!"
|
||||
msgstr "你已经是最新数据,无需更新!"
|
||||
|
||||
msgid "Total Records:"
|
||||
msgstr "新的总纪录数:"
|
||||
|
||||
msgid "Check Server Port"
|
||||
msgstr "【服务器端口】检查"
|
||||
|
||||
msgid "Check Connect"
|
||||
msgstr "检查连通性"
|
||||
|
||||
msgid "Check Server"
|
||||
msgstr "检查服务器"
|
||||
|
||||
msgid "Auto Switch"
|
||||
msgstr "自动切换"
|
||||
|
||||
msgid "Enable Auto Switch"
|
||||
msgstr "启用自动切换"
|
||||
|
||||
msgid "Switch check cycly(second)"
|
||||
msgstr "自动切换检查周期(秒)"
|
||||
|
||||
msgid "Check timout(second)"
|
||||
msgstr "切换检查超时时间(秒)"
|
||||
|
||||
msgid "Check Try Count"
|
||||
msgstr "切换检查重试次数"
|
||||
|
||||
msgid "Enable Process Deamon"
|
||||
msgstr "启用进程自动守护"
|
||||
|
||||
msgid "Advertising Data"
|
||||
msgstr "【广告屏蔽】数据库"
|
||||
|
||||
msgid "DNS Server IP and Port"
|
||||
msgstr "DNS服务器地址和端口"
|
||||
|
||||
msgid "Resolve Dns Mode"
|
||||
msgstr "DNS解析方式"
|
||||
|
||||
msgid "Use SSR DNS Tunnel"
|
||||
msgstr "使用SSR-DNS隧道"
|
||||
|
||||
msgid "Use Pdnsd"
|
||||
msgstr "使用Pdnsd"
|
||||
|
||||
msgid "Use Other DNS Tunnel(Need to install)"
|
||||
msgstr "使用其他DNS转发(需要自己安装)"
|
||||
|
||||
msgid "Import SSR"
|
||||
msgstr "导入ssr配置信息"
|
||||
|
||||
msgid "Export SSR"
|
||||
msgstr "导出ssr配置信息"
|
||||
|
||||
msgid "Import SSR successfully."
|
||||
msgstr "成功导入SSR。"
|
||||
|
||||
msgid "Invalid SSR format."
|
||||
msgstr "无效的SSR格式。"
|
||||
|
||||
msgid "User cancelled."
|
||||
msgstr "用户已取消。"
|
||||
|
||||
msgid "Paste ssr url here"
|
||||
msgstr "在此处粘贴ssr://网址"
|
||||
|
||||
msgid "Unable to copy SSR to clipboard."
|
||||
msgstr "无法复制SSR网址到剪贴板。"
|
||||
|
||||
msgid "Copy SSR to clipboard successfully."
|
||||
msgstr "成功复制SSR网址到剪贴板。"
|
||||
|
||||
msgid "Servers Manage"
|
||||
msgstr "服务器管理"
|
||||
|
||||
msgid "Auto Update"
|
||||
msgstr "自动更新"
|
||||
|
||||
msgid "Through proxy update"
|
||||
msgstr "通过代理更新"
|
||||
|
||||
msgid "GFW List"
|
||||
msgstr "GFW列表"
|
||||
|
||||
msgid "Basic Settings [SS(R)|V2ray|Trojan]"
|
||||
msgstr "基本设置 [SS(R)|V2ray|Trojan]"
|
||||
|
||||
msgid "Main Server"
|
||||
msgstr "主服务器"
|
||||
|
||||
msgid "Anti-pollution DNS Server"
|
||||
msgstr "访问国外域名DNS服务器"
|
||||
|
||||
msgid "Use Pdnsd tcp query and cache"
|
||||
msgstr "使用PDNSD TCP查询并缓存"
|
||||
|
||||
msgid "DNS Server IP:Port"
|
||||
msgstr "DNS服务器 IP:Port"
|
||||
|
||||
msgid "Update time (every day)"
|
||||
msgstr "更新时间 (每天)"
|
||||
|
||||
msgid "Auto Update Server subscription, GFW list and CHN route"
|
||||
msgstr "自动更新服务器订阅、GFW列表和 CHN路由表"
|
||||
|
||||
msgid "Subscribe URL"
|
||||
msgstr "SSR/V2RAY订阅URL地址"
|
||||
|
||||
msgid "Update"
|
||||
msgstr "更新"
|
||||
|
||||
msgid "Save And Start Subscribe"
|
||||
msgstr "保存并开始订阅"
|
||||
|
||||
msgid "Server Count"
|
||||
msgstr "节点数量"
|
||||
|
||||
msgid "IP black-and-white list"
|
||||
msgstr "黑白名单"
|
||||
|
||||
msgid "WAN IP AC"
|
||||
msgstr "广域网访问控制"
|
||||
|
||||
msgid "WAN White List IP"
|
||||
msgstr "不走代理的广域网 IP"
|
||||
|
||||
msgid "WAN Force Proxy IP"
|
||||
msgstr "强制走代理的广域网 IP"
|
||||
|
||||
msgid "LAN Bypassed Host List"
|
||||
msgstr "不走代理的局域网LAN IP"
|
||||
|
||||
msgid "LAN Force Proxy Host List"
|
||||
msgstr "全局代理的LAN IP"
|
||||
|
||||
msgid "Router Self AC"
|
||||
msgstr "路由器自身代理设置"
|
||||
|
||||
msgid "Router Self Proxy"
|
||||
msgstr "路由器自身代理方式"
|
||||
|
||||
msgid "Normal Proxy"
|
||||
msgstr "跟随全局设置"
|
||||
|
||||
msgid "Bypassed Proxy"
|
||||
msgstr "不走代理"
|
||||
|
||||
msgid "Forwarded Proxy"
|
||||
msgstr "全局代理"
|
||||
|
||||
msgid "GFW Custom List"
|
||||
msgstr "GFW 用户自定义列表"
|
||||
|
||||
msgid "Please refer to the following writing"
|
||||
msgstr "每行一个域名,无需写前面的 HTTP(S):// ,提交后即时生效"
|
||||
|
||||
msgid "Servers subscription and manage"
|
||||
msgstr "服务器节点订阅管理(支持SSR/V2ray 订阅)"
|
||||
|
||||
msgid "Subscription"
|
||||
msgstr "节点订阅"
|
||||
|
||||
msgid "Through proxy update list, Not Recommended"
|
||||
msgstr "通过路由器自身代理更新订阅(不推荐)"
|
||||
|
||||
msgid "LAN IP AC"
|
||||
msgstr "局域网访问控制"
|
||||
|
||||
msgid "Game Mode UDP Server"
|
||||
msgstr "游戏模式UDP中继服务器"
|
||||
|
||||
msgid "Game Mode UDP Relay"
|
||||
msgstr "游戏模式UDP中继"
|
||||
|
||||
msgid "Server failsafe auto swith settings"
|
||||
msgstr "服务器节点故障自动切换设置"
|
||||
|
||||
msgid "Delete all severs"
|
||||
msgstr "删除所有服务器"
|
||||
|
||||
msgid "Severs Nodes"
|
||||
msgstr "节点列表"
|
||||
|
||||
msgid "Use Local DNS Service listen port 5335"
|
||||
msgstr "使用本机端口为5335的DNS服务"
|
||||
|
||||
msgid "Server Node Type"
|
||||
msgstr "服务器节点类型"
|
||||
|
||||
msgid "Using incorrect encryption mothod may causes service fail to start"
|
||||
msgstr "输入不正确的参数组合可能会导致服务无法启动"
|
||||
|
||||
msgid "Game Mode Host List"
|
||||
msgstr "增强游戏模式客户端LAN IP"
|
||||
|
||||
msgid "Multi Threads Option"
|
||||
msgstr "多线程并发转发"
|
||||
|
||||
msgid "Auto Threads"
|
||||
msgstr "自动(CPU线程数)"
|
||||
|
||||
msgid "1 Thread"
|
||||
msgstr "单线程"
|
||||
|
||||
msgid "2 Threads"
|
||||
msgstr "2 线程"
|
||||
|
||||
msgid "4 Threads"
|
||||
msgstr "4 线程"
|
||||
|
||||
msgid "8 Threads"
|
||||
msgstr "8 线程"
|
||||
|
||||
msgid "Proxy Ports"
|
||||
msgstr "需要代理的端口"
|
||||
|
||||
msgid "All Ports"
|
||||
msgstr "所有端口(默认)"
|
||||
|
||||
msgid "Only Common Ports"
|
||||
msgstr "仅常用端口(不走P2P流量到代理)"
|
||||
|
||||
msgid "Ping Latency"
|
||||
msgstr "Ping延迟"
|
||||
|
||||
msgid "Bypass Domain List"
|
||||
msgstr "直连域名"
|
||||
|
||||
msgid "Black Domain List"
|
||||
msgstr "代理域名"
|
||||
|
||||
msgid "Socks user"
|
||||
msgstr "用户名"
|
||||
|
||||
msgid "Socks pass"
|
||||
msgstr "密码"
|
||||
|
||||
msgid "Enable Servers"
|
||||
msgstr "开启服务"
|
||||
|
||||
msgid "Enable Auth"
|
||||
msgstr "开启验证"
|
||||
|
||||
msgid "Subscribing,Please do not refresh!"
|
||||
msgstr "请勿刷新本页面,正在订阅中 ..."
|
||||
|
||||
msgid "Apply"
|
||||
msgstr "应用"
|
||||
|
||||
msgid "Edit"
|
||||
msgstr "修改"
|
||||
|
||||
msgid "Delete"
|
||||
msgstr "删除"
|
||||
|
||||
msgid "Ping All Servers"
|
||||
msgstr "Ping 所有节点"
|
||||
|
||||
msgid "Check Ip And Access"
|
||||
msgstr "Ip地址检查"
|
||||
|
||||
msgid "Test From Internal"
|
||||
msgstr "从国内测试"
|
||||
|
||||
msgid "Test From Abroad"
|
||||
msgstr "从国外测试"
|
||||
|
||||
msgid "Test From Google"
|
||||
msgstr "从谷歌测试"
|
||||
|
||||
msgid "Baidu"
|
||||
msgstr "百度搜索"
|
||||
|
||||
msgid "Connection OK"
|
||||
msgstr "访问正常"
|
||||
|
||||
msgid "Cannot Access"
|
||||
msgstr "无法访问"
|
||||
|
||||
msgid "Unavailable"
|
||||
msgstr "无法获取"
|
||||
|
||||
msgid "Connection Timeout"
|
||||
msgstr "连接超时"
|
||||
|
||||
msgid "Update Setting"
|
||||
msgstr "更新设置"
|
||||
|
||||
msgid "Paste Node Link Here"
|
||||
msgstr "在这里粘贴配置链接"
|
||||
|
||||
msgid "User Cancel"
|
||||
msgstr "用户取消"
|
||||
|
||||
msgid "Invalid Format"
|
||||
msgstr "无效的格式"
|
||||
|
||||
msgid "Import Configuration"
|
||||
msgstr "导入配置信息"
|
||||
|
||||
msgid "Import"
|
||||
msgstr "导入"
|
||||
|
||||
|
||||
msgid "Configuration Succeeded"
|
||||
msgstr "配置信息成功"
|
||||
|
||||
msgid "Import Configuration"
|
||||
msgstr "导入配置信息"
|
||||
|
||||
msgid "Configuration Url"
|
||||
msgstr "配置链接"
|
||||
|
||||
msgid "Open v2ray split-flow"
|
||||
msgstr "开启V2ray分流"
|
||||
|
||||
msgid "When open v2ray split-flow,your main server must be a v2ray server"
|
||||
msgstr "当使用v2ray分流功能时 主服务器必须为V2ray"
|
||||
|
||||
msgid "Youtube Proxy"
|
||||
msgstr "Youtube 代理"
|
||||
|
||||
msgid "TaiWan Video Proxy"
|
||||
msgstr "台湾视频服务代理"
|
||||
|
||||
msgid "Netflix Proxy"
|
||||
msgstr "Netflix 代理"
|
||||
|
||||
msgid "Diseny+ Proxy"
|
||||
msgstr "Diseny+ 代理"
|
||||
|
||||
msgid "Prime Video Proxy"
|
||||
msgstr "Prime Video 代理"
|
||||
|
||||
msgid "adblock settings"
|
||||
msgstr "广告屏蔽设置"
|
||||
|
||||
msgid "Enable adblock"
|
||||
msgstr "开启广告屏蔽"
|
||||
|
||||
msgid "Licence"
|
||||
msgstr "许可"
|
||||
|
||||
msgid "Area"
|
||||
msgstr "区域"
|
178
package/ctcgfw/luci-app-vssr/relnotes.txt
Normal file
@ -0,0 +1,178 @@
|
||||
########################################################
|
||||
#
|
||||
# RELEASE NOTES
|
||||
#
|
||||
########################################################
|
||||
|
||||
########################################################
|
||||
//
|
||||
// 1.11 2020-07-19
|
||||
// bug修复
|
||||
//
|
||||
########################################################
|
||||
|
||||
|
||||
Updates
|
||||
|
||||
- UPD: 弃用curl 改用 wget 来获取远端ip
|
||||
- UPD: 修复了不能自动更新gfw list的问题
|
||||
|
||||
########################################################
|
||||
//
|
||||
// 1.10 2020-07-14
|
||||
// bug修复
|
||||
//
|
||||
########################################################
|
||||
|
||||
|
||||
Updates
|
||||
|
||||
- UPD: 修复了trojan链接无法导入的问题
|
||||
- UPD: 修改部分中文翻译
|
||||
- UPD: 更新了域名和ip名单
|
||||
|
||||
########################################################
|
||||
//
|
||||
// 1.09 2020-04-27
|
||||
// bug修复
|
||||
//
|
||||
########################################################
|
||||
|
||||
|
||||
Updates
|
||||
|
||||
- UPD: 增加了Trojan 订阅支持
|
||||
- UPD: 底部应用图标替换成透明背景PNG 以适应深色模式
|
||||
- UPD: 增加试验脚本,以便于可以和SSR+同时编译
|
||||
|
||||
|
||||
########################################################
|
||||
//
|
||||
// 1.08 2020-03-09
|
||||
// bug修复
|
||||
//
|
||||
########################################################
|
||||
|
||||
|
||||
Updates
|
||||
|
||||
- UPD: 修改了主服务图标
|
||||
- UPD: 去除创建服务配置时的域名转换ip
|
||||
|
||||
Bug fixes
|
||||
|
||||
- FIX: 修复了Sock5默认开启的问题。
|
||||
|
||||
########################################################
|
||||
//
|
||||
// 1.07 2020-02-20
|
||||
// 小幅度优化
|
||||
//
|
||||
########################################################
|
||||
|
||||
|
||||
Updates
|
||||
|
||||
- UPD: 所有订阅节点默认全部取消自动切换。在节点列表页面,点击国旗手动将节点添加为自动切换节点。优点是可以按照自己的喜好设定2-3个自动切换节点,这样自动切换不会乱跳。
|
||||
- UPD: 优化了一些页面跳转的逻辑。
|
||||
- UPD: 再次优化了部分获取国旗部分的代码,现在可以识别部分节点名称中的国家名。
|
||||
|
||||
Bug fixes
|
||||
|
||||
- FIX: 修复了V2ray分流中的Netflix不能分流的问题。
|
||||
|
||||
########################################################
|
||||
//
|
||||
// 1.06 2020-02-17
|
||||
// 这是还是一个中期代码精简优化的版本,无新功能,如果当前使用无bug不建议更新。
|
||||
//
|
||||
########################################################
|
||||
|
||||
|
||||
Updates
|
||||
|
||||
- UPD: 使用lua-maxminddb(18k) 库 取代 pyhton-maxminddb(20k) 同时也不再需要依赖 pyhton-base(1.07Mb) 和python-light(1.61Mb) 大幅度减少固件体积,同时解析速度得到大幅提升。
|
||||
- UPD: 优化了节点列表的一些显示问题。
|
||||
- UPD: 优化了部分获取国旗部分的代码。
|
||||
- UPD: 删除一些不必要的国家的国旗,进一步节省空间。
|
||||
|
||||
Bug fixes
|
||||
|
||||
- FIX: 修复了使用GFW 模式时无法正确获取代理IP的问题
|
||||
|
||||
########################################################
|
||||
//
|
||||
// 1.05 2020-02-11
|
||||
// 这是一个中期代码精简优化的版本,无新功能,如果当前使用无bug不建议更新。
|
||||
//
|
||||
########################################################
|
||||
|
||||
|
||||
Updates
|
||||
|
||||
- UPD: 删除了一些不必要的文件。
|
||||
- UPD: 优化了部分前端模板的命名。
|
||||
- UPD: 优化了大部分的前端界面中的Javascript代码[未来还需要进一步的优化]。
|
||||
|
||||
Bug fixes
|
||||
|
||||
- FIX: 修复了Vmess链接导入时,前端js出错无法获得国家代码的Bug。
|
||||
- FIX: 修复了一些文字翻译的错误。
|
||||
|
||||
########################################################
|
||||
//
|
||||
// 1.05 2020-02-10
|
||||
//
|
||||
########################################################
|
||||
|
||||
New features
|
||||
|
||||
- NEW: 增加了Trojan支持
|
||||
- NEW: 增加了广告屏蔽的功能
|
||||
|
||||
Updates
|
||||
|
||||
- UPD: 更新了gfwlist chinaip 和 ad conf的更新代码。
|
||||
- UPD: 当在节点列表应用新的节点时,会先中断所有的ping,以保证切换节点优先。
|
||||
|
||||
########################################################
|
||||
//
|
||||
// 1.04 2020-02-09
|
||||
//
|
||||
########################################################
|
||||
|
||||
Updates
|
||||
|
||||
- UPD: 增加了V2ray简易分流模式,现在当你在使用v2ray作为主节点的时候,可以选择为几个主流的视频插件指定特定的节点来达到分流的目的。目前可以分流的视频有Youtube 一些台湾的视频平台 Netflix Diseny+ Prime Video
|
||||
- UPD: 更新了GeoIp2 库
|
||||
- UPD: 同步更新lean源的订阅代码
|
||||
- UPD: 增加了一个Licence页面用来显示GEOIP2的授权
|
||||
|
||||
Bug fixes
|
||||
|
||||
- FIX: 修复一些节点列表的显示问题。
|
||||
|
||||
########################################################
|
||||
//
|
||||
// 1.02 2019-12-14
|
||||
//
|
||||
########################################################
|
||||
|
||||
New features
|
||||
|
||||
- NEW: 给Hello World 增加了IP状态显示,在页面底部 左边显示当前节点国旗 ip 和中文国家 右边 是四个网站的访问状态 可以访问是彩色 不能访问是灰色。
|
||||
|
||||
Updates
|
||||
|
||||
- UPD: 基于lean ssr+ 全新修改的Vssr(更名为Hello World) 主要做了很多的修改,同时感谢插件原作者所做出的的努力和贡献!
|
||||
- UPD: 节点列表支持国旗显示 TW节点为五星红旗, 节点列表页面 打开自动ping.
|
||||
- UPD: 优化了在节点列表页面点击应用后节点切换的速度。同时也优化了自动切换的速度。
|
||||
- UPD: 将节点订阅转移至 高级设置 请悉知 由于需要获取ip的国家code 新的订阅速度可能会比原来慢一点点 x86无影响。
|
||||
- UPD: 去掉了ss插件,ss节点将通过v2ray进行代理,支持ss的v2ray plugin,可能会遇到老的加密方式不兼容的情况。
|
||||
- UPD: 优化了国旗匹配方法,在部分带有emoji counrty code的节点名称中 优先使用 emoji code 匹配国旗。
|
||||
|
||||
########################################################==
|
||||
//
|
||||
// END RELEASE NOTES
|
||||
//
|
||||
########################################################==
|
8540
package/ctcgfw/luci-app-vssr/root/etc/china_ssr.txt
Normal file
1
package/ctcgfw/luci-app-vssr/root/etc/config/black.list
Normal file
@ -0,0 +1 @@
|
||||
api.ip.sb
|
53
package/ctcgfw/luci-app-vssr/root/etc/config/gfw.list
Normal file
@ -0,0 +1,53 @@
|
||||
91smartyun.pt
|
||||
adobe.com
|
||||
amazonaws.com
|
||||
ampproject.org
|
||||
apple.news
|
||||
aws.amazon.com
|
||||
azureedge.net
|
||||
backpackers.com.tw
|
||||
bitfinex.com
|
||||
buzzfeed.com
|
||||
clockwise.ee
|
||||
cloudfront.net
|
||||
coindesk.com
|
||||
coinsquare.io
|
||||
cryptocompare.com
|
||||
dropboxstatic.com
|
||||
eurecom.fr
|
||||
gdax.com
|
||||
github.com
|
||||
kknews.cc
|
||||
nutaq.com
|
||||
openairinterface.org
|
||||
skype.com
|
||||
sublimetext.com
|
||||
textnow.com
|
||||
textnow.me
|
||||
trouter.io
|
||||
uploaded.net
|
||||
whatsapp.com
|
||||
whatsapp.net
|
||||
wsj.net
|
||||
google.com
|
||||
google.com.hk
|
||||
gstatic.com
|
||||
googleusercontent.com
|
||||
googlepages.com
|
||||
googlevideo.com
|
||||
googlecode.com
|
||||
googleapis.com
|
||||
googlesource.com
|
||||
googledrive.com
|
||||
ggpht.com
|
||||
youtube.com
|
||||
youtu.be
|
||||
ytimg.com
|
||||
twitter.com
|
||||
facebook.com
|
||||
fastly.net
|
||||
akamai.net
|
||||
akamaiedge.net
|
||||
akamaihd.net
|
||||
edgesuite.net
|
||||
edgekey.net
|
42
package/ctcgfw/luci-app-vssr/root/etc/config/vssr
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
config global
|
||||
option tunnel_forward '8.8.4.4:53'
|
||||
option tunnel_address '0.0.0.0'
|
||||
option run_mode 'router'
|
||||
option pdnsd_enable '1'
|
||||
option monitor_enable '1'
|
||||
option global_server 'nil'
|
||||
option enable_switch '0'
|
||||
option switch_timeout '5'
|
||||
option switch_time '667'
|
||||
option switch_try_count '3'
|
||||
option adblock '0'
|
||||
|
||||
config socks5_proxy
|
||||
option enable_server '0'
|
||||
option local_port '1080'
|
||||
option local_address '0.0.0.0'
|
||||
option enable_auth '1'
|
||||
option Socks_user 'user'
|
||||
option Socks_pass 'password'
|
||||
|
||||
config access_control
|
||||
option wan_bp_list '/etc/china_ssr.txt'
|
||||
option lan_ac_mode 'b'
|
||||
option router_proxy '1'
|
||||
list wan_fw_ips '149.154.160.0/20'
|
||||
list wan_fw_ips '67.198.55.0/24'
|
||||
list wan_fw_ips '91.108.4.0/22'
|
||||
list wan_fw_ips '91.108.56.0/22'
|
||||
list wan_fw_ips '109.239.140.0/24'
|
||||
|
||||
config server_global
|
||||
option enable_server '0'
|
||||
|
||||
config server_subscribe
|
||||
option proxy '0'
|
||||
option auto_update_time '2'
|
||||
option auto_update '1'
|
||||
|
||||
|
||||
|
@ -0,0 +1,192 @@
|
||||
server=/v.youku.com/127.0.0.1#5335
|
||||
server=/api.youku.com/127.0.0.1#5335
|
||||
server=/v2.tudou.com/127.0.0.1#5335
|
||||
server=/www.tudou.com/127.0.0.1#5335
|
||||
server=/s.plcloud.music.qq.com/127.0.0.1#5335
|
||||
server=/i.y.qq.com/127.0.0.1#5335
|
||||
server=/hot.vrs.sohu.com/127.0.0.1#5335
|
||||
server=/live.tv.sohu.com/127.0.0.1#5335
|
||||
server=/pad.tv.sohu.com/127.0.0.1#5335
|
||||
server=/my.tv.sohu.com/127.0.0.1#5335
|
||||
server=/hot.vrs.letv.com/127.0.0.1#5335
|
||||
server=/data.video.qiyi.com/127.0.0.1#5335
|
||||
server=/cache.video.qiyi.com/127.0.0.1#5335
|
||||
server=/cache.vip.qiyi.com/127.0.0.1#5335
|
||||
server=/vv.video.qq.com/127.0.0.1#5335
|
||||
server=/tt.video.qq.com/127.0.0.1#5335
|
||||
server=/ice.video.qq.com/127.0.0.1#5335
|
||||
server=/tjsa.video.qq.com/127.0.0.1#5335
|
||||
server=/a10.video.qq.com/127.0.0.1#5335
|
||||
server=/xyy.video.qq.com/127.0.0.1#5335
|
||||
server=/vcq.video.qq.com/127.0.0.1#5335
|
||||
server=/vsh.video.qq.com/127.0.0.1#5335
|
||||
server=/vbj.video.qq.com/127.0.0.1#5335
|
||||
server=/bobo.video.qq.com/127.0.0.1#5335
|
||||
server=/flvs.video.qq.com/127.0.0.1#5335
|
||||
server=/bkvv.video.qq.com/127.0.0.1#5335
|
||||
server=/info.zb.qq.com/127.0.0.1#5335
|
||||
server=/geo.js.kankan.xunlei.com/127.0.0.1#5335
|
||||
server=/web-play.pptv.com/127.0.0.1#5335
|
||||
server=/web-play.pplive.cn/127.0.0.1#5335
|
||||
server=/dyn.ugc.pps.tv/127.0.0.1#5335
|
||||
server=/v.pps.tv/127.0.0.1#5335
|
||||
server=/inner.kandian.com/127.0.0.1#5335
|
||||
server=/ipservice.163.com/127.0.0.1#5335
|
||||
server=/so.open.163.com/127.0.0.1#5335
|
||||
server=/zb.s.qq.com/127.0.0.1#5335
|
||||
server=/ip.kankan.xunlei.com/127.0.0.1#5335
|
||||
server=/vxml.56.com/127.0.0.1#5335
|
||||
server=/music.sina.com.cn/127.0.0.1#5335
|
||||
server=/play.baidu.com/127.0.0.1#5335
|
||||
server=/v.iask.com/127.0.0.1#5335
|
||||
server=/tv.weibo.com/127.0.0.1#5335
|
||||
server=/wtv.v.iask.com/127.0.0.1#5335
|
||||
server=/video.sina.com.cn/127.0.0.1#5335
|
||||
server=/www.yinyuetai.com/127.0.0.1#5335
|
||||
server=/api.letv.com/127.0.0.1#5335
|
||||
server=/live.gslb.letv.com/127.0.0.1#5335
|
||||
server=/static.itv.letv.com/127.0.0.1#5335
|
||||
server=/ip.apps.cntv.cn/127.0.0.1#5335
|
||||
server=/vdn.apps.cntv.cn/127.0.0.1#5335
|
||||
server=/vdn.live.cntv.cn/127.0.0.1#5335
|
||||
server=/vip.sports.cntv.cn/127.0.0.1#5335
|
||||
server=/a.play.api.3g.youku.com/127.0.0.1#5335
|
||||
server=/i.play.api.3g.youku.com/127.0.0.1#5335
|
||||
server=/api.3g.youku.com/127.0.0.1#5335
|
||||
server=/tv.api.3g.youku.com/127.0.0.1#5335
|
||||
server=/play.api.3g.youku.com/127.0.0.1#5335
|
||||
server=/play.api.3g.tudou.com/127.0.0.1#5335
|
||||
server=/tv.api.3g.tudou.com/127.0.0.1#5335
|
||||
server=/api.3g.tudou.com/127.0.0.1#5335
|
||||
server=/api.tv.sohu.com/127.0.0.1#5335
|
||||
server=/access.tv.sohu.com/127.0.0.1#5335
|
||||
server=/iface.iqiyi.com/127.0.0.1#5335
|
||||
server=/iface2.iqiyi.com/127.0.0.1#5335
|
||||
server=/cache.m.iqiyi.com/127.0.0.1#5335
|
||||
server=/dynamic.app.m.letv.com/127.0.0.1#5335
|
||||
server=/dynamic.meizi.app.m.letv.com/127.0.0.1#5335
|
||||
server=/dynamic.search.app.m.letv.com/127.0.0.1#5335
|
||||
server=/dynamic.live.app.m.letv.com/127.0.0.1#5335
|
||||
server=/listso.m.areainfo.ppstream.com/127.0.0.1#5335
|
||||
server=/epg.api.pptv.com/127.0.0.1#5335
|
||||
server=/play.api.pptv.com/127.0.0.1#5335
|
||||
server=/m.letv.com/127.0.0.1#5335
|
||||
server=/interface.bilibili.com/127.0.0.1#5335
|
||||
server=/3g.music.qq.com/127.0.0.1#5335
|
||||
server=/mqqplayer.3g.qq.com/127.0.0.1#5335
|
||||
server=/proxy.music.qq.com/127.0.0.1#5335
|
||||
server=/proxymc.qq.com/127.0.0.1#5335
|
||||
server=/ip2.kugou.com/127.0.0.1#5335
|
||||
server=/ip.kugou.com/127.0.0.1#5335
|
||||
server=/client.api.ttpod.com/127.0.0.1#5335
|
||||
server=/mobi.kuwo.cn/127.0.0.1#5335
|
||||
server=/mobilefeedback.kugou.com/127.0.0.1#5335
|
||||
server=/tingapi.ting.baidu.com/127.0.0.1#5335
|
||||
server=/music.baidu.com/127.0.0.1#5335
|
||||
server=/serviceinfo.sdk.duomi.com/127.0.0.1#5335
|
||||
server=/music.163.com/127.0.0.1#5335
|
||||
server=/www.xiami.com/127.0.0.1#5335
|
||||
server=/spark.api.xiami.com/127.0.0.1#5335
|
||||
server=/iplocation.geo.qiyi.com/127.0.0.1#5335
|
||||
server=/sns.video.qq.com/127.0.0.1#5335
|
||||
server=/v5.pc.duomi.com/127.0.0.1#5335
|
||||
server=/tms.is.ysten.com/127.0.0.1#5335
|
||||
server=/internal.check.duokanbox.com/127.0.0.1#5335
|
||||
server=/openapi.youku.com/127.0.0.1#5335
|
||||
server=/y.qq.com/127.0.0.1#5335
|
||||
ipset=/v.youku.com/oversea
|
||||
ipset=/api.youku.com/oversea
|
||||
ipset=/v2.tudou.com/oversea
|
||||
ipset=/www.tudou.com/oversea
|
||||
ipset=/s.plcloud.music.qq.com/oversea
|
||||
ipset=/i.y.qq.com/oversea
|
||||
ipset=/hot.vrs.sohu.com/oversea
|
||||
ipset=/live.tv.sohu.com/oversea
|
||||
ipset=/pad.tv.sohu.com/oversea
|
||||
ipset=/my.tv.sohu.com/oversea
|
||||
ipset=/hot.vrs.letv.com/oversea
|
||||
ipset=/data.video.qiyi.com/oversea
|
||||
ipset=/cache.video.qiyi.com/oversea
|
||||
ipset=/cache.vip.qiyi.com/oversea
|
||||
ipset=/vv.video.qq.com/oversea
|
||||
ipset=/tt.video.qq.com/oversea
|
||||
ipset=/ice.video.qq.com/oversea
|
||||
ipset=/tjsa.video.qq.com/oversea
|
||||
ipset=/a10.video.qq.com/oversea
|
||||
ipset=/xyy.video.qq.com/oversea
|
||||
ipset=/vcq.video.qq.com/oversea
|
||||
ipset=/vsh.video.qq.com/oversea
|
||||
ipset=/vbj.video.qq.com/oversea
|
||||
ipset=/bobo.video.qq.com/oversea
|
||||
ipset=/flvs.video.qq.com/oversea
|
||||
ipset=/bkvv.video.qq.com/oversea
|
||||
ipset=/info.zb.qq.com/oversea
|
||||
ipset=/geo.js.kankan.xunlei.com/oversea
|
||||
ipset=/web-play.pptv.com/oversea
|
||||
ipset=/web-play.pplive.cn/oversea
|
||||
ipset=/dyn.ugc.pps.tv/oversea
|
||||
ipset=/v.pps.tv/oversea
|
||||
ipset=/inner.kandian.com/oversea
|
||||
ipset=/ipservice.163.com/oversea
|
||||
ipset=/so.open.163.com/oversea
|
||||
ipset=/zb.s.qq.com/oversea
|
||||
ipset=/ip.kankan.xunlei.com/oversea
|
||||
ipset=/vxml.56.com/oversea
|
||||
ipset=/music.sina.com.cn/oversea
|
||||
ipset=/play.baidu.com/oversea
|
||||
ipset=/v.iask.com/oversea
|
||||
ipset=/tv.weibo.com/oversea
|
||||
ipset=/wtv.v.iask.com/oversea
|
||||
ipset=/video.sina.com.cn/oversea
|
||||
ipset=/www.yinyuetai.com/oversea
|
||||
ipset=/api.letv.com/oversea
|
||||
ipset=/live.gslb.letv.com/oversea
|
||||
ipset=/static.itv.letv.com/oversea
|
||||
ipset=/ip.apps.cntv.cn/oversea
|
||||
ipset=/vdn.apps.cntv.cn/oversea
|
||||
ipset=/vdn.live.cntv.cn/oversea
|
||||
ipset=/vip.sports.cntv.cn/oversea
|
||||
ipset=/a.play.api.3g.youku.com/oversea
|
||||
ipset=/i.play.api.3g.youku.com/oversea
|
||||
ipset=/api.3g.youku.com/oversea
|
||||
ipset=/tv.api.3g.youku.com/oversea
|
||||
ipset=/play.api.3g.youku.com/oversea
|
||||
ipset=/play.api.3g.tudou.com/oversea
|
||||
ipset=/tv.api.3g.tudou.com/oversea
|
||||
ipset=/api.3g.tudou.com/oversea
|
||||
ipset=/api.tv.sohu.com/oversea
|
||||
ipset=/access.tv.sohu.com/oversea
|
||||
ipset=/iface.iqiyi.com/oversea
|
||||
ipset=/iface2.iqiyi.com/oversea
|
||||
ipset=/cache.m.iqiyi.com/oversea
|
||||
ipset=/dynamic.app.m.letv.com/oversea
|
||||
ipset=/dynamic.meizi.app.m.letv.com/oversea
|
||||
ipset=/dynamic.search.app.m.letv.com/oversea
|
||||
ipset=/dynamic.live.app.m.letv.com/oversea
|
||||
ipset=/listso.m.areainfo.ppstream.com/oversea
|
||||
ipset=/epg.api.pptv.com/oversea
|
||||
ipset=/play.api.pptv.com/oversea
|
||||
ipset=/m.letv.com/oversea
|
||||
ipset=/interface.bilibili.com/oversea
|
||||
ipset=/3g.music.qq.com/oversea
|
||||
ipset=/mqqplayer.3g.qq.com/oversea
|
||||
ipset=/proxy.music.qq.com/oversea
|
||||
ipset=/proxymc.qq.com/oversea
|
||||
ipset=/ip2.kugou.com/oversea
|
||||
ipset=/ip.kugou.com/oversea
|
||||
ipset=/client.api.ttpod.com/oversea
|
||||
ipset=/mobi.kuwo.cn/oversea
|
||||
ipset=/mobilefeedback.kugou.com/oversea
|
||||
ipset=/tingapi.ting.baidu.com/oversea
|
||||
ipset=/music.baidu.com/oversea
|
||||
ipset=/serviceinfo.sdk.duomi.com/oversea
|
||||
ipset=/music.163.com/oversea
|
||||
ipset=/www.xiami.com/oversea
|
||||
ipset=/spark.api.xiami.com/oversea
|
||||
ipset=/iplocation.geo.qiyi.com/oversea
|
||||
ipset=/sns.video.qq.com/oversea
|
||||
ipset=/v5.pc.duomi.com/oversea
|
||||
ipset=/tms.is.ysten.com/oversea
|
||||
ipset=/internal.check.duokanbox.com/oversea
|
||||
ipset=/openapi.youku.com/oversea
|
||||
ipset=/y.qq.com/oversea
|
5880
package/ctcgfw/luci-app-vssr/root/etc/dnsmasq.ssr/gfw_base.conf
Normal file
10414
package/ctcgfw/luci-app-vssr/root/etc/dnsmasq.ssr/gfw_list.conf
Normal file
534
package/ctcgfw/luci-app-vssr/root/etc/init.d/vssr
Executable file
@ -0,0 +1,534 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
#
|
||||
# Copyright (C) 2017 openwrt-ssr
|
||||
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
|
||||
# Copyright (C) 2018 lean <coolsnowwolf@gmail.com>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v3.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
START=90
|
||||
STOP=15
|
||||
|
||||
SERVICE_DAEMONIZE=1
|
||||
NAME=vssr
|
||||
EXTRA_COMMANDS=rules
|
||||
|
||||
#定义配置文件名称
|
||||
CONFIG_FILE=/var/etc/${NAME}_t.json
|
||||
CONFIG_UDP_FILE=/var/etc/${NAME}_u.json
|
||||
CONFIG_SOCK5_FILE=/var/etc/${NAME}_s.json
|
||||
|
||||
server_count=0
|
||||
redir_tcp=0
|
||||
redir_udp=0
|
||||
tunnel_enable=0
|
||||
local_enable=0
|
||||
kcp_enable_flag=0
|
||||
kcp_flag=0
|
||||
pdnsd_enable_flag=0
|
||||
switch_enable=0
|
||||
switch_server=$1
|
||||
MAXFD=32768
|
||||
CRON_FILE=/etc/crontabs/root
|
||||
threads=1
|
||||
|
||||
uci_get_by_name() {
|
||||
local ret=$(uci get $NAME.$1.$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
uci_get_by_type() {
|
||||
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
add_cron() {
|
||||
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
|
||||
}
|
||||
|
||||
del_cron() {
|
||||
sed -i '/vssr/d' $CRON_FILE
|
||||
sed -i '/vssr.log/d' $CRON_FILE
|
||||
/etc/init.d/cron restart
|
||||
}
|
||||
|
||||
run_mode=$(uci_get_by_type global run_mode)
|
||||
|
||||
gen_config_file() {
|
||||
local hostip=$(uci_get_by_name $1 server)
|
||||
|
||||
[ $2 = "0" -a $kcp_flag = "1" ] && hostip="127.0.0.1"
|
||||
|
||||
if [ $2 = "0" ]; then
|
||||
re_type="tcp"
|
||||
config_file=$CONFIG_FILE
|
||||
server_obj=$GLOBAL_SERVER
|
||||
elif [ $2 = "1" ]; then
|
||||
re_type="udp"
|
||||
config_file=$CONFIG_UDP_FILE
|
||||
server_obj=$UDP_RELAY_SERVER
|
||||
fi
|
||||
if [ $(uci_get_by_name $1 fast_open 0) = "1" ]; then
|
||||
fastopen="true"
|
||||
else
|
||||
fastopen="false"
|
||||
fi
|
||||
|
||||
local stype=$(uci_get_by_name $1 type)
|
||||
local port=$(uci_get_by_name $1 local_port)
|
||||
if [ "$stype" == "trojan" ]; then
|
||||
if [ "$re_type" == "udp" ]; then
|
||||
re_type="client"
|
||||
port="10801"
|
||||
else
|
||||
re_type="nat"
|
||||
fi
|
||||
fi
|
||||
lua /usr/share/vssr/genconfig_${stype}.lua ${server_obj} ${re_type} ${port} ${hostip} >${config_file}
|
||||
sed -i 's/\\//g' $config_file
|
||||
|
||||
}
|
||||
|
||||
get_arg_out() {
|
||||
case "$(uci_get_by_type access_control router_proxy 1)" in
|
||||
1) echo "-o" ;;
|
||||
2) echo "-O" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
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
|
||||
server=${server}
|
||||
elif [ "$server" != "${server#*:[0-9a-fA-F]}" ]; then
|
||||
server=${server}
|
||||
else
|
||||
server=$(ping ${server} -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1)
|
||||
if echo $server | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then
|
||||
echo $server >/etc/ssr_ip
|
||||
else
|
||||
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
|
||||
|
||||
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"
|
||||
local router_proxy=$(uci_get_by_type access_control router_proxy)
|
||||
if [ "$GLOBAL_SERVER" = "$UDP_RELAY_SERVER" -a $kcp_flag = 0 ]; then
|
||||
ARG_UDP="-u"
|
||||
elif [ -n "$UDP_RELAY_SERVER" ]; then
|
||||
ARG_UDP="-U"
|
||||
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=""
|
||||
if [ "$run_mode" = "gfw" ]; then
|
||||
gfwmode="-g"
|
||||
elif [ "$run_mode" = "router" ]; then
|
||||
gfwmode="-r"
|
||||
elif [ "$run_mode" = "oversea" ]; then
|
||||
gfwmode="-c"
|
||||
elif [ "$run_mode" = "all" ]; then
|
||||
gfwmode="-z"
|
||||
fi
|
||||
|
||||
local dports=$(uci_get_by_type global dports 1)
|
||||
if [ $dports = "1" ]; then
|
||||
proxyport=" "
|
||||
else
|
||||
proxyport="-m multiport --dports 22,53,587,465,995,993,143,80,443 "
|
||||
fi
|
||||
|
||||
/usr/bin/vssr-rules \
|
||||
-s "$server" \
|
||||
-l "$local_port" \
|
||||
-S "$udp_server" \
|
||||
-L "$udp_local_port" \
|
||||
-a "$ac_ips" \
|
||||
-i "$(uci_get_by_type access_control wan_bp_list)" \
|
||||
-b "$(uci_get_by_type access_control wan_bp_ips)" \
|
||||
-w "$(uci_get_by_type access_control wan_fw_ips)" \
|
||||
-p "$(uci_get_by_type access_control lan_fp_ips)" \
|
||||
-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"
|
||||
|
||||
[ -d /var/etc ] || mkdir -p /var/etc
|
||||
|
||||
if [ ! -d /var/pdnsd ]; then
|
||||
mkdir -p /var/pdnsd
|
||||
echo -ne "pd13\000\000\000\000" >/var/pdnsd/pdnsd.cache
|
||||
chown -R nobody:nogroup /var/pdnsd
|
||||
fi
|
||||
|
||||
cat >/var/etc/pdnsd.conf <<EOF
|
||||
global {
|
||||
perm_cache=1024;
|
||||
cache_dir="/var/pdnsd";
|
||||
pid_file = /var/run/pdnsd.pid;
|
||||
run_as="nobody";
|
||||
server_ip = 127.0.0.1;
|
||||
server_port = 5335;
|
||||
status_ctl = on;
|
||||
query_method = tcp_only;
|
||||
min_ttl=1h;
|
||||
max_ttl=1w;
|
||||
timeout=10;
|
||||
neg_domain_pol=on;
|
||||
proc_limit=2;
|
||||
procq_limit=8;
|
||||
}
|
||||
server {
|
||||
label= "ssr-usrdns";
|
||||
ip = $usr_dns;
|
||||
port = $usr_port;
|
||||
timeout=6;
|
||||
uptest=none;
|
||||
interval=10m;
|
||||
purge_cache=off;
|
||||
}
|
||||
server {
|
||||
label= "ssr-pdnsd";
|
||||
ip = $tcp_dns_list;
|
||||
port = 5353;
|
||||
timeout=6;
|
||||
uptest=none;
|
||||
interval=10m;
|
||||
purge_cache=off;
|
||||
}
|
||||
EOF
|
||||
|
||||
/usr/sbin/pdnsd -c /var/etc/pdnsd.conf -d
|
||||
}
|
||||
|
||||
start_redir() {
|
||||
case "$(uci_get_by_name $GLOBAL_SERVER auth_enable)" in
|
||||
1 | on | true | yes | enabled) ARG_OTA="-A" ;;
|
||||
*) ARG_OTA="" ;;
|
||||
esac
|
||||
|
||||
#deal kcp
|
||||
local kcp_enable=$(uci_get_by_name $GLOBAL_SERVER kcp_enable 0)
|
||||
if [ $kcp_enable = "1" ]; then
|
||||
[ ! -f "/usr/bin/kcptun-client" ] && return 1
|
||||
|
||||
local kcp_str=$(/usr/bin/kcptun-client -v | grep kcptun | wc -l)
|
||||
[ "0" = $kcp_str ] && return 1
|
||||
local kcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port)
|
||||
local server_port=$(uci_get_by_name $GLOBAL_SERVER server_port)
|
||||
local password=$(uci_get_by_name $GLOBAL_SERVER kcp_password)
|
||||
local kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param)
|
||||
[ "$password" != "" ] && password="--key "${password}
|
||||
service_start /usr/bin/kcptun-client \
|
||||
-r $kcp_server:$kcp_port \
|
||||
-l :$server_port $password $kcp_param
|
||||
kcp_enable_flag=1
|
||||
fi
|
||||
|
||||
gen_config_file $GLOBAL_SERVER 0
|
||||
local stype=$(uci_get_by_name $GLOBAL_SERVER type)
|
||||
if [ "$stype" == "ss" -o "$stype" == "v2ray" ]; then
|
||||
sscmd="/usr/bin/v2ray/v2ray"
|
||||
[ ! -f "$sscmd" ] && sscmd="/usr/bin/v2ray"
|
||||
elif [ "$stype" == "ssr" ]; then
|
||||
sscmd="/usr/bin/ssr-redir"
|
||||
elif [ "$stype" == "trojan" ]; then
|
||||
sscmd="/usr/sbin/trojan"
|
||||
fi
|
||||
|
||||
local utype=$(uci_get_by_name $UDP_RELAY_SERVER type)
|
||||
if [ "$utype" == "ss" -o "$utype" == "v2ray" ]; then
|
||||
ucmd="/usr/bin/v2ray/v2ray"
|
||||
[ ! -f "$ucmd" ] && ucmd="/usr/bin/v2ray"
|
||||
elif [ "$utype" == "ssr" ]; then
|
||||
ucmd="/usr/bin/ssr-redir"
|
||||
elif [ "$utype" == "trojan" ]; then
|
||||
ucmd="/usr/sbin/trojan"
|
||||
fi
|
||||
|
||||
if [ "$(uci_get_by_type global threads 0)" = "0" ]; then
|
||||
threads=$(cat /proc/cpuinfo | grep 'processor' | wc -l)
|
||||
else
|
||||
threads=$(uci_get_by_type global threads)
|
||||
fi
|
||||
#转发TCP
|
||||
redir_tcp=1
|
||||
local last_config_file=$CONFIG_FILE
|
||||
if [ "$stype" == "ssr" ]; then
|
||||
local pid_file="/var/run/ssr-retcp.pid"
|
||||
for i in $(seq 1 $threads); do
|
||||
$sscmd -c $last_config_file $ARG_OTA -f /var/run/ssr-retcp_$i.pid >/dev/null 2>&1
|
||||
done
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") SSR $threads 线程 已启动!" >>/tmp/vssr.log
|
||||
elif [ "$stype" == "v2ray" -o "$stype" == "ss" ]; then
|
||||
$sscmd -config $last_config_file >/dev/null 2>&1 &
|
||||
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd -version | head -1) 已启动!" >>/tmp/vssr.log
|
||||
|
||||
elif [ "$stype" == "trojan" ]; then
|
||||
for i in $(seq 1 $threads); do
|
||||
$sscmd -c $last_config_file >/dev/null 2>&1 &
|
||||
done
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd -V 2>&1 | head -1) $threads 线程 已启动!" >>/tmp/vssr.log
|
||||
fi
|
||||
|
||||
#转发UDP
|
||||
if [ -n "$UDP_RELAY_SERVER" ]; then
|
||||
redir_udp=1
|
||||
gen_config_file $UDP_RELAY_SERVER 1
|
||||
last_config_file=$CONFIG_UDP_FILE
|
||||
echo $utype
|
||||
if [ "$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
|
||||
pid_file="/var/run/ssr-reudp.pid"
|
||||
#echo $ucmd >> /tmp/vssr.log
|
||||
$ucmd -c $last_config_file $ARG_OTA -U -f /var/run/ssr-reudp.pid >/tmp/vssr.log 2>&1
|
||||
#echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd -version | head -1) UDP已启动!" >> /tmp/vssr.log
|
||||
elif [ "$utype" == "ss" -o "$utype" == "v2ray" ]; then
|
||||
$ucmd -config $last_config_file >/dev/null 2>&1 &
|
||||
elif [ "$stype" == "trojan" ]; then
|
||||
$ucmd --config $last_config_file >/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
|
||||
|
||||
#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}')
|
||||
local dnsport=$(echo "$dnsstr" | awk -F ':' '{print $2}')
|
||||
if [ "$run_mode" = "gfw" ]; then
|
||||
ipset add gfwlist $dnsserver 2>/dev/null
|
||||
elif [ "$run_mode" = "oversea" ]; then
|
||||
ipset add oversea $dnsserver 2>/dev/null
|
||||
else
|
||||
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
|
||||
local switch_time=$(uci_get_by_type global switch_time)
|
||||
local switch_timeout=$(uci_get_by_type global switch_timeout)
|
||||
service_start /usr/bin/vssr-switch start $switch_time $switch_timeout
|
||||
switch_enable=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
add_cron
|
||||
|
||||
return $?
|
||||
}
|
||||
|
||||
gen_service_file() {
|
||||
if [ $(uci_get_by_name $1 fast_open) = "1" ]; then
|
||||
fastopen="true"
|
||||
else
|
||||
fastopen="false"
|
||||
fi
|
||||
cat <<-EOF >$2
|
||||
{
|
||||
"server": "0.0.0.0",
|
||||
"server_port": $(uci_get_by_name $1 server_port),
|
||||
"password": "$(uci_get_by_name $1 password)",
|
||||
"timeout": $(uci_get_by_name $1 timeout 60),
|
||||
"method": "$(uci_get_by_name $1 encrypt_method)",
|
||||
"protocol": "$(uci_get_by_name $1 protocol)",
|
||||
"protocol_param": "$(uci_get_by_name $1 protocol_param)",
|
||||
"obfs": "$(uci_get_by_name $1 obfs)",
|
||||
"obfs_param": "$(uci_get_by_name $1 obfs_param)",
|
||||
"fast_open": $fastopen
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
start_service() {
|
||||
[ $(uci_get_by_name $1 enable) = "0" ] && return 1
|
||||
let server_count=server_count+1
|
||||
if [ $server_count = 1 ]; then
|
||||
iptables -N SSR-SERVER-RULE &&
|
||||
iptables -t filter -I INPUT -j SSR-SERVER-RULE
|
||||
fi
|
||||
|
||||
gen_service_file $1 /var/etc/${NAME}_${server_count}.json
|
||||
/usr/bin/ssr-server -c /var/etc/${NAME}_${server_count}.json -u -f /var/run/ssr-server${server_count}.pid >/dev/null 2>&1
|
||||
iptables -t filter -A SSR-SERVER-RULE -p tcp --dport $(uci_get_by_name $1 server_port) -j ACCEPT
|
||||
iptables -t filter -A SSR-SERVER-RULE -p udp --dport $(uci_get_by_name $1 server_port) -j ACCEPT
|
||||
return 0
|
||||
}
|
||||
gen_serv_include() {
|
||||
FWI=$(uci get firewall.vssr.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/"
|
||||
echo 'COMMIT'
|
||||
}
|
||||
cat <<-EOF >>$FWI
|
||||
iptables-save -c | grep -v "SSR-SERVER" | iptables-restore -c
|
||||
iptables-restore -n <<-EOT
|
||||
$(extract_rules)
|
||||
EOT
|
||||
EOF
|
||||
|
||||
}
|
||||
start_server() {
|
||||
SERVER_ENABLE=$(uci_get_by_type server_global enable_server)
|
||||
[ "$SERVER_ENABLE" = 0 ] && return 0
|
||||
mkdir -p /var/run /var/etc
|
||||
|
||||
config_load $NAME
|
||||
config_foreach start_service server_config
|
||||
gen_serv_include
|
||||
return 0
|
||||
}
|
||||
|
||||
start_local() {
|
||||
local local_server=$(uci_get_by_type socks5_proxy enable_server)
|
||||
|
||||
[ "$local_server" = "0" ] && return 0
|
||||
mkdir -p /var/run /var/etc
|
||||
|
||||
lua /usr/share/vssr/genconfig_v2ray_s.lua >$CONFIG_SOCK5_FILE
|
||||
sed -i 's/\\//g' $config_file
|
||||
|
||||
/usr/bin/v2ray/v2ray -config $CONFIG_SOCK5_FILE >/dev/null 2>&1 &
|
||||
|
||||
local_enable=1
|
||||
}
|
||||
|
||||
rules() {
|
||||
[ "$GLOBAL_SERVER" = "nil" ] && return 1
|
||||
mkdir -p /var/run /var/etc
|
||||
UDP_RELAY_SERVER=$(uci_get_by_type global udp_relay_server)
|
||||
[ "$UDP_RELAY_SERVER" = "same" ] && UDP_RELAY_SERVER=$GLOBAL_SERVER
|
||||
if start_rules; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
start() {
|
||||
if [ -z "$switch_server" ]; then
|
||||
GLOBAL_SERVER=$(uci_get_by_type global global_server)
|
||||
else
|
||||
GLOBAL_SERVER=$switch_server
|
||||
switch_enable=1
|
||||
fi
|
||||
|
||||
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 <<EOF
|
||||
conf-dir=/tmp/dnsmasq.ssr
|
||||
EOF
|
||||
else
|
||||
cat >/tmp/dnsmasq.d/dnsmasq-ssr.conf <<EOF
|
||||
conf-dir=/tmp/dnsmasq.oversea
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ $(uci_get_by_type global adblock) = 0 ]; then
|
||||
rm -f /tmp/dnsmasq.ssr/ad.conf
|
||||
fi
|
||||
|
||||
/usr/share/vssr/gfw2ipset.sh
|
||||
/etc/init.d/dnsmasq restart >/dev/null 2>&1
|
||||
|
||||
fi
|
||||
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 ]; 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 $switch_enable
|
||||
fi
|
||||
fi
|
||||
|
||||
ENABLE_SERVER=$(uci_get_by_type global global_server)
|
||||
[ "$ENABLE_SERVER" = "nil" ] && return 1
|
||||
}
|
||||
|
||||
boot() {
|
||||
(/usr/share/vssr/chinaipset.sh && sleep 5 && start >/dev/null 2>&1) &
|
||||
}
|
||||
|
||||
stop() {
|
||||
/usr/bin/vssr-rules -f
|
||||
srulecount=$(iptables -L | grep SSR-SERVER-RULE | wc -l)
|
||||
if [ $srulecount -gt 0 ]; then
|
||||
iptables -F SSR-SERVER-RULE
|
||||
iptables -t filter -D INPUT -j SSR-SERVER-RULE
|
||||
iptables -X SSR-SERVER-RULE 2>/dev/null
|
||||
fi
|
||||
if [ -z "$switch_server" ]; then
|
||||
kill -9 $(busybox ps -w | grep vssr-switch | grep -v grep | awk '{print $1}') >/dev/null 2>&1
|
||||
fi
|
||||
if [ $(uci_get_by_type global monitor_enable) = 1 ]; then
|
||||
kill -9 $(busybox ps -w | grep vssr-monitor | grep -v grep | awk '{print $1}') >/dev/null 2>&1
|
||||
fi
|
||||
killall -q -9 vssr-monitor
|
||||
killall -q -9 ssr-redir
|
||||
killall -q -9 v2ray
|
||||
killall -q -9 trojan
|
||||
killall -q -9 ipt2socks
|
||||
killall -q -9 ssr-server
|
||||
killall -q -9 kcptun-client
|
||||
killall -q -9 ssr-local
|
||||
killall -q -9 pdnsd
|
||||
|
||||
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
|
||||
fi
|
||||
del_cron
|
||||
}
|
18
package/ctcgfw/luci-app-vssr/root/etc/uci-defaults/luci-vssr
Normal file
@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@vssr[-1]
|
||||
add ucitrack vssr
|
||||
set ucitrack.@vssr[-1].init=vssr
|
||||
commit ucitrack
|
||||
delete firewall.vssr
|
||||
set firewall.vssr=include
|
||||
set firewall.vssr.type=script
|
||||
set firewall.vssr.path=/var/etc/vssr.include
|
||||
set firewall.vssr.reload=1
|
||||
commit firewall
|
||||
EOF
|
||||
|
||||
/usr/share/vssr/gfw2ipset.sh
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
5
package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-ad
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
if [ -f /tmp/adnew.conf ]; then
|
||||
cat /tmp/adnew.conf | grep ^\|\|[^\*]*\^$ | sed -e 's:||:address\=\/:' -e 's:\^:/0\.0\.0\.0:' > /tmp/ad.conf
|
||||
fi
|
31
package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-gfw
Executable file
@ -0,0 +1,31 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
generate_china_banned()
|
||||
{
|
||||
|
||||
cat $1 | base64 -d > /tmp/gfwlist.txt
|
||||
rm -f $1
|
||||
sed -i '/^@@|/d' /tmp/gfwlist.txt
|
||||
|
||||
cat /tmp/gfwlist.txt | sort -u |
|
||||
sed 's#!.\+##; s#|##g; s#@##g; s#http:\/\/##; s#https:\/\/##;' |
|
||||
sed '/\*/d; /apple\.com/d; /sina\.cn/d; /sina\.com\.cn/d; /baidu\.com/d; /byr\.cn/d; /jlike\.com/d; /weibo\.com/d; /zhongsou\.com/d; /youdao\.com/d; /sogou\.com/d; /so\.com/d; /soso\.com/d; /aliyun\.com/d; /taobao\.com/d; /jd\.com/d; /qq\.com/d' |
|
||||
sed '/^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$/d' |
|
||||
grep '^[0-9a-zA-Z\.-]\+$' | grep '\.' | sed 's#^\.\+##' | sort -u |
|
||||
awk '
|
||||
BEGIN { prev = "________"; } {
|
||||
cur = $0;
|
||||
if (index(cur, prev) == 1 && substr(cur, 1 + length(prev) ,1) == ".") {
|
||||
} else {
|
||||
print cur;
|
||||
prev = cur;
|
||||
}
|
||||
}' | sort -u
|
||||
|
||||
}
|
||||
|
||||
generate_china_banned /tmp/gfw.b64 > /tmp/gfw.txt
|
||||
rm -f /tmp/gfwlist.txt
|
||||
sed '/.*/s/.*/server=\/\.&\/127.0.0.1#5335\nipset=\/\.&\/gfwlist/' /tmp/gfw.txt >/tmp/gfwnew.txt
|
||||
rm -f /tmp/gfw.txt
|
||||
|
126
package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-monitor
Executable file
@ -0,0 +1,126 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2017 openwrt-ssr
|
||||
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v3.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
NAME=vssr
|
||||
|
||||
uci_get_by_name() {
|
||||
local ret=$(uci get $NAME.$1.$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
uci_get_by_type() {
|
||||
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
server_process_count=$1
|
||||
redir_tcp_process=$2
|
||||
redir_udp_process=$3
|
||||
tunnel_process=$4
|
||||
kcp_process=$5
|
||||
local_process=$6
|
||||
pdnsd_process=$7
|
||||
if [ -z "$pdnsd_process" ]; then
|
||||
pdnsd_process=0
|
||||
fi
|
||||
|
||||
i=0
|
||||
|
||||
GLOBAL_SERVER=$(uci_get_by_type global global_server)
|
||||
server=$(uci_get_by_name $GLOBAL_SERVER server)
|
||||
lkcp_port=$(uci_get_by_name $GLOBAL_SERVER kcp_port)
|
||||
server_port=$(uci_get_by_name $GLOBAL_SERVER server_port)
|
||||
password=$(uci_get_by_name $GLOBAL_SERVER kcp_password)
|
||||
kcp_param=$(uci_get_by_name $GLOBAL_SERVER kcp_param)
|
||||
[ "$password" != "" ] && password="--key "${password}
|
||||
|
||||
sock5_port=$(uci_get_by_type socks5_proxy local_port 1080)
|
||||
|
||||
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}
|
||||
else
|
||||
server=$(cat /etc/ssr_ip)
|
||||
fi
|
||||
|
||||
while [ "1" = "1" ]; do #这里是个死循环
|
||||
sleep 30
|
||||
#redir tcp
|
||||
if [ $redir_tcp_process -gt 0 ]; then
|
||||
icount=$(busybox ps -w | grep vssr_t | grep -v grep | wc -l)
|
||||
if [ $icount = 0 ]; then
|
||||
logger -t "$NAME" "ssr redir tcp error.restart!"
|
||||
/etc/init.d/vssr restart
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
#redir udp
|
||||
if [ $redir_udp_process -gt 0 ]; then
|
||||
icount=$(busybox ps -w | grep vssr_u | grep -v grep | wc -l)
|
||||
if [ $icount = 0 ]; then
|
||||
logger -t "$NAME" "ssr redir udp error.restart!"
|
||||
/etc/init.d/vssr restart
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
#tunnel
|
||||
if [ $tunnel_process -gt 0 ]; then
|
||||
icount=$(busybox ps -w | grep ssr-tunnel | grep -v grep | wc -l)
|
||||
if [ $icount = 0 ]; then
|
||||
logger -t "$NAME" "ssr tunnel error.restart!"
|
||||
/etc/init.d/vssr restart
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
#server
|
||||
if [ $server_process_count -gt 0 ]; then
|
||||
icount=$(busybox ps -w | grep ssr-server | grep -v grep | wc -l)
|
||||
if [ $icount -lt $server_process_count ]; then
|
||||
logger -t "$NAME" "ssr server error.restart!"
|
||||
killall -q -9 ssr-server
|
||||
for i in $(seq $server_process_count); do
|
||||
/usr/bin/ssr-server -c /var/etc/vssr_$i.json -u -f /var/run/ssr-server$i.pid
|
||||
done
|
||||
fi
|
||||
fi
|
||||
#kcptun
|
||||
if [ $kcp_process -gt 0 ]; then
|
||||
icount=$(busybox ps -w | grep kcptun-client | grep -v grep | wc -l)
|
||||
if [ $icount -lt $kcp_process ]; then
|
||||
logger -t "$NAME" "ssr kcptun error.restart!"
|
||||
killall -q -9 kcptun-client
|
||||
|
||||
(/usr/bin/kcptun-client -r $server:$kcp_port -l :$server_port $password $kcp_param &)
|
||||
fi
|
||||
fi
|
||||
#local
|
||||
# if [ $local_process -gt 0 ] ;then
|
||||
# icount=`busybox ps -w | grep ssr-local |grep -v grep| wc -l`
|
||||
# if [ $icount -lt $local_process ]
|
||||
# then
|
||||
# logger -t "$NAME" "ssr local error.restart!"
|
||||
# killall -q -9 ssr-local
|
||||
|
||||
# ( /usr/bin/ssr-local -c /var/etc/vssr_s.json -u -l $sock5_port -f /var/run/ssr-local.pid &)
|
||||
# fi
|
||||
# fi
|
||||
#pdnsd
|
||||
if [ $pdnsd_process -gt 0 ]; then
|
||||
icount=$(busybox ps -w | grep pdnsd | grep -v grep | wc -l)
|
||||
if [ $icount -lt $pdnsd_process ]; then #如果进程挂掉就重启它
|
||||
logger -t "$NAME" "pdnsd tunnel error.restart!"
|
||||
if [ -f /var/run/pdnsd.pid ]; then
|
||||
kill $(cat /var/run/pdnsd.pid) >/dev/null 2>&1
|
||||
else
|
||||
kill -9 $(ps | grep pdnsd | grep -v grep | awk '{print $1}') >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
(/usr/sbin/pdnsd -c /var/etc/pdnsd.conf -d &)
|
||||
fi
|
||||
fi
|
||||
done
|
180
package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-qucikswitch
Executable file
@ -0,0 +1,180 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2019 vssr
|
||||
# Copyright (C) 2019 jerrykuku <jerrykuku@qq.com>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v3.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
NAME=vssr
|
||||
|
||||
#定义配置文件名称
|
||||
CONFIG_FILE=/var/etc/${NAME}_t.json
|
||||
CONFIG_UDP_FILE=/var/etc/${NAME}_u.json
|
||||
CONFIG_SOCK5_FILE=/var/etc/${NAME}_s.json
|
||||
|
||||
switch_server=$1
|
||||
|
||||
uci_get_by_name() {
|
||||
local ret=$(uci get $NAME.$1.$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
uci_get_by_type() {
|
||||
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
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
|
||||
hostip=${host}
|
||||
elif [ "$host" != "${host#*:[0-9a-fA-F]}" ]; then
|
||||
hostip=${host}
|
||||
else
|
||||
hostip=$(ping ${host} -s 1 -c 1 | grep PING | cut -d'(' -f 2 | cut -d')' -f1)
|
||||
if echo $hostip | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then
|
||||
hostip=${hostip}
|
||||
else
|
||||
hostip=$(cat /etc/ssr_ip)
|
||||
fi
|
||||
fi
|
||||
[ $2 = "0" -a $kcp_flag = "1" ] && hostip="127.0.0.1"
|
||||
|
||||
if [ $2 = "0" ]; then
|
||||
re_type="tcp"
|
||||
config_file=$CONFIG_FILE
|
||||
server_obj=$GLOBAL_SERVER
|
||||
elif [ $2 = "1" ]; then
|
||||
re_type="udp"
|
||||
config_file=$CONFIG_UDP_FILE
|
||||
server_obj=$UDP_RELAY_SERVER
|
||||
fi
|
||||
if [ $(uci_get_by_name $1 fast_open 0) = "1" ]; then
|
||||
fastopen="true"
|
||||
else
|
||||
fastopen="false"
|
||||
fi
|
||||
|
||||
local stype=$(uci_get_by_name $1 type)
|
||||
local port=$(uci_get_by_name $1 local_port)
|
||||
if [ "$stype" == "trojan" ]; then
|
||||
if [ "$re_type" == "udp" ]; then
|
||||
re_type="client"
|
||||
port="10801"
|
||||
else
|
||||
re_type="nat"
|
||||
fi
|
||||
fi
|
||||
lua /usr/share/vssr/genconfig_${stype}.lua ${server_obj} ${re_type} ${port} ${hostip} >${config_file}
|
||||
sed -i 's/\\//g' $config_file
|
||||
|
||||
}
|
||||
start_local() {
|
||||
local local_server=$(uci_get_by_type socks5_proxy enable_server)
|
||||
local local_port=$(uci_get_by_type socks5_proxy local_port)
|
||||
local Socks_user=$(uci_get_by_type socks5_proxy Socks_user)
|
||||
local Socks_pass=$(uci_get_by_type socks5_proxy Socks_pass)
|
||||
[ "$local_server" = "0" ] && return 1
|
||||
mkdir -p /var/run /var/etc
|
||||
|
||||
lua /usr/share/vssr/genconfig_v2ray_s.lua "socks" ${local_port} ${Socks_user} ${Socks_pass} >$CONFIG_SOCK5_FILE
|
||||
sed -i 's/\\//g' $config_file
|
||||
|
||||
/usr/bin/v2ray/v2ray -config $CONFIG_SOCK5_FILE >/dev/null 2>&1 &
|
||||
}
|
||||
|
||||
killall -q -9 ssr-redir
|
||||
killall -q -9 v2ray
|
||||
killall -q -9 trojan
|
||||
killall -q -9 ipt2socks
|
||||
|
||||
case "$(uci_get_by_name $GLOBAL_SERVER auth_enable)" in
|
||||
1 | on | true | yes | enabled) ARG_OTA="-A" ;;
|
||||
*) ARG_OTA="" ;;
|
||||
esac
|
||||
|
||||
if [ -z "$switch_server" ]; then
|
||||
GLOBAL_SERVER=$(uci_get_by_type global global_server)
|
||||
else
|
||||
GLOBAL_SERVER=$switch_server
|
||||
fi
|
||||
|
||||
gen_config_file $GLOBAL_SERVER 0
|
||||
stype=$(uci_get_by_name $GLOBAL_SERVER type)
|
||||
local stype=$(uci_get_by_name $GLOBAL_SERVER type)
|
||||
if [ "$stype" == "ss" -o "$stype" == "v2ray" ]; then
|
||||
sscmd="/usr/bin/v2ray/v2ray"
|
||||
[ ! -f "$sscmd" ] && sscmd="/usr/bin/v2ray"
|
||||
elif [ "$stype" == "ssr" ]; then
|
||||
sscmd="/usr/bin/ssr-redir"
|
||||
elif [ "$stype" == "trojan" ]; then
|
||||
sscmd="/usr/sbin/trojan"
|
||||
fi
|
||||
|
||||
local utype=$(uci_get_by_name $UDP_RELAY_SERVER type)
|
||||
if [ "$utype" == "ss" -o "$utype" == "v2ray" ]; then
|
||||
ucmd="/usr/bin/v2ray/v2ray"
|
||||
[ ! -f "$ucmd" ] && ucmd="/usr/bin/v2ray"
|
||||
elif [ "$utype" == "ssr" ]; then
|
||||
ucmd="/usr/bin/ssr-redir"
|
||||
elif [ "$utype" == "trojan" ]; then
|
||||
ucmd="/usr/sbin/trojan"
|
||||
fi
|
||||
|
||||
if [ "$(uci_get_by_type global threads 0)" = "0" ]; then
|
||||
threads=$(cat /proc/cpuinfo | grep 'processor' | wc -l)
|
||||
else
|
||||
threads=$(uci_get_by_type global threads)
|
||||
fi
|
||||
|
||||
#转发TCP
|
||||
if [ "$(uci_get_by_type global threads 0)" = "0" ]; then
|
||||
threads=$(cat /proc/cpuinfo | grep 'processor' | wc -l)
|
||||
else
|
||||
threads=$(uci_get_by_type global threads)
|
||||
fi
|
||||
#转发TCP
|
||||
redir_tcp=1
|
||||
local last_config_file=$CONFIG_FILE
|
||||
if [ "$stype" == "ssr" ]; then
|
||||
local pid_file="/var/run/ssr-retcp.pid"
|
||||
for i in $(seq 1 $threads); do
|
||||
$sscmd -c $last_config_file $ARG_OTA -f /var/run/ssr-retcp_$i.pid >/dev/null 2>&1
|
||||
done
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") SSR $threads 线程 已启动!" >>/tmp/vssr.log
|
||||
elif [ "$stype" == "v2ray" -o "$stype" == "ss" ]; then
|
||||
$sscmd -config $last_config_file >/dev/null 2>&1 &
|
||||
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd -version | head -1) 已启动!" >>/tmp/vssr.log
|
||||
|
||||
elif [ "$stype" == "trojan" ]; then
|
||||
$sscmd -c $last_config_file >/dev/null 2>&1 &
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd -V 2>&1 | head -1) 已启动!" >>/tmp/vssr.log
|
||||
fi
|
||||
|
||||
#转发UDP
|
||||
if [ -n "$UDP_RELAY_SERVER" ]; then
|
||||
redir_udp=1
|
||||
gen_config_file $UDP_RELAY_SERVER 1
|
||||
last_config_file=$CONFIG_UDP_FILE
|
||||
echo $utype
|
||||
if [ "$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
|
||||
pid_file="/var/run/ssr-reudp.pid"
|
||||
#echo $ucmd >> /tmp/vssr.log
|
||||
$ucmd -c $last_config_file $ARG_OTA -U -f /var/run/ssr-reudp.pid >/tmp/vssr.log 2>&1
|
||||
#echo "$(date "+%Y-%m-%d %H:%M:%S") $($sscmd -version | head -1) UDP已启动!" >> /tmp/vssr.log
|
||||
elif [ "$utype" == "ss" -o "$utype" == "v2ray" ]; then
|
||||
$ucmd -config $last_config_file >/dev/null 2>&1 &
|
||||
elif [ "$stype" == "trojan" ]; then
|
||||
$ucmd --config $last_config_file >/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
|
||||
start_local
|
389
package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-rules
Executable file
@ -0,0 +1,389 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2017 openwrt-ssr
|
||||
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v3.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
TAG="_SS_SPEC_RULE_" # comment tag
|
||||
IPT="iptables -t nat" # alias of iptables
|
||||
FWI=$(uci get firewall.vssr.path 2>/dev/null) # firewall include file
|
||||
|
||||
usage() {
|
||||
cat <<-EOF
|
||||
Usage: vssr-rules [options]
|
||||
|
||||
Valid options are:
|
||||
|
||||
-s <server_ip> ip address of vssr remote server
|
||||
-l <local_port> port number of vssr local server
|
||||
-S <server_ip> ip address of vssr remote UDP server
|
||||
-L <local_port> port number of vssr local UDP server
|
||||
-i <ip_list_file> a file content is bypassed ip list
|
||||
-a <lan_ips> lan ip of access control, need a prefix to
|
||||
define access control mode
|
||||
-b <wan_ips> wan ip of will be bypassed
|
||||
-w <wan_ips> wan ip of will be forwarded
|
||||
-p <fp_lan_ips> lan ip of will be global proxy
|
||||
-G <gm_lan_ips> lan ip of will be game mode proxy
|
||||
-D <proxy_ports> proxy ports
|
||||
-e <extra_options> extra options for iptables
|
||||
-o apply the rules to the OUTPUT chain
|
||||
-O apply the global rules to the OUTPUT chain
|
||||
-u enable udprelay mode, TPROXY is required
|
||||
-U enable udprelay mode, using different IP
|
||||
and ports for TCP and UDP
|
||||
-f flush the rules
|
||||
-g gfw list mode
|
||||
-r return china mode
|
||||
-h show this help message and exit
|
||||
EOF
|
||||
exit $1
|
||||
}
|
||||
|
||||
loger() {
|
||||
# 1.alert 2.crit 3.err 4.warn 5.notice 6.info 7.debug
|
||||
logger -st vssr-rules[$$] -p$1 $2
|
||||
}
|
||||
|
||||
flush_r() {
|
||||
flush_iptables() {
|
||||
local ipt="iptables -t $1"
|
||||
local DAT=$(iptables-save -t $1)
|
||||
eval $(echo "$DAT" | grep "$TAG" | sed -e 's/^-A/$ipt -D/' -e 's/$/;/')
|
||||
for chain in $(echo "$DAT" | awk '/^:SS_SPEC/{print $1}'); do
|
||||
$ipt -F ${chain:1} 2>/dev/null && $ipt -X ${chain:1}
|
||||
done
|
||||
}
|
||||
flush_iptables nat
|
||||
flush_iptables mangle
|
||||
ip rule del fwmark 0x01/0x01 table 100 2>/dev/null
|
||||
ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null
|
||||
ipset -X ss_spec_lan_ac 2>/dev/null
|
||||
ipset -X ss_spec_wan_ac 2>/dev/null
|
||||
ipset -X ssr_gen_router 2>/dev/null
|
||||
ipset -X fplan 2>/dev/null
|
||||
ipset -X gmlan 2>/dev/null
|
||||
ipset -X oversea 2>/dev/null
|
||||
ipset -X whitelist 2>/dev/null
|
||||
ipset -X blacklist 2>/dev/null
|
||||
[ -n "$FWI" ] && echo '#!/bin/sh' >$FWI
|
||||
return 0
|
||||
}
|
||||
|
||||
ipset_r() {
|
||||
ipset -N gmlan hash:net 2>/dev/null
|
||||
for ip in $LAN_GM_IP; do ipset -! add gmlan $ip ; done
|
||||
|
||||
if [ "$RUNMODE" = "router" ] ;then
|
||||
ipset -! -R <<-EOF || return 1
|
||||
create ss_spec_wan_ac hash:net
|
||||
$(gen_iplist | sed -e "s/^/add ss_spec_wan_ac /")
|
||||
EOF
|
||||
ipset -N gfwlist hash:net 2>/dev/null
|
||||
$IPT -N SS_SPEC_WAN_AC
|
||||
$IPT -I SS_SPEC_WAN_AC -d $server -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set ss_spec_wan_ac dst -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
|
||||
|
||||
elif [ "$RUNMODE" = "gfw" ] ;then
|
||||
ipset -N gfwlist hash:net 2>/dev/null
|
||||
$IPT -N SS_SPEC_WAN_AC
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set gfwlist dst -j SS_SPEC_WAN_FW
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN
|
||||
$IPT -I SS_SPEC_WAN_AC -d $server -j RETURN
|
||||
|
||||
elif [ "$RUNMODE" = "oversea" ] ;then
|
||||
ipset -N oversea hash:net 2>/dev/null
|
||||
$IPT -N SS_SPEC_WAN_AC
|
||||
ipset -N gmlan hash:net 2>/dev/null
|
||||
for ip in $LAN_GM_IP; do ipset -! add gmlan $ip ; done
|
||||
$IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j SS_SPEC_WAN_FW
|
||||
$IPT -I SS_SPEC_WAN_AC -d $server -j RETURN
|
||||
|
||||
elif [ "$RUNMODE" = "all" ] ;then
|
||||
$IPT -N SS_SPEC_WAN_AC
|
||||
$IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
|
||||
$IPT -I SS_SPEC_WAN_AC -d $server -j RETURN
|
||||
|
||||
fi
|
||||
|
||||
ipset -N fplan hash:net 2>/dev/null
|
||||
for ip in $LAN_FP_IP; do ipset -! add fplan $ip ; done
|
||||
$IPT -I SS_SPEC_WAN_AC -m set --match-set fplan src -j SS_SPEC_WAN_FW
|
||||
|
||||
ipset -N whitelist hash:net 2>/dev/null
|
||||
ipset -N blacklist hash:net 2>/dev/null
|
||||
$IPT -I SS_SPEC_WAN_AC -m set --match-set blacklist dst -j SS_SPEC_WAN_FW
|
||||
$IPT -I SS_SPEC_WAN_AC -m set --match-set whitelist dst -j RETURN
|
||||
|
||||
for ip in $WAN_BP_IP; do ipset -! add whitelist $ip; done
|
||||
for ip in $WAN_FW_IP; do ipset -! add blacklist $ip; done
|
||||
|
||||
return $?
|
||||
}
|
||||
|
||||
fw_rule() {
|
||||
$IPT -N SS_SPEC_WAN_FW
|
||||
$IPT -A SS_SPEC_WAN_FW -d 0.0.0.0/8 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -d 10.0.0.0/8 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -d 127.0.0.0/8 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -d 169.254.0.0/16 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -d 172.16.0.0/12 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -d 192.168.0.0/16 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -d 224.0.0.0/4 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -d 240.0.0.0/4 -j RETURN
|
||||
$IPT -A SS_SPEC_WAN_FW -p tcp $PROXY_PORTS \
|
||||
-j REDIRECT --to-ports $local_port 2>/dev/null || {
|
||||
loger 3 "Can't redirect, please check the iptables."
|
||||
exit 1
|
||||
}
|
||||
return $?
|
||||
}
|
||||
|
||||
ac_rule() {
|
||||
if [ -n "$LAN_AC_IP" ]; then
|
||||
case "${LAN_AC_IP:0:1}" in
|
||||
w|W)
|
||||
MATCH_SET="-m set --match-set ss_spec_lan_ac src"
|
||||
;;
|
||||
b|B)
|
||||
MATCH_SET="-m set ! --match-set ss_spec_lan_ac src"
|
||||
;;
|
||||
*)
|
||||
loger 3 "Bad argument \`-a $LAN_AC_IP\`."
|
||||
return 2
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
IFNAME=$(uci get -P/var/state network.lan.ifname 2>/dev/null)
|
||||
ipset -! -R <<-EOF || return 1
|
||||
create ss_spec_lan_ac hash:net
|
||||
$(for ip in ${LAN_AC_IP:1}; do echo "add ss_spec_lan_ac $ip"; done)
|
||||
EOF
|
||||
$IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS $MATCH_SET \
|
||||
-m comment --comment "$TAG" -j SS_SPEC_WAN_AC
|
||||
if [ "$OUTPUT" = 1 ]; then
|
||||
$IPT -I OUTPUT 1 -p tcp $EXT_ARGS \
|
||||
-m comment --comment "$TAG" -j SS_SPEC_WAN_AC
|
||||
elif [ "$OUTPUT" = 2 ]; then
|
||||
ipset -! -R <<-EOF || return 1
|
||||
create ssr_gen_router hash:net
|
||||
$(gen_spec_iplist | sed -e "s/^/add ssr_gen_router /")
|
||||
EOF
|
||||
$IPT -N SS_SPEC_ROUTER && \
|
||||
$IPT -A SS_SPEC_ROUTER -m set --match-set ssr_gen_router dst -j RETURN && \
|
||||
$IPT -A SS_SPEC_ROUTER -j SS_SPEC_WAN_FW
|
||||
$IPT -I OUTPUT 1 -p tcp -m comment --comment "$TAG" -j SS_SPEC_ROUTER
|
||||
fi
|
||||
return $?
|
||||
}
|
||||
|
||||
tp_rule() {
|
||||
[ -n "$TPROXY" ] || return 0
|
||||
ip rule add fwmark 0x01/0x01 table 100
|
||||
ip route add local 0.0.0.0/0 dev lo table 100
|
||||
local ipt="iptables -t mangle"
|
||||
$ipt -N SS_SPEC_TPROXY
|
||||
$ipt -A SS_SPEC_TPROXY -p udp --dport 53 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d 0.0.0.0/8 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d 10.0.0.0/8 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d 127.0.0.0/8 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d 169.254.0.0/16 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d 172.16.0.0/12 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d 192.168.0.0/16 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d 224.0.0.0/4 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d 240.0.0.0/4 -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -d $SERVER -j RETURN
|
||||
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set fplan src \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
|
||||
if [ "$RUNMODE" = "router" ] ;then
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set ! --match-set ss_spec_wan_ac dst \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
|
||||
elif [ "$RUNMODE" = "gfw" ] ;then
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set china dst -j RETURN
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
$ipt -A SS_SPEC_TPROXY -p udp -m set $PROXY_PORTS --match-set gfwlist dst \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
|
||||
elif [ "$RUNMODE" = "oversea" ] ;then
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set china dst \
|
||||
-j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
|
||||
elif [ "$RUNMODE" = "all" ] ;then
|
||||
$ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
|
||||
fi
|
||||
|
||||
$ipt -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p udp $EXT_ARGS $MATCH_SET \
|
||||
-m comment --comment "$TAG" -j SS_SPEC_TPROXY
|
||||
|
||||
return $?
|
||||
}
|
||||
|
||||
get_wan_ip() {
|
||||
cat <<-EOF | grep -E "^([0-9]{1,3}\.){3}[0-9]{1,3}"
|
||||
$server
|
||||
$SERVER
|
||||
$WAN_BP_IP
|
||||
EOF
|
||||
}
|
||||
|
||||
gen_iplist() {
|
||||
cat <<-EOF
|
||||
0.0.0.0/8
|
||||
10.0.0.0/8
|
||||
100.64.0.0/10
|
||||
127.0.0.0/8
|
||||
169.254.0.0/16
|
||||
172.16.0.0/12
|
||||
192.0.0.0/24
|
||||
192.0.2.0/24
|
||||
192.88.99.0/24
|
||||
192.168.0.0/16
|
||||
198.18.0.0/15
|
||||
198.51.100.0/24
|
||||
203.0.113.0/24
|
||||
224.0.0.0/4
|
||||
240.0.0.0/4
|
||||
255.255.255.255
|
||||
$(get_wan_ip)
|
||||
$(cat ${IGNORE_LIST:=/dev/null} 2>/dev/null)
|
||||
EOF
|
||||
}
|
||||
|
||||
gen_spec_iplist() {
|
||||
cat <<-EOF
|
||||
0.0.0.0/8
|
||||
10.0.0.0/8
|
||||
100.64.0.0/10
|
||||
127.0.0.0/8
|
||||
169.254.0.0/16
|
||||
172.16.0.0/12
|
||||
192.0.0.0/24
|
||||
192.0.2.0/24
|
||||
192.88.99.0/24
|
||||
192.168.0.0/16
|
||||
198.18.0.0/15
|
||||
198.51.100.0/24
|
||||
203.0.113.0/24
|
||||
224.0.0.0/4
|
||||
240.0.0.0/4
|
||||
255.255.255.255
|
||||
$(get_wan_ip)
|
||||
EOF
|
||||
}
|
||||
|
||||
gen_include() {
|
||||
[ -n "$FWI" ] || return 0
|
||||
extract_rules() {
|
||||
echo "*$1"
|
||||
iptables-save -t $1 | grep SS_SPEC_ |\
|
||||
sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
|
||||
echo 'COMMIT'
|
||||
}
|
||||
cat <<-EOF >>$FWI
|
||||
iptables-save -c | grep -v "SS_SPEC" | iptables-restore -c
|
||||
iptables-restore -n <<-EOT
|
||||
$(extract_rules nat)
|
||||
$(extract_rules mangle)
|
||||
EOT
|
||||
EOF
|
||||
return 0
|
||||
}
|
||||
|
||||
while getopts ":s:l:S:L:i:e:a:b:w:p:G:D:oOuUfgrczh" arg; do
|
||||
case "$arg" in
|
||||
s)
|
||||
server=$OPTARG
|
||||
;;
|
||||
l)
|
||||
local_port=$OPTARG
|
||||
;;
|
||||
S)
|
||||
SERVER=$OPTARG
|
||||
;;
|
||||
L)
|
||||
LOCAL_PORT=$OPTARG
|
||||
;;
|
||||
i)
|
||||
IGNORE_LIST=$OPTARG
|
||||
;;
|
||||
e)
|
||||
EXT_ARGS=$OPTARG
|
||||
;;
|
||||
a)
|
||||
LAN_AC_IP=$OPTARG
|
||||
;;
|
||||
b)
|
||||
WAN_BP_IP=$(for ip in $OPTARG; do echo $ip; done)
|
||||
;;
|
||||
w)
|
||||
WAN_FW_IP=$OPTARG
|
||||
;;
|
||||
p)
|
||||
LAN_FP_IP=$OPTARG
|
||||
;;
|
||||
G)
|
||||
LAN_GM_IP=$OPTARG
|
||||
;;
|
||||
D)
|
||||
PROXY_PORTS=$OPTARG
|
||||
;;
|
||||
o)
|
||||
OUTPUT=1
|
||||
;;
|
||||
O)
|
||||
OUTPUT=2
|
||||
;;
|
||||
u)
|
||||
TPROXY=1
|
||||
;;
|
||||
U)
|
||||
TPROXY=2
|
||||
;;
|
||||
g)
|
||||
RUNMODE=gfw
|
||||
;;
|
||||
r)
|
||||
RUNMODE=router
|
||||
;;
|
||||
c)
|
||||
RUNMODE=oversea
|
||||
;;
|
||||
z)
|
||||
RUNMODE=all
|
||||
;;
|
||||
f)
|
||||
flush_r
|
||||
exit 0
|
||||
;;
|
||||
h)
|
||||
usage 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$server" -o -z "$local_port" ]; then
|
||||
usage 2
|
||||
fi
|
||||
|
||||
if [ "$TPROXY" = 1 ]; then
|
||||
SERVER=$server
|
||||
LOCAL_PORT=$local_port
|
||||
elif [ "$TPROXY" = 2 ]; then
|
||||
: ${SERVER:?"You must assign an ip for the udp relay server."}
|
||||
: ${LOCAL_PORT:?"You must assign a port for the udp relay server."}
|
||||
fi
|
||||
|
||||
flush_r && fw_rule && ipset_r && ac_rule && tp_rule && gen_include
|
||||
[ "$?" = 0 ] || loger 3 "Start failed!"
|
||||
exit $?
|
176
package/ctcgfw/luci-app-vssr/root/usr/bin/vssr-switch
Executable file
@ -0,0 +1,176 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
#
|
||||
# Copyright (C) 2017 openwrt-ssr
|
||||
# Copyright (C) 2017 yushi studio <ywb94@qq.com>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v3.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
cycle_time=60
|
||||
switch_time=3
|
||||
normal_flag=0
|
||||
server_locate=0
|
||||
server_count=0
|
||||
NAME=vssr
|
||||
ENABLE_SERVER=nil
|
||||
CONFIG_SWTICH_FILE=/var/etc/${NAME}_t.json
|
||||
|
||||
[ -n "$1" ] && cycle_time=$1
|
||||
[ -n "$2" ] && switch_time=$2
|
||||
|
||||
uci_get_by_name() {
|
||||
local ret=$(uci get $NAME.$1.$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
uci_get_by_type() {
|
||||
local ret=$(uci get $NAME.@$1[0].$2 2>/dev/null)
|
||||
echo ${ret:=$3}
|
||||
}
|
||||
|
||||
DEFAULT_SERVER=$(uci_get_by_type global global_server)
|
||||
CURRENT_SERVER=$DEFAULT_SERVER
|
||||
|
||||
#判断代理是否正常
|
||||
check_proxy() {
|
||||
local result=0
|
||||
local try_count=$(uci_get_by_type global switch_try_count 3)
|
||||
for i in $(seq 1 $try_count); do
|
||||
/usr/bin/ssr-check www.google.com 80 $switch_time 1
|
||||
if [ "$?" == "0" ]; then
|
||||
result=0
|
||||
break
|
||||
else
|
||||
/usr/bin/ssr-check www.baidu.com 80 $switch_time 1
|
||||
if [ "$?" == "0" ]; then
|
||||
result=1
|
||||
else
|
||||
result=2
|
||||
fi
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
return $result
|
||||
}
|
||||
|
||||
test_proxy() {
|
||||
local servername=$(uci_get_by_name $1 server)
|
||||
local serverport=$(uci_get_by_name $1 server_port)
|
||||
ret=$(ping -c 3 $servername | grep 'loss' | awk -F ',' '{ print $3 }' | awk -F "%" '{ print $1 }')
|
||||
[ -z "$ret" ] && return 1
|
||||
[ "$ret" -gt "50" ] && return 1
|
||||
ipset add ss_spec_wan_ac $servername 2>/dev/null
|
||||
ret=$?
|
||||
/usr/bin/ssr-check $servername $serverport $switch_time
|
||||
local ret2=$?
|
||||
if [ "$ret" = "0" ]; then
|
||||
ipset del ss_spec_wan_ac $servername 2>/dev/null
|
||||
fi
|
||||
if [ "$ret2" = "0" ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
search_proxy() {
|
||||
let server_count=server_count+1
|
||||
[ "$normal_flag" = "1" -a "$server_count" -le "$server_locate" ] && return 0
|
||||
[ "$(uci_get_by_name $1 switch_enable)" != "1" ] && return 1
|
||||
[ $ENABLE_SERVER != nil ] && return 0
|
||||
[ "$1" = "$CURRENT_SERVER" ] && return 0
|
||||
local servername=$(uci_get_by_name $1 server)
|
||||
local serverport=$(uci_get_by_name $1 server_port)
|
||||
ipset add ss_spec_wan_ac $servername 2>/dev/null
|
||||
ret=$?
|
||||
/usr/bin/ssr-check $servername $serverport $switch_time
|
||||
local ret2=$?
|
||||
if [ "$ret" = "0" ]; then
|
||||
ipset del ss_spec_wan_ac $servername 2>/dev/null
|
||||
fi
|
||||
if [ "$ret2" = "0" ]; then
|
||||
server_locate=$server_count
|
||||
ENABLE_SERVER=$1
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
#选择可用的代理
|
||||
select_proxy() {
|
||||
|
||||
config_load $NAME
|
||||
ENABLE_SERVER=nil
|
||||
mkdir -p /var/run /var/etc
|
||||
server_count=0
|
||||
config_foreach search_proxy servers
|
||||
|
||||
}
|
||||
|
||||
#切换代理
|
||||
switch_proxy() {
|
||||
/etc/init.d/vssr restart $1
|
||||
return 0
|
||||
}
|
||||
|
||||
start() {
|
||||
#不支持kcptun启用时的切换
|
||||
[ $(uci_get_by_name $DEFAULT_SERVER kcp_enable) = "1" ] && return 1
|
||||
|
||||
while [ "1" = "1" ]; do #死循环
|
||||
sleep $cycle_time
|
||||
|
||||
LOGTIME=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
|
||||
#判断当前代理是否为缺省服务器
|
||||
if [ "$CURRENT_SERVER" != "$DEFAULT_SERVER" ]; then
|
||||
#echo "not default proxy"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 当前为备用节点,尝试切换为主节点。" >>/tmp/vssr.log
|
||||
|
||||
#检查缺省服务器是否正常
|
||||
if test_proxy $DEFAULT_SERVER; then
|
||||
#echo "switch to default proxy"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 主节点不可用." >>/tmp/vssr.log
|
||||
#缺省服务器正常,切换回来
|
||||
CURRENT_SERVER=$DEFAULT_SERVER
|
||||
switch_proxy $CURRENT_SERVER
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 切换为默认节点 ["$(uci_get_by_name $CURRENT_SERVER server)"]" >>/tmp/vssr.log
|
||||
continue
|
||||
else
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 主节点不可用,继续使用当前备用节点。" >>/tmp/vssr.log
|
||||
fi
|
||||
fi
|
||||
|
||||
#判断当前代理是否正常
|
||||
check_proxy
|
||||
current_ret=$?
|
||||
|
||||
if [ "$current_ret" = "1" ]; then
|
||||
#当前代理错误,判断有无可用的服务器
|
||||
#echo "current error"
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 当前节点不可用,尝试切换其他节点。" >>/tmp/vssr.log
|
||||
|
||||
select_proxy
|
||||
if [ "$ENABLE_SERVER" != nil ]; then
|
||||
#有其他服务器可用,进行切换
|
||||
#echo $(uci_get_by_name $new_proxy server)
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 另外一个节点可用,即将切换节点。" >>/tmp/vssr.log
|
||||
CURRENT_SERVER=$ENABLE_SERVER
|
||||
switch_proxy $CURRENT_SERVER
|
||||
normal_flag=1
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 切换节点成功。" >>/tmp/vssr.log
|
||||
else
|
||||
switch_proxy $CURRENT_SERVER
|
||||
normal_flag=1
|
||||
echo "$(date "+%Y-%m-%d %H:%M:%S") 尝试重启当前节点。" >>/tmp/vssr.log
|
||||
fi
|
||||
else
|
||||
normal_flag=0
|
||||
#echo "$(date "+%Y-%m-%d %H:%M:%S") vssr No Problem." >> /tmp/vssr.log
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"luci-app-vssr": {
|
||||
"description": "Grant UCI access for luci-app-vssr",
|
||||
"read": {
|
||||
"uci": [ "vssr" ]
|
||||
},
|
||||
"write": {
|
||||
"uci": [ "vssr" ]
|
||||
}
|
||||
}
|
||||
}
|
BIN
package/ctcgfw/luci-app-vssr/root/usr/share/vssr/GeoLite2-Country.mmdb
Executable file
5
package/ctcgfw/luci-app-vssr/root/usr/share/vssr/chinaipset.sh
Executable file
@ -0,0 +1,5 @@
|
||||
echo "create china hash:net family inet hashsize 1024 maxelem 65536" > /tmp/china.ipset
|
||||
awk '!/^$/&&!/^#/{printf("add china %s'" "'\n",$0)}' /etc/china_ssr.txt >> /tmp/china.ipset
|
||||
ipset -! flush china
|
||||
ipset -! restore < /tmp/china.ipset 2>/dev/null
|
||||
rm -f /tmp/china.ipset
|
61
package/ctcgfw/luci-app-vssr/root/usr/share/vssr/genconfig_ss.lua
Executable file
@ -0,0 +1,61 @@
|
||||
local ucursor = require"luci.model.uci".cursor()
|
||||
local json = require "luci.jsonc"
|
||||
local server_section = arg[1]
|
||||
local proto = arg[2]
|
||||
local local_port = arg[3]
|
||||
local host = arg[4]
|
||||
|
||||
local server = ucursor:get_all("vssr", server_section)
|
||||
|
||||
local v2ray = {
|
||||
log = {
|
||||
-- error = "/var/ssrplus.log",
|
||||
loglevel = "info"
|
||||
},
|
||||
-- 传入连接
|
||||
inbound = {
|
||||
|
||||
port = local_port,
|
||||
protocol = "dokodemo-door",
|
||||
settings = {network = proto, followRedirect = true},
|
||||
sniffing = {enabled = true, destOverride = {"http", "tls"}}
|
||||
|
||||
},
|
||||
-- 传出连接
|
||||
outbounds = {
|
||||
{
|
||||
tag = "protocol_layer",
|
||||
protocol = "shadowsocks",
|
||||
settings = {
|
||||
servers = {
|
||||
{
|
||||
address = host,
|
||||
port = tonumber(server.server_port),
|
||||
method = server.encrypt_method_ss,
|
||||
password = server.password
|
||||
}
|
||||
}
|
||||
},
|
||||
proxySettings = {tag = "transport_layer"}
|
||||
}, {
|
||||
tag = "transport_layer",
|
||||
protocol = "freedom",
|
||||
settings = (server.obfs_host ~= nil) and{
|
||||
redirect = server.obfs_host .. ":" ..
|
||||
tonumber(server.server_port)
|
||||
} or nil,
|
||||
streamSettings = (server.obfs_transport ~= nil) and{
|
||||
network = server.obfs_transport,
|
||||
security = (server.obfs_opts == '1') and "tls" or "none",
|
||||
wsSettings = {
|
||||
path = server.obfs_path,
|
||||
headers = (server.obfs_host ~= nil) and {host = server.obfs_host} or nil
|
||||
}
|
||||
} or nil,
|
||||
mux = {enabled = (server.mux == "1") and true or false}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
print(json.stringify(v2ray, 1))
|
25
package/ctcgfw/luci-app-vssr/root/usr/share/vssr/genconfig_ssr.lua
Executable file
@ -0,0 +1,25 @@
|
||||
local ucursor = require "luci.model.uci".cursor()
|
||||
local json = require "luci.jsonc"
|
||||
local server_section = arg[1]
|
||||
local proto = arg[2]
|
||||
local local_port = arg[3]
|
||||
local host = arg[4]
|
||||
|
||||
local server = ucursor:get_all("vssr", server_section)
|
||||
|
||||
local ssr = {
|
||||
server = host,
|
||||
server_port = server.server_port,
|
||||
local_address = "0.0.0.0",
|
||||
local_port = local_port,
|
||||
password = server.password,
|
||||
timeout = (server.timeout ~= nil) and server.timeout or 60,
|
||||
method = server.encrypt_method,
|
||||
protocol = server.protocol,
|
||||
protocol_param = server.protocol_param,
|
||||
obfs = server.obfs,
|
||||
obfs_param = server.obfs_param,
|
||||
reuse_port = true,
|
||||
fast_open = (server.fast_open == "1") and true or false,
|
||||
}
|
||||
print(json.stringify(ssr, 1))
|
@ -0,0 +1,40 @@
|
||||
local ucursor = require "luci.model.uci".cursor()
|
||||
local json = require "luci.jsonc"
|
||||
local server_section = arg[1]
|
||||
local proto = arg[2]
|
||||
local local_port = arg[3]
|
||||
|
||||
local server = ucursor:get_all("vssr", server_section)
|
||||
|
||||
local trojan = {
|
||||
log_level = 3,
|
||||
run_type = proto,
|
||||
local_addr = "0.0.0.0",
|
||||
local_port = tonumber(local_port),
|
||||
remote_addr = server.server,
|
||||
remote_port = tonumber(server.server_port),
|
||||
udp_timeout = 60,
|
||||
-- 传入连接
|
||||
password = {server.password},
|
||||
-- 传出连接
|
||||
ssl = {
|
||||
verify = false,
|
||||
verify_hostname = (server.tls == "1") and false or true,
|
||||
cert = "",
|
||||
cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA",
|
||||
cipher_tls13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
|
||||
sni = server.peer,
|
||||
alpn = {"h2", "http/1.1"},
|
||||
curve = "",
|
||||
reuse_session = true,
|
||||
session_ticket = false,
|
||||
},
|
||||
tcp = {
|
||||
no_delay = true,
|
||||
keep_alive = true,
|
||||
reuse_port = true,
|
||||
fast_open = (server.fast_open == "1") and true or false,
|
||||
fast_open_qlen = 20
|
||||
}
|
||||
}
|
||||
print(json.stringify(trojan, 1))
|
176
package/ctcgfw/luci-app-vssr/root/usr/share/vssr/genconfig_v2ray.lua
Executable file
@ -0,0 +1,176 @@
|
||||
local ucursor = require"luci.model.uci".cursor()
|
||||
local name = "vssr"
|
||||
local json = require "luci.jsonc"
|
||||
local server_section = arg[1]
|
||||
local proto = arg[2]
|
||||
local local_port = arg[3]
|
||||
local host = arg[4]
|
||||
|
||||
local v2ray_flow = ucursor:get_first(name, 'global', 'v2ray_flow', '0')
|
||||
local youtube_server = ucursor:get_first(name, 'global', 'youtube_server')
|
||||
local tw_video_server = ucursor:get_first(name, 'global', 'tw_video_server')
|
||||
local netflix_server = ucursor:get_first(name, 'global', 'netflix_server')
|
||||
local disney_server = ucursor:get_first(name, 'global', 'disney_server')
|
||||
local prime_server = ucursor:get_first(name, 'global', 'prime_server')
|
||||
|
||||
function gen_outbound(server_node, tags)
|
||||
local bound = {}
|
||||
if server_node == "nil" then
|
||||
bound = nil
|
||||
else
|
||||
local server = ucursor:get_all(name, server_node)
|
||||
bound = {
|
||||
tag = tags,
|
||||
protocol = "vmess",
|
||||
settings = {
|
||||
vnext = {
|
||||
{
|
||||
address = server.server,
|
||||
port = tonumber(server.server_port),
|
||||
users = {
|
||||
{
|
||||
id = server.vmess_id,
|
||||
alterId = tonumber(server.alter_id),
|
||||
security = server.security
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
-- 底层传输配置
|
||||
streamSettings = {
|
||||
network = server.transport,
|
||||
security = (server.tls == '1') and "tls" or "none",
|
||||
tlsSettings = {
|
||||
allowInsecure = (server.insecure == "1") and true or false,
|
||||
serverName = server.ws_host
|
||||
},
|
||||
kcpSettings = (server.transport == "kcp") and {
|
||||
mtu = tonumber(server.mtu),
|
||||
tti = tonumber(server.tti),
|
||||
uplinkCapacity = tonumber(server.uplink_capacity),
|
||||
downlinkCapacity = tonumber(server.downlink_capacity),
|
||||
congestion = (server.congestion == "1") and true or false,
|
||||
readBufferSize = tonumber(server.read_buffer_size),
|
||||
writeBufferSize = tonumber(server.write_buffer_size),
|
||||
header = {type = server.kcp_guise}
|
||||
} or nil,
|
||||
wsSettings = (server.transport == "ws") and
|
||||
(server.ws_path ~= nil or server.ws_host ~= nil) and {
|
||||
path = server.ws_path,
|
||||
headers = (server.ws_host ~= nil) and
|
||||
{Host = server.ws_host} or nil
|
||||
} or nil,
|
||||
httpSettings = (server.transport == "h2") and
|
||||
{path = server.h2_path, host = server.h2_host} or nil,
|
||||
quicSettings = (server.transport == "quic") and {
|
||||
security = server.quic_security,
|
||||
key = server.quic_key,
|
||||
header = {type = server.quic_guise}
|
||||
} or nil
|
||||
},
|
||||
mux = {
|
||||
enabled = (server.mux == "1") and true or false,
|
||||
concurrency = tonumber(server.concurrency)
|
||||
}
|
||||
}
|
||||
end
|
||||
return bound
|
||||
end
|
||||
|
||||
local outbounds_table = {}
|
||||
|
||||
table.insert(outbounds_table, gen_outbound(server_section, "main"))
|
||||
if v2ray_flow == "1" then
|
||||
table.insert(outbounds_table, gen_outbound(youtube_server, "youtube"))
|
||||
table.insert(outbounds_table, gen_outbound(tw_video_server, "twvideo"))
|
||||
table.insert(outbounds_table, gen_outbound(netflix_server, "netflix"))
|
||||
table.insert(outbounds_table, gen_outbound(disney_server, "disney"))
|
||||
table.insert(outbounds_table, gen_outbound(prime_server, "prime"))
|
||||
end
|
||||
|
||||
-- rules gen
|
||||
|
||||
local youtube_rule = {
|
||||
type = "field",
|
||||
domain = {"youtube", "googlevideo.com", "gvt2.com", "youtu.be"},
|
||||
outboundTag = "youtube"
|
||||
}
|
||||
|
||||
local tw_video_rule = {
|
||||
type = "field",
|
||||
domain = {
|
||||
"vidol.tv", "hinet.net", "books.com", "litv.tv", "pstatic.net",
|
||||
"app-measurement.com", "kktv.com.tw", "gamer.com.tw","wetv.vip"
|
||||
},
|
||||
outboundTag = "twvideo"
|
||||
}
|
||||
|
||||
local netflix_rule = {
|
||||
type = "field",
|
||||
domain = {
|
||||
"netflix", "nflxso.net", "nflxext.com",
|
||||
"nflximg.com", "nflximg.net", "nflxvideo.net"
|
||||
},
|
||||
|
||||
outboundTag = "netflix"
|
||||
}
|
||||
|
||||
local disney_rule = {
|
||||
type = "field",
|
||||
domain = {
|
||||
"cdn.registerdisney.go.com", "disneyplus.com", "disney-plus.net",
|
||||
"dssott.com", "bamgrid.com", "execute-api.us-east-1.amazonaws.com"
|
||||
},
|
||||
outboundTag = "disney"
|
||||
}
|
||||
|
||||
local prime_rule = {
|
||||
type = "field",
|
||||
domain = {"aiv-cdn.net", "amazonaws.com", "amazonvideo.com", "llnwd.net"},
|
||||
outboundTag = "prime"
|
||||
}
|
||||
|
||||
local rules_table = {}
|
||||
|
||||
if (youtube_server ~= "nil" and v2ray_flow == "1") then
|
||||
table.insert(rules_table, youtube_rule)
|
||||
end
|
||||
|
||||
if (tw_video_server ~= "nil" and v2ray_flow == "1") then
|
||||
table.insert(rules_table, tw_video_rule)
|
||||
end
|
||||
|
||||
if (netflix_server ~= "nil" and v2ray_flow == "1") then
|
||||
table.insert(rules_table, netflix_rule)
|
||||
end
|
||||
|
||||
if (disney_server ~= "nil" and v2ray_flow == "1") then
|
||||
table.insert(rules_table, disney_rule)
|
||||
end
|
||||
|
||||
if (prime_server ~= "nil" and v2ray_flow == "1") then
|
||||
table.insert(rules_table, prime_rule)
|
||||
end
|
||||
|
||||
local v2ray = {
|
||||
log = {
|
||||
-- error = "/var/ssrplus.log",
|
||||
-- access = "/var/v2rays.log",
|
||||
loglevel = "warning"
|
||||
},
|
||||
-- 传入连接
|
||||
inbounds = {
|
||||
{
|
||||
port = local_port,
|
||||
protocol = "dokodemo-door",
|
||||
settings = {network = proto, followRedirect = true},
|
||||
sniffing = {enabled = true, destOverride = {"http", "tls"}}
|
||||
}
|
||||
|
||||
},
|
||||
-- 传出连接
|
||||
outbounds = outbounds_table,
|
||||
routing = {domainStrategy = "IPIfNonMatch", rules = rules_table}
|
||||
}
|
||||
print(json.stringify(v2ray, 1))
|
42
package/ctcgfw/luci-app-vssr/root/usr/share/vssr/genconfig_v2ray_s.lua
Executable file
@ -0,0 +1,42 @@
|
||||
local ucursor = require "luci.model.uci".cursor()
|
||||
local name = "vssr"
|
||||
local json = require "luci.jsonc"
|
||||
local proto = "socks"
|
||||
local auth_type = ucursor:get_first(name, 'socks5_proxy', 'enable_auth')
|
||||
local local_port = ucursor:get_first(name, 'socks5_proxy', 'local_port')
|
||||
local Socks_user = ucursor:get_first(name, 'socks5_proxy', 'Socks_user')
|
||||
local Socks_pass = ucursor:get_first(name, 'socks5_proxy', 'Socks_pass')
|
||||
|
||||
|
||||
local v2ray = {
|
||||
log = {
|
||||
--error = "/var/log/v2ray.log",
|
||||
loglevel = "warning"
|
||||
},
|
||||
-- 传入连接
|
||||
inbound = {
|
||||
port = local_port,
|
||||
protocol = proto,
|
||||
settings = {
|
||||
auth = (auth_type == '1') and "password" or "noauth",
|
||||
accounts =(auth_type == "1") and {
|
||||
{
|
||||
user = (auth_type == '1') and Socks_user,
|
||||
pass = Socks_pass
|
||||
}
|
||||
} or nil,
|
||||
}
|
||||
},
|
||||
-- 传出连接
|
||||
outbound = {
|
||||
protocol = "freedom"
|
||||
},
|
||||
-- 额外传出连接
|
||||
outboundDetour = {
|
||||
{
|
||||
protocol = "blackhole",
|
||||
tag = "blocked"
|
||||
}
|
||||
}
|
||||
}
|
||||
print(json.stringify(v2ray,1))
|
37
package/ctcgfw/luci-app-vssr/root/usr/share/vssr/getflag.sh
Executable file
@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
# Copyright (C) 2019 Jerryk <jerrykuku@qq.com>
|
||||
lua=/usr/bin/lua
|
||||
name="$1"
|
||||
host=$2
|
||||
code=''
|
||||
iso_array=(AC AD AE AF AG AI AL AM AO AQ AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BL BM BN BO BQ BR BS BT BV BW BY BZ CA CC CD CF CG CH CI CK CL CM CN CO CP CR CU CV CW CX CY CZ DE DG DJ DK DM DO DZ EA EC EE EG EH ER ES ET EU FI FJ FK FM FO FR GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GS GT GU GW GY HK HM HN HR HT HU IC ID IE IL IM IN IO IQ IR IS IT JE JM JO JP KE KG KH KI KM KN KP KR KW KY KZ LA LB LC LI LK LR LS LT LU LV LY MA MC MD ME MF MG MH MK ML MM MN MO MP MQ MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI NL NO NP NR NU NZ OM PA PE PF PG PH PK PL PM PN PR PS PT PW PY QA RE RO RS RU RW SA SB SC SD SE SG SH SI SJ SK SL SM SN SO SR SS ST SV SX SY SZ TA TC TD TF TG TH TJ TK TL TM TN TO TR TT TV TW TZ UA UG UM UN US UY UZ VA VC VE VG VI VN VU WF WS XK YE YT ZA ZM ZW US HK TW JP GB GB DE FR IN TR SG KR RU IE)
|
||||
|
||||
emoji_array=(🇦🇨 🇦🇩 🇦🇪 🇦🇫 🇦🇬 🇦🇮 🇦🇱 🇦🇲 🇦🇴 🇦🇶 🇦🇷 🇦🇸 🇦🇹 🇦🇺 🇦🇼 🇦🇽 🇦🇿 🇧🇦 🇧🇧 🇧🇩 🇧🇪 🇧🇫 🇧🇬 🇧🇭 🇧🇮 🇧🇯 🇧🇱 🇧🇲 🇧🇳 🇧🇴 🇧🇶 🇧🇷 🇧🇸 🇧🇹 🇧🇻 🇧🇼 🇧🇾 🇧🇿 🇨🇦 🇨🇨 🇨🇩 🇨🇫 🇨🇬 🇨🇭 🇨🇮 🇨🇰 🇨🇱 🇨🇲 🇨🇳 🇨🇴 🇨🇵 🇨🇷 🇨🇺 🇨🇻 🇨🇼 🇨🇽 🇨🇾 🇨🇿 🇩🇪 🇩🇬 🇩🇯 🇩🇰 🇩🇲 🇩🇴 🇩🇿 🇪🇦 🇪🇨 🇪🇪 🇪🇬 🇪🇭 🇪🇷 🇪🇸 🇪🇹 🇪🇺 🇫🇮 🇫🇯 🇫🇰 🇫🇲 🇫🇴 🇫🇷 🇬🇦 🇬🇧 🇬🇩 🇬🇪 🇬🇫 🇬🇬 🇬🇭 🇬🇮 🇬🇱 🇬🇲 🇬🇳 🇬🇵 🇬🇶 🇬🇷 🇬🇸 🇬🇹 🇬🇺 🇬🇼 🇬🇾 🇭🇰 🇭🇲 🇭🇳 🇭🇷 🇭🇹 🇭🇺 🇮🇨 🇮🇩 🇮🇪 🇮🇱 🇮🇲 🇮🇳 🇮🇴 🇮🇶 🇮🇷 🇮🇸 🇮🇹 🇯🇪 🇯🇲 🇯🇴 🇯🇵 🇰🇪 🇰🇬 🇰🇭 🇰🇮 🇰🇲 🇰🇳 🇰🇵 🇰🇷 🇰🇼 🇰🇾 🇰🇿 🇱🇦 🇱🇧 🇱🇨 🇱🇮 🇱🇰 🇱🇷 🇱🇸 🇱🇹 🇱🇺 🇱🇻 🇱🇾 🇲🇦 🇲🇨 🇲🇩 🇲🇪 🇲🇫 🇲🇬 🇲🇭 🇲🇰 🇲🇱 🇲🇲 🇲🇳 🇲🇴 🇲🇵 🇲🇶 🇲🇷 🇲🇸 🇲🇹 🇲🇺 🇲🇻 🇲🇼 🇲🇽 🇲🇾 🇲🇿 🇳🇦 🇳🇨 🇳🇪 🇳🇫 🇳🇬 🇳🇮 🇳🇱 🇳🇴 🇳🇵 🇳🇷 🇳🇺 🇳🇿 🇴🇲 🇵🇦 🇵🇪 🇵🇫 🇵🇬 🇵🇭 🇵🇰 🇵🇱 🇵🇲 🇵🇳 🇵🇷 🇵🇸 🇵🇹 🇵🇼 🇵🇾 🇶🇦 🇷🇪 🇷🇴 🇷🇸 🇷🇺 🇷🇼 🇸🇦 🇸🇧 🇸🇨 🇸🇩 🇸🇪 🇸🇬 🇸🇭 🇸🇮 🇸🇯 🇸🇰 🇸🇱 🇸🇲 🇸🇳 🇸🇴 🇸🇷 🇸🇸 🇸🇹 🇸🇻 🇸🇽 🇸🇾 🇸🇿 🇹🇦 🇹🇨 🇹🇩 🇹🇫 🇹🇬 🇹🇭 🇹🇯 🇹🇰 🇹🇱 🇹🇲 🇹🇳 🇹🇴 🇹🇷 🇹🇹 🇹🇻 🇹🇼 🇹🇿 🇺🇦 🇺🇬 🇺🇲 🇺🇳 🇺🇸 🇺🇾 🇺🇿 🇻🇦 🇻🇨 🇻🇪 🇻🇬 🇻🇮 🇻🇳 🇻🇺 🇼🇫 🇼🇸 🇽🇰 🇾🇪 🇾🇹 🇿🇦 🇿🇲 🇿🇼 美国 香港 台湾 日本 英国 UK 德国 法国 印度 土耳其 新加坡 韩国 俄罗斯 爱尔兰)
|
||||
|
||||
|
||||
for i in "${!emoji_array[@]}"; do
|
||||
if [[ $name == *${emoji_array[$i]}* ]]; then
|
||||
code=${iso_array[$i]}
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -z $code ]; then
|
||||
echo $code | tr "[A-Z]" "[a-z]"
|
||||
else
|
||||
|
||||
|
||||
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}
|
||||
else
|
||||
hostip=$(nslookup ${host} | grep 'Address 1' | sed 's/Address 1: //g')
|
||||
if echo $hostip | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$" >/dev/null; then
|
||||
hostip=${hostip}
|
||||
else
|
||||
hostip=$(cat /etc/ssr_ip)
|
||||
fi
|
||||
fi
|
||||
lua /usr/share/vssr/iso_code.lua $hostip
|
||||
fi
|
11
package/ctcgfw/luci-app-vssr/root/usr/share/vssr/gfw2ipset.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
mkdir -p /tmp/dnsmasq.ssr
|
||||
|
||||
awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"gfwlist"'\n",$0)}' /etc/config/gfw.list > /tmp/dnsmasq.ssr/custom_forward.conf
|
||||
awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#5335"'\n",$0)}' /etc/config/gfw.list >> /tmp/dnsmasq.ssr/custom_forward.conf
|
||||
|
||||
awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"blacklist"'\n",$0)}' /etc/config/black.list > /tmp/dnsmasq.ssr/blacklist_forward.conf
|
||||
awk '!/^$/&&!/^#/{printf("server=/.%s/'"127.0.0.1#5335"'\n",$0)}' /etc/config/black.list >> /tmp/dnsmasq.ssr/blacklist_forward.conf
|
||||
|
||||
awk '!/^$/&&!/^#/{printf("ipset=/.%s/'"whitelist"'\n",$0)}' /etc/config/white.list > /tmp/dnsmasq.ssr/whitelist_forward.conf
|
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/lua
|
||||
------------------------------------------------
|
||||
-- This file is converter ip to country iso code
|
||||
-- @author Jerryk <jerrykuku@qq.com>
|
||||
------------------------------------------------
|
||||
|
||||
local mm = require 'maxminddb'
|
||||
local db = mm.open('/usr/share/vssr/GeoLite2-Country.mmdb')
|
||||
local res = db:lookup(arg[1])
|
||||
print(string.lower(res:get("country", "iso_code")))
|
434
package/ctcgfw/luci-app-vssr/root/usr/share/vssr/subscribe.lua
Normal file
@ -0,0 +1,434 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
------------------------------------------------
|
||||
-- This file is part of the luci-app-ssr-plus subscribe.lua
|
||||
-- @author William Chan <root@williamchan.me>
|
||||
------------------------------------------------
|
||||
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 luci = luci
|
||||
local tinsert = table.insert
|
||||
local ssub, slen, schar, sbyte, sformat, sgsub = string.sub, string.len,
|
||||
string.char, string.byte,
|
||||
string.format, string.gsub
|
||||
local jsonParse, jsonStringify = luci.jsonc.parse, luci.jsonc.stringify
|
||||
local b64decode = nixio.bin.b64decode
|
||||
local cache = {}
|
||||
local nodeResult = setmetatable({}, {__index = cache}) -- update result
|
||||
local name = 'vssr'
|
||||
local uciType = 'servers'
|
||||
local ucic = luci.model.uci.cursor()
|
||||
local proxy = ucic:get_first(name, 'server_subscribe', 'proxy', '0')
|
||||
local switch = '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 nStart, 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, nStart - 1))
|
||||
off = nEnd + 1
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
-- urlencode
|
||||
local function get_urlencode(c) return sformat("%%%02X", sbyte(c)) end
|
||||
|
||||
local function urlEncode(szText)
|
||||
local str = szText:gsub("([^0-9a-zA-Z ])", get_urlencode)
|
||||
str = str:gsub(" ", "+")
|
||||
return str
|
||||
end
|
||||
|
||||
local function get_urldecode(h) return schar(tonumber(h, 16)) end
|
||||
local function UrlDecode(szText)
|
||||
return szText:gsub("+", " "):gsub("%%(%x%x)", get_urldecode)
|
||||
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)
|
||||
local raw = text
|
||||
if not text then return '' end
|
||||
text = text:gsub("%z", "")
|
||||
text = text:gsub("_", "/")
|
||||
text = text:gsub("-", "+")
|
||||
local mod4 = #text % 4
|
||||
text = text .. string.sub('====', mod4 + 1)
|
||||
local result = b64decode(text)
|
||||
if result then
|
||||
return result:gsub("%z", "")
|
||||
else
|
||||
return raw
|
||||
end
|
||||
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'
|
||||
}
|
||||
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])
|
||||
local params = {}
|
||||
for _, v in pairs(split(dat[2], '&')) do
|
||||
local t = split(v, '=')
|
||||
params[t[1]] = t[2]
|
||||
end
|
||||
result.obfs_param = base64Decode(params.obfsparam)
|
||||
result.protocol_param = base64Decode(params.protoparam)
|
||||
local group = base64Decode(params.group)
|
||||
if group then result.alias = "[" .. group .. "] " end
|
||||
result.alias = result.alias .. base64Decode(params.remarks)
|
||||
elseif szType == 'vmess' then
|
||||
local info = jsonParse(content)
|
||||
result.type = 'v2ray'
|
||||
result.server = info.add
|
||||
result.server_port = info.port
|
||||
result.transport = info.net
|
||||
result.alter_id = info.aid
|
||||
result.vmess_id = info.id
|
||||
result.alias = info.ps
|
||||
-- result.mux = 1
|
||||
-- result.concurrency = 8
|
||||
if info.net == 'ws' then
|
||||
result.ws_host = info.host
|
||||
result.ws_path = info.path
|
||||
end
|
||||
if info.net == 'h2' then
|
||||
result.h2_host = info.host
|
||||
result.h2_path = info.path
|
||||
end
|
||||
if info.net == 'tcp' then
|
||||
result.tcp_guise = info.type
|
||||
result.http_host = info.host
|
||||
result.http_path = info.path
|
||||
end
|
||||
if info.net == 'kcp' then
|
||||
result.kcp_guise = info.type
|
||||
result.mtu = 1350
|
||||
result.tti = 50
|
||||
result.uplink_capacity = 5
|
||||
result.downlink_capacity = 20
|
||||
result.read_buffer_size = 2
|
||||
result.write_buffer_size = 2
|
||||
end
|
||||
if info.net == 'quic' then
|
||||
result.quic_guise = info.type
|
||||
result.quic_key = info.key
|
||||
result.quic_security = info.securty
|
||||
end
|
||||
if info.security then result.security = info.security end
|
||||
if info.tls == "tls" or info.tls == "1" then
|
||||
result.tls = "1"
|
||||
result.tls_host = info.host
|
||||
else
|
||||
result.tls = "0"
|
||||
end
|
||||
elseif szType == "ss" then
|
||||
local idx_sp = 0
|
||||
local alias = ""
|
||||
if content:find("#") then
|
||||
idx_sp = content:find("#")
|
||||
alias = content:sub(idx_sp + 1, -1)
|
||||
end
|
||||
local info = content:sub(1, idx_sp - 1)
|
||||
local hostInfo = split(base64Decode(info), "@")
|
||||
local host = split(hostInfo[2], ":")
|
||||
local userinfo = base64Decode(hostInfo[1])
|
||||
local method = userinfo:sub(1, userinfo:find(":") - 1)
|
||||
local password = userinfo:sub(userinfo:find(":") + 1, #userinfo)
|
||||
result.alias = UrlDecode(alias)
|
||||
result.type = "ss"
|
||||
result.server = host[1]
|
||||
if host[2]:find("/%?") then
|
||||
local query = split(host[2], "/%?")
|
||||
result.server_port = query[1]
|
||||
local params = {}
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local t = split(v, '=')
|
||||
params[t[1]] = t[2]
|
||||
end
|
||||
if params.plugin then
|
||||
local plugin_info = UrlDecode(params.plugin)
|
||||
local idx_pn = plugin_info:find(";")
|
||||
if idx_pn then
|
||||
result.plugin = plugin_info:sub(1, idx_pn - 1)
|
||||
result.plugin_opts =
|
||||
plugin_info:sub(idx_pn + 1, #plugin_info)
|
||||
else
|
||||
result.plugin = plugin_info
|
||||
end
|
||||
end
|
||||
else
|
||||
result.server_port = host[2]
|
||||
end
|
||||
result.encrypt_method_ss = method
|
||||
result.password = password
|
||||
|
||||
elseif szType == "trojan" then
|
||||
local idx_sp = 0
|
||||
local alias = ""
|
||||
if content:find("#") then
|
||||
idx_sp = content:find("#")
|
||||
alias = content:sub(idx_sp + 1, -1)
|
||||
end
|
||||
local info = content:sub(1, idx_sp - 1)
|
||||
local hostInfo = split(info, "@")
|
||||
local host = split(hostInfo[2], ":")
|
||||
local password = hostInfo[1]
|
||||
result.alias = UrlDecode(alias)
|
||||
result.type = "trojan"
|
||||
result.server = host[1]
|
||||
if host[2]:find("?") then
|
||||
local query = split(host[2], "?")
|
||||
result.server_port = query[1]
|
||||
local params = {}
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local t = split(v, '=')
|
||||
if t[1] == 'peer' then
|
||||
result.peer = t[2]
|
||||
result.tls = "1"
|
||||
end
|
||||
end
|
||||
else
|
||||
result.server_port = host[2]
|
||||
end
|
||||
result.password = password
|
||||
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.plugin = content.plugin
|
||||
result.plugin_opts = content.plugin_options
|
||||
result.alias = "[" .. content.airport .. "] " .. content.remarks
|
||||
end
|
||||
if not result.alias then
|
||||
result.alias = result.server .. ':' .. result.server_port
|
||||
end
|
||||
-- alias 不参与 hashkey 计算
|
||||
local alias = result.alias
|
||||
result.alias = nil
|
||||
local switch_enable = result.switch_enable
|
||||
result.switch_enable = nil
|
||||
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 .. '"')
|
||||
return trim(stdout)
|
||||
end
|
||||
|
||||
local execute = function()
|
||||
-- exec
|
||||
do
|
||||
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 nodes, szType
|
||||
local groupHash = md5(url)
|
||||
cache[groupHash] = {}
|
||||
tinsert(nodeResult, {})
|
||||
local index = #nodeResult
|
||||
-- SSD 似乎是这种格式 ssd:// 开头的
|
||||
if raw:find('ssd://') then
|
||||
szType = 'ssd'
|
||||
local nEnd = select(2, raw:find('ssd://'))
|
||||
nodes = base64Decode(raw:sub(nEnd + 1, #raw))
|
||||
nodes = jsonParse(nodes)
|
||||
local extra = {
|
||||
airport = nodes.airport,
|
||||
port = nodes.port,
|
||||
encryption = nodes.encryption,
|
||||
password = nodes.password
|
||||
}
|
||||
local servers = {}
|
||||
-- SS里面包着 干脆直接这样
|
||||
for _, server in ipairs(nodes.servers) do
|
||||
tinsert(servers, setmetatable(server, {__index = extra}))
|
||||
end
|
||||
nodes = servers
|
||||
else
|
||||
-- ssd 外的格式
|
||||
nodes = split(base64Decode(raw):gsub(" ", "\n"), "\n")
|
||||
end
|
||||
for _, v in ipairs(nodes) do
|
||||
if v then
|
||||
local result
|
||||
if szType == 'ssd' then
|
||||
result = processData(szType, v)
|
||||
elseif not szType then
|
||||
local node = trim(v)
|
||||
local dat = split(node, "://")
|
||||
if dat and dat[1] and dat[2] then
|
||||
if dat[1] == 'ss' then
|
||||
result = processData(dat[1], dat[2])
|
||||
else
|
||||
result =
|
||||
processData(dat[1], base64Decode(dat[2]))
|
||||
end
|
||||
end
|
||||
else
|
||||
log('跳过未知类型: ' .. szType)
|
||||
end
|
||||
-- log(result)
|
||||
if result then
|
||||
if result.alias:find("过期时间") or
|
||||
result.alias:find("剩余流量") or
|
||||
result.alias:find("QQ群") or
|
||||
result.alias:find("官网") or not result.server then
|
||||
log('丢弃无效节点: ' .. result.type ..
|
||||
' 节点, ' .. result.alias)
|
||||
else
|
||||
log('成功解析: ' .. result.type ..
|
||||
' 节点, ' .. result.alias)
|
||||
result.grouphashkey = groupHash
|
||||
tinsert(nodeResult[index], result)
|
||||
cache[groupHash][result.hashkey] =
|
||||
nodeResult[index][#nodeResult[index]]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
log('成功解析节点数量: ' .. #nodes)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- diff
|
||||
do
|
||||
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 的不参与删除
|
||||
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
|
||||
if (old.alias ~= nil) then
|
||||
log('忽略手动添加的节点: ' .. old.alias)
|
||||
else
|
||||
log('忽略手动添加的无效节点')
|
||||
end
|
||||
|
||||
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)
|
||||
ucic:set(name, section, "switch_enable", switch)
|
||||
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('更新成功服务正在启动')
|
||||
log("END SUBSCRIBE")
|
||||
end
|
||||
end
|
||||
|
||||
if subscribe_url and #subscribe_url > 0 then
|
||||
xpcall(execute, function(e)
|
||||
log(e)
|
||||
log(debug.traceback())
|
||||
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 &") -- 不加&的话日志会出现的更早
|
||||
else
|
||||
luci.sys.call("/etc/init.d/" .. name .. " stop > /dev/null 2>&1 &") -- 不加&的话日志会出现的更早
|
||||
end
|
||||
end)
|
||||
end
|
107
package/ctcgfw/luci-app-vssr/root/usr/share/vssr/update.lua
Normal file
@ -0,0 +1,107 @@
|
||||
#!/usr/bin/lua
|
||||
------------------------------------------------
|
||||
-- This file is part of the luci-app-ssr-plus update.lua
|
||||
-- By Mattraks
|
||||
------------------------------------------------
|
||||
require 'nixio'
|
||||
require 'luci.util'
|
||||
require 'luci.jsonc'
|
||||
require 'luci.sys'
|
||||
local icount =0
|
||||
local ucic = luci.model.uci.cursor()
|
||||
|
||||
local log = function(...)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S ") .. table.concat({ ... }, " "))
|
||||
end
|
||||
|
||||
log('正在更新【GFW列表】数据库')
|
||||
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"
|
||||
else
|
||||
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/vssr-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))
|
||||
log('更新成功! 新的总纪录数:'.. icount)
|
||||
else
|
||||
log('你已经是最新数据,无需更新!')
|
||||
end
|
||||
else
|
||||
log('更新失败!')
|
||||
end
|
||||
luci.sys.exec("rm -f /tmp/gfwnew.txt")
|
||||
else
|
||||
log('更新失败!')
|
||||
end
|
||||
|
||||
log('正在更新【国内IP段】数据库')
|
||||
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 then
|
||||
icount = luci.sys.exec("cat /tmp/china_ssr.txt | wc -l")
|
||||
if 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(math.ceil(tonumber(icount)/2))
|
||||
log('更新成功! 新的总纪录数:'.. icount)
|
||||
else
|
||||
log('你已经是最新数据,无需更新!')
|
||||
end
|
||||
else
|
||||
log('更新失败!')
|
||||
end
|
||||
luci.sys.exec("rm -f /tmp/china_ssr.txt")
|
||||
else
|
||||
log('更新失败!')
|
||||
end
|
||||
|
||||
-- --[[
|
||||
if ucic:get_first('vssr', 'global', 'adblock', '') == '1' then
|
||||
log('正在更新【广告屏蔽】数据库')
|
||||
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"
|
||||
end
|
||||
sret=luci.sys.call(refresh_cmd .. " 2>/dev/null")
|
||||
if sret== 0 then
|
||||
if need_process == 1 then
|
||||
luci.sys.call("/usr/bin/vssr-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
|
||||
log('更新成功! 新的总纪录数:'.. icount)
|
||||
else
|
||||
log('你已经是最新数据,无需更新!')
|
||||
end
|
||||
else
|
||||
log('更新失败!')
|
||||
end
|
||||
luci.sys.exec("rm -f /tmp/ad.conf")
|
||||
else
|
||||
log('更新失败!')
|
||||
end
|
||||
end
|
||||
-- --]]
|
1
package/ctcgfw/luci-app-vssr/root/www/luci-static/vssr/css/flag-icon.min.css
vendored
Normal file
@ -0,0 +1,700 @@
|
||||
@import url("flag-icon.min.css");
|
||||
|
||||
/*!
|
||||
Pure v1.0.1
|
||||
Copyright 2013 Yahoo!
|
||||
Licensed under the BSD License.
|
||||
https://github.com/pure-css/pure/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
|
||||
.pure-g {
|
||||
letter-spacing: -.31em;
|
||||
text-rendering: optimizespeed;
|
||||
font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-webkit-flex-flow: row wrap;
|
||||
-ms-flex-flow: row wrap;
|
||||
flex-flow: row wrap;
|
||||
-webkit-align-content: flex-start;
|
||||
-ms-flex-line-pack: start;
|
||||
align-content: flex-start
|
||||
}
|
||||
|
||||
@media all and (-ms-high-contrast:none),
|
||||
(-ms-high-contrast:active) {
|
||||
table .pure-g {
|
||||
display: block
|
||||
}
|
||||
}
|
||||
|
||||
.opera-only :-o-prefocus,
|
||||
.pure-g {
|
||||
word-spacing: -.43em
|
||||
}
|
||||
|
||||
.pure-u {
|
||||
display: inline-block;
|
||||
zoom: 1;
|
||||
letter-spacing: normal;
|
||||
word-spacing: normal;
|
||||
vertical-align: top;
|
||||
text-rendering: auto
|
||||
}
|
||||
|
||||
.pure-g [class*=pure-u] {
|
||||
font-family: sans-serif
|
||||
}
|
||||
|
||||
.pure-u-1,
|
||||
.pure-u-1-1,
|
||||
.pure-u-1-12,
|
||||
.pure-u-1-2,
|
||||
.pure-u-1-24,
|
||||
.pure-u-1-3,
|
||||
.pure-u-1-4,
|
||||
.pure-u-1-5,
|
||||
.pure-u-1-6,
|
||||
.pure-u-1-8,
|
||||
.pure-u-10-24,
|
||||
.pure-u-11-12,
|
||||
.pure-u-11-24,
|
||||
.pure-u-12-24,
|
||||
.pure-u-13-24,
|
||||
.pure-u-14-24,
|
||||
.pure-u-15-24,
|
||||
.pure-u-16-24,
|
||||
.pure-u-17-24,
|
||||
.pure-u-18-24,
|
||||
.pure-u-19-24,
|
||||
.pure-u-2-24,
|
||||
.pure-u-2-3,
|
||||
.pure-u-2-5,
|
||||
.pure-u-20-24,
|
||||
.pure-u-21-24,
|
||||
.pure-u-22-24,
|
||||
.pure-u-23-24,
|
||||
.pure-u-24-24,
|
||||
.pure-u-3-24,
|
||||
.pure-u-3-4,
|
||||
.pure-u-3-5,
|
||||
.pure-u-3-8,
|
||||
.pure-u-4-24,
|
||||
.pure-u-4-5,
|
||||
.pure-u-5-12,
|
||||
.pure-u-5-24,
|
||||
.pure-u-5-5,
|
||||
.pure-u-5-6,
|
||||
.pure-u-5-8,
|
||||
.pure-u-6-24,
|
||||
.pure-u-7-12,
|
||||
.pure-u-7-24,
|
||||
.pure-u-7-8,
|
||||
.pure-u-8-24,
|
||||
.pure-u-9-24 {
|
||||
display: inline-block;
|
||||
zoom: 1;
|
||||
letter-spacing: normal;
|
||||
word-spacing: normal;
|
||||
vertical-align: top;
|
||||
text-rendering: auto
|
||||
}
|
||||
|
||||
.pure-u-1-24 {
|
||||
width: 4.1667%
|
||||
}
|
||||
|
||||
.pure-u-1-12,
|
||||
.pure-u-2-24 {
|
||||
width: 8.3333%
|
||||
}
|
||||
|
||||
.pure-u-1-8,
|
||||
.pure-u-3-24 {
|
||||
width: 12.5%
|
||||
}
|
||||
|
||||
.pure-u-1-6,
|
||||
.pure-u-4-24 {
|
||||
width: 16.6667%
|
||||
}
|
||||
|
||||
.pure-u-1-5 {
|
||||
width: 20%
|
||||
}
|
||||
|
||||
.pure-u-5-24 {
|
||||
width: 20.8333%
|
||||
}
|
||||
|
||||
.pure-u-1-4,
|
||||
.pure-u-6-24 {
|
||||
width: 25%
|
||||
}
|
||||
|
||||
.pure-u-7-24 {
|
||||
width: 29.1667%
|
||||
}
|
||||
|
||||
.pure-u-1-3,
|
||||
.pure-u-8-24 {
|
||||
width: 33.3333%
|
||||
}
|
||||
|
||||
.pure-u-3-8,
|
||||
.pure-u-9-24 {
|
||||
width: 37.5%
|
||||
}
|
||||
|
||||
.pure-u-2-5 {
|
||||
width: 40%
|
||||
}
|
||||
|
||||
.pure-u-10-24,
|
||||
.pure-u-5-12 {
|
||||
width: 41.6667%
|
||||
}
|
||||
|
||||
.pure-u-11-24 {
|
||||
width: 45.8333%
|
||||
}
|
||||
|
||||
.pure-u-1-2,
|
||||
.pure-u-12-24 {
|
||||
width: 50%
|
||||
}
|
||||
|
||||
.pure-u-13-24 {
|
||||
width: 54.1667%
|
||||
}
|
||||
|
||||
.pure-u-14-24,
|
||||
.pure-u-7-12 {
|
||||
width: 58.3333%
|
||||
}
|
||||
|
||||
.pure-u-3-5 {
|
||||
width: 60%
|
||||
}
|
||||
|
||||
.pure-u-15-24,
|
||||
.pure-u-5-8 {
|
||||
width: 62.5%
|
||||
}
|
||||
|
||||
.pure-u-16-24,
|
||||
.pure-u-2-3 {
|
||||
width: 66.6667%
|
||||
}
|
||||
|
||||
.pure-u-17-24 {
|
||||
width: 70.8333%
|
||||
}
|
||||
|
||||
.pure-u-18-24,
|
||||
.pure-u-3-4 {
|
||||
width: 75%
|
||||
}
|
||||
|
||||
.pure-u-19-24 {
|
||||
width: 79.1667%
|
||||
}
|
||||
|
||||
.pure-u-4-5 {
|
||||
width: 80%
|
||||
}
|
||||
|
||||
.pure-u-20-24,
|
||||
.pure-u-5-6 {
|
||||
width: 83.3333%
|
||||
}
|
||||
|
||||
.pure-u-21-24,
|
||||
.pure-u-7-8 {
|
||||
width: 87.5%
|
||||
}
|
||||
|
||||
.pure-u-11-12,
|
||||
.pure-u-22-24 {
|
||||
width: 91.6667%
|
||||
}
|
||||
|
||||
.pure-u-23-24 {
|
||||
width: 95.8333%
|
||||
}
|
||||
|
||||
.pure-u-1,
|
||||
.pure-u-1-1,
|
||||
.pure-u-24-24,
|
||||
.pure-u-5-5 {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.status {
|
||||
margin: 1rem -0.5rem 1rem -0.5rem;
|
||||
}
|
||||
|
||||
.block {
|
||||
margin: 0.5rem 0.5rem;
|
||||
padding: 0;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
line-height: 1;
|
||||
font-family: inherit;
|
||||
min-width: inherit;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
border: 1px solid rgba(0, 0, 0, .05);
|
||||
border-radius: .375rem;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 2rem 0 rgba(136, 152, 170, .15);
|
||||
}
|
||||
|
||||
.img-con {
|
||||
margin: 1rem;
|
||||
|
||||
}
|
||||
.pure-img{
|
||||
max-height: 100%;
|
||||
width: auto;
|
||||
}
|
||||
.pure-imgw{
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
.green {
|
||||
font-size: 1.25rem;
|
||||
color: #2dce89;
|
||||
}
|
||||
|
||||
.red {
|
||||
font-size: 1.25rem;
|
||||
color: #fb6340;
|
||||
}
|
||||
|
||||
.sk-text-success {
|
||||
color: #2dce89;
|
||||
}
|
||||
|
||||
.sk-text-error {
|
||||
color: #fb6340;
|
||||
}
|
||||
|
||||
.gap {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.block img {
|
||||
width: 48px;
|
||||
height: auto;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.pure-u-5-8 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.block h4 {
|
||||
font-size: .8125rem;
|
||||
font-weight: 600;
|
||||
margin: 1rem;
|
||||
color: #8898aa !important;
|
||||
line-height: 1.8em;
|
||||
}
|
||||
.p-in5{
|
||||
padding: 8px;
|
||||
}
|
||||
.flag-icon:before{
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.cbi-section-table-row {
|
||||
position: relative;
|
||||
background-color: #edf3f8;
|
||||
margin: 10px !important;
|
||||
padding: 8px 15px 8px 70px;
|
||||
box-shadow: 0 0 5px 0 rgba(136, 152, 170, .75);
|
||||
border-radius: .5rem;
|
||||
border: 0;
|
||||
color: #525f7f;
|
||||
text-align: left;
|
||||
line-height: 1.7em;
|
||||
overflow: hidden;
|
||||
letter-spacing: normal;
|
||||
|
||||
}
|
||||
.cbi-section-table-row:hover{
|
||||
background: #fff;
|
||||
|
||||
}
|
||||
|
||||
.cbi-section-table-row.fast{
|
||||
background: #5e72e4;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.cbi-section-table-row.fast .ssr-button{
|
||||
color: #fff;
|
||||
}
|
||||
.cbi-section-table-row.fast .ssr-button:hover,
|
||||
.cbi-section-table-row.fast .ssr-button:focus,
|
||||
.cbi-section-table-row.fast .ssr-button:active {
|
||||
color: #fff;
|
||||
outline: 0;
|
||||
text-decoration: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.cbi-section-table-row.fast .host_con{
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.host_con.fast {
|
||||
color: #6f9a37;
|
||||
}
|
||||
|
||||
.host_con.nopass {
|
||||
color: #dc3545;
|
||||
}
|
||||
|
||||
.host_con.middle {
|
||||
color: #fbc658;
|
||||
}
|
||||
|
||||
.host_con.slow {
|
||||
color: #fb6340;
|
||||
}
|
||||
|
||||
.loadings {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
border-radius: .5rem;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 30px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.loadings.hide {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.loadings span {
|
||||
animation: anim-rotate 2s infinite linear;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
|
||||
.alias{
|
||||
margin-bottom:1px;
|
||||
}
|
||||
.incon{
|
||||
cursor: pointer;
|
||||
}
|
||||
.incon .pure-imgw{
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.incon:nth-child(2) {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 61px;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
border-right: #d1dfed 1px solid;
|
||||
background-position: top;
|
||||
|
||||
}
|
||||
.incon:nth-child(2) .tp{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 25%;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
color: #fff;
|
||||
background: #525f7f;
|
||||
}
|
||||
|
||||
.incon:nth-child(3) {
|
||||
padding-left: 0px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.incon:nth-child(5),
|
||||
.incon:nth-child(6) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cbi-section-table-cell {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.ssr-button {
|
||||
background: none;
|
||||
color: #525f7f;
|
||||
padding: 0 0 0 0;
|
||||
height: auto;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.ssr-button:hover,
|
||||
.ssr-button:focus,
|
||||
.ssr-button:active {
|
||||
color: #525f7f;
|
||||
outline: 0;
|
||||
text-decoration: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.cbi-section h3 {
|
||||
margin-left: 10px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.cbi-button-check {
|
||||
color: #fff !important;
|
||||
background-color: #337ab7 !important;
|
||||
border-color: #2e6da4 !important;
|
||||
float: right;
|
||||
margin-right: 18px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.cbi-section-table-cell {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.host_con {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 70px;
|
||||
text-align: left;
|
||||
height: 22px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.host_ok {
|
||||
color: #fff;
|
||||
background: #2dce89;
|
||||
padding: 0.1rem 0.5rem;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
|
||||
.host_error {
|
||||
color: #fff;
|
||||
background: #f5365c;
|
||||
padding: 0.1rem 0.5rem;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
footer.mobile-hide{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mar-10 {margin-left: 50px; margin-right: 10px;}
|
||||
|
||||
.status-bar{
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
box-shadow: 0 0 2rem 0 rgba(136,152,170,.3);
|
||||
color: #525f7f;
|
||||
background: #fff;
|
||||
z-index: 5;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.status-bar .inner{
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.status-bar .inner .flag{
|
||||
height: 3em;
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
}
|
||||
.status-bar .inner .status-info{
|
||||
font-weight: bold;
|
||||
}
|
||||
.status-bar .icon-con{
|
||||
height: 3em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 2000px) {
|
||||
.pure-u-1-5 {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1600px) {
|
||||
.pure-u-1-5 {
|
||||
width: 33.33333333%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
.pure-u-1-5 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.status .pure-u-1-5 {
|
||||
width: 33.333%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 700px) {
|
||||
.pure-u-1-4 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.pure-u-1-2 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pure-u-1-5 {
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.status .pure-u-1-5 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.cbi-button-add {
|
||||
position: fixed;
|
||||
padding: 0.3rem 0.5rem;
|
||||
z-index: 1000;
|
||||
width: 50px !important;
|
||||
height: 50px;
|
||||
bottom: 90px;
|
||||
right: 5px;
|
||||
font-size: 16px;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
background-color: #fb6340 !important;
|
||||
border-color: #fb6340 !important;
|
||||
box-shadow: 0 0 1rem 0 rgba(136, 152, 170, .75);
|
||||
}
|
||||
}
|
||||
|
||||
.modals-bg {
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.modals {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
width: 60%;
|
||||
height: 500px;
|
||||
background: #172b4d;
|
||||
left: 20%;
|
||||
top: 15%;
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
/* Firefox */
|
||||
-webkit-box-sizing: border-box;
|
||||
/* Safari */
|
||||
}
|
||||
|
||||
.modals h2 {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.modals h3 {
|
||||
font-size: 14px;
|
||||
color: #f5365c !important;
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#log_content3 {
|
||||
border: 0;
|
||||
width: 99%;
|
||||
height: calc(100% - 4rem);
|
||||
font-family: 'Lucida Console';
|
||||
font-size: 11px;
|
||||
background: transparent;
|
||||
color: #FFFFFF;
|
||||
outline: none;
|
||||
padding-left: 3px;
|
||||
padding-right: 22px;
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
.modals {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
width: 80%;
|
||||
height: 500px;
|
||||
background: #172b4d;
|
||||
left: 10%;
|
||||
top: 15%;
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 700px) {
|
||||
.modals-bg {
|
||||
position: fixed;
|
||||
z-index: 100000;
|
||||
|
||||
}
|
||||
|
||||
.modals {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.status-bar .pure-u-1-2{
|
||||
width: 50%;
|
||||
}
|
||||
.status-bar .inner .flag{
|
||||
height: 3em;
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 1em;
|
||||
}
|
||||
.status-bar .icon-con{
|
||||
height: 2.5em;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
129
package/ctcgfw/luci-app-vssr/root/www/luci-static/vssr/emoji.js
Normal file
After Width: | Height: | Size: 884 B |
After Width: | Height: | Size: 745 B |
After Width: | Height: | Size: 574 B |
After Width: | Height: | Size: 675 B |
After Width: | Height: | Size: 635 B |
After Width: | Height: | Size: 626 B |
After Width: | Height: | Size: 466 B |
After Width: | Height: | Size: 831 B |
After Width: | Height: | Size: 521 B |
After Width: | Height: | Size: 440 B |
After Width: | Height: | Size: 533 B |
After Width: | Height: | Size: 651 B |
After Width: | Height: | Size: 547 B |
After Width: | Height: | Size: 649 B |
After Width: | Height: | Size: 513 B |
After Width: | Height: | Size: 656 B |
After Width: | Height: | Size: 870 B |
After Width: | Height: | Size: 496 B |
After Width: | Height: | Size: 488 B |
After Width: | Height: | Size: 438 B |
After Width: | Height: | Size: 478 B |
After Width: | Height: | Size: 526 B |
After Width: | Height: | Size: 616 B |
After Width: | Height: | Size: 492 B |
After Width: | Height: | Size: 655 B |
After Width: | Height: | Size: 531 B |
After Width: | Height: | Size: 557 B |
After Width: | Height: | Size: 939 B |
After Width: | Height: | Size: 957 B |
After Width: | Height: | Size: 824 B |
After Width: | Height: | Size: 578 B |
After Width: | Height: | Size: 572 B |
After Width: | Height: | Size: 597 B |
After Width: | Height: | Size: 828 B |
After Width: | Height: | Size: 908 B |
After Width: | Height: | Size: 550 B |
After Width: | Height: | Size: 520 B |
After Width: | Height: | Size: 548 B |
After Width: | Height: | Size: 532 B |
After Width: | Height: | Size: 550 B |
After Width: | Height: | Size: 937 B |
After Width: | Height: | Size: 926 B |
After Width: | Height: | Size: 611 B |
After Width: | Height: | Size: 413 B |