luci-app-passwall2: sync upstream

This commit is contained in:
actions 2024-04-12 00:00:07 +08:00
parent 2c76d81a42
commit 174fc1ed8d
14 changed files with 194 additions and 186 deletions

View File

@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2 PKG_NAME:=luci-app-passwall2
PKG_VERSION:=1.28-5 PKG_VERSION:=1.28-6
PKG_RELEASE:= PKG_RELEASE:=
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \

View File

@ -316,7 +316,7 @@ o.rmempty = false
o = s:taboption("DNS", Button, "clear_ipset", translate("Clear IPSet"), translate("Try this feature if the rule modification does not take effect.")) o = s:taboption("DNS", Button, "clear_ipset", translate("Clear IPSet"), translate("Try this feature if the rule modification does not take effect."))
o.inputstyle = "remove" o.inputstyle = "remove"
function o.write(e, e) function o.write(e, e)
luci.sys.call("[ -n \"$(nft list sets 2>/dev/null | grep \"passwall2_\")\" ] && sh /usr/share/" .. appname .. "/nftables.sh flush_nftset || sh /usr/share/" .. appname .. "/iptables.sh flush_ipset > /dev/null 2>&1 &") luci.sys.call('[ -n "$(nft list sets 2>/dev/null | grep \"passwall2_\")" ] && sh /usr/share/passwall2/nftables.sh flush_nftset_reload || sh /usr/share/passwall2/iptables.sh flush_ipset_reload > /dev/null 2>&1 &')
luci.http.redirect(api.url("log")) luci.http.redirect(api.url("log"))
end end

View File

@ -121,6 +121,8 @@ domain_list.validate = function(self, value)
flag = 0 flag = 0
elseif host:find("ext:") and host:find("ext:") == 1 then elseif host:find("ext:") and host:find("ext:") == 1 then
flag = 0 flag = 0
elseif host:find("#") and host:find("#") == 1 then
flag = 0
end end
if flag == 1 then if flag == 1 then
if not datatypes.hostname(tmp_host) then if not datatypes.hostname(tmp_host) then
@ -135,7 +137,7 @@ domain_list.description = "<br /><ul><li>" .. translate("Plaintext: If this stri
.. "</li><li>" .. translate("Subdomain (recommended): Begining with 'domain:' and the rest is a domain. When the targeting domain is exactly the value, or is a subdomain of the value, this rule takes effect. Example: rule 'domain:v2ray.com' matches 'www.v2ray.com', 'v2ray.com', but not 'xv2ray.com'.") .. "</li><li>" .. translate("Subdomain (recommended): Begining with 'domain:' and the rest is a domain. When the targeting domain is exactly the value, or is a subdomain of the value, this rule takes effect. Example: rule 'domain:v2ray.com' matches 'www.v2ray.com', 'v2ray.com', but not 'xv2ray.com'.")
.. "</li><li>" .. translate("Full domain: Begining with 'full:' and the rest is a domain. When the targeting domain is exactly the value, the rule takes effect. Example: rule 'domain:v2ray.com' matches 'v2ray.com', but not 'www.v2ray.com'.") .. "</li><li>" .. translate("Full domain: Begining with 'full:' and the rest is a domain. When the targeting domain is exactly the value, the rule takes effect. Example: rule 'domain:v2ray.com' matches 'v2ray.com', but not 'www.v2ray.com'.")
.. "</li><li>" .. translate("Pre-defined domain list: Begining with 'geosite:' and the rest is a name, such as geosite:google or geosite:cn.") .. "</li><li>" .. translate("Pre-defined domain list: Begining with 'geosite:' and the rest is a name, such as geosite:google or geosite:cn.")
.. "</li><li>" .. translate("Domains from file: Such as 'ext:file:tag'. The value must begin with ext: (lowercase), and followed by filename and tag. The file is placed in resource directory, and has the same format of geosite.dat. The tag must exist in the file.") .. "</li><li>" .. translate("Annotation: Begining with #")
.. "</li></ul>" .. "</li></ul>"
ip_list = s:option(TextValue, "ip_list", "IP") ip_list = s:option(TextValue, "ip_list", "IP")
ip_list.rows = 10 ip_list.rows = 10
@ -146,6 +148,7 @@ ip_list.validate = function(self, value)
for index, ipmask in ipairs(ipmasks) do for index, ipmask in ipairs(ipmasks) do
if ipmask:find("geoip:") and ipmask:find("geoip:") == 1 then if ipmask:find("geoip:") and ipmask:find("geoip:") == 1 then
elseif ipmask:find("ext:") and ipmask:find("ext:") == 1 then elseif ipmask:find("ext:") and ipmask:find("ext:") == 1 then
elseif ipmask:find("#") and ipmask:find("#") == 1 then
else else
if not (datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask)) then if not (datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask)) then
return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!") return nil, ipmask .. " " .. translate("Not valid IP format, please re-enter!")
@ -157,7 +160,7 @@ end
ip_list.description = "<br /><ul><li>" .. translate("IP: such as '127.0.0.1'.") ip_list.description = "<br /><ul><li>" .. translate("IP: such as '127.0.0.1'.")
.. "</li><li>" .. translate("CIDR: such as '127.0.0.0/8'.") .. "</li><li>" .. translate("CIDR: such as '127.0.0.0/8'.")
.. "</li><li>" .. translate("GeoIP: such as 'geoip:cn'. It begins with geoip: (lower case) and followed by two letter of country code.") .. "</li><li>" .. translate("GeoIP: such as 'geoip:cn'. It begins with geoip: (lower case) and followed by two letter of country code.")
.. "</li><li>" .. translate("IPs from file: Such as 'ext:file:tag'. The value must begin with ext: (lowercase), and followed by filename and tag. The file is placed in resource directory, and has the same format of geoip.dat. The tag must exist in the file.") .. "</li><li>" .. translate("Annotation: Begining with #")
.. "</li></ul>" .. "</li></ul>"
return m return m

