diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua index 1872017f1..fb8846783 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua @@ -337,6 +337,7 @@ o.default = 0 o:depends({ [option_name("tls")] = true, [option_name("transport")] = "tcp" }) o:depends({ [option_name("tls")] = true, [option_name("transport")] = "h2" }) o:depends({ [option_name("tls")] = true, [option_name("transport")] = "grpc" }) +o:depends({ [option_name("tls")] = true, [option_name("transport")] = "splithttp" }) o = s:option(ListValue, option_name("alpn"), translate("alpn")) o.default = "default" @@ -566,7 +567,7 @@ o = s:option(Value, option_name("httpupgrade_path"), translate("HttpUpgrade Path o.placeholder = "/" o:depends({ [option_name("transport")] = "httpupgrade" }) --- [[ SplitHTTP部分 ]]-- +-- [[ XHTTP(SplitHTTP)部分 ]]-- o = s:option(Value, option_name("splithttp_host"), translate("SplitHTTP Host")) o:depends({ [option_name("transport")] = "splithttp" }) @@ -574,20 +575,101 @@ o = s:option(Value, option_name("splithttp_path"), translate("SplitHTTP Path")) o.placeholder = "/" o:depends({ [option_name("transport")] = "splithttp" }) -o = s:option(Flag, option_name("splithttp_xmux"), "XMUX", translate("Enable SplitHTTP XMUX. It's not recommended to enable Mux.Cool at the same time.")) +-- XHTTP XMUX +o = s:option(Flag, option_name("xhttp_xmux"), "XMUX", translate("Enable XHTTP XMUX. It's not recommended to enable Mux.Cool at the same time.")) o:depends({ [option_name("transport")] = "splithttp" }) o = s:option(Value, option_name("maxConcurrency"), translate("XMUX Max Concurrency")) -o:depends({ [option_name("splithttp_xmux")] = true }) +o:depends({ [option_name("xhttp_xmux")] = true }) o = s:option(Value, option_name("maxConnections"), translate("XMUX Max Connections")) -o:depends({ [option_name("splithttp_xmux")] = true }) +o:depends({ [option_name("xhttp_xmux")] = true }) o = s:option(Value, option_name("cMaxReuseTimes"), translate("XMUX Connection Max Reuse Times")) -o:depends({ [option_name("splithttp_xmux")] = true }) +o:depends({ [option_name("xhttp_xmux")] = true }) o = s:option(Value, option_name("cMaxLifetimeMs"), translate("XMUX Connection Max Lifetime (ms)")) -o:depends({ [option_name("splithttp_xmux")] = true }) +o:depends({ [option_name("xhttp_xmux")] = true }) + +-- XHTTP 下行 +o = s:option(Flag, option_name("xhttp_download"), string.format('%s', translate("XHTTP download splitting"))) +o:depends({ [option_name("transport")] = "splithttp" }) + +o = s:option(Value, option_name("xhttp_download_address"), string.format('%s', translate("Address"))) +o:depends({ [option_name("xhttp_download")] = true }) + +o = s:option(Value, option_name("xhttp_download_port"), string.format('%s', translate("Port"))) +o:depends({ [option_name("xhttp_download")] = true }) + +o = s:option(Value, option_name("xhttp_download_path"), string.format('%s', "XHTTP Path"), translate("Must be the same as upload path.")) +o.placeholder = "/" +o:depends({ [option_name("xhttp_download")] = true }) + +o = s:option(Flag, option_name("xhttp_download_tls"), string.format('%s', "TLS")) +o:depends({ [option_name("xhttp_download")] = true }) +o.default = 0 + +o = s:option(Flag, option_name("xhttp_download_reality"), string.format('%s', "REALITY")) +o.default = 0 +o:depends({ [option_name("xhttp_download_tls")] = true }) + +o = s:option(ListValue, option_name("xhttp_download_alpn"), string.format('%s', "alpn")) +o.default = "default" +o:value("default", translate("Default")) +o:value("h3") +o:value("h2") +o:value("h3,h2") +o:value("http/1.1") +o:value("h2,http/1.1") +o:value("h3,h2,http/1.1") +o:depends({ [option_name("xhttp_download_tls")] = true, [option_name("xhttp_download_reality")] = false }) + +o = s:option(Value, option_name("xhttp_download_tls_serverName"), string.format('%s', translate("Domain"))) +o:depends({ [option_name("xhttp_download_tls")] = true }) + +o = s:option(Value, option_name("xhttp_download_reality_publicKey"), string.format('%s', translate("Public Key"))) +o:depends({ [option_name("xhttp_download_tls")] = true, [option_name("xhttp_download_reality")] = true }) + +o = s:option(Value, option_name("xhttp_download_reality_shortId"), string.format('%s', translate("Short Id"))) +o:depends({ [option_name("xhttp_download_tls")] = true, [option_name("xhttp_download_reality")] = true }) + +o = s:option(Value, option_name("xhttp_download_reality_spiderX"), string.format('%s', "Spider X")) +o.placeholder = "/" +o:depends({ [option_name("xhttp_download_tls")] = true, [option_name("xhttp_download_reality")] = true }) + +o = s:option(Flag, option_name("xhttp_download_utls"), string.format('%s', "uTLS")) +o.default = "0" +o:depends({ [option_name("xhttp_download_tls")] = true, [option_name("xhttp_download_reality")] = false }) + +o = s:option(ListValue, option_name("xhttp_download_fingerprint"), string.format('%s', translate("Finger Print"))) +o:value("chrome") +o:value("firefox") +o:value("edge") +o:value("safari") +o:value("360") +o:value("qq") +o:value("ios") +o:value("android") +o:value("random") +o:value("randomized") +o.default = "chrome" +o:depends({ [option_name("xhttp_download_tls")] = true, [option_name("xhttp_download_utls")] = true }) +o:depends({ [option_name("xhttp_download_tls")] = true, [option_name("xhttp_download_reality")] = true }) + +o = s:option(Flag, option_name("xhttp_download_xmux"), string.format('%s', "XMUX"), translate("Enable XHTTP XMUX. It's not recommended to enable Mux.Cool at the same time.")) +o:depends({ [option_name("xhttp_download")] = true }) + +o = s:option(Value, option_name("download_maxConcurrency"), string.format('%s', translate("XMUX Max Concurrency"))) +o:depends({ [option_name("xhttp_download_xmux")] = true }) + +o = s:option(Value, option_name("download_maxConnections"), string.format('%s', translate("XMUX Max Connections"))) +o:depends({ [option_name("xhttp_download_xmux")] = true }) + +o = s:option(Value, option_name("download_cMaxReuseTimes"), string.format('%s', translate("XMUX Connection Max Reuse Times"))) +o:depends({ [option_name("xhttp_download_xmux")] = true }) + +o = s:option(Value, option_name("download_cMaxLifetimeMs"), string.format('%s', translate("XMUX Connection Max Lifetime (ms)"))) +o:depends({ [option_name("xhttp_download_xmux")] = true }) -- [[ Mux.Cool ]]-- o = s:option(Flag, option_name("mux"), "Mux", translate("Enable Mux.Cool")) diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index b07657589..dbcea4e16 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -118,6 +118,15 @@ function gen_outbound(flag, node, tag, proxy_table) end end + if node.type == "Xray" and node.transport == "splithttp" then + if node.xhttp_download_tls and node.xhttp_download_tls == "1" then + node.xhttp_download_stream_security = "tls" + if node.xhttp_download_reality and node.xhttp_download_reality == "1" then + node.xhttp_download_stream_security = "reality" + end + end + end + if node.protocol == "wireguard" and node.wireguard_reserved then local bytes = {} if not node.wireguard_reserved:match("[^%d,]+") then @@ -223,7 +232,32 @@ function gen_outbound(flag, node, tag, proxy_table) } or nil, splithttpSettings = (node.transport == "splithttp") and { path = node.splithttp_path or "/", - host = node.splithttp_host + host = node.splithttp_host, + downloadSettings = (node.xhttp_download == "1") and { + address = node.xhttp_download_address, + port = tonumber(node.xhttp_download_port), + network = "xhttp", + xhttpSettings = { + path = node.xhttp_download_path, + }, + security = node.xhttp_download_stream_security, + tlsSettings = (node.xhttp_download_stream_security == "tls") and { + serverName = node.xhttp_download_tls_serverName, + allowInsecure = false, + fingerprint = (node.xhttp_download_utls == "1" and + node.xhttp_download_fingerprint and + node.xhttp_download_fingerprint ~= "") and node.xhttp_download_fingerprint or nil + } or nil, + realitySettings = (node.xhttp_download_stream_security == "reality") and { + serverName = node.xhttp_download_tls_serverName, + publicKey = node.xhttp_download_reality_publicKey, + shortId = node.xhttp_download_reality_shortId or "", + spiderX = node.xhttp_download_reality_spiderX or "/", + fingerprint = ( + node.xhttp_download_fingerprint and + node.xhttp_download_fingerprint ~= "") and node.xhttp_download_fingerprint or nil + } or nil, + } or nil } or nil, } or nil, settings = { @@ -290,7 +324,7 @@ function gen_outbound(flag, node, tag, proxy_table) end local xmux = {} - if node.splithttp_xmux then + if (node.xhttp_xmux == "1") then xmux.maxConcurrency = node.maxConcurrency and (string.find(node.maxConcurrency, "-") and node.maxConcurrency or tonumber(node.maxConcurrency)) or 0 xmux.maxConnections = node.maxConnections and (string.find(node.maxConnections, "-") and node.maxConnections or tonumber(node.maxConnections)) or 0 xmux.cMaxReuseTimes = node.cMaxReuseTimes and (string.find(node.cMaxReuseTimes, "-") and node.cMaxReuseTimes or tonumber(node.cMaxReuseTimes)) or 0 @@ -300,6 +334,17 @@ function gen_outbound(flag, node, tag, proxy_table) end end + local xmux_download = {} + if (node.xhttp_download_xmux == "1") then + xmux_download.maxConcurrency = node.download_maxConcurrency and (string.find(node.download_maxConcurrency, "-") and node.download_maxConcurrency or tonumber(node.download_maxConcurrency)) or 0 + xmux_download.maxConnections = node.download_maxConnections and (string.find(node.download_maxConnections, "-") and node.download_maxConnections or tonumber(node.download_maxConnections)) or 0 + xmux_download.cMaxReuseTimes = node.download_cMaxReuseTimes and (string.find(node.download_cMaxReuseTimes, "-") and node.download_cMaxReuseTimes or tonumber(node.download_cMaxReuseTimes)) or 0 + xmux_download.cMaxLifetimeMs = node.download_cMaxLifetimeMs and (string.find(node.download_cMaxLifetimeMs, "-") and node.download_cMaxLifetimeMs or tonumber(node.download_cMaxLifetimeMs)) or 0 + if result.streamSettings.splithttpSettings.downloadSettings then + result.streamSettings.splithttpSettings.downloadSettings.xmux = xmux_download + end + end + end return result end diff --git a/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm b/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm index f5b164aa2..ecf4de1bd 100644 --- a/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm +++ b/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm @@ -371,6 +371,10 @@ local api = require "luci.passwall.api" v_transport = "splithttp"; params += opt.query("host", dom_prefix + "splithttp_host"); params += opt.query("path", dom_prefix + "splithttp_path"); + } else if (v_transport === "xhttp") { + v_transport = "xhttp"; + params += opt.query("host", dom_prefix + "xhttp_host"); + params += opt.query("path", dom_prefix + "xhttp_path"); } else if (v_transport === "httpupgrade") { v_transport = "httpupgrade"; params += opt.query("host", dom_prefix + "httpupgrade_host"); @@ -1153,6 +1157,9 @@ local api = require "luci.passwall.api" } else if (queryParam.type === "splithttp") { opt.set(dom_prefix + 'splithttp_host', queryParam.host || ""); opt.set(dom_prefix + 'splithttp_path', queryParam.path || ""); + } else if (queryParam.type === "xhttp") { + opt.set(dom_prefix + 'xhttp_host', queryParam.host || ""); + opt.set(dom_prefix + 'xhttp_path', queryParam.path || ""); } else if (queryParam.type === "httpupgrade") { opt.set(dom_prefix + 'httpupgrade_host', queryParam.host || ""); opt.set(dom_prefix + 'httpupgrade_path', queryParam.path || ""); diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index 34f991d98..97e4d5b15 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -1519,8 +1519,14 @@ msgstr "客户端文件不适合当前设备。" msgid "Can't move new file to path: %s" msgstr "无法移动新文件到:%s" -msgid "Enable SplitHTTP XMUX. It's not recommended to enable Mux.Cool at the same time." -msgstr "启用 SplitHTTP XMUX。不建议与 Mux.Cool 同时启用。" +msgid "XHTTP download splitting" +msgstr "XHTTP 下行分离" + +msgid "Must be the same as upload path." +msgstr "必须与上行 path 相同。" + +msgid "Enable XHTTP XMUX. It's not recommended to enable Mux.Cool at the same time." +msgstr "启用 XHTTP XMUX。不建议与 Mux.Cool 同时启用。" msgid "XMUX Max Concurrency" msgstr "XMUX 连接最大复用流数"