diff --git a/applications/luci-app-passwall/Makefile b/applications/luci-app-passwall/Makefile
index c4b74a5d3b..44ae942705 100644
--- a/applications/luci-app-passwall/Makefile
+++ b/applications/luci-app-passwall/Makefile
@@ -7,7 +7,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
-PKG_VERSION:=26.1.17
+PKG_VERSION:=26.1.25
PKG_RELEASE:=1
PKG_CONFIG_DEPENDS:= \
diff --git a/applications/luci-app-passwall/luasrc/controller/passwall.lua b/applications/luci-app-passwall/luasrc/controller/passwall.lua
index a052e29635..cc50ae8c9e 100644
--- a/applications/luci-app-passwall/luasrc/controller/passwall.lua
+++ b/applications/luci-app-passwall/luasrc/controller/passwall.lua
@@ -11,6 +11,7 @@ local http = require "luci.http"
local util = require "luci.util"
local i18n = require "luci.i18n"
local jsonStringify = luci.jsonc.stringify
+local jsonParse = luci.jsonc.parse
function index()
if not nixio.fs.access("/etc/config/passwall") then
@@ -79,6 +80,7 @@ function index()
entry({"admin", "services", appname, "ping_node"}, call("ping_node")).leaf = true
entry({"admin", "services", appname, "urltest_node"}, call("urltest_node")).leaf = true
entry({"admin", "services", appname, "add_node"}, call("add_node")).leaf = true
+ entry({"admin", "services", appname, "update_node"}, call("update_node")).leaf = true
entry({"admin", "services", appname, "set_node"}, call("set_node")).leaf = true
entry({"admin", "services", appname, "copy_node"}, call("copy_node")).leaf = true
entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true
@@ -119,6 +121,16 @@ local function http_write_json(content)
http.write(jsonStringify(content or {code = 1}))
end
+local function http_write_json_ok(data)
+ http.prepare_content("application/json")
+ http.write(jsonStringify({code = 1, data = data}))
+end
+
+local function http_write_json_error(data)
+ http.prepare_content("application/json")
+ http.write(jsonStringify({code = 0, data = data}))
+end
+
function reset_config()
luci.sys.call('/etc/init.d/passwall stop')
luci.sys.call('[ -f "/usr/share/passwall/0_default_config" ] && cp -f /usr/share/passwall/0_default_config /etc/config/passwall')
@@ -412,6 +424,8 @@ function add_node()
uci:set(appname, uuid, "group", group)
end
+ uci:set(appname, uuid, "type", "Xray")
+
if redirect == "1" then
api.uci_save(uci, appname)
http.redirect(api.url("node_config", uuid))
@@ -421,6 +435,23 @@ function add_node()
end
end
+function update_node()
+ local id = http.formvalue("id") -- Node id
+ local data = http.formvalue("data") -- json new Data
+ if id and data then
+ local data_t = jsonParse(data) or {}
+ if next(data_t) then
+ for k, v in pairs(data_t) do
+ uci:set(appname, id, k, v)
+ end
+ api.uci_save(uci, appname)
+ http_write_json_ok()
+ return
+ end
+ end
+ http_write_json_error()
+end
+
function set_node()
local protocol = http.formvalue("protocol")
local section = http.formvalue("section")
diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua
index 8cffe54e57..435390ce04 100644
--- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua
+++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua
@@ -464,11 +464,19 @@ o:depends({xray_dns_mode = "tcp+doh"})
o:depends({singbox_dns_mode = "doh"})
o = s:option(Value, "remote_dns_client_ip", translate("EDNS Client Subnet"))
+o.description = translate("Notify the DNS server when the DNS query is notified, the location of the client (cannot be a private IP address).") .. "
" ..
+ translate("This feature requires the DNS server to support the Edns Client Subnet (RFC7871).")
o.datatype = "ipaddr"
o:depends({dns_mode = "sing-box"})
o:depends({dns_mode = "xray"})
o:depends({_node_sel_shunt = "1"})
+o = s:option(Flag, "remote_fakedns", "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy."))
+o.default = "0"
+o.rmempty = false
+o:depends({dns_mode = "sing-box"})
+o:depends({dns_mode = "xray"})
+
o = s:option(ListValue, "chinadns_ng_default_tag", translate("Default DNS"))
o.default = "none"
o:value("gfw", translate("Remote DNS"))
diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
index 4cd6b0ea8e..181688f720 100644
--- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
+++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
@@ -95,6 +95,8 @@ end
m:append(Template(appname .. "/global/status"))
+local global_cfgid = m:get("@global[0]")[".name"]
+
s = m:section(TypedSection, "global")
s.anonymous = true
s.addremove = false
@@ -118,29 +120,34 @@ o:value("", translate("Close"))
o:value("tcp", translate("Same as the tcp node"))
o.group = {"",""}
+local tcp_node_id = m.uci:get(appname, global_cfgid, "tcp_node")
+local tcp_node = tcp_node_id and m.uci:get_all(appname, tcp_node_id) or {}
+
-- 分流
if (has_singbox or has_xray) and #nodes_table > 0 then
- local function get_cfgvalue(shunt_node_id, option)
- return function(self, section)
- return m:get(shunt_node_id, option)
- end
- end
- local function get_write(shunt_node_id, option)
- return function(self, section, value)
- if s.fields["tcp_node"]:formvalue(section) == shunt_node_id then
- m:set(shunt_node_id, option, value)
+ if #normal_list > 0 and tcp_node.protocol == "_shunt" then
+ local v = tcp_node
+ if v then
+ local function get_cfgvalue(shunt_node_id, option)
+ return function(self, section)
+ return m:get(shunt_node_id, option)
+ end
end
- end
- end
- local function get_remove(shunt_node_id, option)
- return function(self, section)
- if s.fields["tcp_node"]:formvalue(section) == shunt_node_id then
- m:del(shunt_node_id, option)
+ local function get_write(shunt_node_id, option)
+ return function(self, section, value)
+ if s.fields["tcp_node"]:formvalue(section) == shunt_node_id then
+ m:set(shunt_node_id, option, value)
+ end
+ end
end
- end
- end
- if #normal_list > 0 then
- for k, v in pairs(shunt_list) do
+ local function get_remove(shunt_node_id, option)
+ return function(self, section)
+ if s.fields["tcp_node"]:formvalue(section) == shunt_node_id then
+ m:del(shunt_node_id, option)
+ end
+ end
+ end
+ v.id = v[".name"]
local vid = v.id
-- shunt node type, Sing-Box or Xray
o = s:taboption("Main", ListValue, vid .. "-type", translate("Type"))
@@ -161,7 +168,7 @@ if (has_singbox 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", 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:depends(vid .. "-preproxy_enabled", "1")
o.template = appname .. "/cbi/nodes_listvalue"
o.group = {}
@@ -188,6 +195,12 @@ if (has_singbox or has_xray) and #nodes_table > 0 then
o.cfgvalue = get_cfgvalue(v.id, "main_node")
o.write = get_write(v.id, "main_node")
+ o = s:taboption("Main", Flag, vid .. "-fakedns", "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy."))
+ o:depends("tcp_node", v.id)
+ o.cfgvalue = get_cfgvalue(v.id, "fakedns")
+ o.write = get_write(v.id, "fakedns")
+ o.remove = get_remove(v.id, "fakedns")
+
m.uci:foreach(appname, "shunt_rules", function(e)
local id = e[".name"]
local node_option = vid .. "-" .. id .. "_node"
@@ -204,16 +217,23 @@ if (has_singbox or has_xray) and #nodes_table > 0 then
o.template = appname .. "/cbi/nodes_listvalue"
o.group = {"","","",""}
- local pt = s:taboption("Main", ListValue, vid .. "-".. id .. "_proxy_tag", string.format('* %s', e.remarks .. " " .. translate("Preproxy")))
+ local pt = s:taboption("Main", ListValue, vid .. "-".. id .. "_proxy_tag", string.format('* %s', e.remarks .. " " .. translate("Preproxy")))
pt.cfgvalue = get_cfgvalue(v.id, id .. "_proxy_tag")
pt.write = get_write(v.id, id .. "_proxy_tag")
pt.remove = get_remove(v.id, id .. "_proxy_tag")
pt:value("", translate("Close"))
pt:value("main", translate("Preproxy Node"))
pt:depends("__hide__", "1")
+
+ local fakedns_tag = s:taboption("Main", Flag, vid .. "-".. id .. "_fakedns", string.format('* %s', e.remarks .. " " .. "FakeDNS"))
+ fakedns_tag.cfgvalue = get_cfgvalue(v.id, id .. "_fakedns")
+ fakedns_tag.write = get_write(v.id, id .. "_fakedns")
+ fakedns_tag.remove = get_remove(v.id, id .. "_fakedns")
+
for k1, v1 in pairs(socks_list) do
o:value(v1.id, v1.remark)
o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default")
+ fakedns_tag:depends({ [node_option] = v1.id, [vid .. "-fakedns"] = "1" })
end
for k1, v1 in pairs(balancing_list) do
o:value(v1.id, v1.remark)
@@ -233,6 +253,10 @@ if (has_singbox or has_xray) and #nodes_table > 0 then
if not api.is_local_ip(v1.address) then --本地节点禁止使用前置
pt:depends({ [node_option] = v1.id, [vid .. "-preproxy_enabled"] = "1" })
end
+ fakedns_tag:depends({ [node_option] = v1.id, [vid .. "-fakedns"] = "1" })
+ end
+ if v.default_node ~= "_direct" or v.default_node ~= "_blackhole" then
+ fakedns_tag:depends({ [node_option] = "_default", [vid .. "-fakedns"] = "1" })
end
end
end)
@@ -269,7 +293,7 @@ if (has_singbox or has_xray) and #nodes_table > 0 then
end
local id = "default_proxy_tag"
- o = s:taboption("Main", ListValue, vid .. "-" .. id, string.format('* %s', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node."))
+ o = s:taboption("Main", ListValue, vid .. "-" .. id, string.format('* %s', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node."))
o.cfgvalue = get_cfgvalue(v.id, id)
o.write = get_write(v.id, id)
o.remove = get_remove(v.id, id)
@@ -335,7 +359,7 @@ if api.is_finded("smartdns") then
o = s:taboption("DNS", Value, "group_domestic", translate("Domestic group name"))
o.placeholder = "local"
o:depends("dns_shunt", "smartdns")
- o.description = translate("You only need to configure domestic DNS packets in SmartDNS and set it redirect or as Dnsmasq upstream, and fill in the domestic DNS group name here.")
+ o.description = translate("You only need to configure domestic DNS packets in SmartDNS, and fill in the domestic DNS group name here.")
end
o = s:taboption("DNS", ListValue, "direct_dns_mode", translate("Direct DNS") .. " " .. translate("Request protocol"))
@@ -559,7 +583,7 @@ o:depends({singbox_dns_mode = "doh"})
o = s:taboption("DNS", Value, "remote_dns_client_ip", translate("EDNS Client Subnet"))
o.description = translate("Notify the DNS server when the DNS query is notified, the location of the client (cannot be a private IP address).") .. "
" ..
- translate("This feature requires the DNS server to support the Edns Client Subnet (RFC7871).")
+ translate("This feature requires the DNS server to support the Edns Client Subnet (RFC7871).")
o.datatype = "ipaddr"
o:depends({dns_mode = "sing-box"})
o:depends({dns_mode = "xray"})
@@ -574,7 +598,7 @@ o:depends({smartdns_dns_mode = "sing-box", dns_shunt = "smartdns"})
o:depends({dns_mode = "xray", dns_shunt = "dnsmasq"})
o:depends({dns_mode = "xray", dns_shunt = "chinadns-ng"})
o:depends({smartdns_dns_mode = "xray", dns_shunt = "smartdns"})
-o:depends("_node_sel_shunt", "1")
+--o:depends("_node_sel_shunt", "1")
o.validate = function(self, value, t)
if value and value == "1" then
local _dns_mode = s.fields["dns_mode"]:formvalue(t)
@@ -924,6 +948,10 @@ for k, v in pairs(nodes_table) do
end
end
-m:append(Template(appname .. "/global/footer"))
+local footer = Template(appname .. "/global/footer")
+footer.api = api
+footer.global_cfgid = global_cfgid
+footer.shunt_list = api.jsonc.stringify(shunt_list)
+m:append(footer)
return m
diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
index a6201bebe0..8f6bb76046 100644
--- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
+++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua
@@ -9,6 +9,11 @@ if not arg[1] or not m:get(arg[1]) then
luci.http.redirect(m.redirect)
end
+local header = Template(appname .. "/node_config/header")
+header.api = api
+header.section = arg[1]
+m:append(header)
+
m:append(Template(appname .. "/cbi/nodes_multivalue_com"))
m:append(Template(appname .. "/cbi/nodes_listvalue_com"))
@@ -18,7 +23,7 @@ s.dynamic = false
o = s:option(DummyValue, "passwall", " ")
o.rawhtml = true
-o.template = "passwall/node_list/link_share_man"
+o.template = "passwall/node_config/link_share_man"
o.value = arg[1]
o = s:option(Value, "remarks", translate("Node Remarks"))
@@ -55,35 +60,40 @@ o.write = function(self, section, value)
m:set(section, self.option, value)
end
+local fs = api.fs
+local types_dir = "/usr/lib/lua/luci/model/cbi/passwall/client/type/"
+s.val = {}
+s.val["type"] = m.uci:get(appname, arg[1], "type")
+s.val["protocol"] = m.uci:get(appname, arg[1], "protocol")
+
o = s:option(ListValue, "type", translate("Type"))
if api.is_finded("ipt2socks") then
- local function _n(name)
- return "socks_" .. name
- end
-
s.fields["type"]:value("Socks", translate("Socks"))
- o = s:option(ListValue, _n("del_protocol"), " ") --始终隐藏,用于删除 protocol
- o:depends({ [_n("__hide")] = "1" })
- o.rewrite_option = "protocol"
+ if s.val["type"] == "Socks" then
+ local function _n(name)
+ return "socks_" .. name
+ end
+ o = s:option(ListValue, _n("del_protocol"), " ") --始终隐藏,用于删除 protocol
+ o:depends({ [_n("__hide")] = "1" })
+ o.rewrite_option = "protocol"
+
+ o = s:option(Value, _n("address"), translate("Address (Support Domain Name)"))
- o = s:option(Value, _n("address"), translate("Address (Support Domain Name)"))
+ o = s:option(Value, _n("port"), translate("Port"))
+ o.datatype = "port"
- o = s:option(Value, _n("port"), translate("Port"))
- o.datatype = "port"
+ o = s:option(Value, _n("username"), translate("Username"))
- o = s:option(Value, _n("username"), translate("Username"))
+ o = s:option(Value, _n("password"), translate("Password"))
+ o.password = true
- o = s:option(Value, _n("password"), translate("Password"))
- o.password = true
+ api.luci_types(arg[1], m, s, "Socks", "socks_")
+ end
- api.luci_types(arg[1], m, s, "Socks", "socks_")
end
-local fs = api.fs
-local types_dir = "/usr/lib/lua/luci/model/cbi/passwall/client/type/"
-
local type_table = {}
for filename in fs.dir(types_dir) do
table.insert(type_table, filename)
@@ -95,4 +105,10 @@ for index, value in ipairs(type_table) do
setfenv(p_func, getfenv(1))(m, s)
end
+local footer = Template(appname .. "/node_config/footer")
+footer.api = api
+footer.section = arg[1]
+
+m:append(footer)
+
return m
diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/shunt_rules.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/shunt_rules.lua
index 764e0020a3..77b7275a9f 100644
--- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/shunt_rules.lua
+++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/shunt_rules.lua
@@ -138,7 +138,10 @@ end
source.write = dynamicList_write
+--[[
+-- Too low usage rate, hidden
sourcePort = s:option(Value, "sourcePort", translate("Source port"))
+]]--
port = s:option(Value, "port", translate("port"))
@@ -163,6 +166,11 @@ domain_list.validate = function(self, value)
flag = 0
elseif host:find("ext:") and host:find("ext:") == 1 then
flag = 0
+ elseif host:find("rule-set:", 1, true) == 1 or host:find("rs:") == 1 then
+ local w = host:sub(host:find(":") + 1, #host)
+ if w:find("local:") == 1 or w:find("remote:") == 1 then
+ flag = 0
+ end
elseif host:find("#") and host:find("#") == 1 then
flag = 0
end
@@ -174,13 +182,21 @@ domain_list.validate = function(self, value)
end
return value
end
-domain_list.description = "
s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "Default) has a separate switch that controls whether this rule uses the pre-proxy or not."))
- o:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true })
- o.template = appname .. "/cbi/nodes_listvalue"
- o.group = {}
- for k, v in pairs(socks_list) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ -- 检查fallback链,去掉会形成闭环的balancer节点
+ if is_balancer then
+ check_fallback_chain(arg[1])
end
- for k, v in pairs(balancers_table) do
+ for k, v in pairs(socks_list) do
o:value(v.id, v.remark)
o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
end
- for k, v in pairs(iface_table) do
+ for k, v in pairs(fallback_table) do
o:value(v.id, v.remark)
o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
end
@@ -241,104 +187,179 @@ if #nodes_table > 0 then
o:value(v.id, v.remark)
o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
end
-end
-m.uci:foreach(appname, "shunt_rules", function(e)
- if e[".name"] and e.remarks then
- o = s:option(ListValue, _n(e[".name"]), string.format('* %s', api.url("shunt_rules", e[".name"]), e.remarks))
- o:value("", translate("Close"))
- o:value("_default", translate("Default"))
- o:value("_direct", translate("Direct Connection"))
- o:value("_blackhole", translate("Blackhole"))
+
+ -- 探测地址
+ o = s:option(Flag, _n("useCustomProbeUrl"), translate("Use Custom Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL."))
+ o:depends({ [_n("protocol")] = "_balancing" })
+
+ o = s:option(Value, _n("probeUrl"), translate("Probe URL"))
+ o:depends({ [_n("useCustomProbeUrl")] = true })
+ o:value("https://cp.cloudflare.com/", "Cloudflare")
+ o:value("https://www.gstatic.com/generate_204", "Gstatic")
+ o:value("https://www.google.com/generate_204", "Google")
+ o:value("https://www.youtube.com/generate_204", "YouTube")
+ o:value("https://connect.rom.miui.com/generate_204", "MIUI (CN)")
+ o:value("https://connectivitycheck.platform.hicloud.com/generate_204", "HiCloud (CN)")
+ o.default = o.keylist[3]
+ o.description = translate("The URL used to detect the connection status.")
+
+ -- 探测间隔
+ o = s:option(Value, _n("probeInterval"), translate("Probe Interval"))
+ o:depends({ [_n("protocol")] = "_balancing" })
+ o.default = "1m"
+ o.placeholder = "1m"
+ o.description = translate("The interval between initiating probes.") .. "s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "Default) has a separate switch that controls whether this rule uses the pre-proxy or not."))
+ o:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true })
o.template = appname .. "/cbi/nodes_listvalue"
- o.group = {"","","",""}
+ o.group = {}
+ for k, v in pairs(socks_list) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(balancers_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(iface_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(nodes_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
- if #nodes_table > 0 then
- for k, v in pairs(socks_list) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- for k, v in pairs(balancers_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- for k, v in pairs(iface_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- local pt = s:option(ListValue, _n(e[".name"] .. "_proxy_tag"), string.format('* %s', e.remarks .. " " .. translate("Preproxy")))
- pt:value("", translate("Close"))
- pt:value("main", translate("Preproxy Node"))
- pt:depends("__hide__", "1")
- for k, v in pairs(nodes_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- if not api.is_local_ip(v.address) then --本地节点禁止使用前置
- pt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n(e[".name"])] = v.id })
+ o = s:option(Flag, _n("fakedns"), "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy."))
+ o:depends({ [_n("protocol")] = "_shunt" })
+ end
+ m.uci:foreach(appname, "shunt_rules", function(e)
+ if e[".name"] and e.remarks then
+ o = s:option(ListValue, _n(e[".name"]), string.format('* %s', api.url("shunt_rules", e[".name"]), e.remarks))
+ o:value("", translate("Close"))
+ o:value("_default", translate("Default"))
+ o:value("_direct", translate("Direct Connection"))
+ o:value("_blackhole", translate("Blackhole"))
+ o:depends({ [_n("protocol")] = "_shunt" })
+ o.template = appname .. "/cbi/nodes_listvalue"
+ o.group = {"","","",""}
+
+ if #nodes_table > 0 then
+ local pt = s:option(ListValue, _n(e[".name"] .. "_proxy_tag"), string.format('* %s', e.remarks .. " " .. translate("Preproxy")))
+ pt:value("", translate("Close"))
+ pt:value("main", translate("Preproxy Node"))
+ pt:depends("__hide__", "1")
+
+ local fakedns_tag = s:option(Flag, _n(e[".name"] .. "_fakedns"), string.format('* %s', e.remarks .. " " .. "FakeDNS"))
+
+ for k, v in pairs(socks_list) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = v.id })
+ end
+ for k, v in pairs(balancers_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(iface_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(nodes_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ if not api.is_local_ip(v.address) then --本地节点禁止使用前置
+ pt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n(e[".name"])] = v.id })
+ end
+ fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = v.id })
+ end
+ if default_node ~= "_direct" or default_node ~= "_blackhole" then
+ fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = "_default" })
end
end
end
- end
-end)
+ end)
-o = s:option(DummyValue, _n("shunt_tips"), " ")
-o.not_rewrite = true
-o.rawhtml = true
-o.cfgvalue = function(t, n)
- return string.format('%s', translate("No shunt rules? Click me to go to add."))
-end
-o:depends({ [_n("protocol")] = "_shunt" })
+ o = s:option(DummyValue, _n("shunt_tips"), " ")
+ o.not_rewrite = true
+ o.rawhtml = true
+ o.cfgvalue = function(t, n)
+ return string.format('%s', translate("No shunt rules? Click me to go to add."))
+ end
+ o:depends({ [_n("protocol")] = "_shunt" })
-local o = s:option(ListValue, _n("default_node"), string.format('* %s', translate("Default")))
-o:depends({ [_n("protocol")] = "_shunt" })
-o:value("_direct", translate("Direct Connection"))
-o:value("_blackhole", translate("Blackhole"))
-o.template = appname .. "/cbi/nodes_listvalue"
-o.group = {"",""}
+ local o = s:option(ListValue, _n("default_node"), string.format('* %s', translate("Default")))
+ o:depends({ [_n("protocol")] = "_shunt" })
+ o:value("_direct", translate("Direct Connection"))
+ o:value("_blackhole", translate("Blackhole"))
+ o.template = appname .. "/cbi/nodes_listvalue"
+ o.group = {"",""}
-if #nodes_table > 0 then
- for k, v in pairs(socks_list) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- for k, v in pairs(balancers_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- for k, v in pairs(iface_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- local dpt = s:option(ListValue, _n("default_proxy_tag"), string.format('* %s', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node."))
- dpt:value("", translate("Close"))
- dpt:value("main", translate("Preproxy Node"))
- dpt:depends("__hide__", "1")
- for k, v in pairs(nodes_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- if not api.is_local_ip(v.address) then
- dpt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n("default_node")] = v.id })
+ if #nodes_table > 0 then
+ for k, v in pairs(socks_list) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(balancers_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(iface_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ local dpt = s:option(ListValue, _n("default_proxy_tag"), string.format('* %s', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node."))
+ dpt:value("", translate("Close"))
+ dpt:value("main", translate("Preproxy Node"))
+ dpt:depends("__hide__", "1")
+ for k, v in pairs(nodes_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ if not api.is_local_ip(v.address) then
+ dpt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n("default_node")] = v.id })
+ end
end
end
-end
-o = s:option(ListValue, _n("domainStrategy"), translate("Domain Strategy"))
-o:value("AsIs")
-o:value("IPIfNonMatch")
-o:value("IPOnDemand")
-o.default = "IPOnDemand"
-o.description = "s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "Default) has a separate switch that controls whether this rule uses the pre-proxy or not."))
- o:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true })
- o.template = appname .. "/cbi/nodes_listvalue"
- o.group = {}
- for k, v in pairs(socks_list) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- for k, v in pairs(urltest_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- for k, v in pairs(iface_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- for k, v in pairs(nodes_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
-end
-m.uci:foreach(appname, "shunt_rules", function(e)
- if e[".name"] and e.remarks then
- o = s:option(ListValue, _n(e[".name"]), string.format('* %s', api.url("shunt_rules", e[".name"]), e.remarks))
- o:value("", translate("Close"))
- o:value("_default", translate("Default"))
- o:value("_direct", translate("Direct Connection"))
- o:value("_blackhole", translate("Blackhole"))
+if s.val["protocol"] == "_shunt" then -- [[ 分流模块 Start ]]
+ local default_node = m.uci:get(appname, arg[1], "default_node") or "_direct"
+ if #nodes_table > 0 then
+ o = s:option(Flag, _n("preproxy_enabled"), translate("Preproxy"))
o:depends({ [_n("protocol")] = "_shunt" })
+
+ o = s:option(ListValue, _n("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({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true })
o.template = appname .. "/cbi/nodes_listvalue"
- o.group = {"","","",""}
+ o.group = {}
+ for k, v in pairs(socks_list) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(urltest_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(iface_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(nodes_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
- if #nodes_table > 0 then
- for k, v in pairs(socks_list) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- for k, v in pairs(urltest_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- for k, v in pairs(iface_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- local pt = s:option(ListValue, _n(e[".name"] .. "_proxy_tag"), string.format('* %s', e.remarks .. " " .. translate("Preproxy")))
- pt:value("", translate("Close"))
- pt:value("main", translate("Preproxy Node"))
- pt:depends("__hide__", "1")
- for k, v in pairs(nodes_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- if not api.is_local_ip(v.address) then --本地节点禁止使用前置
- pt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n(e[".name"])] = v.id })
+ o = s:option(Flag, _n("fakedns"), "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy."))
+ o:depends({ [_n("protocol")] = "_shunt" })
+ end
+ m.uci:foreach(appname, "shunt_rules", function(e)
+ if e[".name"] and e.remarks then
+ o = s:option(ListValue, _n(e[".name"]), string.format('* %s', api.url("shunt_rules", e[".name"]), e.remarks))
+ o:value("", translate("Close"))
+ o:value("_default", translate("Default"))
+ o:value("_direct", translate("Direct Connection"))
+ o:value("_blackhole", translate("Blackhole"))
+ o:depends({ [_n("protocol")] = "_shunt" })
+ o.template = appname .. "/cbi/nodes_listvalue"
+ o.group = {"","","",""}
+
+ if #nodes_table > 0 then
+ local pt = s:option(ListValue, _n(e[".name"] .. "_proxy_tag"), string.format('* %s', e.remarks .. " " .. translate("Preproxy")))
+ pt:value("", translate("Close"))
+ pt:value("main", translate("Preproxy Node"))
+ pt:depends("__hide__", "1")
+
+ local fakedns_tag = s:option(Flag, _n(e[".name"] .. "_fakedns"), string.format('* %s', e.remarks .. " " .. "FakeDNS"))
+
+ for k, v in pairs(socks_list) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = v.id })
+ end
+ for k, v in pairs(urltest_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(iface_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(nodes_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ if not api.is_local_ip(v.address) then --本地节点禁止使用前置
+ pt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n(e[".name"])] = v.id })
+ end
+ fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = v.id })
+ end
+ if default_node ~= "_direct" or default_node ~= "_blackhole" then
+ fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = "_default" })
end
end
end
- end
-end)
+ end)
-o = s:option(DummyValue, _n("shunt_tips"), " ")
-o.not_rewrite = true
-o.rawhtml = true
-o.cfgvalue = function(t, n)
- return string.format('%s', translate("No shunt rules? Click me to go to add."))
-end
-o:depends({ [_n("protocol")] = "_shunt" })
+ o = s:option(DummyValue, _n("shunt_tips"), " ")
+ o.not_rewrite = true
+ o.rawhtml = true
+ o.cfgvalue = function(t, n)
+ return string.format('%s', translate("No shunt rules? Click me to go to add."))
+ end
+ o:depends({ [_n("protocol")] = "_shunt" })
-local o = s:option(ListValue, _n("default_node"), string.format('* %s', translate("Default")))
-o:depends({ [_n("protocol")] = "_shunt" })
-o:value("_direct", translate("Direct Connection"))
-o:value("_blackhole", translate("Blackhole"))
-o.template = appname .. "/cbi/nodes_listvalue"
-o.group = {"",""}
+ local o = s:option(ListValue, _n("default_node"), string.format('* %s', translate("Default")))
+ o:depends({ [_n("protocol")] = "_shunt" })
+ o:value("_direct", translate("Direct Connection"))
+ o:value("_blackhole", translate("Blackhole"))
+ o.template = appname .. "/cbi/nodes_listvalue"
+ o.group = {"",""}
-if #nodes_table > 0 then
- for k, v in pairs(socks_list) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- for k, v in pairs(urltest_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- for k, v in pairs(iface_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- end
- local dpt = s:option(ListValue, _n("default_proxy_tag"), string.format('* %s', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node."))
- dpt:value("", translate("Close"))
- dpt:value("main", translate("Preproxy Node"))
- dpt:depends("__hide__", "1")
- for k, v in pairs(nodes_table) do
- o:value(v.id, v.remark)
- o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
- if not api.is_local_ip(v.address) then
- dpt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n("default_node")] = v.id })
+ if #nodes_table > 0 then
+ for k, v in pairs(socks_list) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(urltest_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ for k, v in pairs(iface_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ end
+ local dpt = s:option(ListValue, _n("default_proxy_tag"), string.format('* %s', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node."))
+ dpt:value("", translate("Close"))
+ dpt:value("main", translate("Preproxy Node"))
+ dpt:depends("__hide__", "1")
+ for k, v in pairs(nodes_table) do
+ o:value(v.id, v.remark)
+ o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
+ if not api.is_local_ip(v.address) then
+ dpt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n("default_node")] = v.id })
+ end
end
end
-end
+end -- [[ 分流模块 End ]]
--- [[ 分流模块 End ]]
+if s.val["protocol"] == "_iface" then -- [[ 自定义接口 Start ]]
+ o = s:option(Value, _n("iface"), translate("Interface"))
+ o.default = "eth1"
+ o:depends({ [_n("protocol")] = "_iface" })
+end
o = s:option(Value, _n("address"), translate("Address (Support Domain Name)"))
diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ss-rust.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ss-rust.lua
index 04b8686ce5..feb15c029b 100644
--- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ss-rust.lua
+++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ss-rust.lua
@@ -8,6 +8,14 @@ end
local type_name = "SS-Rust"
+-- [[ Shadowsocks Rust ]]
+
+s.fields["type"]:value(type_name, "Shadowsocks Rust")
+
+if s.val["type"] ~= type_name then
+ return
+end
+
local option_prefix = "ssrust_"
local function _n(name)
@@ -20,10 +28,6 @@ local ssrust_encrypt_method_list = {
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
}
--- [[ Shadowsocks Rust ]]
-
-s.fields["type"]:value(type_name, translate("Shadowsocks Rust"))
-
o = s:option(ListValue, _n("del_protocol")) --始终隐藏,用于删除 protocol
o:depends({ [_n("__hide")] = "1" })
o.rewrite_option = "protocol"
diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ss.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ss.lua
index fba5cd564c..1b28c488bc 100644
--- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ss.lua
+++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ss.lua
@@ -8,6 +8,14 @@ end
local type_name = "SS"
+-- [[ Shadowsocks Libev ]]
+
+s.fields["type"]:value(type_name, "Shadowsocks Libev")
+
+if s.val["type"] ~= type_name then
+ return
+end
+
local option_prefix = "ss_"
local function _n(name)
@@ -21,10 +29,6 @@ local ss_encrypt_method_list = {
"xchacha20-ietf-poly1305"
}
--- [[ Shadowsocks Libev ]]
-
-s.fields["type"]:value(type_name, translate("Shadowsocks Libev"))
-
o = s:option(ListValue, _n("del_protocol")) --始终隐藏,用于删除 protocol
o:depends({ [_n("__hide")] = "1" })
o.rewrite_option = "protocol"
diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ssr.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ssr.lua
index 67629e6334..c8f5ac6f3c 100644
--- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ssr.lua
+++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ssr.lua
@@ -8,6 +8,14 @@ end
local type_name = "SSR"
+-- [[ ShadowsocksR Libev ]]
+
+s.fields["type"]:value(type_name, "ShadowsocksR Libev")
+
+if s.val["type"] ~= type_name then
+ return
+end
+
local option_prefix = "ssr_"
local function _n(name)
@@ -33,10 +41,6 @@ local ssr_obfs_list = {
"tls1.0_session_auth", "tls1.2_ticket_auth"
}
--- [[ ShadowsocksR Libev ]]
-
-s.fields["type"]:value(type_name, translate("ShadowsocksR Libev"))
-
o = s:option(ListValue, _n("del_protocol")) --始终隐藏,用于删除 protocol
o:depends({ [_n("__hide")] = "1" })
o.rewrite_option = "protocol"
diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/trojan-plus.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/trojan-plus.lua
index 016ae34ad4..22dd8e24ae 100644
--- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/trojan-plus.lua
+++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/trojan-plus.lua
@@ -8,16 +8,20 @@ end
local type_name = "Trojan-Plus"
+-- [[ Trojan Plus ]]
+
+s.fields["type"]:value(type_name, "Trojan-Plus")
+
+if s.val["type"] ~= type_name then
+ return
+end
+
local option_prefix = "trojan_plus_"
local function _n(name)
return option_prefix .. name
end
--- [[ Trojan Plus ]]
-
-s.fields["type"]:value(type_name, "Trojan-Plus")
-
o = s:option(ListValue, _n("del_protocol")) --始终隐藏,用于删除 protocol
o:depends({ [_n("__hide")] = "1" })
o.rewrite_option = "protocol"
diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/tuic.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/tuic.lua
index cf748a3d4f..0d882fb1e6 100644
--- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/tuic.lua
+++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/tuic.lua
@@ -8,16 +8,20 @@ end
local type_name = "TUIC"
+-- [[ TUIC ]]
+
+s.fields["type"]:value(type_name, "TUIC")
+
+if s.val["type"] ~= type_name then
+ return
+end
+
local option_prefix = "tuic_"
local function _n(name)
return option_prefix .. name
end
--- [[ TUIC ]]
-
-s.fields["type"]:value(type_name, translate("TUIC"))
-
o = s:option(ListValue, _n("del_protocol")) --始终隐藏,用于删除 protocol
o:depends({ [_n("__hide")] = "1" })
o.rewrite_option = "protocol"
diff --git a/applications/luci-app-passwall/luasrc/passwall/api.lua b/applications/luci-app-passwall/luasrc/passwall/api.lua
index a878d8f892..05c39fa611 100644
--- a/applications/luci-app-passwall/luasrc/passwall/api.lua
+++ b/applications/luci-app-passwall/luasrc/passwall/api.lua
@@ -21,6 +21,8 @@ LOG_FILE = "/tmp/log/" .. appname .. ".log"
TMP_PATH = "/tmp/etc/" .. appname
TMP_IFACE_PATH = TMP_PATH .. "/iface"
+NEW_PORT = nil
+
function log(...)
local result = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ")
local f, err = io.open(LOG_FILE, "a")
@@ -94,6 +96,16 @@ function get_cache_var(key)
return val
end
+function get_new_port()
+ local cmd_format = ". /usr/share/passwall/utils.sh ; echo -n $(get_new_port %s tcp,udp)"
+ local set_port = 0
+ if NEW_PORT and tonumber(NEW_PORT) then
+ set_port = tonumber(NEW_PORT) + 1
+ end
+ NEW_PORT = tonumber(sys.exec(string.format(cmd_format, set_port == 0 and "auto" or set_port)))
+ return NEW_PORT
+end
+
function exec_call(cmd)
local process = io.popen(cmd .. '; echo -e "\n$?"')
local lines = {}
diff --git a/applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua
index 8cdac56960..9f18299e8c 100644
--- a/applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua
+++ b/applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua
@@ -11,66 +11,74 @@ local local_version = api.get_app_version("sing-box"):match("[^v]+")
local version_ge_1_11_0 = api.compare_versions(local_version, ">=", "1.11.0")
local version_ge_1_12_0 = api.compare_versions(local_version, ">=", "1.12.0")
-local geosite_all_tag = {}
-local geoip_all_tag = {}
-local srss_path = "/tmp/etc/" .. appname .."_tmp/srss/"
+local GEO_VAR = {
+ OK = nil,
+ DIR = nil,
+ SITE_PATH = nil,
+ IP_PATH = nil,
+ SITE_TAGS = {},
+ IP_TAGS = {},
+ TO_SRS_PATH = "/tmp/etc/" .. appname .."_tmp/singbox_srss/"
+}
+
+function check_geoview()
+ if not GEO_VAR.OK then
+ -- Only get once
+ GEO_VAR.OK = (api.finded_com("geoview") and api.compare_versions(api.get_app_version("geoview"), ">=", "0.1.10")) and 1 or 0
+ end
+ if GEO_VAR.OK == 0 then
+ api.log("!!!注意:缺少 Geoview 组件或版本过低,Sing-Box 分流无法启用!")
+ else
+ GEO_VAR.DIR = GEO_VAR.DIR or (uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"):match("^(.*)/")
+ GEO_VAR.SITE_PATH = GEO_VAR.SITE_PATH or (GEO_VAR.DIR .. "/geosite.dat")
+ GEO_VAR.IP_PATH = GEO_VAR.IP_PATH or (GEO_VAR.DIR .. "/geoip.dat")
+ if not fs.access(GEO_VAR.TO_SRS_PATH) then
+ fs.mkdir(GEO_VAR.TO_SRS_PATH)
+ end
+ end
+ return GEO_VAR.OK
+end
-local function convert_geofile()
- if api.compare_versions(local_version, "<", "1.8.0") then
- api.log("!!!注意:Sing-Box 版本低,Sing-Box 分流无法启用!请在[组件更新]中更新。")
+function geo_convert_srs(var)
+ if check_geoview() ~= 1 then
return
end
- local geo_dir = (uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"):match("^(.*)/")
- local geosite_path = geo_dir .. "/geosite.dat"
- local geoip_path = geo_dir .. "/geoip.dat"
- if not api.finded_com("geoview") then
- api.log("!!!注意:缺少 Geoview 组件,Sing-Box 分流无法启用!请在[组件更新]中更新。")
- return
- else
- if api.compare_versions(api.get_app_version("geoview"), "<", "0.1.10") then
- api.log("!!!注意:Geoview 组件版本低,Sing-Box 分流无法启用!请在[组件更新]中更新。")
- return
+ local geo_path = var["-geo_path"]
+ local prefix = var["-prefix"]
+ local rule_name = var["-rule_name"]
+ local output_srs_file = GEO_VAR.TO_SRS_PATH .. prefix .. "-" .. rule_name .. ".srs"
+ if not fs.access(output_srs_file) then
+ local cmd = string.format("geoview -type %s -action convert -input '%s' -list '%s' -output '%s' -lowmem=true",
+ prefix, geo_path, rule_name, output_srs_file)
+ sys.call(cmd)
+ local status = fs.access(output_srs_file) and "success." or "failed!"
+ if status == "failed!" then
+ api.log(string.format(" - %s:%s 转换为srs格式:%s", prefix, rule_name, status))
end
end
- if not fs.access(srss_path) then
- fs.mkdir(srss_path)
+end
+
+local function convert_geofile()
+ if check_geoview() ~= 1 then
+ return
end
local function convert(file_path, prefix, tags)
if next(tags) and fs.access(file_path) then
- local md5_file = srss_path .. prefix .. ".dat.md5"
+ local md5_file = GEO_VAR.TO_SRS_PATH .. prefix .. ".dat.md5"
local new_md5 = sys.exec("md5sum " .. file_path .. " 2>/dev/null | awk '{print $1}'"):gsub("\n", "")
local old_md5 = sys.exec("[ -f " .. md5_file .. " ] && head -n 1 " .. md5_file .. " | tr -d ' \t\n' || echo ''")
if new_md5 ~= "" and new_md5 ~= old_md5 then
sys.call("printf '%s' " .. new_md5 .. " > " .. md5_file)
- sys.call("rm -rf " .. srss_path .. prefix .. "-*.srs" )
+ sys.call("rm -rf " .. GEO_VAR.TO_SRS_PATH .. prefix .. "-*.srs" )
end
for k in pairs(tags) do
- local srs_file = srss_path .. prefix .. "-" .. k .. ".srs"
- if not fs.access(srs_file) then
- local cmd = string.format("geoview -type %s -action convert -input '%s' -list '%s' -output '%s' -lowmem=true",
- prefix, file_path, k, srs_file)
- sys.exec(cmd)
- --local status = fs.access(srs_file) and "成功。" or "失败!"
- --api.log(string.format(" - 转换 %s:%s ... %s", prefix, k, status))
- end
+ geo_convert_srs({["-geo_path"] = file_path, ["-prefix"] = prefix, ["-rule_name"] = k})
end
end
end
--api.log("Sing-Box 规则集转换:")
- convert(geosite_path, "geosite", geosite_all_tag)
- convert(geoip_path, "geoip", geoip_all_tag)
-end
-
-local new_port
-
-local function get_new_port()
- local cmd_format = ". /usr/share/passwall/utils.sh ; echo -n $(get_new_port %s tcp)"
- local set_port = 0
- if new_port and tonumber(new_port) then
- set_port = tonumber(new_port) + 1
- end
- new_port = tonumber(sys.exec(string.format(cmd_format, set_port == 0 and "auto" or set_port)))
- return new_port
+ convert(GEO_VAR.SITE_PATH, "geosite", GEO_VAR.SITE_TAGS)
+ convert(GEO_VAR.IP_PATH, "geoip", GEO_VAR.IP_TAGS)
end
function gen_outbound(flag, node, tag, proxy_table)
@@ -94,7 +102,7 @@ function gen_outbound(flag, node, tag, proxy_table)
if node.type ~= "sing-box" then
local relay_port = node.port
- new_port = get_new_port()
+ local new_port = api.get_new_port()
local config_file = string.format("%s_%s_%s.json", flag, tag, new_port)
if tag and node_id and not tag:find(node_id) then
config_file = string.format("%s_%s_%s_%s.json", flag, tag, node_id, new_port)
@@ -925,6 +933,7 @@ function gen_config(var)
local dns = nil
local inbounds = {}
local outbounds = {}
+ local rule_set_table = {}
local COMMON = {}
local singbox_settings = uci:get_all(appname, "@global_singbox[0]") or {}
@@ -935,6 +944,59 @@ function gen_config(var)
local experimental = nil
+ function add_rule_set(tab)
+ if tab and next(tab) and tab.tag and not rule_set_table[tab.tag]then
+ rule_set_table[tab.tag] = tab
+ end
+ end
+
+ function parse_rule_set(w, rs)
+ -- Format: remote:https://raw.githubusercontent.com/lyc8503/sing-box-rules/rule-set-geosite/geosite-netflix.srs'
+ -- Format: local:/usr/share/sing-box/geosite-netflix.srs'
+ local result = nil
+ if w and #w > 0 then
+ if w:find("local:") == 1 or w:find("remote:") == 1 then
+ local _type = w:sub(1, w:find(":") - 1) -- "local" or "remote"
+ w = w:sub(w:find(":") + 1, #w)
+ local format = nil
+ local filename = w:sub(-w:reverse():find("/") + 1) -- geosite-netflix.srs
+ local suffix = ""
+ local find_doc = filename:reverse():find("%.")
+ if find_doc then
+ suffix = filename:sub(-find_doc + 1) -- "srs" or "json"
+ end
+ if suffix == "srs" then
+ format = "binary"
+ elseif suffix == "json" then
+ format = "source"
+ end
+ if format then
+ local rule_set_tag = filename:sub(1, filename:find("%.") - 1) --geosite-netflix
+ if rule_set_tag and #rule_set_tag > 0 then
+ if rs then
+ rule_set_tag = "rs_" .. rule_set_tag
+ end
+ result = {
+ type = _type,
+ tag = rule_set_tag,
+ format = format,
+ path = _type == "local" and w or nil,
+ url = _type == "remote" and w or nil,
+ --download_detour = _type == "remote" and "",
+ --update_interval = _type == "remote" and "",
+ }
+ end
+ end
+ end
+ end
+ return result
+ end
+
+ function geo_rule_set(prefix, rule_name)
+ local output_srs_file = "local:" .. GEO_VAR.TO_SRS_PATH .. prefix .. "-" .. rule_name .. ".srs"
+ return parse_rule_set(output_srs_file)
+ end
+
if node_id then
local node = uci:get_all(appname, node_id)
if node then
@@ -1154,6 +1216,8 @@ function gen_config(var)
local preproxy_tag = preproxy_rule_name
local preproxy_node_id = preproxy_rule_name and node["main_node"] or nil
+ inner_fakedns = node.fakedns or "0"
+
local function gen_shunt_node(rule_name, _node_id)
if not rule_name then return nil, nil end
if not _node_id then _node_id = node[rule_name] end
@@ -1205,7 +1269,7 @@ function gen_config(var)
pre_proxy = true
end
if pre_proxy then
- new_port = get_new_port()
+ local new_port = api.get_new_port()
table.insert(inbounds, {
type = "direct",
tag = "proxy_" .. rule_name,
@@ -1344,6 +1408,8 @@ function gen_config(var)
if is_private or #source_ip_cidr > 0 then rule.rule_set_ip_cidr_match_source = true end
end
+ --[[
+ -- Too low usage rate, hidden
if e.sourcePort then
local source_port = {}
local source_port_range = {}
@@ -1357,6 +1423,7 @@ function gen_config(var)
rule.source_port = #source_port > 0 and source_port or nil
rule.source_port_range = #source_port_range > 0 and source_port_range or nil
end
+ ]]--
if e.port then
local port = {}
@@ -1372,7 +1439,7 @@ function gen_config(var)
rule.port_range = #port_range > 0 and port_range or nil
end
- local rule_set_tag = {}
+ local rule_set = {}
if e.domain_list then
local domain_table = {
@@ -1382,20 +1449,34 @@ function gen_config(var)
domain_keyword = {},
domain_regex = {},
rule_set = {},
+ fakedns = nil,
+ invert = e.invert == "1" and true or nil
}
string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
if w:find("geosite:") == 1 then
local _geosite = w:sub(1 + #"geosite:") --适配srs
- geosite_all_tag[_geosite] = true
- table.insert(rule_set_tag, "geosite-" .. _geosite)
- table.insert(domain_table.rule_set, "geosite-" .. _geosite)
+ local t = geo_rule_set("geosite", _geosite)
+ if t then
+ GEO_VAR.SITE_TAGS[_geosite] = true
+ add_rule_set(t)
+ table.insert(rule_set, t.tag)
+ table.insert(domain_table.rule_set, t.tag)
+ end
elseif w:find("regexp:") == 1 then
table.insert(domain_table.domain_regex, w:sub(1 + #"regexp:"))
elseif w:find("full:") == 1 then
table.insert(domain_table.domain, w:sub(1 + #"full:"))
elseif w:find("domain:") == 1 then
table.insert(domain_table.domain_suffix, w:sub(1 + #"domain:"))
+ elseif w:find("rule-set:", 1, true) == 1 or w:find("rs:") == 1 then
+ w = w:sub(w:find(":") + 1, #w)
+ local t = parse_rule_set(w, true)
+ if t then
+ add_rule_set(t)
+ table.insert(rule_set, t.tag)
+ table.insert(domain_table.rule_set, t.tag)
+ end
else
table.insert(domain_table.domain_keyword, w)
end
@@ -1404,6 +1485,10 @@ function gen_config(var)
rule.domain_suffix = #domain_table.domain_suffix > 0 and domain_table.domain_suffix or nil
rule.domain_keyword = #domain_table.domain_keyword > 0 and domain_table.domain_keyword or nil
rule.domain_regex = #domain_table.domain_regex > 0 and domain_table.domain_regex or nil
+ rule.rule_set = #domain_table.rule_set > 0 and domain_table.rule_set or nil
+ if inner_fakedns == "1" and node[e[".name"] .. "_fakedns"] == "1" then
+ domain_table.fakedns = true
+ end
if outboundTag then
table.insert(dns_domain_rules, api.clone(domain_table))
@@ -1420,8 +1505,19 @@ function gen_config(var)
if _geoip == "private" then
is_private = true
else
- geoip_all_tag[_geoip] = true
- table.insert(rule_set_tag, "geoip-" .. _geoip)
+ local t = geo_rule_set("geoip", _geoip)
+ if t then
+ GEO_VAR.IP_TAGS[_geoip] = true
+ add_rule_set(t)
+ table.insert(rule_set, t.tag)
+ end
+ end
+ elseif w:find("rule-set:", 1, true) == 1 or w:find("rs:") == 1 then
+ w = w:sub(w:find(":") + 1, #w)
+ local t = parse_rule_set(w, true)
+ if t then
+ add_rule_set(t)
+ table.insert(rule_set, t.tag)
end
else
table.insert(ip_cidr, w)
@@ -1432,7 +1528,8 @@ function gen_config(var)
rule.ip_cidr = #ip_cidr > 0 and ip_cidr or nil
end
- rule.rule_set = #rule_set_tag > 0 and rule_set_tag or nil --适配srs
+ rule.rule_set = #rule_set > 0 and rule_set or nil --适配srs
+ rule.invert = e.invert == "1" and true or nil
table.insert(rules, rule)
end
@@ -1441,34 +1538,6 @@ function gen_config(var)
for index, value in ipairs(rules) do
table.insert(route.rules, rules[index])
end
-
- local rule_set = {} --适配srs
- if next(geosite_all_tag) then
- for k,v in pairs(geosite_all_tag) do
- local srs_file = srss_path .. "geosite-" .. k ..".srs"
- local _rule_set = {
- tag = "geosite-" .. k,
- type = "local",
- format = "binary",
- path = srs_file
- }
- table.insert(rule_set, _rule_set)
- end
- end
- if next(geoip_all_tag) then
- for k,v in pairs(geoip_all_tag) do
- local srs_file = srss_path .. "geoip-" .. k ..".srs"
- local _rule_set = {
- tag = "geoip-" .. k,
- type = "local",
- format = "binary",
- path = srs_file
- }
- table.insert(rule_set, _rule_set)
- end
- end
- route.rule_set = #rule_set >0 and rule_set or nil
-
elseif node.protocol == "_urltest" then
if node.urltest_node then
COMMON.default_outbound_tag = gen_urltest(node)
@@ -1571,7 +1640,7 @@ function gen_config(var)
table.insert(dns.servers, remote_server)
end
- if remote_dns_fake then
+ if remote_dns_fake or inner_fakedns == "1" then
dns.fakeip = {
enabled = true,
inet4_range = "198.18.0.0/15",
@@ -1637,7 +1706,7 @@ function gen_config(var)
table.insert(dns.servers, remote_server)
end
- if remote_dns_fake then
+ if remote_dns_fake or inner_fakedns == "1" then
table.insert(dns.servers, {
tag = fakedns_tag,
type = "fakeip",
@@ -1755,8 +1824,9 @@ function gen_config(var)
domain_suffix = (value.domain_suffix and #value.domain_suffix > 0) and value.domain_suffix or nil,
domain_keyword = (value.domain_keyword and #value.domain_keyword > 0) and value.domain_keyword or nil,
domain_regex = (value.domain_regex and #value.domain_regex > 0) and value.domain_regex or nil,
- rule_set = (value.rule_set and #value.rule_set > 0) and value.rule_set or nil, --适配srs
+ rule_set = (value.rule_set and #value.rule_set > 0) and value.rule_set or nil, --适配srs
disable_cache = false,
+ invert = value.invert,
strategy = (version_ge_1_12_0 and value.outboundTag == "direct") and direct_strategy or nil --Migrate to 1.12 DNS
}
if version_ge_1_12_0 and value.outboundTag == "block" then --Migrate to 1.12 DNS
@@ -1778,7 +1848,7 @@ function gen_config(var)
table.insert(dns.servers, remote_shunt_server)
dns_rule.server = remote_shunt_server.tag
end
- if remote_dns_fake then
+ if value.fakedns then
local fakedns_dns_rule = api.clone(dns_rule)
fakedns_dns_rule.query_type = {
"A", "AAAA"
@@ -1813,6 +1883,13 @@ function gen_config(var)
})
end
+ if next(rule_set_table) then
+ route.rule_set = {}
+ for k, v in pairs(rule_set_table) do
+ table.insert(route.rule_set, v)
+ end
+ end
+
if inbounds or outbounds then
local config = {
log = {
@@ -2053,12 +2130,13 @@ end
_G.gen_config = gen_config
_G.gen_proto_config = gen_proto_config
+_G.geo_convert_srs = geo_convert_srs
if arg[1] then
local func =_G[arg[1]]
if func then
print(func(api.get_function_args(arg)))
- if (next(geosite_all_tag) or next(geoip_all_tag)) and not no_run then
+ if (next(GEO_VAR.SITE_TAGS) or next(GEO_VAR.IP_TAGS)) and not no_run then
convert_geofile()
end
end
diff --git a/applications/luci-app-passwall/luasrc/passwall/util_xray.lua b/applications/luci-app-passwall/luasrc/passwall/util_xray.lua
index 7c9ae0ad59..a09af5d945 100644
--- a/applications/luci-app-passwall/luasrc/passwall/util_xray.lua
+++ b/applications/luci-app-passwall/luasrc/passwall/util_xray.lua
@@ -6,18 +6,6 @@ local jsonc = api.jsonc
local appname = "passwall"
local fs = api.fs
-local new_port
-
-local function get_new_port()
- local cmd_format = ". /usr/share/passwall/utils.sh ; echo -n $(get_new_port %s tcp)"
- local set_port = 0
- if new_port and tonumber(new_port) then
- set_port = tonumber(new_port) + 1
- end
- new_port = tonumber(sys.exec(string.format(cmd_format, set_port == 0 and "auto" or set_port)))
- return new_port
-end
-
local function get_noise_packets()
local noises = {}
uci:foreach(appname, "xray_noise_packets", function(n)
@@ -73,7 +61,7 @@ function gen_outbound(flag, node, tag, proxy_table)
node.transport = "tcp"
else
local relay_port = node.port
- new_port = get_new_port()
+ local new_port = api.get_new_port()
local config_file = string.format("%s_%s_%s.json", flag, tag, new_port)
if tag and node_id and not tag:find(node_id) then
config_file = string.format("%s_%s_%s_%s.json", flag, tag, node_id, new_port)
@@ -273,7 +261,7 @@ function gen_outbound(flag, node, tag, proxy_table)
port = string.gsub(node.hysteria2_hop, ":", "-"),
interval = (function()
local v = tonumber((node.hysteria2_hop_interval or "30s"):match("^%d+"))
- return (v and v >= 5) and (v .. "s") or "30s"
+ return (v and v >= 5) and v or 30
end)()
} or nil,
maxIdleTimeout = (function()
@@ -731,50 +719,6 @@ function gen_config(var)
table.insert(inbounds, inbound)
end
- if tcp_redir_port or udp_redir_port then
- local inbound = {
- protocol = "dokodemo-door",
- settings = {network = "tcp,udp", followRedirect = true},
- streamSettings = {sockopt = {tproxy = "tproxy"}},
- sniffing = {
- enabled = xray_settings.sniffing_override_dest == "1" or node.protocol == "_shunt"
- }
- }
- if inbound.sniffing.enabled == true then
- inbound.sniffing.destOverride = {"http", "tls", "quic"}
- inbound.sniffing.metadataOnly = false
- inbound.sniffing.routeOnly = xray_settings.sniffing_override_dest ~= "1" or nil
- inbound.sniffing.domainsExcluded = xray_settings.sniffing_override_dest == "1" and get_domain_excluded() or nil
- end
- if remote_dns_fake then
- inbound.sniffing.enabled = true
- if not inbound.sniffing.destOverride then
- inbound.sniffing.destOverride = {"fakedns"}
- inbound.sniffing.metadataOnly = true
- else
- table.insert(inbound.sniffing.destOverride, "fakedns")
- inbound.sniffing.metadataOnly = false
- end
- end
-
- if tcp_redir_port then
- local tcp_inbound = api.clone(inbound)
- tcp_inbound.tag = "tcp_redir"
- tcp_inbound.settings.network = "tcp"
- tcp_inbound.port = tonumber(tcp_redir_port)
- tcp_inbound.streamSettings.sockopt.tproxy = tcp_proxy_way
- table.insert(inbounds, tcp_inbound)
- end
-
- if udp_redir_port then
- local udp_inbound = api.clone(inbound)
- udp_inbound.tag = "udp_redir"
- udp_inbound.settings.network = "udp"
- udp_inbound.port = tonumber(udp_redir_port)
- table.insert(inbounds, udp_inbound)
- end
- end
-
local function gen_loopback(outbound_tag, loopback_dst)
if not outbound_tag or outbound_tag == "" then return nil end
local inbound_tag = loopback_dst and "lo-to-" .. loopback_dst or outbound_tag .. "-lo"
@@ -993,6 +937,8 @@ function gen_config(var)
local preproxy_outbound_tag, preproxy_balancer_tag
local preproxy_nodes
+ inner_fakedns = node.fakedns or "0"
+
local function gen_shunt_node(rule_name, _node_id)
if not rule_name then return nil, nil end
if not _node_id then
@@ -1047,7 +993,7 @@ function gen_config(var)
end
--new outbound
if use_proxy and _node.type ~= "Xray" then
- new_port = get_new_port()
+ local new_port = api.get_new_port()
table.insert(inbounds, {
tag = "proxy_" .. rule_name,
listen = "127.0.0.1",
@@ -1193,13 +1139,18 @@ function gen_config(var)
outboundTag = outbound_tag,
balancerTag = balancer_tag,
domain = {},
+ fakedns = nil,
}
domains = {}
string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
+ if w:find("rule-set:", 1, true) == 1 or w:find("rs:") == 1 then return end
table.insert(domains, w)
table.insert(domain_table.domain, w)
end)
+ if inner_fakedns == "1" and node[e[".name"] .. "_fakedns"] == "1" and #domains > 0 then
+ domain_table.fakedns = true
+ end
if outbound_tag or balancer_tag then
table.insert(dns_domain_rules, api.clone(domain_table))
end
@@ -1210,6 +1161,7 @@ function gen_config(var)
ip = {}
string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
+ if w:find("rule-set:", 1, true) == 1 or w:find("rs:") == 1 then return end
table.insert(ip, w)
end)
if #ip == 0 then ip = nil end
@@ -1228,7 +1180,7 @@ function gen_config(var)
balancerTag = balancer_tag,
network = e["network"] or "tcp,udp",
source = source,
- sourcePort = e["sourcePort"] ~= "" and e["sourcePort"] or nil,
+ --sourcePort = e["sourcePort"] ~= "" and e["sourcePort"] or nil,
port = e["port"] ~= "" and e["port"] or nil,
protocol = protocols
}
@@ -1320,6 +1272,50 @@ function gen_config(var)
network = "tcp,udp"
})
end
+
+ if tcp_redir_port or udp_redir_port then
+ local inbound = {
+ protocol = "dokodemo-door",
+ settings = {network = "tcp,udp", followRedirect = true},
+ streamSettings = {sockopt = {tproxy = "tproxy"}},
+ sniffing = {
+ enabled = xray_settings.sniffing_override_dest == "1" or node.protocol == "_shunt"
+ }
+ }
+ if inbound.sniffing.enabled == true then
+ inbound.sniffing.destOverride = {"http", "tls", "quic"}
+ inbound.sniffing.metadataOnly = false
+ inbound.sniffing.routeOnly = xray_settings.sniffing_override_dest ~= "1" or nil
+ inbound.sniffing.domainsExcluded = xray_settings.sniffing_override_dest == "1" and get_domain_excluded() or nil
+ end
+ if remote_dns_fake or inner_fakedns == "1" then
+ inbound.sniffing.enabled = true
+ if not inbound.sniffing.destOverride then
+ inbound.sniffing.destOverride = {"fakedns"}
+ inbound.sniffing.metadataOnly = true
+ else
+ table.insert(inbound.sniffing.destOverride, "fakedns")
+ inbound.sniffing.metadataOnly = false
+ end
+ end
+
+ if tcp_redir_port then
+ local tcp_inbound = api.clone(inbound)
+ tcp_inbound.tag = "tcp_redir"
+ tcp_inbound.settings.network = "tcp"
+ tcp_inbound.port = tonumber(tcp_redir_port)
+ tcp_inbound.streamSettings.sockopt.tproxy = tcp_proxy_way
+ table.insert(inbounds, tcp_inbound)
+ end
+
+ if udp_redir_port then
+ local udp_inbound = api.clone(inbound)
+ udp_inbound.tag = "udp_redir"
+ udp_inbound.settings.network = "udp"
+ udp_inbound.port = tonumber(udp_redir_port)
+ table.insert(inbounds, udp_inbound)
+ end
+ end
end
if (remote_dns_udp_server and remote_dns_udp_port) or (remote_dns_tcp_server and remote_dns_tcp_port) then
@@ -1402,7 +1398,7 @@ function gen_config(var)
address = "fakedns",
}
- if remote_dns_fake then
+ if remote_dns_fake or inner_fakedns == "1" then
fakedns = {}
local fakedns4 = {
ipPool = "198.18.0.0/15",
@@ -1420,7 +1416,9 @@ function gen_config(var)
elseif remote_dns_query_strategy == "UseIPv6" then
table.insert(fakedns, fakedns6)
end
- table.insert(dns.servers, 1, _remote_fakedns)
+ if remote_dns_fake and inner_fakedns == "0" then
+ table.insert(dns.servers, 1, _remote_fakedns)
+ end
end
local dns_outbound_tag = "direct"
@@ -1510,7 +1508,7 @@ function gen_config(var)
if value.outboundTag == "direct" and _direct_dns.address then
dns_server = api.clone(_direct_dns)
else
- if remote_dns_fake then
+ if value.fakedns then
dns_server = api.clone(_remote_fakedns)
else
dns_server = api.clone(_remote_dns)
diff --git a/applications/luci-app-passwall/luasrc/view/passwall/global/footer.htm b/applications/luci-app-passwall/luasrc/view/passwall/global/footer.htm
index 221949738f..ddf3b139c8 100644
--- a/applications/luci-app-passwall/luasrc/view/passwall/global/footer.htm
+++ b/applications/luci-app-passwall/luasrc/view/passwall/global/footer.htm
@@ -1,5 +1,5 @@
<%
-local api = require "luci.passwall.api"
+local api = self.api
-%>
diff --git a/applications/luci-app-passwall/luasrc/view/passwall/node_config/header.htm b/applications/luci-app-passwall/luasrc/view/passwall/node_config/header.htm
new file mode 100644
index 0000000000..7824b1a763
--- /dev/null
+++ b/applications/luci-app-passwall/luasrc/view/passwall/node_config/header.htm
@@ -0,0 +1,53 @@
+<%
+local api = self.api
+-%>
+
diff --git a/applications/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm b/applications/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm
similarity index 98%
rename from applications/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm
rename to applications/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm
index 46440b1388..a7ad9e9e31 100644
--- a/applications/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm
+++ b/applications/luci-app-passwall/luasrc/view/passwall/node_config/link_share_man.htm
@@ -692,7 +692,7 @@
return server.replace(/^\[/, '').replace(/\]$/, '');
}
- function fromUrl(btn, urlname, sid) {
+ function fromUrl(btn, urlname, sid, cacheData) {
var opt = {
base: 'cbid.passwall',
client: true,
@@ -800,9 +800,21 @@
}
opt.base = "cbid." + urlname + "." + sid;
opt.client = urlname.indexOf("server") === -1;
- var ssrurl = prompt('<%:Paste Share URL Here%>', '');
- if (ssrurl === null || ssrurl === "") {
- return false;
+ var ssrurl = null;
+ if (cacheData) {
+ ssrurl = cacheData.ssrurl
+ } else {
+ ssrurl = prompt('<%:Paste Share URL Here%>', '');
+ if (ssrurl === null || ssrurl === "") {
+ return false;
+ }
+ sessionStorage.setItem("fromUrl", JSON.stringify({
+ timestamp: Date.now(),
+ savetime: 60 * 1000,
+ urlname: urlname,
+ sid: sid,
+ ssrurl: ssrurl
+ }));
}
ssrurl = ssrurl.replace(/&/gi, '&').replace(/\s*#\s*/, '#').trim(); //一些奇葩的链接用"&"当做"&","#"前后带空格
s.innerHTML = "";
@@ -1658,13 +1670,23 @@
return false;
}
s.innerHTML = "<%:Import Finished %>";
- return false;
+ sessionStorage.removeItem("fromUrl");
+ return true;
}
function exportConfigFile(btn, sid) {
window.open('<%=api.url("gen_client_config")%>?id=' + sid, "_blank")
}
+ document.addEventListener("DOMContentLoaded", function () {
+ const fromUrlCache = JSON.parse(sessionStorage.getItem("fromUrl"));
+ if (fromUrlCache && fromUrlCache.savetime && (Date.now() - fromUrlCache.timestamp) < fromUrlCache.savetime) {
+ fromUrl(null, fromUrlCache.urlname, fromUrlCache.sid, fromUrlCache)
+ } else {
+ sessionStorage.removeItem("fromUrl");
+ }
+ })
+
//]]>