View File

@ -49,7 +49,9 @@ o:depends({ [option_name("protocol")] = "_iface" })
local nodes_table = {} local nodes_table = {}
local balancers_table = {} local balancers_table = {}
local fallback_table = {}
local iface_table = {} local iface_table = {}
local is_balancer = nil
for k, e in ipairs(api.get_valid_nodes()) do for k, e in ipairs(api.get_valid_nodes()) do
if e.node_type == "normal" then if e.node_type == "normal" then
nodes_table[#nodes_table + 1] = { nodes_table[#nodes_table + 1] = {
@ -63,6 +65,15 @@ for k, e in ipairs(api.get_valid_nodes()) do
id = e[".name"], id = e[".name"],
remark = e["remark"] remark = e["remark"]
} }
if e[".name"] ~= arg[1] then
fallback_table[#fallback_table + 1] = {
id = e[".name"],
remark = e["remark"],
fallback = e["fallback_node"]
}
else
is_balancer = true
end
end end
if e.protocol == "_iface" then if e.protocol == "_iface" then
iface_table[#iface_table + 1] = { iface_table[#iface_table + 1] = {
@ -90,14 +101,35 @@ for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end
local o = s:option(ListValue, option_name("balancingStrategy"), translate("Balancing Strategy")) local o = s:option(ListValue, option_name("balancingStrategy"), translate("Balancing Strategy"))
o:depends({ [option_name("protocol")] = "_balancing" }) o:depends({ [option_name("protocol")] = "_balancing" })
o:value("random") o:value("random")
o:value("roundRobin")
o:value("leastPing") o:value("leastPing")
o:value("leastLoad") o.default = "leastPing"
o.default = "leastLoad"
-- Fallback Node
if api.compare_versions(api.get_app_version("xray"), ">=", "1.8.10") then
local o = s:option(ListValue, option_name("fallback_node"), translate("Fallback Node"))
o:depends({ [option_name("balancingStrategy")] = "leastPing" })
o:value("",translate("Null"))
o.default = ""
local function check_fallback_chain(fb)
for k, v in pairs(fallback_table) do
if v.fallback == fb then
fallback_table[k] = nil
check_fallback_chain(v.id)
end
end
end
-- 检查fallback链去掉会形成闭环的balancer节点
if is_balancer then
check_fallback_chain(arg[1])
end
for k, v in pairs(fallback_table) do o:value(v.id, v.remark) end
for k, v in pairs(nodes_table) do o:value(v.id, v.remark) end
end
-- 探测地址 -- 探测地址
local o = s:option(Flag, option_name("useCustomProbeUrl"), translate("Use Custome Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL.")) local o = s:option(Flag, option_name("useCustomProbeUrl"), translate("Use Custome Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL."))
o:depends({ [option_name("balancingStrategy")] = "leastPing" }) o:depends({ [option_name("balancingStrategy")] = "leastPing" })
o:depends({ [option_name("balancingStrategy")] = "leastLoad" })
local o = s:option(Value, option_name("probeUrl"), translate("Probe URL")) local o = s:option(Value, option_name("probeUrl"), translate("Probe URL"))
o:depends({ [option_name("useCustomProbeUrl")] = true }) o:depends({ [option_name("useCustomProbeUrl")] = true })
@ -107,7 +139,6 @@ o.description = translate("The URL used to detect the connection status.")
-- 探测间隔 -- 探测间隔
local o = s:option(Value, option_name("probeInterval"), translate("Probe Interval")) local o = s:option(Value, option_name("probeInterval"), translate("Probe Interval"))
o:depends({ [option_name("balancingStrategy")] = "leastPing" }) o:depends({ [option_name("balancingStrategy")] = "leastPing" })
o:depends({ [option_name("balancingStrategy")] = "leastLoad" })
o.default = "1m" o.default = "1m"
o.description = translate("The interval between initiating probes. Every time this time elapses, a server status check is performed on a server. The time format is numbers + units, such as '10s', '2h45m', and the supported time units are <code>ns</code>, <code>us</code>, <code>ms</code>, <code>s</code>, <code>m</code>, <code>h</code>, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively.") o.description = translate("The interval between initiating probes. Every time this time elapses, a server status check is performed on a server. The time format is numbers + units, such as '10s', '2h45m', and the supported time units are <code>ns</code>, <code>us</code>, <code>ms</code>, <code>s</code>, <code>m</code>, <code>h</code>, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively.")

View File

@ -1155,6 +1155,7 @@ function gen_config(var)
geosite = {}, geosite = {},
} }
string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w) string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
if w:find("geosite:") == 1 then if w:find("geosite:") == 1 then
table.insert(domain_table.geosite, w:sub(1 + #"geosite:")) table.insert(domain_table.geosite, w:sub(1 + #"geosite:"))
elseif w:find("regexp:") == 1 then elseif w:find("regexp:") == 1 then
@ -1183,6 +1184,7 @@ function gen_config(var)
local ip_cidr = {} local ip_cidr = {}
local geoip = {} local geoip = {}
string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w) string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
if w:find("geoip:") == 1 then if w:find("geoip:") == 1 then
table.insert(geoip, w:sub(1 + #"geoip:")) table.insert(geoip, w:sub(1 + #"geoip:"))
else else

View File

@ -574,6 +574,8 @@ function gen_config(var)
nodes[node_id] = node nodes[node_id] = node
end end
end end
local balancers = {}
local rules = {}
if local_socks_port then if local_socks_port then
local inbound = { local inbound = {
@ -644,8 +646,20 @@ function gen_config(var)
return "balancer-" .. _node_id return "balancer-" .. _node_id
end end
local function gen_loopback(outboundTag, dst_node_id)
if not outboundTag then return nil end
local inboundTag = dst_node_id and "loop-in-" .. dst_node_id or outboundTag .. "-lo"
table.insert(outbounds, {
protocol = "loopback",
tag = outboundTag,
settings = { inboundTag = inboundTag }
})
return inboundTag
end
local function gen_balancer(_node, loopbackTag) local function gen_balancer(_node, loopbackTag)
local blc_nodes = _node.balancing_node local blc_nodes = _node.balancing_node
local fallback_node_id = _node.fallback_node
local length = #blc_nodes local length = #blc_nodes
local valid_nodes = {} local valid_nodes = {}
for i = 1, length do for i = 1, length do
@ -668,40 +682,60 @@ function gen_config(var)
end end
end end
end end
if fallback_node_id == "" then
fallback_node_id = nil
end
if fallback_node_id then
local is_new_node = true
for _, outbound in ipairs(outbounds) do
if outbound.tag == fallback_node_id then
is_new_node = false
break
end
end
if is_new_node then
local fallback_node = uci:get_all(appname, fallback_node_id)
if fallback_node.protocol ~= "_balancing" then
local outbound = gen_outbound(flag, fallback_node, fallback_node_id, { fragment = xray_settings.fragment == "1" or nil })
if outbound then
table.insert(outbounds, outbound)
else
fallback_node_id = nil
end
else
local valid = gen_balancer(fallback_node)
if not valid then
fallback_node_id = nil
end
end
end
end
local balancer, rule local valid = nil
if #valid_nodes > 0 then if #valid_nodes > 0 then
local balancerTag = get_balancer_tag(_node[".name"]) local balancerTag = get_balancer_tag(_node[".name"])
balancer = { table.insert(balancers, {
tag = balancerTag, tag = balancerTag,
selector = valid_nodes, selector = valid_nodes,
fallbackTag = fallback_node_id,
strategy = { type = _node.balancingStrategy or "random" } strategy = { type = _node.balancingStrategy or "random" }
} })
if _node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" then if _node.balancingStrategy == "leastPing" then
if not observatory then if not observatory then
observatory = { observatory = {
subjectSelector = { "blc-" }, subjectSelector = { "blc-" },
probeUrl = _node.useCustomProbeUrl and _node.probeUrl or nil, probeUrl = _node.useCustomProbeUrl and _node.probeUrl or nil,
probeInterval = _node.probeInterval or "1m", probeInterval = _node.probeInterval or "1m",
enableConcurrency = (nodes[node_id] and nodes[node_id].type == "Xray") and true or nil --这里只判断顶层节点(分流总节点/单独的负载均衡节点)类型为Xray就可以启用并发 enableConcurrency = true
} }
end end
end end
if loopbackTag and loopbackTag ~= "" then if loopbackTag == nil or loopbackTag =="" then loopbackTag = _node[".name"] end
local inboundTag = loopbackTag .. "-in" local inboundTag = gen_loopback(loopbackTag, _node[".name"])
table.insert(outbounds, { table.insert(rules, { type = "field", inboundTag = { inboundTag }, balancerTag = balancerTag })
protocol = "loopback", valid = true
tag = loopbackTag,
settings = { inboundTag = inboundTag }
})
rule = {
type = "field",
inboundTag = { inboundTag },
balancerTag = balancerTag
}
end end
end return valid
return balancer, rule
end end
local function set_outbound_detour(node, outbound, outbounds_table, shunt_rule_name) local function set_outbound_detour(node, outbound, outbounds_table, shunt_rule_name)
@ -739,52 +773,10 @@ function gen_config(var)
end end
local node = v local node = v
if node.protocol == "_shunt" then if node.protocol == "_shunt" then
local rules = {} local proxy_tag = "main"
local balancers = {} local proxy_node_id = node["main_node"]
local proxy_node = node.preproxy_enabled == "1" and proxy_node_id or nil
local preproxy_enabled = node.preproxy_enabled == "1" local proxy_outboundTag, proxy_balancerTag
local preproxy_tag = "main"
local preproxy_node_id = node["main_node"]
local preproxy_node = preproxy_enabled and preproxy_node_id and uci:get_all(appname, preproxy_node_id) or nil
local preproxy_is_balancer
if preproxy_node_id and preproxy_node_id:find("Socks_") then
local socks_id = preproxy_node_id:sub(1 + #"Socks_")
local socks_node = uci:get_all(appname, socks_id) or nil
if socks_node then
local _node = {
type = "Xray",
protocol = "socks",
address = "127.0.0.1",
port = socks_node.port,
transport = "tcp",
stream_security = "none"
}
local preproxy_outbound = gen_outbound(flag, _node, preproxy_tag)
if preproxy_outbound then
table.insert(outbounds, preproxy_outbound)
else
preproxy_enabled = false
end
end
elseif preproxy_node and api.is_normal_node(preproxy_node) then
local preproxy_outbound = gen_outbound(flag, preproxy_node, preproxy_tag, { fragment = xray_settings.fragment == "1" or nil })
if preproxy_outbound then
set_outbound_detour(preproxy_node, preproxy_outbound, outbounds, preproxy_tag)
table.insert(outbounds, preproxy_outbound)
else
preproxy_enabled = false
end
elseif preproxy_node and preproxy_node.protocol == "_balancing" then
preproxy_is_balancer = true
local preproxy_balancer, preproxy_rule = gen_balancer(preproxy_node, preproxy_tag)
if preproxy_balancer and preproxy_rule then
table.insert(balancers, preproxy_balancer)
table.insert(rules, preproxy_rule)
else
preproxy_enabled = false
end
end
local function gen_shunt_node(rule_name, _node_id) local function gen_shunt_node(rule_name, _node_id)
if not rule_name then return nil, nil end if not rule_name then return nil, nil end
@ -795,7 +787,7 @@ function gen_config(var)
rule_outboundTag = "direct" rule_outboundTag = "direct"
elseif _node_id == "_blackhole" then elseif _node_id == "_blackhole" then
rule_outboundTag = "blackhole" rule_outboundTag = "blackhole"
elseif _node_id == "_default" and rule_name ~= "default" then elseif _node_id == "_default" then
rule_outboundTag = "default" rule_outboundTag = "default"
elseif _node_id:find("Socks_") then elseif _node_id:find("Socks_") then
local socks_id = _node_id:sub(1 + #"Socks_") local socks_id = _node_id:sub(1 + #"Socks_")
@ -809,9 +801,9 @@ function gen_config(var)
transport = "tcp", transport = "tcp",
stream_security = "none" stream_security = "none"
} }
local _outbound = gen_outbound(flag, _node, rule_name) local outbound = gen_outbound(flag, _node, rule_name)
if _outbound then if outbound then
table.insert(outbounds, _outbound) table.insert(outbounds, outbound)
rule_outboundTag = rule_name rule_outboundTag = rule_name
end end
end end
@ -820,19 +812,19 @@ function gen_config(var)
if not _node then return nil, nil end if not _node then return nil, nil end
if api.is_normal_node(_node) then if api.is_normal_node(_node) then
local proxy = preproxy_enabled and node[rule_name .. "_proxy_tag"] == preproxy_tag and _node_id ~= preproxy_node_id local _proxy_node = uci:get_all(appname, proxy_node_id) or nil
if proxy and preproxy_is_balancer then local use_proxy = _proxy_node and node[rule_name .. "_proxy_tag"] == proxy_tag and _node_id ~= proxy_node_id
local blc_nodes = preproxy_node.balancing_node if use_proxy and proxy_balancerTag then
for _, blc_node_id in ipairs(blc_nodes) do for _, blc_node_id in ipairs(_proxy_node.balancing_node) do
if _node_id == blc_node_id then if _node_id == blc_node_id then
proxy = false use_proxy = false
break break
end end
end end
end end
local copied_outbound local copied_outbound
for index, value in ipairs(outbounds) do for index, value in ipairs(outbounds) do
if value["_flag_tag"] == _node_id and value["_flag_proxy_tag"] == preproxy_tag then if value["_flag_tag"] == _node_id and value["_flag_proxy_tag"] == proxy_tag then
copied_outbound = api.clone(value) copied_outbound = api.clone(value)
break break
end end
@ -842,15 +834,7 @@ function gen_config(var)
table.insert(outbounds, copied_outbound) table.insert(outbounds, copied_outbound)
rule_outboundTag = rule_name rule_outboundTag = rule_name
else else
if proxy then if use_proxy and (_node.type ~= "Xray" or _node.flow == "xtls-rprx-vision") then
local pre_proxy = nil
if _node.type ~= "Xray" then
pre_proxy = true
end
if _node.type == "Xray" and _node.flow == "xtls-rprx-vision" then
pre_proxy = true
end
if pre_proxy then
new_port = get_new_port() new_port = get_new_port()
table.insert(inbounds, { table.insert(inbounds, {
tag = "proxy_" .. rule_name, tag = "proxy_" .. rule_name,
@ -867,45 +851,43 @@ function gen_config(var)
table.insert(rules, 1, { table.insert(rules, 1, {
type = "field", type = "field",
inboundTag = {"proxy_" .. rule_name}, inboundTag = {"proxy_" .. rule_name},
outboundTag = is_balancing_proxy and nil or preproxy_tag, outboundTag = proxy_outboundTag,
balancerTag = is_balancing_proxy and get_balancer_tag(proxy_node_id) or nil balancerTag = proxy_balancerTag
}) })
end end
end
local proxy_table = { local proxy_table = {
proxy = proxy and 1 or 0, proxy = use_proxy and 1 or 0,
tag = proxy and preproxy_tag or nil tag = use_proxy and proxy_tag or nil
} }
if xray_settings.fragment == "1" and not proxy_table.tag then if xray_settings.fragment == "1" and not proxy_table.tag then
proxy_table.fragment = true proxy_table.fragment = true
end end
local _outbound = gen_outbound(flag, _node, rule_name, proxy_table) local outbound = gen_outbound(flag, _node, rule_name, proxy_table)
if _outbound then if outbound then
set_outbound_detour(_node, _outbound, outbounds, rule_name) set_outbound_detour(_node, outbound, outbounds, rule_name)
table.insert(outbounds, _outbound) table.insert(outbounds, outbound)
if proxy then preproxy_used = true end
rule_outboundTag = rule_name rule_outboundTag = rule_name
end end
end end
elseif _node.protocol == "_balancing" then elseif _node.protocol == "_balancing" then
local is_new_balancer = true local is_new_balancer = true
rule_balancerTag = get_balancer_tag(_node_id)
for _, v in ipairs(balancers) do for _, v in ipairs(balancers) do
if v["_flag_tag"] == _node_id then if v.tag == rule_balancerTag then
is_new_balancer = false is_new_balancer = false
rule_balancerTag = v.tag gen_loopback(rule_name, _node_id)
break break
end end
end end
if is_new_balancer then if is_new_balancer then
local balancer = gen_balancer(_node) local valid = gen_balancer(_node, rule_name)
if balancer then if not valid then
table.insert(balancers, balancer) rule_balancerTag = nil
rule_balancerTag = balancer.tag
end end
end end
elseif _node.protocol == "_iface" then elseif _node.protocol == "_iface" then
if _node.iface then if _node.iface then
local _outbound = { local outbound = {
protocol = "freedom", protocol = "freedom",
tag = rule_name, tag = rule_name,
streamSettings = { streamSettings = {
@ -915,7 +897,7 @@ function gen_config(var)
} }
} }
} }
table.insert(outbounds, _outbound) table.insert(outbounds, outbound)
rule_outboundTag = rule_name rule_outboundTag = rule_name
sys.call("touch /tmp/etc/passwall2/iface/" .. _node.iface) sys.call("touch /tmp/etc/passwall2/iface/" .. _node.iface)
end end
@ -923,6 +905,14 @@ function gen_config(var)
end end
return rule_outboundTag, rule_balancerTag return rule_outboundTag, rule_balancerTag
end end
--proxy_node
if proxy_node then
proxy_outboundTag, proxy_balancerTag = gen_shunt_node(proxy_tag, proxy_node_id)
if not proxy_outboundTag and not proxy_balancerTag then
proxy_node = nil
end
end
--default_node --default_node
local default_node_id = node.default_node or "_direct" local default_node_id = node.default_node or "_direct"
local default_outboundTag, default_balancerTag = gen_shunt_node("default", default_node_id) local default_outboundTag, default_balancerTag = gen_shunt_node("default", default_node_id)
@ -965,6 +955,7 @@ function gen_config(var)
} }
domains = {} domains = {}
string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w) string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
table.insert(domains, w) table.insert(domains, w)
table.insert(domain_table.domain, w) table.insert(domain_table.domain, w)
end) end)
@ -976,6 +967,7 @@ function gen_config(var)
if e.ip_list then if e.ip_list then
ip = {} ip = {}
string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w) string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
table.insert(ip, w) table.insert(ip, w)
end) end)
end end
@ -1034,12 +1026,13 @@ function gen_config(var)
} }
elseif node.protocol == "_balancing" then elseif node.protocol == "_balancing" then
if node.balancing_node then if node.balancing_node then
local balancer = gen_balancer(node) local valid = gen_balancer(node)
if valid then
table.insert(rules, { type = "field", network = "tcp,udp", balancerTag = get_balancer_tag(node_id) })
end
routing = { routing = {
balancers = { balancer }, balancers = balancers,
rules = { rules = rules
{ type = "field", network = "tcp,udp", balancerTag = balancer.tag }
}
} }
end end
elseif node.protocol == "_iface" then elseif node.protocol == "_iface" then

