|
@@ -75,11 +75,20 @@ local encrypt_methods_ss = {
|
|
|
"camellia-256-cfb",
|
|
"camellia-256-cfb",
|
|
|
"salsa20",
|
|
"salsa20",
|
|
|
"chacha20",
|
|
"chacha20",
|
|
|
- "chacha20-ietf" ]]
|
|
|
|
|
|
|
+ "chacha20-ietf" ]]--
|
|
|
}
|
|
}
|
|
|
-- 分割字符串
|
|
-- 分割字符串
|
|
|
local function split(full, sep)
|
|
local function split(full, sep)
|
|
|
- full = full:gsub("%z", "") -- 这里不是很清楚 有时候结尾带个\0
|
|
|
|
|
|
|
+ if full == nil or type(full) ~= "string" then
|
|
|
|
|
+ -- print("Debug: split() received nil or non-string value")
|
|
|
|
|
+ return {}
|
|
|
|
|
+ end
|
|
|
|
|
+ full = full:gsub("%z", ""):gsub("^%s+", ""):gsub("%s+$", "") -- 去除首尾空白字符和\0
|
|
|
|
|
+ if full == "" then
|
|
|
|
|
+ -- print("Debug: split() received empty string after trimming")
|
|
|
|
|
+ return {}
|
|
|
|
|
+ end
|
|
|
|
|
+ sep = sep or "," -- 默认分隔符
|
|
|
local off, result = 1, {}
|
|
local off, result = 1, {}
|
|
|
while true do
|
|
while true do
|
|
|
local nStart, nEnd = full:find(sep, off)
|
|
local nStart, nEnd = full:find(sep, off)
|
|
@@ -154,9 +163,23 @@ local function checkTabValue(tab)
|
|
|
end
|
|
end
|
|
|
return revtab
|
|
return revtab
|
|
|
end
|
|
end
|
|
|
|
|
+-- JSON完整性检查
|
|
|
|
|
+local function isCompleteJSON(str)
|
|
|
|
|
+ -- 检查JSON格式
|
|
|
|
|
+ if type(str) ~= "string" or str:match("^%s*$") then
|
|
|
|
|
+ return false
|
|
|
|
|
+ end
|
|
|
|
|
+ -- 尝试解析JSON验证完整性
|
|
|
|
|
+ local success, _ = pcall(jsonParse, str)
|
|
|
|
|
+ return success
|
|
|
|
|
+end
|
|
|
-- 处理数据
|
|
-- 处理数据
|
|
|
local function processData(szType, content)
|
|
local function processData(szType, content)
|
|
|
local result = {type = szType, local_port = 1234, kcp_param = '--nocomp'}
|
|
local result = {type = szType, local_port = 1234, kcp_param = '--nocomp'}
|
|
|
|
|
+ -- 检查JSON的格式如不完整丢弃
|
|
|
|
|
+ if not isCompleteJSON(content) then
|
|
|
|
|
+ return nil
|
|
|
|
|
+ end
|
|
|
if szType == "hysteria2" then
|
|
if szType == "hysteria2" then
|
|
|
local url = URL.parse("http://" .. content)
|
|
local url = URL.parse("http://" .. content)
|
|
|
local params = url.query
|
|
local params = url.query
|
|
@@ -215,8 +238,13 @@ local function processData(szType, content)
|
|
|
result.alias = "[" .. group .. "] "
|
|
result.alias = "[" .. group .. "] "
|
|
|
end
|
|
end
|
|
|
result.alias = result.alias .. base64Decode(params.remarks)
|
|
result.alias = result.alias .. base64Decode(params.remarks)
|
|
|
- elseif szType == 'vmess' then
|
|
|
|
|
- local info = jsonParse(content)
|
|
|
|
|
|
|
+ elseif szType == "vmess" then
|
|
|
|
|
+ -- 解析正常节点
|
|
|
|
|
+ local success, info = pcall(jsonParse, content)
|
|
|
|
|
+ if not success or type(info) ~= "table" then
|
|
|
|
|
+ return nil
|
|
|
|
|
+ end
|
|
|
|
|
+ -- 处理有效数据
|
|
|
result.type = 'v2ray'
|
|
result.type = 'v2ray'
|
|
|
result.v2ray_protocol = 'vmess'
|
|
result.v2ray_protocol = 'vmess'
|
|
|
result.server = info.add
|
|
result.server = info.add
|
|
@@ -317,12 +345,21 @@ local function processData(szType, content)
|
|
|
idx_sp = content:find("#")
|
|
idx_sp = content:find("#")
|
|
|
alias = content:sub(idx_sp + 1, -1)
|
|
alias = content:sub(idx_sp + 1, -1)
|
|
|
end
|
|
end
|
|
|
- local info = content:sub(1, idx_sp - 1)
|
|
|
|
|
|
|
+ local info = content:sub(1, idx_sp > 0 and idx_sp - 1 or #content)
|
|
|
local hostInfo = split(base64Decode(info), "@")
|
|
local hostInfo = split(base64Decode(info), "@")
|
|
|
|
|
+ if #hostInfo < 2 then
|
|
|
|
|
+ --log("SS节点格式错误,解码后内容:", base64Decode(info))
|
|
|
|
|
+ return nil
|
|
|
|
|
+ end
|
|
|
local host = split(hostInfo[2], ":")
|
|
local host = split(hostInfo[2], ":")
|
|
|
|
|
+ if #host < 2 then
|
|
|
|
|
+ --log("SS节点主机格式错误:", hostInfo[2])
|
|
|
|
|
+ return nil
|
|
|
|
|
+ end
|
|
|
|
|
+ -- 提取用户信息
|
|
|
local userinfo = base64Decode(hostInfo[1])
|
|
local userinfo = base64Decode(hostInfo[1])
|
|
|
- local method = userinfo:sub(1, userinfo:find(":") - 1)
|
|
|
|
|
- local password = userinfo:sub(userinfo:find(":") + 1, #userinfo)
|
|
|
|
|
|
|
+ local method, password = userinfo:match("^([^:]*):(.*)$")
|
|
|
|
|
+ -- 填充结果
|
|
|
result.alias = UrlDecode(alias)
|
|
result.alias = UrlDecode(alias)
|
|
|
result.type = v2_ss
|
|
result.type = v2_ss
|
|
|
result.v2ray_protocol = (v2_ss == "v2ray") and "shadowsocks" or nil
|
|
result.v2ray_protocol = (v2_ss == "v2ray") and "shadowsocks" or nil
|
|
@@ -330,39 +367,47 @@ local function processData(szType, content)
|
|
|
result.encrypt_method_ss = method
|
|
result.encrypt_method_ss = method
|
|
|
result.password = password
|
|
result.password = password
|
|
|
result.server = host[1]
|
|
result.server = host[1]
|
|
|
- if host[2]:find("/%?") then
|
|
|
|
|
- local query = split(host[2], "/%?")
|
|
|
|
|
|
|
+ -- 处理端口和插件
|
|
|
|
|
+ local port_part = host[2]
|
|
|
|
|
+ if port_part:find("/%?") then
|
|
|
|
|
+ local query = split(port_part, "/%?")
|
|
|
result.server_port = query[1]
|
|
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
|
|
|
|
|
- result.plugin_opts = ""
|
|
|
|
|
- end
|
|
|
|
|
- -- 部分机场下发的插件名为 simple-obfs,这里应该改为 obfs-local
|
|
|
|
|
- if result.plugin == "simple-obfs" then
|
|
|
|
|
- result.plugin = "obfs-local"
|
|
|
|
|
|
|
+ if query[2] then
|
|
|
|
|
+ local params = {}
|
|
|
|
|
+ for _, v in pairs(split(query[2], '&')) do
|
|
|
|
|
+ local t = split(v, '=')
|
|
|
|
|
+ if #t >= 2 then
|
|
|
|
|
+ params[t[1]] = t[2]
|
|
|
|
|
+ end
|
|
|
end
|
|
end
|
|
|
- -- 如果插件不為 none,確保 enable_plugin 為 1
|
|
|
|
|
- if result.plugin ~= "none" and result.plugin ~= "" then
|
|
|
|
|
- result.enable_plugin = 1
|
|
|
|
|
|
|
+ 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
|
|
|
|
|
+ result.plugin_opts = ""
|
|
|
|
|
+ end
|
|
|
|
|
+ -- 部分机场下发的插件名为 simple-obfs,这里应该改为 obfs-local
|
|
|
|
|
+ if result.plugin == "simple-obfs" then
|
|
|
|
|
+ result.plugin = "obfs-local"
|
|
|
|
|
+ end
|
|
|
|
|
+ -- 如果插件不为 none,确保 enable_plugin 为 1
|
|
|
|
|
+ if result.plugin ~= "none" and result.plugin ~= "" then
|
|
|
|
|
+ result.enable_plugin = 1
|
|
|
|
|
+ end
|
|
|
end
|
|
end
|
|
|
end
|
|
end
|
|
|
else
|
|
else
|
|
|
- result.server_port = host[2]:gsub("/","")
|
|
|
|
|
|
|
+ result.server_port = port_part:gsub("/","")
|
|
|
end
|
|
end
|
|
|
|
|
+ -- 检查加密方法
|
|
|
if not checkTabValue(encrypt_methods_ss)[method] then
|
|
if not checkTabValue(encrypt_methods_ss)[method] then
|
|
|
- -- 1202 年了还不支持 SS AEAD 的屑机场
|
|
|
|
|
- result.server = nil
|
|
|
|
|
|
|
+ -- 1202 年了还不支持 SS AEAD 的屑机场
|
|
|
|
|
+ -- log("不支持的SS加密方法:", method)
|
|
|
|
|
+ result.server = nil
|
|
|
end
|
|
end
|
|
|
elseif szType == "sip008" then
|
|
elseif szType == "sip008" then
|
|
|
result.type = v2_ss
|
|
result.type = v2_ss
|
|
@@ -606,7 +651,7 @@ local function processData(szType, content)
|
|
|
end
|
|
end
|
|
|
-- wget
|
|
-- wget
|
|
|
local function wget(url)
|
|
local function wget(url)
|
|
|
- local stdout = luci.sys.exec('wget-ssl -q --user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36" --no-check-certificate -O- "' .. url .. '"')
|
|
|
|
|
|
|
+ local stdout = luci.sys.exec('wget-ssl --timeout=20 --tries=3 -q --user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36" --no-check-certificate -O- "' .. url .. '"')
|
|
|
return trim(stdout)
|
|
return trim(stdout)
|
|
|
end
|
|
end
|
|
|
|
|
|
|
@@ -819,5 +864,3 @@ if subscribe_url and #subscribe_url > 0 then
|
|
|
end
|
|
end
|
|
|
end)
|
|
end)
|
|
|
end
|
|
end
|
|
|
-
|
|
|
|
|
-
|
|
|