update 2024-12-31 00:24:40

This commit is contained in:
kenzok8 2024-12-31 00:24:40 +08:00
parent 981a076945
commit accb1bd370
10 changed files with 520 additions and 38 deletions

View File

@ -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 .. "<font color = 'green'>[" .. server_name .. "] OK.</font><br />"
retstring .. "<font><b style='color:green'>[" .. server_name .. "] OK.</b></font><br />"
else
retstring = retstring .. "<font color = 'red'>[" .. server_name .. "] Error.</font><br />"
retstring = retstring .. "<font><b style='color:red'>[" .. server_name .. "] Error.</b></font><br />"
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

View File

@ -937,7 +937,7 @@ if is_finded("xray") then
-- [[ 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"))
@ -1016,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"})

View File

@ -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.") ..
"<br><font style='color:red'><b>" ..
translate("Note: Restoring configurations across different versions may cause compatibility issues.") ..
"</b></font>")
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

View File

@ -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

View File

@ -0,0 +1,154 @@
<%+cbi/valueheader%>
<div class="cbi-value" id="_backup_div">
<label class="cbi-value-title"><%:Create Backup File%></label>
<div class="cbi-value-field">
<input type="button" class="btn cbi-button cbi-input-apply" onclick="dl_backup()" value="<%:DL Backup%>" />
</div>
</div>
<div class="cbi-value" id="_upload_div">
<label class="cbi-value-title"><%:Restore Backup File%></label>
<div class="cbi-value-field">
<input type="button" class="btn cbi-button cbi-input-apply" id="upload-btn" value="<%:RST Backup%>" />
</div>
</div>
<div class="cbi-value" id="_reset_div">
<label class="cbi-value-title"><%:Restore to default configuration%></label>
<div class="cbi-value-field">
<input type="button" class="btn cbi-button cbi-button-remove" onclick="do_reset()" value="<%:Do Reset%>" />
</div>
</div>
<div id="upload-modal" class="up-modal" style="display:none;">
<div class="up-modal-content">
<h3><%:Restore Backup File%></h3>
<div class="cbi-value" id="_upload_div">
<div class="up-cbi-value-field">
<input class="cbi-input-file" type="file" id="ulfile" name="ulfile" accept=".tar.gz" required />
<br />
<div class="up-button-container">
<input type="submit" class="btn cbi-button cbi-input-apply" value="<%:UL Restore%>" />
<button class="btn cbi-button cbi-button-remove" id="upload-close"><%:CLOSE WIN%></button>
</div>
</div>
</div>
</div>
</div>
<style>
.up-modal {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border: 2px solid #ccc;
box-shadow: 0 0 10px rgba(0,0,0,0.5);
z-index: 1000;
}
.up-modal-content {
width: 100%;
max-width: 400px;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.up-button-container {
display: flex;
justify-content: space-between;
width: 100%;
max-width: 250px;
}
.up-cbi-value-field {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
</style>
<script>
// JavaScript 版本的 url 函数
function url(...args) {
let url = "/cgi-bin/luci/admin/services/shadowsocksr";
for (let i = 0; i < args.length; i++) {
if (args[i] !== "") {
url += "/" + args[i];
}
}
return url;
}
// 上传按钮点击事件
document.getElementById("upload-btn").addEventListener("click", function() {
document.getElementById("upload-modal").style.display = "block";
});
// 关闭上传模态框
document.getElementById("upload-close").addEventListener("click", function() {
document.getElementById("upload-modal").style.display = "none";
});
// 备份下载函数
function dl_backup(btn) {
fetch(url("backup"), { // 使用 JavaScript 版本的 url 函数
method: 'POST',
credentials: 'same-origin'
})
.then(response => {
if (!response.ok) {
throw new Error("备份失败!");
}
const filename = response.headers.get("X-Backup-Filename");
if (!filename) {
return;
}
return response.blob().then(blob => ({ blob, filename }));
})
.then(result => {
if (!result) return;
const { blob, filename } = result;
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
})
.catch(error => alert(error.message));
}
// 恢复出厂设置
function do_reset(btn) {
if (confirm("<%: Do you want to restore the client to default settings?%>")) {
setTimeout(function () {
if (confirm("<%: Are you sure you want to restore the client to default settings?%>")) {
// 清理日志
var xhr1 = new XMLHttpRequest();
xhr1.open("GET", url("clear_log"), true); // 使用 JavaScript 版本的 url 函数
xhr1.send();
// 恢复出厂
var xhr2 = new XMLHttpRequest();
xhr2.open("GET", url("reset"), true); // 使用 JavaScript 版本的 url 函数
xhr2.send();
// 处理响应
xhr2.onload = function() {
if (xhr2.status === 200) {
window.location.href = url("reset");
}
};
}
}, 1000);
}
}
</script>
<%+cbi/valuefooter%>

View File

@ -0,0 +1,37 @@
<%
local dsp = require "luci.dispatcher"
-%>
<script type="text/javascript">
//<![CDATA[
function clearlog(btn) {
XHR.get('<%=dsp.build_url("admin/services/shadowsocksr/clear_log")%>', null,
function(x, data) {
if (x && x.status == 200) {
var log_textarea = document.getElementById('log_textarea');
log_textarea.innerHTML = "";
log_textarea.scrollTop = log_textarea.scrollHeight;
}
}
);
}
XHR.poll(5, '<%=dsp.build_url("admin/services/shadowsocksr/get_log")%>', null,
function(x, data) {
if (x && x.status == 200) {
var log_textarea = document.getElementById('log_textarea');
// 将日志分行处理,移除最后一行空行但保留中间空行
var logs = x.responseText.split("\n");
if (logs[logs.length - 1].trim() === "") {
logs.pop(); // 删除最后的空行
}
logs = logs.reverse().join("\n"); // 倒序排列
log_textarea.innerHTML = logs;
}
}
);
//]]>
</script>
<fieldset class="cbi-section" id="_log_fieldset">
<input class="btn cbi-button cbi-button-remove" type="button" onclick="clearlog()" value="<%:Clear logs%>" />
<textarea id="log_textarea" class="cbi-input-textarea" style="width: 100%;margin-top: 10px;" data-update="change" rows="20" wrap="off" readonly="readonly"></textarea>
</fieldset>

View File

@ -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 = "<font style=\'color:green\'><%:Import configuration information successfully.%></font>";
return false;
@ -306,7 +365,7 @@ 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;
}
// Check if the elements exist before trying to modify them
@ -336,7 +395,7 @@ function import_ssr_url(btn, urlname, sid) {
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" :
(["tcp", "raw"].includes(params.get("type")) ? "raw" :
(params.get("type") || "tcp"))
);
dispatchEventIfExists('cbid.shadowsocksr.' + sid + '.transport', event);

View File

@ -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 "【谷歌】连通性检查"
@ -1168,3 +1176,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 "是否真的要恢复客户端默认配置?"

View File

@ -283,8 +283,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
}
@ -321,8 +322,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 拥塞控制算法
}
}
})

View File

@ -319,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
@ -327,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]
@ -349,10 +357,62 @@ local function processData(szType, content)
-- 未指定peersni默认使用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