luci-app-passwall2: sync upstream

last commit: d61359f4a4
This commit is contained in:
gitea-action 2024-11-17 17:00:21 +08:00
parent 38a728258f
commit a89e62e998
8 changed files with 330 additions and 114 deletions

View File

@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2 PKG_NAME:=luci-app-passwall2
PKG_VERSION:=24.11.17 PKG_VERSION:=24.11.17
PKG_RELEASE:=1 PKG_RELEASE:=2
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \

View File

@ -147,6 +147,7 @@ if has_xray then
o = s_xray:option(ListValue, "fragment_packets", translate("Fragment Packets"), translate(" \"1-3\" is for segmentation at TCP layer, applying to the beginning 1 to 3 data writes by the client. \"tlshello\" is for TLS client hello packet fragmentation.")) o = s_xray:option(ListValue, "fragment_packets", translate("Fragment Packets"), translate(" \"1-3\" is for segmentation at TCP layer, applying to the beginning 1 to 3 data writes by the client. \"tlshello\" is for TLS client hello packet fragmentation."))
o.default = "tlshello" o.default = "tlshello"
o:value("tlshello", "tlshello") o:value("tlshello", "tlshello")
o:value("1-1", "1-1")
o:value("1-2", "1-2") o:value("1-2", "1-2")
o:value("1-3", "1-3") o:value("1-3", "1-3")
o:value("1-5", "1-5") o:value("1-5", "1-5")

View File

