From b53f44e7f1aac96e8e4d64d84dd593ce9c5e4b05 Mon Sep 17 00:00:00 2001 From: gitea-action Date: Thu, 19 Dec 2024 12:18:34 +0800 Subject: [PATCH] luci-app-passwall: sync upstream last commit: https://github.com/xiaorouji/openwrt-passwall/commit/582e13a15cf90e9168565b04a3f25c8bd7322f49 --- luci-app-passwall/Makefile | 4 +- .../luasrc/controller/passwall.lua | 34 +- .../model/cbi/passwall/client/global.lua | 4 + .../cbi/passwall/client/socks_config.lua | 5 +- .../model/cbi/passwall/client/type/ray.lua | 24 +- .../cbi/passwall/client/type/sing-box.lua | 23 +- luci-app-passwall/luasrc/passwall/api.lua | 18 +- .../luasrc/passwall/util_sing-box.lua | 43 +- .../luasrc/passwall/util_xray.lua | 48 +- .../luasrc/view/passwall/global/status.htm | 3 +- .../passwall/node_list/link_share_man.htm | 2 +- .../view/passwall/node_list/node_list.htm | 12 +- luci-app-passwall/po/zh-cn/passwall.po | 11 +- .../root/usr/share/passwall/0_default_config | 1 + .../root/usr/share/passwall/app.sh | 153 +++- .../usr/share/passwall/helper_dnsmasq.lua | 675 ++++++++++++++++++ .../root/usr/share/passwall/helper_dnsmasq.sh | 27 - .../usr/share/passwall/helper_dnsmasq_add.lua | 506 ------------- .../root/usr/share/passwall/iptables.sh | 303 +++----- .../root/usr/share/passwall/nftables.sh | 280 +++----- .../usr/share/passwall/socks_auto_switch.sh | 5 +- .../root/usr/share/passwall/subscribe.lua | 17 + patch-luci-app-passwall.patch | 91 +-- 23 files changed, 1223 insertions(+), 1066 deletions(-) create mode 100644 luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua delete mode 100755 luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.sh delete mode 100644 luci-app-passwall/root/usr/share/passwall/helper_dnsmasq_add.lua diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index eac865674..15c64372e 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -6,8 +6,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall -PKG_VERSION:=24.12.08 -PKG_RELEASE:=1 +PKG_VERSION:=24.12.17 +PKG_RELEASE:=2 PKG_CONFIG_DEPENDS:= \ CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \ diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua index 83cbafc53..6ddcdfd46 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -166,13 +166,13 @@ end function get_now_use_node() local path = "/tmp/etc/passwall/acl/default" local e = {} - local data, code, msg = nixio.fs.readfile(path .. "/TCP.id") - if data then - e["TCP"] = util.trim(data) + local tcp_node = api.get_cache_var("GLOBAL_TCP_node") + if tcp_node then + e["TCP"] = tcp_node end - local data, code, msg = nixio.fs.readfile(path .. "/UDP.id") - if data then - e["UDP"] = util.trim(data) + local udp_node = api.get_cache_var("GLOBAL_UDP_node") + if udp_node then + e["UDP"] = udp_node end luci.http.prepare_content("application/json") luci.http.write_json(e) @@ -269,8 +269,8 @@ function connect_status() local chn_list = uci:get(appname, "@global[0]", "chn_list") or "direct" local gfw_list = uci:get(appname, "@global[0]", "use_gfw_list") or "1" local proxy_mode = uci:get(appname, "@global[0]", "tcp_proxy_mode") or "proxy" - local socks_server = luci.sys.exec("[ -f /tmp/etc/passwall/acl/default/TCP_SOCKS_server ] && echo -n $(cat /tmp/etc/passwall/acl/default/TCP_SOCKS_server) || echo -n ''") - if socks_server ~= "" then + local socks_server = api.get_cache_var("GLOBAL_TCP_SOCKS_server") + if socks_server and socks_server ~= "" then if (chn_list == "proxy" and gfw_list == "0" and proxy_mode ~= "proxy" and baidu ~= nil) or (chn_list == "0" and gfw_list == "0" and proxy_mode == "proxy") then -- 中国列表+百度 or 全局 url = "-x socks5h://" .. socks_server .. " " .. url @@ -374,8 +374,8 @@ function clear_all_nodes() uci:delete(appname, t[".name"]) end) uci:foreach(appname, "acl_rule", function(t) - uci:set(appname, t[".name"], "tcp_node", "default") - uci:set(appname, t[".name"], "udp_node", "default") + uci:set(appname, t[".name"], "tcp_node", "nil") + uci:set(appname, t[".name"], "udp_node", "nil") end) uci:foreach(appname, "nodes", function(node) uci:delete(appname, node['.name']) @@ -413,10 +413,20 @@ function delete_select_nodes() end) uci:foreach(appname, "acl_rule", function(t) if t["tcp_node"] == w then - uci:set(appname, t[".name"], "tcp_node", "default") + uci:set(appname, t[".name"], "tcp_node", "nil") end if t["udp_node"] == w then - uci:set(appname, t[".name"], "udp_node", "default") + uci:set(appname, t[".name"], "udp_node", "nil") + end + end) + uci:foreach(appname, "nodes", function(t) + if t["preproxy_node"] == w then + uci:delete(appname, t[".name"], "preproxy_node") + uci:delete(appname, t[".name"], "chain_proxy") + end + if t["to_node"] == w then + uci:delete(appname, t[".name"], "to_node") + uci:delete(appname, t[".name"], "chain_proxy") end end) uci:delete(appname, w) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua index e5d6a46a6..541167fe6 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua @@ -563,6 +563,10 @@ if api.is_finded("smartdns") then o:depends({dns_shunt = "smartdns", tcp_proxy_mode = "proxy", chn_list = "direct"}) end +o = s:taboption("DNS", Flag, "dns_redirect", translate("DNS Redirect"), translate("Force special DNS server to need proxy devices.")) +o.default = "1" +o.rmempty = false + if (uci:get(appname, "@global_forwarding[0]", "use_nft") or "0") == "1" then o = s:taboption("DNS", Button, "clear_ipset", translate("Clear NFTSET"), translate("Try this feature if the rule modification does not take effect.")) else diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua index c537d5519..793cab032 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua @@ -21,9 +21,8 @@ o.default = 1 o.rmempty = false local auto_switch_tip -local current_node_file = string.format("/tmp/etc/%s/id/socks_%s", appname, arg[1]) -local current_node = luci.sys.exec(string.format("[ -f '%s' ] && echo -n $(cat %s)", current_node_file, current_node_file)) -if current_node and current_node ~= "" and current_node ~= "nil" then +local current_node = api.get_cache_var("socks_" .. arg[1]) +if current_node then local n = uci:get_all(appname, current_node) if n then if tonumber(m:get(arg[1], "enable_autoswitch") or 0) == 1 then diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua index 8ec330c11..8b55b6b46 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua @@ -646,12 +646,26 @@ o.default = 0 o = s:option(Flag, option_name("tcpNoDelay"), "tcpNoDelay") o.default = 0 -o = s:option(ListValue, option_name("to_node"), translate("Landing node"), translate("Only support a layer of proxy.")) -o.default = "" +o = s:option(ListValue, option_name("chain_proxy"), translate("Chain Proxy")) o:value("", translate("Close(Not use)")) +o:value("1", translate("Preproxy Node")) +o:value("2", translate("Landing Node")) +for i, v in ipairs(s.fields[option_name("protocol")].keylist) do + if not v:find("_") then + o:depends({ [option_name("protocol")] = v }) + end +end + +o = s:option(ListValue, option_name("preproxy_node"), translate("Preproxy Node"), translate("Only support a layer of proxy.")) +o:depends({ [option_name("chain_proxy")] = "1" }) + +o = s:option(ListValue, option_name("to_node"), translate("Landing Node"), translate("Only support a layer of proxy.")) +o:depends({ [option_name("chain_proxy")] = "2" }) + for k, v in pairs(nodes_table) do - if v.type == "Xray" then - o:value(v.id, v.remark) + if v.type == "Xray" and v.id ~= arg[1] then + s.fields[option_name("preproxy_node")]:value(v.id, v.remark) + s.fields[option_name("to_node")]:value(v.id, v.remark) end end @@ -659,7 +673,7 @@ for i, v in ipairs(s.fields[option_name("protocol")].keylist) do if not v:find("_") then s.fields[option_name("tcpMptcp")]:depends({ [option_name("protocol")] = v }) s.fields[option_name("tcpNoDelay")]:depends({ [option_name("protocol")] = v }) - s.fields[option_name("to_node")]:depends({ [option_name("protocol")] = v }) + s.fields[option_name("chain_proxy")]:depends({ [option_name("protocol")] = v }) end end diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua index 8e8824a79..794bf1349 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua @@ -677,18 +677,27 @@ o:depends({ [option_name("protocol")] = "vless" }) o:depends({ [option_name("protocol")] = "tuic" }) o:depends({ [option_name("protocol")] = "hysteria2" }) -o = s:option(ListValue, option_name("to_node"), translate("Landing node"), translate("Only support a layer of proxy.")) -o.default = "" +o = s:option(ListValue, option_name("chain_proxy"), translate("Chain Proxy")) o:value("", translate("Close(Not use)")) -for k, v in pairs(nodes_table) do - if v.type == "sing-box" then - o:value(v.id, v.remark) - end -end +o:value("1", translate("Preproxy Node")) +o:value("2", translate("Landing Node")) for i, v in ipairs(s.fields[option_name("protocol")].keylist) do if not v:find("_") then o:depends({ [option_name("protocol")] = v }) end end +o = s:option(ListValue, option_name("preproxy_node"), translate("Preproxy Node"), translate("Only support a layer of proxy.")) +o:depends({ [option_name("chain_proxy")] = "1" }) + +o = s:option(ListValue, option_name("to_node"), translate("Landing Node"), translate("Only support a layer of proxy.")) +o:depends({ [option_name("chain_proxy")] = "2" }) + +for k, v in pairs(nodes_table) do + if v.type == "sing-box" and v.id ~= arg[1] then + s.fields[option_name("preproxy_node")]:value(v.id, v.remark) + s.fields[option_name("to_node")]:value(v.id, v.remark) + end +end + api.luci_types(arg[1], m, s, type_name, option_prefix) diff --git a/luci-app-passwall/luasrc/passwall/api.lua b/luci-app-passwall/luasrc/passwall/api.lua index 5d67e767c..61c0a0f8b 100644 --- a/luci-app-passwall/luasrc/passwall/api.lua +++ b/luci-app-passwall/luasrc/passwall/api.lua @@ -16,8 +16,10 @@ OPENWRT_ARCH = nil DISTRIB_ARCH = nil OPENWRT_BOARD = nil -LOG_FILE = "/tmp/log/" .. appname .. ".log" CACHE_PATH = "/tmp/etc/" .. appname .. "_tmp" +LOG_FILE = "/tmp/log/" .. appname .. ".log" +TMP_PATH = "/tmp/etc/" .. appname +TMP_IFACE_PATH = TMP_PATH .. "/iface" function log(...) local result = os.date("%Y-%m-%d %H:%M:%S: ") .. table.concat({...}, " ") @@ -28,6 +30,16 @@ function log(...) end end +function set_cache_var(key, val) + sys.call(string.format('/usr/share/passwall/app.sh set_cache_var %s "%s"', key, val)) +end + +function get_cache_var(key) + local val = sys.exec(string.format('echo -n $(/usr/share/passwall/app.sh get_cache_var %s)', key)) + if val == "" then val = nil end + return val +end + function exec_call(cmd) local process = io.popen(cmd .. '; echo -e "\n$?"') local lines = {} @@ -97,8 +109,8 @@ end function curl_proxy(url, file, args) --使用代理 - local socks_server = luci.sys.exec("[ -f /tmp/etc/passwall/acl/default/TCP_SOCKS_server ] && echo -n $(cat /tmp/etc/passwall/acl/default/TCP_SOCKS_server) || echo -n ''") - if socks_server ~= "" then + local socks_server = get_cache_var("GLOBAL_TCP_SOCKS_server") + if socks_server and socks_server ~= "" then if not args then args = {} end local tmp_args = clone(args) tmp_args[#tmp_args + 1] = "-x socks5h://" .. socks_server diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index d4f516878..e65138999 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -688,7 +688,7 @@ function gen_config_server(node) bind_interface = node.outbound_node_iface, routing_mark = 255, } - sys.call("mkdir -p /tmp/etc/passwall/iface && touch /tmp/etc/passwall/iface/" .. node.outbound_node_iface) + sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, node.outbound_node_iface)) else local outbound_node_t = uci:get_all("passwall", node.outbound_node) if node.outbound_node == "_socks" or node.outbound_node == "_http" then @@ -880,6 +880,7 @@ function gen_config(var) local function set_outbound_detour(node, outbound, outbounds_table, shunt_rule_name) if not node or not outbound or not outbounds_table then return nil end local default_outTag = outbound.tag + local last_insert_outbound if node.shadowtls == "1" then local _node = { @@ -896,14 +897,31 @@ function gen_config(var) } local shadowtls_outbound = gen_outbound(nil, _node, outbound.tag .. "_shadowtls") if shadowtls_outbound then - table.insert(outbounds_table, shadowtls_outbound) + last_insert_outbound = shadowtls_outbound outbound.detour = outbound.tag .. "_shadowtls" outbound.server = nil outbound.server_port = nil end end - if node.to_node then + if node.chain_proxy == "1" and node.preproxy_node then + if outbound["_flag_proxy_tag"] and outbound["_flag_proxy_tag"] ~= "nil" then + --Ignore + else + local preproxy_node = uci:get_all(appname, node.preproxy_node) + if preproxy_node then + local preproxy_outbound = gen_outbound(nil, preproxy_node) + if preproxy_outbound then + preproxy_outbound.tag = preproxy_node[".name"] .. ":" .. preproxy_node.remarks + outbound.tag = preproxy_outbound.tag .. " -> " .. outbound.tag + outbound.detour = preproxy_outbound.tag + last_insert_outbound = preproxy_outbound + default_outTag = outbound.tag + end + end + end + end + if node.chain_proxy == "2" and node.to_node then local to_node = uci:get_all(appname, node.to_node) if to_node then local to_outbound = gen_outbound(nil, to_node) @@ -921,7 +939,7 @@ function gen_config(var) end end end - return default_outTag + return default_outTag, last_insert_outbound end if node.protocol == "_shunt" then @@ -1006,8 +1024,11 @@ function gen_config(var) local _outbound = gen_outbound(flag, _node, rule_name, { tag = use_proxy and preproxy_tag or nil }) if _outbound then _outbound.tag = _outbound.tag .. ":" .. _node.remarks - rule_outboundTag = set_outbound_detour(_node, _outbound, outbounds, rule_name) + rule_outboundTag, last_insert_outbound = set_outbound_detour(_node, _outbound, outbounds, rule_name) table.insert(outbounds, _outbound) + if last_insert_outbound then + table.insert(outbounds, last_insert_outbound) + end end end elseif _node.protocol == "_iface" then @@ -1020,7 +1041,7 @@ function gen_config(var) } table.insert(outbounds, _outbound) rule_outboundTag = _outbound.tag - sys.call("touch /tmp/etc/passwall/iface/" .. _node.iface) + sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, _node.iface)) end end end @@ -1197,14 +1218,17 @@ function gen_config(var) } table.insert(outbounds, outbound) COMMON.default_outbound_tag = outbound.tag - sys.call("touch /tmp/etc/passwall/iface/" .. node.iface) + sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, node.iface)) end else local outbound = gen_outbound(flag, node) if outbound then outbound.tag = outbound.tag .. ":" .. node.remarks - COMMON.default_outbound_tag = set_outbound_detour(node, outbound, outbounds) + COMMON.default_outbound_tag, last_insert_outbound = set_outbound_detour(node, outbound, outbounds) table.insert(outbounds, outbound) + if last_insert_outbound then + table.insert(outbounds, last_insert_outbound) + end end end end @@ -1452,6 +1476,9 @@ function gen_config(var) tag = "block" }) for index, value in ipairs(config.outbounds) do + if (not value["_flag_proxy_tag"] or value["_flag_proxy_tag"] == "nil") and not value.detour and value["_id"] and value.server and value.server_port then + sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list")) + end for k, v in pairs(config.outbounds[index]) do if k:find("_") == 1 then config.outbounds[index][k] = nil diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index d521b5e73..0a2a663a7 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -417,7 +417,7 @@ function gen_config_server(node) } } } - sys.call("mkdir -p /tmp/etc/passwall/iface && touch /tmp/etc/passwall/iface/" .. node.outbound_node_iface) + sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, node.outbound_node_iface)) else local outbound_node_t = uci:get_all("passwall", node.outbound_node) if node.outbound_node == "_socks" or node.outbound_node == "_http" then @@ -780,9 +780,30 @@ function gen_config(var) local function set_outbound_detour(node, outbound, outbounds_table, shunt_rule_name) if not node or not outbound or not outbounds_table then return nil end - local default_out_tag = outbound.tag + local default_outTag = outbound.tag + local last_insert_outbound - if node.to_node then + if node.chain_proxy == "1" and node.preproxy_node then + if outbound["_flag_proxy_tag"] and outbound["_flag_proxy_tag"] ~= "nil" then + --Ignore + else + local preproxy_node = uci:get_all(appname, node.preproxy_node) + if preproxy_node then + local preproxy_outbound = gen_outbound(nil, preproxy_node) + if preproxy_outbound then + preproxy_outbound.tag = preproxy_node[".name"] .. ":" .. preproxy_node.remarks + outbound.tag = preproxy_outbound.tag .. " -> " .. outbound.tag + outbound.proxySettings = { + tag = preproxy_outbound.tag, + transportLayer = true + } + last_insert_outbound = preproxy_outbound + default_outTag = outbound.tag + end + end + end + end + if node.chain_proxy == "2" and node.to_node then local to_node = uci:get_all(appname, node.to_node) if to_node then local to_outbound = gen_outbound(nil, to_node) @@ -799,11 +820,11 @@ function gen_config(var) transportLayer = true } table.insert(outbounds_table, to_outbound) - default_out_tag = to_outbound.tag + default_outTag = to_outbound.tag end end end - return default_out_tag + return default_outTag, last_insert_outbound end if node.protocol == "_shunt" then @@ -901,12 +922,15 @@ function gen_config(var) local outbound_tag if outbound then outbound.tag = outbound.tag .. ":" .. _node.remarks - outbound_tag = set_outbound_detour(_node, outbound, outbounds, rule_name) + outbound_tag, last_insert_outbound = set_outbound_detour(_node, outbound, outbounds, rule_name) if rule_name == "default" then table.insert(outbounds, 1, outbound) else table.insert(outbounds, outbound) end + if last_insert_outbound then + table.insert(outbounds, last_insert_outbound) + end end return outbound_tag, nil elseif _node.protocol == "_balancing" then @@ -926,7 +950,7 @@ function gen_config(var) } outbound_tag = outbound.tag table.insert(outbounds, outbound) - sys.call("touch /tmp/etc/passwall/iface/" .. _node.iface) + sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, _node.iface)) end return outbound_tag, nil end @@ -1075,14 +1099,17 @@ function gen_config(var) } table.insert(outbounds, outbound) COMMON.default_outbound_tag = outbound.tag - sys.call("touch /tmp/etc/passwall/iface/" .. node.iface) + sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, node.iface)) end else local outbound = gen_outbound(flag, node, nil, { fragment = xray_settings.fragment == "1" or nil, noise = xray_settings.fragment == "1" or nil }) if outbound then outbound.tag = outbound.tag .. ":" .. node.remarks - COMMON.default_outbound_tag = set_outbound_detour(node, outbound, outbounds) + COMMON.default_outbound_tag, last_insert_outbound = set_outbound_detour(node, outbound, outbounds) table.insert(outbounds, outbound) + if last_insert_outbound then + table.insert(outbounds, last_insert_outbound) + end end routing = { domainStrategy = "AsIs", @@ -1369,6 +1396,9 @@ function gen_config(var) end for index, value in ipairs(config.outbounds) do + if (not value["_flag_proxy_tag"] or value["_flag_proxy_tag"] == "nil") and value["_id"] and value.server and value.server_port then + sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list")) + end for k, v in pairs(config.outbounds[index]) do if k:find("_") == 1 then config.outbounds[index][k] = nil diff --git a/luci-app-passwall/luasrc/view/passwall/global/status.htm b/luci-app-passwall/luasrc/view/passwall/global/status.htm index 452d369af..a8729505e 100644 --- a/luci-app-passwall/luasrc/view/passwall/global/status.htm +++ b/luci-app-passwall/luasrc/view/passwall/global/status.htm @@ -58,9 +58,10 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md color:#8898aa!important; line-height: 1.8em; min-height: 48px; - background-image: linear-gradient(270deg, #dde2ff 0%, #fffeff 100%); border-radius: 12.375px; + background-image: linear-gradient(270deg, #dde2ff 0%, #fffeff 100%); } + @media (prefers-color-scheme: dark) { .block h4 { background-image: none; diff --git a/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm b/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm index 3dad68b73..6bcad56da 100644 --- a/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm +++ b/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm @@ -1101,7 +1101,7 @@ local api = require "luci.passwall.api" } } - opt.set(dom_prefix + 'encryption', queryParam.encryption); + opt.set(dom_prefix + 'encryption', queryParam.encryption || "none"); if (queryParam.security) { if (queryParam.security == "tls") { opt.set(dom_prefix + 'tls', true); diff --git a/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm b/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm index 077856625..a00b943e3 100644 --- a/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm +++ b/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm @@ -221,6 +221,10 @@ table td, .table .td { dom.title = "当前TCP节点"; //var v = "当前TCP节点:" + document.getElementById("cbid.passwall." + id + ".remarks").value; //document.getElementById("cbi-passwall-" + id + "-remarks").innerHTML = v; + var tds = dom.getElementsByTagName("td") + for (var j = 0; j < tds.length; j++) { + tds[j].classList.add("_now_use"); + } } } id = result["UDP"]; @@ -229,6 +233,10 @@ table td, .table .td { if (dom) { dom.classList.add("_now_use"); dom.title = "当前UDP节点"; + var tds = dom.getElementsByTagName("td") + for (var j = 0; j < tds.length; j++) { + tds[j].classList.add("_now_use"); + } } } } @@ -295,8 +303,6 @@ table td, .table .td { ); } } - - get_now_use_node(); /* 自动Ping */ if (auto_detection_time == "icmp" || auto_detection_time == "tcping") { @@ -417,6 +423,8 @@ table td, .table .td { console.error(err); } } + + get_now_use_node(); if (true) { var str = ""; diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index 28fbc6854..c8a0ec1d8 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -223,6 +223,12 @@ msgstr "需要代理的分流规则域名使用 FakeDNS。" msgid "Redirect" msgstr "重定向" +msgid "DNS Redirect" +msgstr "DNS 重定向" + +msgid "Force special DNS server to need proxy devices." +msgstr "强制需要代理的设备使用专用 DNS 服务器。" + msgid "Clear IPSET" msgstr "清空 IPSET" @@ -1714,7 +1720,10 @@ msgstr "延迟(ms)" msgid "If is domain name, The requested domain name will be resolved to IP before connect." msgstr "如果是域名,域名将在请求发出之前解析为 IP。" -msgid "Landing node" +msgid "Chain Proxy" +msgstr "链式代理" + +msgid "Landing Node" msgstr "落地节点" msgid "Only support a layer of proxy." diff --git a/luci-app-passwall/root/usr/share/passwall/0_default_config b/luci-app-passwall/root/usr/share/passwall/0_default_config index 4b20280bb..19b16b7a6 100644 --- a/luci-app-passwall/root/usr/share/passwall/0_default_config +++ b/luci-app-passwall/root/usr/share/passwall/0_default_config @@ -12,6 +12,7 @@ config global list smartdns_remote_dns 'https://1.1.1.1/dns-query' option use_default_dns 'direct' option chinadns_ng_default_tag 'none' + option dns_redirect '1' option use_direct_list '1' option use_proxy_list '1' option use_block_list '1' diff --git a/luci-app-passwall/root/usr/share/passwall/app.sh b/luci-app-passwall/root/usr/share/passwall/app.sh index 56a46c00a..40b657cd6 100755 --- a/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/luci-app-passwall/root/usr/share/passwall/app.sh @@ -9,7 +9,6 @@ CONFIG=passwall TMP_PATH=/tmp/etc/$CONFIG TMP_BIN_PATH=$TMP_PATH/bin TMP_SCRIPT_FUNC_PATH=$TMP_PATH/script_func -TMP_ID_PATH=$TMP_PATH/id TMP_ROUTE_PATH=$TMP_PATH/route TMP_ACL_PATH=$TMP_PATH/acl TMP_IFACE_PATH=$TMP_PATH/iface @@ -373,6 +372,20 @@ get_geoip() { fi } +set_cache_var() { + local key="${1}" + shift 1 + local val="$@" + [ -n "${key}" ] && [ -n "${val}" ] && echo "${key}=\"${val}\"" >> $TMP_PATH/var +} + +get_cache_var() { + local key="${1}" + [ -n "${key}" ] && [ -s "$TMP_PATH/var" ] && { + echo $(cat $TMP_PATH/var | grep "^${key}=" | awk -F '=' '{print $2}' | tail -n 1 | awk -F'"' '{print $2}') + } +} + run_ipt2socks() { local flag proto tcp_tproxy local_port socks_address socks_port socks_username socks_password log_file local _extra_param="" @@ -712,6 +725,8 @@ run_socks() { fi } unset http_flag + + [ "${server_host}" != "127.0.0.1" ] && [ "$type" != "sing-box" ] && [ "$type" != "xray" ] && echo "${node}" >> $TMP_PATH/direct_node_list } run_redir() { @@ -1064,11 +1079,12 @@ run_redir() { [ "$tcp_node_socks" = "1" ] && { TCP_SOCKS_server="127.0.0.1:$tcp_node_socks_port" - echo "${TCP_SOCKS_server}" > ${GLOBAL_ACL_PATH}/TCP_SOCKS_server + set_cache_var "GLOBAL_TCP_SOCKS_server" "${TCP_SOCKS_server}" } ;; esac unset tcp_node_socks_flag tcp_node_http_flag + [ "$type" != "sing-box" ] && [ "$type" != "xray" ] && echo "${node}" >> $TMP_PATH/direct_node_list return 0 } @@ -1083,7 +1099,7 @@ start_redir() { local port=$(echo $(get_new_port $current_port $proto)) eval ${proto}_REDIR=$port run_redir node=$node proto=${proto} bind=0.0.0.0 local_port=$port config_file=$config_file log_file=$log_file - echo $node > ${GLOBAL_ACL_PATH}/${proto}.id + set_cache_var "GLOBAL_${proto}_node" "$node" else [ "${proto}" = "UDP" ] && [ "$TCP_UDP" = "1" ] && return echolog "${proto}节点没有选择或为空,不代理${proto}。" @@ -1111,7 +1127,7 @@ start_socks() { local http_port=$(config_n_get $id http_port 0) local http_config_file="HTTP2SOCKS_${id}.json" run_socks flag=$id node=$node bind=$bind socks_port=$port config_file=$config_file http_port=$http_port http_config_file=$http_config_file log_file=$log_file - echo $node > $TMP_ID_PATH/socks_${id} + set_cache_var "socks_${id}" "$node" #自动切换逻辑 local enable_autoswitch=$(config_n_get $id enable_autoswitch 0) @@ -1145,7 +1161,9 @@ socks_node_switch() { local http_config_file="HTTP2SOCKS_${flag}.json" LOG_FILE="/dev/null" run_socks flag=$flag node=$new_node bind=$bind socks_port=$port config_file=$config_file http_port=$http_port http_config_file=$http_config_file log_file=$log_file - echo $new_node > $TMP_ID_PATH/socks_${flag} + set_cache_var "socks_${flag}" "$new_node" + local USE_TABLES=$(get_cache_var "USE_TABLES") + [ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh filter_direct_node_list } } @@ -1548,19 +1566,43 @@ start_dns() { [ "$(expr $dnsmasq_version \>= 2.87)" == 0 ] && echolog "Dnsmasq版本低于2.87,有可能无法正常使用!!!" } - GLOBAL_DNSMASQ_PORT=$(get_new_port 11400) - local GLOBAL_DNSMASQ_CONF=${GLOBAL_ACL_PATH}/dnsmasq.conf - local GLOBAL_DNSMASQ_CONF_PATH=${GLOBAL_ACL_PATH}/dnsmasq.d - source $APP_PATH/helper_dnsmasq.sh copy_instance listen_port=$GLOBAL_DNSMASQ_PORT dnsmasq_conf="${GLOBAL_DNSMASQ_CONF}" dnsmasq_conf_path="${GLOBAL_DNSMASQ_CONF_PATH}" - lua $APP_PATH/helper_dnsmasq_add.lua -FLAG "default" -TMP_DNSMASQ_PATH ${GLOBAL_DNSMASQ_CONF_PATH} \ - -DNSMASQ_CONF_FILE ${GLOBAL_DNSMASQ_CONF} -DEFAULT_DNS ${DEFAULT_DNS} -LOCAL_DNS ${LOCAL_DNS} \ - -TUN_DNS ${TUN_DNS} -REMOTE_FAKEDNS ${fakedns:-0} -USE_DEFAULT_DNS "${USE_DEFAULT_DNS:-direct}" -CHINADNS_DNS ${china_ng_listen:-0} \ - -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}" \ - -TCP_NODE ${TCP_NODE} -DEFAULT_PROXY_MODE ${TCP_PROXY_MODE} -NO_PROXY_IPV6 ${DNSMASQ_FILTER_PROXY_IPV6:-0} -NFTFLAG ${nftflag:-0} \ - -NO_LOGIC_LOG ${NO_LOGIC_LOG:-0} - ln_run "$(first_type dnsmasq)" "dnsmasq_default" "/dev/null" -C ${GLOBAL_DNSMASQ_CONF} -x ${GLOBAL_ACL_PATH}/dnsmasq.pid - echo "${GLOBAL_DNSMASQ_PORT}" > ${GLOBAL_ACL_PATH}/var_redirect_dns_port - DNS_REDIRECT_PORT=${GLOBAL_DNSMASQ_PORT} + local RUN_NEW_DNSMASQ=1 + if [ "${RUN_NEW_DNSMASQ}" == "0" ]; then + #The old logic will be removed in the future. + #Run a copy dnsmasq instance, DNS hijack that don't need a proxy devices. + [ "1" = "0" ] && { + DIRECT_DNSMASQ_PORT=$(get_new_port 11400) + DIRECT_DNSMASQ_CONF=${GLOBAL_ACL_PATH}/direct_dnsmasq.conf + lua $APP_PATH/helper_dnsmasq.lua copy_instance -LISTEN_PORT ${DIRECT_DNSMASQ_PORT} -DNSMASQ_CONF ${DIRECT_DNSMASQ_CONF} + ln_run "$(first_type dnsmasq)" "dnsmasq_direct" "/dev/null" -C ${DIRECT_DNSMASQ_CONF} -x ${GLOBAL_ACL_PATH}/direct_dnsmasq.pid + echo "${DIRECT_DNSMASQ_PORT}" > ${GLOBAL_ACL_PATH}/direct_dnsmasq_port + } + + #Rewrite the default DNS service configuration + #Modify the default dnsmasq service + lua $APP_PATH/helper_dnsmasq.lua stretch + lua $APP_PATH/helper_dnsmasq.lua add_rule -FLAG "default" -TMP_DNSMASQ_PATH ${GLOBAL_DNSMASQ_CONF_PATH} -DNSMASQ_CONF_FILE ${GLOBAL_DNSMASQ_CONF} \ + -DEFAULT_DNS ${DEFAULT_DNS} -LOCAL_DNS ${LOCAL_DNS} -TUN_DNS ${TUN_DNS} \ + -REMOTE_FAKEDNS ${fakedns:-0} -USE_DEFAULT_DNS "${USE_DEFAULT_DNS:-direct}" -CHINADNS_DNS ${china_ng_listen:-0} \ + -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}" \ + -TCP_NODE ${TCP_NODE} -DEFAULT_PROXY_MODE ${TCP_PROXY_MODE} -NO_PROXY_IPV6 ${DNSMASQ_FILTER_PROXY_IPV6:-0} -NFTFLAG ${nftflag:-0} \ + -NO_LOGIC_LOG ${NO_LOGIC_LOG:-0} + /etc/init.d/dnsmasq restart >/dev/null 2>&1 + else + #Run a copy dnsmasq instance, DNS hijack for that need proxy devices. + GLOBAL_DNSMASQ_PORT=$(get_new_port 11400) + GLOBAL_DNSMASQ_CONF=${GLOBAL_ACL_PATH}/dnsmasq.conf + GLOBAL_DNSMASQ_CONF_PATH=${GLOBAL_ACL_PATH}/dnsmasq.d + lua $APP_PATH/helper_dnsmasq.lua add_rule -FLAG "default" -TMP_DNSMASQ_PATH ${GLOBAL_DNSMASQ_CONF_PATH} -DNSMASQ_CONF_FILE ${GLOBAL_DNSMASQ_CONF} \ + -LISTEN_PORT ${GLOBAL_DNSMASQ_PORT} -DEFAULT_DNS ${DEFAULT_DNS} -LOCAL_DNS ${LOCAL_DNS} -TUN_DNS ${TUN_DNS} \ + -REMOTE_FAKEDNS ${fakedns:-0} -USE_DEFAULT_DNS "${USE_DEFAULT_DNS:-direct}" -CHINADNS_DNS ${china_ng_listen:-0} \ + -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}" \ + -TCP_NODE ${TCP_NODE} -DEFAULT_PROXY_MODE ${TCP_PROXY_MODE} -NO_PROXY_IPV6 ${DNSMASQ_FILTER_PROXY_IPV6:-0} -NFTFLAG ${nftflag:-0} \ + -NO_LOGIC_LOG ${NO_LOGIC_LOG:-0} + ln_run "$(first_type dnsmasq)" "dnsmasq_default" "/dev/null" -C ${GLOBAL_DNSMASQ_CONF} -x ${GLOBAL_ACL_PATH}/dnsmasq.pid + set_cache_var "ACL_default_dns_port" "${GLOBAL_DNSMASQ_PORT}" + DNS_REDIRECT_PORT=${GLOBAL_DNSMASQ_PORT} + fi } add_ip2route() { @@ -1600,7 +1642,7 @@ delete_ip2route() { start_haproxy() { [ "$(config_t_get global_haproxy balancing_enable 0)" != "1" ] && return - haproxy_path=${TMP_PATH}/haproxy + haproxy_path=$TMP_PATH/haproxy haproxy_conf="config.cfg" lua $APP_PATH/haproxy.lua -path ${haproxy_path} -conf ${haproxy_conf} -dns ${LOCAL_DNS} ln_run "$(first_type haproxy)" haproxy "/dev/null" -f "${haproxy_path}/${haproxy_conf}" @@ -1751,15 +1793,14 @@ acl_app() { dnsmasq_port=$(get_new_port $(expr $dnsmasq_port + 1)) local dnsmasq_conf=${acl_path}/dnsmasq.conf local dnsmasq_conf_path=${acl_path}/dnsmasq.d - source $APP_PATH/helper_dnsmasq.sh copy_instance listen_port=$dnsmasq_port dnsmasq_conf="${dnsmasq_conf}" dnsmasq_conf_path="${dnsmasq_conf_path}" - lua $APP_PATH/helper_dnsmasq_add.lua -FLAG ${sid} -TMP_DNSMASQ_PATH ${dnsmasq_conf_path} \ - -DNSMASQ_CONF_FILE ${dnsmasq_conf} -DEFAULT_DNS $DEFAULT_DNS -LOCAL_DNS $LOCAL_DNS \ + 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}" -REMOTE_FAKEDNS 0 -USE_DEFAULT_DNS "${use_default_dns:-direct}" -CHINADNS_DNS ${_china_ng_listen:-0} \ -TCP_NODE $tcp_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 - echo "${dnsmasq_port}" > ${acl_path}/var_redirect_dns_port + set_cache_var "ACL_${sid}_dns_port" "${dnsmasq_port}" eval node_${tcp_node}_$(echo -n "${tcp_proxy_mode}${remote_dns}" | md5sum | cut -d " " -f1)=${dnsmasq_port} } _redir_port=$(eval echo \${node_${tcp_node}_redir_port}) @@ -1772,7 +1813,7 @@ acl_app() { _dns_port=$(eval echo \${node_${tcp_node}_$(echo -n "${remote_dns}" | md5sum | cut -d " " -f1)}) run_dns ${_dns_port} else - [ -n "${_dnsmasq_port}" ] && echo "${_dnsmasq_port}" > ${acl_path}/var_redirect_dns_port + [ -n "${_dnsmasq_port}" ] && set_cache_var "ACL_${sid}_dns_port" "${_dnsmasq_port}" fi else socks_port=$(get_new_port $(expr $socks_port + 1)) @@ -1810,10 +1851,10 @@ acl_app() { fi run_dns ${_dns_port} fi - echo "${tcp_node}" > ${acl_path}/var_tcp_node + set_cache_var "ACL_${sid}_tcp_node" "${tcp_node}" } fi - echo "${tcp_port}" > ${acl_path}/var_tcp_port + set_cache_var "ACL_${sid}_tcp_port" "${tcp_port}" } [ "$udp_node" != "nil" ] && { [ "$udp_node" = "tcp" ] && udp_node=$tcp_node @@ -1862,12 +1903,11 @@ acl_app() { run_ipt2socks flag=acl_${udp_node} local_port=$redir_port socks_address=127.0.0.1 socks_port=$socks_port log_file=$log_file fi fi - echo "${udp_node}" > ${acl_path}/var_udp_node + set_cache_var "ACL_${sid}_udp_node" "${udp_node}" fi } fi - echo "${udp_port}" > ${acl_path}/var_udp_port - udp_flag=1 + set_cache_var "ACL_${sid}_udp_port" "${udp_port}" } unset enabled sid remarks sources interface use_global_config tcp_node udp_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 dns_client_ip unset _ip _mac _iprange _ipset _ip_or_mac source_list tcp_port udp_port config_file _extra_param @@ -1913,6 +1953,14 @@ start() { [ "$(expr $dnsmasq_version \>= 2.90)" == 0 ] && echolog "Dnsmasq版本低于2.90,建议升级至2.90及以上版本以避免部分情况下Dnsmasq崩溃问题!" } + if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then + [ "$(uci -q get dhcp.@dnsmasq[0].dns_redirect)" == "1" ] && { + uci -q set dhcp.@dnsmasq[0].dns_redirect='0' 2>/dev/null + uci commit dhcp 2>/dev/null + /etc/init.d/dnsmasq restart >/dev/null 2>&1 + } + fi + [ "$ENABLED_DEFAULT_ACL" == 1 ] && { mkdir -p ${GLOBAL_ACL_PATH} start_redir TCP @@ -1920,6 +1968,19 @@ start() { start_dns } [ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start + set_cache_var "USE_TABLES" "$USE_TABLES" + [ -z "$(get_cache_var "ACL_default_dns_port")" ] && lua $APP_PATH/helper_dnsmasq.lua logic_restart -LOG 1 + if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then + bridge_nf_ipt=$(sysctl -e -n net.bridge.bridge-nf-call-iptables) + set_cache_var "bak_bridge_nf_ipt" "$bridge_nf_ipt" + sysctl -w net.bridge.bridge-nf-call-iptables=0 >/dev/null 2>&1 + [ "$PROXY_IPV6" == "1" ] && { + bridge_nf_ip6t=$(sysctl -e -n net.bridge.bridge-nf-call-ip6tables) + set_cache_var "bak_bridge_nf_ip6t" "$bridge_nf_ip6t" + sysctl -w net.bridge.bridge-nf-call-ip6tables=0 >/dev/null 2>&1 + } + fi + start_crontab echolog "运行完成!\n" } @@ -1936,9 +1997,14 @@ stop() { unset XRAY_LOCATION_ASSET stop_crontab source $APP_PATH/helper_smartdns.sh del - [ -s "$TMP_PATH/bridge_nf_ipt" ] && sysctl -w net.bridge.bridge-nf-call-iptables=$(cat $TMP_PATH/bridge_nf_ipt) >/dev/null 2>&1 - [ -s "$TMP_PATH/bridge_nf_ip6t" ] && sysctl -w net.bridge.bridge-nf-call-ip6tables=$(cat $TMP_PATH/bridge_nf_ip6t) >/dev/null 2>&1 - rm -rf ${TMP_PATH} + rm -rf $GLOBAL_DNSMASQ_CONF + rm -rf $GLOBAL_DNSMASQ_CONF_PATH + [ -z "$(get_cache_var "ACL_default_dns_port")" ] && lua $APP_PATH/helper_dnsmasq.lua restart -LOG 0 + bak_bridge_nf_ipt=$(get_cache_var "bak_bridge_nf_ipt") + [ -n "${bak_bridge_nf_ipt}" ] && sysctl -w net.bridge.bridge-nf-call-iptables=${bak_bridge_nf_ipt} >/dev/null 2>&1 + bak_bridge_nf_ip6t=$(get_cache_var "bak_bridge_nf_ip6t") + [ -n "${bak_bridge_nf_ip6t}" ] && sysctl -w net.bridge.bridge-nf-call-ip6tables=${bak_bridge_nf_ip6t} >/dev/null 2>&1 + rm -rf $TMP_PATH rm -rf /tmp/lock/${CONFIG}_socks_auto_switch* echolog "清空并关闭相关程序和缓存完成。" exit 0 @@ -2011,13 +2077,28 @@ DEFAULT_DNS=$(uci show dhcp.@dnsmasq[0] | grep "\.server=" | awk -F '=' '{print LOCAL_DNS="${DEFAULT_DNS:-119.29.29.29,223.5.5.5}" IPT_APPEND_DNS=${LOCAL_DNS} +DNSMASQ_CONF_DIR=/tmp/dnsmasq.d +TMP_DNSMASQ_PATH=${DNSMASQ_CONF_DIR}/${CONFIG} +DEFAULT_DNSMASQ_CFGID="$(uci -q show "dhcp.@dnsmasq[0]" | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')" +if [ -f "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID" ]; then + DNSMASQ_CONF_DIR="$(awk -F '=' '/^conf-dir=/ {print $2}' "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID")" + if [ -n "$DNSMASQ_CONF_DIR" ]; then + DNSMASQ_CONF_DIR=${DNSMASQ_CONF_DIR%*/} + TMP_DNSMASQ_PATH=${DNSMASQ_CONF_DIR}/${CONFIG} + else + DNSMASQ_CONF_DIR="/tmp/dnsmasq.d" + fi +fi +GLOBAL_DNSMASQ_CONF=${DNSMASQ_CONF_DIR}/dnsmasq-${CONFIG}.conf +GLOBAL_DNSMASQ_CONF_PATH=${TMP_DNSMASQ_PATH} + DNS_QUERY_STRATEGY="UseIP" [ "$FILTER_PROXY_IPV6" = "1" ] && DNS_QUERY_STRATEGY="UseIPv4" DNSMASQ_FILTER_PROXY_IPV6=${FILTER_PROXY_IPV6} export V2RAY_LOCATION_ASSET=$(config_t_get global_rules v2ray_location_asset "/usr/share/v2ray/") export XRAY_LOCATION_ASSET=$V2RAY_LOCATION_ASSET -mkdir -p /tmp/etc $TMP_PATH $TMP_BIN_PATH $TMP_SCRIPT_FUNC_PATH $TMP_ID_PATH $TMP_ROUTE_PATH $TMP_ACL_PATH $TMP_IFACE_PATH $TMP_PATH2 +mkdir -p /tmp/etc $TMP_PATH $TMP_BIN_PATH $TMP_SCRIPT_FUNC_PATH $TMP_ROUTE_PATH $TMP_ACL_PATH $TMP_PATH2 arg1=$1 shift @@ -2040,6 +2121,12 @@ socks_node_switch) echolog) echolog $@ ;; +get_cache_var) + get_cache_var $@ + ;; +set_cache_var) + set_cache_var $@ + ;; stop) stop ;; diff --git a/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua b/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua new file mode 100644 index 000000000..55153806f --- /dev/null +++ b/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua @@ -0,0 +1,675 @@ +local api = require "luci.passwall.api" +local appname = "passwall" +local uci = api.uci +local sys = api.sys +local fs = api.fs +local datatypes = api.datatypes +local TMP = {} + +local function tinsert(table_name, val) + if table_name and type(table_name) == "table" then + if not TMP[table_name] then + TMP[table_name] = {} + end + if TMP[table_name][val] then + return false + end + table.insert(table_name, val) + TMP[table_name][val] = true + return true + end + return false +end + +local function backup_servers() + local DNSMASQ_DNS = uci:get("dhcp", "@dnsmasq[0]", "server") + if DNSMASQ_DNS and #DNSMASQ_DNS > 0 then + uci:set(appname, "@global[0]", "dnsmasq_servers", DNSMASQ_DNS) + uci:commit(appname) + end +end + +local function restore_servers() + local dns_table = {} + local DNSMASQ_DNS = uci:get("dhcp", "@dnsmasq[0]", "server") + if DNSMASQ_DNS and #DNSMASQ_DNS > 0 then + for k, v in ipairs(DNSMASQ_DNS) do + tinsert(dns_table, v) + end + end + local OLD_SERVER = uci:get(appname, "@global[0]", "dnsmasq_servers") + if OLD_SERVER and #OLD_SERVER > 0 then + for k, v in ipairs(OLD_SERVER) do + tinsert(dns_table, v) + end + uci:delete(appname, "@global[0]", "dnsmasq_servers") + uci:commit(appname) + end + if dns_table and #dns_table > 0 then + uci:set_list("dhcp", "@dnsmasq[0]", "server", dns_table) + uci:commit("dhcp") + end +end + +function stretch() + local dnsmasq_server = uci:get("dhcp", "@dnsmasq[0]", "server") + local dnsmasq_noresolv = uci:get("dhcp", "@dnsmasq[0]", "noresolv") + local _flag + if dnsmasq_server and #dnsmasq_server > 0 then + for k, v in ipairs(dnsmasq_server) do + if not v:find("/") then + _flag = true + end + end + end + if not _flag and dnsmasq_noresolv == "1" then + uci:delete("dhcp", "@dnsmasq[0]", "noresolv") + local RESOLVFILE = "/tmp/resolv.conf.d/resolv.conf.auto" + local file = io.open(RESOLVFILE, "r") + if not file then + RESOLVFILE = "/tmp/resolv.conf.auto" + else + local size = file:seek("end") + file:close() + if size == 0 then + RESOLVFILE = "/tmp/resolv.conf.auto" + end + end + uci:set("dhcp", "@dnsmasq[0]", "resolvfile", RESOLVFILE) + uci:commit("dhcp") + end +end + +function restart(var) + local LOG = var["-LOG"] + sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1") + if LOG == "1" then + api.log("重启 dnsmasq 服务") + end +end + +function logic_restart(var) + local LOG = var["-LOG"] + local DEFAULT_DNS = api.get_cache_var("DEFAULT_DNS") + if DEFAULT_DNS then + backup_servers() + --sys.call("sed -i '/list server/d' /etc/config/dhcp >/dev/null 2>&1") + local dns_table = {} + local dnsmasq_server = uci:get("dhcp", "@dnsmasq[0]", "server") + if dnsmasq_server and #dnsmasq_server > 0 then + for k, v in ipairs(dnsmasq_server) do + if v:find("/") then + tinsert(dns_table, v) + end + end + if dns_table and #dns_table > 0 then + uci:set_list("dhcp", "@dnsmasq[0]", "server", dns_table) + uci:commit("dhcp") + end + end + sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1") + restore_servers() + else + sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1") + end + if LOG == "1" then + api.log("重启 dnsmasq 服务") + end +end + +function copy_instance(var) + local LISTEN_PORT = var["-LISTEN_PORT"] + local DNSMASQ_CONF = var["-DNSMASQ_CONF"] + local conf_lines = {} + local DEFAULT_DNSMASQ_CFGID = sys.exec("echo -n $(uci -q show dhcp.@dnsmasq[0] | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')") + for line in io.lines("/tmp/etc/dnsmasq.conf." .. DEFAULT_DNSMASQ_CFGID) do + local filter + if line:find("passwall") then filter = true end + if line:find("ubus") then filter = true end + if line:find("dhcp") then filter = true end + if line:find("server") then filter = true end + if line:find("port") then filter = true end + if not filter then + tinsert(conf_lines, line) + end + end + tinsert(conf_lines, "port=" .. LISTEN_PORT) + if #conf_lines > 0 then + local conf_out = io.open(DNSMASQ_CONF, "a") + conf_out:write(table.concat(conf_lines, "\n")) + conf_out:close() + end +end + +function add_rule(var) + local FLAG = var["-FLAG"] + local TMP_DNSMASQ_PATH = var["-TMP_DNSMASQ_PATH"] + local DNSMASQ_CONF_FILE = var["-DNSMASQ_CONF_FILE"] + local LISTEN_PORT = var["-LISTEN_PORT"] + local DEFAULT_DNS = var["-DEFAULT_DNS"] + local LOCAL_DNS = var["-LOCAL_DNS"] + local TUN_DNS = var["-TUN_DNS"] + local REMOTE_FAKEDNS = var["-REMOTE_FAKEDNS"] + local USE_DEFAULT_DNS = var["-USE_DEFAULT_DNS"] + local CHINADNS_DNS = var["-CHINADNS_DNS"] + local TCP_NODE = var["-TCP_NODE"] + local USE_DIRECT_LIST = var["-USE_DIRECT_LIST"] + local USE_PROXY_LIST = var["-USE_PROXY_LIST"] + local USE_BLOCK_LIST = var["-USE_BLOCK_LIST"] + local USE_GFW_LIST = var["-USE_GFW_LIST"] + local CHN_LIST = var["-CHN_LIST"] + local DEFAULT_PROXY_MODE = var["-DEFAULT_PROXY_MODE"] + local NO_PROXY_IPV6 = var["-NO_PROXY_IPV6"] + local NO_LOGIC_LOG = var["-NO_LOGIC_LOG"] + local NFTFLAG = var["-NFTFLAG"] + local CACHE_PATH = api.CACHE_PATH + local CACHE_FLAG = "dnsmasq_" .. FLAG + local CACHE_DNS_PATH = CACHE_PATH .. "/" .. CACHE_FLAG + local CACHE_TEXT_FILE = CACHE_DNS_PATH .. ".txt" + local USE_CHINADNS_NG = "0" + + local list1 = {} + local excluded_domain = {} + local excluded_domain_str = "!" + + local function log(...) + if NO_LOGIC_LOG == "1" then + return + end + api.log(...) + end + + local function check_dns(domain, dns) + if domain == "" or domain:find("#") then + return false + end + if not dns then + return + end + for k,v in ipairs(list1[domain].dns) do + if dns == v then + return true + end + end + return false + end + + local function check_ipset(domain, ipset) + if domain == "" or domain:find("#") then + return false + end + if not ipset then + return + end + for k,v in ipairs(list1[domain].ipsets) do + if ipset == v then + return true + end + end + return false + end + + local function set_domain_address(domain, address) + if domain == "" or domain:find("#") then + return + end + if not list1[domain] then + list1[domain] = { + dns = {}, + ipsets = {} + } + end + if not list1[domain].address then + list1[domain].address = address + end + end + + local function set_domain_dns(domain, dns) + if domain == "" or domain:find("#") then + return + end + if not dns then + return + end + if not list1[domain] then + list1[domain] = { + dns = {}, + ipsets = {} + } + end + for line in string.gmatch(dns, '[^' .. "," .. ']+') do + if not check_dns(domain, line) then + table.insert(list1[domain].dns, line) + end + end + end + + local function set_domain_ipset(domain, ipset) + if domain == "" or domain:find("#") then + return + end + if not ipset then + return + end + if not list1[domain] then + list1[domain] = { + dns = {}, + ipsets = {} + } + end + for line in string.gmatch(ipset, '[^' .. "," .. ']+') do + if not check_ipset(domain, line) then + table.insert(list1[domain].ipsets, line) + end + end + end + + local function add_excluded_domain(domain) + if domain == "" or domain:find("#") then + return + end + table.insert(excluded_domain, domain) + excluded_domain_str = excluded_domain_str .. "|" .. domain + end + + local function check_excluded_domain(domain) + if domain == "" or domain:find("#") then + return false + end + for k,v in ipairs(excluded_domain) do + if domain:find(v) then + return true + end + end + return false + end + + local cache_text = "" + local nodes_address_md5 = sys.exec("echo -n $(uci show passwall | grep '\\.address') | md5sum") + local new_rules = sys.exec("echo -n $(find /usr/share/passwall/rules -type f | xargs md5sum)") + local new_text = TMP_DNSMASQ_PATH .. DNSMASQ_CONF_FILE .. DEFAULT_DNS .. LOCAL_DNS .. TUN_DNS .. REMOTE_FAKEDNS .. USE_DEFAULT_DNS .. CHINADNS_DNS .. USE_DIRECT_LIST .. USE_PROXY_LIST .. USE_BLOCK_LIST .. USE_GFW_LIST .. CHN_LIST .. DEFAULT_PROXY_MODE .. NO_PROXY_IPV6 .. nodes_address_md5 .. new_rules .. NFTFLAG + if fs.access(CACHE_TEXT_FILE) then + for line in io.lines(CACHE_TEXT_FILE) do + cache_text = line + end + end + + if cache_text ~= new_text then + api.remove(CACHE_DNS_PATH .. "*") + end + + local dnsmasq_default_dns + if USE_DEFAULT_DNS ~= "nil" then + if USE_DEFAULT_DNS == "direct" then + dnsmasq_default_dns = LOCAL_DNS + end + if USE_DEFAULT_DNS == "remote" then + dnsmasq_default_dns = TUN_DNS + end + if USE_DEFAULT_DNS == "remote" and CHN_LIST == "direct" then + dnsmasq_default_dns = TUN_DNS + end + end + + local only_global + if DEFAULT_PROXY_MODE == "proxy" and CHN_LIST == "0" and USE_GFW_LIST == "0" then + --没有启用中国列表和GFW列表时 + dnsmasq_default_dns = TUN_DNS + only_global = 1 + end + if USE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0" then + dnsmasq_default_dns = CHINADNS_DNS + USE_CHINADNS_NG = "1" + end + + local setflag_4= (NFTFLAG == "1") and "4#inet#passwall#" or "" + local setflag_6= (NFTFLAG == "1") and "6#inet#passwall#" or "" + + if not fs.access(CACHE_DNS_PATH) then + fs.mkdir(CACHE_DNS_PATH) + + --屏蔽列表 + if USE_CHINADNS_NG == "0" then + if USE_BLOCK_LIST == "1" then + for line in io.lines("/usr/share/passwall/rules/block_host") do + line = api.get_std_domain(line) + if line ~= "" and not line:find("#") then + set_domain_address(line, "") + end + end + end + end + + local fwd_dns + local ipset_flag + local no_ipv6 + + --始终用国内DNS解析节点域名 + if true then + fwd_dns = LOCAL_DNS + if USE_CHINADNS_NG == "1" then + fwd_dns = nil + else + uci:foreach(appname, "nodes", function(t) + local function process_address(address) + if address == "engage.cloudflareclient.com" then return end + if datatypes.hostname(address) then + set_domain_dns(address, fwd_dns) + set_domain_ipset(address, setflag_4 .. "passwall_vpslist," .. setflag_6 .. "passwall_vpslist6") + end + end + process_address(t.address) + process_address(t.download_address) + end) + log(string.format(" - 节点列表中的域名(vpslist):%s", fwd_dns or "默认")) + end + end + + --直连(白名单)列表 + if USE_DIRECT_LIST == "1" then + if fs.access("/usr/share/passwall/rules/direct_host") then + fwd_dns = LOCAL_DNS + if USE_CHINADNS_NG == "1" then + fwd_dns = nil + end + if fwd_dns then + --始终用国内DNS解析直连(白名单)列表 + for line in io.lines("/usr/share/passwall/rules/direct_host") do + line = api.get_std_domain(line) + if line ~= "" and not line:find("#") then + add_excluded_domain(line) + set_domain_dns(line, fwd_dns) + set_domain_ipset(line, setflag_4 .. "passwall_whitelist," .. setflag_6 .. "passwall_whitelist6") + end + end + log(string.format(" - 域名白名单(whitelist):%s", fwd_dns or "默认")) + end + end + end + + --代理(黑名单)列表 + if USE_PROXY_LIST == "1" then + if fs.access("/usr/share/passwall/rules/proxy_host") then + fwd_dns = TUN_DNS + if USE_CHINADNS_NG == "1" then + fwd_dns = nil + end + if fwd_dns then + --始终使用远程DNS解析代理(黑名单)列表 + for line in io.lines("/usr/share/passwall/rules/proxy_host") do + line = api.get_std_domain(line) + if line ~= "" and not line:find("#") then + add_excluded_domain(line) + local ipset_flag = setflag_4 .. "passwall_blacklist," .. setflag_6 .. "passwall_blacklist6" + if NO_PROXY_IPV6 == "1" then + set_domain_address(line, "::") + ipset_flag = setflag_4 .. "passwall_blacklist" + end + if REMOTE_FAKEDNS == "1" then + ipset_flag = nil + end + set_domain_dns(line, fwd_dns) + set_domain_ipset(line, ipset_flag) + end + end + log(string.format(" - 代理域名表(blacklist):%s", fwd_dns or "默认")) + end + end + end + + --GFW列表 + if USE_GFW_LIST == "1" then + if fs.access("/usr/share/passwall/rules/gfwlist") then + fwd_dns = TUN_DNS + if USE_CHINADNS_NG == "1" then + fwd_dns = nil + end + if fwd_dns then + local ipset_flag = setflag_4 .. "passwall_gfwlist," .. setflag_6 .. "passwall_gfwlist6" + if NO_PROXY_IPV6 == "1" then + ipset_flag = setflag_4 .. "passwall_gfwlist" + end + if REMOTE_FAKEDNS == "1" then + ipset_flag = nil + end + local gfwlist_str = sys.exec('cat /usr/share/passwall/rules/gfwlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"') + for line in string.gmatch(gfwlist_str, "[^\r\n]+") do + if line ~= "" then + if NO_PROXY_IPV6 == "1" then + set_domain_address(line, "::") + end + if dnsmasq_default_dns == fwd_dns then + fwd_dns = nil + else + set_domain_dns(line, fwd_dns) + end + set_domain_ipset(line, ipset_flag) + end + end + log(string.format(" - 防火墙域名表(gfwlist):%s", fwd_dns or "默认")) + end + end + end + + --中国列表 + if CHN_LIST ~= "0" then + if fs.access("/usr/share/passwall/rules/chnlist") then + fwd_dns = nil + if CHN_LIST == "direct" then + fwd_dns = LOCAL_DNS + end + if CHN_LIST == "proxy" then + fwd_dns = TUN_DNS + end + if USE_CHINADNS_NG == "1" then + fwd_dns = nil + end + if fwd_dns then + local ipset_flag = setflag_4 .. "passwall_chnroute," .. setflag_6 .. "passwall_chnroute6" + if CHN_LIST == "proxy" then + if NO_PROXY_IPV6 == "1" then + ipset_flag = setflag_4 .. "passwall_chnroute" + end + if REMOTE_FAKEDNS == "1" then + ipset_flag = nil + end + end + local chnlist_str = sys.exec('cat /usr/share/passwall/rules/chnlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"') + for line in string.gmatch(chnlist_str, "[^\r\n]+") do + if line ~= "" then + if CHN_LIST == "proxy" and NO_PROXY_IPV6 == "1" then + set_domain_address(line, "::") + end + if dnsmasq_default_dns == fwd_dns then + fwd_dns = nil + else + set_domain_dns(line, fwd_dns) + end + set_domain_ipset(line, ipset_flag) + end + end + log(string.format(" - 中国域名表(chnroute):%s", fwd_dns or "默认")) + end + end + end + + --分流规则 + if uci:get(appname, TCP_NODE, "protocol") == "_shunt" and USE_CHINADNS_NG == "0" then + local t = uci:get_all(appname, TCP_NODE) + local default_node_id = t["default_node"] or "_direct" + uci:foreach(appname, "shunt_rules", function(s) + local _node_id = t[s[".name"]] or "nil" + if _node_id ~= "nil" and _node_id ~= "_blackhole" then + if _node_id == "_default" then + _node_id = default_node_id + end + + fwd_dns = nil + ipset_flag = nil + no_ipv6 = nil + + if _node_id == "_direct" then + fwd_dns = LOCAL_DNS + if USE_DIRECT_LIST == "1" then + ipset_flag = setflag_4 .. "passwall_whitelist," .. setflag_6 .. "passwall_whitelist6" + else + ipset_flag = setflag_4 .. "passwall_shuntlist," .. setflag_6 .. "passwall_shuntlist6" + end + else + fwd_dns = TUN_DNS + ipset_flag = setflag_4 .. "passwall_shuntlist," .. setflag_6 .. "passwall_shuntlist6" + if NO_PROXY_IPV6 == "1" then + ipset_flag = setflag_4 .. "passwall_shuntlist" + no_ipv6 = true + end + if not only_global then + if REMOTE_FAKEDNS == "1" then + ipset_flag = nil + end + end + end + + local domain_list = s.domain_list or "" + for line in string.gmatch(domain_list, "[^\r\n]+") do + if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("geosite:") and not line:find("ext:") then + if line:find("domain:") or line:find("full:") then + line = string.match(line, ":([^:]+)$") + end + line = api.get_std_domain(line) + add_excluded_domain(line) + + if no_ipv6 then + set_domain_address(line, "::") + end + set_domain_dns(line, fwd_dns) + set_domain_ipset(line, ipset_flag) + end + end + if _node_id ~= "_direct" then + log(string.format(" - Sing-Box/Xray分流规则(%s):%s", s.remarks, fwd_dns or "默认")) + end + end + end) + elseif only_global == 1 and NO_PROXY_IPV6 == "1" then + --节点:固定节点 + --代理模式:全局模式 + --过滤代理域名 IPv6:启用 + --禁止解析所有IPv6记录 + list1["#"] = { + dns = {}, + ipsets = {}, + address = "::" + } + end + + if list1 and next(list1) then + local address_out = io.open(CACHE_DNS_PATH .. "/000-address.conf", "a") + local server_out = io.open(CACHE_DNS_PATH .. "/001-server.conf", "a") + local ipset_out = io.open(CACHE_DNS_PATH .. "/ipset.conf", "a") + local set_name = "ipset" + if NFTFLAG == "1" then + set_name = "nftset" + end + for key, value in pairs(list1) do + if value.address then + local domain = "." .. key + if key == "#" then + domain = key + end + address_out:write(string.format("address=/%s/%s", domain, value.address) .. "\n") + end + if value.dns and #value.dns > 0 then + for i, dns in ipairs(value.dns) do + server_out:write(string.format("server=/.%s/%s", key, dns) .. "\n") + end + end + if value.ipsets and #value.ipsets > 0 then + local ipsets_str = "" + for i, ipset in ipairs(value.ipsets) do + ipsets_str = ipsets_str .. ipset .. "," + end + ipsets_str = ipsets_str:sub(1, #ipsets_str - 1) + ipset_out:write(string.format("%s=/.%s/%s", set_name, key, ipsets_str) .. "\n") + end + end + address_out:close() + server_out:close() + ipset_out:close() + end + + local f_out = io.open(CACHE_TEXT_FILE, "a") + f_out:write(new_text) + f_out:close() + end + + if USE_CHINADNS_NG == "0" then + if api.is_install("procd\\-ujail") then + fs.copyr(CACHE_DNS_PATH, TMP_DNSMASQ_PATH) + else + api.remove(TMP_DNSMASQ_PATH) + fs.symlink(CACHE_DNS_PATH, TMP_DNSMASQ_PATH) + end + end + + if DNSMASQ_CONF_FILE ~= "nil" then + local conf_lines = {} + if LISTEN_PORT then + --Copy dnsmasq instance + local DEFAULT_DNSMASQ_CFGID = sys.exec("echo -n $(uci -q show dhcp.@dnsmasq[0] | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')") + for line in io.lines("/tmp/etc/dnsmasq.conf." .. DEFAULT_DNSMASQ_CFGID) do + local filter + if line:find("passwall") then filter = true end + if line:find("ubus") then filter = true end + if line:find("dhcp") then filter = true end + if line:find("server") then filter = true end + if line:find("port") then filter = true end + if not filter then + tinsert(conf_lines, line) + end + end + tinsert(conf_lines, "port=" .. LISTEN_PORT) + else + --Modify the default dnsmasq service + end + if USE_CHINADNS_NG == "0" then + tinsert(conf_lines, string.format("conf-dir=%s", TMP_DNSMASQ_PATH)) + end + if dnsmasq_default_dns then + for s in string.gmatch(dnsmasq_default_dns, '[^' .. "," .. ']+') do + tinsert(conf_lines, string.format("server=%s", s)) + end + tinsert(conf_lines, "all-servers") + tinsert(conf_lines, "no-poll") + tinsert(conf_lines, "no-resolv") + if USE_CHINADNS_NG == "0" then + log(string.format(" - 默认:%s", dnsmasq_default_dns)) + end + + if FLAG == "default" then + api.set_cache_var("DEFAULT_DNS", DEFAULT_DNS) + end + end + if #conf_lines > 0 then + local conf_out = io.open(DNSMASQ_CONF_FILE, "a") + conf_out:write(table.concat(conf_lines, "\n")) + conf_out:close() + end + end + + if USE_CHINADNS_NG == "0" then + log(" - PassWall必须依赖于Dnsmasq,如果你自行配置了错误的DNS流程,将会导致域名(直连/代理域名)分流失效!!!") + end +end + +_G.stretch = stretch +_G.restart = restart +_G.logic_restart = logic_restart +_G.copy_instance = copy_instance +_G.add_rule = add_rule + +if arg[1] then + local func =_G[arg[1]] + if func then + func(api.get_function_args(arg)) + end +end diff --git a/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.sh b/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.sh deleted file mode 100755 index 746726084..000000000 --- a/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -copy_instance() { - local listen_port dnsmasq_conf - eval_set_val $@ - [ -s "/tmp/etc/dnsmasq.conf.${DEFAULT_DNSMASQ_CFGID}" ] && { - cp -r /tmp/etc/dnsmasq.conf.${DEFAULT_DNSMASQ_CFGID} $dnsmasq_conf - sed -i "/ubus/d" $dnsmasq_conf - sed -i "/dhcp/d" $dnsmasq_conf - sed -i "/port=/d" $dnsmasq_conf - sed -i "/conf-dir/d" $dnsmasq_conf - sed -i "/no-poll/d" $dnsmasq_conf - sed -i "/no-resolv/d" $dnsmasq_conf - } - echo "port=${listen_port}" >> $dnsmasq_conf -} - -DEFAULT_DNSMASQ_CFGID="$(uci -q show "dhcp.@dnsmasq[0]" | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')" - -arg1=$1 -shift -case $arg1 in -copy_instance) - copy_instance $@ - ;; -*) ;; -esac diff --git a/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq_add.lua b/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq_add.lua deleted file mode 100644 index 6c0176607..000000000 --- a/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq_add.lua +++ /dev/null @@ -1,506 +0,0 @@ -require "luci.sys" -local api = require "luci.passwall.api" -local appname = "passwall" - -local var = api.get_args(arg) -local FLAG = var["-FLAG"] -local TMP_DNSMASQ_PATH = var["-TMP_DNSMASQ_PATH"] -local DNSMASQ_CONF_FILE = var["-DNSMASQ_CONF_FILE"] -local DEFAULT_DNS = var["-DEFAULT_DNS"] -local LOCAL_DNS = var["-LOCAL_DNS"] -local TUN_DNS = var["-TUN_DNS"] -local REMOTE_FAKEDNS = var["-REMOTE_FAKEDNS"] -local USE_DEFAULT_DNS = var["-USE_DEFAULT_DNS"] -local CHINADNS_DNS = var["-CHINADNS_DNS"] -local TCP_NODE = var["-TCP_NODE"] -local USE_DIRECT_LIST = var["-USE_DIRECT_LIST"] -local USE_PROXY_LIST = var["-USE_PROXY_LIST"] -local USE_BLOCK_LIST = var["-USE_BLOCK_LIST"] -local USE_GFW_LIST = var["-USE_GFW_LIST"] -local CHN_LIST = var["-CHN_LIST"] -local DEFAULT_PROXY_MODE = var["-DEFAULT_PROXY_MODE"] -local NO_PROXY_IPV6 = var["-NO_PROXY_IPV6"] -local NO_LOGIC_LOG = var["-NO_LOGIC_LOG"] -local NFTFLAG = var["-NFTFLAG"] -local CACHE_PATH = api.CACHE_PATH -local CACHE_FLAG = "dnsmasq_" .. FLAG -local CACHE_DNS_PATH = CACHE_PATH .. "/" .. CACHE_FLAG -local CACHE_TEXT_FILE = CACHE_DNS_PATH .. ".txt" -local USE_CHINADNS_NG = "0" - -local uci = api.uci -local sys = api.sys -local fs = api.fs -local datatypes = api.datatypes - -local list1 = {} -local excluded_domain = {} -local excluded_domain_str = "!" - -local function log(...) - if NO_LOGIC_LOG == "1" then - return - end - api.log(...) -end - -local function check_dns(domain, dns) - if domain == "" or domain:find("#") then - return false - end - if not dns then - return - end - for k,v in ipairs(list1[domain].dns) do - if dns == v then - return true - end - end - return false -end - -local function check_ipset(domain, ipset) - if domain == "" or domain:find("#") then - return false - end - if not ipset then - return - end - for k,v in ipairs(list1[domain].ipsets) do - if ipset == v then - return true - end - end - return false -end - -local function set_domain_address(domain, address) - if domain == "" or domain:find("#") then - return - end - if not list1[domain] then - list1[domain] = { - dns = {}, - ipsets = {} - } - end - if not list1[domain].address then - list1[domain].address = address - end -end - -local function set_domain_dns(domain, dns) - if domain == "" or domain:find("#") then - return - end - if not dns then - return - end - if not list1[domain] then - list1[domain] = { - dns = {}, - ipsets = {} - } - end - for line in string.gmatch(dns, '[^' .. "," .. ']+') do - if not check_dns(domain, line) then - table.insert(list1[domain].dns, line) - end - end -end - -local function set_domain_ipset(domain, ipset) - if domain == "" or domain:find("#") then - return - end - if not ipset then - return - end - if not list1[domain] then - list1[domain] = { - dns = {}, - ipsets = {} - } - end - for line in string.gmatch(ipset, '[^' .. "," .. ']+') do - if not check_ipset(domain, line) then - table.insert(list1[domain].ipsets, line) - end - end -end - -local function add_excluded_domain(domain) - if domain == "" or domain:find("#") then - return - end - table.insert(excluded_domain, domain) - excluded_domain_str = excluded_domain_str .. "|" .. domain -end - -local function check_excluded_domain(domain) - if domain == "" or domain:find("#") then - return false - end - for k,v in ipairs(excluded_domain) do - if domain:find(v) then - return true - end - end - return false -end - -local cache_text = "" -local nodes_address_md5 = luci.sys.exec("echo -n $(uci show passwall | grep '\\.address') | md5sum") -local new_rules = luci.sys.exec("echo -n $(find /usr/share/passwall/rules -type f | xargs md5sum)") -local new_text = TMP_DNSMASQ_PATH .. DNSMASQ_CONF_FILE .. DEFAULT_DNS .. LOCAL_DNS .. TUN_DNS .. REMOTE_FAKEDNS .. USE_DEFAULT_DNS .. CHINADNS_DNS .. USE_DIRECT_LIST .. USE_PROXY_LIST .. USE_BLOCK_LIST .. USE_GFW_LIST .. CHN_LIST .. DEFAULT_PROXY_MODE .. NO_PROXY_IPV6 .. nodes_address_md5 .. new_rules .. NFTFLAG -if fs.access(CACHE_TEXT_FILE) then - for line in io.lines(CACHE_TEXT_FILE) do - cache_text = line - end -end - -if cache_text ~= new_text then - api.remove(CACHE_DNS_PATH .. "*") -end - -local dnsmasq_default_dns -if USE_DEFAULT_DNS ~= "nil" then - if USE_DEFAULT_DNS == "direct" then - dnsmasq_default_dns = LOCAL_DNS - end - if USE_DEFAULT_DNS == "remote" then - dnsmasq_default_dns = TUN_DNS - end - if USE_DEFAULT_DNS == "remote" and CHN_LIST == "direct" then - dnsmasq_default_dns = TUN_DNS - end -end - -local only_global -if DEFAULT_PROXY_MODE == "proxy" and CHN_LIST == "0" and USE_GFW_LIST == "0" then - --没有启用中国列表和GFW列表时 - dnsmasq_default_dns = TUN_DNS - only_global = 1 -end -if USE_DEFAULT_DNS == "chinadns_ng" and CHINADNS_DNS ~= "0" then - dnsmasq_default_dns = CHINADNS_DNS - USE_CHINADNS_NG = "1" -end - -local setflag_4= (NFTFLAG == "1") and "4#inet#passwall#" or "" -local setflag_6= (NFTFLAG == "1") and "6#inet#passwall#" or "" - -if not fs.access(CACHE_DNS_PATH) then - fs.mkdir(CACHE_DNS_PATH) - - --屏蔽列表 - if USE_CHINADNS_NG == "0" then - if USE_BLOCK_LIST == "1" then - for line in io.lines("/usr/share/passwall/rules/block_host") do - line = api.get_std_domain(line) - if line ~= "" and not line:find("#") then - set_domain_address(line, "") - end - end - end - end - - local fwd_dns - local ipset_flag - local no_ipv6 - - --始终用国内DNS解析节点域名 - if true then - fwd_dns = LOCAL_DNS - if USE_CHINADNS_NG == "1" then - fwd_dns = nil - else - uci:foreach(appname, "nodes", function(t) - local function process_address(address) - if address == "engage.cloudflareclient.com" then return end - if datatypes.hostname(address) then - set_domain_dns(address, fwd_dns) - set_domain_ipset(address, setflag_4 .. "passwall_vpslist," .. setflag_6 .. "passwall_vpslist6") - end - end - process_address(t.address) - process_address(t.download_address) - end) - log(string.format(" - 节点列表中的域名(vpslist):%s", fwd_dns or "默认")) - end - end - - --直连(白名单)列表 - if USE_DIRECT_LIST == "1" then - if fs.access("/usr/share/passwall/rules/direct_host") then - fwd_dns = LOCAL_DNS - if USE_CHINADNS_NG == "1" then - fwd_dns = nil - end - if fwd_dns then - --始终用国内DNS解析直连(白名单)列表 - for line in io.lines("/usr/share/passwall/rules/direct_host") do - line = api.get_std_domain(line) - if line ~= "" and not line:find("#") then - add_excluded_domain(line) - set_domain_dns(line, fwd_dns) - set_domain_ipset(line, setflag_4 .. "passwall_whitelist," .. setflag_6 .. "passwall_whitelist6") - end - end - log(string.format(" - 域名白名单(whitelist):%s", fwd_dns or "默认")) - end - end - end - - --代理(黑名单)列表 - if USE_PROXY_LIST == "1" then - if fs.access("/usr/share/passwall/rules/proxy_host") then - fwd_dns = TUN_DNS - if USE_CHINADNS_NG == "1" then - fwd_dns = nil - end - if fwd_dns then - --始终使用远程DNS解析代理(黑名单)列表 - for line in io.lines("/usr/share/passwall/rules/proxy_host") do - line = api.get_std_domain(line) - if line ~= "" and not line:find("#") then - add_excluded_domain(line) - local ipset_flag = setflag_4 .. "passwall_blacklist," .. setflag_6 .. "passwall_blacklist6" - if NO_PROXY_IPV6 == "1" then - set_domain_address(line, "::") - ipset_flag = setflag_4 .. "passwall_blacklist" - end - if REMOTE_FAKEDNS == "1" then - ipset_flag = nil - end - set_domain_dns(line, fwd_dns) - set_domain_ipset(line, ipset_flag) - end - end - log(string.format(" - 代理域名表(blacklist):%s", fwd_dns or "默认")) - end - end - end - - --GFW列表 - if USE_GFW_LIST == "1" then - if fs.access("/usr/share/passwall/rules/gfwlist") then - fwd_dns = TUN_DNS - if USE_CHINADNS_NG == "1" then - fwd_dns = nil - end - if fwd_dns then - local ipset_flag = setflag_4 .. "passwall_gfwlist," .. setflag_6 .. "passwall_gfwlist6" - if NO_PROXY_IPV6 == "1" then - ipset_flag = setflag_4 .. "passwall_gfwlist" - end - if REMOTE_FAKEDNS == "1" then - ipset_flag = nil - end - local gfwlist_str = sys.exec('cat /usr/share/passwall/rules/gfwlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"') - for line in string.gmatch(gfwlist_str, "[^\r\n]+") do - if line ~= "" then - if NO_PROXY_IPV6 == "1" then - set_domain_address(line, "::") - end - if dnsmasq_default_dns == fwd_dns then - fwd_dns = nil - else - set_domain_dns(line, fwd_dns) - end - set_domain_ipset(line, ipset_flag) - end - end - log(string.format(" - 防火墙域名表(gfwlist):%s", fwd_dns or "默认")) - end - end - end - - --中国列表 - if CHN_LIST ~= "0" then - if fs.access("/usr/share/passwall/rules/chnlist") then - fwd_dns = nil - if CHN_LIST == "direct" then - fwd_dns = LOCAL_DNS - end - if CHN_LIST == "proxy" then - fwd_dns = TUN_DNS - end - if USE_CHINADNS_NG == "1" then - fwd_dns = nil - end - if fwd_dns then - local ipset_flag = setflag_4 .. "passwall_chnroute," .. setflag_6 .. "passwall_chnroute6" - if CHN_LIST == "proxy" then - if NO_PROXY_IPV6 == "1" then - ipset_flag = setflag_4 .. "passwall_chnroute" - end - if REMOTE_FAKEDNS == "1" then - ipset_flag = nil - end - end - local chnlist_str = sys.exec('cat /usr/share/passwall/rules/chnlist | grep -v -E "^#" | grep -v -E "' .. excluded_domain_str .. '"') - for line in string.gmatch(chnlist_str, "[^\r\n]+") do - if line ~= "" then - if CHN_LIST == "proxy" and NO_PROXY_IPV6 == "1" then - set_domain_address(line, "::") - end - if dnsmasq_default_dns == fwd_dns then - fwd_dns = nil - else - set_domain_dns(line, fwd_dns) - end - set_domain_ipset(line, ipset_flag) - end - end - log(string.format(" - 中国域名表(chnroute):%s", fwd_dns or "默认")) - end - end - end - - --分流规则 - if uci:get(appname, TCP_NODE, "protocol") == "_shunt" and USE_CHINADNS_NG == "0" then - local t = uci:get_all(appname, TCP_NODE) - local default_node_id = t["default_node"] or "_direct" - uci:foreach(appname, "shunt_rules", function(s) - local _node_id = t[s[".name"]] or "nil" - if _node_id ~= "nil" and _node_id ~= "_blackhole" then - if _node_id == "_default" then - _node_id = default_node_id - end - - fwd_dns = nil - ipset_flag = nil - no_ipv6 = nil - - if _node_id == "_direct" then - fwd_dns = LOCAL_DNS - if USE_DIRECT_LIST == "1" then - ipset_flag = setflag_4 .. "passwall_whitelist," .. setflag_6 .. "passwall_whitelist6" - else - ipset_flag = setflag_4 .. "passwall_shuntlist," .. setflag_6 .. "passwall_shuntlist6" - end - else - fwd_dns = TUN_DNS - ipset_flag = setflag_4 .. "passwall_shuntlist," .. setflag_6 .. "passwall_shuntlist6" - if NO_PROXY_IPV6 == "1" then - ipset_flag = setflag_4 .. "passwall_shuntlist" - no_ipv6 = true - end - if not only_global then - if REMOTE_FAKEDNS == "1" then - ipset_flag = nil - end - end - end - - local domain_list = s.domain_list or "" - for line in string.gmatch(domain_list, "[^\r\n]+") do - if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("geosite:") and not line:find("ext:") then - if line:find("domain:") or line:find("full:") then - line = string.match(line, ":([^:]+)$") - end - line = api.get_std_domain(line) - add_excluded_domain(line) - - if no_ipv6 then - set_domain_address(line, "::") - end - set_domain_dns(line, fwd_dns) - set_domain_ipset(line, ipset_flag) - end - end - if _node_id ~= "_direct" then - log(string.format(" - Sing-Box/Xray分流规则(%s):%s", s.remarks, fwd_dns or "默认")) - end - end - end) - elseif only_global == 1 and NO_PROXY_IPV6 == "1" then - --节点:固定节点 - --代理模式:全局模式 - --过滤代理域名 IPv6:启用 - --禁止解析所有IPv6记录 - list1["#"] = { - dns = {}, - ipsets = {}, - address = "::" - } - end - - if list1 and next(list1) then - local address_out = io.open(CACHE_DNS_PATH .. "/000-address.conf", "a") - local server_out = io.open(CACHE_DNS_PATH .. "/001-server.conf", "a") - local ipset_out = io.open(CACHE_DNS_PATH .. "/ipset.conf", "a") - local set_name = "ipset" - if NFTFLAG == "1" then - set_name = "nftset" - end - for key, value in pairs(list1) do - if value.address then - local domain = "." .. key - if key == "#" then - domain = key - end - address_out:write(string.format("address=/%s/%s\n", domain, value.address)) - end - if value.dns and #value.dns > 0 then - for i, dns in ipairs(value.dns) do - server_out:write(string.format("server=/.%s/%s\n", key, dns)) - end - end - if value.ipsets and #value.ipsets > 0 then - local ipsets_str = "" - for i, ipset in ipairs(value.ipsets) do - ipsets_str = ipsets_str .. ipset .. "," - end - ipsets_str = ipsets_str:sub(1, #ipsets_str - 1) - ipset_out:write(string.format("%s=/.%s/%s\n", set_name, key, ipsets_str)) - end - end - address_out:close() - server_out:close() - ipset_out:close() - end - - local f_out = io.open(CACHE_TEXT_FILE, "a") - f_out:write(new_text) - f_out:close() -end - -if USE_CHINADNS_NG == "0" then - if api.is_install("procd\\-ujail") then - fs.copyr(CACHE_DNS_PATH, TMP_DNSMASQ_PATH) - else - api.remove(TMP_DNSMASQ_PATH) - fs.symlink(CACHE_DNS_PATH, TMP_DNSMASQ_PATH) - end -end - -if DNSMASQ_CONF_FILE ~= "nil" then - local conf_out = io.open(DNSMASQ_CONF_FILE, "a") - if USE_CHINADNS_NG == "0" then - conf_out:write(string.format("conf-dir=%s\n", TMP_DNSMASQ_PATH)) - end - if dnsmasq_default_dns then - for s in string.gmatch(dnsmasq_default_dns, '[^' .. "," .. ']+') do - conf_out:write(string.format("server=%s\n", s)) - end - conf_out:write("all-servers\n") - conf_out:write("no-poll\n") - conf_out:write("no-resolv\n") - conf_out:close() - if USE_CHINADNS_NG == "0" then - log(string.format(" - 默认:%s", dnsmasq_default_dns)) - end - - if FLAG == "default" then - local f_out = io.open("/tmp/etc/passwall/default_DNS", "a") - f_out:write(DEFAULT_DNS) - f_out:close() - end - end -end - -if USE_CHINADNS_NG == "0" then - log(" - PassWall必须依赖于Dnsmasq,如果你自行配置了错误的DNS流程,将会导致域名(直连/代理域名)分流失效!!!") -end diff --git a/luci-app-passwall/root/usr/share/passwall/iptables.sh b/luci-app-passwall/root/usr/share/passwall/iptables.sh index ac2895566..826297bf8 100755 --- a/luci-app-passwall/root/usr/share/passwall/iptables.sh +++ b/luci-app-passwall/root/usr/share/passwall/iptables.sh @@ -2,6 +2,7 @@ DIR="$(cd "$(dirname "$0")" && pwd)" MY_PATH=$DIR/iptables.sh +IPSET_LOCALLIST="passwall_locallist" IPSET_LANLIST="passwall_lanlist" IPSET_VPSLIST="passwall_vpslist" IPSET_SHUNTLIST="passwall_shuntlist" @@ -11,6 +12,7 @@ IPSET_BLACKLIST="passwall_blacklist" IPSET_WHITELIST="passwall_whitelist" IPSET_BLOCKLIST="passwall_blocklist" +IPSET_LOCALLIST6="passwall_locallist6" IPSET_LANLIST6="passwall_lanlist6" IPSET_VPSLIST6="passwall_vpslist6" IPSET_SHUNTLIST6="passwall_shuntlist6" @@ -212,11 +214,11 @@ load_acl() { [ "$tcp_redir_ports" = "default" ] && tcp_redir_ports=$TCP_REDIR_PORTS [ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS - [ -s "${TMP_ACL_PATH}/${sid}/var_tcp_node" ] && tcp_node=$(cat ${TMP_ACL_PATH}/${sid}/var_tcp_node) - [ -s "${TMP_ACL_PATH}/${sid}/var_udp_node" ] && udp_node=$(cat ${TMP_ACL_PATH}/${sid}/var_udp_node) - [ -s "${TMP_ACL_PATH}/${sid}/var_tcp_port" ] && tcp_port=$(cat ${TMP_ACL_PATH}/${sid}/var_tcp_port) - [ -s "${TMP_ACL_PATH}/${sid}/var_udp_port" ] && udp_port=$(cat ${TMP_ACL_PATH}/${sid}/var_udp_port) - [ -s "${TMP_ACL_PATH}/${sid}/var_redirect_dns_port" ] && dns_redirect_port=$(cat ${TMP_ACL_PATH}/${sid}/var_redirect_dns_port) + [ -n "$(get_cache_var "ACL_${sid}_tcp_node")" ] && tcp_node=$(get_cache_var "ACL_${sid}_tcp_node") + [ -n "$(get_cache_var "ACL_${sid}_udp_node")" ] && udp_node=$(get_cache_var "ACL_${sid}_udp_node") + [ -n "$(get_cache_var "ACL_${sid}_tcp_port")" ] && tcp_port=$(get_cache_var "ACL_${sid}_tcp_port") + [ -n "$(get_cache_var "ACL_${sid}_udp_port")" ] && udp_port=$(get_cache_var "ACL_${sid}_udp_port") + [ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") use_shunt_tcp=0 use_shunt_udp=0 @@ -320,23 +322,23 @@ load_acl() { echolog " - ${msg}不代理所有 UDP 端口" fi } - + + local dns_redirect + [ $(config_t_get global dns_redirect "1") = "1" ] && dns_redirect=53 if ([ -n "$tcp_port" ] && [ -n "${tcp_proxy_mode}" ]) || ([ -n "$udp_port" ] && [ -n "${udp_proxy_mode}" ]); then - [ -n "$dns_redirect_port" ] && { - $ipt_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN - $ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null - $ipt_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN - $ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null - $ipt_n -A PSW_REDIRECT $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port - $ip6t_n -A PSW_REDIRECT $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port 2>/dev/null - $ipt_n -A PSW_REDIRECT $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port - $ip6t_n -A PSW_REDIRECT $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $dns_redirect_port 2>/dev/null - } + [ -n "${dns_redirect_port}" ] && dns_redirect=${dns_redirect_port} else - $ipt_n -A PSW_REDIRECT $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN - $ip6t_n -A PSW_REDIRECT $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null - $ipt_n -A PSW_REDIRECT $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN - $ip6t_n -A PSW_REDIRECT $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null + [ -n "${DIRECT_DNSMASQ_PORT}" ] && dns_redirect=${DIRECT_DNSMASQ_PORT} + fi + if [ -n "${dns_redirect}" ]; then + $ipt_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN + $ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null + $ipt_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN + $ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j RETURN 2>/dev/null + $ipt_n -A PSW_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports ${dns_redirect} + $ip6t_n -A PSW_DNS $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports ${dns_redirect} 2>/dev/null + $ipt_n -A PSW_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j REDIRECT --to-ports ${dns_redirect} + $ip6t_n -A PSW_DNS $(comment "$remarks") -p tcp ${_ipt_source} --dport 53 -j REDIRECT --to-ports ${dns_redirect} 2>/dev/null fi [ -n "$tcp_port" -o -n "$udp_port" ] && { @@ -468,7 +470,7 @@ load_acl() { unset ipt_tmp ipt_j _ipt_source msg msg2 done unset enabled sid remarks sources use_global_config use_direct_list use_proxy_list use_block_list use_gfw_list chn_list tcp_proxy_mode udp_proxy_mode dns_redirect_port tcp_no_redir_ports udp_no_redir_ports tcp_proxy_drop_ports udp_proxy_drop_ports tcp_redir_ports udp_redir_ports tcp_node udp_node interface - unset tcp_port udp_port tcp_node_remark udp_node_remark _acl_list use_shunt_tcp use_shunt_udp + unset tcp_port udp_port tcp_node_remark udp_node_remark _acl_list use_shunt_tcp use_shunt_udp dns_redirect done } @@ -498,18 +500,24 @@ load_acl() { echolog " - ${msg}不代理所有 UDP 端口" fi } - + + local DNS_REDIRECT + [ $(config_t_get global dns_redirect "1") = "1" ] && DNS_REDIRECT=53 if ([ "$TCP_NODE" != "nil" ] && [ -n "${TCP_PROXY_MODE}" ]) || ([ "$UDP_NODE" != "nil" ] && [ -n "${UDP_PROXY_MODE}" ]); then - [ -n "$DNS_REDIRECT_PORT" ] && { - $ipt_m -A PSW $(comment "默认") -p udp --dport 53 -j RETURN - $ip6t_m -A PSW $(comment "默认") -p udp --dport 53 -j RETURN 2>/dev/null - $ipt_m -A PSW $(comment "默认") -p tcp --dport 53 -j RETURN - $ip6t_m -A PSW $(comment "默认") -p tcp --dport 53 -j RETURN 2>/dev/null - $ipt_n -A PSW_REDIRECT $(comment "默认") -p udp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT - $ip6t_n -A PSW_REDIRECT $(comment "默认") -p udp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null - $ipt_n -A PSW_REDIRECT $(comment "默认") -p tcp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT - $ip6t_n -A PSW_REDIRECT $(comment "默认") -p tcp --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null - } + [ -n "${DNS_REDIRECT_PORT}" ] && DNS_REDIRECT=${DNS_REDIRECT_PORT} + else + [ -n "${DIRECT_DNSMASQ_PORT}" ] && DNS_REDIRECT=${DIRECT_DNSMASQ_PORT} + fi + + if [ -n "${DNS_REDIRECT}" ]; then + $ipt_m -A PSW $(comment "默认") -p udp --dport 53 -j RETURN + $ip6t_m -A PSW $(comment "默认") -p udp --dport 53 -j RETURN 2>/dev/null + $ipt_m -A PSW $(comment "默认") -p tcp --dport 53 -j RETURN + $ip6t_m -A PSW $(comment "默认") -p tcp --dport 53 -j RETURN 2>/dev/null + $ipt_n -A PSW_DNS $(comment "默认") -p udp --dport 53 -j REDIRECT --to-ports ${DNS_REDIRECT} + $ip6t_n -A PSW_DNS $(comment "默认") -p udp --dport 53 -j REDIRECT --to-ports ${DNS_REDIRECT} 2>/dev/null + $ipt_n -A PSW_DNS $(comment "默认") -p tcp --dport 53 -j REDIRECT --to-ports ${DNS_REDIRECT} + $ip6t_n -A PSW_DNS $(comment "默认") -p tcp --dport 53 -j REDIRECT --to-ports ${DNS_REDIRECT} 2>/dev/null fi [ -n "${TCP_PROXY_MODE}" -o -n "${UDP_PROXY_MODE}" ] && { @@ -632,7 +640,6 @@ load_acl() { } echolog " - ${msg2}" - udp_flag=1 } fi $ipt_m -A PSW $(comment "默认") -p udp -j RETURN @@ -655,113 +662,53 @@ filter_vpsip() { echolog " - [$?]加入所有IPv6节点到ipset[$IPSET_VPSLIST6]直连完成" } +filter_server_port() { + local address=${1} + local port=${2} + local stream=${3} + stream=$(echo ${3} | tr 'A-Z' 'a-z') + local _is_tproxy ipt_tmp + ipt_tmp=$ipt_n + _is_tproxy=${is_tproxy} + [ "$stream" == "udp" ] && _is_tproxy="TPROXY" + [ -n "${_is_tproxy}" ] && ipt_tmp=$ipt_m + + for _ipt in 4 6; do + [ "$_ipt" == "4" ] && _ipt=$ipt_tmp + [ "$_ipt" == "6" ] && _ipt=$ip6t_m + $_ipt -n -L PSW_OUTPUT | grep -q "${address}:${port}" + if [ $? -ne 0 ]; then + $_ipt -I PSW_OUTPUT $(comment "${address}:${port}") -p $stream -d $address --dport $port -j RETURN 2>/dev/null + fi + done +} + filter_node() { - local proxy_node=${1} - local stream=$(echo ${2} | tr 'A-Z' 'a-z') - local proxy_port=${3} - - filter_rules() { - local node=${1} - local stream=${2} - local _proxy=${3} - local _port=${4} - local _is_tproxy ipt_tmp msg msg2 - - if [ -n "$node" ] && [ "$node" != "nil" ]; then - local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') - local address=$(config_n_get $node address) - local port=$(config_n_get $node port) - [ -z "$address" ] && [ -z "$port" ] && { - echolog " - 节点配置不正常,略过" - return 1 - } - ipt_tmp=$ipt_n - _is_tproxy=${is_tproxy} - [ "$stream" == "udp" ] && _is_tproxy="TPROXY" - if [ -n "${_is_tproxy}" ]; then - ipt_tmp=$ipt_m - msg="TPROXY" - else - msg="REDIRECT" - fi - else - echolog " - 节点配置不正常,略过" + local node=${1} + local stream=${2} + if [ -n "$node" ] && [ "$node" != "nil" ]; then + local address=$(config_n_get $node address) + local port=$(config_n_get $node port) + [ -z "$address" ] && [ -z "$port" ] && { return 1 - fi - - local ADD_INDEX=$FORCE_INDEX - for _ipt in 4 6; do - [ "$_ipt" == "4" ] && _ipt=$ipt_tmp && _set_name=$IPSET_VPSLIST - [ "$_ipt" == "6" ] && _ipt=$ip6t_m && _set_name=$IPSET_VPSLIST6 - $_ipt -n -L PSW_OUTPUT | grep -q "${address}:${port}" - if [ $? -ne 0 ]; then - local dst_rule="-j PSW_RULE" - msg2="按规则路由(${msg})" - [ "$_ipt" == "$ipt_m" -o "$_ipt" == "$ip6t_m" ] || { - dst_rule=$(REDIRECT $_port) - msg2="套娃使用(${msg}:${port} -> ${_port})" - } - [ -n "$_proxy" ] && [ "$_proxy" == "1" ] && [ -n "$_port" ] || { - ADD_INDEX=$(RULE_LAST_INDEX "$_ipt" PSW_OUTPUT "$_set_name" $FORCE_INDEX) - dst_rule=" -j RETURN" - msg2="直连代理" - } - $_ipt -I PSW_OUTPUT $ADD_INDEX $(comment "${address}:${port}") -p $stream -d $address --dport $port $dst_rule 2>/dev/null - else - msg2="已配置过的节点," - fi - done - msg="[$?]$(echo ${2} | tr 'a-z' 'A-Z')${msg2}使用链${ADD_INDEX},节点(${type}):${address}:${port}" - #echolog " - ${msg}" - } - - local proxy_protocol=$(config_n_get $proxy_node protocol) - local proxy_type=$(echo $(config_n_get $proxy_node type nil) | tr 'A-Z' 'a-z') - [ "$proxy_type" == "nil" ] && echolog " - 节点配置不正常,略过!:${proxy_node}" && return 1 - if [ "$proxy_protocol" == "_balancing" ]; then - #echolog " - 多节点负载均衡(${proxy_type})..." - proxy_node=$(config_n_get $proxy_node balancing_node) - for _node in $proxy_node; do - filter_rules "$_node" "$stream" - done - elif [ "$proxy_protocol" == "_shunt" ]; then - #echolog " - 按请求目的地址分流(${proxy_type})..." - local preproxy_enabled=$(config_n_get $proxy_node preproxy_enabled 0) - [ "$preproxy_enabled" == "1" ] && { - local preproxy_node=$(config_n_get $proxy_node main_node nil) - [ "$preproxy_node" != "nil" ] && { - local preproxy_node_address=$(config_n_get $preproxy_node address) - if [ -n "$preproxy_node_address" ]; then - filter_rules $preproxy_node $stream - else - preproxy_enabled=0 - fi - } } - local default_node=$(config_n_get $proxy_node default_node _direct) - if [ "$default_node" != "_direct" ] && [ "$default_node" != "_blackhole" ]; then - local default_proxy_tag=$(config_n_get $proxy_node default_proxy_tag nil) - [ "$default_proxy_tag" == "main" ] && [ "$preproxy_enabled" == "0" ] && default_proxy_tag="nil" - [ "$default_proxy_tag" == "nil" ] && filter_rules $default_node $stream - fi - local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}') - for shunt_id in $shunt_ids; do - local shunt_node=$(config_n_get $proxy_node "${shunt_id}" nil) - [ "$shunt_node" == "nil" -o "$shunt_node" == "_default" -o "$shunt_node" == "_direct" -o "$shunt_node" == "_blackhole" ] && continue - local shunt_node_address=$(config_n_get $shunt_node address) - [ -z "$shunt_node_address" ] && continue - local shunt_proxy_tag=$(config_n_get $proxy_node "${shunt_id}_proxy_tag" nil) - [ "$shunt_proxy_tag" == "main" ] && [ "$preproxy_enabled" == "0" ] && shunt_proxy_tag="nil" - [ "$shunt_proxy_tag" == "nil" ] && filter_rules $shunt_node $stream - done - else - #echolog " - 普通节点(${proxy_type})..." - filter_rules "$proxy_node" "$stream" + filter_server_port $address $port $stream + filter_server_port $address $port $stream fi } +filter_direct_node_list() { + [ ! -s "$TMP_PATH/direct_node_list" ] && return + for _node_id in $(cat $TMP_PATH/direct_node_list | awk '!seen[$0]++'); do + filter_node "$_node_id" TCP + filter_node "$_node_id" UDP + unset _node_id + done +} + add_firewall_rule() { echolog "开始加载防火墙规则..." + ipset -! create $IPSET_LOCALLIST nethash maxelem 1048576 ipset -! create $IPSET_LANLIST nethash maxelem 1048576 ipset -! create $IPSET_VPSLIST nethash maxelem 1048576 ipset -! create $IPSET_SHUNTLIST nethash maxelem 1048576 timeout 172800 @@ -771,6 +718,7 @@ add_firewall_rule() { ipset -! create $IPSET_WHITELIST nethash maxelem 1048576 timeout 172800 ipset -! create $IPSET_BLOCKLIST nethash maxelem 1048576 timeout 172800 + ipset -! create $IPSET_LOCALLIST6 nethash family inet6 maxelem 1048576 ipset -! create $IPSET_LANLIST6 nethash family inet6 maxelem 1048576 ipset -! create $IPSET_VPSLIST6 nethash family inet6 maxelem 1048576 ipset -! create $IPSET_SHUNTLIST6 nethash family inet6 maxelem 1048576 timeout 172800 @@ -869,6 +817,14 @@ add_firewall_rule() { echolog " - [$?]解析并加入[分流节点] GeoIP 到 IPSET 完成" fi } + + ipset -! -R <<-EOF + $(ip address show | grep -w "inet" | awk '{print $2}' | awk -F '/' '{print $1}' | sed -e "s/^/add $IPSET_LOCALLIST /") + EOF + + ipset -! -R <<-EOF + $(ip address show | grep -w "inet6" | awk '{print $2}' | awk -F '/' '{print $1}' | sed -e "s/^/add $IPSET_LOCALLIST6 /") + EOF #局域网IP列表 ipset -! -R <<-EOF @@ -943,8 +899,13 @@ add_firewall_rule() { [ "${USE_DIRECT_LIST}" = "1" ] && $ipt_n -A PSW_OUTPUT $(dst $IPSET_WHITELIST) -j RETURN $ipt_n -A PSW_OUTPUT -m mark --mark 0xff -j RETURN - $ipt_n -N PSW_REDIRECT - $ipt_n -I PREROUTING 1 -j PSW_REDIRECT + $ipt_n -N PSW_DNS + if [ $(config_t_get global dns_redirect "1") = "0" ]; then + #Only hijack when dest address is local IP + $ipt_n -I PREROUTING $(dst $IPSET_LOCALLIST) -j PSW_DNS + else + $ipt_n -I PREROUTING 1 -j PSW_DNS + fi $ipt_m -N PSW_DIVERT $ipt_m -A PSW_DIVERT -j MARK --set-mark 1 @@ -1011,8 +972,13 @@ add_firewall_rule() { $ip6t_n -A PSW_OUTPUT -m mark --mark 0xff -j RETURN } - $ip6t_n -N PSW_REDIRECT - $ip6t_n -I PREROUTING 1 -j PSW_REDIRECT + $ip6t_n -N PSW_DNS + if [ $(config_t_get global dns_redirect "1") = "0" ]; then + #Only hijack when dest address is local IP + $ip6t_n -I PREROUTING $(dst $IPSET_LOCALLIST6) -j PSW_DNS + else + $ip6t_n -I PREROUTING 1 -j PSW_DNS + fi $ip6t_m -N PSW_DIVERT $ip6t_m -A PSW_DIVERT -j MARK --set-mark 1 @@ -1047,44 +1013,8 @@ add_firewall_rule() { ip -6 route add local ::/0 dev lo table 100 [ "$TCP_UDP" = "1" ] && [ "$UDP_NODE" = "nil" ] && UDP_NODE=$TCP_NODE - - # 过滤Socks节点 - [ "$SOCKS_ENABLED" = "1" ] && { - local ids=$(uci show $CONFIG | grep "=socks" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}') - #echolog "分析 Socks 服务所使用节点..." - local id enabled node port msg num - for id in $ids; do - enabled=$(config_n_get $id enabled 0) - [ "$enabled" == "1" ] || continue - node=$(config_n_get $id node nil) - port=$(config_n_get $id port 0) - msg="Socks 服务 [:${port}]" - if [ "$node" == "nil" ] || [ "$port" == "0" ]; then - msg="${msg} 未配置完全,略过" - else - filter_node $node TCP > /dev/null 2>&1 & - filter_node $node UDP > /dev/null 2>&1 & - fi - #echolog " - ${msg}" - done - } [ "$ENABLED_DEFAULT_ACL" == 1 ] && { - # 处理轮换节点的分流或套娃 - local node port stream switch - for stream in TCP UDP; do - eval "node=\${${stream}_NODE}" - eval "port=\${${stream}_REDIR_PORT}" - #echolog "分析 $stream 代理自动切换..." - [ "$stream" == "UDP" ] && [ "$node" == "tcp" ] && { - eval "node=\${TCP_NODE}" - eval "port=\${TCP_REDIR_PORT}" - } - if [ "$node" != "nil" ] && [ "$(config_get_type $node nil)" != "nil" ]; then - filter_node $node $stream $port > /dev/null 2>&1 & - fi - done - local ipt_tmp=$ipt_n if [ -n "${is_tproxy}" ]; then ipt_tmp=$ipt_m @@ -1287,24 +1217,18 @@ add_firewall_rule() { # 加载ACLS load_acl - for iface in $(ls ${TMP_IFACE_PATH}); do - $ipt_n -I PSW_OUTPUT -o $iface -j RETURN - $ipt_m -I PSW_OUTPUT -o $iface -j RETURN - done + filter_direct_node_list + + [ -d "${TMP_IFACE_PATH}" ] && { + for iface in $(ls ${TMP_IFACE_PATH}); do + $ipt_n -I PSW_OUTPUT -o $iface -j RETURN + $ipt_m -I PSW_OUTPUT -o $iface -j RETURN + done + } $ipt_n -I PREROUTING $(comment "PSW") -m mark --mark 1 -j RETURN $ip6t_n -I PREROUTING $(comment "PSW") -m mark --mark 1 -j RETURN - [ -n "${is_tproxy}" -o -n "${udp_flag}" ] && { - bridge_nf_ipt=$(sysctl -e -n net.bridge.bridge-nf-call-iptables) - echo -n $bridge_nf_ipt > $TMP_PATH/bridge_nf_ipt - sysctl -w net.bridge.bridge-nf-call-iptables=0 >/dev/null 2>&1 - [ "$PROXY_IPV6" == "1" ] && { - bridge_nf_ip6t=$(sysctl -e -n net.bridge.bridge-nf-call-ip6tables) - echo -n $bridge_nf_ip6t > $TMP_PATH/bridge_nf_ip6t - sysctl -w net.bridge.bridge-nf-call-ip6tables=0 >/dev/null 2>&1 - } - } echolog "防火墙规则加载完成!" } @@ -1316,7 +1240,7 @@ del_firewall_rule() { $ipt -D $chain $index 2>/dev/null done done - for chain in "PSW" "PSW_OUTPUT" "PSW_DIVERT" "PSW_REDIRECT" "PSW_RULE"; do + for chain in "PSW" "PSW_OUTPUT" "PSW_DIVERT" "PSW_DNS" "PSW_RULE"; do $ipt -F $chain 2>/dev/null $ipt -X $chain 2>/dev/null done @@ -1328,6 +1252,7 @@ del_firewall_rule() { ip -6 rule del fwmark 1 table 100 2>/dev/null ip -6 route del local ::/0 dev lo table 100 2>/dev/null + destroy_ipset $IPSET_LOCALLIST destroy_ipset $IPSET_LANLIST destroy_ipset $IPSET_VPSLIST destroy_ipset $IPSET_SHUNTLIST @@ -1337,6 +1262,7 @@ del_firewall_rule() { destroy_ipset $IPSET_BLOCKLIST destroy_ipset $IPSET_WHITELIST + destroy_ipset $IPSET_LOCALLIST6 destroy_ipset $IPSET_LANLIST6 destroy_ipset $IPSET_VPSLIST6 destroy_ipset $IPSET_SHUNTLIST6 @@ -1498,6 +1424,9 @@ get_wan_ip) get_wan6_ip) get_wan6_ip ;; +filter_direct_node_list) + filter_direct_node_list + ;; stop) stop ;; diff --git a/luci-app-passwall/root/usr/share/passwall/nftables.sh b/luci-app-passwall/root/usr/share/passwall/nftables.sh index eca8b922d..27ff6638e 100755 --- a/luci-app-passwall/root/usr/share/passwall/nftables.sh +++ b/luci-app-passwall/root/usr/share/passwall/nftables.sh @@ -3,6 +3,7 @@ DIR="$(cd "$(dirname "$0")" && pwd)" MY_PATH=$DIR/nftables.sh NFTABLE_NAME="inet passwall" +NFTSET_LOCALLIST="passwall_locallist" NFTSET_LANLIST="passwall_lanlist" NFTSET_VPSLIST="passwall_vpslist" NFTSET_SHUNTLIST="passwall_shuntlist" @@ -12,6 +13,7 @@ NFTSET_BLACKLIST="passwall_blacklist" NFTSET_WHITELIST="passwall_whitelist" NFTSET_BLOCKLIST="passwall_blocklist" +NFTSET_LOCALLIST6="passwall_locallist6" NFTSET_LANLIST6="passwall_lanlist6" NFTSET_VPSLIST6="passwall_vpslist6" NFTSET_SHUNTLIST6="passwall_shuntlist6" @@ -272,11 +274,11 @@ load_acl() { [ "$tcp_redir_ports" = "default" ] && tcp_redir_ports=$TCP_REDIR_PORTS [ "$udp_redir_ports" = "default" ] && udp_redir_ports=$UDP_REDIR_PORTS - [ -s "${TMP_ACL_PATH}/${sid}/var_tcp_node" ] && tcp_node=$(cat ${TMP_ACL_PATH}/${sid}/var_tcp_node) - [ -s "${TMP_ACL_PATH}/${sid}/var_udp_node" ] && udp_node=$(cat ${TMP_ACL_PATH}/${sid}/var_udp_node) - [ -s "${TMP_ACL_PATH}/${sid}/var_tcp_port" ] && tcp_port=$(cat ${TMP_ACL_PATH}/${sid}/var_tcp_port) - [ -s "${TMP_ACL_PATH}/${sid}/var_udp_port" ] && udp_port=$(cat ${TMP_ACL_PATH}/${sid}/var_udp_port) - [ -s "${TMP_ACL_PATH}/${sid}/var_redirect_dns_port" ] && dns_redirect_port=$(cat ${TMP_ACL_PATH}/${sid}/var_redirect_dns_port) + [ -n "$(get_cache_var "ACL_${sid}_tcp_node")" ] && tcp_node=$(get_cache_var "ACL_${sid}_tcp_node") + [ -n "$(get_cache_var "ACL_${sid}_udp_node")" ] && udp_node=$(get_cache_var "ACL_${sid}_udp_node") + [ -n "$(get_cache_var "ACL_${sid}_tcp_port")" ] && tcp_port=$(get_cache_var "ACL_${sid}_tcp_port") + [ -n "$(get_cache_var "ACL_${sid}_udp_port")" ] && udp_port=$(get_cache_var "ACL_${sid}_udp_port") + [ -n "$(get_cache_var "ACL_${sid}_dns_port")" ] && dns_redirect_port=$(get_cache_var "ACL_${sid}_dns_port") use_shunt_tcp=0 use_shunt_udp=0 @@ -371,22 +373,22 @@ load_acl() { fi } + local dns_redirect + [ $(config_t_get global dns_redirect "1") = "1" ] && dns_redirect=53 if ([ -n "$tcp_port" ] && [ -n "${tcp_proxy_mode}" ]) || ([ -n "$udp_port" ] && [ -n "${udp_proxy_mode}" ]); then - [ -n "$dns_redirect_port" ] && { - nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_REDIRECT ip protocol udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_REDIRECT ip protocol tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_REDIRECT meta l4proto udp ${_ipt_source} udp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_REDIRECT meta l4proto tcp ${_ipt_source} tcp dport 53 counter redirect to :$dns_redirect_port comment \"$remarks\"" - } + [ -n "${dns_redirect_port}" ] && dns_redirect=${dns_redirect_port} else - nft "add rule $NFTABLE_NAME PSW_REDIRECT ip protocol udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_REDIRECT ip protocol tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_REDIRECT meta l4proto udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" - nft "add rule $NFTABLE_NAME PSW_REDIRECT meta l4proto tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" + [ -n "${DIRECT_DNSMASQ_PORT}" ] && dns_redirect=${DIRECT_DNSMASQ_PORT} + fi + if [ -n "${dns_redirect}" ]; then + nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} udp dport 53 counter return comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} tcp dport 53 counter return comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_DNS ip protocol udp ${_ipt_source} udp dport 53 counter redirect to :${dns_redirect} comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_DNS ip protocol tcp ${_ipt_source} tcp dport 53 counter redirect to :${dns_redirect} comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp ${_ipt_source} udp dport 53 counter redirect to :${dns_redirect} comment \"$remarks\"" + nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp ${_ipt_source} tcp dport 53 counter redirect to :${dns_redirect} comment \"$remarks\"" fi [ -n "$tcp_port" -o -n "$udp_port" ] && { @@ -524,7 +526,7 @@ load_acl() { unset nft_chain nft_j _ipt_source msg msg2 done unset enabled sid remarks sources use_global_config use_direct_list use_proxy_list use_block_list use_gfw_list chn_list tcp_proxy_mode udp_proxy_mode dns_redirect_port tcp_no_redir_ports udp_no_redir_ports tcp_proxy_drop_ports udp_proxy_drop_ports tcp_redir_ports udp_redir_ports tcp_node udp_node interface - unset tcp_port udp_port tcp_node_remark udp_node_remark _acl_list use_shunt_tcp use_shunt_udp + unset tcp_port udp_port tcp_node_remark udp_node_remark _acl_list use_shunt_tcp use_shunt_udp dns_redirect done } @@ -552,17 +554,23 @@ load_acl() { fi } + local DNS_REDIRECT + [ $(config_t_get global dns_redirect "1") = "1" ] && DNS_REDIRECT=53 if ([ "$TCP_NODE" != "nil" ] && [ -n "${TCP_PROXY_MODE}" ]) || ([ "$UDP_NODE" != "nil" ] && [ -n "${UDP_PROXY_MODE}" ]); then - [ -n "$DNS_REDIRECT_PORT" ] && { - nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp udp dport 53 counter return comment \"默认\"" - nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp udp dport 53 counter return comment \"默认\"" - nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol tcp tcp dport 53 counter return comment \"默认\"" - nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp tcp dport 53 counter return comment \"默认\"" - nft "add rule $NFTABLE_NAME PSW_REDIRECT ip protocol udp udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"默认\"" - nft "add rule $NFTABLE_NAME PSW_REDIRECT ip protocol tcp tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"默认\"" - nft "add rule $NFTABLE_NAME PSW_REDIRECT meta l4proto udp udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"默认\"" - nft "add rule $NFTABLE_NAME PSW_REDIRECT meta l4proto tcp tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"默认\"" - } + [ -n "${DNS_REDIRECT_PORT}" ] && DNS_REDIRECT=${DNS_REDIRECT_PORT} + else + [ -n "${DIRECT_DNSMASQ_PORT}" ] && DNS_REDIRECT=${DIRECT_DNSMASQ_PORT} + fi + + if [ -n "${DNS_REDIRECT}" ]; then + nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp udp dport 53 counter return comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp udp dport 53 counter return comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol tcp tcp dport 53 counter return comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp tcp dport 53 counter return comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_DNS ip protocol udp udp dport 53 counter redirect to :${DNS_REDIRECT} comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_DNS ip protocol tcp tcp dport 53 counter redirect to :${DNS_REDIRECT} comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto udp udp dport 53 counter redirect to :${DNS_REDIRECT} comment \"默认\"" + nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp tcp dport 53 counter redirect to :${DNS_REDIRECT} comment \"默认\"" fi [ -n "${TCP_PROXY_MODE}" -o -n "${UDP_PROXY_MODE}" ] && { @@ -694,7 +702,6 @@ load_acl() { } echolog " - ${msg2}" - udp_flag=1 } fi } @@ -724,114 +731,54 @@ filter_vpsip() { echolog " - [$?]加入所有IPv6节点到nftset[$NFTSET_VPSLIST6]直连完成" } +filter_server_port() { + local address=${1} + local port=${2} + local stream=${3} + stream=$(echo ${3} | tr 'A-Z' 'a-z') + local _is_tproxy + _is_tproxy=${is_tproxy} + [ "$stream" == "udp" ] && _is_tproxy="TPROXY" + + for _ipt in 4 6; do + [ "$_ipt" == "4" ] && _ip_type=ip + [ "$_ipt" == "6" ] && _ip_type=ip6 + nft "list chain $NFTABLE_NAME $nft_output_chain" 2>/dev/null | grep -q "${address}:${port}" + if [ $? -ne 0 ]; then + nft "insert rule $NFTABLE_NAME $nft_output_chain meta l4proto $stream $_ip_type daddr $address $stream dport $port return comment \"${address}:${port}\"" 2>/dev/null + fi + done +} + filter_node() { - local proxy_node=${1} - local stream=$(echo ${2} | tr 'A-Z' 'a-z') - local proxy_port=${3} - - filter_rules() { - local node=${1} - local stream=${2} - local _proxy=${3} - local _port=${4} - local _is_tproxy msg msg2 - - if [ -n "$node" ] && [ "$node" != "nil" ]; then - local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') - local address=$(config_n_get $node address) - local port=$(config_n_get $node port) - [ -z "$address" ] && [ -z "$port" ] && { - echolog " - 节点配置不正常,略过" - return 1 - } - _is_tproxy=${is_tproxy} - [ "$stream" == "udp" ] && _is_tproxy="TPROXY" - if [ -n "${_is_tproxy}" ]; then - msg="TPROXY" - else - msg="REDIRECT" - fi - else - echolog " - 节点配置不正常,略过" + local node=${1} + local stream=${2} + if [ -n "$node" ] && [ "$node" != "nil" ]; then + local address=$(config_n_get $node address) + local port=$(config_n_get $node port) + [ -z "$address" ] && [ -z "$port" ] && { return 1 - fi - - local ADD_INDEX=$FORCE_INDEX - for _ipt in 4 6; do - [ "$_ipt" == "4" ] && _ip_type=ip && _set_name=$NFTSET_VPSLIST - [ "$_ipt" == "6" ] && _ip_type=ip6 && _set_name=$NFTSET_VPSLIST6 - nft "list chain $NFTABLE_NAME $nft_output_chain" 2>/dev/null | grep -q "${address}:${port}" - if [ $? -ne 0 ]; then - local dst_rule="jump PSW_RULE" - msg2="按规则路由(${msg})" - [ -n "${is_tproxy}" ] || { - dst_rule=$(REDIRECT $_port) - msg2="套娃使用(${msg}:${port} -> ${_port})" - } - [ -n "$_proxy" ] && [ "$_proxy" == "1" ] && [ -n "$_port" ] || { - ADD_INDEX=$(RULE_LAST_INDEX "$NFTABLE_NAME" $nft_output_chain $_set_name $FORCE_INDEX) - dst_rule="return" - msg2="直连代理" - } - nft "insert rule $NFTABLE_NAME $nft_output_chain position $ADD_INDEX meta l4proto $stream $_ip_type daddr $address $stream dport $port $dst_rule comment \"${address}:${port}\"" 2>/dev/null - else - msg2="已配置过的节点," - fi - done - msg="[$?]$(echo ${2} | tr 'a-z' 'A-Z')${msg2}使用链${ADD_INDEX},节点(${type}):${address}:${port}" - #echolog " - ${msg}" - } - - local proxy_protocol=$(config_n_get $proxy_node protocol) - local proxy_type=$(echo $(config_n_get $proxy_node type nil) | tr 'A-Z' 'a-z') - [ "$proxy_type" == "nil" ] && echolog " - 节点配置不正常,略过!:${proxy_node}" && return 1 - if [ "$proxy_protocol" == "_balancing" ]; then - #echolog " - 多节点负载均衡(${proxy_type})..." - proxy_node=$(config_n_get $proxy_node balancing_node) - for _node in $proxy_node; do - filter_rules "$_node" "$stream" - done - elif [ "$proxy_protocol" == "_shunt" ]; then - #echolog " - 按请求目的地址分流(${proxy_type})..." - local preproxy_enabled=$(config_n_get $proxy_node preproxy_enabled 0) - [ "$preproxy_enabled" == "1" ] && { - local preproxy_node=$(config_n_get $proxy_node main_node nil) - [ "$preproxy_node" != "nil" ] && { - local preproxy_node_address=$(config_n_get $preproxy_node address) - if [ -n "$preproxy_node_address" ]; then - filter_rules $preproxy_node $stream - else - preproxy_enabled=0 - fi - } } - local default_node=$(config_n_get $proxy_node default_node _direct) - if [ "$default_node" != "_direct" ] && [ "$default_node" != "_blackhole" ]; then - local default_proxy_tag=$(config_n_get $proxy_node default_proxy_tag nil) - [ "$default_proxy_tag" == "main" ] && [ "$preproxy_enabled" == "0" ] && default_proxy_tag="nil" - [ "$default_proxy_tag" == "nil" ] && filter_rules $default_node $stream - fi - local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}') - for shunt_id in $shunt_ids; do - local shunt_node=$(config_n_get $proxy_node "${shunt_id}" nil) - [ "$shunt_node" == "nil" -o "$shunt_node" == "_default" -o "$shunt_node" == "_direct" -o "$shunt_node" == "_blackhole" ] && continue - local shunt_node_address=$(config_n_get $shunt_node address) - [ -z "$shunt_node_address" ] && continue - local shunt_proxy_tag=$(config_n_get $proxy_node "${shunt_id}_proxy_tag" nil) - [ "$shunt_proxy_tag" == "main" ] && [ "$preproxy_enabled" == "0" ] && shunt_proxy_tag="nil" - [ "$shunt_proxy_tag" == "nil" ] && filter_rules $shunt_node $stream - done - else - #echolog " - 普通节点(${proxy_type})..." - filter_rules "$proxy_node" "$stream" + filter_server_port $address $port $stream + filter_server_port $address $port $stream fi } +filter_direct_node_list() { + [ ! -s "$TMP_PATH/direct_node_list" ] && return + for _node_id in $(cat $TMP_PATH/direct_node_list | awk '!seen[$0]++'); do + filter_node "$_node_id" TCP + filter_node "$_node_id" UDP + unset _node_id + done +} + add_firewall_rule() { echolog "开始加载防火墙规则..." gen_nft_tables gen_nftset $NFTSET_VPSLIST ipv4_addr 0 0 gen_nftset $NFTSET_GFW ipv4_addr "2d" 0 + gen_nftset $NFTSET_LOCALLIST ipv4_addr 0 "-1" gen_nftset $NFTSET_LANLIST ipv4_addr 0 "-1" $(gen_lanlist) if [ -f $RULES_PATH/chnroute.nft ] && [ -s $RULES_PATH/chnroute.nft ] && [ $(awk 'END{print NR}' $RULES_PATH/chnroute.nft) -ge 8 ]; then #echolog "使用缓存加载chnroute..." @@ -846,6 +793,7 @@ add_firewall_rule() { gen_nftset $NFTSET_VPSLIST6 ipv6_addr 0 0 gen_nftset $NFTSET_GFW6 ipv6_addr "2d" 0 + gen_nftset $NFTSET_LOCALLIST6 ipv6_addr 0 "-1" gen_nftset $NFTSET_LANLIST6 ipv6_addr 0 "-1" $(gen_lanlist_6) if [ -f $RULES_PATH/chnroute6.nft ] && [ -s $RULES_PATH/chnroute6.nft ] && [ $(awk 'END{print NR}' $RULES_PATH/chnroute6.nft) -ge 8 ]; then #echolog "使用缓存加载chnroute6..." @@ -945,6 +893,9 @@ add_firewall_rule() { fi } + insert_nftset $NFTSET_LOCALLIST "-1" $(ip address show | grep -w "inet" | awk '{print $2}' | awk -F '/' '{print $1}' | sed -e "s/ /\n/g") + insert_nftset $NFTSET_LOCALLIST6 "-1" $(ip address show | grep -w "inet6" | awk '{print $2}' | awk -F '/' '{print $1}' | sed -e "s/ /\n/g") + # 忽略特殊IP段 local lan_ifname lan_ip lan_ifname=$(uci -q -p /tmp/state get network.lan.ifname) @@ -999,9 +950,15 @@ add_firewall_rule() { nft "flush chain $NFTABLE_NAME PSW_DIVERT" nft "add rule $NFTABLE_NAME PSW_DIVERT meta l4proto tcp socket transparent 1 mark set 1 counter accept" - nft "add chain $NFTABLE_NAME PSW_REDIRECT" - nft "flush chain $NFTABLE_NAME PSW_REDIRECT" - nft "add rule $NFTABLE_NAME dstnat jump PSW_REDIRECT" + nft "add chain $NFTABLE_NAME PSW_DNS" + nft "flush chain $NFTABLE_NAME PSW_DNS" + if [ $(config_t_get global dns_redirect "1") = "0" ]; then + #Only hijack when dest address is local IP + nft "insert rule $NFTABLE_NAME dstnat ip daddr @${NFTSET_LOCALLIST} jump PSW_DNS" + nft "insert rule $NFTABLE_NAME dstnat ip6 daddr @${NFTSET_LOCALLIST6} jump PSW_DNS" + else + nft "insert rule $NFTABLE_NAME dstnat jump PSW_DNS" + fi # for ipv4 ipv6 tproxy mark nft "add chain $NFTABLE_NAME PSW_RULE" @@ -1121,44 +1078,8 @@ add_firewall_rule() { } [ "$TCP_UDP" = "1" ] && [ "$UDP_NODE" = "nil" ] && UDP_NODE=$TCP_NODE - - # 过滤Socks节点 - [ "$SOCKS_ENABLED" = "1" ] && { - local ids=$(uci show $CONFIG | grep "=socks" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}') - #echolog "分析 Socks 服务所使用节点..." - local id enabled node port msg num - for id in $ids; do - enabled=$(config_n_get $id enabled 0) - [ "$enabled" == "1" ] || continue - node=$(config_n_get $id node nil) - port=$(config_n_get $id port 0) - msg="Socks 服务 [:${port}]" - if [ "$node" == "nil" ] || [ "$port" == "0" ]; then - msg="${msg} 未配置完全,略过" - else - filter_node $node TCP > /dev/null 2>&1 & - filter_node $node UDP > /dev/null 2>&1 & - fi - #echolog " - ${msg}" - done - } [ "$ENABLED_DEFAULT_ACL" == 1 ] && { - # 处理轮换节点的分流或套娃 - local node port stream switch - for stream in TCP UDP; do - eval "node=\${${stream}_NODE}" - eval "port=\${${stream}_REDIR_PORT}" - #echolog "分析 $stream 代理自动切换..." - [ "$stream" == "UDP" ] && [ "$node" == "tcp" ] && { - eval "node=\${TCP_NODE}" - eval "port=\${TCP_REDIR_PORT}" - } - if [ "$node" != "nil" ] && [ "$(config_get_type $node nil)" != "nil" ]; then - filter_node $node $stream $port > /dev/null 2>&1 & - fi - done - msg="【路由器本机】," [ "$TCP_NO_REDIR_PORTS" != "disable" ] && { @@ -1354,21 +1275,15 @@ add_firewall_rule() { # 加载ACLS load_acl - for iface in $(ls ${TMP_IFACE_PATH}); do - nft "insert rule $NFTABLE_NAME $nft_output_chain oif $iface counter return" - nft "insert rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 oif $iface counter return" - done + filter_direct_node_list - [ -n "${is_tproxy}" -o -n "${udp_flag}" ] && { - bridge_nf_ipt=$(sysctl -e -n net.bridge.bridge-nf-call-iptables) - echo -n $bridge_nf_ipt > $TMP_PATH/bridge_nf_ipt - sysctl -w net.bridge.bridge-nf-call-iptables=0 >/dev/null 2>&1 - [ "$PROXY_IPV6" == "1" ] && { - bridge_nf_ip6t=$(sysctl -e -n net.bridge.bridge-nf-call-ip6tables) - echo -n $bridge_nf_ip6t > $TMP_PATH/bridge_nf_ip6t - sysctl -w net.bridge.bridge-nf-call-ip6tables=0 >/dev/null 2>&1 - } + [ -d "${TMP_IFACE_PATH}" ] && { + for iface in $(ls ${TMP_IFACE_PATH}); do + nft "insert rule $NFTABLE_NAME $nft_output_chain oif $iface counter return" + nft "insert rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 oif $iface counter return" + done } + echolog "防火墙规则加载完成!" } @@ -1393,6 +1308,7 @@ del_firewall_rule() { ip -6 rule del fwmark 1 table 100 2>/dev/null ip -6 route del local ::/0 dev lo table 100 2>/dev/null + destroy_nftset $NFTSET_LOCALLIST destroy_nftset $NFTSET_LANLIST destroy_nftset $NFTSET_VPSLIST destroy_nftset $NFTSET_SHUNTLIST @@ -1402,6 +1318,7 @@ del_firewall_rule() { destroy_nftset $NFTSET_BLOCKLIST destroy_nftset $NFTSET_WHITELIST + destroy_nftset $NFTSET_LOCALLIST6 destroy_nftset $NFTSET_LANLIST6 destroy_nftset $NFTSET_VPSLIST6 destroy_nftset $NFTSET_SHUNTLIST6 @@ -1513,6 +1430,9 @@ get_wan_ip) get_wan6_ip) get_wan6_ip ;; +filter_direct_node_list) + filter_direct_node_list + ;; stop) stop ;; diff --git a/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh b/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh index a43f895a8..a7d403fa7 100755 --- a/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh +++ b/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh @@ -82,9 +82,8 @@ test_auto_switch() { local b_nodes=$1 local now_node=$2 [ -z "$now_node" ] && { - local f="/tmp/etc/$CONFIG/id/socks_${id}" - if [ -f "${f}" ]; then - now_node=$(cat ${f}) + if [ -n "$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}")" ]; then + now_node=$(/usr/share/${CONFIG}/app.sh get_cache_var "socks_${id}") else #echolog "自动切换检测:未知错误" return 1 diff --git a/luci-app-passwall/root/usr/share/passwall/subscribe.lua b/luci-app-passwall/root/usr/share/passwall/subscribe.lua index 49b5fc2b5..227e7ad70 100755 --- a/luci-app-passwall/root/usr/share/passwall/subscribe.lua +++ b/luci-app-passwall/root/usr/share/passwall/subscribe.lua @@ -327,6 +327,23 @@ do } end else + --前置代理节点 + local currentNode = uci:get_all(appname, node_id) or nil + if currentNode and currentNode.preproxy_node then + CONFIG[#CONFIG + 1] = { + log = true, + id = node_id, + remarks = "节点[" .. node_id .. "]前置代理节点", + currentNode = uci:get_all(appname, currentNode.preproxy_node) or nil, + set = function(o, server) + uci:set(appname, node_id, "preproxy_node", server) + o.newNodeId = server + end, + delete = function(o) + uci:delete(appname, node_id, "preproxy_node") + end + } + end --落地节点 local currentNode = uci:get_all(appname, node_id) or nil if currentNode and currentNode.to_node then diff --git a/patch-luci-app-passwall.patch b/patch-luci-app-passwall.patch index 95566b64a..c2a238741 100644 --- a/patch-luci-app-passwall.patch +++ b/patch-luci-app-passwall.patch @@ -1,5 +1,5 @@ diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile -index fa1cd41..eac8656 100644 +index 2b72468..15c6437 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -144,7 +144,7 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Geodata @@ -20,7 +20,7 @@ index fa1cd41..eac8656 100644 define Package/$(PKG_NAME)/postrm diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua -index 02ce26c..83cbafc 100644 +index 33c5319..6ddcdfd 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -279,7 +279,7 @@ function connect_status() @@ -33,7 +33,7 @@ index 02ce26c..83cbafc 100644 if code ~= 0 then local use_time = luci.sys.exec("echo -n '" .. result .. "' | awk -F ':' '{print $2}'") diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua -index d766646..e5d6a46 100644 +index 488cd50..541167f 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua @@ -467,6 +467,12 @@ o:value("9.9.9.9", "9.9.9.9 (Quad9)") @@ -49,44 +49,8 @@ index d766646..e5d6a46 100644 o:depends({dns_mode = "dns2socks"}) o:depends({dns_mode = "tcp"}) o:depends({dns_mode = "udp"}) -diff --git a/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm b/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm -index 739c593..3769e7d 100644 ---- a/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm -+++ b/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm -@@ -180,12 +180,12 @@ local version = {} -
- -
--
-+ - 【 <%=api.get_version()%> 】 - - --
-+ -
-
- -@@ -196,14 +196,14 @@ local version = {} - <%:Version%> - -
--
-+ - 【 <%=version[k] ~="" and version[k] or translate("Null") %> 】 - - - --
-+ -
- - <%end%> diff --git a/luci-app-passwall/luasrc/view/passwall/global/status.htm b/luci-app-passwall/luasrc/view/passwall/global/status.htm -index 00f79ff..452d369 100644 +index e8d76ec..a872950 100644 --- a/luci-app-passwall/luasrc/view/passwall/global/status.htm +++ b/luci-app-passwall/luasrc/view/passwall/global/status.htm @@ -1,5 +1,11 @@ @@ -101,13 +65,13 @@ index 00f79ff..452d369 100644 -%>