|
@@ -318,8 +318,10 @@ local function processData(szType, content)
|
|
result.xhttp_host = info.host
|
|
result.xhttp_host = info.host
|
|
result.xhttp_path = info.path
|
|
result.xhttp_path = info.path
|
|
-- 检查 extra 参数是否存在且非空
|
|
-- 检查 extra 参数是否存在且非空
|
|
- result.enable_xhttp_extra = (info.extra and info.extra ~= "") and "1" or nil
|
|
|
|
- result.xhttp_extra = (info.extra and info.extra ~= "") and info.extra or nil
|
|
|
|
|
|
+ if params.extra and params.extra ~= "" then
|
|
|
|
+ result.enable_xhttp_extra = "1"
|
|
|
|
+ result.xhttp_extra = params.extra
|
|
|
|
+ end
|
|
-- 尝试解析 JSON 数据
|
|
-- 尝试解析 JSON 数据
|
|
local success, Data = pcall(jsonParse, info.extra or "")
|
|
local success, Data = pcall(jsonParse, info.extra or "")
|
|
if success and type(Data) == "table" then
|
|
if success and type(Data) == "table" then
|
|
@@ -403,16 +405,18 @@ local function processData(szType, content)
|
|
local idx_sp = content:find("#") or 0
|
|
local idx_sp = content:find("#") or 0
|
|
local alias = ""
|
|
local alias = ""
|
|
if idx_sp > 0 then
|
|
if idx_sp > 0 then
|
|
- alias = UrlDecode(content:sub(idx_sp + 1))
|
|
|
|
|
|
+ alias = content:sub(idx_sp + 1, -1)
|
|
|
|
+ content = content:sub(0, idx_sp - 1):gsub("/%?", "?")
|
|
end
|
|
end
|
|
- local info = content:sub(1, idx_sp > 0 and idx_sp - 1 or #content):gsub("/%?", "?")
|
|
|
|
|
|
+ result.alias = UrlDecode(alias)
|
|
|
|
|
|
-- 拆 base64 主体和 ? 参数部分
|
|
-- 拆 base64 主体和 ? 参数部分
|
|
- local uri_main, query_str = info:match("^([^?]+)%??(.*)$")
|
|
|
|
- --log("SS 节点格式:", uri_main)
|
|
|
|
|
|
+ local info = content
|
|
|
|
+ local find_index, query = info:match("^([^?]+)%??(.*)$")
|
|
|
|
+ --log("SS 节点格式:", find_index)
|
|
local params = {}
|
|
local params = {}
|
|
- if query_str and query_str ~= "" then
|
|
|
|
- for _, v in ipairs(split(query_str, '&')) do
|
|
|
|
|
|
+ if query and query ~= "" then
|
|
|
|
+ for _, v in ipairs(split(query, '&')) do
|
|
local t = split(v, '=')
|
|
local t = split(v, '=')
|
|
if #t >= 2 then
|
|
if #t >= 2 then
|
|
params[t[1]] = UrlDecode(t[2])
|
|
params[t[1]] = UrlDecode(t[2])
|
|
@@ -421,28 +425,28 @@ local function processData(szType, content)
|
|
end
|
|
end
|
|
|
|
|
|
if not params.type or params.type == "" then
|
|
if not params.type or params.type == "" then
|
|
- local is_old_format = uri_main:find("@") and not uri_main:find("://.*@")
|
|
|
|
- local base64_str, host_port, userinfo, server, port, method, password
|
|
|
|
|
|
+ local is_old_format = find_index:find("@") and not find_index:find("://.*@")
|
|
|
|
+ local old_base64, host_port, userinfo, server, port, method, password
|
|
|
|
|
|
if is_old_format then
|
|
if is_old_format then
|
|
-- 旧格式:base64(method:pass)@host:port
|
|
-- 旧格式:base64(method:pass)@host:port
|
|
- base64_str, host_port = uri_main:match("^([^@]+)@(.-)$")
|
|
|
|
- log("SS 节点旧格式解析:", base64_str)
|
|
|
|
- if not base64_str or not host_port then
|
|
|
|
- log("SS 节点旧格式解析失败:", uri_main)
|
|
|
|
|
|
+ old_base64, host_port = find_index:match("^([^@]+)@(.-)$")
|
|
|
|
+ log("SS 节点旧格式解析:", old_base64)
|
|
|
|
+ if not old_base64 or not host_port then
|
|
|
|
+ log("SS 节点旧格式解析失败:", find_index)
|
|
return nil
|
|
return nil
|
|
end
|
|
end
|
|
- local decoded = base64Decode(UrlDecode(base64_str))
|
|
|
|
|
|
+ local decoded = base64Decode(UrlDecode(old_base64))
|
|
if not decoded then
|
|
if not decoded then
|
|
- log("SS base64 解码失败(旧格式):", base64_str)
|
|
|
|
|
|
+ log("SS base64 解码失败(旧格式):", old_base64)
|
|
return nil
|
|
return nil
|
|
end
|
|
end
|
|
userinfo = decoded
|
|
userinfo = decoded
|
|
else
|
|
else
|
|
-- 新格式:base64(method:pass@host:port)
|
|
-- 新格式:base64(method:pass@host:port)
|
|
- local decoded = base64Decode(UrlDecode(uri_main))
|
|
|
|
|
|
+ local decoded = base64Decode(UrlDecode(find_index))
|
|
if not decoded then
|
|
if not decoded then
|
|
- log("SS base64 解码失败(新格式):", uri_main)
|
|
|
|
|
|
+ log("SS base64 解码失败(新格式):", find_index)
|
|
return nil
|
|
return nil
|
|
end
|
|
end
|
|
userinfo, host_port = decoded:match("^(.-)@(.-)$")
|
|
userinfo, host_port = decoded:match("^(.-)@(.-)$")
|
|
@@ -453,13 +457,13 @@ local function processData(szType, content)
|
|
end
|
|
end
|
|
|
|
|
|
-- 解析加密方式和密码(允许密码包含冒号)
|
|
-- 解析加密方式和密码(允许密码包含冒号)
|
|
- local split_pos = userinfo:find(":")
|
|
|
|
- if not split_pos then
|
|
|
|
|
|
+ local meth_pass = userinfo:find(":")
|
|
|
|
+ if not meth_pass then
|
|
log("SS 用户信息格式错误:", userinfo)
|
|
log("SS 用户信息格式错误:", userinfo)
|
|
return nil
|
|
return nil
|
|
end
|
|
end
|
|
- method = userinfo:sub(1, split_pos - 1)
|
|
|
|
- password = userinfo:sub(split_pos + 1)
|
|
|
|
|
|
+ method = userinfo:sub(1, meth_pass - 1)
|
|
|
|
+ password = userinfo:sub(meth_pass + 1)
|
|
|
|
|
|
-- 判断密码是否经过url编码
|
|
-- 判断密码是否经过url编码
|
|
local function isURLEncodedPassword(pwd)
|
|
local function isURLEncodedPassword(pwd)
|
|
@@ -492,23 +496,13 @@ local function processData(szType, content)
|
|
end
|
|
end
|
|
|
|
|
|
-- 填充 result
|
|
-- 填充 result
|
|
- result.alias = alias
|
|
|
|
result.type = v2_ss
|
|
result.type = v2_ss
|
|
- result.v2ray_protocol = (v2_ss == "v2ray") and "shadowsocks" or nil
|
|
|
|
result.has_ss_type = has_ss_type
|
|
result.has_ss_type = has_ss_type
|
|
result.encrypt_method_ss = method
|
|
result.encrypt_method_ss = method
|
|
result.password = password
|
|
result.password = password
|
|
result.server = server
|
|
result.server = server
|
|
result.server_port = port
|
|
result.server_port = port
|
|
|
|
|
|
- -- 仅在 v2ray + shadowsocks 协议时处理 ECH
|
|
|
|
- if v2_ss == "v2ray" and result.v2ray_protocol == "shadowsocks" then
|
|
|
|
- if params.ech and params.ech ~= "" then
|
|
|
|
- result.enable_ech = "1"
|
|
|
|
- result.ech_config = ech
|
|
|
|
- end
|
|
|
|
- end
|
|
|
|
-
|
|
|
|
-- 插件处理
|
|
-- 插件处理
|
|
if params.plugin then
|
|
if params.plugin then
|
|
local plugin_info = UrlDecode(params.plugin)
|
|
local plugin_info = UrlDecode(params.plugin)
|
|
@@ -573,17 +567,17 @@ local function processData(szType, content)
|
|
local url = URL.parse("http://" .. info)
|
|
local url = URL.parse("http://" .. info)
|
|
local params = url.query
|
|
local params = url.query
|
|
|
|
|
|
- result.alias = alias
|
|
|
|
- result.type = "v2ray"
|
|
|
|
|
|
+ v2_ss = "v2ray"
|
|
|
|
+ result.type = v2_ss
|
|
result.v2ray_protocol = "shadowsocks"
|
|
result.v2ray_protocol = "shadowsocks"
|
|
result.server = url.host
|
|
result.server = url.host
|
|
result.server_port = url.port
|
|
result.server_port = url.port
|
|
|
|
|
|
-- 判断 @ 前部分是否为 Base64
|
|
-- 判断 @ 前部分是否为 Base64
|
|
- local is_base64_decoded = base64Decode(UrlDecode(url.user))
|
|
|
|
- if is_base64_decoded:find(":") then
|
|
|
|
|
|
+ local is_base64 = base64Decode(UrlDecode(url.user))
|
|
|
|
+ if is_base64:find(":") then
|
|
-- 新格式:method:password
|
|
-- 新格式:method:password
|
|
- result.encrypt_method_ss, result.password = is_base64_decoded:match("^(.-):(.*)$")
|
|
|
|
|
|
+ result.encrypt_method_ss, result.password = is_base64:match("^(.-):(.*)$")
|
|
else
|
|
else
|
|
-- 旧格式:UUID 直接作为密码
|
|
-- 旧格式:UUID 直接作为密码
|
|
result.password = url.user
|
|
result.password = url.user
|
|
@@ -613,11 +607,15 @@ local function processData(szType, content)
|
|
result.reality_shortid = params.sid
|
|
result.reality_shortid = params.sid
|
|
result.reality_spiderx = params.spx and UrlDecode(params.spx) or nil
|
|
result.reality_spiderx = params.spx and UrlDecode(params.spx) or nil
|
|
-- 检查 ech 参数是否存在且非空
|
|
-- 检查 ech 参数是否存在且非空
|
|
- result.enable_ech = (params.ech and params.ech ~= "") and "1" or nil
|
|
|
|
- result.ech_config = (params.ech and params.ech ~= "") and params.ech or nil
|
|
|
|
|
|
+ if params.ech and params.ech ~= "" then
|
|
|
|
+ result.enable_ech = "1"
|
|
|
|
+ result.ech_config = params.ech
|
|
|
|
+ end
|
|
-- 检查 pqv 参数是否存在且非空
|
|
-- 检查 pqv 参数是否存在且非空
|
|
- result.enable_mldsa65verify = (params.pqv and params.pqv ~= "") and "1" or nil
|
|
|
|
- result.reality_mldsa65verify = (params.pqv and params.pqv ~= "") and params.pqv or nil
|
|
|
|
|
|
+ if params.pqv and params.pqv ~= "" then
|
|
|
|
+ result.enable_mldsa65verify = "1"
|
|
|
|
+ result.reality_mldsa65verify = params.pqv
|
|
|
|
+ end
|
|
if result.transport == "ws" then
|
|
if result.transport == "ws" then
|
|
result.ws_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil
|
|
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 "/"
|
|
result.ws_path = params.path and UrlDecode(params.path) or "/"
|
|
@@ -629,8 +627,10 @@ local function processData(szType, content)
|
|
result.xhttp_mode = params.mode or "auto"
|
|
result.xhttp_mode = params.mode or "auto"
|
|
result.xhttp_path = params.path and UrlDecode(params.path) or "/"
|
|
result.xhttp_path = params.path and UrlDecode(params.path) or "/"
|
|
-- 检查 extra 参数是否存在且非空
|
|
-- 检查 extra 参数是否存在且非空
|
|
- result.enable_xhttp_extra = (params.extra and params.extra ~= "") and "1" or nil
|
|
|
|
- result.xhttp_extra = (params.extra and params.extra ~= "") and params.extra or nil
|
|
|
|
|
|
+ if params.extra and params.extra ~= "" then
|
|
|
|
+ result.enable_xhttp_extra = "1"
|
|
|
|
+ result.xhttp_extra = params.extra
|
|
|
|
+ end
|
|
-- 尝试解析 JSON 数据
|
|
-- 尝试解析 JSON 数据
|
|
local success, Data = pcall(jsonParse, params.extra or "")
|
|
local success, Data = pcall(jsonParse, params.extra or "")
|
|
if success and type(Data) == "table" then
|
|
if success and type(Data) == "table" then
|
|
@@ -703,90 +703,67 @@ local function processData(szType, content)
|
|
result.server = nil
|
|
result.server = nil
|
|
end
|
|
end
|
|
elseif szType == "trojan" then
|
|
elseif szType == "trojan" then
|
|
- local params = {}
|
|
|
|
- local idx_sp = 0
|
|
|
|
- local alias = ""
|
|
|
|
-
|
|
|
|
-- 提取别名(如果存在)
|
|
-- 提取别名(如果存在)
|
|
|
|
+ local alias = ""
|
|
if content:find("#") then
|
|
if content:find("#") then
|
|
- idx_sp = content:find("#")
|
|
|
|
|
|
+ local idx_sp = content:find("#")
|
|
alias = content:sub(idx_sp + 1, -1)
|
|
alias = content:sub(idx_sp + 1, -1)
|
|
|
|
+ content = content:sub(0, idx_sp - 1)
|
|
end
|
|
end
|
|
- local info = content:sub(1, idx_sp > 0 and idx_sp - 1 or #content):gsub("/%?", "?")
|
|
|
|
- local paramStr = ""
|
|
|
|
-
|
|
|
|
- if info:find("?") then
|
|
|
|
- paramStr = info:match("%?(.*)$") or ""
|
|
|
|
- info = info:gsub("%?.*$", "") -- 去掉 ? 后的参数部分
|
|
|
|
- end
|
|
|
|
-
|
|
|
|
- -- 解析 query 参数(key=value&key2=value2)
|
|
|
|
- for k, v in paramStr:gmatch("([^&=?]+)=([^&=?]+)") do
|
|
|
|
- params[k] = UrlDecode(v)
|
|
|
|
- end
|
|
|
|
-
|
|
|
|
- local hostInfo = split(info, "@")
|
|
|
|
-
|
|
|
|
- -- 基础验证
|
|
|
|
- if #hostInfo < 2 then
|
|
|
|
- --log("Trojan节点格式错误: 缺少@符号")
|
|
|
|
- return nil
|
|
|
|
- end
|
|
|
|
-
|
|
|
|
- local userinfo = hostInfo[1]
|
|
|
|
- local hostPort = hostInfo[2]
|
|
|
|
-
|
|
|
|
- -- 分离服务器地址和端口
|
|
|
|
- local hostParts = split(hostPort, ":")
|
|
|
|
-
|
|
|
|
- -- 验证服务器地址和端口
|
|
|
|
- if #hostParts < 2 then
|
|
|
|
- --log("Trojan节点格式错误: 缺少端口号")
|
|
|
|
- return nil
|
|
|
|
- end
|
|
|
|
-
|
|
|
|
- local server = hostParts[1]
|
|
|
|
- local port = hostParts[2]
|
|
|
|
-
|
|
|
|
result.alias = UrlDecode(alias)
|
|
result.alias = UrlDecode(alias)
|
|
- result.server = server
|
|
|
|
- result.password = userinfo
|
|
|
|
-
|
|
|
|
- -- 默认设置
|
|
|
|
- -- 按照官方的建议 默认验证ssl证书
|
|
|
|
- result.insecure = "0"
|
|
|
|
- result.tls = "1"
|
|
|
|
-
|
|
|
|
- -- 解析查询参数(如果存在)
|
|
|
|
- if port:find("?") then
|
|
|
|
- local queryParts = split(port, "?")
|
|
|
|
- result.server_port = queryParts[1]
|
|
|
|
-
|
|
|
|
- -- 解析查询参数
|
|
|
|
- for _, v in pairs(split(queryParts[2], "&")) do
|
|
|
|
- local t = split(v, "=")
|
|
|
|
- if #t >= 2 then
|
|
|
|
- params[t[1]] = t[2]
|
|
|
|
|
|
+
|
|
|
|
+ -- 分离和提取 password
|
|
|
|
+ local Info = content
|
|
|
|
+ local params = {}
|
|
|
|
+ if Info:find("@") then
|
|
|
|
+ local contents = split(Info, "@")
|
|
|
|
+ result.password = UrlDecode(contents[1])
|
|
|
|
+ local port = "443"
|
|
|
|
+ Info = (contents[2] or ""):gsub("/%?", "?")
|
|
|
|
+
|
|
|
|
+ -- 分离主机和 query 参数(key=value&key2=value2)
|
|
|
|
+ local query = split(Info, "%?")
|
|
|
|
+ local host_port = query[1]
|
|
|
|
+ for _, v in pairs(split(query[2], '&')) do
|
|
|
|
+ local t = split(v, '=')
|
|
|
|
+ if #t > 1 then
|
|
|
|
+ params[string.lower(t[1])] = UrlDecode(t[2])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
+ -- 提取服务器地址和端口
|
|
|
|
+ if host_port:find(":") then
|
|
|
|
+ local sp = split(host_port, ":")
|
|
|
|
+ result.server_port = sp[#sp]
|
|
|
|
+ result.server = sp[1]
|
|
|
|
+ else
|
|
|
|
+ result.server = host_port
|
|
|
|
+ end
|
|
|
|
+
|
|
|
|
+ -- 默认设置
|
|
|
|
+ -- 按照官方的建议 默认验证ssl证书
|
|
|
|
+ result.insecure = "0"
|
|
|
|
+ result.tls = "1"
|
|
|
|
+
|
|
-- 处理参数
|
|
-- 处理参数
|
|
if params.alpn then
|
|
if params.alpn then
|
|
-- 处理 alpn 参数
|
|
-- 处理 alpn 参数
|
|
result.tls_alpn = params.alpn
|
|
result.tls_alpn = params.alpn
|
|
end
|
|
end
|
|
-
|
|
|
|
- if params.sni then
|
|
|
|
|
|
+ if params.peer or params.sni then
|
|
-- 未指定peer(sni)默认使用remote addr
|
|
-- 未指定peer(sni)默认使用remote addr
|
|
- result.tls_host = params.sni
|
|
|
|
|
|
+ result.tls_host = params.peer or params.sni
|
|
end
|
|
end
|
|
-
|
|
|
|
if params.allowInsecure then
|
|
if params.allowInsecure then
|
|
-- 处理 insecure 参数
|
|
-- 处理 insecure 参数
|
|
- result.insecure = params.allowInsecure
|
|
|
|
|
|
+ if params.allowinsecure == "1" or params.allowinsecure == "0" then
|
|
|
|
+ result.insecure = params.allowInsecure
|
|
|
|
+ else
|
|
|
|
+ result.insecure = string.lower(params.allowinsecure) == "true" and "1" or "0"
|
|
|
|
+ end
|
|
end
|
|
end
|
|
if params.tfo then
|
|
if params.tfo then
|
|
- -- 处理 insecure 参数
|
|
|
|
|
|
+ -- 处理 fast open 参数
|
|
result.fast_open = params.tfo
|
|
result.fast_open = params.tfo
|
|
end
|
|
end
|
|
else
|
|
else
|
|
@@ -831,8 +808,10 @@ local function processData(szType, content)
|
|
result.xhttp_mode = params.mode or "auto"
|
|
result.xhttp_mode = params.mode or "auto"
|
|
result.xhttp_path = params.path and UrlDecode(params.path) or "/"
|
|
result.xhttp_path = params.path and UrlDecode(params.path) or "/"
|
|
-- 检查 extra 参数是否存在且非空
|
|
-- 检查 extra 参数是否存在且非空
|
|
- result.enable_xhttp_extra = (params.extra and params.extra ~= "") and "1" or nil
|
|
|
|
- result.xhttp_extra = (params.extra and params.extra ~= "") and params.extra or nil
|
|
|
|
|
|
+ if params.extra and params.extra ~= "" then
|
|
|
|
+ result.enable_xhttp_extra = "1"
|
|
|
|
+ result.xhttp_extra = params.extra
|
|
|
|
+ end
|
|
-- 尝试解析 JSON 数据
|
|
-- 尝试解析 JSON 数据
|
|
local success, Data = pcall(jsonParse, params.extra or "")
|
|
local success, Data = pcall(jsonParse, params.extra or "")
|
|
if success and type(Data) == "table" then
|
|
if success and type(Data) == "table" then
|
|
@@ -908,11 +887,15 @@ local function processData(szType, content)
|
|
result.reality_shortid = params.sid
|
|
result.reality_shortid = params.sid
|
|
result.reality_spiderx = params.spx and UrlDecode(params.spx) or nil
|
|
result.reality_spiderx = params.spx and UrlDecode(params.spx) or nil
|
|
-- 检查 ech 参数是否存在且非空
|
|
-- 检查 ech 参数是否存在且非空
|
|
- result.enable_ech = (params.ech and params.ech ~= "") and "1" or nil
|
|
|
|
- result.ech_config = (params.ech and params.ech ~= "") and params.ech or nil
|
|
|
|
|
|
+ if params.ech and params.ech ~= "" then
|
|
|
|
+ result.enable_ech = "1"
|
|
|
|
+ result.ech_config = params.ech
|
|
|
|
+ end
|
|
-- 检查 pqv 参数是否存在且非空
|
|
-- 检查 pqv 参数是否存在且非空
|
|
- result.enable_mldsa65verify = (params.pqv and params.pqv ~= "") and "1" or nil
|
|
|
|
- result.reality_mldsa65verify = (params.pqv and params.pqv ~= "") and params.pqv or nil
|
|
|
|
|
|
+ if params.pqv and params.pqv ~= "" then
|
|
|
|
+ result.enable_mldsa65verify = "1"
|
|
|
|
+ result.reality_mldsa65verify = params.pqv
|
|
|
|
+ end
|
|
if result.transport == "ws" then
|
|
if result.transport == "ws" then
|
|
result.ws_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil
|
|
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 "/"
|
|
result.ws_path = params.path and UrlDecode(params.path) or "/"
|
|
@@ -924,8 +907,10 @@ local function processData(szType, content)
|
|
result.xhttp_mode = params.mode or "auto"
|
|
result.xhttp_mode = params.mode or "auto"
|
|
result.xhttp_path = params.path and UrlDecode(params.path) or "/"
|
|
result.xhttp_path = params.path and UrlDecode(params.path) or "/"
|
|
-- 检查 extra 参数是否存在且非空
|
|
-- 检查 extra 参数是否存在且非空
|
|
- result.enable_xhttp_extra = (params.extra and params.extra ~= "") and "1" or nil
|
|
|
|
- result.xhttp_extra = (params.extra and params.extra ~= "") and params.extra or nil
|
|
|
|
|
|
+ if params.extra and params.extra ~= "" then
|
|
|
|
+ result.enable_xhttp_extra = "1"
|
|
|
|
+ result.xhttp_extra = params.extra
|
|
|
|
+ end
|
|
-- 尝试解析 JSON 数据
|
|
-- 尝试解析 JSON 数据
|
|
local success, Data = pcall(jsonParse, params.extra or "")
|
|
local success, Data = pcall(jsonParse, params.extra or "")
|
|
if success and type(Data) == "table" then
|
|
if success and type(Data) == "table" then
|
|
@@ -965,64 +950,48 @@ local function processData(szType, content)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif szType == "tuic" then
|
|
elseif szType == "tuic" then
|
|
- local params = {}
|
|
|
|
- local idx_sp = 0
|
|
|
|
- local alias = ""
|
|
|
|
-
|
|
|
|
-- 提取别名(如果存在)
|
|
-- 提取别名(如果存在)
|
|
|
|
+ local alias = ""
|
|
if content:find("#") then
|
|
if content:find("#") then
|
|
- idx_sp = content:find("#")
|
|
|
|
|
|
+ local idx_sp = content:find("#")
|
|
alias = content:sub(idx_sp + 1, -1)
|
|
alias = content:sub(idx_sp + 1, -1)
|
|
|
|
+ content = content:sub(0, idx_sp - 1)
|
|
end
|
|
end
|
|
- local info = content:sub(1, idx_sp > 0 and idx_sp - 1 or #content):gsub("/%?", "?")
|
|
|
|
- local paramStr = ""
|
|
|
|
-
|
|
|
|
- if info:find("?") then
|
|
|
|
- paramStr = info:match("%?(.*)$") or ""
|
|
|
|
- info = info:gsub("%?.*$", "") -- 去掉 ? 后的参数部分
|
|
|
|
- end
|
|
|
|
|
|
+ result.alias = UrlDecode(alias)
|
|
|
|
|
|
- -- 解析 query 参数(key=value&key2=value2)
|
|
|
|
- for k, v in paramStr:gmatch("([^&=?]+)=([^&=?]+)") do
|
|
|
|
- params[k] = UrlDecode(v)
|
|
|
|
|
|
+ -- 分离和提取 uuid 和 password
|
|
|
|
+ local Info = content
|
|
|
|
+ if Info:find("@") then
|
|
|
|
+ local contents = split(Info, "@")
|
|
|
|
+ if contents[1]:find(":") then
|
|
|
|
+ local userinfo = split(contents[1], ":")
|
|
|
|
+ result.tuic_uuid = UrlDecode(userinfo[1])
|
|
|
|
+ result.tuic_passwd = UrlDecode(userinfo[2])
|
|
|
|
+ end
|
|
|
|
+ Info = (contents[2] or ""):gsub("/%?", "?")
|
|
end
|
|
end
|
|
|
|
|
|
- local hostInfo = split(info, "@")
|
|
|
|
- -- 基础验证
|
|
|
|
- if #hostInfo < 2 then
|
|
|
|
- log("TUIC 节点格式错误: 缺少 @")
|
|
|
|
- return nil
|
|
|
|
|
|
+ -- 分离主机和 query 参数(key=value&key2=value2)
|
|
|
|
+ local query = split(Info, "%?")
|
|
|
|
+ local host_port = query[1]
|
|
|
|
+ local params = {}
|
|
|
|
+ for _, v in pairs(split(query[2], '&')) do
|
|
|
|
+ local t = split(v, '=')
|
|
|
|
+ if #t > 1 then
|
|
|
|
+ params[string.lower(t[1])] = UrlDecode(t[2])
|
|
|
|
+ end
|
|
end
|
|
end
|
|
|
|
|
|
- local userinfo = hostInfo[1]
|
|
|
|
- local hostPort = hostInfo[2]
|
|
|
|
-
|
|
|
|
- -- 分离 uuid 和 password
|
|
|
|
- local userInfoSplit = split(userinfo, ":")
|
|
|
|
- if #userInfoSplit < 2 then
|
|
|
|
- log("TUIC 节点格式错误: 用户信息不完整")
|
|
|
|
- return nil
|
|
|
|
- end
|
|
|
|
- local uuid = userInfoSplit[1]
|
|
|
|
- local password = userInfoSplit[2]
|
|
|
|
-
|
|
|
|
- -- 分离服务器地址和端口
|
|
|
|
- local hostParts = split(hostPort, ":")
|
|
|
|
- -- 验证服务器地址和端口
|
|
|
|
- if #hostParts < 2 then
|
|
|
|
- log("TUIC 节点格式错误: 缺少端口号")
|
|
|
|
- return nil
|
|
|
|
|
|
+ -- 提取服务器地址和端口
|
|
|
|
+ if host_port:find(":") then
|
|
|
|
+ local sp = split(host_port, ":")
|
|
|
|
+ result.server_port = sp[#sp]
|
|
|
|
+ result.server = sp[1]
|
|
|
|
+ else
|
|
|
|
+ result.server = host_port
|
|
end
|
|
end
|
|
- local server = hostParts[1]
|
|
|
|
- local port = hostParts[2]
|
|
|
|
|
|
|
|
result.type = tuic_type
|
|
result.type = tuic_type
|
|
- result.alias = UrlDecode(alias)
|
|
|
|
- result.server = server
|
|
|
|
- result.server_port = port
|
|
|
|
- result.tuic_uuid = uuid
|
|
|
|
- result.tuic_passwd = password
|
|
|
|
-
|
|
|
|
result.tuic_ip = params.sni or ""
|
|
result.tuic_ip = params.sni or ""
|
|
result.udp_relay_mode = params.udp_relay_mode or "native"
|
|
result.udp_relay_mode = params.udp_relay_mode or "native"
|
|
result.congestion_control = params.congestion_control or "cubic"
|
|
result.congestion_control = params.congestion_control or "cubic"
|