@ -334,9 +334,10 @@ o:depends({ [option_name("protocol")] = "shadowsocks" })
o = s:option(Flag, option_name("reality"), translate("REALITY")) o = s:option(Flag, option_name("reality"), translate("REALITY"))
o.default = 0 o.default = 0
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "tcp" }) o:depends({ [option_name("tls")] = true, [option_name("transport")] = "raw" })
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "h2" }) 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")] = "grpc" })
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "xhttp" })
o = s:option(ListValue, option_name("alpn"), translate("alpn")) o = s:option(ListValue, option_name("alpn"), translate("alpn"))
o.default = "default" o.default = "default"
@ -392,7 +393,7 @@ o:depends({ [option_name("tls")] = true, [option_name("utls")] = true })
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true }) o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
o = s:option(ListValue, option_name("transport"), translate("Transport")) o = s:option(ListValue, option_name("transport"), translate("Transport"))
o:value("tcp", "TCP") o:value("raw", "RAW")
o:value("mkcp", "mKCP") o:value("mkcp", "mKCP")
o:value("ws", "WebSocket") o:value("ws", "WebSocket")
o:value("h2", "HTTP/2") o:value("h2", "HTTP/2")
@ -400,7 +401,7 @@ o:value("ds", "DomainSocket")
o:value("quic", "QUIC") o:value("quic", "QUIC")
o:value("grpc", "gRPC") o:value("grpc", "gRPC")
o:value("httpupgrade", "HttpUpgrade") o:value("httpupgrade", "HttpUpgrade")
o:value("splithttp", "SplitHTTP") o:value("xhttp", "XHTTP")
o:depends({ [option_name("protocol")] = "vmess" }) o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" }) o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "socks" }) o:depends({ [option_name("protocol")] = "socks" })
@ -432,13 +433,13 @@ o = s:option(Value, option_name("wireguard_keepAlive"), translate("Keep Alive"))
o.default = "0" o.default = "0"
o:depends({ [option_name("protocol")] = "wireguard" }) o:depends({ [option_name("protocol")] = "wireguard" })
-- [[ TCP部分 ]]-- -- [[ RAW部分 ]]--
-- TCP伪装 -- TCP伪装
o = s:option(ListValue, option_name("tcp_guise"), translate("Camouflage Type")) o = s:option(ListValue, option_name("tcp_guise"), translate("Camouflage Type"))
o:value("none", "none") o:value("none", "none")
o:value("http", "http") o:value("http", "http")
o:depends({ [option_name("transport")] = "tcp" }) o:depends({ [option_name("transport")] = "raw" })
-- HTTP域名 -- HTTP域名
o = s:option(DynamicList, option_name("tcp_guise_http_host"), translate("HTTP Host")) o = s:option(DynamicList, option_name("tcp_guise_http_host"), translate("HTTP Host"))
@ -566,16 +567,115 @@ o = s:option(Value, option_name("httpupgrade_path"), translate("HttpUpgrade Path
o.placeholder = "/" o.placeholder = "/"
o:depends({ [option_name("transport")] = "httpupgrade" }) o:depends({ [option_name("transport")] = "httpupgrade" })
-- [[ SplitHTTP部分 ]]-- -- [[ XHTTP部分 ]]--
o = s:option(Value, option_name("splithttp_host"), translate("SplitHTTP Host")) o = s:option(Value, option_name("xhttp_host"), translate("XHTTP Host"))
o:depends({ [option_name("transport")] = "splithttp" }) o:depends({ [option_name("transport")] = "xhttp" })
o = s:option(Value, option_name("splithttp_path"), translate("SplitHTTP Path")) o = s:option(Value, option_name("xhttp_path"), translate("XHTTP Path"))
o.placeholder = "/" o.placeholder = "/"
o:depends({ [option_name("transport")] = "splithttp" }) o:depends({ [option_name("transport")] = "xhttp" })
-- [[ Mux ]]-- -- XHTTP XMUX
o = s:option(Flag, option_name("mux"), translate("Mux")) 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")] = "xhttp" })
o = s:option(Value, option_name("maxConcurrency"), translate("XMUX Max Concurrency"))
o:depends({ [option_name("xhttp_xmux")] = true })
o = s:option(Value, option_name("maxConnections"), translate("XMUX Max Connections"))
o:depends({ [option_name("xhttp_xmux")] = true })
o = s:option(Value, option_name("cMaxReuseTimes"), translate("XMUX Connection Max Reuse Times"))
o:depends({ [option_name("xhttp_xmux")] = true })
o = s:option(Value, option_name("cMaxLifetimeMs"), translate("XMUX Connection Max Lifetime (ms)"))
o:depends({ [option_name("xhttp_xmux")] = true })
-- XHTTP 下行
o = s:option(Flag, option_name("xhttp_download"), string.format('<a style="color:red">%s</a>', translate("XHTTP download splitting")))
o:depends({ [option_name("transport")] = "xhttp" })
o = s:option(Value, option_name("xhttp_download_address"), string.format('<a style="color:red">%s</a>', translate("Address")))
o:depends({ [option_name("xhttp_download")] = true })
o = s:option(Value, option_name("xhttp_download_port"), string.format('<a style="color:red">%s</a>', translate("Port")))
o:depends({ [option_name("xhttp_download")] = true })
o = s:option(Value, option_name("xhttp_download_host"), string.format('<a style="color:red">%s</a>', "XHTTP Host"))
o:depends({ [option_name("xhttp_download")] = true })
o = s:option(Value, option_name("xhttp_download_path"), string.format('<a style="color:red">%s</a>', "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('<a style="color:red">%s</a>', "TLS"))
o:depends({ [option_name("xhttp_download")] = true })
o.default = 0
o = s:option(Flag, option_name("xhttp_download_reality"), string.format('<a style="color:red">%s</a>', "REALITY"))
o.default = 0
o:depends({ [option_name("xhttp_download_tls")] = true })
o = s:option(ListValue, option_name("xhttp_download_alpn"), string.format('<a style="color:red">%s</a>', "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('<a style="color:red">%s</a>', translate("Domain")))
o:depends({ [option_name("xhttp_download_tls")] = true })
o = s:option(Value, option_name("xhttp_download_reality_publicKey"), string.format('<a style="color:red">%s</a>', 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('<a style="color:red">%s</a>', 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('<a style="color:red">%s</a>', "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('<a style="color:red">%s</a>', "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('<a style="color:red">%s</a>', 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('<a style="color:red">%s</a>', "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('<a style="color:red">%s</a>', translate("XMUX Max Concurrency")))
o:depends({ [option_name("xhttp_download_xmux")] = true })
o = s:option(Value, option_name("download_maxConnections"), string.format('<a style="color:red">%s</a>', translate("XMUX Max Connections")))
o:depends({ [option_name("xhttp_download_xmux")] = true })
o = s:option(Value, option_name("download_cMaxReuseTimes"), string.format('<a style="color:red">%s</a>', translate("XMUX Connection Max Reuse Times")))
o:depends({ [option_name("xhttp_download_xmux")] = true })
o = s:option(Value, option_name("download_cMaxLifetimeMs"), string.format('<a style="color:red">%s</a>', 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"))
o:depends({ [option_name("protocol")] = "vmess" }) o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "" }) o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "" })
o:depends({ [option_name("protocol")] = "http" }) o:depends({ [option_name("protocol")] = "http" })
@ -588,7 +688,7 @@ o.default = 8
o:depends({ [option_name("mux")] = true }) o:depends({ [option_name("mux")] = true })
-- [[ XUDP Mux ]]-- -- [[ XUDP Mux ]]--
o = s:option(Flag, option_name("xmux"), translate("xMux")) o = s:option(Flag, option_name("xmux"), "XUDP Mux")
o.default = 1 o.default = 1
o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "xtls-rprx-vision" }) o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "xtls-rprx-vision" })
o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "xtls-rprx-vision-udp443" }) o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "xtls-rprx-vision-udp443" })

View File

@ -110,6 +110,15 @@ function gen_outbound(flag, node, tag, proxy_table)
end end
end end
if node.type == "Xray" and node.transport == "xhttp" 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 if node.protocol == "wireguard" and node.wireguard_reserved then
local bytes = {} local bytes = {}
if not node.wireguard_reserved:match("[^%d,]+") then if not node.wireguard_reserved:match("[^%d,]+") then
@ -159,7 +168,7 @@ function gen_outbound(flag, node, tag, proxy_table)
spiderX = node.reality_spiderX or "/", spiderX = node.reality_spiderX or "/",
fingerprint = (node.type == "Xray" and node.fingerprint and node.fingerprint ~= "") and node.fingerprint or "chrome" fingerprint = (node.type == "Xray" and node.fingerprint and node.fingerprint ~= "") and node.fingerprint or "chrome"
} or nil, } or nil,
tcpSettings = (node.transport == "tcp" and node.protocol ~= "socks") and { rawSettings = ((node.transport == "raw" or node.transport == "tcp") and node.protocol ~= "socks") and {
header = { header = {
type = node.tcp_guise or "none", type = node.tcp_guise or "none",
request = (node.tcp_guise == "http") and { request = (node.tcp_guise == "http") and {
@ -213,9 +222,35 @@ function gen_outbound(flag, node, tag, proxy_table)
path = node.httpupgrade_path or "/", path = node.httpupgrade_path or "/",
host = node.httpupgrade_host host = node.httpupgrade_host
} or nil, } or nil,
splithttpSettings = (node.transport == "splithttp") and { xhttpSettings = (node.transport == "xhttp" or node.transport == "splithttp") and {
path = node.splithttp_path or "/", path = node.xhttp_path or node.splithttp_path or "/",
host = node.splithttp_host host = node.xhttp_host or 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,
host = node.xhttp_download_host,
},
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,
} or nil, } or nil,
settings = { settings = {
@ -280,6 +315,41 @@ function gen_outbound(flag, node, tag, proxy_table)
result.streamSettings.tlsSettings.alpn = alpn result.streamSettings.tlsSettings.alpn = alpn
end end
end end
local alpn_download = {}
if node.xhttp_download_alpn and node.xhttp_download_alpn ~= "default" then
string.gsub(node.xhttp_download_alpn, '[^' .. "," .. ']+', function(w)
table.insert(alpn_download, w)
end)
end
if alpn_download and #alpn_download > 0 then
if result.streamSettings.xhttpSettings.downloadSettings.tlsSettings then
result.streamSettings.xhttpSettings.downloadSettings.tlsSettings.alpn = alpn_download
end
end
local xmux = {}
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
xmux.cMaxLifetimeMs = node.cMaxLifetimeMs and (string.find(node.cMaxLifetimeMs, "-") and node.cMaxLifetimeMs or tonumber(node.cMaxLifetimeMs)) or 0
if result.streamSettings.xhttpSettings then
result.streamSettings.xhttpSettings.xmux = xmux
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.xhttpSettings.downloadSettings.xhttpSettings then
result.streamSettings.xhttpSettings.downloadSettings.xhttpSettings.xmux = xmux_download
end
end
end end
return result return result
end end
@ -447,7 +517,7 @@ function gen_config_server(node)
} }
} }
} or nil, } or nil,
tcpSettings = (node.transport == "tcp") and { rawSettings = (node.transport == "raw" or node.transport == "tcp") and {
header = { header = {
type = node.tcp_guise, type = node.tcp_guise,
request = (node.tcp_guise == "http") and { request = (node.tcp_guise == "http") and {
@ -672,9 +742,20 @@ function gen_config(var)
return inboundTag return inboundTag
end end
local function gen_balancer(_node, loopbackTag) local function gen_balancer(_node, loopback_tag)
local balancer_id = _node[".name"]
local balancer_tag = "balancer-" .. balancer_id
local loopback_dst = balancer_id -- route destination for the loopback outbound
if not loopback_tag or loopback_tag == "" then loopback_tag = balancer_id end
-- existing balancer
for _, v in ipairs(balancers) do
if v.tag == balancer_tag then
gen_loopback(loopback_tag, loopback_dst)
return balancer_tag
end
end
-- new balancer
local blc_nodes = _node.balancing_node local blc_nodes = _node.balancing_node
local fallback_node_id = _node.fallback_node
local length = #blc_nodes local length = #blc_nodes
local valid_nodes = {} local valid_nodes = {}
for i = 1, length do for i = 1, length do
@ -698,6 +779,10 @@ function gen_config(var)
end end
end end
end end
if #valid_nodes == 0 then return nil end
-- fallback node
local fallback_node_id = _node.fallback_node
if fallback_node_id == "" then fallback_node_id = nil end if fallback_node_id == "" then fallback_node_id = nil end
if fallback_node_id then if fallback_node_id then
local is_new_node = true local is_new_node = true
@ -718,41 +803,33 @@ function gen_config(var)
fallback_node_id = nil fallback_node_id = nil
end end
else else
local valid = gen_balancer(fallback_node) if not gen_balancer(fallback_node) then
if not valid then
fallback_node_id = nil fallback_node_id = nil
end end
end end
end end
end end
table.insert(balancers, {
local valid = nil tag = balancer_tag,
if #valid_nodes > 0 then selector = valid_nodes,
local balancerTag = get_balancer_tag(_node[".name"]) fallbackTag = fallback_node_id,
table.insert(balancers, { strategy = { type = _node.balancingStrategy or "random" }
tag = balancerTag, })
selector = valid_nodes, if _node.balancingStrategy == "leastPing" or fallback_node_id then
fallbackTag = fallback_node_id, if not observatory then
strategy = { type = _node.balancingStrategy or "random" } observatory = {
}) subjectSelector = { "blc-" },
if _node.balancingStrategy == "leastPing" or fallback_node_id then probeUrl = _node.useCustomProbeUrl and _node.probeUrl or nil,
if not observatory then probeInterval = _node.probeInterval or "1m",
observatory = { enableConcurrency = true
subjectSelector = { "blc-" }, }
probeUrl = _node.useCustomProbeUrl and _node.probeUrl or nil,
probeInterval = _node.probeInterval or "1m",
enableConcurrency = true
}
end
end end
if loopbackTag == nil or loopbackTag =="" then loopbackTag = _node[".name"] end
local inboundTag = gen_loopback(loopbackTag, _node[".name"])
table.insert(rules, { inboundTag = { inboundTag }, balancerTag = balancerTag })
valid = true
end end
return valid local inbound_tag = gen_loopback(loopback_tag, loopback_dst)
table.insert(rules, { inboundTag = { inbound_tag }, balancerTag = balancer_tag })
return balancer_tag
end end
local function set_outbound_detour(node, outbound, outbounds_table, shunt_rule_name) local function set_outbound_detour(node, outbound, outbounds_table, shunt_rule_name)
if not node or not outbound or not outbounds_table then return nil end if not node or not outbound or not outbounds_table then return nil end
local default_outTag = outbound.tag local default_outTag = outbound.tag
@ -787,31 +864,25 @@ function gen_config(var)
node.port = server_port node.port = server_port
end end
if node.protocol == "_shunt" then if node.protocol == "_shunt" then
local preproxy_enabled = node.preproxy_enabled == "1" local preproxy_rule_name = node.preproxy_enabled == "1" and "main" or nil
local preproxy_rule_name = "main" local preproxy_tag = preproxy_rule_name
local preproxy_tag = "main"
local preproxy_node_id = node["main_node"] local preproxy_node_id = node["main_node"]
local preproxy_node = preproxy_enabled and preproxy_node_id and uci:get_all(appname, preproxy_node_id) or nil local preproxy_outbound_tag, preproxy_balancer_tag
if preproxy_node then local preproxy_nodes
preproxy_tag = preproxy_tag .. ":" .. preproxy_node.remarks
end
local proxy_outboundTag, proxy_balancerTag
local function gen_shunt_node(rule_name, _node_id) local function gen_shunt_node(rule_name, _node_id)
if not rule_name then return nil, nil end if not rule_name then return nil, nil end
if not _node_id then _node_id = node[rule_name] or "nil" end if not _node_id then _node_id = node[rule_name] or "nil" end
local rule_outboundTag
local rule_balancerTag
if _node_id == "_direct" then if _node_id == "_direct" then
rule_outboundTag = "direct" return "direct", nil
elseif _node_id == "_blackhole" then elseif _node_id == "_blackhole" then
rule_outboundTag = "blackhole" return "blackhole", nil
elseif _node_id == "_default" then elseif _node_id == "_default" then
rule_outboundTag = "default" return "default", nil
elseif _node_id:find("Socks_") then elseif _node_id:find("Socks_") then
local socks_id = _node_id:sub(1 + #"Socks_") local socks_id = _node_id:sub(1 + #"Socks_")
local socks_node = uci:get_all(appname, socks_id) or nil local socks_node = uci:get_all(appname, socks_id) or nil
local socks_tag
if socks_node then if socks_node then
local _node = { local _node = {
type = "Xray", type = "Xray",
@ -823,27 +894,25 @@ function gen_config(var)
} }
local outbound = gen_outbound(flag, _node, rule_name) local outbound = gen_outbound(flag, _node, rule_name)
if outbound then if outbound then
table.insert(outbounds, outbound) if rule_name == "default" then
rule_outboundTag = outbound.tag table.insert(outbounds, 1, outbound)
else
table.insert(outbounds, outbound)
end
socks_tag = outbound.tag
end end
end end
return socks_tag, nil
elseif _node_id ~= "nil" then elseif _node_id ~= "nil" then
local _node = uci:get_all(appname, _node_id) local _node = uci:get_all(appname, _node_id)
if not _node then return nil, nil end if not _node then return nil, nil end
if api.is_normal_node(_node) then if api.is_normal_node(_node) then
local use_proxy = preproxy_node and node[rule_name .. "_proxy_tag"] == preproxy_rule_name and _node_id ~= preproxy_node_id local use_proxy = preproxy_tag and node[rule_name .. "_proxy_tag"] == preproxy_rule_name and _node_id ~= preproxy_node_id
if use_proxy and proxy_balancerTag then if use_proxy and preproxy_balancer_tag and preproxy_nodes[_node_id] then use_proxy = false end
for _, blc_node_id in ipairs(preproxy_node.balancing_node) do
if _node_id == blc_node_id then
use_proxy = false
break
end
end
end
local copied_outbound local copied_outbound
for index, value in ipairs(outbounds) do for index, value in ipairs(outbounds) do
if value["_id"] == _node_id and value["_flag_proxy_tag"] == preproxy_tag then if value["_id"] == _node_id and value["_flag_proxy_tag"] == (use_proxy and preproxy_tag or nil) then
copied_outbound = api.clone(value) copied_outbound = api.clone(value)
break break
end end
@ -851,7 +920,7 @@ function gen_config(var)
if copied_outbound then if copied_outbound then
copied_outbound.tag = rule_name .. ":" .. _node.remarks copied_outbound.tag = rule_name .. ":" .. _node.remarks
table.insert(outbounds, copied_outbound) table.insert(outbounds, copied_outbound)
rule_outboundTag = rule_name return copied_outbound.tag, nil
else else
if use_proxy and (_node.type ~= "Xray" or _node.flow == "xtls-rprx-vision") then if use_proxy and (_node.type ~= "Xray" or _node.flow == "xtls-rprx-vision") then
new_port = get_new_port() new_port = get_new_port()
@ -869,8 +938,8 @@ function gen_config(var)
_node.port = new_port _node.port = new_port
table.insert(rules, 1, { table.insert(rules, 1, {
inboundTag = {"proxy_" .. rule_name}, inboundTag = {"proxy_" .. rule_name},
outboundTag = proxy_outboundTag, outboundTag = not preproxy_balancer_tag and preproxy_tag or nil,
balancerTag = proxy_balancerTag balancerTag = preproxy_balancer_tag
}) })
end end
local proxy_table = { local proxy_table = {
@ -885,33 +954,22 @@ function gen_config(var)
end end
end end
local outbound = gen_outbound(flag, _node, rule_name, proxy_table) local outbound = gen_outbound(flag, _node, rule_name, proxy_table)
local outbound_tag
if outbound then if outbound then
outbound.tag = outbound.tag .. ":" .. _node.remarks outbound.tag = outbound.tag .. ":" .. _node.remarks
rule_outboundTag = set_outbound_detour(_node, outbound, outbounds, rule_name) outbound_tag = set_outbound_detour(_node, outbound, outbounds, rule_name)
if rule_name == "default" then if rule_name == "default" then
table.insert(outbounds, 1, outbound) table.insert(outbounds, 1, outbound)
else else
table.insert(outbounds, outbound) table.insert(outbounds, outbound)
end end
end end
return outbound_tag, nil
end end
elseif _node.protocol == "_balancing" then elseif _node.protocol == "_balancing" then
local is_new_balancer = true return nil, gen_balancer(_node, rule_name)
rule_balancerTag = get_balancer_tag(_node_id)
for _, v in ipairs(balancers) do
if v.tag == rule_balancerTag then
is_new_balancer = false
gen_loopback(rule_name, _node_id)
break
end
end
if is_new_balancer then
local valid = gen_balancer(_node, rule_name)
if not valid then
rule_balancerTag = nil
end
end
elseif _node.protocol == "_iface" then elseif _node.protocol == "_iface" then
local outbound_tag
if _node.iface then if _node.iface then
local outbound = { local outbound = {
protocol = "freedom", protocol = "freedom",
@ -923,26 +981,40 @@ function gen_config(var)
} }
} }
} }
outbound_tag = outbound.tag
table.insert(outbounds, outbound) table.insert(outbounds, outbound)
rule_outboundTag = rule_name
sys.call("touch /tmp/etc/passwall2/iface/" .. _node.iface) sys.call("touch /tmp/etc/passwall2/iface/" .. _node.iface)
end end
return outbound_tag, nil
end end
end end
return rule_outboundTag, rule_balancerTag
end end
if preproxy_node then if preproxy_tag and preproxy_node_id then
proxy_outboundTag, proxy_balancerTag = gen_shunt_node(preproxy_rule_name, preproxy_node_id) preproxy_outbound_tag, preproxy_balancer_tag = gen_shunt_node(preproxy_rule_name, preproxy_node_id)
if not proxy_outboundTag and not proxy_balancerTag then if preproxy_balancer_tag then
preproxy_node = nil local _node_id = preproxy_node_id
preproxy_nodes = {}
while _node_id do
_node = uci:get_all(appname, _node_id)
if not _node then break end
if _node.protocol ~= "_balancing" then
preproxy_nodes[_node_id] = true
break
end
local _blc_nodes = _node.balancing_node
for i = 1, #_blc_nodes do preproxy_nodes[_blc_nodes[i]] = true end
_node_id = _node.fallback_node
end
elseif preproxy_outbound_tag then
preproxy_tag = preproxy_outbound_tag
end end
end end
--default_node --default_node
local default_node_id = node.default_node or "_direct" local default_node_id = node.default_node or "_direct"
local default_outboundTag, default_balancerTag = gen_shunt_node("default", default_node_id) local default_outboundTag, default_balancerTag = gen_shunt_node("default", default_node_id)
COMMON.default_outbound_tag = default_outbound_tag COMMON.default_outbound_tag = default_outboundTag
COMMON.default_balancer_tag = default_balancer_tag COMMON.default_balancer_tag = default_balancerTag
--shunt rule --shunt rule
uci:foreach(appname, "shunt_rules", function(e) uci:foreach(appname, "shunt_rules", function(e)
local outboundTag, balancerTag = gen_shunt_node(e[".name"]) local outboundTag, balancerTag = gen_shunt_node(e[".name"])
@ -1053,15 +1125,15 @@ function gen_config(var)
} }
elseif node.protocol == "_balancing" then elseif node.protocol == "_balancing" then
if node.balancing_node then if node.balancing_node then
local valid = gen_balancer(node) local balancer_tag = gen_balancer(node)
if valid then if balancer_tag then
table.insert(rules, { network = "tcp,udp", balancerTag = get_balancer_tag(node_id) }) table.insert(rules, { network = "tcp,udp", balancerTag = balancer_tag })
end end
routing = { routing = {
balancers = balancers, balancers = balancers,
rules = rules rules = rules
} }
COMMON.default_balancer_tag = get_balancer_tag(node_id) COMMON.default_balancer_tag = balancer_tag
end end
elseif node.protocol == "_iface" then elseif node.protocol == "_iface" then
if node.iface then if node.iface then
@ -1358,7 +1430,7 @@ function gen_config(var)
local default_rule_index = #routing.rules > 0 and #routing.rules or 1 local default_rule_index = #routing.rules > 0 and #routing.rules or 1
for index, value in ipairs(routing.rules) do for index, value in ipairs(routing.rules) do
if value["_flag"] == "default" then if value.ruleTag == "default" then
default_rule_index = index default_rule_index = index
break break
end end
@ -1461,7 +1533,7 @@ function gen_config(var)
}) })
end end
table.insert(outbounds, { local direct_outbound = {
protocol = "freedom", protocol = "freedom",
tag = "direct", tag = "direct",
settings = { settings = {
@ -1472,11 +1544,23 @@ function gen_config(var)
mark = 255 mark = 255
} }
} }
}) }
table.insert(outbounds, { if COMMON.default_outbound_tag == "direct" then
table.insert(outbounds, 1, direct_outbound)
else
table.insert(outbounds, direct_outbound)
end
local blackhole_outbound = {
protocol = "blackhole", protocol = "blackhole",
tag = "blackhole" tag = "blackhole"
}) }
if COMMON.default_outbound_tag == "blackhole" then
table.insert(outbounds, 1, blackhole_outbound)
else
table.insert(outbounds, blackhole_outbound)
end
for index, value in ipairs(config.outbounds) do for index, value in ipairs(config.outbounds) do
for k, v in pairs(config.outbounds[index]) do for k, v in pairs(config.outbounds[index]) do
if k:find("_") == 1 then if k:find("_") == 1 then