View File

@ -343,6 +343,9 @@ msgstr "负载均衡"
msgid "Balancing Strategy" msgid "Balancing Strategy"
msgstr "负载均衡策略" msgstr "负载均衡策略"
msgid "Fallback Node"
msgstr "后备节点"
msgid "Use Custome Probe URL" msgid "Use Custome Probe URL"
msgstr "使用自定义探测网址" msgstr "使用自定义探测网址"
@ -1003,8 +1006,8 @@ msgstr "完整匹配: 由'full:'开始,余下部分是一个域名。当此域
msgid "Pre-defined domain list: Begining with 'geosite:' and the rest is a name, such as geosite:google or geosite:cn." msgid "Pre-defined domain list: Begining with 'geosite:' and the rest is a name, such as geosite:google or geosite:cn."
msgstr "预定义域名列表:由'geosite:'开头余下部分是一个名称如geosite:google或者geosite:cn。" msgstr "预定义域名列表:由'geosite:'开头余下部分是一个名称如geosite:google或者geosite:cn。"
msgid "Domains from file: Such as 'ext:file:tag'. The value must begin with ext: (lowercase), and followed by filename and tag. The file is placed in resource directory, and has the same format of geosite.dat. The tag must exist in the file." msgid "Annotation: Begining with #"
msgstr "从文件中加载域名: 形如'ext:file:tag'必须以ext:小写开头后面跟文件名和标签文件存放在资源目录中文件格式与geosite.dat相同标签必须在文件中存在。" msgstr "注释: 由 # 开头"
msgid "IP: such as '127.0.0.1'." msgid "IP: such as '127.0.0.1'."
msgstr "IP: 形如'127.0.0.1'。" msgstr "IP: 形如'127.0.0.1'。"
@ -1015,9 +1018,6 @@ msgstr "CIDR: 形如'10.0.0.0/8'."
msgid "GeoIP: such as 'geoip:cn'. It begins with geoip: (lower case) and followed by two letter of country code." msgid "GeoIP: such as 'geoip:cn'. It begins with geoip: (lower case) and followed by two letter of country code."
msgstr "GeoIP: 形如'geoip:cn'必须以geoip:(小写)开头,后面跟双字符国家代码,支持几乎所有可以上网的国家。" msgstr "GeoIP: 形如'geoip:cn'必须以geoip:(小写)开头,后面跟双字符国家代码,支持几乎所有可以上网的国家。"
msgid "IPs from file: Such as 'ext:file:tag'. The value must begin with ext: (lowercase), and followed by filename and tag. The file is placed in resource directory, and has the same format of geoip.dat. The tag must exist in the file."
msgstr "从文件中加载 IP: 形如'ext:file:tag'必须以ext:小写开头后面跟文件名和标签文件存放在资源目录中文件格式与geoip.dat相同标签必须在文件中存在。"
msgid "Clear logs" msgid "Clear logs"
msgstr "清空日志" msgstr "清空日志"

