💐 Sync 2026-09-10 14:49:21

This commit is contained in:
github-actions[bot] committed 2026-09-10 14:49:21 +08:00
1 parent 0e9e9c2496
commit 7b0b16dcd4
181 files changed
+23375 -22143

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.9.9
PKG_RELEASE:=262
PKG_RELEASE:=263
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
@@ -556,7 +556,21 @@ function add_node()
uci_set(uid, "group", group)
end
uci_set(uid, "type", "Socks")
if api.is_finded("ipt2socks") then
uci_set(uid, "type", "Socks")
elseif api.finded_com("sing-box") then
uci_set(uid, "type", "sing-box")
elseif api.finded_com("xray") then
uci_set(uid, "type", "Xray")
elseif api.is_finded("sslocal") then
uci_set(uid, "type", "SS-Rust")
elseif api.is_finded("ssr-local") then
uci_set(uid, "type", "SSR")
elseif api.finded_com("hysteria") then
uci_set(uid, "type", "Hysteria2")
elseif api.is_finded("naive") then
uci_set(uid, "type", "Naiveproxy")
end
if redirect == "1" then
uci_save()
@@ -47,20 +47,23 @@ end
-- [[ ACLs Settings ]]--
s = m:section(NamedSection, arg[1], translate("ACLs"), translate("ACLs"))
s.addremove = false
s.dynamic = false
s:tab("Main", translate("Main"))
s:tab("Proxy", translate("Proxy"))
s:tab("DNS", translate("DNS"))
s:tab("Log", translate("Log"))
---- Enable
o = s:option(Flag, "enabled", translate("Enable"))
o = s:taboption("Main", Flag, "enabled", translate("Enable"))
o.default = 1
o.rmempty = false
---- Remarks
o = s:option(Value, "remarks", translate("Remarks"))
o = s:taboption("Main", Value, "remarks", translate("Remarks"))
o.default = arg[1]
o.rmempty = false
o = s:option(Value, "interface", translate("Source Interface"))
o = s:taboption("Main", Value, "interface", translate("Source Interface"))
o:value("", translate("All"))
local iface = api.get_network_devices()
for _, d in ipairs(iface) do
@@ -94,7 +97,7 @@ table.sort(mac_t, function(a,b)
end)
---- Source
sources = s:option(DynamicList, "sources", translate("Source"))
sources = s:taboption("Main", DynamicList, "sources", translate("Source"))
sources.description = "<ul><li>" .. translate("Example:")
.. "</li><li>" .. translate("MAC") .. ": 00:00:00:FF:FF:FF"
.. "</li><li>" .. translate("IP") .. ": 192.168.1.100"
@@ -152,13 +155,14 @@ sources.validate = function(self, value, t)
return value
end
o = s:option(ListValue, "mode", translate("Mode"))
local NODE = m:get("@global[0]", "node") or ""
o = s:taboption("Main", ListValue, "mode", translate("Mode"))
o:value("0", translate("No Proxy"))
o:value("1", translate("Proxy"))
---- TCP No Redir Ports
local TCP_NO_REDIR_PORTS = m:get("@global_forwarding[0]", "tcp_no_redir_ports")
o = s:option(Value, "tcp_no_redir_ports", translate("TCP No Redir Ports"))
o = s:taboption("Proxy", Value, "tcp_no_redir_ports", translate("TCP No Redir Ports"))
o:value("", translate("Use global config") .. "(" .. TCP_NO_REDIR_PORTS .. ")")
o:value("disable", translate("No patterns are used"))
o:value("1:65535", translate("All"))
@@ -167,7 +171,7 @@ o.validate = port_validate
---- UDP No Redir Ports
local UDP_NO_REDIR_PORTS = m:get("@global_forwarding[0]", "udp_no_redir_ports")
o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"),
o = s:taboption("Proxy", Value, "udp_no_redir_ports", translate("UDP No Redir Ports"),
"<font color='red'>" ..
translate("Fill in the ports you don't want to be forwarded by the agent, with the highest priority.") ..
"</font>")
@@ -177,7 +181,7 @@ o:value("1:65535", translate("All"))
o:depends("mode", "1")
o.validate = port_validate
o = s:option(DummyValue, "_hide_node_option", "")
o = s:taboption("Main", DummyValue, "_hide_node_option", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends("mode", "0")
@@ -186,44 +190,46 @@ if TCP_NO_REDIR_PORTS == "1:65535" and UDP_NO_REDIR_PORTS == "1:65535" then
o:depends({ tcp_no_redir_ports = "", udp_no_redir_ports = "" })
end
o = s:option(Flag, "use_global_config", translatef("Use global config"))
o = s:taboption("Main", Flag, "use_global_config", translatef("Use global config"))
o.default = "0"
o.rmempty = false
o:depends({ _hide_node_option = "1", ['!reverse'] = true })
o:depends({ _hide_node_option = "1", ['!reverse'] = true })
o = s:option(ListValue, "node", "<a style='color: red'>" .. translate("Proxy Node") .. "</a>")
o = s:taboption("Main", ListValue, "node", "<a style='color: red'>" .. translate("Proxy Node") .. "</a>")
o.group = {}
o:depends({ _hide_node_option = false, use_global_config = false })
o.template = m:template_path("/cbi/nodes_listvalue")
o.description = translate("Use global configuration when using the global node.")
current_node_id = o:formvalue(arg[1])
if not current_node_id then
current_node_id = m:get(arg[1], "node")
current_node_id = m:get(arg[1], "node")
local node_value = s.fields["node"]:formvalue(s.section)
if node_value then
current_node_id = node_value
end
current_node = current_node_id and m:get(current_node_id) or {}
o = s:option(DummyValue, "_acl_node_bool", "")
o = s:taboption("Main", DummyValue, "node_save_before", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = current_node[".name"]
o.cbid = function(self, section) return "node_save_before" end
o = s:taboption("Main", DummyValue, "_acl_node_bool", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends({ node = "", ['!reverse'] = true })
o:depends({ node = "", ['!reverse'] = true })
---- Log
o = s:option(Flag, "log", translate("Enable Node Log"))
o.default = 0
o.rmempty = false
o:depends({ _hide_node_option = false, use_global_config = false })
o = s:option(ListValue, "loglevel", "Sing-Box/Xray " .. translate("Log Level"))
o.default = "warn"
o:value("debug", "Debug")
o:value("info", "Info")
o:value("warn", "Warning")
o:value("error", "Error")
o:depends("log", "1")
o = s:taboption("Main", DummyValue, "_diff_global_node", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
if NODE ~= "" then
o:depends({ node = NODE, ['!reverse'] = true })
else
o:depends({ _acl_node_bool = "1" })
end
---- TCP Proxy Drop Ports
local TCP_PROXY_DROP_PORTS = m:get("@global_forwarding[0]", "tcp_proxy_drop_ports")
o = s:option(Value, "tcp_proxy_drop_ports", translate("TCP Proxy Drop Ports"))
o = s:taboption("Proxy", Value, "tcp_proxy_drop_ports", translate("TCP Proxy Drop Ports"))
o:value("", translate("Use global config") .. "(" .. TCP_PROXY_DROP_PORTS .. ")")
o:value("disable", translate("No patterns are used"))
o.validate = port_validate
@@ -232,7 +238,7 @@ o:depends({ _acl_node_bool = "1" })
---- UDP Proxy Drop Ports
local UDP_PROXY_DROP_PORTS = m:get("@global_forwarding[0]", "udp_proxy_drop_ports")
o = s:option(Value, "udp_proxy_drop_ports", translate("UDP Proxy Drop Ports"))
o = s:taboption("Proxy", Value, "udp_proxy_drop_ports", translate("UDP Proxy Drop Ports"))
o:value("", translate("Use global config") .. "(" .. UDP_PROXY_DROP_PORTS .. ")")
o:value("disable", translate("No patterns are used"))
o:value("443", translate("QUIC"))
@@ -242,7 +248,7 @@ o:depends({ _acl_node_bool = "1" })
---- TCP Redir Ports
local TCP_REDIR_PORTS = m:get("@global_forwarding[0]", "tcp_redir_ports")
o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports"), translatef("Only work with using the %s node.", "TCP"))
o = s:taboption("Proxy", Value, "tcp_redir_ports", translate("TCP Redir Ports"), translatef("Only work with using the %s node.", "TCP"))
o:value("", translate("Use global config") .. "(" .. TCP_REDIR_PORTS .. ")")
o:value("1:65535", translate("All"))
o:value("80,443", "80,443")
@@ -254,7 +260,7 @@ o:depends({ _acl_node_bool = "1" })
---- UDP Redir Ports
local UDP_REDIR_PORTS = m:get("@global_forwarding[0]", "udp_redir_ports")
o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports"), translatef("Only work with using the %s node.", "UDP"))
o = s:taboption("Proxy", Value, "udp_redir_ports", translate("UDP Redir Ports"), translatef("Only work with using the %s node.", "UDP"))
o:value("", translate("Use global config") .. "(" .. UDP_REDIR_PORTS .. ")")
o:value("1:65535", translate("All"))
o:value("53", "53")
@@ -262,7 +268,7 @@ o.validate = port_validate
o:depends({ use_global_config = true })
o:depends({ _acl_node_bool = "1" })
o = s:option(DummyValue, "tips", " ")
o = s:taboption("Proxy", DummyValue, "tips", " ")
o.rawhtml = true
o.cfgvalue = function(t, n)
return string.format('<font color="red">%s</font>',
@@ -271,71 +277,71 @@ end
o:depends({ use_global_config = true })
o:depends({ _acl_node_bool = "1" })
o = s:option(Flag, "use_direct_list", translatef("Use %s", translate("Direct List")))
o = s:taboption("Proxy", Flag, "use_direct_list", translatef("Use %s", translate("Direct List")))
o.default = "1"
o:depends({ _acl_node_bool = "1" })
o:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
o = s:option(Flag, "use_proxy_list", translatef("Use %s", translate("Proxy List")))
o = s:taboption("Proxy", Flag, "use_proxy_list", translatef("Use %s", translate("Proxy List")))
o.default = "1"
o:depends({ _acl_node_bool = "1" })
o:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
o = s:option(Flag, "use_block_list", translatef("Use %s", translate("Block List")))
o = s:taboption("Proxy", Flag, "use_block_list", translatef("Use %s", translate("Block List")))
o.default = "1"
o:depends({ _acl_node_bool = "1" })
o:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
if has_gfwlist then
o = s:option(Flag, "use_gfw_list", translatef("Use %s", translate("GFW List")))
o = s:taboption("Proxy", Flag, "use_gfw_list", translatef("Use %s", translate("GFW List")))
o.default = "1"
o:depends({ _acl_node_bool = "1" })
o:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
end
if has_chnlist or has_chnroute then
o = s:option(ListValue, "chn_list", translate("China List"))
o = s:taboption("Proxy", ListValue, "chn_list", translate("China List"))
o:value("0", translate("Close(Not use)"))
o:value("direct", translate("Direct Connection"))
o:value("proxy", translate("Proxy"))
o.default = "direct"
o:depends({ _acl_node_bool = "1" })
o:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
end
o = s:option(ListValue, "tcp_proxy_mode", "TCP " .. translate("Proxy Mode"))
o = s:taboption("Proxy", ListValue, "tcp_proxy_mode", "TCP " .. translate("Proxy Mode"))
o:value("disable", translate("No Proxy"))
o:value("proxy", translate("Proxy"))
o:depends({ _acl_node_bool = "1" })
o:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
o = s:option(ListValue, "udp_proxy_mode", "UDP " .. translate("Proxy Mode"))
o = s:taboption("Proxy", ListValue, "udp_proxy_mode", "UDP " .. translate("Proxy Mode"))
o:value("disable", translate("No Proxy"))
o:value("proxy", translate("Proxy"))
o:depends({ _acl_node_bool = "1" })
o:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
o = s:option(DummyValue, "switch_mode", " ")
o = s:taboption("Proxy", DummyValue, "switch_mode", "")
o.template = m:template_path("/global/proxy")
o:depends({ _acl_node_bool = "1" })
o:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
-- Node → DNS Depends Settings
o = s:option(DummyValue, "_node_sel_shunt", "")
o = s:taboption("Main", DummyValue, "_node_sel_shunt", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends({ node = "__always__" })
o = s:option(DummyValue, "_node_sel_other", "")
o = s:taboption("Main", DummyValue, "_node_sel_other", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
o:depends({ _node_sel_shunt = "1", ['!reverse'] = true })
o:depends({ _node_sel_shunt = "1", ['!reverse'] = true })
---- DNS
o = s:option(ListValue, "dns_shunt", "DNS " .. translate("Shunt"))
o = s:taboption("DNS", ListValue, "dns_shunt", "DNS " .. translate("Shunt"))
o.default = "chinadns-ng"
o:value("dnsmasq", "Dnsmasq")
o:value("chinadns-ng", translate("ChinaDNS-NG (recommended)"))
o:depends({ _acl_node_bool = "1" })
o:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
o = s:option(Flag, "filter_proxy_ipv6", translate("Filter Proxy Host IPv6"), translate("Experimental feature."))
o = s:taboption("DNS", Flag, "filter_proxy_ipv6", translate("Filter Proxy Host IPv6"), translate("Experimental feature."))
o.default = "0"
o:depends({ _acl_node_bool = "1" })
o:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
---- DNS Forward Mode
o = s:option(ListValue, "dns_mode", translate("Filter Mode"))
o = s:taboption("DNS", ListValue, "dns_mode", translate("Filter Mode"))
if api.is_finded("dns2socks") then
o:value("dns2socks", "dns2socks")
end
@@ -345,7 +351,7 @@ end
if has_xray then
o:value("xray", "Xray")
end
o:depends({ _acl_node_bool = "1", _node_sel_other = "1" })
o:depends({ _acl_node_bool = "1", _node_sel_other = "1", _diff_global_node = "1" })
o.write = function(self, section, value)
if value == "dns2socks" then
m:del(section, "v2ray_dns_mode")
@@ -374,7 +380,7 @@ o.remove = function(self, section)
end
end
o = s:option(ListValue, "xray_dns_mode", translate("Request protocol"))
o = s:taboption("DNS", ListValue, "xray_dns_mode", translate("Request protocol"))
o.default = "tcp"
o:value("tcp", "TCP")
o:value("udp", "UDP")
@@ -389,7 +395,7 @@ o.write = function(self, section, value)
end
end
o = s:option(ListValue, "singbox_dns_mode", translate("Request protocol"))
o = s:taboption("DNS", ListValue, "singbox_dns_mode", translate("Request protocol"))
o.default = "tcp"
o:value("tcp", "TCP")
o:value("udp", "UDP")
@@ -408,7 +414,7 @@ o.write = function(self, section, value)
end
---- DNS Forward
o = s:option(Value, "remote_dns", translate("Remote DNS"))
o = s:taboption("DNS", Value, "remote_dns", translate("Remote DNS"))
o.datatype = "or(ipaddr,ipaddrport(1))"
o.default = "1.1.1.1"
o:value("1.1.1.1", "1.1.1.1 (CloudFlare)")
@@ -427,7 +433,7 @@ o:depends({singbox_dns_mode = "tcp"})
o:depends({singbox_dns_mode = "tls"})
o:depends({singbox_dns_mode = "quic"})
o = s:option(Value, "remote_dns_doh", translate("Remote DNS DoH"))
o = s:taboption("DNS", Value, "remote_dns_doh", translate("Remote DNS DoH"))
o.description = translate("Format: URL[,IP] (optional IP to map the domain in the URL)")
o:value("https://1.1.1.1/dns-query", "1.1.1.1 (CloudFlare)")
o:value("https://1.1.1.2/dns-query", "1.1.1.2 (CloudFlare-Security)")
@@ -466,15 +472,15 @@ o:depends({xray_dns_mode = "doh"})
o:depends({singbox_dns_mode = "doh"})
o:depends({singbox_dns_mode = "http3"})
o = s:option(Value, "remote_dns_client_ip", translate("EDNS Client Subnet"))
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).") .. "<br />" ..
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:depends({_node_sel_shunt = "1", _diff_global_node = "1"})
o = s:option(Flag, "remote_fakedns", "FakeDNS", translate("Use FakeDNS work in the domain that proxy."))
o = s:taboption("DNS", Flag, "remote_fakedns", "FakeDNS", translate("Use FakeDNS work in the domain that proxy."))
o.default = "0"
o.rmempty = false
o:depends({dns_mode = "sing-box"})
@@ -492,12 +498,12 @@ o.validate = function(self, value, t)
return value
end
o = s:option(Value, "remote_rewrite_ttl", translate("Remote DNS") .. " TTL")
o = s:taboption("DNS", Value, "remote_rewrite_ttl", translate("Remote DNS") .. " TTL")
o.datatype = "min(1)"
o.default = "30"
o:depends({dns_mode = "sing-box"})
o = s:option(ListValue, "chinadns_ng_default_tag", translate("Default DNS"))
o = s:taboption("DNS", ListValue, "chinadns_ng_default_tag", translate("Default DNS"))
o.default = "none"
o:value("gfw", translate("Remote DNS"))
o:value("chn", translate("Direct DNS"))
@@ -515,18 +521,73 @@ o.description = desc
.. "</ul>"
o:depends({dns_shunt = "chinadns-ng", tcp_proxy_mode = "proxy", chn_list = "direct"})
o = s:option(Flag, "force_https_soa", translate("Force HTTPS SOA"), translate("Force queries with qtype 65 to respond with an SOA record."))
o = s:taboption("DNS", Flag, "force_https_soa", translate("Force HTTPS SOA"), translate("Force queries with qtype 65 to respond with an SOA record."))
o.default = "0"
o.rmempty = false
o:depends({dns_shunt = "chinadns-ng"})
o = s:option(ListValue, "use_default_dns", translate("Default DNS"))
o = s:taboption("DNS", ListValue, "use_default_dns", translate("Default DNS"))
o.default = "direct"
o:value("remote", translate("Remote DNS"))
o:value("direct", translate("Direct DNS"))
o.description = desc .. "</ul>"
o:depends({dns_shunt = "dnsmasq", tcp_proxy_mode = "proxy", chn_list = "direct"})
---- Log
o = s:taboption("Log", Flag, "log", translate("Enable Node Log"))
o.default = 0
o.rmempty = false
o:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
o = s:taboption("Log", ListValue, "loglevel", "Sing-Box/Xray " .. translate("Log Level"))
o.default = "warn"
o:value("debug", "Debug")
o:value("info", "Info")
o:value("warn", "Warning")
o:value("error", "Error")
o:depends("log", "1")
o = s:taboption("Log", DummyValue, "_node_log", translate("Log File"))
o.rawhtml = true
o.cfgvalue = function(t, n)
local log_file = api.TMP_PATH .. "/acl/" .. arg[1] .. "/node.log"
local log_url = api.url("get_redir_log") .. "?id=" .. arg[1]
local s = "<code>%s</code>&nbsp;&nbsp;" % log_file
if api.fs.access(log_file) then
local btn = string.format(
'<input class="btn cbi-button cbi-button-apply" type="button" value="%s" onclick="window.open(\'%s\', \'_blank\')" />',
translate("View Log"),
log_url
)
s = s .. btn
end
return s
end
o:depends("log", "1")
o = s:taboption("Log", Flag, "log_chinadns_ng", translate("Enable") .. " ChinaDNS-NG " .. translate("Log"))
o.default = "0"
o.rmempty = false
o:depends("dns_shunt", "chinadns-ng")
o = s:taboption("Log", DummyValue, "_chinadns_ng_log", translate("Log File"))
o.rawhtml = true
o.cfgvalue = function(t, n)
local log_file = api.TMP_PATH .. "/acl/" .. arg[1] .. "/chinadns_ng.log"
local log_url = api.url("get_chinadns_log") .. "?flag=" .. arg[1]
local s = "<code>%s</code>&nbsp;&nbsp;" % log_file
if api.fs.access(log_file) then
local btn = string.format(
'<input class="btn cbi-button cbi-button-apply" type="button" value="%s" onclick="window.open(\'%s\', \'_blank\')" />',
translate("View Log"),
log_url
)
s = s .. btn
end
return s
end
o:depends("log_chinadns_ng", "1")
local o_node = s.fields["node"]
local shunt_list = {}
@@ -536,7 +597,7 @@ for k, v in pairs(socks_list) do
end
for k, v in pairs(nodes_table) do
if #normal_list == 0 then
s.fields["dns_mode"]:depends({ _acl_node_bool = "1" })
s.fields["dns_mode"]:depends({ _acl_node_bool = "1", _diff_global_node = "1" })
break
end
if v.protocol and v.protocol == "_shunt" then
@@ -544,16 +605,16 @@ for k, v in pairs(nodes_table) do
o_node:value(v.id, v["remark"])
o_node.group[#o_node.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
s.fields["xray_dns_mode"]:depends({ _acl_node_bool = "1", node = v.id })
s.fields["xray_dns_mode"]:depends({ _acl_node_bool = "1", _diff_global_node = "1", node = v.id })
s.fields["_node_sel_shunt"]:depends({ node = v.id })
end
if v.type == "sing-box" and has_singbox then
o_node:value(v.id, v["remark"])
o_node.group[#o_node.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
s.fields["singbox_dns_mode"]:depends({ _acl_node_bool = "1", node = v.id })
s.fields["singbox_dns_mode"]:depends({ _acl_node_bool = "1", _diff_global_node = "1", node = v.id })
s.fields["_node_sel_shunt"]:depends({ node = v.id })
s.fields["remote_rewrite_ttl"]:depends({ _acl_node_bool = "1", node = v.id })
s.fields["remote_rewrite_ttl"]:depends({ _acl_node_bool = "1", _diff_global_node = "1", node = v.id })
end
shunt_list[#shunt_list + 1] = v
else
@@ -562,21 +623,17 @@ for k, v in pairs(nodes_table) do
end
end
m:appendTemplate("/acl/config_footer", {section = arg[1]})
--[[
-- Shunt
if current_node.protocol == "_shunt" then
if current_node.protocol == "_shunt" and current_node[".name"] ~= NODE then
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall/client/include/shunt_options.lua")
setfenv(shunt_lua, getfenv(1))(m, s, {
s_cfgid = s.section,
node_id = current_node_id,
node = current_node,
verify_option = s.fields["node"]
verify_option = s.fields["node"],
tab = "Shunt",
tab_desc = translate("Shunt Rule"),
})
end
m:appendTemplate("/acl/shunt", { shunt_list = api.jsonc.stringify(shunt_list), section = s.section })
]]--
m:appendTemplate("/include/node_change", { verify_option = s.fields["node"], shunt_list = api.jsonc.stringify(shunt_list) })
return api.return_map(m)
@@ -112,6 +112,10 @@ o:value("", translate("Close"))
o.group = {""}
current_node_id = m:get(s.section, "node")
local node_value = s.fields["node"]:formvalue(s.section)
if node_value then
current_node_id = node_value
end
current_node = current_node_id and m:get(current_node_id) or {}
-- Shunt Start
@@ -120,17 +124,10 @@ if (has_singbox or has_xray) and #nodes_table > 0 then
if current_node.protocol == "_shunt" then
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall/client/include/shunt_options.lua")
setfenv(shunt_lua, getfenv(1))(m, s, {
s_cfgid = s.section,
node_id = current_node_id,
node = current_node,
socks_list = socks_list,
urltest_list = urltest_list,
balancing_list = balancing_list,
iface_list = iface_list,
normal_list = normal_list,
verify_option = s.fields["node"],
tab = "Shunt",
tab_desc = translate("Shunt Rule")
tab_desc = translate("Shunt Rule"),
})
end
else
@@ -165,6 +162,11 @@ o = s:taboption("Main", Flag, "node_socks_bind_local", translate("Node") .. " So
o.default = "1"
o:depends("_node", "1")
o = s:taboption("Main", DummyValue, "node_save_before", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = current_node[".name"]
o.cbid = function(self, section) return "node_save_before" end
o = s:taboption("Main", DummyValue, "_node", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
@@ -605,7 +607,7 @@ o:value("disable", translate("No Proxy"))
o:value("proxy", translate("Proxy"))
o.default = "proxy"
o = s:taboption("Proxy", DummyValue, "switch_mode", " ")
o = s:taboption("Proxy", DummyValue, "switch_mode", "")
o.template = m:template_path("/global/proxy")
---- Check the transparent proxy component
@@ -687,6 +689,8 @@ s:tab("maintain", translate("Maintain"))
o = s:taboption("maintain", DummyValue, "")
o.template = m:template_path("/global/backup")
m:appendTemplate("/include/node_change", { verify_option = s.fields["node"], shunt_list = api.jsonc.stringify(shunt_list) })
-- [[ Socks Server ]]--
o = s:taboption("Main", Flag, "socks_enabled", "Socks " .. translate("Main switch"))
o.rmempty = false
@@ -824,7 +828,7 @@ for k, v in pairs(nodes_table) do
end
end
m:appendTemplate("/global/footer", {shunt_list = api.jsonc.stringify(shunt_list)})
m:appendTemplate("/global/footer")
m:appendTemplate("/global/status_bottom")
m:appendTemplate("/cbi/sortable", {sectiontype = s2.sectiontype})
@@ -1,13 +1,28 @@
local m, s, data = ...
if not data.node_id or not data.node then
if not data.node or not data.node[".name"] then
return
end
local api = m.api
local s_cfgid = data.s_cfgid
local current_node_id = data.node_id
local section_id = s.section
local current_node = data.node
local current_node_id = current_node[".name"]
local verify_option = data.verify_option
local node_list = data.node_list or api.get_node_list()
local shunt_section_type = "shunt_option_list"
if data.tab then
if #s.tab_names > 0 then
table.insert(s.tab_names, 2, data.tab)
s.tabs[data.tab] = {
title = data.tab_desc,
childs = { }
}
else
s:tab(data.tab, data.tab_desc)
end
end
local groups = {}
m:foreach("shunt_rules", function(s)
@@ -16,6 +31,9 @@ m:foreach("shunt_rules", function(s)
end
end)
local node_save_before = luci.http.formvalue("node_save_before")
local load_shunt = luci.http.formvalue("load_shunt")
local function get_cfgvalue()
return function(self, section)
return m:get(current_node_id, self.option)
@@ -23,8 +41,10 @@ local function get_cfgvalue()
end
local function get_write()
return function(self, section, value)
if data.verify_option then
if data.verify_option:formvalue(section) == current_node_id then
if node_save_before and node_save_before ~= current_node_id then return end
if load_shunt == "1" then return end
if verify_option then
if verify_option:formvalue(section) == current_node_id then
m:set(current_node_id, self.option, value)
end
else
@@ -34,8 +54,10 @@ local function get_write()
end
local function get_remove()
return function(self, section)
if data.verify_option then
if data.verify_option:formvalue(section) == current_node_id then
if node_save_before and node_save_before ~= current_node_id then return end
if load_shunt == "1" then return end
if verify_option then
if verify_option:formvalue(section) == current_node_id then
m:del(current_node_id, self.option)
end
else
@@ -44,10 +66,6 @@ local function get_remove()
end
end
if data.tab then
s:tab(data.tab, data.tab_desc)
end
local function add_option(class, option_name, option_title, option_desc)
local a
if data.tab then
@@ -63,8 +81,8 @@ local function add_option(class, option_name, option_title, option_desc)
a.write = get_write()
a.remove = get_remove()
end
if data.verify_option then
a:depends(data.verify_option.option, current_node_id)
if verify_option then
a:depends(verify_option.option, current_node_id)
end
return a
end
@@ -81,7 +99,7 @@ local function add_depends(o, deps)
end
end
if data.node.type == "Xray" then
if current_node.type == "Xray" then
o = add_option(ListValue, "domainStrategy", translate("Domain Strategy"))
o:value("AsIs")
o:value("IPIfNonMatch")
@@ -134,7 +152,7 @@ table.insert(shunt_rules, {
s2 = m:section(Table, shunt_rules, " ")
s2.config = m.config
s2.sectiontype = "shunt_option_list"
s2.sectiontype = shunt_section_type
o = s2:option(DummyValue, "remarks", translate("Rule"))
o.rawhtml = true
@@ -157,9 +175,13 @@ _node.cfgvalue = function(self, section)
return m:get(current_node_id, shunt_rules[section]["_node_option"]) or shunt_rules[section]["_node_default"]
end
_node.write = function(self, section, value)
if node_save_before and node_save_before ~= current_node_id then return end
if load_shunt == "1" then return end
return m:set(current_node_id, shunt_rules[section]["_node_option"], value)
end
_node.remove = function(self, section)
if node_save_before and node_save_before ~= current_node_id then return end
if load_shunt == "1" then return end
return m:del(current_node_id, shunt_rules[section]["_node_option"])
end
@@ -170,9 +192,13 @@ o.cfgvalue = function(self, section)
return m:get(current_node_id, shunt_rules[section]["_fakedns_option"])
end
o.write = function(self, section, value)
if node_save_before and node_save_before ~= current_node_id then return end
if load_shunt == "1" then return end
return m:set(current_node_id, shunt_rules[section]["_fakedns_option"], value)
end
o.remove = function(self, section)
if node_save_before and node_save_before ~= current_node_id then return end
if load_shunt == "1" then return end
return m:del(current_node_id, shunt_rules[section]["_fakedns_option"])
end
@@ -186,9 +212,13 @@ proxy_tag_node.cfgvalue = function(self, section)
return m:get(current_node_id, shunt_rules[section]["_proxy_tag_option"])
end
proxy_tag_node.write = function(self, section, value)
if node_save_before and node_save_before ~= current_node_id then return end
if load_shunt == "1" then return end
return m:set(current_node_id, shunt_rules[section]["_proxy_tag_option"], value)
end
proxy_tag_node.remove = function(self, section)
if node_save_before and node_save_before ~= current_node_id then return end
if load_shunt == "1" then return end
return m:del(current_node_id, shunt_rules[section]["_proxy_tag_option"])
end
@@ -204,4 +234,11 @@ for k1, v1 in pairs(node_list) do
end
end
m:appendTemplate("/include/shunt_options", {id = current_node_id, s_cfgid = s_cfgid or current_node_id, normal_list = api.jsonc.stringify(node_list.normal_list)})
m:appendTemplate("/include/shunt_options", {
node_id = current_node_id,
section_id = section_id or current_node_id,
section_type = shunt_section_type,
tab_name = data.tab,
normal_list = api.jsonc.stringify(node_list.normal_list),
shunt_list = api.jsonc.stringify(node_list.shunt_list)
})
@@ -61,7 +61,6 @@ end
local types_dir = "/usr/lib/lua/luci/model/cbi/" .. api.appname .. "/client/type/"
s.val = {}
s.val["type"] = m:get(arg[1], "type")
s.val["protocol"] = m:get(arg[1], "protocol")
if luci.http.formvalue("cbi.submit") == "1" then
local formvalue_type = luci.http.formvalue(formvalue_key .. "type")
@@ -72,34 +71,6 @@ end
o = s:option(ListValue, "type", translate("Type"))
if api.is_finded("ipt2socks") then
local type_name = "Socks"
s.fields["type"]:value(type_name, "Socks")
if s.val["type"] == type_name then
local s2 = NamedSection(m, arg[1], "server")
s2.type_name = type_name
s2.option_prefix = "socks_"
o = s2:option(ListValue, "del_protocol", " ") --始终隐藏,用于删除 protocol
o:depends({ __hide = "1" })
o.rewrite_option = "protocol"
o = s2:option(Value, "address", translate("Address (Support Domain Name)"))
o = s2:option(Value, "port", translate("Port"))
o.datatype = "port"
o = s2:option(Value, "username", translate("Username"))
o = s2:option(Value, "password", translate("Password"))
o.password = true
api.luci_types(s, s2)
end
end
local type_table = {}
for filename in api.fs.dir(types_dir) do
table.insert(type_table, filename)
@@ -0,0 +1,35 @@
if not api.is_finded("ipt2socks") then
return
end
-- [[ Socks ]]
local m, s1 = ...
local type_name = "Socks"
s1.fields["type"]:value(type_name, "Socks")
if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "socks_"
api.set_type_cbi(s)
o = s:option(ListValue, "del_protocol", "¡¡") --ʼÖÕÒþ²Ø£¬ÓÃÓÚɾ³ý protocol
o:depends({ __hide = "1" })
o.rewrite_option = "protocol"
o = s:option(Value, "address", translate("Address (Support Domain Name)"))
o = s:option(Value, "port", translate("Port"))
o.datatype = "port"
o = s:option(Value, "username", translate("Username"))
o = s:option(Value, "password", translate("Password"))
o.password = true
api.type_cbi_section(s1, s)
@@ -17,15 +17,11 @@ if s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "singbox_"
local formvalue_proto = luci.http.formvalue(formvalue_key .. "protocol")
if formvalue_proto then s1.val["protocol"] = formvalue_proto end
local arg_select_proto = luci.http.formvalue("select_proto") or ""
api.set_type_cbi(s)
local ss_method_new_list = {
"none", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
@@ -72,24 +68,20 @@ end
o:value("_urltest", translate("URLTest"))
o:value("_shunt", translate("Shunt"))
o:value("_iface", translate("Custom Interface"))
function o.custom_cfgvalue(self, section)
if arg_select_proto ~= "" then
return arg_select_proto
else
return m:get(section, self.config_option)
end
local protocol_val = m:get(s.section, "protocol")
local formvalue_proto = s.fields["protocol"]:formvalue(s.section)
if formvalue_proto then
protocol_val = formvalue_proto
end
local load_urltest_options = s1.val["protocol"] == "_urltest" or arg_select_proto == "_urltest"
local load_shunt_options = s1.val["protocol"] == "_shunt" or arg_select_proto == "_shunt"
local load_iface_options = s1.val["protocol"] == "_iface" or arg_select_proto == "_iface"
local load_urltest_options = protocol_val == "_urltest"
local load_shunt_options = protocol_val == "_shunt"
local load_iface_options = protocol_val == "_iface"
local load_normal_options = true
if load_urltest_options or load_shunt_options or load_iface_options then
load_normal_options = nil
end
if not arg_select_proto:find("_") then
load_normal_options = true
end
local netdev_list = api.get_network_devices()
local node_list = api.get_node_list()
@@ -115,11 +107,11 @@ if load_urltest_options then -- [[ URLTest Start ]]
end
end
-- 读取旧 DynamicList
function o.custom_cfgvalue(self, section)
function o.cfgvalue(self, section)
return table.concat(m:get(section, "urltest_node") or {}, " ")
end
-- 写入保持 DynamicList
function o.custom_write(self, section, value)
function o.write(self, section, value)
local old = m:get(section, "urltest_node") or {}
local new, set = {}, {}
for v in value:gmatch("%S+") do
@@ -935,7 +927,7 @@ if not load_shunt_options then
for k1, v1 in pairs(node_list) do
if k1 ~= "shunt_list" and k1 ~= "iface_list" then
for i, v in ipairs(v1) do
if v.id ~= arg[1] then
if v.id ~= s.section then
o1:value(v.id, v.remark)
o1.group[#o1.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
if k1 == "normal_list" then
@@ -949,14 +941,15 @@ if not load_shunt_options then
end
end
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
if load_shunt_options then
local current_node = m:get(arg[1]) or {}
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall/client/include/shunt_options.lua")
setfenv(shunt_lua, getfenv(1))(m, s1, {
node_id = arg[1],
node = current_node,
node = {
[".name"] = s.section,
type = type_name,
},
node_list = node_list,
})
end
@@ -15,15 +15,11 @@ if s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "xray_"
local formvalue_proto = luci.http.formvalue(formvalue_key .. "protocol")
if formvalue_proto then s1.val["protocol"] = formvalue_proto end
local arg_select_proto = luci.http.formvalue("select_proto") or ""
api.set_type_cbi(s)
local ss_method_list = {
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
@@ -53,31 +49,26 @@ if api.compare_versions(xray_version, ">=", "1.8.12") then
end
o:value("_shunt", translate("Shunt"))
o:value("_iface", translate("Custom Interface"))
function o.custom_cfgvalue(self, section)
if arg_select_proto ~= "" then
return arg_select_proto
else
return m:get(section, self.config_option)
end
local protocol_val = m:get(s.section, "protocol")
local formvalue_proto = s.fields["protocol"]:formvalue(s.section)
if formvalue_proto then
protocol_val = formvalue_proto
end
local load_balancing_options = s1.val["protocol"] == "_balancing" or arg_select_proto == "_balancing"
local load_shunt_options = s1.val["protocol"] == "_shunt" or arg_select_proto == "_shunt"
local load_iface_options = s1.val["protocol"] == "_iface" or arg_select_proto == "_iface"
local load_balancing_options = protocol_val == "_balancing"
local load_shunt_options = protocol_val == "_shunt"
local load_iface_options = protocol_val == "_iface"
local load_normal_options = true
if load_balancing_options or load_shunt_options or load_iface_options then
load_normal_options = nil
end
if not arg_select_proto:find("_") then
load_normal_options = true
end
local netdev_list = api.get_network_devices()
local node_list = api.get_node_list()
local fallback_list = {}
local is_balancer = nil
for k, e in ipairs(node_list.balancing_list or {}) do
if e.id ~= arg[1] then
if e.id ~= s.section then
fallback_list[#fallback_list + 1] = {
id = e["id"],
remark = e["remark"],
@@ -110,11 +101,11 @@ if load_balancing_options then -- [[ Load balancing Start ]]
end
end
-- 读取旧 DynamicList
function o.custom_cfgvalue(self, section)
function o.cfgvalue(self, section)
return table.concat(m:get(section, "balancing_node") or {}, " ")
end
-- 写入保持 DynamicList
function o.custom_write(self, section, value)
function o.write(self, section, value)
local old = m:get(section, "balancing_node") or {}
local new, set = {}, {}
for v in value:gmatch("%S+") do
@@ -213,7 +204,7 @@ if load_balancing_options then -- [[ Load balancing Start ]]
local depth = get_fallback_depth(v.id)
-- 超过最大套娃层数后,不允许继续选择 balancer
if depth < MAX_FALLBACK_DEPTH
and not will_loop(arg[1], v.id)
and not will_loop(s.section, v.id)
then
o:value(v.id, v.remark)
o.group[#o.group + 1] = (v.group and v.group ~= "") and v.group or translate("default")
@@ -678,13 +669,13 @@ o.validate = function(self, value)
if v then return v end
return nil, "XHTTP Extra " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
o.cfgvalue = function(self, section, value)
local raw = m:get(section, "xhttp_extra")
if raw then
return api.base64Decode(raw)
end
end
o.custom_write = function(self, section, value)
o.write = function(self, section, value)
m:set(section, "xhttp_extra", api.base64Encode(value) or "")
local success, data = pcall(api.jsonc.parse, value)
if success and data then
@@ -700,7 +691,7 @@ o.custom_write = function(self, section, value)
m:del(section, "download_address")
end
end
o.custom_remove = function(self, section, value)
o.remove = function(self, section, value)
m:del(section, "xhttp_extra")
m:del(section, "download_address")
end
@@ -763,13 +754,13 @@ o.validate = function(self, value)
if v then return v end
return nil, "FinalMask " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
o.cfgvalue = function(self, section, value)
local raw = m:get(section, "finalmask")
if raw then
return api.base64Decode(raw)
end
end
o.custom_write = function(self, section, value)
o.write = function(self, section, value)
m:set(section, "finalmask", api.base64Encode(value) or "")
end
@@ -871,7 +862,7 @@ if not load_shunt_options then
for k1, v1 in pairs(node_list) do
if k1 ~= "shunt_list" and k1 ~= "iface_list" then
for i, v in ipairs(v1) do
if v.id ~= arg[1] then
if v.id ~= s.section then
o1:value(v.id, v.remark)
o1.group[#o1.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
if k1 == "normal_list" then
@@ -885,14 +876,16 @@ if not load_shunt_options then
end
end
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
if load_shunt_options then
local current_node = m:get(arg[1]) or {}
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall/client/include/shunt_options.lua")
setfenv(shunt_lua, getfenv(1))(m, s1, {
node_id = arg[1],
node = current_node,
node = {
[".name"] = s.section,
type = type_name,
},
node_list = node_list,
})
end
@@ -12,9 +12,11 @@ if s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "ssrust_"
api.set_type_cbi(s)
local ssrust_encrypt_method_list = {
"none", "plain",
@@ -69,4 +71,4 @@ end
o = s:option(Value, "plugin_opts", translate("opts"))
o:depends({ plugin_enabled = true })
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
@@ -12,9 +12,11 @@ if s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "ssr_"
api.set_type_cbi(s)
local ssr_encrypt_method_list = {
"none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb",
@@ -63,4 +65,4 @@ o.default = 300
o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"), translate("Need node support required"))
o.default = 0
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
@@ -12,13 +12,11 @@ if s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "hysteria2_"
local function _n(name)
return s.option_prefix .. name
end
api.set_type_cbi(s)
o = s:option(ListValue, "protocol", translate("Protocol"))
o:value("udp", "UDP")
@@ -32,22 +30,22 @@ o:depends({ realms = false })
o = s:option(Value, "hop", translate("Port hopping range"))
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ realms = false })
o = s:option(Value, "hop_interval", translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
o.datatype = "or(uinteger,portrange)"
o.placeholder = "30"
o.default = "30"
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ realms = false })
o = s:option(Flag, "realms", translate("Realms"))
o.default = "0"
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Value, "realm_url", translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ realms = "1" })
o.validate = function(self, value)
value = api.trim(value)
@@ -58,26 +56,26 @@ end
o = s:option(DynamicList, "realm_stun", translate("Realm STUN"))
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ realms = "1" })
o = s:option(Flag, "realm_upnp", translate("Enable") .. " UPnP/NAT-PMP", translate("Enable UPnP/NAT-PMP port mapping on your gateway to improve hole punching success."))
o.default = "0"
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ realms = "1" })
o = s:option(Value, "auth_password", translate("Auth Password"))
o.password = true
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(ListValue, "obfs_type", translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:value("gecko")
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Value, "obfs_password", translate("Obfs Password"))
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ obfs_type = "salamander" })
o:depends({ obfs_type = "gecko" })
@@ -86,14 +84,14 @@ o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ obfs_type = "gecko" })
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Value, "obfs_MaxPacketSize", translate("Gecko Packet Size (max)"))
o.datatype = "uinteger"
o.placeholder = "1200"
o.default = "1200"
o:depends({ obfs_type = "gecko" })
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Flag, "fast_open", translate("Fast Open"))
o.default = "0"
@@ -106,28 +104,28 @@ o.default = "0"
o = s:option(Value, "tls_pinSHA256", translate("PinSHA256"),translate("Certificate fingerprint"))
o = s:option(Value, "up_mbps", translate("Max upload Mbps"))
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Value, "down_mbps", translate("Max download Mbps"))
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Value, "recv_window", translate("QUIC stream receive window"))
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Value, "recv_window_conn", translate("QUIC connection receive window"))
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Value, "idle_timeout", translate("Idle Timeout"), translate("Units:seconds") .. " (4~120)")
o.datatype = "range(4,120)"
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Value, "keep_alive_period", translate("QUIC KeepAlive interval"), translate("Units:seconds") .. " (2~60)")
o.datatype = "range(2,60)"
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Flag, "disable_mtu_discovery", translate("Disable MTU detection"))
o.default = "0"
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Flag, "ech", translate("ECH"))
@@ -145,6 +143,6 @@ end
o = s:option(Flag, "lazy_start", translate("Lazy Start"))
o.default = "0"
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
@@ -12,9 +12,11 @@ if s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "naive_"
api.set_type_cbi(s)
o = s:option(ListValue, "protocol", translate("Protocol"))
o:value("https", translate("HTTPS"))
@@ -30,4 +32,4 @@ o = s:option(Value, "username", translate("Username"))
o = s:option(Value, "password", translate("Password"))
o.password = true
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
@@ -15,9 +15,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "socks_"
api.set_type_cbi(s)
o = s:option(Value, "port", translate("Listen Port"))
o.datatype = "port"
@@ -44,4 +46,4 @@ o:depends({ firewall_allow = true })
o = s:option(Flag, "log", translate("Log"))
o.default = "1"
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
@@ -21,9 +21,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "singbox_"
api.set_type_cbi(s)
local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
@@ -48,13 +50,13 @@ o.validate = function(self, value)
if v then return v end
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
o.cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
o.write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
@@ -562,4 +564,4 @@ o:value("warn")
o:value("error")
o:depends({ log = true })
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
@@ -19,9 +19,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "xray_"
api.set_type_cbi(s)
local ss_method_list = {
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
@@ -44,13 +46,13 @@ o.validate = function(self, value)
if v then return v end
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
o.cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
o.write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
@@ -257,8 +259,8 @@ end
-- [[ TLS部分 ]] --
o = s:option(FileUpload, "tls_certificateFile", translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. s.section .. ".pem"
if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end
o:depends({ tls = true, reality = false })
o:depends({ protocol = "hysteria2"})
o.validate = function(self, value, t)
@@ -273,8 +275,8 @@ o.validate = function(self, value, t)
end
o = s:option(FileUpload, "tls_keyFile", translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key"
if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. s.section .. ".key"
if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end
o:depends({ tls = true, reality = false })
o:depends({ protocol = "hysteria2"})
o.validate = function(self, value, t)
@@ -396,13 +398,13 @@ o:depends({ use_finalmask = true })
o.rows = 10
o.wrap = "off"
o.datatype = "json"
o.custom_cfgvalue = function(self, section, value)
o.cfgvalue = function(self, section, value)
local raw = m:get(section, "finalmask")
if raw then
return api.base64Decode(raw)
end
end
o.custom_write = function(self, section, value)
o.write = function(self, section, value)
m:set(section, "finalmask", api.base64Encode(value) or "")
end
@@ -549,4 +551,4 @@ o:value("warning")
o:value("error")
o:depends({ log = true })
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
@@ -16,9 +16,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "ssrust_"
api.set_type_cbi(s)
local ssrust_encrypt_method_list = {
"plain", "none",
@@ -39,13 +41,13 @@ o.validate = function(self, value)
if v then return v end
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
o.cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
o.write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
@@ -88,4 +90,4 @@ o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
@@ -16,9 +16,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "ssr_"
api.set_type_cbi(s)
local ssr_encrypt_method_list = {
"none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb",
@@ -52,13 +54,13 @@ o.validate = function(self, value)
if v then return v end
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
o.cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
o.write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
@@ -119,4 +121,4 @@ o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
@@ -12,13 +12,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
local s = NamedSection(m, arg[1], "server")
local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
s.parent = s1
s.type_name = type_name
s.option_prefix = "hysteria2_"
local function _n(name)
return s.option_prefix .. name
end
api.set_type_cbi(s)
o = s:option(Flag, "custom", translate("Use Custom Config"))
@@ -33,13 +31,13 @@ o.validate = function(self, value)
if v then return v end
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
o.custom_cfgvalue = function(self, section, value)
o.cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
o.write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
@@ -55,11 +53,11 @@ o:depends({ custom = false })
o = s:option(Flag, "realms", translate("Realms"))
o.default = "0"
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ custom = false })
o = s:option(Value, "realm_url", translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ realms = "1" })
o.validate = function(self, value)
value = api.trim(value)
@@ -70,23 +68,23 @@ end
o = s:option(DynamicList, "realm_stun", translate("Realm STUN"))
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ realms = "1" })
o = s:option(Flag, "realm_upnp", translate("Enable") .. " UPnP/NAT-PMP", translate("Enable UPnP/NAT-PMP port mapping on your gateway to improve hole punching success."))
o.default = "0"
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ realms = "1" })
o = s:option(ListValue, "obfs_type", translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:value("gecko")
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ custom = false })
o = s:option(Value, "obfs_password", translate("Obfs Password"))
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ obfs_type = "salamander" })
o:depends({ obfs_type = "gecko" })
@@ -95,31 +93,31 @@ o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ obfs_type = "gecko" })
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Value, "obfs_MaxPacketSize", translate("Gecko Packet Size (max)"))
o.datatype = "uinteger"
o.placeholder = "1200"
o.default = "1200"
o:depends({ obfs_type = "gecko" })
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o = s:option(Flag, "udp", translate("UDP"))
o.default = "1"
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ custom = false })
o = s:option(Value, "up_mbps", translate("Max upload Mbps"))
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ custom = false })
o = s:option(Value, "down_mbps", translate("Max download Mbps"))
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ custom = false })
o = s:option(Flag, "ignoreClientBandwidth", translate("ignoreClientBandwidth"))
o.default = "0"
o.rewrite_option = _n(o.option)
o.rewrite_option = o.option
o:depends({ custom = false })
o = s:option(FileUpload, "tls_certificateFile", translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
@@ -181,4 +179,4 @@ o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
api.luci_types(s1, s)
api.type_cbi_section(s1, s)
+76 -98
View File
@@ -1537,110 +1537,88 @@ function return_map(map)
return map
end
function luci_types(s, s2)
function set_type_cbi(s)
local cbi = require "luci.cbi"
local m = s.map
local id = s2.section
local type_name = s2.type_name
local option_prefix = s2.option_prefix
local fv_type
local field_type = s.fields["type"]
if field_type then
fv_type = field_type:formvalue(id)
local s1 = s.parent
function s.option(self, class, option, ...)
local obj = class(self.map, self, option, ...)
obj.config_option = option
obj.option_prefix = self.option_prefix
obj.option = self.option_prefix .. option
obj.cfgvalue = function(o_self, section)
if o_self.rewrite_option then
return o_self.map:get(section, o_self.rewrite_option)
else
return o_self.map:get(section, o_self.config_option)
end
end
obj.write = function(o_self, section, value)
if s1.fields["type"]:formvalue(self.section) == self.type_name then
local new_val = value
if util.instanceof(o_self, cbi.DynamicList) then
local new_t = {}
if type(value) == "table" then
new_t = table_remove_duplicates(value)
else
new_t = { value }
end
if o_self.cast == "string" then
new_val = table.concat(new_t, " ")
else
new_val = new_t
end
end
if o_self.rewrite_option then
o_self.map:set(section, o_self.rewrite_option, new_val)
else
o_self.map:set(section, o_self.config_option, new_val)
end
end
end
obj.remove = function(o_self, section)
if s1.fields["type"]:formvalue(self.section) == self.type_name then
if o_self.rewrite_option then
o_self.map:del(section, o_self.rewrite_option)
else
o_self.map:del(section, o_self.config_option)
end
end
end
obj.depends = function(o_self, field, value)
local deps
if type(field) == "string" then
deps = {}
deps[field] = value
else
deps = field
end
local new_deps = {}
for k, v in pairs(deps) do
local n_k = k
if self.fields[k] then
n_k = self.fields[k].option
end
new_deps[n_k] = v
end
new_deps["type"] = self.type_name
if next(new_deps) then
table.insert(o_self.deps, new_deps)
end
end
self:append(obj)
self.fields[option] = obj
return obj
end
end
function type_cbi_section(s, s2)
for i, v in ipairs(s2.children) do
local o = s2.children[i]
o.config_option = o.option
o.option_prefix = option_prefix
o.option = option_prefix .. o.option
if not o.not_rewrite then
o.cfgvalue = function(self, section)
-- Add a custom `custom_cfgvalue` attribute. If a custom `custom_cfgvalue` function exists, the custom `cfgvalue` logic will be used.
if self.custom_cfgvalue then
return self:custom_cfgvalue(section)
else
if self.rewrite_option then
return m:get(section, self.rewrite_option)
else
return m:get(section, self.config_option)
end
end
end
o.write = function(self, section, value)
if s.fields["type"]:formvalue(id) == type_name then
-- Add a custom `custom_write` attribute; if a custom `custom_write` function exists, then use the custom write logic.
if self.custom_write then
self:custom_write(section, value)
else
local new_val = value
if util.instanceof(self, cbi.DynamicList) then
local new_t = {}
if type(value) == "table" then
new_t = table_remove_duplicates(value)
else
new_t = { value }
end
if self.cast == "string" then
new_val = table.concat(new_t, " ")
else
new_val = new_t
end
end
if self.rewrite_option then
m:set(section, self.rewrite_option, new_val)
else
m:set(section, self.config_option, new_val)
end
end
end
end
o.remove = function(self, section)
if s.fields["type"]:formvalue(id) == type_name then
-- Add a custom `custom_remove` attribute; if a custom `custom_remove` function exists, use the custom remove logic.
if self.custom_remove then
self:custom_remove(section)
else
if self.rewrite_option then
m:del(section, self.rewrite_option)
else
m:del(section, self.config_option)
end
end
end
end
if #o.deps == 0 then
o:depends({ type = s2.type_name })
end
local deps = o.deps
if #deps > 0 then
local function process_deps(dep)
local rewrite_deps = {}
for k, v in pairs(dep) do
if k:find("!") then
rewrite_deps[k] = v
else
rewrite_deps[option_prefix .. k] = v
end
end
if not rewrite_deps['!reverse'] then
rewrite_deps["type"] = type_name
end
return rewrite_deps
end
for index, value in ipairs(deps) do
local rewrite_deps = process_deps(value)
if rewrite_deps then
deps[index] = rewrite_deps
end
end
else
o:depends({ type = type_name })
end
if fv_type and fv_type ~= type_name then
o.rmempty = true
end
s:append(o)
s.fields[o.option] = o
end
end
+11 -17
View File
@@ -44,6 +44,7 @@ function gen_outbound(flag, node, tag, proxy_table)
local remarks = node.remarks
local proxy_tag = nil
local dialer_proxy_tag = nil
local fragment = nil
local noise = nil
local run_socks_instance = true
@@ -86,12 +87,7 @@ function gen_outbound(flag, node, tag, proxy_table)
node.stream_security = "none"
proxy_tag = "socks <- " .. node_id
else
if proxy_tag then
node.proxySettings = {
tag = proxy_tag,
transportLayer = true
}
end
dialer_proxy_tag = proxy_tag
end
if node.type == "Xray" then
@@ -135,7 +131,6 @@ function gen_outbound(flag, node, tag, proxy_table)
_flag = flag,
_flag_proxy_tag = proxy_tag,
tag = tag,
proxySettings = node.proxySettings or nil,
protocol = node.protocol,
mux = {
enabled = (node.mux == "1") and true or false,
@@ -143,7 +138,7 @@ function gen_outbound(flag, node, tag, proxy_table)
xudpConcurrency = (node.mux == "1" and ((node.xudp_concurrency) and tonumber(node.xudp_concurrency) or 8)) or nil
} or nil,
-- 底层传输配置
streamSettings = (node.streamSettings or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and {
streamSettings = (node.streamSettings or dialer_proxy_tag or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and {
sockopt = {
mark = 255,
domainStrategy = node.domain_strategy or "UseIP",
@@ -154,7 +149,8 @@ function gen_outbound(flag, node, tag, proxy_table)
PrioritizeIPv6 = false,
Interleave = 1,
MaxConcurrentTry = 4
} or nil
} or nil,
dialerProxy = dialer_proxy_tag,
},
[(api.compare_versions(xray_version, "<", "26.7.11")) and "network" or "method"] = node.transport, -- Todo: Remove version check and "network"
security = node.stream_security,
@@ -1209,10 +1205,9 @@ function gen_config(var)
end
if preproxy_outbound then
outbound.tag = preproxy_outbound.tag .. " -> " .. outbound.tag
outbound.proxySettings = {
tag = preproxy_outbound.tag,
transportLayer = true
}
outbound.streamSettings = outbound.streamSettings or {}
outbound.streamSettings.sockopt = outbound.streamSettings.sockopt or {}
outbound.streamSettings.sockopt.dialerProxy = preproxy_outbound.tag
if not exist then
last_insert_outbound = preproxy_outbound
end
@@ -1260,10 +1255,9 @@ function gen_config(var)
if to_outbound then
to_outbound.tag = outbound.tag .. " -> " .. to_outbound.tag
if to_node.type == "Xray" then
to_outbound.proxySettings = {
tag = outbound.tag,
transportLayer = true
}
to_outbound.streamSettings = to_outbound.streamSettings or {}
to_outbound.streamSettings.sockopt = to_outbound.streamSettings.sockopt or {}
to_outbound.streamSettings.sockopt.dialerProxy = outbound.tag
end
table.insert(outbounds_table, to_outbound)
default_outTag = to_outbound.tag
@@ -1,121 +0,0 @@
<%
local map = self.map
local api = map.api
local sid = self.section
-%>
<script type="text/javascript">
//<![CDATA[
function to_edit_node(btn) {
if (!btn) return;
const idReg = /^cbid\..*\..*node$/;
let hidden_select = null;
const selects = document.querySelectorAll('select[id^="cbid."][id*="."][id$="node"]');
for (const sel of selects) {
if ( idReg.test(sel.id) && getComputedStyle(sel).display === "none" && (sel.compareDocumentPosition(btn) & Node.DOCUMENT_POSITION_FOLLOWING)) {
hidden_select = sel;
}
}
if (!hidden_select) return;
let node_select_value = hidden_select?.options[0]?.value;
if (!node_select_value || node_select_value.indexOf("tcp") === 0) {
return;
}
let to_url = '<%=api.url("node_config")%>/' + node_select_value;
if (node_select_value.indexOf("socks_") === 0) {
to_url = '<%=api.url("socks_config")%>/' + node_select_value;
}
location.href = to_url;
}
document.addEventListener('DOMContentLoaded', function () {
function go() {
const node = document.querySelector(".cbi-section-node");
if (!node) return false;
let changed = false;
const all_node = node.querySelectorAll("[id]");
const reg1 = /^cbid\..*node\.main$/;
for (const el of all_node) {
if (!reg1.test(el.id)) continue;
if (el.querySelector(".node-actions")) continue;
const cbid = el.id.replace(/\.main$/, "");
const hidden_select = document.getElementById(cbid);
const node_select_value = hidden_select?.options[0]?.value;
if (!node_select_value) {
continue;
}
let html = '<a href="#" onclick="return to_edit_node(this);"><%:Edit%></a>';
const m = cbid.match(/\.node$/);
if (m) {
html += '<a href="#" onclick="window.open(\'' + '<%=api.url("get_redir_log") .. "?id=" .. sid%>' + '\', \'_blank\')"><%:Log%></a>';
}
html = '<div class="node-actions" style="display:inline-flex; align-items:center; gap:4px; flex-wrap:wrap; margin-left:4px;">' + html + '</div>'
el.insertAdjacentHTML("beforeend", html);
changed = true;
}
return changed;
}
const target = document.querySelector('form') || document.body;
const observer = new MutationObserver(() => go() ? observer.disconnect() : 0);
observer.observe(target, { childList: true, subtree: true });
const timer = setInterval(() => go() ? (clearInterval(timer), observer.disconnect()) : 0, 300);
setTimeout(() => { clearInterval(timer); observer.disconnect(); }, 5000);
});
(function () {
const startTime = Date.now();
const TIMEOUT = 3000;
const waitForDnsSelect = () => {
const dns_select = document.querySelector("select[id*='dns_shunt']");
if (dns_select) {
initDnsSelect(dns_select);
return;
}
if (Date.now() - startTime >= TIMEOUT) {
return;
}
requestAnimationFrame(waitForDnsSelect);
};
waitForDnsSelect();
const initDnsSelect = (dns_select) => {
if (dns_select.value === "chinadns-ng") {
addLogLink(dns_select);
}
if (dns_select._dnsLogBinded) return;
dns_select._dnsLogBinded = true;
dns_select.addEventListener("change", () => {
const existingLogLink = dns_select.parentElement.querySelector("a.dns-log-link");
if (existingLogLink) {
existingLogLink.remove();
}
if (dns_select.value === "chinadns-ng") {
addLogLink(dns_select);
}
});
};
const addLogLink = (select) => {
if (select.parentElement.querySelector("a.dns-log-link")) {
return;
}
const logLink = document.createElement("a");
logLink.innerHTML = "<%:Log%>";
logLink.href = "#";
logLink.className = "dns-log-link";
logLink.style.marginLeft = "10px";
logLink.setAttribute("onclick", "window.open('" + '<%=api.url("get_chinadns_log") .. "?flag=" .. sid%>' + "', '_blank')");
select.insertAdjacentElement("afterend", logLink);
};
})();
//]]>
</script>
@@ -1,59 +0,0 @@
<%
local map = self.map
local api = map.api
local appname = map.config
local section = self.section
-%>
<script type="text/javascript">
//<![CDATA[
const shunt_list = JSON.parse('<%=self.shunt_list%>');
document.addEventListener("DOMContentLoaded", () => {
const id = "cbid.<%=appname%>.<%=section%>.node";
let node = null;
const onChange = (e) => {
const new_val = e.target.value;
const new_hasItem = shunt_list.some(element => element.id == new_val);
if (new_hasItem) {
XHR.get('<%=api.url("update_config")%>', {
id: "<%=section%>",
data: JSON.stringify({
node: new_val,
mode: "1"
})
}, function(x, data) {
if (x && x.status == 200 && data.code == 1) {
window.location.reload();
} else {
alert("<%:Error%>");
}
});
} else {
document.getElementById("cbi-<%=appname%>-shunt_option_list")?.style.setProperty("display", "none");
}
};
const check = () => {
const el = document.getElementById(id);
if (el === node) return;
if (node && !el) {
document.getElementById("cbi-<%=appname%>-shunt_option_list")?.style.setProperty("display", "none");
} else {
let o_hasItem = shunt_list.some(element => element.id == el.value);
if (o_hasItem) {
document.getElementById("cbi-<%=appname%>-shunt_option_list")?.style.setProperty("display", "");
}
}
node = el;
if (node) {
node.addEventListener("change", onChange);
}
};
const observer = new MutationObserver(check);
observer.observe(document.body, {
childList: true,
subtree: true
});
check();
});
//]]>
</script>
@@ -14,11 +14,6 @@ local sid = "@global[0]"
}
}
.shunt-tab-hidden {
display: none !important;
visibility: hidden !important;
}
@media screen and (max-width: 1152px) {
#cbi-<%=appname%>-socks .cbi-section-table-titles {
display: none !important;
@@ -28,7 +23,6 @@ local sid = "@global[0]"
<script type="text/javascript">
//<![CDATA[
let global_id = "<%=sid%>";
const shunt_list = JSON.parse('<%=self.shunt_list%>');
function to_edit_node(btn, stype) {
if (!btn) return;
@@ -235,47 +229,5 @@ local sid = "@global[0]"
select.insertAdjacentElement("afterend", logLink);
};
})();
document.addEventListener("DOMContentLoaded", () => setTimeout(() => {
const hiddenSelect = document.getElementById("cbid.<%=appname%>.<%=sid%>.node");
let o_val = hiddenSelect.value
const o_hasItem = shunt_list.find(element => element.id == o_val);
hiddenSelect.addEventListener("change", function(el){
let new_val = el.target.value
const new_hasItem = shunt_list.find(element => element.id == new_val);
if (new_hasItem) {
XHR.get('<%=api.url("update_config")%>', {
id: "<%=sid%>",
data: JSON.stringify({
node: new_val
})
},
function(x, data) {
if (x && x.status == 200 && data.code == 1) {
window.location.reload();
}
else {
alert("<%:Error%>");
}
});
} else {
try {
document.getElementById("tab.<%=appname%>.<%=sid%>.Shunt").classList.add('shunt-tab-hidden');
document.getElementById("tab.<%=appname%>.<%=sid%>.Shunt").style.display = "none";
} catch (error) {}
try {
document.querySelector('li[data-tab*="Shunt"]').classList.add('shunt-tab-hidden');
document.querySelector('li[data-tab*="Shunt"]').style.display = "none";
} catch (error) {}
}
});
let shunt_taboption = document.getElementById("container.<%=appname%>.<%=sid%>.Shunt");
if (shunt_taboption) {
let shunt_option_list = document.getElementById("cbi-<%=appname%>-shunt_option_list");
if (shunt_option_list) {
shunt_taboption.appendChild(shunt_option_list);
}
}
}, 100));
//]]>
</script>
@@ -1,14 +1,14 @@
<div class="cbi-value" id="cbi-<%=self.config.."-"..section.."-"..self.option%>" data-index="<%=self.index%>" data-depends="<%=pcdata(self:deplist2json(section))%>">
<label class="cbi-value-title">
<%:Switch Mode%>
</label>
<div class="cbi-value-field">
<div>
<input class="btn cbi-button cbi-button-apply" type="button" onclick="switch_gfw_mode()" value="<%:GFW List%>" />
<input class="btn cbi-button cbi-button-apply" type="button" onclick="switch_chnroute_mode()" value="<%:Not China List%>" />
<input class="btn cbi-button cbi-button-apply" type="button" onclick="switch_returnhome_mode()" value="<%:China List%>" />
<input class="btn cbi-button cbi-button-apply" type="button" onclick="switch_global_mode()" value="<%:Global Proxy%>" />
</div>
<%+cbi/valueheader%>
<label class="cbi-value-title">
<%:Switch Mode%>
</label>
<div class="cbi-value-field">
<div>
<input class="btn cbi-button cbi-button-apply" type="button" onclick="switch_gfw_mode()" value="<%:GFW List%>" />
<input class="btn cbi-button cbi-button-apply" type="button" onclick="switch_chnroute_mode()" value="<%:Not China List%>" />
<input class="btn cbi-button cbi-button-apply" type="button" onclick="switch_returnhome_mode()" value="<%:China List%>" />
<input class="btn cbi-button cbi-button-apply" type="button" onclick="switch_global_mode()" value="<%:Global Proxy%>" />
</div>
</div>
@@ -108,3 +108,4 @@
opt.set("udp_proxy_mode", "proxy");
}
</script>
<%+cbi/valuefooter%>
@@ -0,0 +1,73 @@
<%
local map = self.map
local api = map.api
local config = map.config
local verify_option = self.verify_option
local section_id = verify_option.section.section
-%>
<% if verify_option then -%>
<script type="text/javascript">
//<![CDATA[
document.addEventListener("DOMContentLoaded", () => {
const shunt_list = JSON.parse('<%=self.shunt_list%>');
const dom_node_id = "<%=verify_option:cbid(section_id)%>";
let uci_node_val = "";
const onChange = (e) => {
const new_val = e.target.value;
const to_shunt = shunt_list.some(element => element.id == new_val);
if (to_shunt) {
const map = document.getElementById("cbi-<%=config%>");
const hiddenInput = document.createElement('input');
hiddenInput.type = 'hidden';
hiddenInput.name = 'node_save_before';
hiddenInput.value = uci_node_val;
map.appendChild(hiddenInput);
const saveBtn = document.getElementsByClassName('cbi-button-save');
if (saveBtn && saveBtn.length > 0) {
saveBtn[saveBtn.length - 1].click();
}
/*
XHR.get('<%=api.url("update_config")%>', {
id: "<%=section_id%>",
data: JSON.stringify({
node: new_val,
mode: "1"
})
}, function(x, data) {
if (x && x.status == 200 && data.code == 1) {
window.location.reload();
} else {
alert("<%:Error%>");
}
});
*/
} else {
try { shunt.hide(); } catch (error) {}
}
};
const check = () => {
const el = document.getElementById(dom_node_id);
if (!el) {
try { shunt.hide(); } catch (error) {}
return;
}
let is_shunt = shunt_list.some(element => element.id == el.value);
if (is_shunt) {
try { shunt.show(); } catch (error) {}
}
if (!el.hasEventListener) {
uci_node_val = el.value;
el.addEventListener("change", onChange);
el.hasEventListener = true;
}
};
const observer = new MutationObserver(check);
observer.observe(document.body, {
childList: true,
subtree: true
});
check();
});
//]]>
</script>
<%- end %>
@@ -2,18 +2,22 @@
local map = self.map
local api = map.api
local config = map.config
local id = self.id
local s_cfgid = self.s_cfgid
local node_id = self.node_id
local verify_option = self.verify_option
local section_id = self.section_id
local section_type = self.section_type
local tab_name = self.tab_name
-%>
<style>
.hidden {
.shunt_hidden {
display: none !important;
visibility: hidden !important;
}
</style>
<script type="text/javascript">
//<![CDATA[
const normal_list = JSON.parse('<%=self.normal_list%>');
var normal_list = JSON.parse('<%=self.normal_list%>');
function check_fakedns(id, val) {
const dom_id = "cbid.table." + id + ".";
const fakedns_dom = document.getElementById(dom_id + "_fakedns");
@@ -21,12 +25,14 @@ local s_cfgid = self.s_cfgid
const selectNode = document.getElementById(dom_id + "_node");
val = selectNode.value;
}
if (val == "" || val == "_direct") {
fakedns_dom.value = 0;
fakedns_dom.checked = false;
fakedns_dom.classList.add('hidden');
} else {
fakedns_dom.classList.remove('hidden');
if (fakedns_dom) {
if (val == "" || val == "_direct") {
fakedns_dom.value = 0;
fakedns_dom.checked = false;
fakedns_dom.classList.add('shunt_hidden');
} else {
fakedns_dom.classList.remove('shunt_hidden');
}
}
}
function check_proxy_tag(id, val) {
@@ -45,13 +51,13 @@ local s_cfgid = self.s_cfgid
const searchInput = document.getElementById(cbid + ".search");
const listContainer = document.getElementById(cbid + ".list");
lv_change(cbid, listContainer, hiddenSelect, labelSpan, searchInput, "", "<%:Close (Not use)%>");
proxy_tag_dom.classList.add('hidden');
proxy_tag_dom?.classList.add('shunt_hidden');
} else {
proxy_tag_dom.classList.remove('hidden');
proxy_tag_dom?.classList.remove('shunt_hidden');
}
}
function refresh_depends() {
const table_dom = document.getElementById("cbi-passwall-shunt_option_list");
const table_dom = document.getElementById("cbi-<%=config%>-<%=section_type%>");
if (table_dom) {
const trs = table_dom.getElementsByTagName("tr");
for (let i = 1; i < trs.length;i++) {
@@ -60,40 +66,82 @@ local s_cfgid = self.s_cfgid
}
}
}
const shunt = {
tab() {
// Move the shunt options to Tab
<% if tab_name then -%>
const shunt_taboption = document.getElementById("container.<%=config%>.<%=section_id%>.<%=tab_name%>");
if (shunt_taboption) {
const shunt_option_list = document.getElementById("cbi-<%=config%>-<%=section_type%>");
if (shunt_option_list) {
shunt_taboption.appendChild(shunt_option_list);
}
}
<%- end %>
},
hide() {
document.getElementById("cbi-<%=config%>-<%=section_type%>")?.classList.add('shunt_hidden');
<% if tab_name then -%>
try { document.getElementById("tab.<%=config%>.<%=section_id%>.<%=tab_name%>")?.classList.add('shunt_hidden'); } catch (error) {}
try { document.querySelector('li[data-tab*="<%=tab_name%>"]')?.classList.add('shunt_hidden'); } catch (error) {}
const shunt_taboption = document.getElementById("container.<%=config%>.<%=section_id%>.<%=tab_name%>");
if (shunt_taboption) {
[...shunt_taboption.querySelectorAll('[name]')].forEach(el => {
const nameValue = el.getAttribute('name');
el.setAttribute('o-name', nameValue);
el.removeAttribute('name');
});
}
<%- end %>
},
show() {
document.getElementById("cbi-<%=config%>-<%=section_type%>")?.classList.remove('shunt_hidden');
<% if tab_name then -%>
try { document.getElementById("tab.<%=config%>.<%=section_id%>.<%=tab_name%>")?.classList.remove('shunt_hidden'); } catch (error) {}
try { document.querySelector('li[data-tab*="<%=tab_name%>"]')?.classList.remove('shunt_hidden'); } catch (error) {}
const shunt_taboption = document.getElementById("container.<%=config%>.<%=section_id%>.<%=tab_name%>");
if (shunt_taboption) {
[...shunt_taboption.querySelectorAll('[o-name]')].forEach(el => {
const nameValue = el.getAttribute('o-name');
el.setAttribute('name', nameValue);
el.removeAttribute('o-name');
});
}
<%- end %>
}
}
document.addEventListener("DOMContentLoaded", function () {
shunt.tab();
waitForElement('select[name*="<%=config%>"][name*="shunt_group"]', function(el) {
let o_val = el.value;
el.addEventListener("change", () => {
el.blur();
if (o_val != el.value) {
let save = true;
if (save) {
update_config("<%=id%>", {
shunt_group: getOption("<%=config%>", "<%=s_cfgid%>", "shunt_group").value,
}, get_current_url());
}
update_config("<%=node_id%>", {
shunt_group: getOption("<%=config%>", "<%=section_id%>", "shunt_group").value,
}, get_current_url());
}
});
});
});
document.addEventListener("DOMContentLoaded", () => setTimeout(() => {
refresh_depends();
const table_dom = document.getElementById("cbi-passwall-shunt_option_list");
if (table_dom) {
const trs = table_dom.getElementsByTagName("tr");
for (let i = 1; i < trs.length;i++) {
const selectNode = document.getElementById("cbid.table." + i + "._node.main");
selectNode.addEventListener("change", function(el){
let new_val = el.target.value
check_fakedns(i, new_val);
check_proxy_tag(i, new_val);
});
if (i == trs.length - 1) {
const newArray = window.lv_dropdown_data["cbid.table." + i + "._node"].ungrouped.filter(item => item.key !== "_default");
window.lv_dropdown_data["cbid.table." + i + "._node"].ungrouped = newArray
setTimeout(() => {
refresh_depends();
const table_dom = document.getElementById("cbi-<%=config%>-<%=section_type%>");
if (table_dom) {
const trs = table_dom.getElementsByTagName("tr");
for (let i = 1; i < trs.length;i++) {
const selectNode = document.getElementById("cbid.table." + i + "._node.main");
selectNode.addEventListener("change", function(el){
let new_val = el.target.value
check_fakedns(i, new_val);
check_proxy_tag(i, new_val);
});
if (i == trs.length - 1) {
const newArray = window.lv_dropdown_data["cbid.table." + i + "._node"].ungrouped.filter(item => item.key !== "_default");
window.lv_dropdown_data["cbid.table." + i + "._node"].ungrouped = newArray
}
}
}
}
}, 100));
}, 200)
});
//]]>
</script>
@@ -35,27 +35,30 @@ local config = map.config
});
waitForElement('select[name*="<%=config%>"][name*="protocol"]', function(el) {
let o_val = el.value;
const name_split = el.name.split(".");
const name = name_split[name_split.length - 1];
el.addEventListener("change", () => {
el.blur();
if (el.value.startsWith("_") || (o_val.startsWith("_") && !el.value.startsWith("_"))) {
let name_split = el.name.split(".");
let name = name_split[name_split.length - 1];
let save = true;
if (save) {
/*
const saveBtn = document.getElementsByClassName('cbi-button-save');
if (saveBtn && saveBtn.length > 0) {
saveBtn[saveBtn.length - 1].click();
}
*/
update_config(node_id, {
remarks: getOption("<%=config%>", "<%=sid%>", "remarks").value,
group: getOption("<%=config%>", "<%=sid%>", "group").value,
protocol: getOption("<%=config%>", "<%=sid%>", name).value,
}, node_config_url);
} else {
window.location.href = node_config_url + "?select_proto=" + encodeURIComponent(el.value);
if (el.value.startsWith("_")) {
const map = document.getElementById("cbi-<%=config%>");
const hiddenInput = document.createElement('input');
hiddenInput.type = 'hidden';
hiddenInput.name = 'load' + el.value;
hiddenInput.value = '1';
map.appendChild(hiddenInput);
}
const saveBtn = document.getElementsByClassName('cbi-button-save');
if (saveBtn && saveBtn.length > 0) {
saveBtn[saveBtn.length - 1].click();
}
/*
update_config(node_id, {
remarks: getOption("<%=config%>", "<%=sid%>", "remarks").value,
group: getOption("<%=config%>", "<%=sid%>", "group").value,
protocol: getOption("<%=config%>", "<%=sid%>", name).value,
}, node_config_url);
*/
}
});
});
+3
View File
@@ -1295,6 +1295,9 @@ msgstr "访问控制"
msgid "ACLs is a tools which used to designate specific IP proxy mode."
msgstr "访问控制列表是用于指定特殊 IP 代理模式的工具。"
msgid "Use global configuration when using the global node."
msgstr "与全局节点相同时,将使用全局配置。"
msgid "Example:"
msgstr "例:"
+162 -170
View File
@@ -566,11 +566,7 @@ start_global() {
local node_socks_bind_local=$(config_n_get @global[0] node_socks_bind_local 1)
local node_socks_bind="127.0.0.1"
[ "${node_socks_bind_local}" != "1" ] && node_socks_bind="0.0.0.0"
local global_socks_port=$(config_n_get @global[0] node_socks_port 1070)
GLOBAL_SOCKS_port=$(get_new_port $global_socks_port)
if [ "$GLOBAL_SOCKS_port" != "$global_socks_port" ]; then
echolog "注意:全局节点 Socks 端口冲突,原端口 ${global_socks_port} 已自动更改为 ${GLOBAL_SOCKS_port}!"
fi
GLOBAL_SOCKS_port=$(config_n_get @global[0] node_socks_port 1070)
GLOBAL_HTTP_port=$(config_n_get @global[0] node_http_port 0)
[ "$GLOBAL_HTTP_port" != "0" ] && local on_node_http=1
if [ $PROXY_IPV6 = "1" ]; then
@@ -1390,6 +1386,7 @@ acl_app() {
log=${log:-0}
loglevel=${loglevel:-warn}
log_chinadns_ng=${log_chinadns_ng:-0}
if [ -n "${sources}" ]; then
for s in $sources; do
@@ -1445,7 +1442,10 @@ acl_app() {
[ -n "$node" ] && {
local GLOBAL_NODE=$(get_cache_var "ACL_GLOBAL_node")
[ -n "${GLOBAL_NODE}" ] && GLOBAL_redir_port=$(get_cache_var "ACL_GLOBAL_redir_port")
[ -n "${GLOBAL_NODE}" ] && {
local GLOBAL_redir_port=$(get_cache_var "ACL_GLOBAL_redir_port")
[ "$node" = "${GLOBAL_NODE}" ] && node="default"
}
if [ "$node" = "default" ]; then
if [ -n "${GLOBAL_NODE}" ]; then
set_cache_var "ACL_${sid}_node" "${GLOBAL_NODE}"
@@ -1457,187 +1457,179 @@ acl_app() {
echolog " - 全局节点未启用,跳过【${remarks}】"
fi
else
[ "$(config_get_type $node)" = "nodes" ] || [ "$(config_get_type $node)" = "socks" ] && {
if [ -n "${GLOBAL_NODE}" ] && [ "$node" = "${GLOBAL_NODE}" ]; then
set_cache_var "ACL_${sid}_node" "${GLOBAL_NODE}"
set_cache_var "ACL_${sid}_redir_port" "${GLOBAL_redir_port}"
set_cache_var "ACL_${sid}_dns_port" "${GLOBAL_DNSMASQ_PORT}"
set_cache_var "ACL_${sid}_default" "1"
[ "$GLOBAL_SHUNT_NODE_FAKEDNS" = "1" ] && use_fakedns=1
([ "$(config_get_type $node)" = "nodes" ] || [ "$(config_get_type $node)" = "socks" ]) && {
local type protocol
if [ "$(config_get_type $node)" = "socks" ]; then
if [ "${dns_mode}" = "xray" ]; then
type="xray"
elif [ "${dns_mode}" = "sing-box" ]; then
type="sing-box"
elif [ -n "${SINGBOX_BIN}" ]; then
type="sing-box"
elif [ -n "${XRAY_BIN}" ]; then
type="xray"
fi
else
local type protocol
if [ "$(config_get_type $node)" = "socks" ]; then
if [ "${dns_mode}" = "xray" ]; then
type="xray"
elif [ "${dns_mode}" = "sing-box" ]; then
type="sing-box"
elif [ -n "${SINGBOX_BIN}" ]; then
type="sing-box"
elif [ -n "${XRAY_BIN}" ]; then
type="xray"
type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
protocol=$(config_n_get $node protocol)
fi
([ "$type" = "sing-box" ] || [ "$type" = "xray" ]) && [ "$protocol" = "_shunt" ] && [ "$type" != "$dns_mode" ] && {
dns_mode=$type
[ "$type" = "xray" ] && {
case "$v2ray_dns_mode" in http3|tls|quic)
v2ray_dns_mode="tcp"
remote_dns="1.1.1.1#53"
;;
esac
}
}
dns_cache_key="${dns_mode}_${remote_dns}_${v2ray_dns_mode:-none}_${remote_dns_client_ip:-0}_${remote_fakedns:-0}_${remote_rewrite_ttl:-30}"
([ "$v2ray_dns_mode" = "doh" ] || [ "$v2ray_dns_mode" = "http3" ]) && {
dns_cache_key="${dns_mode}_${remote_dns_doh:-https://1.1.1.1/dns-query}_${v2ray_dns_mode:-doh}_${remote_dns_client_ip:-0}_${remote_fakedns:-0}_${remote_rewrite_ttl:-30}"
}
if [ "$remote_fakedns" = "1" ] || ([ "$protocol" = "_shunt" ] && [ "$(config_n_get $node fakedns)" = "1" ]); then
use_fakedns=1
fi
run_dns() {
local _dns_port
[ -n $1 ] && _dns_port=$1
[ -z ${_dns_port} ] && {
dns_port=$(get_new_port $(expr $dns_port + 1))
_dns_port=$dns_port
if [ "$dns_mode" = "dns2socks" ]; then
run_dns2socks flag=acl_${sid} socks_address=127.0.0.1 socks_port=$socks_port listen_address=0.0.0.0 listen_port=${_dns_port} dns=$remote_dns cache=1
elif [ "$dns_mode" = "sing-box" ] || [ "$dns_mode" = "xray" ]; then
config_file=$TMP_ACL_PATH/${node}_SOCKS_${socks_port}_DNS.json
remote_dns_doh=${remote_dns_doh:-https://1.1.1.1/dns-query}
local type=${dns_mode}
[ "${dns_mode}" = "sing-box" ] && type="singbox"
dnsmasq_filter_proxy_ipv6=0
remote_dns_query_strategy="UseIP"
[ "$filter_proxy_ipv6" = "1" ] && remote_dns_query_strategy="UseIPv4"
run_${type} flag=acl_${sid} type=$dns_mode dns_socks_address=127.0.0.1 dns_socks_port=$socks_port dns_listen_port=${_dns_port} remote_dns_protocol=${v2ray_dns_mode} remote_dns_udp_server=${remote_dns} remote_dns_tcp_server=${remote_dns} remote_dns_doh="${remote_dns_doh}" remote_dns_query_strategy=${remote_dns_query_strategy} remote_dns_client_ip=${remote_dns_client_ip} config_file=$config_file
fi
set_cache_var "node_${node}_$(echo -n "${dns_cache_key}" | md5sum | cut -d " " -f1)" "${_dns_port}"
}
[ "$dns_shunt" = "chinadns-ng" ] && [ -n "$(first_type chinadns-ng)" ] && {
chinadns_ng_min=2024.04.13
chinadns_ng_now=$($(first_type chinadns-ng) -V | grep -i "ChinaDNS-NG " | awk '{print $2}')
if [ $(check_ver "$chinadns_ng_now" "$chinadns_ng_min") = 1 ]; then
echolog " * 注意:当前 ChinaDNS-NG 版本为[ $chinadns_ng_now ],请更新到[ $chinadns_ng_min ]或以上版本,否则 DNS 有可能无法正常工作!"
fi
[ "$filter_proxy_ipv6" = "1" ] && dnsmasq_filter_proxy_ipv6=0
chinadns_port=$(expr $chinadns_port + 1)
_china_ng_listen="127.0.0.1#${chinadns_port},::1#${chinadns_port}"
_chinadns_local_dns=$(IFS=','; set -- $LOCAL_DNS; [ "${1%%[#:]*}" = "127.0.0.1" ] && echo "$1" || ([ -n "$2" ] && echo "$1,$2" || echo "$1"))
_direct_dns_mode=$(config_n_get @global[0] direct_dns_mode "auto")
case "${_direct_dns_mode}" in
udp)
_chinadns_local_dns=$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")
;;
tcp)
_chinadns_local_dns="tcp://$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")"
;;
esac
run_chinadns_ng \
_flag="$sid" \
_listen_port=${chinadns_port} \
_dns_local=${_chinadns_local_dns} \
_dns_trust=127.0.0.1#${_dns_port} \
_no_ipv6_trust=${filter_proxy_ipv6} \
_use_direct_list=${use_direct_list} \
_use_proxy_list=${use_proxy_list} \
_use_block_list=${use_block_list} \
_gfwlist=${use_gfw_list} \
_chnlist=${chn_list} \
_default_mode=${tcp_proxy_mode} \
_default_tag=${chinadns_ng_default_tag:-smart} \
_no_logic_log=1 \
_node=${node} \
_filter_https=${force_https_soa:-0} \
_log=${log_chinadns_ng}
use_default_dns="chinadns_ng"
}
dnsmasq_port=$(get_new_port $(expr $dnsmasq_port + 1))
local dnsmasq_conf=${acl_path}/dnsmasq.conf
local dnsmasq_conf_path=${acl_path}/dnsmasq.d
lua $APP_PATH/helper_dnsmasq.lua add_rule -FLAG ${sid} -TMP_DNSMASQ_PATH ${dnsmasq_conf_path} -DNSMASQ_CONF_FILE ${dnsmasq_conf} \
-LISTEN_PORT ${dnsmasq_port} -DEFAULT_DNS ${DEFAULT_DNS} -LOCAL_DNS $LOCAL_DNS \
-USE_DIRECT_LIST "${use_direct_list}" -USE_PROXY_LIST "${use_proxy_list}" -USE_BLOCK_LIST "${use_block_list}" -USE_GFW_LIST "${use_gfw_list}" -CHN_LIST "${chn_list}" \
-TUN_DNS "127.0.0.1#${_dns_port}" -USE_DEFAULT_DNS "${use_default_dns:-direct}" -CHINADNS_DNS ${_china_ng_listen:-0} \
-NODE $node -DEFAULT_PROXY_MODE ${tcp_proxy_mode} -NO_PROXY_IPV6 ${dnsmasq_filter_proxy_ipv6:-0} -NFTFLAG ${nftflag:-0} \
-NO_LOGIC_LOG 1
ln_run "$(first_type dnsmasq)" "dnsmasq_${sid}" "/dev/null" -C ${dnsmasq_conf} -x ${acl_path}/dnsmasq.pid
set_cache_var "ACL_${sid}_dns_port" "${dnsmasq_port}"
set_cache_var "node_${node}_$(echo -n "${tcp_proxy_mode}_${dns_cache_key}" | md5sum | cut -d " " -f1)" "${dnsmasq_port}"
#dhcp.leases to hosts
$APP_PATH/lease2hosts.sh > /dev/null 2>&1 &
}
_redir_port=$(get_cache_var "node_${node}_redir_port")
_socks_port=$(get_cache_var "node_${node}_socks_port")
if [ -n "${_socks_port}" ] && [ -n "${_redir_port}" ]; then
socks_port=${_socks_port}
node_port=${_redir_port}
_dnsmasq_port=$(get_cache_var "node_${node}_$(echo -n "${tcp_proxy_mode}_${dns_cache_key}" | md5sum | cut -d " " -f1)")
if [ -z "${_dnsmasq_port}" ]; then
_dns_port=$(get_cache_var "node_${node}_$(echo -n "${dns_cache_key}" | md5sum | cut -d " " -f1)")
run_dns ${_dns_port}
else
type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
protocol=$(config_n_get $node protocol)
[ -n "${_dnsmasq_port}" ] && set_cache_var "ACL_${sid}_dns_port" "${_dnsmasq_port}"
fi
([ "$type" = "sing-box" ] || [ "$type" = "xray" ]) && [ "$protocol" = "_shunt" ] && [ "$type" != "$dns_mode" ] && {
dns_mode=$type
[ "$type" = "xray" ] && {
case "$v2ray_dns_mode" in http3|tls|quic)
v2ray_dns_mode="tcp"
remote_dns="1.1.1.1#53"
;;
esac
}
}
dns_cache_key="${dns_mode}_${remote_dns}_${v2ray_dns_mode:-none}_${remote_dns_client_ip:-0}_${remote_fakedns:-0}_${remote_rewrite_ttl:-30}"
([ "$v2ray_dns_mode" = "doh" ] || [ "$v2ray_dns_mode" = "http3" ]) && {
dns_cache_key="${dns_mode}_${remote_dns_doh:-https://1.1.1.1/dns-query}_${v2ray_dns_mode:-doh}_${remote_dns_client_ip:-0}_${remote_fakedns:-0}_${remote_rewrite_ttl:-30}"
}
else
socks_port=$(get_new_port $(expr $socks_port + 1))
set_cache_var "node_${node}_socks_port" "${socks_port}"
redir_port=$(get_new_port $(expr $redir_port + 1))
set_cache_var "node_${node}_redir_port" "${redir_port}"
node_port=$redir_port
local log_file="/dev/null"
[ "${log}" = "1" ] && log_file="${TMP_ACL_PATH}/${sid}/node.log"
if [ "$remote_fakedns" = "1" ] || ([ "$protocol" = "_shunt" ] && [ "$(config_n_get $node fakedns)" = "1" ]); then
use_fakedns=1
fi
run_dns() {
local _dns_port
[ -n $1 ] && _dns_port=$1
[ -z ${_dns_port} ] && {
if [ "${type}" = "sing-box" ] || [ "${type}" = "xray" ]; then
config_file="acl/${node}_${redir_port}.json"
_extra_param="socks_address=127.0.0.1 socks_port=$socks_port"
[ "${type}" = "${dns_mode}" ] && {
dns_port=$(get_new_port $(expr $dns_port + 1))
_dns_port=$dns_port
if [ "$dns_mode" = "dns2socks" ]; then
run_dns2socks flag=acl_${sid} socks_address=127.0.0.1 socks_port=$socks_port listen_address=0.0.0.0 listen_port=${_dns_port} dns=$remote_dns cache=1
elif [ "$dns_mode" = "sing-box" ] || [ "$dns_mode" = "xray" ]; then
config_file=$TMP_ACL_PATH/${node}_SOCKS_${socks_port}_DNS.json
remote_dns_doh=${remote_dns_doh:-https://1.1.1.1/dns-query}
local type=${dns_mode}
[ "${dns_mode}" = "sing-box" ] && type="singbox"
dnsmasq_filter_proxy_ipv6=0
remote_dns_query_strategy="UseIP"
[ "$filter_proxy_ipv6" = "1" ] && remote_dns_query_strategy="UseIPv4"
run_${type} flag=acl_${sid} type=$dns_mode dns_socks_address=127.0.0.1 dns_socks_port=$socks_port dns_listen_port=${_dns_port} remote_dns_protocol=${v2ray_dns_mode} remote_dns_udp_server=${remote_dns} remote_dns_tcp_server=${remote_dns} remote_dns_doh="${remote_dns_doh}" remote_dns_query_strategy=${remote_dns_query_strategy} remote_dns_client_ip=${remote_dns_client_ip} config_file=$config_file
fi
set_cache_var "node_${node}_$(echo -n "${dns_cache_key}" | md5sum | cut -d " " -f1)" "${_dns_port}"
dnsmasq_filter_proxy_ipv6=0
remote_dns_query_strategy="UseIP"
[ "$filter_proxy_ipv6" = "1" ] && remote_dns_query_strategy="UseIPv4"
remote_dns_doh=${remote_dns_doh:-https://1.1.1.1/dns-query}
_extra_param="${_extra_param} dns_listen_port=${_dns_port} remote_dns_protocol=${v2ray_dns_mode} remote_dns_udp_server=${remote_dns} remote_dns_tcp_server=${remote_dns}"
_extra_param="${_extra_param} remote_dns_doh=${remote_dns_doh} remote_dns_query_strategy=${remote_dns_query_strategy} remote_fakedns=${remote_fakedns:-0} remote_dns_client_ip=${remote_dns_client_ip}"
}
[ "$dns_shunt" = "chinadns-ng" ] && [ -n "$(first_type chinadns-ng)" ] && {
chinadns_ng_min=2024.04.13
chinadns_ng_now=$($(first_type chinadns-ng) -V | grep -i "ChinaDNS-NG " | awk '{print $2}')
if [ $(check_ver "$chinadns_ng_now" "$chinadns_ng_min") = 1 ]; then
echolog " * 注意:当前 ChinaDNS-NG 版本为[ $chinadns_ng_now ],请更新到[ $chinadns_ng_min ]或以上版本,否则 DNS 有可能无法正常工作!"
fi
[ "$filter_proxy_ipv6" = "1" ] && dnsmasq_filter_proxy_ipv6=0
chinadns_port=$(expr $chinadns_port + 1)
_china_ng_listen="127.0.0.1#${chinadns_port},::1#${chinadns_port}"
_chinadns_local_dns=$(IFS=','; set -- $LOCAL_DNS; [ "${1%%[#:]*}" = "127.0.0.1" ] && echo "$1" || ([ -n "$2" ] && echo "$1,$2" || echo "$1"))
_direct_dns_mode=$(config_n_get @global[0] direct_dns_mode "auto")
case "${_direct_dns_mode}" in
udp)
_chinadns_local_dns=$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")
;;
tcp)
_chinadns_local_dns="tcp://$(normalize_dns "$(config_n_get @global[0] direct_dns 223.5.5.5:53)")"
;;
esac
run_chinadns_ng \
_flag="$sid" \
_listen_port=${chinadns_port} \
_dns_local=${_chinadns_local_dns} \
_dns_trust=127.0.0.1#${_dns_port} \
_no_ipv6_trust=${filter_proxy_ipv6} \
_use_direct_list=${use_direct_list} \
_use_proxy_list=${use_proxy_list} \
_use_block_list=${use_block_list} \
_gfwlist=${use_gfw_list} \
_chnlist=${chn_list} \
_default_mode=${tcp_proxy_mode} \
_default_tag=${chinadns_ng_default_tag:-smart} \
_no_logic_log=1 \
_node=${node} \
_filter_https=${force_https_soa:-0} \
_log=${log}
use_default_dns="chinadns_ng"
_extra_param="${_extra_param} tcp_proxy_way=$TCP_PROXY_WAY"
config_file="$TMP_PATH/$config_file"
[ "${type}" = "sing-box" ] && {
type="singbox"
_extra_param="${_extra_param} remote_rewrite_ttl=${remote_rewrite_ttl:-30}"
}
dnsmasq_port=$(get_new_port $(expr $dnsmasq_port + 1))
local dnsmasq_conf=${acl_path}/dnsmasq.conf
local dnsmasq_conf_path=${acl_path}/dnsmasq.d
lua $APP_PATH/helper_dnsmasq.lua add_rule -FLAG ${sid} -TMP_DNSMASQ_PATH ${dnsmasq_conf_path} -DNSMASQ_CONF_FILE ${dnsmasq_conf} \
-LISTEN_PORT ${dnsmasq_port} -DEFAULT_DNS ${DEFAULT_DNS} -LOCAL_DNS $LOCAL_DNS \
-USE_DIRECT_LIST "${use_direct_list}" -USE_PROXY_LIST "${use_proxy_list}" -USE_BLOCK_LIST "${use_block_list}" -USE_GFW_LIST "${use_gfw_list}" -CHN_LIST "${chn_list}" \
-TUN_DNS "127.0.0.1#${_dns_port}" -USE_DEFAULT_DNS "${use_default_dns:-direct}" -CHINADNS_DNS ${_china_ng_listen:-0} \
-NODE $node -DEFAULT_PROXY_MODE ${tcp_proxy_mode} -NO_PROXY_IPV6 ${dnsmasq_filter_proxy_ipv6:-0} -NFTFLAG ${nftflag:-0} \
-NO_LOGIC_LOG 1
ln_run "$(first_type dnsmasq)" "dnsmasq_${sid}" "/dev/null" -C ${dnsmasq_conf} -x ${acl_path}/dnsmasq.pid
set_cache_var "ACL_${sid}_dns_port" "${dnsmasq_port}"
set_cache_var "node_${node}_$(echo -n "${tcp_proxy_mode}_${dns_cache_key}" | md5sum | cut -d " " -f1)" "${dnsmasq_port}"
#dhcp.leases to hosts
$APP_PATH/lease2hosts.sh > /dev/null 2>&1 &
}
_redir_port=$(get_cache_var "node_${node}_redir_port")
_socks_port=$(get_cache_var "node_${node}_socks_port")
if [ -n "${_socks_port}" ] && [ -n "${_redir_port}" ]; then
socks_port=${_socks_port}
node_port=${_redir_port}
_dnsmasq_port=$(get_cache_var "node_${node}_$(echo -n "${tcp_proxy_mode}_${dns_cache_key}" | md5sum | cut -d " " -f1)")
if [ -z "${_dnsmasq_port}" ]; then
_dns_port=$(get_cache_var "node_${node}_$(echo -n "${dns_cache_key}" | md5sum | cut -d " " -f1)")
run_dns ${_dns_port}
else
[ -n "${_dnsmasq_port}" ] && set_cache_var "ACL_${sid}_dns_port" "${_dnsmasq_port}"
fi
_extra_param="${_extra_param} use_proxy_list=$use_proxy_list use_gfw_list=$use_gfw_list chn_list=$chn_list"
run_${type} flag=$node node=$node redir_port=$redir_port ${_extra_param} config_file=$config_file log_file=$log_file loglevel=$loglevel
else
socks_port=$(get_new_port $(expr $socks_port + 1))
set_cache_var "node_${node}_socks_port" "${socks_port}"
redir_port=$(get_new_port $(expr $redir_port + 1))
set_cache_var "node_${node}_redir_port" "${redir_port}"
node_port=$redir_port
local log_file="/dev/null"
[ "${log}" = "1" ] && log_file="${TMP_ACL_PATH}/${sid}/node.log"
if [ "${type}" = "sing-box" ] || [ "${type}" = "xray" ]; then
config_file="acl/${node}_${redir_port}.json"
_extra_param="socks_address=127.0.0.1 socks_port=$socks_port"
[ "${type}" = "${dns_mode}" ] && {
dns_port=$(get_new_port $(expr $dns_port + 1))
_dns_port=$dns_port
dnsmasq_filter_proxy_ipv6=0
remote_dns_query_strategy="UseIP"
[ "$filter_proxy_ipv6" = "1" ] && remote_dns_query_strategy="UseIPv4"
remote_dns_doh=${remote_dns_doh:-https://1.1.1.1/dns-query}
_extra_param="${_extra_param} dns_listen_port=${_dns_port} remote_dns_protocol=${v2ray_dns_mode} remote_dns_udp_server=${remote_dns} remote_dns_tcp_server=${remote_dns}"
_extra_param="${_extra_param} remote_dns_doh=${remote_dns_doh} remote_dns_query_strategy=${remote_dns_query_strategy} remote_fakedns=${remote_fakedns:-0} remote_dns_client_ip=${remote_dns_client_ip}"
}
_extra_param="${_extra_param} tcp_proxy_way=$TCP_PROXY_WAY"
config_file="$TMP_PATH/$config_file"
[ "${type}" = "sing-box" ] && {
type="singbox"
_extra_param="${_extra_param} remote_rewrite_ttl=${remote_rewrite_ttl:-30}"
}
_extra_param="${_extra_param} use_proxy_list=$use_proxy_list use_gfw_list=$use_gfw_list chn_list=$chn_list"
run_${type} flag=$node node=$node redir_port=$redir_port ${_extra_param} config_file=$config_file log_file=$log_file loglevel=$loglevel
else
config_file="acl/${node}_SOCKS_${socks_port}.json"
run_socks flag=$node node=$node bind=127.0.0.1 socks_port=$socks_port config_file=$config_file log_file=$log_file
# log_file=$TMP_ACL_PATH/ipt2socks_${node}_${redir_port}.log
log_file="/dev/null"
run_ipt2socks flag=acl_${node} tcp_tproxy=${is_tproxy} local_port=$redir_port socks_address=127.0.0.1 socks_port=$socks_port log_file=$log_file
fi
run_dns ${_dns_port}
config_file="acl/${node}_SOCKS_${socks_port}.json"
run_socks flag=$node node=$node bind=127.0.0.1 socks_port=$socks_port config_file=$config_file log_file=$log_file
# log_file=$TMP_ACL_PATH/ipt2socks_${node}_${redir_port}.log
log_file="/dev/null"
run_ipt2socks flag=acl_${node} tcp_tproxy=${is_tproxy} local_port=$redir_port socks_address=127.0.0.1 socks_port=$socks_port log_file=$log_file
fi
set_cache_var "ACL_${sid}_node" "${node}"
set_cache_var "ACL_${sid}_redir_port" "${node_port}"
run_dns ${_dns_port}
fi
set_cache_var "ACL_${sid}_node" "${node}"
set_cache_var "ACL_${sid}_redir_port" "${node_port}"
}
fi
[ "${use_fakedns}" = "1" ] && set_cache_var "ACL_${sid}_fakedns" "1"
}
unset enabled sid remarks sources interface tcp_no_redir_ports udp_no_redir_ports use_global_config node use_direct_list use_proxy_list use_block_list use_gfw_list chn_list tcp_proxy_mode udp_proxy_mode filter_proxy_ipv6 dns_mode remote_dns v2ray_dns_mode remote_dns_doh remote_dns_client_ip
unset _ip _mac _iprange _ipset _ip_or_mac source_list node_port config_file _extra_param dns_cache_key log loglevel
unset _ip _mac _iprange _ipset _ip_or_mac source_list node_port config_file _extra_param dns_cache_key log loglevel log_chinadns_ng
unset _china_ng_listen _chinadns_local_dns _direct_dns_mode chinadns_ng_default_tag dnsmasq_filter_proxy_ipv6 remote_fakedns force_https_soa use_fakedns remote_rewrite_ttl
done
unset socks_port redir_port dns_port dnsmasq_port chinadns_port
@@ -236,6 +236,12 @@ load_acl() {
}
[ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port")
[ -n "$(get_cache_var "ACL_${sid}_fakedns")" ] && use_fakedns=$(get_cache_var "ACL_${sid}_fakedns")
([ -n "$node" ] && ([ "$node" = "default" ] || [ "$node" = "$NODE" ])) && {
use_global_config=1
unset node
}
[ -n "$node" ] && {
if [ "$(config_get_type $node)" = "socks" ]; then
node_remark="Socks 配置($(config_n_get $node port) 端口)"
@@ -296,6 +296,12 @@ load_acl() {
}
[ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port")
[ -n "$(get_cache_var "ACL_${sid}_fakedns")" ] && use_fakedns=$(get_cache_var "ACL_${sid}_fakedns")
([ -n "$node" ] && ([ "$node" = "default" ] || [ "$node" = "$NODE" ])) && {
use_global_config=1
unset node
}
[ -n "$node" ] && {
if [ "$(config_get_type $node)" = "socks" ]; then
node_remark="Socks 配置($(config_n_get $node port) 端口)"