From 95389eb6744552e442906c35d9bb94d49c1a403c Mon Sep 17 00:00:00 2001
From: xiaorouji <60100640+xiaorouji@users.noreply.github.com>
Date: Sat, 15 Apr 2023 02:46:15 +0800
Subject: [PATCH] luci: shunt mode select node can custom
You can directly customize SOCKS/HTTP server when selecting nodes.
For example:
socks://127.0.0.1:1080
socks://username:password@127.0.0.1:1080
http://127.0.0.1:2080
http://username:password@127.0.0.1:2080
---
.../model/cbi/passwall/client/global.lua | 6 +--
.../model/cbi/passwall/client/node_config.lua | 6 +--
luci-app-passwall/luasrc/passwall/api.lua | 38 +++++++++++++++++++
.../luasrc/passwall/util_xray.lua | 38 ++++++++++++++++++-
4 files changed, 81 insertions(+), 7 deletions(-)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
index cc5a89451..4d1c136a6 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
@@ -174,7 +174,7 @@ if (has_v2ray or has_xray) and #nodes_table > 0 then
o.cfgvalue = get_cfgvalue(v.id, "preproxy_enabled")
o.write = get_write(v.id, "preproxy_enabled")
- o = s:taboption("Main", ListValue, vid .. "-main_node", string.format('%s', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including Default
) has a separate switch that controls whether this rule uses the pre-proxy or not."))
+ o = s:taboption("Main", Value, vid .. "-main_node", string.format('%s', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including Default
) has a separate switch that controls whether this rule uses the pre-proxy or not."))
o:depends(vid .. "-preproxy_enabled", "1")
for k1, v1 in pairs(balancing_list) do
o:value(v1.id, v1.remark)
@@ -198,7 +198,7 @@ if (has_v2ray or has_xray) and #nodes_table > 0 then
local id = e[".name"]
local node_option = vid .. "-" .. id .. "_node"
if id and e.remarks then
- o = s:taboption("Main", ListValue, node_option, string.format('* %s', api.url("shunt_rules", id), e.remarks))
+ o = s:taboption("Main", Value, node_option, string.format('* %s', api.url("shunt_rules", id), e.remarks))
o.cfgvalue = get_cfgvalue(v.id, id)
o.write = get_write(v.id, id)
o:depends("tcp_node", v.id)
@@ -224,7 +224,7 @@ if (has_v2ray or has_xray) and #nodes_table > 0 then
end)
local id = "default_node"
- o = s:taboption("Main", ListValue, vid .. "-" .. id, string.format('* %s', translate("Default")))
+ o = s:taboption("Main", Value, vid .. "-" .. id, string.format('* %s', translate("Default")))
o.cfgvalue = get_cfgvalue(v.id, id)
o.write = get_write(v.id, id)
o:depends("tcp_node", v.id)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
index 1d5bb7518..2e1e8b223 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
@@ -175,7 +175,7 @@ probeInterval.description = translate("The interval between initiating probes. E
if #nodes_table > 0 then
o = s:option(Flag, "preproxy_enabled", translate("Preproxy"))
o:depends("protocol", "_shunt")
- o = s:option(ListValue, "main_node", string.format('%s', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including Default
) has a separate switch that controls whether this rule uses the pre-proxy or not."))
+ o = s:option(Value, "main_node", string.format('%s', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including Default
) has a separate switch that controls whether this rule uses the pre-proxy or not."))
o:depends("preproxy_enabled", "1")
for k, v in pairs(balancers_table) do
o:value(v.id, v.remarks)
@@ -187,7 +187,7 @@ if #nodes_table > 0 then
end
uci:foreach(appname, "shunt_rules", function(e)
if e[".name"] and e.remarks then
- o = s:option(ListValue, e[".name"], string.format('* %s', api.url("shunt_rules", e[".name"]), e.remarks))
+ o = s:option(Value, e[".name"], string.format('* %s', api.url("shunt_rules", e[".name"]), e.remarks))
o:value("nil", translate("Close"))
o:value("_default", translate("Default"))
o:value("_direct", translate("Direct Connection"))
@@ -217,7 +217,7 @@ shunt_tips.cfgvalue = function(t, n)
end
shunt_tips:depends("protocol", "_shunt")
-local default_node = s:option(ListValue, "default_node", string.format('* %s', translate("Default")))
+local default_node = s:option(Value, "default_node", string.format('* %s', translate("Default")))
default_node:depends("protocol", "_shunt")
default_node:value("_direct", translate("Direct Connection"))
default_node:value("_blackhole", translate("Blackhole"))
diff --git a/luci-app-passwall/luasrc/passwall/api.lua b/luci-app-passwall/luasrc/passwall/api.lua
index a7d197e28..b8bf472f0 100644
--- a/luci-app-passwall/luasrc/passwall/api.lua
+++ b/luci-app-passwall/luasrc/passwall/api.lua
@@ -611,6 +611,44 @@ local function auto_get_arch()
return util.trim(arch)
end
+function parseURL(url)
+ if not url or url == "" then
+ return nil
+ end
+ local pattern = "^(%w+)://"
+ local protocol = url:match(pattern)
+
+ if not protocol then
+ --error("Invalid URL: " .. url)
+ return nil
+ end
+
+ local auth_host_port = url:sub(#protocol + 4)
+ local auth_pattern = "^([^@]+)@"
+ local auth = auth_host_port:match(auth_pattern)
+ local username, password
+
+ if auth then
+ username, password = auth:match("^([^:]+):([^:]+)$")
+ auth_host_port = auth_host_port:sub(#auth + 2)
+ end
+
+ local host, port = auth_host_port:match("^([^:]+):(%d+)$")
+
+ if not host or not port then
+ --error("Invalid URL: " .. url)
+ return nil
+ end
+
+ return {
+ protocol = protocol,
+ username = username,
+ password = password,
+ host = host,
+ port = tonumber(port)
+ }
+end
+
local default_file_tree = {
x86_64 = "amd64",
x86 = "386",
diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua
index c2da7c4e7..9cf130e4a 100644
--- a/luci-app-passwall/luasrc/passwall/util_xray.lua
+++ b/luci-app-passwall/luasrc/passwall/util_xray.lua
@@ -674,7 +674,26 @@ function gen_config(var)
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_is_balancer
- if preproxy_node and api.is_normal_node(preproxy_node) then
+
+ if not preproxy_node and preproxy_node_id and api.parseURL(preproxy_node_id) then
+ local parsed1 = api.parseURL(preproxy_node_id)
+ local _node = {
+ type = "Xray",
+ protocol = parsed1.protocol,
+ username = parsed1.username,
+ password = parsed1.password,
+ address = parsed1.host,
+ port = parsed1.port,
+ transport = "tcp",
+ stream_security = "none"
+ }
+ local preproxy_outbound = gen_outbound(flag, _node, preproxy_tag)
+ if preproxy_outbound then
+ table.insert(outbounds, preproxy_outbound)
+ else
+ preproxy_enabled = false
+ end
+ elseif preproxy_node and api.is_normal_node(preproxy_node) then
local preproxy_outbound = gen_outbound(flag, preproxy_node, preproxy_tag)
if preproxy_outbound then
table.insert(outbounds, preproxy_outbound)
@@ -703,6 +722,23 @@ function gen_config(var)
rule_outboundTag = "blackhole"
elseif _node_id == "_default" and rule_name ~= "default" then
rule_outboundTag = "default"
+ elseif api.parseURL(_node_id) then
+ local parsed1 = api.parseURL(_node_id)
+ local _node = {
+ type = "Xray",
+ protocol = parsed1.protocol,
+ username = parsed1.username,
+ password = parsed1.password,
+ address = parsed1.host,
+ port = parsed1.port,
+ transport = "tcp",
+ stream_security = "none"
+ }
+ local _outbound = gen_outbound(flag, _node, rule_name)
+ if _outbound then
+ table.insert(outbounds, _outbound)
+ rule_outboundTag = rule_name
+ end
elseif _node_id ~= "nil" then
local _node = uci:get_all(appname, _node_id)
if not _node then return nil, nil end