diff --git a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
index f381a54b2..eb7ccb701 100644
--- a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
+++ b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
@@ -21,11 +21,15 @@ function index()
entry({"admin", "services", "shadowsocksr", "subscribe"}, call("subscribe"))
entry({"admin", "services", "shadowsocksr", "checkport"}, call("check_port"))
entry({"admin", "services", "shadowsocksr", "log"}, form("shadowsocksr/log"), _("Log"), 80).leaf = true
+ entry({"admin", "services", "shadowsocksr", "get_log"}, call("get_log")).leaf = true
+ entry({"admin", "services", "shadowsocksr", "clear_log"}, call("clear_log")).leaf = true
entry({"admin", "services", "shadowsocksr", "run"}, call("act_status"))
entry({"admin", "services", "shadowsocksr", "ping"}, call("act_ping"))
entry({"admin", "services", "shadowsocksr", "reset"}, call("act_reset"))
entry({"admin", "services", "shadowsocksr", "restart"}, call("act_restart"))
entry({"admin", "services", "shadowsocksr", "delete"}, call("act_delete"))
+ --[[Backup]]
+ entry({"admin", "services", "shadowsocksr", "backup"}, call("create_backup")).leaf = true
end
function subscribe()
@@ -107,9 +111,9 @@ function check_port()
ret = socket:connect(s.server, s.server_port)
if tostring(ret) == "true" then
socket:close()
- retstring = retstring .. "[" .. server_name .. "] OK.
"
+ retstring = retstring .. "[" .. server_name .. "] OK.
"
else
- retstring = retstring .. "[" .. server_name .. "] Error.
"
+ retstring = retstring .. "[" .. server_name .. "] Error.
"
end
if iret == 0 then
luci.sys.call("ipset del ss_spec_wan_ac " .. s.server)
@@ -120,7 +124,7 @@ function check_port()
end
function act_reset()
- luci.sys.call("/etc/init.d/shadowsocksr reset &")
+ luci.sys.call("/etc/init.d/shadowsocksr reset >/dev/null 2>&1")
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr"))
end
@@ -133,3 +137,28 @@ function act_delete()
luci.sys.call("/etc/init.d/shadowsocksr restart &")
luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "servers"))
end
+
+function get_log()
+ luci.http.write(luci.sys.exec("[ -f '/var/log/ssrplus.log' ] && cat /var/log/ssrplus.log"))
+end
+
+function clear_log()
+ luci.sys.call("echo '' > /var/log/ssrplus.log")
+end
+
+function create_backup()
+ local backup_files = {
+ "/etc/config/shadowsocksr",
+ "/etc/ssrplus/*"
+ }
+ local date = os.date("%Y%m%d")
+ local tar_file = "/tmp/shadowsocksr-" .. date .. "-backup.tar.gz"
+ nixio.fs.remove(tar_file)
+ local cmd = "tar -czf " .. tar_file .. " " .. table.concat(backup_files, " ")
+ luci.sys.call(cmd)
+ luci.http.header("Content-Disposition", "attachment; filename=shadowsocksr-" .. date .. "-backup.tar.gz")
+ luci.http.header("X-Backup-Filename", "shadowsocksr-" .. date .. "-backup.tar.gz")
+ luci.http.prepare_content("application/octet-stream")
+ luci.http.write(nixio.fs.readfile(tar_file))
+ nixio.fs.remove(tar_file)
+end
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua
index de97787f2..e5f159343 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua
@@ -1,5 +1,7 @@
+local m, s, o
local uci = luci.model.uci.cursor()
local server_table = {}
+local type_table = {}
local function is_finded(e)
return luci.sys.exec('type -t -p "%s"' % e) ~= "" and true or false
end
@@ -10,6 +12,9 @@ uci:foreach("shadowsocksr", "servers", function(s)
elseif s.server and s.server_port then
server_table[s[".name"]] = "[%s]:%s:%s" % {string.upper(s.v2ray_protocol or s.type), s.server, s.server_port}
end
+ if s.type then
+ type_table[s[".name"]] = s.type
+ end
end)
local key_table = {}
@@ -96,7 +101,7 @@ o.default = "https://raw.githubusercontent.com/neodevpro/neodevhost/master/lite_
o:depends("adblock", "1")
o.description = translate("Support AdGuardHome and DNSMASQ format list")
-o = s:option(Button, "reset", translate("Reset to defaults"))
+o = s:option(Button, "Reset", translate("Reset to defaults"))
o.inputstyle = "reload"
o.write = function()
luci.sys.call("/etc/init.d/shadowsocksr reset")
@@ -107,15 +112,82 @@ end
s = m:section(TypedSection, "socks5_proxy", translate("Global SOCKS5 Proxy Server"))
s.anonymous = true
-o = s:option(ListValue, "server", translate("Server"))
-o:value("nil", 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.default = "nil"
+-- Enable/Disable Option
+o = s:option(Flag, "enabled", translate("Enable"))
+o.default = 0
o.rmempty = false
+-- Server Selection
+o = s:option(ListValue, "server", translate("Server"))
+o:value("same", translate("Same as Global Server"))
+for _, key in pairs(key_table) do
+ o:value(key, server_table[key])
+end
+o.default = "same"
+o.rmempty = false
+
+-- Dynamic value handling based on enabled/disabled state
+o.cfgvalue = function(self, section)
+ local enabled = m:get(section, "enabled")
+ if enabled == "0" then
+ return m:get(section, "old_server") or "same"
+ end
+ return Value.cfgvalue(self, section) or "same" -- Default to `same` when enabled
+end
+
+o.write = function(self, section, value)
+ local enabled = m:get(section, "enabled")
+ if enabled == "0" then
+ local old_server = Value.cfgvalue(self, section) or "same"
+ if old_server ~= "nil" then
+ m:set(section, "old_server", old_server)
+ end
+ m:set(section, "server", "nil")
+ else
+ m:del(section, "old_server")
+ -- Write the value normally when enabled
+ Value.write(self, section, value)
+ end
+end
+
+-- Socks Auth
+if is_finded("xray") then
+o = s:option(ListValue, "socks5_auth", translate("Socks5 Auth Mode"), translate("Socks protocol auth methods, default:noauth."))
+o.default = "noauth"
+o:value("noauth", "NOAUTH")
+o:value("password", "PASSWORD")
+o.rmempty = true
+for key, server_type in pairs(type_table) do
+ if server_type == "v2ray" then
+ -- 如果服务器类型是 v2ray,则设置依赖项显示
+ o:depends("server", key)
+ end
+end
+
+-- Socks User
+o = s:option(Value, "socks5_user", translate("Socks5 User"), translate("Only when auth is password valid, Mandatory."))
+o.rmempty = true
+o:depends("socks5_auth", "password")
+
+-- Socks Password
+o = s:option(Value, "socks5_pass", translate("Socks5 Password"), translate("Only when auth is password valid, Not mandatory."))
+o.password = true
+o.rmempty = true
+o:depends("socks5_auth", "password")
+
+-- Socks Mixed
+o = s:option(Flag, "socks5_mixed", translate("Enabled Mixed"), translate("Mixed as an alias of socks, default:Enabled."))
+o.default = "1"
+o.rmempty = false
+for key, server_type in pairs(type_table) do
+ if server_type == "v2ray" then
+ -- 如果服务器类型是 v2ray,则设置依赖项显示
+ o:depends("server", key)
+ end
+end
+end
+
+-- Local Port
o = s:option(Value, "local_port", translate("Local Port"))
o.datatype = "port"
o.default = 1080
@@ -132,6 +204,7 @@ o.default = 0
o = s:option(ListValue, "fragment_packets", translate("Fragment Packets"), translate("\"1-3\" is for segmentation at TCP layer, applying to the beginning 1 to 3 data writes by the client. \"tlshello\" is for TLS client hello packet fragmentation."))
o.default = "tlshello"
o:value("tlshello", "tlshello")
+o:value("1-1", "1-1")
o:value("1-2", "1-2")
o:value("1-3", "1-3")
o:value("1-5", "1-5")
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua
index 2b91c2cf8..c858b9515 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua
@@ -618,8 +618,7 @@ o:depends({type = "v2ray", v2ray_protocol = "socks"})
-- 传输协议
o = s:option(ListValue, "transport", translate("Transport"))
-o:value("tcp", "TCP")
-o:value("raw", "RAW")
+o:value("raw", "RAW (TCP)")
o:value("kcp", "mKCP")
o:value("ws", "WebSocket")
o:value("httpupgrade", "HTTPUpgrade")
@@ -635,17 +634,9 @@ o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"})
o:depends({type = "v2ray", v2ray_protocol = "socks"})
o:depends({type = "v2ray", v2ray_protocol = "http"})
--- [[ TCP部分 ]]--
+-- [[ RAW部分 ]]--
-- 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
-
--- [[ RAW部分 ]]--
--- RAW伪装
-o = s:option(ListValue, "raw_guise", translate("Camouflage Type"))
o:depends("transport", "raw")
o:value("none", translate("None"))
o:value("http", "HTTP")
@@ -654,13 +645,11 @@ o.rmempty = true
-- HTTP域名
o = s:option(Value, "http_host", translate("HTTP Host"))
o:depends("tcp_guise", "http")
-o:depends("raw_guise", "http")
o.rmempty = true
-- HTTP路径
o = s:option(Value, "http_path", translate("HTTP Path"))
o:depends("tcp_guise", "http")
-o:depends("raw_guise", "http")
o.rmempty = true
-- [[ WS部分 ]]--
@@ -935,17 +924,20 @@ if is_finded("xray") then
-- [[ XTLS ]]--
o = s:option(ListValue, "tls_flow", translate("Flow"))
for _, v in ipairs(tls_flows) do
- o:value(v, translate(v))
+ if v == "none" then
+ o.default = "none"
+ o:value("none", translate("none"))
+ else
+ o:value(v, translate(v))
+ end
end
o.rmempty = true
- o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "tcp", tls = true})
o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "raw", tls = true})
- o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "tcp", reality = true})
o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "raw", reality = true})
-- [[ uTLS ]]--
o = s:option(ListValue, "fingerprint", translate("Finger Print"))
- o.default = "chrome"
+ o.default = ""
o:value("chrome", translate("chrome"))
o:value("firefox", translate("firefox"))
o:value("safari", translate("safari"))
@@ -1024,7 +1016,7 @@ o:depends("mux", true)
-- [[ MPTCP ]]--
-o = s:option(Flag, "mptcp", translate("MPTCP"))
+o = s:option(Flag, "mptcp", translate("MPTCP"), translate("Enabling MPTCP Requires Server Support."))
o.rmempty = false
o.default = false
o:depends({type = "v2ray", v2ray_protocol = "vless"})
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua
index 070fb5b9b..956f8959d 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua
@@ -1,5 +1,6 @@
require "luci.ip"
require "nixio.fs"
+require "luci.sys"
local m, s, o
m = Map("shadowsocksr")
@@ -140,4 +141,11 @@ o.remove = function(self, section, value)
nixio.fs.writefile(netflixconf, "")
end
+if luci.sys.call('[ -f "/www/luci-static/resources/uci.js" ]') == 0 then
+ m.apply_on_parse = true
+ function m.on_apply(self)
+ luci.sys.call("/etc/init.d/shadowsocksr reload > /dev/null 2>&1 &")
+ end
+end
+
return m
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua
index fdf9e59f0..b0bd4f6f3 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/log.lua
@@ -1,20 +1,102 @@
require "luci.util"
require "nixio.fs"
+require "luci.sys"
+require "luci.http"
+
f = SimpleForm("logview")
f.reset = false
f.submit = false
-t = f:field(TextValue, "conf")
-t.rmempty = true
-t.rows = 20
-function t.cfgvalue()
- if nixio.fs.access("/var/log/ssrplus.log") then
- local logs = luci.util.execi("cat /var/log/ssrplus.log")
- local s = ""
- for line in logs do
- s = line .. "\n" .. s
- end
- return s
- end
+f:append(Template("shadowsocksr/log"))
+
+-- 自定义 log 函数
+function log(...)
+ local result = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ")
+ local f, err = io.open("/var/log/ssrplus.log", "a")
+ if f and err == nil then
+ f:write(result .. "\n")
+ f:close()
+ end
end
-t.readonly = "readonly"
-return f
+
+-- 创建备份与恢复表单
+fb = SimpleForm('backup-restore')
+fb.reset = false
+fb.submit = false
+s = fb:section(SimpleSection, translate("Backup and Restore"), translate("Backup or Restore Client and Server Configurations.") ..
+ "
" ..
+ translate("Note: Restoring configurations across different versions may cause compatibility issues.") ..
+ "")
+o = s:option(DummyValue, '', nil)
+o.template = "shadowsocksr/backup_restore"
+
+-- 定义备份目标文件和目录
+local backup_targets = {
+ files = {
+ "/etc/config/shadowsocksr"
+ },
+ dirs = {
+ "/etc/ssrplus"
+ }
+}
+
+local file_path = '/tmp/shadowsocksr_upload.tar.gz'
+local temp_dir = '/tmp/shadowsocksr_bak'
+local fd
+
+-- 处理文件上传
+luci.http.setfilehandler(function(meta, chunk, eof)
+ if not fd and meta and meta.name == "ulfile" and chunk then
+ -- 初始化上传处理
+ luci.sys.call("rm -rf " .. temp_dir)
+ nixio.fs.remove(file_path)
+ fd = nixio.open(file_path, "w")
+ luci.sys.call("echo '' > /var/log/ssrplus.log")
+ end
+
+ if fd and chunk then
+ fd:write(chunk)
+ end
+
+ if eof and fd then
+ fd:close()
+ fd = nil
+ if nixio.fs.access(file_path) then
+ log(" * shadowsocksr 配置文件上传成功…") -- 使用自定义的 log 函数
+ luci.sys.call("mkdir -p " .. temp_dir)
+
+ if luci.sys.call("tar -xzf " .. file_path .. " -C " .. temp_dir) == 0 then
+ -- 处理文件还原
+ for _, target in ipairs(backup_targets.files) do
+ local temp_file = temp_dir .. target
+ if nixio.fs.access(temp_file) then
+ luci.sys.call(string.format("cp -f '%s' '%s'", temp_file, target))
+ log(" * 文件 " .. target .. " 还原成功…") -- 使用自定义的 log 函数
+ end
+ end
+
+ -- 处理目录还原
+ for _, target in ipairs(backup_targets.dirs) do
+ local temp_dir_path = temp_dir .. target
+ if nixio.fs.access(temp_dir_path) then
+ luci.sys.call(string.format("cp -rf '%s'/* '%s/'", temp_dir_path, target))
+ log(" * 目录 " .. target .. " 还原成功…") -- 使用自定义的 log 函数
+ end
+ end
+
+ log(" * shadowsocksr 配置还原成功…") -- 使用自定义的 log 函数
+ log(" * 重启 shadowsocksr 服务中…\n") -- 使用自定义的 log 函数
+ luci.sys.call('/etc/init.d/shadowsocksr restart > /dev/null 2>&1 &')
+ else
+ log(" * shadowsocksr 配置文件解压失败,请重试!") -- 使用自定义的 log 函数
+ end
+ else
+ log(" * shadowsocksr 配置文件上传失败,请重试!") -- 使用自定义的 log 函数
+ end
+
+ -- 清理临时文件
+ luci.sys.call("rm -rf " .. temp_dir)
+ nixio.fs.remove(file_path)
+ end
+end)
+
+return f, fb
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua
index d1850cca7..a7166abdb 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua
@@ -29,7 +29,7 @@ o:value("5", translate("Every Friday"))
o:value("6", translate("Every Saturday"))
o:value("0", translate("Every Sunday"))
o.default = "*"
-o.rmempty = false
+o.rmempty = true
o:depends("auto_update", "1")
o = s:option(ListValue, "auto_update_day_time", translate("Update time (every day)"))
@@ -37,7 +37,7 @@ for t = 0, 23 do
o:value(t, t .. ":00")
end
o.default = 2
-o.rmempty = false
+o.rmempty = true
o:depends("auto_update", "1")
o = s:option(ListValue, "auto_update_min_time", translate("Update Interval (min)"))
@@ -45,7 +45,7 @@ for i = 0, 59 do
o:value(i, i .. ":00")
end
o.default = 30
-o.rmempty = false
+o.rmempty = true
o:depends("auto_update", "1")
o = s:option(DynamicList, "subscribe_url", translate("Subscribe URL"))
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua
index 65b916ec0..83a88a2a4 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua
@@ -155,6 +155,14 @@ if nixio.fs.access("/usr/bin/kcptun-client") then
end
end
+s = m:field(Button, "Restart", translate("Restart ShadowSocksR Plus+"))
+s.inputtitle = translate("Restart Service")
+s.inputstyle = "reload"
+s.write = function()
+ luci.sys.call("/etc/init.d/shadowsocksr restart >/dev/null 2>&1 &")
+ luci.http.redirect(luci.dispatcher.build_url("admin", "services", "shadowsocksr", "client"))
+end
+
s = m:field(DummyValue, "google", translate("Google Connectivity"))
s.value = translate("No Check")
s.template = "shadowsocksr/check"
@@ -181,10 +189,10 @@ if uci:get_first("shadowsocksr", 'global', 'apple_optimization', '0') ~= '0' the
end
if uci:get_first("shadowsocksr", 'global', 'netflix_enable', '0') ~= '0' then
-s = m:field(DummyValue, "nfip_data", translate("Netflix IP Data"))
-s.rawhtml = true
-s.template = "shadowsocksr/refresh"
-s.value = nfip_count .. " " .. translate("Records")
+ s = m:field(DummyValue, "nfip_data", translate("Netflix IP Data"))
+ s.rawhtml = true
+ s.template = "shadowsocksr/refresh"
+ s.value = nfip_count .. " " .. translate("Records")
end
if uci:get_first("shadowsocksr", 'global', 'adblock', '0') == '1' then
diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm
new file mode 100644
index 000000000..d775addf8
--- /dev/null
+++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/backup_restore.htm
@@ -0,0 +1,154 @@
+<%+cbi/valueheader%>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
<%:Restore Backup File%>
+
+
+
+
+
+
+
+<%+cbi/valuefooter%>
diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/log.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/log.htm
new file mode 100644
index 000000000..251f14b22
--- /dev/null
+++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/log.htm
@@ -0,0 +1,37 @@
+<%
+local dsp = require "luci.dispatcher"
+-%>
+
+
diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm
index a7485acb5..62e1b1cc5 100644
--- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm
+++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm
@@ -217,8 +217,9 @@ function import_ssr_url(btn, urlname, sid) {
case "trojan":
try {
var url = new URL("http://" + ssu[1]);
+ var params = url.searchParams;
} catch(e) {
- alert(e)
+ alert(e);
return false;
}
@@ -232,7 +233,65 @@ function import_ssr_url(btn, urlname, sid) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.password')[0].value = decodeURIComponent(url.username);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event);
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = url.searchParams.get("sni");
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.fingerprint')[0].value = params.get("fp") || "";
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = params.get("sni");
+ if (params.get("allowInsecure") === "1") {
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true; // 设置 insecure 为 true
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event); // 触发事件
+ }
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].value =
+ params.get("type") == "http" ? "h2" :
+ (["tcp", "raw"].includes(params.get("type")) ? "raw" :
+ (params.get("type") || "raw"));
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].dispatchEvent(event);
+ switch (params.get("type")) {
+ case "ws":
+ if (params.get("security") !== "tls") {
+ setElementValue('cbid.shadowsocksr.' + sid + '.ws_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ }
+ setElementValue('cbid.shadowsocksr.' + sid + '.ws_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
+ break;
+ case "httpupgrade":
+ if (params.get("security") !== "tls") {
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
+ }
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
+ break;
+ case "splithttp":
+ if (params.get("security") !== "tls") {
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.splithttp_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
+ }
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.splithttp_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
+ break;
+ case "kcp":
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.kcp_guise')[0].value = params.get("headerType") || "none";
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.seed')[0].value = params.get("seed") || "";
+ break;
+ case "http":
+ /* this is non-standard, bullshit */
+ case "h2":
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
+ break;
+ case "quic":
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_guise')[0].value = params.get("headerType") || "none";
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_security')[0].value = params.get("quicSecurity") || "none";
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_key')[0].value = params.get("key") || "";
+ break;
+ case "grpc":
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.serviceName')[0].value = params.get("serviceName") || "";
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.grpc_mode')[0].value = params.get("mode") || "gun";
+ break;
+ case "raw":
+ case "tcp":
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].value = params.get("headerType") || "none";
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].dispatchEvent(event);
+ if (params.get("headerType") === "http") {
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
+ }
+ break;
+ }
s.innerHTML = "<%:Import configuration information successfully.%>";
return false;
@@ -254,11 +313,12 @@ function import_ssr_url(btn, urlname, sid) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = ssm.port;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.alter_id')[0].value = ssm.aid;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.vmess_id')[0].value = ssm.id;
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].value = ssm.net;
+ document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].value =
+ (ssm.net === "raw" || ssm.net === "tcp") ? "raw" : ssm.net;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].dispatchEvent(event);
- if (ssm.net == "tcp") {
+ if (ssm.net === "raw" || ssm.net === "tcp") {
if (ssm.type && ssm.type != "http") {
- ssm.type = "none"
+ ssm.type = "none";
} else {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_host')[0].value = ssm.host;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_path')[0].value = ssm.path;
@@ -294,8 +354,10 @@ function import_ssr_url(btn, urlname, sid) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event);
document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = ssm.sni || ssm.host;
}
+ if (ssm.mux !== undefined) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.mux')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.mux')[0].dispatchEvent(event);
+ }
s.innerHTML = "<%:Import configuration information successfully.%>";
return false;
case "vless":
@@ -303,88 +365,101 @@ function import_ssr_url(btn, urlname, sid) {
var url = new URL("http://" + ssu[1]);
var params = url.searchParams;
} catch(e) {
- alert(e)
+ alert(e);
return false;
}
-
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].value = "v2ray";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.type')[0].dispatchEvent(event);
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].value = "vless";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.v2ray_protocol')[0].dispatchEvent(event);
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.server')[0].value = url.hostname;
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.server_port')[0].value = url.port || "80";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.vmess_id')[0].value = url.username;
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].value =
- params.get("type") == "http" ? "h2" :
- (params.get("type") == "raw" ? "raw" :
- (params.get("type") || "tcp"));
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.transport')[0].dispatchEvent(event);
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.vless_encryption')[0].value = params.get("encryption") || "none";
+ // Check if the elements exist before trying to modify them
+ function setElementValue(name, value) {
+ const element = document.getElementsByName(name)[0];
+ if (element) {
+ if (element.type === "checkbox" || element.type === "radio") {
+ element.checked = value === true;
+ } else {
+ element.value = value;
+ }
+ }
+ }
+ function dispatchEventIfExists(name, event) {
+ const element = document.getElementsByName(name)[0];
+ if (element) {
+ element.dispatchEvent(event);
+ }
+ }
+ setElementValue('cbid.shadowsocksr.' + sid + '.alias', url.hash ? decodeURIComponent(url.hash.slice(1)) : "");
+ setElementValue('cbid.shadowsocksr.' + sid + '.type', "v2ray");
+ dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.type', event);
+ setElementValue('cbid.shadowsocksr.' + sid + '.v2ray_protocol', "vless");
+ dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.v2ray_protocol', event);
+ setElementValue('cbid.shadowsocksr.' + sid + '.server', url.hostname);
+ setElementValue('cbid.shadowsocksr.' + sid + '.server_port', url.port || "80");
+ setElementValue('cbid.shadowsocksr.' + sid + '.vmess_id', url.username);
+ setElementValue('cbid.shadowsocksr.' + sid + '.transport',
+ params.get("type") === "http" ? "h2" :
+ (["tcp", "raw"].includes(params.get("type")) ? "raw" :
+ (params.get("type") || "tcp"))
+ );
+ dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.transport', event);
+ setElementValue('cbid.shadowsocksr.' + sid + '.vless_encryption', params.get("encryption") || "none");
if ([ "tls", "xtls", "reality" ].includes(params.get("security"))) {
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.' + params.get("security"))[0].checked = true;
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.' + params.get("security"))[0].dispatchEvent(event);
+ setElementValue('cbid.shadowsocksr.' + sid + '.' + params.get("security"), true);
+ dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.' + params.get("security"), event);
if (params.get("security") === "reality") {
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.reality_publickey')[0].value = params.get("pbk") ? decodeURIComponent(params.get("pbk")) : "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.reality_shortid')[0].value = params.get("sid") || "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.reality_spiderx')[0].value = params.get("spx") ? decodeURIComponent(params.get("spx")) : "";
+ setElementValue('cbid.shadowsocksr.' + sid + '.reality_publickey', params.get("pbk") ? decodeURIComponent(params.get("pbk")) : "");
+ setElementValue('cbid.shadowsocksr.' + sid + '.reality_shortid', params.get("sid") || "");
+ setElementValue('cbid.shadowsocksr.' + sid + '.reality_spiderx', params.get("spx") ? decodeURIComponent(params.get("spx")) : "");
}
- if (params.get("security") === "xtls") {
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_flow')[0].value = params.get("flow") || "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_flow')[0].dispatchEvent(event);
- }
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.fingerprint')[0].value = params.get("fp") || "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = params.get("sni") || "";
+ setElementValue('cbid.shadowsocksr.' + sid + '.tls_flow', params.get("flow") || "none");
+ dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.tls_flow', event);
+
+ setElementValue('cbid.shadowsocksr.' + sid + '.fingerprint', params.get("fp") || "");
+ setElementValue('cbid.shadowsocksr.' + sid + '.tls_host', params.get("sni") || "");
}
switch (params.get("type")) {
case "ws":
- if (params.get("security") !== "tls")
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.ws_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
+ if (params.get("security") !== "tls") {
+ setElementValue('cbid.shadowsocksr.' + sid + '.ws_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ }
+ setElementValue('cbid.shadowsocksr.' + sid + '.ws_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
break;
case "httpupgrade":
- if (params.get("security") !== "tls")
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.httpupgrade_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
+ if (params.get("security") !== "tls") {
+ setElementValue('cbid.shadowsocksr.' + sid + '.httpupgrade_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ }
+ setElementValue('cbid.shadowsocksr.' + sid + '.httpupgrade_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
break;
case "splithttp":
- if (params.get("security") !== "tls")
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.splithttp_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.splithttp_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
+ if (params.get("security") !== "tls") {
+ setElementValue('cbid.shadowsocksr.' + sid + '.splithttp_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ }
+ setElementValue('cbid.shadowsocksr.' + sid + '.splithttp_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
break;
case "kcp":
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.kcp_guise')[0].value = params.get("headerType") || "none";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.seed')[0].value = params.get("seed") || "";
+ setElementValue('cbid.shadowsocksr.' + sid + '.kcp_guise', params.get("headerType") || "none");
+ setElementValue('cbid.shadowsocksr.' + sid + '.seed', params.get("seed") || "");
break;
case "http":
/* this is non-standard, bullshit */
case "h2":
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.h2_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
+ setElementValue('cbid.shadowsocksr.' + sid + '.h2_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ setElementValue('cbid.shadowsocksr.' + sid + '.h2_path', params.get("path") ? decodeURIComponent(params.get("path")) : "");
break;
case "quic":
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_guise')[0].value = params.get("headerType") || "none";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_security')[0].value = params.get("quicSecurity") || "none";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.quic_key')[0].value = params.get("key") || "";
+ setElementValue('cbid.shadowsocksr.' + sid + '.quic_guise', params.get("headerType") || "none");
+ setElementValue('cbid.shadowsocksr.' + sid + '.quic_security', params.get("quicSecurity") || "none");
+ setElementValue('cbid.shadowsocksr.' + sid + '.quic_key', params.get("key") || "");
break;
case "grpc":
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.serviceName')[0].value = params.get("serviceName") || "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.grpc_mode')[0].value = params.get("mode") || "gun";
+ setElementValue('cbid.shadowsocksr.' + sid + '.serviceName', params.get("serviceName") || "");
+ setElementValue('cbid.shadowsocksr.' + sid + '.grpc_mode', params.get("mode") || "gun");
break;
case "tcp":
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].value = params.get("headerType") || "none";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.tcp_guise')[0].dispatchEvent(event);
- if (params.get("headerType") === "http") {
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
- }
case "raw":
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.raw_guise')[0].value = params.get("headerType") || "none";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.raw_guise')[0].dispatchEvent(event);
+ setElementValue('cbid.shadowsocksr.' + sid + '.tcp_guise', params.get("headerType") || "none");
+ dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.tcp_guise', event);
if (params.get("headerType") === "http") {
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.http_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
+ setElementValue('cbid.shadowsocksr.' + sid + '.http_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ setElementValue('cbid.shadowsocksr.' + sid + '.http_path', params.get("path") ? decodeURIComponent(params.get("path")) : "");
}
break;
}
diff --git a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po
index 7621a513a..6d547ca19 100644
--- a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po
+++ b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po
@@ -91,6 +91,8 @@ msgstr "TLS 主机名"
msgid "allowInsecure"
msgstr "允许不安全连接"
+msgid "Enabling MPTCP Requires Server Support."
+msgstr "启用 MPTCP 需服务端支持。"
msgid "concurrency"
msgstr "TCP 最大并发连接数"
@@ -377,6 +379,12 @@ msgstr "强制走代理"
msgid "UDP Relay"
msgstr "UDP 中继"
+msgid "Restart ShadowSocksR Plus+"
+msgstr "重启 ShadowSocksR Plus+"
+
+msgid "Restart Service"
+msgstr "重启服务"
+
msgid "Google Connectivity"
msgstr "【谷歌】连通性检查"
@@ -863,6 +871,30 @@ msgstr "本机服务端"
msgid "Global SOCKS5 Proxy Server"
msgstr "SOCKS5 代理服务端(全局)"
+msgid "Socks5 Auth Mode"
+msgstr "Socks5 认证方式"
+
+msgid "Socks protocol auth methods, default:noauth."
+msgstr "Socks 协议的认证方式,默认值:noauth。"
+
+msgid "Socks5 User"
+msgstr "Socks5 用户名"
+
+msgid "Only when auth is password valid, Mandatory."
+msgstr "仅当 auth 为 password 时有效,必填。"
+
+msgid "Socks5 Password"
+msgstr "Socks5 密码"
+
+msgid "Only when auth is password valid, Not mandatory."
+msgstr "仅当 auth 为 password 时有效,非必填。"
+
+msgid "Enabled Mixed"
+msgstr "启用 Mixed"
+
+msgid "Mixed as an alias of socks, default:Enabled."
+msgstr "Mixed 作为 SOCKS 的别名,默认:启用。"
+
msgid "Xray Fragment Settings"
msgstr "Xray 分片设置"
@@ -1147,3 +1179,45 @@ msgstr "socks5 服务器可以从外部接收的最大数据包大小(单位
msgid "Disable ChinaDNS-NG"
msgstr "直通模式(禁用 ChinaDNS-NG)"
+
+msgid "Clear logs"
+msgstr "清空日志"
+
+msgid "Backup and Restore"
+msgstr "备份还原"
+
+msgid "Backup or Restore Client and Server Configurations."
+msgstr "备份或还原客户端及服务端配置。"
+
+msgid "Note: Restoring configurations across different versions may cause compatibility issues."
+msgstr "注意:不同版本间的配置恢复可能会导致兼容性问题。"
+
+msgid "Create Backup File"
+msgstr "创建备份文件"
+
+msgid "Restore Backup File"
+msgstr "恢复备份文件"
+
+msgid "DL Backup"
+msgstr "下载备份"
+
+msgid "RST Backup"
+msgstr "恢复备份"
+
+msgid "UL Restore"
+msgstr "上传恢复"
+
+msgid "CLOSE WIN"
+msgstr "关闭窗口"
+
+msgid "Restore to default configuration"
+msgstr "恢复默认配置"
+
+msgid "Do Reset"
+msgstr "执行重置"
+
+msgid "Do you want to restore the client to default settings?"
+msgstr "是否要恢复客户端默认配置?"
+
+msgid "Are you sure you want to restore the client to default settings?"
+msgstr "是否真的要恢复客户端默认配置?"
diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua
index 569b46263..8210ac360 100755
--- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua
+++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/gen_config.lua
@@ -12,6 +12,7 @@ local chain = arg[5] or "0"
local chain_local_port = string.split(chain, "/")[2] or "0"
local server = ucursor:get_all("shadowsocksr", server_section)
+local socks_server = ucursor:get_all("shadowsocksr", "@socks5_proxy[0]") or {}
local xray_fragment = ucursor:get_all("shadowsocksr", "@global_xray_fragment[0]") or {}
local xray_noise = ucursor:get_all("shadowsocksr", "@xray_noise_packets[0]") or {}
local outbound_settings = nil
@@ -28,7 +29,7 @@ function vmess_vless()
alterId = (server.v2ray_protocol == "vmess" or not server.v2ray_protocol) and tonumber(server.alter_id) or nil,
security = (server.v2ray_protocol == "vmess" or not server.v2ray_protocol) and server.security or nil,
encryption = (server.v2ray_protocol == "vless") and server.vless_encryption or nil,
- flow = ((server.xtls == '1') or (server.tls == '1') or (server.reality == '1')) and server.tls_flow or nil
+ flow = (((server.xtls == '1') or (server.tls == '1') or (server.reality == '1')) and server.tls_flow ~= "none") and server.tls_flow or nil
}
}
}
@@ -180,10 +181,20 @@ end
-- 检查是否启用 socks 代理
if proto:find("tcp") and socks_port ~= "0" then
table.insert(Xray.inbounds, {
- -- socks
+ -- socks
protocol = "socks",
port = tonumber(socks_port),
- settings = {auth = "noauth", udp = true}
+ settings = {
+ auth = socks_server.socks5_auth,
+ udp = true,
+ mixed = (socks_server.socks5_mixed == '1') and true or false,
+ accounts = (socks_server.socks5_auth ~= "noauth") and {
+ {
+ user = socks_server.socks5_user,
+ pass = socks_server.socks5_pass
+ }
+ } or nil
+ }
})
end
@@ -220,26 +231,15 @@ end
fingerprint = server.fingerprint,
serverName = server.tls_host
} or nil,
- tcpSettings = (server.transport == "tcp" and server.tcp_guise == "http") and {
+ rawSettings = (server.transport == "raw" or server.transport == "tcp") and {
-- tcp
header = {
- type = server.tcp_guise,
- request = {
+ type = server.tcp_guise or "none",
+ request = (server.tcp_guise == "http") and {
-- request
path = {server.http_path} or {"/"},
headers = {Host = {server.http_host} or {}}
- }
- }
- } or nil,
- rawSettings = (server.transport == "raw" and server.raw_guise == "http") and {
- -- raw
- header = {
- type = server.raw_guise,
- request = {
- -- request
- path = {server.http_path} or {"/"},
- headers = {Host = {server.http_host} or {}}
- }
+ } or nil
}
} or nil,
kcpSettings = (server.transport == "kcp") and {
@@ -256,10 +256,7 @@ end
} or nil,
wsSettings = (server.transport == "ws") and (server.ws_path or server.ws_host or server.tls_host) and {
-- ws
- headers = (server.ws_host or server.tls_host) and {
- -- headers
- Host = server.ws_host or server.tls_host
- } or nil,
+ Host = server.ws_host or server.tls_host or nil,
path = server.ws_path,
maxEarlyData = tonumber(server.ws_ed) or nil,
earlyDataHeaderName = server.ws_ed_header or nil
@@ -297,8 +294,9 @@ end
initial_windows_size = tonumber(server.initial_windows_size) or nil
} or nil,
sockopt = {
- tcpMptcp = (server.mptcp == "1") and true or false, -- MPTCP
- tcpNoDelay = (server.mptcp == "1") and true or false, -- MPTCP
+ mark = 250,
+ tcpMptcp = (server.mptcp == "1") and true or nil, -- MPTCP
+ tcpNoDelay = (server.mptcp == "1") and true or nil, -- MPTCP
tcpcongestion = server.custom_tcpcongestion, -- 连接服务器节点的 TCP 拥塞控制算法
dialerProxy = (xray_fragment.fragment == "1" or xray_fragment.noise == "1") and "dialerproxy" or nil
}
@@ -335,8 +333,10 @@ if xray_fragment.fragment ~= "0" or (xray_fragment.noise ~= "0" and xray_noise.e
},
streamSettings = {
sockopt = {
- tcpMptcp = (server.mptcp == "1") and true or false, -- MPTCP
- tcpNoDelay = (server.mptcp == "1") and true or false -- MPTCP
+ mark = 250,
+ tcpMptcp = (server.mptcp == "1") and true or nil, -- MPTCP
+ tcpNoDelay = (server.mptcp == "1") and true or nil, -- MPTCP
+ tcpcongestion = server.custom_tcpcongestion -- 连接服务器节点的 TCP 拥塞控制算法
}
}
})
diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua
index ccdd8be7a..777923a18 100755
--- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua
+++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua
@@ -172,6 +172,9 @@ local function processData(szType, content)
result.v2ray_protocol = 'vmess'
result.server = info.add
result.server_port = info.port
+ if info.net == "tcp" then
+ info.net = "raw"
+ end
result.transport = info.net
result.alter_id = info.aid
result.vmess_id = info.id
@@ -194,7 +197,7 @@ local function processData(szType, content)
result.h2_host = info.host
result.h2_path = info.path
end
- if info.net == 'tcp' then
+ if info.net == 'raw' or info.net == 'tcp' then
if info.type and info.type ~= "http" then
info.type = "none"
end
@@ -316,6 +319,7 @@ local function processData(szType, content)
result.server = nil
end
elseif szType == "trojan" then
+ local params = {}
local idx_sp = 0
local alias = ""
if content:find("#") then
@@ -324,20 +328,27 @@ local function processData(szType, content)
end
local info = content:sub(1, idx_sp - 1)
local hostInfo = split(info, "@")
- local host = split(hostInfo[2], ":")
local userinfo = hostInfo[1]
local password = userinfo
+
+ -- 分离服务器地址和端口
+ local host = split(hostInfo[2], ":")
+ local server = host[1]
+ local port = host[2]
+
result.alias = UrlDecode(alias)
result.type = v2_tj
result.v2ray_protocol = "trojan"
- result.server = host[1]
+ result.server = server
+ result.password = password
+
-- 按照官方的建议 默认验证ssl证书
result.insecure = "0"
result.tls = "1"
- if host[2]:find("?") then
- local query = split(host[2], "?")
+
+ if port:find("?") then
+ local query = split(port, "?")
result.server_port = query[1]
- local params = {}
for _, v in pairs(split(query[2], '&')) do
local t = split(v, '=')
params[t[1]] = t[2]
@@ -346,10 +357,62 @@ local function processData(szType, content)
-- 未指定peer(sni)默认使用remote addr
result.tls_host = params.sni
end
+
+ if params.allowInsecure then
+ -- 处理 insecure 参数
+ result.insecure = params.allowInsecure
+ end
else
- result.server_port = host[2]
+ result.server_port = port
+ end
+
+ if v2_tj ~= "trojan" then
+ if params.fp then
+ -- 处理 fingerprint 参数
+ result.fingerprint = params.fp
+ end
+ -- 处理传输协议
+ result.transport = params.type or "tcp" -- 默认传输协议为 tcp
+ if result.transport == "tcp" then
+ result.transport = "raw"
+ end
+ if result.transport == "ws" then
+ result.ws_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil
+ result.ws_path = params.path and UrlDecode(params.path) or "/"
+ elseif result.transport == "httpupgrade" then
+ result.httpupgrade_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil
+ result.httpupgrade_path = params.path and UrlDecode(params.path) or "/"
+ elseif result.transport == "splithttp" then
+ result.splithttp_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil
+ result.splithttp_path = params.path and UrlDecode(params.path) or "/"
+ elseif result.transport == "http" or result.transport == "h2" then
+ result.transport = "h2"
+ result.h2_host = params.host and UrlDecode(params.host) or nil
+ result.h2_path = params.path and UrlDecode(params.path) or nil
+ elseif result.transport == "kcp" then
+ result.kcp_guise = params.headerType or "none"
+ result.seed = params.seed
+ result.mtu = 1350
+ result.tti = 50
+ result.uplink_capacity = 5
+ result.downlink_capacity = 20
+ result.read_buffer_size = 2
+ result.write_buffer_size = 2
+ elseif result.transport == "quic" then
+ result.quic_guise = params.headerType or "none"
+ result.quic_security = params.quicSecurity or "none"
+ result.quic_key = params.key
+ elseif result.transport == "grpc" then
+ result.serviceName = params.serviceName
+ result.grpc_mode = params.mode or "gun"
+ elseif result.transport == "tcp" or result.transport == "raw" then
+ result.tcp_guise = params.headerType and params.headerType ~= "" and params.headerType or "none"
+ if result.tcp_guise == "http" then
+ result.tcp_host = params.host and UrlDecode(params.host) or nil
+ result.tcp_path = params.path and UrlDecode(params.path) or nil
+ end
+ end
end
- result.password = password
elseif szType == "vless" then
local url = URL.parse("http://" .. content)
local params = url.query
@@ -400,18 +463,12 @@ local function processData(szType, content)
elseif result.transport == "grpc" then
result.serviceName = params.serviceName
result.grpc_mode = params.mode or "gun"
- elseif result.transport == "tcp" then
+ elseif result.transport == "tcp" or result.transport == "raw" then
result.tcp_guise = params.headerType or "none"
if result.tcp_guise == "http" then
result.tcp_host = params.host and UrlDecode(params.host) or nil
result.tcp_path = params.path and UrlDecode(params.path) or nil
end
- elseif result.transport == "raw" then
- result.raw_guise = params.headerType or "none"
- if result.raw_guise == "http" then
- result.tcp_host = params.host and UrlDecode(params.host) or nil
- result.tcp_path = params.path and UrlDecode(params.path) or nil
- end
end
end
if not result.alias then
diff --git a/patch-luci-app-ssr-plus.patch b/patch-luci-app-ssr-plus.patch
index b027ebbb5..7c4d31e89 100644
--- a/patch-luci-app-ssr-plus.patch
+++ b/patch-luci-app-ssr-plus.patch
@@ -121,7 +121,7 @@ index b469328..3a0b055 100644
bool "Include ShadowsocksR Libev Client"
default y
diff --git a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
-index 8ceaba7..f381a54 100644
+index 0469b87..eb7ccb7 100644
--- a/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
+++ b/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua
@@ -7,7 +7,7 @@ function index()
@@ -134,10 +134,10 @@ index 8ceaba7..f381a54 100644
page.acl_depends = { "luci-app-ssr-plus" }
entry({"admin", "services", "shadowsocksr", "client"}, cbi("shadowsocksr/client"), _("SSR Client"), 10).leaf = true
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua
-index 9853997..de97787 100644
+index 88351ff..e5f1593 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua
-@@ -70,45 +70,6 @@ o.default = "https://fastly.jsdelivr.net/gh/QiuSimons/Netflix_IP/NF_only.txt"
+@@ -75,45 +75,6 @@ o.default = "https://fastly.jsdelivr.net/gh/QiuSimons/Netflix_IP/NF_only.txt"
o.description = translate("Customize Netflix IP Url")
o:depends("netflix_enable", "1")
@@ -238,7 +238,7 @@ index 26de9ba..b24183e 100644
o = s:option(Value, "chinadns_forward", translate("Domestic DNS Server"))
o:value("", translate("Disable ChinaDNS-NG"))
diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua
-index 2a5c5e2..65b916e 100644
+index c7e84ec..83a88a2 100644
--- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua
+++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/status.lua
@@ -92,7 +92,7 @@ if Process_list:find("ssr.server") then
@@ -338,7 +338,7 @@ index d0b77f1..259cb7f 100644
res();
});
diff --git a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm
-index 0e19670..a7485ac 100644
+index 2607fb7..62e1b1c 100644
--- a/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm
+++ b/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm
@@ -69,9 +69,9 @@ function export_ssr_url(btn, urlname, sid) {
@@ -398,25 +398,25 @@ index 0e19670..a7485ac 100644
return false;
case "trojan":
try {
-@@ -234,7 +234,7 @@ function import_ssr_url(btn, urlname, sid) {
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls')[0].dispatchEvent(event);
- document.getElementsByName('cbid.shadowsocksr.' + sid + '.tls_host')[0].value = url.searchParams.get("sni");
+@@ -293,7 +293,7 @@ function import_ssr_url(btn, urlname, sid) {
+ break;
+ }
- s.innerHTML = "<%:Import configuration information successfully.%>";
+ s.innerHTML = "<%:Import configuration information successfully.%>";
return false;
case "vmess":
var sstr = b64DecodeUnicode(ssu[1]);
-@@ -296,7 +296,7 @@ function import_ssr_url(btn, urlname, sid) {
- }
+@@ -358,7 +358,7 @@ function import_ssr_url(btn, urlname, sid) {
document.getElementsByName('cbid.shadowsocksr.' + sid + '.mux')[0].checked = true;
document.getElementsByName('cbid.shadowsocksr.' + sid + '.mux')[0].dispatchEvent(event);
+ }
- s.innerHTML = "<%:Import configuration information successfully.%>";
+ s.innerHTML = "<%:Import configuration information successfully.%>";
return false;
case "vless":
try {
-@@ -388,10 +388,10 @@ function import_ssr_url(btn, urlname, sid) {
+@@ -463,10 +463,10 @@ function import_ssr_url(btn, urlname, sid) {
}
break;
}
@@ -430,10 +430,10 @@ index 0e19670..a7485ac 100644
}
}
diff --git a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po
-index 69dae19..7621a51 100644
+index 9992e81..6d547ca 100644
--- a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po
+++ b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po
-@@ -569,27 +569,6 @@ msgstr "使用 DNS2TCP 查询"
+@@ -577,27 +577,6 @@ msgstr "使用 DNS2TCP 查询"
msgid "Use DNS2SOCKS query and cache"
msgstr "使用 DNS2SOCKS 查询并缓存"