diff --git a/luasrc/view/admin_network/user_status.htm b/luasrc/view/admin_network/user_status.htm
deleted file mode 100755
index 0519ecba6..000000000
--- a/luasrc/view/admin_network/user_status.htm
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/luci-app-bypass/luasrc/model/cbi/bypass/client-config.lua b/luci-app-bypass/luasrc/model/cbi/bypass/client-config.lua
index 77e53bd17..b4152edc3 100644
--- a/luci-app-bypass/luasrc/model/cbi/bypass/client-config.lua
+++ b/luci-app-bypass/luasrc/model/cbi/bypass/client-config.lua
@@ -4,6 +4,7 @@
require "nixio.fs"
require "luci.sys"
require "luci.http"
+require "luci.jsonc"
require "luci.model.ipkg"
local m, s, o
@@ -433,7 +434,7 @@ o:depends("type", "shadowtls")
o.default = "1"
o.rmempty = false
-o = s:option(Flag, "fastopen", translate("TCP Fast Open"))
+o = s:option(Flag, "fastopen", translate("TCP Fast Open"), translate("Enabling TCP Fast Open Requires Server Support."))
o:depends("type", "shadowtls")
o.default = "0"
o.rmempty = false
@@ -618,11 +619,12 @@ o:depends({type = "v2ray", v2ray_protocol = "socks"})
-- 传输协议
o = s:option(ListValue, "transport", translate("Transport"))
-o:value("tcp", "TCP")
+o:value("raw", "RAW (TCP)")
o:value("kcp", "mKCP")
o:value("ws", "WebSocket")
o:value("httpupgrade", "HTTPUpgrade")
o:value("splithttp", "SplitHTTP")
+o:value("xhttp", "XHTTP")
o:value("h2", "HTTP/2")
o:value("quic", "QUIC")
o:value("grpc", "gRPC")
@@ -634,10 +636,10 @@ 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:depends("transport", "raw")
o:value("none", translate("None"))
o:value("http", "HTTP")
o.rmempty = true
@@ -703,6 +705,78 @@ o = s:option(Value, "splithttp_path", translate("Splithttp Path"))
o:depends("transport", "splithttp")
o.rmempty = true
+-- [[ XHTTP部分 ]]--
+o = s:option(ListValue, "xhttp_alpn", translate("XHTTP Alpn"))
+o.default = ""
+o:value("", 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("transport", "xhttp")
+
+o = s:option(ListValue, "xhttp_mode", translate("XHTTP Mode"))
+o:depends("transport", "xhttp")
+o.default = "auto"
+o:value("auto")
+o:value("packet-up")
+o:value("stream-up")
+o:value("stream-one")
+
+o = s:option(Value, "xhttp_host", translate("XHTTP Host"))
+o:depends({transport = "xhttp", tls = false})
+o.rmempty = true
+
+o = s:option(Value, "xhttp_path", translate("XHTTP Path"))
+o.placeholder = "/"
+o:depends("transport", "xhttp")
+o.rmempty = true
+
+o = s:option(Flag, "enable_xhttp_extra", translate("XHTTP Extra"))
+o.description = translate("Enable this option to configure XHTTP Extra (JSON format).")
+o.rmempty = true
+o.default = "0"
+o:depends("transport", "xhttp")
+
+o = s:option(TextValue, "xhttp_extra", " ")
+o.description = translate(
+ "" .. translate("Configure XHTTP Extra Settings (JSON format), see:") .. "" ..
+ " " ..
+ "" .. translate("Click to the page") .. "")
+o:depends("enable_xhttp_extra", true)
+o.rmempty = true
+o.rows = 10
+o.wrap = "off"
+o.custom_write = function(self, section, value)
+ m:set(section, "xhttp_extra", value)
+ local success, data = pcall(luci.jsonc.parse, value)
+ if success and data then
+ local address = (data.extra and data.extra.downloadSettings and data.extra.downloadSettings.address)
+ or (data.downloadSettings and data.downloadSettings.address)
+ if address and address ~= "" then
+ m:set(section, "download_address", address)
+ else
+ m:del(section, "download_address")
+ end
+ else
+ m:del(section, "download_address")
+ end
+end
+o.validate = function(self, value)
+ value = value:gsub("\r\n", "\n"):gsub("^[ \t]*\n", ""):gsub("\n[ \t]*$", ""):gsub("\n[ \t]*\n", "\n")
+ if value:sub(-1) == "\n" then
+ value = value:sub(1, -2)
+ end
+ local success, data = pcall(luci.jsonc.parse, value)
+ if not success or not data then
+ return nil, translate("Invalid JSON format")
+ end
+
+ return value
+end
+
-- [[ H2部分 ]]--
-- H2域名
@@ -924,15 +998,33 @@ 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 = "tcp", reality = true})
+ o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "raw", tls = true})
+ o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "raw", reality = true})
+
+ o = s:option(ListValue, "xhttp_tls_flow", translate("Flow"))
+ for _, v in ipairs(tls_flows) do
+ if v == "none" then
+ o.default = "none"
+ o:value("none", translate("none"))
+ else
+ o:value("xtls-rprx-vision", translate("xtls-rprx-vision"))
+ end
+ end
+ o.rmempty = true
+ o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "xhttp", tls = true})
+ o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "xhttp", reality = true})
-- [[ uTLS ]]--
- o = s:option(Value, "fingerprint", translate("Finger Print"))
- o.default = "chrome"
+ o = s:option(ListValue, "fingerprint", translate("Finger Print"))
+ o.default = ""
o:value("chrome", translate("chrome"))
o:value("firefox", translate("firefox"))
o:value("safari", translate("safari"))
@@ -973,19 +1065,37 @@ o:depends({type = "hysteria", insecure = true })
o.rmempty = true
--- [[ Mux ]]--
-o = s:option(Flag, "mux", translate("Mux"))
+-- [[ Mux.Cool ]] --
+o = s:option(Flag, "mux", translate("Mux"), translate("Enable Mux.Cool"))
o.rmempty = false
o.default = false
-o:depends({type = "v2ray", v2ray_protocol = "vless"})
+o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "raw"})
+o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "ws"})
+o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "kcp"})
+o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "httpupgrade"})
+o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "splithttp"})
+o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "h2"})
+o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "quic"})
+o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "grpc"})
o:depends({type = "v2ray", v2ray_protocol = "vmess"})
o:depends({type = "v2ray", v2ray_protocol = "trojan"})
o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"})
o:depends({type = "v2ray", v2ray_protocol = "socks"})
o:depends({type = "v2ray", v2ray_protocol = "http"})
+-- [[ XUDP Mux ]] --
+o = s:option(Flag, "xmux", translate("Xudp Mux"), translate("Enable Xudp Mux"))
+o.rmempty = false
+o.default = false
+o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "xhttp"})
+
-- [[ TCP 最大并发连接数 ]]--
-o = s:option(ListValue, "concurrency", translate("concurrency"))
+o = s:option(Value, "concurrency", translate("concurrency"))
+o.description = translate(
+ "
"
+ .. "- " .. translate("Default: disable. When entering a negative number, such as -1, The Mux module will not be used to carry TCP traffic.") .. "
"
+ .. "- " .. translate("Min value is 1, Max value is 128. When omitted or set to 0, it equals 8.") .. "
"
+ .. "
")
o.rmempty = true
o.default = "-1"
o:value("-1", translate("disable"))
@@ -993,15 +1103,27 @@ o:value("8", translate("8"))
o:depends("mux", true)
-- [[ UDP 最大并发连接数 ]]--
-o = s:option(ListValue, "xudpConcurrency", translate("xudpConcurrency"))
+o = s:option(Value, "xudpConcurrency", translate("xudpConcurrency"))
+o.description = translate(
+ ""
+ .. "- " .. translate("Default:16. When entering a negative number, such as -1, The Mux module will not be used to carry UDP traffic, Use original UDP transmission method of proxy protocol.") .. "
"
+ .. "- " .. translate("Min value is 1, Max value is 1024. When omitted or set to 0, Will same path as TCP traffic.") .. "
"
+ .. "
")
o.rmempty = true
o.default = "16"
o:value("-1", translate("disable"))
o:value("16", translate("16"))
o:depends("mux", true)
+o:depends("xmux", true)
-- [[ 对被代理的 UDP/443 流量处理方式 ]]--
o = s:option(ListValue, "xudpProxyUDP443", translate("xudpProxyUDP443"))
+o.description = translate(
+ ""
+ .. "- " .. translate("Default reject rejects traffic.") .. "
"
+ .. "- " .. translate("allow: Allows use Mux connection.") .. "
"
+ .. "- " .. translate("skip: Not use Mux module to carry UDP 443 traffic, Use original UDP transmission method of proxy protocol.") .. "
"
+ .. "
")
o.rmempty = true
o.default = "reject"
o:value("reject", translate("reject"))
@@ -1009,11 +1131,16 @@ o:value("allow", translate("allow"))
o:value("skip", translate("skip"))
o:depends("mux", true)
+-- [[ XHTTP TCP Fast Open ]]--
+o = s:option(Flag, "tcpfastopen", translate("TCP Fast Open"), translate("Enabling TCP Fast Open Requires Server Support."))
+o.rmempty = true
+o.default = "0"
+o:depends({type = "v2ray", v2ray_protocol = "vless", transport = "xhttp"})
-- [[ MPTCP ]]--
-o = s:option(Flag, "mptcp", translate("MPTCP"))
-o.rmempty = false
-o.default = false
+o = s:option(Flag, "mptcp", translate("MPTCP"), translate("Enable Multipath TCP, need to be enabled in both server and client configuration."))
+o.rmempty = true
+o.default = "0"
o:depends({type = "v2ray", v2ray_protocol = "vless"})
o:depends({type = "v2ray", v2ray_protocol = "vmess"})
o:depends({type = "v2ray", v2ray_protocol = "trojan"})
@@ -1088,7 +1215,7 @@ o:value("/etc/ssl/private/ca.pem")
o.description = translate("Please confirm the current certificate path")
o.default = "/etc/ssl/private/ca.pem"
-o = s:option(Flag, "fast_open", translate("TCP Fast Open"))
+o = s:option(Flag, "fast_open", translate("TCP Fast Open"), translate("Enabling TCP Fast Open Requires Server Support."))
o.rmempty = true
o.default = "0"
o:depends("type", "ssr")
diff --git a/luci-app-bypass/luasrc/model/cbi/bypass/control.lua b/luci-app-bypass/luasrc/model/cbi/bypass/control.lua
index 2ca2e872d..a71446ef9 100644
--- a/luci-app-bypass/luasrc/model/cbi/bypass/control.lua
+++ b/luci-app-bypass/luasrc/model/cbi/bypass/control.lua
@@ -1,3 +1,4 @@
+require "luci.sys"
local fs = require "nixio.fs"
local m,s,o
@@ -132,4 +133,11 @@ o.validate = function(self, value)
return value
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/bypass reload > /dev/null 2>&1 &")
+ end
+end
+
return m
diff --git a/luci-app-bypass/luasrc/view/bypass/server_list.htm b/luci-app-bypass/luasrc/view/bypass/server_list.htm
index 466a1058e..c0ee49601 100644
--- a/luci-app-bypass/luasrc/view/bypass/server_list.htm
+++ b/luci-app-bypass/luasrc/view/bypass/server_list.htm
@@ -14,7 +14,7 @@ local dsp=require "luci.dispatcher"
return new Promise((res) =>{
const dom=doms[index];
const port=ports[index];
- if (!dom) res()
+ if (!dom) res();
port.innerHTML='<%:connecting%>';
XHR.get('<%=dsp.build_url("admin/services/bypass/ping")%>',{
index,
@@ -28,7 +28,7 @@ local dsp=require "luci.dispatcher"
if (result.ping < 200) col='#ff7700';
if (result.ping < 100) col='#249400';
}
- dom.innerHTML=`${(result.ping ? result.ping : "--") + " ms"}`
+ dom.innerHTML=`${(result.ping ? result.ping : "--") + " ms"}`;
if (result.socket){
port.innerHTML='<%:ok%>';
} else{
@@ -36,20 +36,20 @@ local dsp=require "luci.dispatcher"
}
res();
});
- })
- }
+ });
+ };
let task=-1;
const thread=() =>{
- task=task + 1
+ task=task + 1;
if (doms[task]){
xhr(task).then(thread);
}
- }
+ };
for (let i=0; i < 20; i++){
- thread()
+ thread();
}
- })
+ });
function cbi_row_drop(fromId,toId,store,isToBottom){
var fromNode=document.getElementById(fromId);
@@ -181,4 +181,5 @@ local dsp=require "luci.dispatcher"
console.error(err);
}
}
+ //]]>
diff --git a/luci-app-bypass/luasrc/view/bypass/ssrurl.htm b/luci-app-bypass/luasrc/view/bypass/ssrurl.htm
index 5867db34a..3db681b1b 100644
--- a/luci-app-bypass/luasrc/view/bypass/ssrurl.htm
+++ b/luci-app-bypass/luasrc/view/bypass/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,77 @@ function import_ssr_url(btn, urlname, sid) {
document.getElementsByName('cbid.bypass.' + sid + '.password')[0].value = decodeURIComponent(url.username);
document.getElementsByName('cbid.bypass.' + sid + '.tls')[0].checked = true;
document.getElementsByName('cbid.bypass.' + sid + '.tls')[0].dispatchEvent(event);
- document.getElementsByName('cbid.bypass.' + sid + '.tls_host')[0].value = url.searchParams.get("sni");
+ document.getElementsByName('cbid.bypass.' + sid + '.fingerprint')[0].value = params.get("fp") || "";
+ document.getElementsByName('cbid.bypass.' + sid + '.tls_host')[0].value = params.get("sni");
+ if (params.get("allowInsecure") === "1") {
+ document.getElementsByName('cbid.bypass.' + sid + '.insecure')[0].checked = true; // 设置 insecure 为 true
+ document.getElementsByName('cbid.bypass.' + sid + '.insecure')[0].dispatchEvent(event); // 触发事件
+ }
+ document.getElementsByName('cbid.bypass.' + sid + '.transport')[0].value =
+ params.get("type") == "http" ? "h2" :
+ (["tcp", "raw"].includes(params.get("type")) ? "raw" :
+ (params.get("type") || "raw"));
+ document.getElementsByName('cbid.bypass.' + sid + '.transport')[0].dispatchEvent(event);
+ switch (params.get("type")) {
+ case "ws":
+ if (params.get("security") !== "tls") {
+ setElementValue('cbid.bypass.' + sid + '.ws_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ }
+ setElementValue('cbid.bypass.' + sid + '.ws_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
+ break;
+ case "httpupgrade":
+ if (params.get("security") !== "tls") {
+ document.getElementsByName('cbid.bypass.' + sid + '.httpupgrade_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
+ }
+ document.getElementsByName('cbid.bypass.' + sid + '.httpupgrade_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
+ break;
+ case "splithttp":
+ if (params.get("security") !== "tls") {
+ document.getElementsByName('cbid.bypass.' + sid + '.splithttp_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
+ }
+ document.getElementsByName('cbid.bypass.' + sid + '.splithttp_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
+ break;
+ case "xhttp":
+ if (params.get("security") !== "tls") {
+ document.getElementsByName('cbid.bypass.' + sid + '.xhttp_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
+ }
+ document.getElementsByName('cbid.bypass.' + sid + '.xhttp_mode')[0].value = params.get("mode") || "auto";
+ document.getElementsByName('cbid.bypass.' + sid + '.xhttp_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
+ if (params.get("extra") && params.get("extra").trim() !== "") {
+ document.getElementsByName('cbid.bypass.' + sid + '.enable_xhttp_extra')[0].checked = true; // 设置 enable_xhttp_extra 为 true
+ document.getElementsByName('cbid.bypass.' + sid + '.enable_xhttp_extra')[0].dispatchEvent(event); // 触发事件
+ document.getElementsByName('cbid.bypass.' + sid + '.xhttp_extra')[0].value = params.get("extra") || "";
+ }
+ break;
+ case "kcp":
+ document.getElementsByName('cbid.bypass.' + sid + '.kcp_guise')[0].value = params.get("headerType") || "none";
+ document.getElementsByName('cbid.bypass.' + sid + '.seed')[0].value = params.get("seed") || "";
+ break;
+ case "http":
+ /* this is non-standard, bullshit */
+ case "h2":
+ document.getElementsByName('cbid.bypass.' + sid + '.h2_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
+ document.getElementsByName('cbid.bypass.' + sid + '.h2_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
+ break;
+ case "quic":
+ document.getElementsByName('cbid.bypass.' + sid + '.quic_guise')[0].value = params.get("headerType") || "none";
+ document.getElementsByName('cbid.bypass.' + sid + '.quic_security')[0].value = params.get("quicSecurity") || "none";
+ document.getElementsByName('cbid.bypass.' + sid + '.quic_key')[0].value = params.get("key") || "";
+ break;
+ case "grpc":
+ document.getElementsByName('cbid.bypass.' + sid + '.serviceName')[0].value = params.get("serviceName") || "";
+ document.getElementsByName('cbid.bypass.' + sid + '.grpc_mode')[0].value = params.get("mode") || "gun";
+ break;
+ case "raw":
+ case "tcp":
+ document.getElementsByName('cbid.bypass.' + sid + '.tcp_guise')[0].value = params.get("headerType") || "none";
+ document.getElementsByName('cbid.bypass.' + sid + '.tcp_guise')[0].dispatchEvent(event);
+ if (params.get("headerType") === "http") {
+ document.getElementsByName('cbid.bypass.' + sid + '.http_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
+ document.getElementsByName('cbid.bypass.' + sid + '.http_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
+ }
+ break;
+ }
s.innerHTML = "<%:Import configuration information successfully.%>";
return false;
@@ -254,21 +325,41 @@ function import_ssr_url(btn, urlname, sid) {
document.getElementsByName('cbid.bypass.' + sid + '.server_port')[0].value = ssm.port;
document.getElementsByName('cbid.bypass.' + sid + '.alter_id')[0].value = ssm.aid;
document.getElementsByName('cbid.bypass.' + sid + '.vmess_id')[0].value = ssm.id;
- document.getElementsByName('cbid.bypass.' + sid + '.transport')[0].value = ssm.net;
+ document.getElementsByName('cbid.bypass.' + sid + '.transport')[0].value =
+ (ssm.net === "raw" || ssm.net === "tcp") ? "raw" : ssm.net;
document.getElementsByName('cbid.bypass.' + 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.bypass.' + sid + '.http_host')[0].value = ssm.host;
+ document.getElementsByName('cbid.bypass.' + sid + '.http_path')[0].value = ssm.path;
}
document.getElementsByName('cbid.bypass.' + sid + '.tcp_guise')[0].value = ssm.type;
document.getElementsByName('cbid.bypass.' + sid + '.tcp_guise')[0].dispatchEvent(event);
- document.getElementsByName('cbid.bypass.' + sid + '.http_host')[0].value = ssm.host;
- document.getElementsByName('cbid.bypass.' + sid + '.http_path')[0].value = ssm.path;
}
if (ssm.net == "ws") {
document.getElementsByName('cbid.bypass.' + sid + '.ws_host')[0].value = ssm.host;
document.getElementsByName('cbid.bypass.' + sid + '.ws_path')[0].value = ssm.path;
}
+ if (ssm.net == "httpupgrade") {
+ document.getElementsByName('cbid.bypass.' + sid + '.httpupgrade_host')[0].value = ssm.host;
+ document.getElementsByName('cbid.bypass.' + sid + '.httpupgrade_path')[0].value = ssm.path;
+ }
+ if (ssm.net == "splithttp") {
+ document.getElementsByName('cbid.bypass.' + sid + '.splithttp_host')[0].value = ssm.host;
+ document.getElementsByName('cbid.bypass.' + sid + '.splithttp_path')[0].value = ssm.path;
+ }
+ if (ssm.net == "xhttp") {
+ document.getElementsByName('cbid.bypass.' + sid + '.xhttp_mode')[0].value = ssm.mode;
+ document.getElementsByName('cbid.bypass.' + sid + '.xhttp_host')[0].value = ssm.host;
+ document.getElementsByName('cbid.bypass.' + sid + '.xhttp_path')[0].value = ssm.path;
+ if (params.get("extra") && params.get("extra").trim() !== "") {
+ document.getElementsByName('cbid.bypass.' + sid + '.enable_xhttp_extra')[0].checked = true; // 设置 enable_xhttp_extra 为 true
+ document.getElementsByName('cbid.bypass.' + sid + '.enable_xhttp_extra')[0].dispatchEvent(event); // 触发事件
+ document.getElementsByName('cbid.bypass.' + sid + '.xhttp_extra')[0].value = ssm.extra;
+ }
+ }
if (ssm.net == "h2") {
document.getElementsByName('cbid.bypass.' + sid + '.h2_host')[0].value = ssm.host;
document.getElementsByName('cbid.bypass.' + sid + '.h2_path')[0].value = ssm.path;
@@ -283,10 +374,20 @@ function import_ssr_url(btn, urlname, sid) {
if (ssm.tls == "tls") {
document.getElementsByName('cbid.bypass.' + sid + '.tls')[0].checked = true;
document.getElementsByName('cbid.bypass.' + sid + '.tls')[0].dispatchEvent(event);
+ document.getElementsByName('cbid.bypass.' + sid + '.fingerprint')[0].value = ssm.fp;
+ if (ssm.net == "xhttp") {
+ document.getElementsByName('cbid.bypass.' + sid + '.xhttp_alpn')[0].value = ssm.alpn;
+ }
document.getElementsByName('cbid.bypass.' + sid + '.tls_host')[0].value = ssm.sni || ssm.host;
}
- document.getElementsByName('cbid.bypass.' + sid + '.mux')[0].checked = true;
- document.getElementsByName('cbid.bypass.' + sid + '.mux')[0].dispatchEvent(event);
+ if (ssm.mux !== undefined) {
+ document.getElementsByName('cbid.bypass.' + sid + '.mux')[0].checked = true;
+ document.getElementsByName('cbid.bypass.' + sid + '.mux')[0].dispatchEvent(event);
+ }
+ if (ssm.xmux !== undefined) {
+ document.getElementsByName('cbid.bypass.' + sid + '.xmux')[0].checked = true;
+ document.getElementsByName('cbid.bypass.' + sid + '.xmux')[0].dispatchEvent(event);
+ }
s.innerHTML = "<%:Import configuration information successfully.%>";
return false;
case "vless":
@@ -294,66 +395,114 @@ 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.bypass.' + sid + '.alias')[0].value = url.hash ? decodeURIComponent(url.hash.slice(1)) : "";
- document.getElementsByName('cbid.bypass.' + sid + '.type')[0].value = "v2ray";
- document.getElementsByName('cbid.bypass.' + sid + '.type')[0].dispatchEvent(event);
- document.getElementsByName('cbid.bypass.' + sid + '.v2ray_protocol')[0].value = "vless";
- document.getElementsByName('cbid.bypass.' + sid + '.v2ray_protocol')[0].dispatchEvent(event);
- document.getElementsByName('cbid.bypass.' + sid + '.server')[0].value = url.hostname;
- document.getElementsByName('cbid.bypass.' + sid + '.server_port')[0].value = url.port || "80";
- document.getElementsByName('cbid.bypass.' + sid + '.vmess_id')[0].value = url.username;
- document.getElementsByName('cbid.bypass.' + sid + '.transport')[0].value = params.get("type") == "http" ? "h2" : params.get("type") || "tcp";
- document.getElementsByName('cbid.bypass.' + sid + '.transport')[0].dispatchEvent(event);
- document.getElementsByName('cbid.bypass.' + sid + '.vless_encryption')[0].value = params.get("encryption") || "none";
- if ([ "tls", "reality" ].includes(params.get("security"))) {
- document.getElementsByName('cbid.bypass.' + sid + '.' + params.get("security"))[0].checked = true;
- document.getElementsByName('cbid.bypass.' + sid + '.' + params.get("security"))[0].dispatchEvent(event);
-
- document.getElementsByName('cbid.bypass.' + sid + '.fingerprint')[0].value = params.get("fp") || "";
- document.getElementsByName('cbid.bypass.' + sid + '.tls_flow')[0].value = params.get("flow") || "";
- document.getElementsByName('cbid.bypass.' + sid + '.tls_host')[0].value = params.get("sni") || "";
+ // 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.bypass.' + sid + '.alias', url.hash ? decodeURIComponent(url.hash.slice(1)) : "");
+ setElementValue('cbid.bypass.' + sid + '.type', "v2ray");
+ dispatchEventIfExists('cbid.bypass.' + sid + '.type', event);
+ setElementValue('cbid.bypass.' + sid + '.v2ray_protocol', "vless");
+ dispatchEventIfExists('cbid.bypass.' + sid + '.v2ray_protocol', event);
+ setElementValue('cbid.bypass.' + sid + '.server', url.hostname);
+ setElementValue('cbid.bypass.' + sid + '.server_port', url.port || "80");
+ setElementValue('cbid.bypass.' + sid + '.vmess_id', url.username);
+ setElementValue('cbid.bypass.' + sid + '.transport',
+ params.get("type") === "http" ? "h2" :
+ (["tcp", "raw"].includes(params.get("type")) ? "raw" :
+ (params.get("type") || "tcp"))
+ );
+ dispatchEventIfExists('cbid.bypass.' + sid + '.transport', event);
+ setElementValue('cbid.bypass.' + sid + '.vless_encryption', params.get("encryption") || "none");
+ if ([ "tls", "xtls", "reality" ].includes(params.get("security"))) {
+ setElementValue('cbid.bypass.' + sid + '.' + params.get("security"), true);
+ dispatchEventIfExists('cbid.bypass.' + sid + '.' + params.get("security"), event);
if (params.get("security") === "reality") {
- document.getElementsByName('cbid.bypass.' + sid + '.reality_publickey')[0].value = params.get("pbk") ? decodeURIComponent(params.get("pbk")) : "";
- document.getElementsByName('cbid.bypass.' + sid + '.reality_shortid')[0].value = params.get("sid") || "";
- document.getElementsByName('cbid.bypass.' + sid + '.reality_spiderx')[0].value = params.get("spx") ? decodeURIComponent(params.get("spx")) : "";
+ setElementValue('cbid.bypass.' + sid + '.reality_publickey', params.get("pbk") ? decodeURIComponent(params.get("pbk")) : "");
+ setElementValue('cbid.bypass.' + sid + '.reality_shortid', params.get("sid") || "");
+ setElementValue('cbid.bypass.' + sid + '.reality_spiderx', params.get("spx") ? decodeURIComponent(params.get("spx")) : "");
}
+ setElementValue('cbid.bypass.' + sid + '.tls_flow', params.get("flow") || "none");
+ dispatchEventIfExists('cbid.bypass.' + sid + '.tls_flow', event);
+
+ setElementValue('cbid.bypass.' + sid + '.xhttp_alpn', params.get("alpn") || "");
+ setElementValue('cbid.bypass.' + sid + '.fingerprint', params.get("fp") || "");
+ setElementValue('cbid.bypass.' + sid + '.tls_host', params.get("sni") || "");
}
switch (params.get("type")) {
case "ws":
- if (params.get("security") !== "tls")
- document.getElementsByName('cbid.bypass.' + sid + '.ws_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
- document.getElementsByName('cbid.bypass.' + sid + '.ws_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "/";
+ if (params.get("security") !== "tls") {
+ setElementValue('cbid.bypass.' + sid + '.ws_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ }
+ setElementValue('cbid.bypass.' + sid + '.ws_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
+ break;
+ case "httpupgrade":
+ if (params.get("security") !== "tls") {
+ setElementValue('cbid.bypass.' + sid + '.httpupgrade_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ }
+ setElementValue('cbid.bypass.' + sid + '.httpupgrade_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
+ break;
+ case "splithttp":
+ if (params.get("security") !== "tls") {
+ setElementValue('cbid.bypass.' + sid + '.splithttp_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ }
+ setElementValue('cbid.bypass.' + sid + '.splithttp_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
+ break;
+ case "xhttp":
+ if (params.get("security") !== "tls") {
+ setElementValue('cbid.bypass.' + sid + '.xhttp_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ }
+ setElementValue('cbid.bypass.' + sid + '.xhttp_mode', params.get("mode") || "auto");
+ setElementValue('cbid.bypass.' + sid + '.xhttp_path', params.get("path") ? decodeURIComponent(params.get("path")) : "/");
+ if (params.get("extra") && params.get("extra").trim() !== "") {
+ setElementValue('cbid.bypass.' + sid + '.enable_xhttp_extra', true); // 设置 enable_xhttp_extra 为 true
+ dispatchEventIfExists('cbid.bypass.' + sid + '.enable_xhttp_extra', event); // 触发事件
+ setElementValue('cbid.bypass.' + sid + '.xhttp_extra', params.get("extra") || "");
+ }
break;
case "kcp":
- document.getElementsByName('cbid.bypass.' + sid + '.kcp_guise')[0].value = params.get("headerType") || "none";
- document.getElementsByName('cbid.bypass.' + sid + '.seed')[0].value = params.get("seed") || "";
+ setElementValue('cbid.bypass.' + sid + '.kcp_guise', params.get("headerType") || "none");
+ setElementValue('cbid.bypass.' + sid + '.seed', params.get("seed") || "");
break;
case "http":
/* this is non-standard, bullshit */
case "h2":
- document.getElementsByName('cbid.bypass.' + sid + '.h2_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
- document.getElementsByName('cbid.bypass.' + sid + '.h2_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
+ setElementValue('cbid.bypass.' + sid + '.h2_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ setElementValue('cbid.bypass.' + sid + '.h2_path', params.get("path") ? decodeURIComponent(params.get("path")) : "");
break;
case "quic":
- document.getElementsByName('cbid.bypass.' + sid + '.quic_guise')[0].value = params.get("headerType") || "none";
- document.getElementsByName('cbid.bypass.' + sid + '.quic_security')[0].value = params.get("quicSecurity") || "none";
- document.getElementsByName('cbid.bypass.' + sid + '.quic_key')[0].value = params.get("key") || "";
+ setElementValue('cbid.bypass.' + sid + '.quic_guise', params.get("headerType") || "none");
+ setElementValue('cbid.bypass.' + sid + '.quic_security', params.get("quicSecurity") || "none");
+ setElementValue('cbid.bypass.' + sid + '.quic_key', params.get("key") || "");
break;
case "grpc":
- document.getElementsByName('cbid.bypass.' + sid + '.serviceName')[0].value = params.get("serviceName") || "";
- document.getElementsByName('cbid.bypass.' + sid + '.grpc_mode')[0].value = params.get("mode") || "gun";
+ setElementValue('cbid.bypass.' + sid + '.serviceName', params.get("serviceName") || "");
+ setElementValue('cbid.bypass.' + sid + '.grpc_mode', params.get("mode") || "gun");
break;
case "tcp":
- document.getElementsByName('cbid.bypass.' + sid + '.tcp_guise')[0].value = params.get("headerType") || "none";
- document.getElementsByName('cbid.bypass.' + sid + '.tcp_guise')[0].dispatchEvent(event);
+ case "raw":
+ setElementValue('cbid.bypass.' + sid + '.tcp_guise', params.get("headerType") || "none");
+ dispatchEventIfExists('cbid.bypass.' + sid + '.tcp_guise', event);
if (params.get("headerType") === "http") {
- document.getElementsByName('cbid.bypass.' + sid + '.http_host')[0].value = params.get("host") ? decodeURIComponent(params.get("host")) : "";
- document.getElementsByName('cbid.bypass.' + sid + '.http_path')[0].value = params.get("path") ? decodeURIComponent(params.get("path")) : "";
+ setElementValue('cbid.bypass.' + sid + '.http_host', params.get("host") ? decodeURIComponent(params.get("host")) : "");
+ setElementValue('cbid.bypass.' + sid + '.http_path', params.get("path") ? decodeURIComponent(params.get("path")) : "");
}
break;
}
diff --git a/luci-app-bypass/root/etc/init.d/bypass b/luci-app-bypass/root/etc/init.d/bypass
index f699b8d95..fc731c00f 100755
--- a/luci-app-bypass/root/etc/init.d/bypass
+++ b/luci-app-bypass/root/etc/init.d/bypass
@@ -16,12 +16,16 @@ PID=/var/run/smartdns.pid
LOG=/var/log/bypass.log
BIN_DIR=/usr/share/bypass
# Get the default DNSMasq config ID from the UCI configuration
-DEFAULT_DNSMASQ_CFGID=$(uci show dhcp.@dnsmasq[0] | awk -F '.' '{print $2}' | awk -F '=' '{print $1}' | head -1)
+DEFAULT_DNSMASQ_CFGID="$(uci -q show "dhcp.@dnsmasq[0]" | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')"
# Locate the dnsmasq.conf file that contains the conf-dir option
DNSMASQ_CONF_PATH=$(grep -l "^conf-dir=" "/tmp/etc/dnsmasq.conf.${DEFAULT_DNSMASQ_CFGID}")
# Extract the directory path from the conf-dir line
-DNSMASQ_CONF_DIR=$(grep '^conf-dir=' "$DNSMASQ_CONF_PATH" | cut -d'=' -f2 | head -n 1)
-DNS_FILE=${DNSMASQ_CONF_DIR%*/}/dnsmasq-by.conf
+if [ -f "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID" ]; then
+ DNSMASQ_CONF_DIR="$(awk -F '=' '/^conf-dir=/ {print $2}' "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID")"
+else
+ DNSMASQ_CONF_DIR="/tmp/dnsmasq.d"
+fi
+DNS_FILE="${DNSMASQ_CONF_DIR%*/}/dnsmasq-by.conf"
DNS_DIR=/tmp/dnsmasq.by
O=$DNS_DIR/tmp
CRON="grep -q $BIN_DIR $CRON_FILE && sed -i '/\/share\/bypass/d' $CRON_FILE"
diff --git a/luci-app-bypass/root/usr/share/bypass/gen_config b/luci-app-bypass/root/usr/share/bypass/gen_config
index 98bacef5f..5696bc992 100644
--- a/luci-app-bypass/root/usr/share/bypass/gen_config
+++ b/luci-app-bypass/root/usr/share/bypass/gen_config
@@ -13,9 +13,12 @@ local chain = arg[6] or "0"
local chain_local_port = string.split(chain, "/")[2] or "0"
local server = ucursor:get_all("bypass", server_section)
+local socks_server = ucursor:get_all("bypass", "@socks5_proxy[0]") or {}
+local xray_fragment = ucursor:get_all("bypass", "@global_xray_fragment[0]") or {}
+local xray_noise = ucursor:get_all("bypass", "@xray_noise_packets[0]") or {}
local outbound_settings = nil
-local tls_host = (server.tls_host) and server.tls_host or server.server
+local tls_host = (tls_host) and tls_host or server.server
function vmess_vless()
outbound_settings = {
@@ -29,7 +32,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 ((server.xhttp_tls_flow ~= "none") and server.xhttp_tls_flow))) or nil
}
}
}
@@ -131,6 +134,8 @@ local Xray = {
-- 初始化 inbounds 表
inbounds = {},
+ -- 初始化 outbounds 表
+ outbounds = {},
}
-- 传入连接
-- 添加 dokodemo-door 配置,如果 local_port 不为 0
@@ -177,12 +182,22 @@ end
-- 开启 socks 代理
-- 检查是否启用 socks 代理
-if proto:find("tcp") and socks_port ~= "0" then
+if proto and 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 = (socks_ip_addr ~= "same") and {
+ 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
+ } or nil
})
end
@@ -197,7 +212,7 @@ end
security = (server.xtls == '1') and "xtls" or (server.tls == '1') and "tls" or (server.reality == '1') and "reality" or nil,
tlsSettings = (server.tls == '1') and {
-- tls
- alpn = server.tls_alpn,
+ alpn = (server.transport == "xhttp" and server.xhttp_alpn ~= "") and server.xhttp_alpn or server.tls_alpn,
fingerprint = server.fingerprint,
allowInsecure = (server.insecure == "1"),
serverName = tls_host,
@@ -213,21 +228,22 @@ end
minVersion = "1.3"
} or nil,
realitySettings = (server.reality == '1') and {
+ alpn = (server.transport == "xhttp" and server.xhttp_alpn ~= "") and server.xhttp_alpn or nil,
publicKey = server.reality_publickey,
shortId = server.reality_shortid,
spiderX = server.reality_spiderx,
fingerprint = server.fingerprint,
serverName = 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
}
} or nil,
kcpSettings = (server.transport == "kcp") and {
@@ -244,10 +260,10 @@ end
} or nil,
wsSettings = (server.transport == "ws") and (server.ws_path or server.ws_host or tls_host) and {
-- ws
- headers = (server.ws_host or tls_host) and {
- -- headers
- Host = server.ws_host or tls_host
- } or nil,
+ Host = server.ws_host or tls_host or nil,
+
+
+
path = server.ws_path,
maxEarlyData = tonumber(server.ws_ed) or nil,
earlyDataHeaderName = server.ws_ed_header or nil
@@ -262,6 +278,20 @@ end
host = (server.splithttp_host or tls_host) or nil,
path = server.splithttp_path or "/"
} or nil,
+ xhttpSettings = (server.transport == "xhttp") and {
+ -- xhttp
+ mode = server.xhttp_mode or "auto",
+ host = (server.xhttp_host or tls_host) or nil,
+ path = server.xhttp_path or "/",
+ extra = (server.enable_xhttp_extra == "1" and server.xhttp_extra) and (function()
+ local success, parsed = pcall(json.parse, server.xhttp_extra)
+ if success then
+ return parsed.extra or parsed
+ else
+ return nil
+ end
+ end)() or nil
+ } or nil,
httpSettings = (server.transport == "h2") and {
-- h2
path = server.h2_path or "",
@@ -285,21 +315,56 @@ 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
- tcpcongestion = server.custom_tcpcongestion -- 连接服务器节点的 TCP 拥塞控制算法
+ mark = 250,
+ tcpFastOpen = ((server.transport == "xhttp" and server.tcpfastopen == "1") and true or false) or (server.transport ~= "xhttp") and nil, -- XHTTP Tcp Fast Open
+ tcpMptcp = (server.mptcp == "1") and true or nil, -- MPTCP
+ Penetrate = (server.mptcp == "1") and true or nil, -- Penetrate MPTCP
+ tcpcongestion = server.custom_tcpcongestion, -- 连接服务器节点的 TCP 拥塞控制算法
+ dialerProxy = (xray_fragment.fragment == "1" or xray_fragment.noise == "1") and "dialerproxy" or nil
}
} or nil,
mux = (server.v2ray_protocol ~= "wireguard") and {
-- mux
- enabled = (server.mux == "1") and true or false, -- Mux
- concurrency = tonumber(server.concurrency), -- TCP 最大并发连接数
- xudpConcurrency = tonumber(server.xudpConcurrency), -- UDP 最大并发连接数
- xudpProxyUDP443 = server.xudpProxyUDP443 -- 对被代理的 UDP/443 流量处理方式
+ enabled = (server.mux == "1" or server.xmux == "1") and true or false, -- Mux
+ concurrency = (server.mux == "1" and ((server.concurrency ~= "0") and tonumber(server.concurrency) or 8)) or (server.xmux == "1" and -1) or nil, -- TCP 最大并发连接数
+ xudpConcurrency = ((server.xudpConcurrency ~= "0") and tonumber(server.xudpConcurrency)) or nil, -- UDP 最大并发连接数
+ xudpProxyUDP443 = (server.mux == "1") and server.xudpProxyUDP443 or nil -- 对被代理的 UDP/443 流量处理方式
} or nil
}
}
+-- 添加带有 fragment 设置的 dialerproxy 配置
+if xray_fragment.fragment ~= "0" or (xray_fragment.noise ~= "0" and xray_noise.enabled ~= "0") then
+ table.insert(Xray.outbounds, {
+ protocol = "freedom",
+ tag = "dialerproxy",
+ settings = {
+ domainStrategy = (xray_fragment.noise == "1" and xray_noise.enabled == "1") and xray_noise.domainStrategy,
+ fragment = (xray_fragment.fragment == "1") and {
+ packets = (xray_fragment.fragment_packets ~= "") and xray_fragment.fragment_packets or nil,
+ length = (xray_fragment.fragment_length ~= "") and xray_fragment.fragment_length or nil,
+ interval = (xray_fragment.fragment_interval ~= "") and xray_fragment.fragment_interval or nil
+ } or nil,
+ noises = (xray_fragment.noise == "1" and xray_noise.enabled == "1") and {
+ {
+ type = xray_noise.type,
+ packet = xray_noise.packet,
+ delay = xray_noise.delay:find("-") and xray_noise.delay or tonumber(xray_noise.delay)
+ }
+ } or nil
+ },
+ streamSettings = {
+ sockopt = {
+ mark = 250,
+ tcpFastOpen = ((server.transport == "xhttp" and server.tcpfastopen == "1") and true or false) or (server.transport ~= "xhttp") and nil, -- XHTTP Tcp Fast Open
+ tcpMptcp = (server.mptcp == "1") and true or nil, -- MPTCP
+ Penetrate = (server.mptcp == "1") and true or nil, -- Penetrate MPTCP
+ tcpcongestion = server.custom_tcpcongestion -- 连接服务器节点的 TCP 拥塞控制算法
+ }
+ }
+ })
+end
+
local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA"
local cipher13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384"
local trojan = {
@@ -345,7 +410,7 @@ local ss = {
server_port = tonumber(server.server_port),
local_address = "0.0.0.0",
local_port = tonumber(local_port),
- mode = (proto == "tcp,udp") and "tcp_and_udp" or proto .. "_only",
+ mode = (proto == "tcp,udp") and "tcp_and_udp" or (proto .. "_only"),
password = server.password,
method = server.encrypt_method_ss,
timeout = tonumber(server.timeout),
@@ -353,7 +418,7 @@ local ss = {
reuse_port = true
}
local hysteria = {
- server = (server.server_port and (server.port_range and (ip_addr .. ":" .. server.server_port .. "," .. server.port_range) or ip_addr .. ":" .. server.server_port) or (server.port_range and ip_addr .. ":" .. server.port_range or ip_addr .. ":443")),
+ server = (server.server_port and (server.port_range and (ip_addr .. ":" .. server.server_port .. "," .. server.port_range) or (ip_addr .. ":" .. server.server_port) or (server.port_range and ip_addr .. ":" .. server.port_range or ip_addr .. ":443"))),
bandwidth = (server.uplink_capacity or server.downlink_capacity) and {
up = tonumber(server.uplink_capacity) and tonumber(server.uplink_capacity) .. " mbps" or nil,
down = tonumber(server.downlink_capacity) and tonumber(server.downlink_capacity) .. " mbps" or nil
diff --git a/luci-app-bypass/root/usr/share/bypass/subscribe b/luci-app-bypass/root/usr/share/bypass/subscribe
index 596f26321..f271de45c 100755
--- a/luci-app-bypass/root/usr/share/bypass/subscribe
+++ b/luci-app-bypass/root/usr/share/bypass/subscribe
@@ -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
@@ -190,11 +193,29 @@ local function processData(szType, content)
result.splithttp_host = info.host
result.splithttp_path = info.path
end
+ if info.net == 'xhttp' then
+ result.xhttp_mode = info.mode
+ result.xhttp_host = info.host
+ result.xhttp_path = info.path
+ -- 检查 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
+ -- 尝试解析 JSON 数据
+ local success, Data = pcall(jsonParse, info.extra)
+ if success and Data then
+ local address = (Data.extra and Data.extra.downloadSettings and Data.extra.downloadSettings.address)
+ or (Data.downloadSettings and Data.downloadSettings.address)
+ result.download_address = address and address ~= "" and address or nil
+ else
+ -- 如果解析失败,清空下载地址
+ result.download_address = nil
+ end
+ end
if info.net == 'h2' then
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
@@ -228,6 +249,9 @@ local function processData(szType, content)
end
if info.tls == "tls" or info.tls == "1" then
result.tls = "1"
+ if info.alpn and info.alpn ~= "" then
+ result.xhttp_alpn = info.alpn
+ end
if info.sni and info.sni ~= "" then
result.tls_host = info.sni
elseif info.host then
@@ -316,6 +340,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,32 +349,113 @@ 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]
end
+ if params.alpn then
+ -- 处理 alpn 参数
+ result.xhttp_alpn = params.alpn
+ end
+
if params.sni then
-- 未指定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 == "xhttp" then
+ result.xhttp_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil
+ result.xhttp_mode = params.mode or "auto"
+ result.xhttp_path = params.path and UrlDecode(params.path) or "/"
+ -- 检查 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
+ -- 尝试解析 JSON 数据
+ local success, Data = pcall(jsonParse, params.extra)
+ if success and Data then
+ local address = (Data.extra and Data.extra.downloadSettings and Data.extra.downloadSettings.address)
+ or (Data.downloadSettings and Data.downloadSettings.address)
+ result.download_address = address and address ~= "" and address or nil
+ else
+ -- 如果解析失败,清空下载地址
+ result.download_address = nil
+ end
+ 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
@@ -363,6 +469,7 @@ local function processData(szType, content)
result.vless_encryption = params.encryption or "none"
result.transport = params.type or "tcp"
result.tls = (params.security == "tls" or params.security == "xtls") and "1" or "0"
+ result.xhttp_alpn = params.alpn or ""
result.tls_host = params.sni
result.tls_flow = (params.security == "tls" or params.security == "reality") and params.flow or nil
result.fingerprint = params.fp
@@ -379,6 +486,23 @@ local function processData(szType, content)
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 == "xhttp" then
+ result.xhttp_host = (result.tls ~= "1") and (params.host and UrlDecode(params.host)) or nil
+ result.xhttp_mode = params.mode or "auto"
+ result.xhttp_path = params.path and UrlDecode(params.path) or "/"
+ -- 检查 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
+ -- 尝试解析 JSON 数据
+ local success, Data = pcall(jsonParse, params.extra)
+ if success and Data then
+ local address = (Data.extra and Data.extra.downloadSettings and Data.extra.downloadSettings.address)
+ or (Data.downloadSettings and Data.downloadSettings.address)
+ result.download_address = address and address ~= "" and address or nil
+ else
+ -- 如果解析失败,清空下载地址
+ result.download_address = nil
+ end
-- make it compatible with bullshit, "h2" transport is non-existent at all
elseif result.transport == "http" or result.transport == "h2" then
result.transport = "h2"
@@ -400,7 +524,7 @@ 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
diff --git a/luci-app-bypass/root/usr/share/rpcd/acl.d/luci-app-bypass.json b/luci-app-bypass/root/usr/share/rpcd/acl.d/luci-app-bypass.json
index 1840faa5f..59e19cf96 100644
--- a/luci-app-bypass/root/usr/share/rpcd/acl.d/luci-app-bypass.json
+++ b/luci-app-bypass/root/usr/share/rpcd/acl.d/luci-app-bypass.json
@@ -2,9 +2,15 @@
"luci-app-bypass": {
"description": "Grant UCI access for luci-app-bypass",
"read": {
+ "file": {
+ "/etc/bypass/*": [ "read" ]
+ },
"uci": [ "bypass" ]
},
"write": {
+ "file": {
+ "/etc/bypass/*": [ "write" ]
+ },
"uci": [ "bypass" ]
}
}
diff --git a/luci-app-nekobox/htdocs/nekobox/ping.php b/luci-app-nekobox/htdocs/nekobox/ping.php
index bb493b351..a0e628b33 100644
--- a/luci-app-nekobox/htdocs/nekobox/ping.php
+++ b/luci-app-nekobox/htdocs/nekobox/ping.php
@@ -4026,6 +4026,22 @@ input[type="range"]:focus {
}
}
+@media (max-width: 768px) {
+ .modal-body .d-flex {
+ align-items: stretch;
+ gap: 10px;
+ }
+ .modal-body .btn {
+ width: 100%;
+ text-align: center;
+ margin-bottom: 8px;
+ padding: 10px;
+ }
+ .modal-body .btn:last-child {
+ margin-bottom: 0;
+ }
+}
+