View File

@ -368,6 +368,10 @@ local api = require "luci.passwall2.api"
v_transport = "splithttp"; v_transport = "splithttp";
params += opt.query("host", dom_prefix + "splithttp_host"); params += opt.query("host", dom_prefix + "splithttp_host");
params += opt.query("path", dom_prefix + "splithttp_path"); 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");
} }
params += "&type=" + v_transport; params += "&type=" + v_transport;
@ -1135,6 +1139,9 @@ local api = require "luci.passwall2.api"
} else if (queryParam.type === "splithttp") { } else if (queryParam.type === "splithttp") {
opt.set(dom_prefix + 'splithttp_host', queryParam.host || ""); opt.set(dom_prefix + 'splithttp_host', queryParam.host || "");
opt.set(dom_prefix + 'splithttp_path', queryParam.path || ""); 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 || "");
} }
if (m.hash) { if (m.hash) {

View File

@ -1378,6 +1378,30 @@ msgstr "客户端文件不适合当前设备。"
msgid "Can't move new file to path: %s" msgid "Can't move new file to path: %s"
msgstr "无法移动新文件到:%s" msgstr "无法移动新文件到:%s"
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 连接最大复用流数"
msgid "XMUX Max Connections"
msgstr "XMUX 最大连接数"
msgid "XMUX Connection Max Reuse Times"
msgstr "XMUX 连接最多复用次数"
msgid "XMUX Connection Max Lifetime (ms)"
msgstr "XMUX 连接最大存活时间ms"
msgid "Enable Mux.Cool"
msgstr "启用 Mux.Cool"
msgid "Mux concurrency" msgid "Mux concurrency"
msgstr "最大并发连接数" msgstr "最大并发连接数"

View File

@ -223,10 +223,10 @@ load_acl() {
} }
_acl_list=${TMP_ACL_PATH}/${sid}/rule_list _acl_list=${TMP_ACL_PATH}/${sid}/rule_list
[ $use_interface = "1" ] && _acl_list=${TMP_ACL_PATH}/${sid}/interface_list [ "$use_interface" = "1" ] && _acl_list=${TMP_ACL_PATH}/${sid}/interface_list
for i in $(cat $_acl_list); do for i in $(cat $_acl_list); do
if [ $use_interface = "0" ]; then if [ "$use_interface" = "0" ]; then
if [ -n "$(echo ${i} | grep '^iprange:')" ]; then if [ -n "$(echo ${i} | grep '^iprange:')" ]; then
_iprange=$(echo ${i} | sed 's#iprange:##g') _iprange=$(echo ${i} | sed 's#iprange:##g')
_ipt_source=$(factor ${_iprange} "-m iprange --src-range") _ipt_source=$(factor ${_iprange} "-m iprange --src-range")

View File

@ -277,10 +277,10 @@ load_acl() {
} }
_acl_list=${TMP_ACL_PATH}/${sid}/rule_list _acl_list=${TMP_ACL_PATH}/${sid}/rule_list
[ $use_interface = "1" ] && _acl_list=${TMP_ACL_PATH}/${sid}/interface_list [ "$use_interface" = "1" ] && _acl_list=${TMP_ACL_PATH}/${sid}/interface_list
for i in $(cat $_acl_list); do for i in $(cat $_acl_list); do
if [ $use_interface = "0" ]; then if [ "$use_interface" = "0" ]; then
if [ -n "$(echo ${i} | grep '^iprange:')" ]; then if [ -n "$(echo ${i} | grep '^iprange:')" ]; then
_iprange=$(echo ${i} | sed 's#iprange:##g') _iprange=$(echo ${i} | sed 's#iprange:##g')
_ipt_source=$(factor ${_iprange} "ip saddr") _ipt_source=$(factor ${_iprange} "ip saddr")