View File

@ -16,7 +16,7 @@
echo $$ > ${LOCK_FILE} echo $$ > ${LOCK_FILE}
/etc/init.d/passwall2 restart >/dev/null 2>&1 & /etc/init.d/passwall2 restart >/dev/null 2>&1 &
echo "passwall2: restart when $INTERFACE ifup" > /dev/kmsg logger -p notice -t network -s "passwall2: restart when $INTERFACE ifup"
rm -rf ${LOCK_FILE} rm -rf ${LOCK_FILE}
} }

View File

@ -30,46 +30,10 @@ EOF
touch /etc/config/passwall2_show >/dev/null 2>&1 touch /etc/config/passwall2_show >/dev/null 2>&1
[ ! -s "/etc/config/passwall2" ] && cp -f /usr/share/passwall2/0_default_config /etc/config/passwall2 [ ! -s "/etc/config/passwall2" ] && cp -f /usr/share/passwall2/0_default_config /etc/config/passwall2
use_nft=$(uci -q get passwall2.@global_forwarding[0].use_nft || echo "0")
[ "${use_nft}" = "0" ] && {
if [ -z "$(command -v iptables-legacy || command -v iptables)" ] || [ -z "$(command -v ipset)" ] || [ -z "$(dnsmasq --version | grep 'Compile time options:.* ipset')" ]; then
[ "$(opkg list-installed | grep "firewall4")" ] && [ "$(opkg list-installed | grep "nftables")" ] && {
[ "$(opkg list-installed | grep "kmod\-nft\-socket")" ] && [ "$(opkg list-installed | grep "kmod\-nft\-tproxy")" ] && [ "$(opkg list-installed | grep "kmod\-nft\-nat")" ] && {
uci -q set passwall2.@global_forwarding[0].use_nft=1
uci -q commit passwall2
sed -i "s#use_nft '0'#use_nft '1'#g" /usr/share/passwall2/0_default_config
}
}
fi
}
global_xray=$(uci -q get passwall2.@global_xray[0])
[ -z "${global_xray}" ] && {
cfgid=$(uci add passwall2 global_xray)
uci -q set passwall2.${cfgid}.sniffing=$(uci -q get passwall2.@global_forwarding[0].sniffing || echo "1")
uci -q set passwall2.${cfgid}.route_only=$(uci -q get passwall2.@global_forwarding[0].route_only || echo "0")
uci -q set passwall2.${cfgid}.buffer_size=$(uci -q get passwall2.@global_forwarding[0].buffer_size || echo "")
uci -q delete passwall2.@global_forwarding[0].sniffing
uci -q delete passwall2.@global_forwarding[0].route_only
uci -q delete passwall2.@global_forwarding[0].buffer_size
uci -q commit passwall2
}
global_singbox=$(uci -q get passwall2.@global_singbox[0])
[ -z "${global_singbox}" ] && {
cfgid=$(uci add passwall2 global_singbox)
uci -q set passwall2.${cfgid}.sniff_override_destination=0
uci -q set passwall2.${cfgid}.geoip_path="/tmp/singbox/geoip.db"
uci -q set passwall2.${cfgid}.geoip_url="https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db"
uci -q set passwall2.${cfgid}.geosite_path="/tmp/singbox/geosite.db"
uci -q set passwall2.${cfgid}.geosite_url="https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db"
uci -q commit passwall2
}
chmod +x /usr/share/passwall2/*.sh chmod +x /usr/share/passwall2/*.sh
rm -f /tmp/luci-indexcache rm -f /tmp/luci-indexcache
rm -rf /tmp/luci-modulecache/ rm -rf /tmp/luci-modulecache/
killall -HUP rpcd 2>/dev/null killall -HUP rpcd 2>/dev/null
exit 0 exit 0

View File

@ -1026,14 +1026,13 @@ start() {
if [ -n "$(command -v iptables-legacy || command -v iptables)" ] && [ -n "$(command -v ipset)" ] && [ -n "$(dnsmasq --version | grep 'Compile time options:.* ipset')" ]; then if [ -n "$(command -v iptables-legacy || command -v iptables)" ] && [ -n "$(command -v ipset)" ] && [ -n "$(dnsmasq --version | grep 'Compile time options:.* ipset')" ]; then
USE_TABLES="iptables" USE_TABLES="iptables"
else else
echolog "系统未安装iptables或ipset或Dnsmasq没有开启ipset支持无法使用iptables+ipset透明代理"
if [ -n "$(command -v fw4)" ] && [ -n "$(command -v nft)" ] && [ -n "$(dnsmasq --version | grep 'Compile time options:.* nftset')" ]; then if [ -n "$(command -v fw4)" ] && [ -n "$(command -v nft)" ] && [ -n "$(dnsmasq --version | grep 'Compile time options:.* nftset')" ]; then
echolog "检测到fw4使用nftables进行透明代理。" echolog "检测到fw4使用nftables进行透明代理。"
USE_TABLES="nftables" USE_TABLES="nftables"
nftflag=1 nftflag=1
config_t_set global_forwarding use_nft 1 config_t_set global_forwarding use_nft 1
uci commit ${CONFIG} uci commit ${CONFIG}
else
echolog "系统未安装iptables或ipset或Dnsmasq没有开启ipset支持无法透明代理"
fi fi
fi fi
else else

View File

@ -101,7 +101,7 @@ add() {
#始终用国内DNS解析节点域名 #始终用国内DNS解析节点域名
servers=$(uci show "${CONFIG}" | grep ".address=" | cut -d "'" -f 2) servers=$(uci show "${CONFIG}" | grep ".address=" | cut -d "'" -f 2)
hosts_foreach "servers" host_from_url | grep '[a-zA-Z]$' | sort -u | gen_items settype="${set_type}" setnames="${setflag_4}passwall2_vpslist,${setflag_6}passwall2_vpslist6" dnss="${LOCAL_DNS:-${DEFAULT_DNS}}" outf="${TMP_DNSMASQ_PATH}/10-vpslist_host.conf" ipsetoutf="${TMP_DNSMASQ_PATH}/ipset.conf" hosts_foreach "servers" host_from_url | grep '[a-zA-Z]$' | sort -u | grep -v "engage.cloudflareclient.com" | gen_items settype="${set_type}" setnames="${setflag_4}passwall2_vpslist,${setflag_6}passwall2_vpslist6" dnss="${LOCAL_DNS:-${DEFAULT_DNS}}" outf="${TMP_DNSMASQ_PATH}/10-vpslist_host.conf" ipsetoutf="${TMP_DNSMASQ_PATH}/ipset.conf"
echolog " - [$?]节点列表中的域名(vpslist)${DEFAULT_DNS:-默认}" echolog " - [$?]节点列表中的域名(vpslist)${DEFAULT_DNS:-默认}"
echo "conf-dir=${TMP_DNSMASQ_PATH}" > $DNSMASQ_CONF_FILE echo "conf-dir=${TMP_DNSMASQ_PATH}" > $DNSMASQ_CONF_FILE

View File

@ -868,14 +868,19 @@ del_firewall_rule() {
ip -6 rule del fwmark 1 table 100 2>/dev/null ip -6 rule del fwmark 1 table 100 2>/dev/null
ip -6 route del local ::/0 dev lo table 100 2>/dev/null ip -6 route del local ::/0 dev lo table 100 2>/dev/null
$DIR/app.sh echolog "删除相关防火墙规则完成。" $DIR/app.sh echolog "删除iptables防火墙规则完成。"
} }
flush_ipset() { flush_ipset() {
del_firewall_rule $DIR/app.sh echolog "清空 IPSET。"
for _name in $(ipset list | grep "Name: " | grep "passwall2_" | awk '{print $2}'); do for _name in $(ipset list | grep "Name: " | grep "passwall2_" | awk '{print $2}'); do
destroy_ipset ${_name} destroy_ipset ${_name}
done done
}
flush_ipset_reload() {
del_firewall_rule
flush_ipset
rm -rf /tmp/singbox_passwall2_* rm -rf /tmp/singbox_passwall2_*
/etc/init.d/passwall2 reload /etc/init.d/passwall2 reload
} }
@ -988,6 +993,9 @@ insert_rule_after)
flush_ipset) flush_ipset)
flush_ipset flush_ipset
;; ;;
flush_ipset_reload)
flush_ipset_reload
;;
get_ipt_bin) get_ipt_bin)
get_ipt_bin get_ipt_bin
;; ;;

View File

@ -918,14 +918,19 @@ del_firewall_rule() {
destroy_nftset $NFTSET_LANLIST6 destroy_nftset $NFTSET_LANLIST6
destroy_nftset $NFTSET_VPSLIST6 destroy_nftset $NFTSET_VPSLIST6
$DIR/app.sh echolog "删除相关防火墙规则完成。" $DIR/app.sh echolog "删除nftables防火墙规则完成。"
} }
flush_nftset() { flush_nftset() {
del_firewall_rule $DIR/app.sh echolog "清空 NFTSET。"
for _name in $(nft -a list sets | grep -E "passwall2" | awk -F 'set ' '{print $2}' | awk '{print $1}'); do for _name in $(nft -a list sets | grep -E "passwall2" | awk -F 'set ' '{print $2}' | awk '{print $1}'); do
destroy_nftset ${_name} destroy_nftset ${_name}
done done
}
flush_nftset_reload() {
del_firewall_rule
flush_nftset
rm -rf /tmp/singbox_passwall2_* rm -rf /tmp/singbox_passwall2_*
/etc/init.d/passwall2 reload /etc/init.d/passwall2 reload
} }
@ -1031,6 +1036,9 @@ insert_rule_after)
flush_nftset) flush_nftset)
flush_nftset flush_nftset
;; ;;
flush_nftset_reload)
flush_nftset_reload
;;
get_wan_ip) get_wan_ip)
get_wan_ip get_wan_ip
;; ;;

View File

@ -186,9 +186,9 @@ luci.sys.call("uci commit " .. name)
if reboot == 1 then if reboot == 1 then
log("重启服务,应用新的规则。") log("重启服务,应用新的规则。")
if use_nft == "1" then if use_nft == "1" then
luci.sys.call("sh /usr/share/" .. name .. "/nftables.sh flush_nftset > /dev/null 2>&1 &") luci.sys.call("sh /usr/share/" .. name .. "/nftables.sh flush_nftset_reload > /dev/null 2>&1 &")
else else
luci.sys.call("sh /usr/share/" .. name .. "/iptables.sh flush_ipset > /dev/null 2>&1 &") luci.sys.call("sh /usr/share/" .. name .. "/iptables.sh flush_ipset_reload > /dev/null 2>&1 &")
end end
end end
log("规则更新完毕...") log("规则更新完毕...")