diff --git a/applications/luci-app-passwall/Makefile b/applications/luci-app-passwall/Makefile index af394e4002e..28a141da233 100644 --- a/applications/luci-app-passwall/Makefile +++ b/applications/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)_INCLUDE_Haproxy \ diff --git a/applications/luci-app-passwall/luasrc/controller/passwall.lua b/applications/luci-app-passwall/luasrc/controller/passwall.lua index ce89a3749dd..4956e811395 100644 --- a/applications/luci-app-passwall/luasrc/controller/passwall.lua +++ b/applications/luci-app-passwall/luasrc/controller/passwall.lua @@ -77,6 +77,11 @@ function index() entry({"admin", "services", appname, "delete_select_nodes"}, call("delete_select_nodes")).leaf = true entry({"admin", "services", appname, "update_rules"}, call("update_rules")).leaf = true + --[[rule_list]] + entry({"admin", "services", appname, "read_gfwlist"}, call("read_rulelist", "gfw")).leaf = true + entry({"admin", "services", appname, "read_chnlist"}, call("read_rulelist", "chn")).leaf = true + entry({"admin", "services", appname, "read_chnroute"}, call("read_rulelist", "chnroute")).leaf = true + --[[Components update]] entry({"admin", "services", appname, "check_passwall"}, call("app_check")).leaf = true local coms = require "luci.passwall.com" @@ -161,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) @@ -264,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 @@ -369,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']) @@ -408,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) @@ -475,3 +490,18 @@ function com_update(comname) http_write_json(json) end + +function read_rulelist(list) + local rule_path + if list == "gfw" then + rule_path = "/usr/share/passwall/rules/gfwlist" + elseif list == "chn" then + rule_path = "/usr/share/passwall/rules/chnlist" + else + rule_path = "/usr/share/passwall/rules/chnroute" + end + if api.fs.access(rule_path) then + luci.http.prepare_content("text/plain") + luci.http.write(api.fs.readfile(rule_path)) + end +end diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua index a21bf82b7d9..4d9595e33dc 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua +++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua @@ -557,8 +557,9 @@ 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", "DNS " .. translate("Redirect"), translate("Force Router DNS server to all local devices.")) -o.default = "0" +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.")) diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua index 11a052dd554..0bc15c66d78 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua +++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua @@ -180,7 +180,7 @@ if has_xray then o = s_xray:option(Flag, "sniffing_override_dest", translate("Override the connection destination address")) o.default = 0 - o.description = translate("Override the connection destination address with the sniffed domain.
When enabled, traffic will match only by domain, ignoring IP rules.
If using shunt nodes, configure the domain shunt rules correctly.") + o.description = translate("Override the connection destination address with the sniffed domain.
Otherwise use sniffed domain for routing only.
If using shunt nodes, configure the domain shunt rules correctly.") local domains_excluded = string.format("/usr/share/%s/rules/domains_excluded", appname) o = s_xray:option(TextValue, "excluded_domains", translate("Excluded Domains"), translate("If the traffic sniffing result is in this list, the destination address will not be overridden.")) diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/rule_list.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/rule_list.lua index 27e863a158b..5c9abb15b5a 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/rule_list.lua +++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/rule_list.lua @@ -273,71 +273,41 @@ end if api.fs.access(gfwlist_path) then s:tab("gfw_list", translate("GFW List")) - o = s:taboption("gfw_list", TextValue, "gfw_list", "") - o.readonly = true - o.rows = 45 - o.wrap = "off" - o.cfgvalue = function(self, section) - local limit = 100 -- 限制行数 - local cmd = string.format("head -n %d %s", limit, gfwlist_path) - return api.sys.exec(cmd) or "" - -- return fs.readfile(gfwlist_path) or "" - end - local total_lines_cmd = string.format("wc -l < %s", gfwlist_path) - local total_lines = tonumber(api.sys.exec(total_lines_cmd)) or 0 - local displayed_lines = 100 - - local total_lines_label = s:taboption("gfw_list", DummyValue, "total_lines", translate("Total Lines")) - total_lines_label.value = translatef("%d lines", total_lines) - - local displayed_lines_label = s:taboption("gfw_list", DummyValue, "displayed_lines", translate("Displayed Lines")) - displayed_lines_label.value = translatef("%d lines", displayed_lines) + o = s:taboption("gfw_list", DummyValue, "_gfw_fieldset") + o.rawhtml = true + o.default = string.format([[ +
+ + +
+ + ]], translate("Read List")) end if api.fs.access(chnlist_path) then s:tab("chn_list", translate("China List") .. "(" .. translate("Domain") .. ")") - o = s:taboption("chn_list", TextValue, "chn_list", "") - o.readonly = true - o.rows = 45 - o.wrap = "off" - o.cfgvalue = function(self, section) - local limit = 100 -- 限制行数 - local cmd = string.format("head -n %d %s", limit, chnlist_path) - return api.sys.exec(cmd) or "" - -- return fs.readfile(chnlist_path) or "" - end - local total_lines_cmd = string.format("wc -l < %s", chnlist_path) - local total_lines = tonumber(api.sys.exec(total_lines_cmd)) or 0 - local displayed_lines = 100 - - local total_lines_label = s:taboption("chn_list", DummyValue, "total_lines", translate("Total Lines")) - total_lines_label.value = translatef("%d lines", total_lines) - - local displayed_lines_label = s:taboption("chn_list", DummyValue, "displayed_lines", translate("Displayed Lines")) - displayed_lines_label.value = translatef("%d lines", displayed_lines) + o = s:taboption("chn_list", DummyValue, "_chn_fieldset") + o.rawhtml = true + o.default = string.format([[ +
+ + +
+ + ]], translate("Read List")) end if api.fs.access(chnroute_path) then s:tab("chnroute_list", translate("China List") .. "(IP)") - o = s:taboption("chnroute_list", TextValue, "chnroute_list", "") - o.readonly = true - o.rows = 45 - o.wrap = "off" - o.cfgvalue = function(self, section) - local limit = 100 -- 限制行数 - local cmd = string.format("head -n %d %s", limit, chnroute_path) - return api.sys.exec(cmd) or "" - -- return fs.readfile(chnroute_path) or "" - end - local total_lines_cmd = string.format("wc -l < %s", chnroute_path) - local total_lines = tonumber(api.sys.exec(total_lines_cmd)) or 0 - local displayed_lines = 100 - - local total_lines_label = s:taboption("chnroute_list", DummyValue, "total_lines", translate("Total Lines")) - total_lines_label.value = translatef("%d lines", total_lines) - - local displayed_lines_label = s:taboption("chnroute_list", DummyValue, "displayed_lines", translate("Displayed Lines")) - displayed_lines_label.value = translatef("%d lines", displayed_lines) + o = s:taboption("chnroute_list", DummyValue, "_chnroute_fieldset") + o.rawhtml = true + o.default = string.format([[ +
+ + +
+ + ]], translate("Read List")) end m:append(Template(appname .. "/rule_list/js")) diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua index a1b400f1b32..1152bf67e50 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua +++ b/applications/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/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua index 70308f873f9..5330a941e32 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua +++ b/applications/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/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua index a51388cdc29..e64c7017b5b 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua +++ b/applications/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/applications/luci-app-passwall/luasrc/passwall/api.lua b/applications/luci-app-passwall/luasrc/passwall/api.lua index 5d67e767c3e..61c0a0f8b71 100644 --- a/applications/luci-app-passwall/luasrc/passwall/api.lua +++ b/applications/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/applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua index 5d9e3abafe9..774764b6337 100644 --- a/applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/applications/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/applications/luci-app-passwall/luasrc/passwall/util_xray.lua b/applications/luci-app-passwall/luasrc/passwall/util_xray.lua index 3c9907758a9..0a2a663a744 100644 --- a/applications/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/applications/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -186,8 +186,7 @@ function gen_outbound(flag, node, tag, proxy_table) } or nil, wsSettings = (node.transport == "ws") and { path = node.ws_path or "/", - headers = (node.ws_host ~= nil) and - {Host = node.ws_host} or nil, + host = node.ws_host or nil, maxEarlyData = tonumber(node.ws_maxEarlyData) or nil, earlyDataHeaderName = (node.ws_earlyDataHeaderName) and node.ws_earlyDataHeaderName or nil, heartbeatPeriod = tonumber(node.ws_heartbeatPeriod) or nil @@ -418,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 @@ -486,7 +485,7 @@ function gen_config_server(node) header = {type = node.mkcp_guise} } or nil, wsSettings = (node.transport == "ws") and { - headers = (node.ws_host) and {Host = node.ws_host} or nil, + host = node.ws_host or nil, path = node.ws_path } or nil, httpSettings = (node.transport == "h2") and { @@ -612,8 +611,15 @@ function gen_config(var) port = tonumber(local_socks_port), protocol = "socks", settings = {auth = "noauth", udp = true}, - sniffing = {enabled = true, destOverride = {"http", "tls", "quic"}} + sniffing = { + enabled = xray_settings.sniffing_override_dest == "1" or node.protocol == "_shunt" + } } + if inbound.sniffing.enabled == true then + inbound.sniffing.destOverride = {"http", "tls", "quic"} + inbound.sniffing.routeOnly = xray_settings.sniffing_override_dest ~= "1" or nil + inbound.sniffing.domainsExcluded = xray_settings.sniffing_override_dest == "1" and get_domain_excluded() or nil + end if local_socks_username and local_socks_password and local_socks_username ~= "" and local_socks_password ~= "" then inbound.settings.auth = "password" inbound.settings.accounts = { @@ -649,13 +655,15 @@ function gen_config(var) settings = {network = "tcp,udp", followRedirect = true}, streamSettings = {sockopt = {tproxy = "tproxy"}}, sniffing = { - enabled = xray_settings.sniffing_override_dest == "1" or node.protocol == "_shunt", - destOverride = {"http", "tls", "quic"}, - metadataOnly = false, - routeOnly = node.protocol == "_shunt" and xray_settings.sniffing_override_dest ~= "1" or nil, - domainsExcluded = xray_settings.sniffing_override_dest == "1" and get_domain_excluded() or nil + enabled = xray_settings.sniffing_override_dest == "1" or node.protocol == "_shunt" } } + if inbound.sniffing.enabled == true then + inbound.sniffing.destOverride = {"http", "tls", "quic", (remote_dns_fake) and "fakedns"} + inbound.sniffing.metadataOnly = false + inbound.sniffing.routeOnly = xray_settings.sniffing_override_dest ~= "1" or nil + inbound.sniffing.domainsExcluded = xray_settings.sniffing_override_dest == "1" and get_domain_excluded() or nil + end if tcp_redir_port then local tcp_inbound = api.clone(inbound) @@ -772,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) @@ -791,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 @@ -893,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 @@ -918,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 @@ -1067,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", @@ -1112,8 +1147,7 @@ function gen_config(var) local _remote_dns = { --_flag = "remote", - address = "tcp://" .. remote_dns_tcp_server, - port = tonumber(remote_dns_tcp_port) + address = "tcp://" .. remote_dns_tcp_server .. ":" .. tonumber(remote_dns_tcp_port) or 53 } local _remote_dns_host @@ -1362,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/applications/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm b/applications/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm index 739c593063b..3769e7ded77 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm @@ -180,12 +180,12 @@
-
+ 【 <%=api.get_version()%> 】 -
+
@@ -196,14 +196,14 @@ <%:Version%>
-
+ 【 <%=version[k] ~="" and version[k] or translate("Null") %> 】 -
+
<%end%> diff --git a/applications/luci-app-passwall/luasrc/view/passwall/global/status.htm b/applications/luci-app-passwall/luasrc/view/passwall/global/status.htm index dcdd1d643ed..8fb6ac95361 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/global/status.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/global/status.htm @@ -52,6 +52,7 @@ color:#8898aa!important; line-height: 1.8em; min-height: 48px; + border-radius: 12.375px; } .check { diff --git a/applications/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm b/applications/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm index 39c8b80fd25..b0a8abe5891 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/node_list/link_share_man.htm @@ -976,6 +976,18 @@ opt.set(dom_prefix + 'grpc_mode', queryParam.mode || "gun"); } + opt.set(dom_prefix + 'tls', queryParam.security === "tls"); + if (queryParam.security === "tls") { + var tls_serverName = queryParam.peer; + if (queryParam.sni) { + tls_serverName = queryParam.sni + } + opt.set(dom_prefix + 'tls_serverName', tls_serverName); + } + if (queryParam.allowinsecure === '1') { + opt.set(dom_prefix + 'tls_allowInsecure', true); + } + if (m.hash) { opt.set('remarks', decodeURIComponent(m.hash.substr(1))); } @@ -1089,7 +1101,7 @@ } } - 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/applications/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm b/applications/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm index 3b1ca2b1df3..497a4373fdc 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm @@ -26,7 +26,7 @@ } ._now_use { - background: #94e1ff !important; + background: #5e72e445 !important; } .ping a:hover{ @@ -221,6 +221,10 @@ 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 @@ 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"); + } } } } @@ -296,8 +304,6 @@ } } - get_now_use_node(); - /* 自动Ping */ if (auto_detection_time == "icmp" || auto_detection_time == "tcping") { var nodes = []; @@ -418,6 +424,8 @@ } } + get_now_use_node(); + if (true) { var str = ""; for (var add_from in node_list) { diff --git a/applications/luci-app-passwall/luasrc/view/passwall/rule/rule_version.htm b/applications/luci-app-passwall/luasrc/view/passwall/rule/rule_version.htm index 24662dee066..77b6a0b9df3 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/rule/rule_version.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/rule/rule_version.htm @@ -70,7 +70,7 @@ /> geosite - +

diff --git a/applications/luci-app-passwall/luasrc/view/passwall/rule_list/js.htm b/applications/luci-app-passwall/luasrc/view/passwall/rule_list/js.htm index 096fe8635b5..0797d8d5dc8 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/rule_list/js.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/rule_list/js.htm @@ -1,18 +1,47 @@ <% local api = require "luci.passwall.api" +local translate = luci.i18n.translate +local total_lines_text = translate("Total Lines") -%> diff --git a/applications/luci-app-passwall/po/zh_Hans/passwall.po b/applications/luci-app-passwall/po/zh_Hans/passwall.po index a32f413fe58..c8a0ec1d800 100644 --- a/applications/luci-app-passwall/po/zh_Hans/passwall.po +++ b/applications/luci-app-passwall/po/zh_Hans/passwall.po @@ -223,8 +223,11 @@ msgstr "需要代理的分流规则域名使用 FakeDNS。" msgid "Redirect" msgstr "重定向" -msgid "Force Router DNS server to all local devices." -msgstr "强制所有本地设备使用路由器 DNS。" +msgid "DNS Redirect" +msgstr "DNS 重定向" + +msgid "Force special DNS server to need proxy devices." +msgstr "强制需要代理的设备使用专用 DNS 服务器。" msgid "Clear IPSET" msgstr "清空 IPSET" @@ -1645,6 +1648,9 @@ msgstr "握手服务器" msgid "Handshake Server Port" msgstr "握手服务器端口" +msgid "Override the connection destination address with the sniffed domain.
Otherwise use sniffed domain for routing only.
If using shunt nodes, configure the domain shunt rules correctly." +msgstr "用探测出的域名覆盖连接目标地址。
否则仅将探测得到的域名用于路由。
如使用分流节点,请正确设置域名分流规则。" + msgid "Override the connection destination address with the sniffed domain.
When enabled, traffic will match only by domain, ignoring IP rules.
If using shunt nodes, configure the domain shunt rules correctly." msgstr "用探测出的域名覆盖连接目标地址。
启用后仅使用域名进行流量匹配,将忽略IP规则。
如使用分流节点,请正确设置域名分流规则。" @@ -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." @@ -1729,8 +1738,5 @@ msgstr "为 sing-box 节点设置默认的域名解析策略。" msgid "Total Lines" msgstr "总行数:" -msgid "Displayed Lines" -msgstr "展示行数:" - -msgid "%d lines" -msgstr "%d 行" +msgid "Read List" +msgstr "读取列表" diff --git a/applications/luci-app-passwall/root/usr/share/passwall/0_default_config b/applications/luci-app-passwall/root/usr/share/passwall/0_default_config index 918aaa4a9d1..83482179338 100644 --- a/applications/luci-app-passwall/root/usr/share/passwall/0_default_config +++ b/applications/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/applications/luci-app-passwall/root/usr/share/passwall/app.sh b/applications/luci-app-passwall/root/usr/share/passwall/app.sh index e6226731ed9..effc3851ec2 100755 --- a/applications/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/applications/luci-app-passwall/root/usr/share/passwall/app.sh @@ -9,18 +9,14 @@ 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 TMP_PATH2=/tmp/etc/${CONFIG}_tmp -DNSMASQ_PATH=/etc/dnsmasq.d -DNSMASQ_CONF_DIR=/tmp/dnsmasq.d -TMP_DNSMASQ_PATH=${DNSMASQ_CONF_DIR}/${CONFIG} +GLOBAL_ACL_PATH=${TMP_ACL_PATH}/default LOG_FILE=/tmp/log/$CONFIG.log APP_PATH=/usr/share/$CONFIG RULES_PATH=/usr/share/${CONFIG}/rules -DNS_N=dnsmasq DNS_PORT=15353 TUN_DNS="127.0.0.1#${DNS_PORT}" LOCAL_DNS=119.29.29.29,223.5.5.5 @@ -359,6 +355,37 @@ parse_doh() { eval "${__url_var}='${__url}' ${__host_var}='${__host}' ${__port_var}='${__port}' ${__bootstrap_var}='${__bootstrap}'" } +get_geoip() { + local geoip_code="$1" + local geoip_type_flag="" + local geoip_path="$(config_t_get global_rules v2ray_location_asset)" + geoip_path="${geoip_path%*/}/geoip.dat" + [ -e "$geoip_path" ] || { echo ""; return; } + case "$2" in + "ipv4") geoip_type_flag="-ipv6=false" ;; + "ipv6") geoip_type_flag="-ipv4=false" ;; + esac + if type geoview &> /dev/null; then + geoview -input "$geoip_path" -list "$geoip_code" $geoip_type_flag -lowmem=true + else + echo "" + 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="" @@ -698,15 +725,17 @@ 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() { local node proto bind local_port config_file log_file eval_set_val $@ local tcp_node_socks_flag tcp_node_http_flag - [ -n "$config_file" ] && [ -z "$(echo ${config_file} | grep $TMP_PATH)" ] && config_file=${TMP_ACL_PATH}/default/${config_file} + [ -n "$config_file" ] && [ -z "$(echo ${config_file} | grep $TMP_PATH)" ] && config_file=${GLOBAL_ACL_PATH}/${config_file} if [ -n "$log_file" ] && [ -z "$(echo ${log_file} | grep $TMP_PATH)" ]; then - log_file=${TMP_ACL_PATH}/default/${log_file} + log_file=${GLOBAL_ACL_PATH}/${log_file} else log_file="/dev/null" fi @@ -1050,11 +1079,12 @@ run_redir() { [ "$tcp_node_socks" = "1" ] && { TCP_SOCKS_server="127.0.0.1:$tcp_node_socks_port" - echo "${TCP_SOCKS_server}" > $TMP_ACL_PATH/default/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 } @@ -1069,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 > $TMP_ACL_PATH/default/${proto}.id + set_cache_var "GLOBAL_${proto}_node" "$node" else [ "${proto}" = "UDP" ] && [ "$TCP_UDP" = "1" ] && return echolog "${proto}节点没有选择或为空,不代理${proto}。" @@ -1097,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) @@ -1131,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 } } @@ -1533,13 +1565,44 @@ start_dns() { dnsmasq_version=$(dnsmasq -v | grep -i "Dnsmasq version " | awk '{print $3}') [ "$(expr $dnsmasq_version \>= 2.87)" == 0 ] && echolog "Dnsmasq版本低于2.87,有可能无法正常使用!!!" } - source $APP_PATH/helper_dnsmasq.sh stretch - lua $APP_PATH/helper_dnsmasq_add.lua -FLAG "default" -TMP_DNSMASQ_PATH ${TMP_DNSMASQ_PATH} -DNSMASQ_CONF_DIR ${DNSMASQ_CONF_DIR} \ - -DNSMASQ_CONF_FILE "${DNSMASQ_CONF_DIR}/dnsmasq-${CONFIG}.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} + + 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() { @@ -1579,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}" @@ -1599,6 +1662,7 @@ acl_app() { redir_port=11200 dns_port=11300 dnsmasq_port=11400 + [ -n "${GLOBAL_DNSMASQ_PORT}" ] && dnsmasq_port=$(get_new_port $GLOBAL_DNSMASQ_PORT) chinadns_port=11500 for item in $items; do sid=$(uci -q show "${CONFIG}.${item}" | grep "=acl_rule" | awk -F '=' '{print $1}' | awk -F '.' '{print $2}') @@ -1625,9 +1689,10 @@ acl_app() { unset s2 done - mkdir -p $TMP_ACL_PATH/$sid + local acl_path=${TMP_ACL_PATH}/$sid + mkdir -p ${acl_path} - [ ! -z "${source_list}" ] && echo -e "${source_list}" | sed '/^$/d' > $TMP_ACL_PATH/$sid/source_list + [ ! -z "${source_list}" ] && echo -e "${source_list}" | sed '/^$/d' > ${acl_path}/source_list use_global_config=${use_global_config:-0} tcp_node=${tcp_node:-nil} @@ -1726,28 +1791,16 @@ acl_app() { } dnsmasq_port=$(get_new_port $(expr $dnsmasq_port + 1)) - redirect_dns_port=$dnsmasq_port - mkdir -p $TMP_ACL_PATH/$sid/dnsmasq.d - [ -s "/tmp/etc/dnsmasq.conf.${DEFAULT_DNSMASQ_CFGID}" ] && { - cp -r /tmp/etc/dnsmasq.conf.${DEFAULT_DNSMASQ_CFGID} $TMP_ACL_PATH/$sid/dnsmasq.conf - sed -i "/ubus/d" $TMP_ACL_PATH/$sid/dnsmasq.conf - sed -i "/dhcp/d" $TMP_ACL_PATH/$sid/dnsmasq.conf - sed -i "/port=/d" $TMP_ACL_PATH/$sid/dnsmasq.conf - sed -i "/conf-dir/d" $TMP_ACL_PATH/$sid/dnsmasq.conf - sed -i "/server/d" $TMP_ACL_PATH/$sid/dnsmasq.conf - } - echo "port=${dnsmasq_port}" >> $TMP_ACL_PATH/$sid/dnsmasq.conf - [ "$use_default_dns" = "remote" ] && { - dnsmasq_version=$(dnsmasq -v | grep -i "Dnsmasq version " | awk '{print $3}') - [ "$(expr $dnsmasq_version \>= 2.87)" == 0 ] && echolog "Dnsmasq版本低于2.87,有可能无法正常使用!!!" - } - lua $APP_PATH/helper_dnsmasq_add.lua -FLAG ${sid} -TMP_DNSMASQ_PATH $TMP_ACL_PATH/$sid/dnsmasq.d -DNSMASQ_CONF_DIR ${DNSMASQ_CONF_DIR} \ - -DNSMASQ_CONF_FILE $TMP_ACL_PATH/$sid/dnsmasq.conf -DEFAULT_DNS $DEFAULT_DNS -LOCAL_DNS $LOCAL_DNS \ + local dnsmasq_conf=${acl_path}/dnsmasq.conf + local dnsmasq_conf_path=${acl_path}/dnsmasq.d + lua $APP_PATH/helper_dnsmasq.lua add_rule -FLAG ${sid} -TMP_DNSMASQ_PATH ${dnsmasq_conf_path} -DNSMASQ_CONF_FILE ${dnsmasq_conf} \ + -LISTEN_PORT ${dnsmasq_port} -DEFAULT_DNS $DEFAULT_DNS -LOCAL_DNS $LOCAL_DNS \ -USE_DIRECT_LIST "${use_direct_list}" -USE_PROXY_LIST "${use_proxy_list}" -USE_BLOCK_LIST "${use_block_list}" -USE_GFW_LIST "${use_gfw_list}" -CHN_LIST "${chn_list}" \ -TUN_DNS "127.0.0.1#${_dns_port}" -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 $TMP_ACL_PATH/$sid/dnsmasq.conf -x $TMP_ACL_PATH/$sid/dnsmasq.pid + ln_run "$(first_type dnsmasq)" "dnsmasq_${sid}" "/dev/null" -C ${dnsmasq_conf} -x ${acl_path}/dnsmasq.pid + set_cache_var "ACL_${sid}_dns_port" "${dnsmasq_port}" 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}) @@ -1760,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 - redirect_dns_port=${_dnsmasq_port} + [ -n "${_dnsmasq_port}" ] && set_cache_var "ACL_${sid}_dns_port" "${_dnsmasq_port}" fi else socks_port=$(get_new_port $(expr $socks_port + 1)) @@ -1798,10 +1851,10 @@ acl_app() { fi run_dns ${_dns_port} fi - echo "${tcp_node}" > $TMP_ACL_PATH/$sid/var_tcp_node + set_cache_var "ACL_${sid}_tcp_node" "${tcp_node}" } fi - echo "${tcp_port}" > $TMP_ACL_PATH/$sid/var_tcp_port + set_cache_var "ACL_${sid}_tcp_port" "${tcp_port}" } [ "$udp_node" != "nil" ] && { [ "$udp_node" = "tcp" ] && udp_node=$tcp_node @@ -1850,18 +1903,15 @@ 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}" > $TMP_ACL_PATH/$sid/var_udp_node + set_cache_var "ACL_${sid}_udp_node" "${udp_node}" fi } fi - echo "${udp_port}" > $TMP_ACL_PATH/$sid/var_udp_port - udp_flag=1 + set_cache_var "ACL_${sid}_udp_port" "${udp_port}" } - [ -n "$redirect_dns_port" ] && echo "${redirect_dns_port}" > $TMP_ACL_PATH/$sid/var_redirect_dns_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 unset _china_ng_listen _chinadns_local_dns _direct_dns_mode chinadns_ng_default_tag dnsmasq_filter_proxy_ipv6 - unset redirect_dns_port done unset socks_port redir_port dns_port dnsmasq_port chinadns_port } @@ -1903,14 +1953,34 @@ 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 $TMP_ACL_PATH/default + mkdir -p ${GLOBAL_ACL_PATH} start_redir TCP start_redir UDP start_dns } [ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start - [ "$ENABLED_DEFAULT_ACL" == 1 ] && source $APP_PATH/helper_${DNS_N}.sh logic_restart + 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" } @@ -1927,11 +1997,14 @@ stop() { unset XRAY_LOCATION_ASSET stop_crontab source $APP_PATH/helper_smartdns.sh del - source $APP_PATH/helper_dnsmasq.sh del - source $APP_PATH/helper_dnsmasq.sh restart no_log=1 - [ -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 @@ -1999,9 +2072,16 @@ RESOLVFILE=/tmp/resolv.conf.d/resolv.conf.auto ISP_DNS=$(cat $RESOLVFILE 2>/dev/null | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | sort -u | grep -v 0.0.0.0 | grep -v 127.0.0.1) ISP_DNS6=$(cat $RESOLVFILE 2>/dev/null | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | awk -F % '{print $1}' | awk -F " " '{print $2}'| sort -u | grep -v -Fx ::1 | grep -v -Fx ::) +DEFAULT_DNS=$(uci show dhcp.@dnsmasq[0] | grep "\.server=" | awk -F '=' '{print $2}' | sed "s/'//g" | tr ' ' '\n' | grep -v "\/" | head -2 | sed ':label;N;s/\n/,/;b label') +[ -z "${DEFAULT_DNS}" ] && [ "$(echo $ISP_DNS | tr ' ' '\n' | wc -l)" -le 2 ] && DEFAULT_DNS=$(echo -n $ISP_DNS | tr ' ' '\n' | head -2 | tr '\n' ',') +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")" + 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} @@ -2009,11 +2089,8 @@ if [ -f "/tmp/etc/dnsmasq.conf.$DEFAULT_DNSMASQ_CFGID" ]; then DNSMASQ_CONF_DIR="/tmp/dnsmasq.d" fi fi - -DEFAULT_DNS=$(uci show dhcp.@dnsmasq[0] | grep "\.server=" | awk -F '=' '{print $2}' | sed "s/'//g" | tr ' ' '\n' | grep -v "\/" | head -2 | sed ':label;N;s/\n/,/;b label') -[ -z "${DEFAULT_DNS}" ] && [ "$(echo $ISP_DNS | tr ' ' '\n' | wc -l)" -le 2 ] && DEFAULT_DNS=$(echo -n $ISP_DNS | tr ' ' '\n' | head -2 | tr '\n' ',') -LOCAL_DNS="${DEFAULT_DNS:-119.29.29.29,223.5.5.5}" -IPT_APPEND_DNS=${LOCAL_DNS} +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" @@ -2021,7 +2098,7 @@ 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 @@ -2044,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/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua b/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua new file mode 100644 index 00000000000..f1c04d538ed --- /dev/null +++ b/applications/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/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.sh b/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.sh deleted file mode 100755 index 000924a64f7..00000000000 --- a/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/sh - -stretch() { - #zhenduiluanshezhiDNSderen - local dnsmasq_server=$(uci -q get dhcp.@dnsmasq[0].server) - local dnsmasq_noresolv=$(uci -q get dhcp.@dnsmasq[0].noresolv) - local _flag - for server in $dnsmasq_server; do - [ -z "$(echo $server | grep '\/')" ] && _flag=1 - done - [ -z "$_flag" ] && [ "$dnsmasq_noresolv" = "1" ] && { - uci -q delete dhcp.@dnsmasq[0].noresolv - uci -q set dhcp.@dnsmasq[0].resolvfile="$RESOLVFILE" - uci commit dhcp - } -} - -backup_servers() { - DNSMASQ_DNS=$(uci show dhcp.@dnsmasq[0] | grep ".server=" | awk -F '=' '{print $2}' | sed "s/'//g" | tr ' ' ',') - if [ -n "${DNSMASQ_DNS}" ]; then - uci -q set $CONFIG.@global[0].dnsmasq_servers="${DNSMASQ_DNS}" - uci commit $CONFIG - fi -} - -restore_servers() { - OLD_SERVER=$(uci -q get $CONFIG.@global[0].dnsmasq_servers | tr "," " ") - for server in $OLD_SERVER; do - uci -q del_list dhcp.@dnsmasq[0].server=$server - uci -q add_list dhcp.@dnsmasq[0].server=$server - done - uci commit dhcp - uci -q delete $CONFIG.@global[0].dnsmasq_servers - uci commit $CONFIG -} - -logic_restart() { - local no_log - eval_set_val $@ - _LOG_FILE=$LOG_FILE - [ -n "$no_log" ] && LOG_FILE="/dev/null" - if [ -f "$TMP_PATH/default_DNS" ]; then - backup_servers - #sed -i "/list server/d" /etc/config/dhcp >/dev/null 2>&1 - for server in $(uci -q get dhcp.@dnsmasq[0].server); do - [ -n "$(echo $server | grep '\/')" ] || uci -q del_list dhcp.@dnsmasq[0].server="$server" - done - /etc/init.d/dnsmasq restart >/dev/null 2>&1 - restore_servers - else - /etc/init.d/dnsmasq restart >/dev/null 2>&1 - fi - echolog "重启 dnsmasq 服务" - LOG_FILE=${_LOG_FILE} -} - -restart() { - local no_log - eval_set_val $@ - _LOG_FILE=$LOG_FILE - [ -n "$no_log" ] && LOG_FILE="/dev/null" - /etc/init.d/dnsmasq restart >/dev/null 2>&1 - echolog "重启 dnsmasq 服务" - LOG_FILE=${_LOG_FILE} -} - -del() { - rm -rf $DNSMASQ_CONF_DIR/dnsmasq-$CONFIG.conf - rm -rf $DNSMASQ_PATH/dnsmasq-$CONFIG.conf - rm -rf $TMP_DNSMASQ_PATH -} - -arg1=$1 -shift -case $arg1 in -stretch) - stretch $@ - ;; -del) - del $@ - ;; -restart) - restart $@ - ;; -logic_restart) - logic_restart $@ - ;; -*) ;; -esac diff --git a/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq_add.lua b/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq_add.lua deleted file mode 100644 index 12748328263..00000000000 --- a/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq_add.lua +++ /dev/null @@ -1,508 +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 DNSMASQ_CONF_DIR = var["-DNSMASQ_CONF_DIR"] -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(DNSMASQ_CONF_DIR) - 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/applications/luci-app-passwall/root/usr/share/passwall/iptables.sh b/applications/luci-app-passwall/root/usr/share/passwall/iptables.sh index 9e9762278e7..8a30e42d531 100755 --- a/applications/luci-app-passwall/root/usr/share/passwall/iptables.sh +++ b/applications/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" @@ -182,23 +184,6 @@ get_wan6_ip() { echo $NET_ADDR } -get_geoip() { - local geoip_code="$1" - local geoip_type_flag="" - local geoip_path="$(config_t_get global_rules v2ray_location_asset)" - geoip_path="${geoip_path%*/}/geoip.dat" - [ -e "$geoip_path" ] || { echo ""; return; } - case "$2" in - "ipv4") geoip_type_flag="-ipv6=false" ;; - "ipv6") geoip_type_flag="-ipv4=false" ;; - esac - if type geoview &> /dev/null; then - geoview -input "$geoip_path" -list "$geoip_code" $geoip_type_flag -lowmem=true - else - echo "" - fi -} - load_acl() { ([ "$ENABLED_ACLS" == 1 ] || ([ "$ENABLED_DEFAULT_ACL" == 1 ] && [ "$CLIENT_PROXY" == 1 ])) && echolog " - 访问控制:" [ "$ENABLED_ACLS" == 1 ] && { @@ -229,10 +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) + [ -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 @@ -259,6 +245,9 @@ load_acl() { chn_list=${CHN_LIST} tcp_proxy_mode=${TCP_PROXY_MODE} udp_proxy_mode=${UDP_PROXY_MODE} + use_shunt_tcp=${USE_SHUNT_TCP} + use_shunt_udp=${USE_SHUNT_UDP} + dns_redirect_port=${DNS_REDIRECT_PORT} } _acl_list=${TMP_ACL_PATH}/${sid}/source_list @@ -334,6 +323,24 @@ 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}" ] && 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 "$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" ] && { [ "${use_direct_list}" = "1" ] && $ipt_n -A PSW $(comment "$remarks") ${_ipt_source} $(dst $IPSET_WHITELIST) -j RETURN [ "${use_direct_list}" = "1" ] && $ipt_m -A PSW $(comment "$remarks") ${_ipt_source} $(dst $IPSET_WHITELIST) -j RETURN @@ -380,7 +387,6 @@ load_acl() { [ -n "$tcp_port" ] && { if [ -n "${tcp_proxy_mode}" ]; then - [ -s "${TMP_ACL_PATH}/${sid}/var_redirect_dns_port" ] && $ipt_n -A PSW_REDIRECT $(comment "$remarks") -p udp ${_ipt_source} --dport 53 -j REDIRECT --to-ports $(cat ${TMP_ACL_PATH}/${sid}/var_redirect_dns_port) msg2="${msg}使用 TCP 节点[$tcp_node_remark]" if [ -n "${is_tproxy}" ]; then msg2="${msg2}(TPROXY:${tcp_port})" @@ -463,8 +469,8 @@ load_acl() { $ipt_m -A PSW $(comment "$remarks") ${_ipt_source} -p udp -j RETURN 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 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 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 dns_redirect done } @@ -495,6 +501,25 @@ 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}" ] && 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}" ] && { [ "${USE_DIRECT_LIST}" = "1" ] && $ipt_n -A PSW $(comment "默认") $(dst $IPSET_WHITELIST) -j RETURN [ "${USE_DIRECT_LIST}" = "1" ] && $ipt_m -A PSW $(comment "默认") $(dst $IPSET_WHITELIST) -j RETURN @@ -615,7 +640,6 @@ load_acl() { } echolog " - ${msg2}" - udp_flag=1 } fi $ipt_m -A PSW $(comment "默认") -p udp -j RETURN @@ -638,126 +662,53 @@ filter_vpsip() { echolog " - [$?]加入所有IPv6节点到ipset[$IPSET_VPSLIST6]直连完成" } -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) - 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 " - 节点配置不正常,略过" - return 0 - 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 - unset dst_rule - 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 0 - 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 default_node=$(config_n_get $proxy_node default_node _direct) - local main_node=$(config_n_get $proxy_node main_node nil) - if [ "$main_node" != "nil" ]; then - filter_rules $main_node $stream - else - if [ "$default_node" != "_direct" ] && [ "$default_node" != "_blackhole" ]; then - filter_rules $default_node $stream - fi +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 -:</dev/null - $ipt_n -I PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 53 -m comment --comment "PSW_DNS_Hijack" 2>/dev/null - $ip6t_n -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 53 -m comment --comment "PSW_DNS_Hijack" 2>/dev/null - $ip6t_n -I PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 53 -m comment --comment "PSW_DNS_Hijack" 2>/dev/null - echolog " - 开启 DNS 重定向" - } +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 @@ -767,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 @@ -866,6 +818,14 @@ add_firewall_rule() { 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 $(gen_lanlist | sed -e "s/^/add $IPSET_LANLIST /") @@ -939,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 @@ -1007,6 +972,14 @@ add_firewall_rule() { $ip6t_n -A PSW_OUTPUT -m mark --mark 0xff -j RETURN } + $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 $ip6t_m -A PSW_DIVERT -j ACCEPT @@ -1041,43 +1014,7 @@ 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 - local ipt_tmp=$ipt_n if [ -n "${is_tproxy}" ]; then ipt_tmp=$ipt_m @@ -1109,6 +1046,15 @@ add_firewall_rule() { fi } + if ([ "$TCP_NODE" != "nil" ] && [ -n "${LOCALHOST_TCP_PROXY_MODE}" ]) || ([ "$UDP_NODE" != "nil" ] && [ -n "${LOCALHOST_UDP_PROXY_MODE}" ]); then + [ -n "$DNS_REDIRECT_PORT" ] && { + $ipt_n -A OUTPUT $(comment "PSW") -p udp -o lo --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT + $ip6t_n -A OUTPUT $(comment "PSW") -p udp -o lo --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null + $ipt_n -A OUTPUT $(comment "PSW") -p tcp -o lo --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT + $ip6t_n -A OUTPUT $(comment "PSW") -p tcp -o lo --dport 53 -j REDIRECT --to-ports $DNS_REDIRECT_PORT 2>/dev/null + } + fi + [ -n "${LOCALHOST_TCP_PROXY_MODE}" -o -n "${LOCALHOST_UDP_PROXY_MODE}" ] && { [ "$TCP_PROXY_DROP_PORTS" != "disable" ] && { $ipt_m -A PSW_OUTPUT -p tcp $(factor $TCP_PROXY_DROP_PORTS "-m multiport --dport") -d $FAKE_IP -j DROP @@ -1266,32 +1212,23 @@ add_firewall_rule() { $ip6t_m -I OUTPUT $(comment "mangle-OUTPUT-PSW") -o lo -j RETURN insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW) -m mark --mark 1 -j RETURN" - - dns_hijack - } # 加载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 "防火墙规则加载完成!" } @@ -1303,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 @@ -1315,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 @@ -1324,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 @@ -1485,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/applications/luci-app-passwall/root/usr/share/passwall/nftables.sh b/applications/luci-app-passwall/root/usr/share/passwall/nftables.sh index 6e95c237e12..e90fd767cef 100755 --- a/applications/luci-app-passwall/root/usr/share/passwall/nftables.sh +++ b/applications/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" @@ -242,23 +244,6 @@ get_wan6_ip() { echo $NET_ADDR } -get_geoip() { - local geoip_code="$1" - local geoip_type_flag="" - local geoip_path="$(config_t_get global_rules v2ray_location_asset)" - geoip_path="${geoip_path%*/}/geoip.dat" - [ -e "$geoip_path" ] || { echo ""; return; } - case "$2" in - "ipv4") geoip_type_flag="-ipv6=false" ;; - "ipv6") geoip_type_flag="-ipv4=false" ;; - esac - if type geoview &> /dev/null; then - geoview -input "$geoip_path" -list "$geoip_code" $geoip_type_flag -lowmem=true - else - echo "" - fi -} - load_acl() { ([ "$ENABLED_ACLS" == 1 ] || ([ "$ENABLED_DEFAULT_ACL" == 1 ] && [ "$CLIENT_PROXY" == 1 ])) && echolog " - 访问控制:" [ "$ENABLED_ACLS" == 1 ] && { @@ -289,10 +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) + [ -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 @@ -321,6 +307,7 @@ load_acl() { udp_proxy_mode=${UDP_PROXY_MODE} use_shunt_tcp=${USE_SHUNT_TCP} use_shunt_udp=${USE_SHUNT_UDP} + dns_redirect_port=${DNS_REDIRECT_PORT} } _acl_list=${TMP_ACL_PATH}/${sid}/source_list @@ -386,6 +373,24 @@ 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}" ] && 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 ${_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" ] && { [ "${use_direct_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE ${_ipt_source} ip daddr @$NFTSET_WHITELIST counter return comment \"$remarks\"" [ "${use_direct_list}" = "1" ] && [ -z "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME PSW_NAT ${_ipt_source} ip daddr @$NFTSET_WHITELIST counter return comment \"$remarks\"" @@ -433,7 +438,6 @@ load_acl() { [ -n "$tcp_port" ] && { if [ -n "${tcp_proxy_mode}" ]; then - [ -s "${TMP_ACL_PATH}/${sid}/var_redirect_dns_port" ] && nft "add rule $NFTABLE_NAME PSW_REDIRECT ip protocol udp ${_ipt_source} udp dport 53 counter redirect to $(cat ${TMP_ACL_PATH}/${sid}/var_redirect_dns_port) comment \"$remarks\"" msg2="${msg}使用 TCP 节点[$tcp_node_remark]" if [ -n "${is_tproxy}" ]; then msg2="${msg2}(TPROXY:${tcp_port})" @@ -521,8 +525,8 @@ load_acl() { nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} counter return comment \"$remarks\"" 2>/dev/null 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 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 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 dns_redirect done } @@ -550,6 +554,25 @@ 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}" ] && 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}" ] && { [ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE ip daddr @$NFTSET_WHITELIST counter return comment \"默认\"" [ "${USE_DIRECT_LIST}" = "1" ] && [ -z "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME PSW_NAT ip daddr @$NFTSET_WHITELIST counter return comment \"默认\"" @@ -679,7 +702,6 @@ load_acl() { } echolog " - ${msg2}" - udp_flag=1 } fi } @@ -709,122 +731,46 @@ filter_vpsip() { echolog " - [$?]加入所有IPv6节点到nftset[$NFTSET_VPSLIST6]直连完成" } -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) - _is_tproxy=${is_tproxy} - [ "$stream" == "udp" ] && _is_tproxy="TPROXY" - if [ -n "${_is_tproxy}" ]; then - msg="TPROXY" - else - msg="REDIRECT" - fi - else - echolog " - 节点配置不正常,略过" - return 0 - 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 - unset dst_rule - 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 0 - 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 default_node=$(config_n_get $proxy_node default_node _direct) - local main_node=$(config_n_get $proxy_node main_node nil) - if [ "$main_node" != "nil" ]; then - filter_rules $main_node $stream - else - if [ "$default_node" != "_direct" ] && [ "$default_node" != "_blackhole" ]; then - filter_rules $default_node $stream - fi +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 -:</dev/null - nft insert rule $NFTABLE_NAME dstnat position 0 udp dport 53 counter redirect to :53 comment \"PSW_DNS_Hijack\" 2>/dev/null - nft insert rule $NFTABLE_NAME dstnat position 0 meta nfproto {ipv6} tcp dport 53 counter redirect to :53 comment \"PSW_DNS_Hijack\" 2>/dev/null - nft insert rule $NFTABLE_NAME dstnat position 0 meta nfproto {ipv6} udp dport 53 counter redirect to :53 comment \"PSW_DNS_Hijack\" 2>/dev/null - uci -q set dhcp.@dnsmasq[0].dns_redirect='0' 2>/dev/null - uci commit dhcp 2>/dev/null - echolog " - 开启 DNS 重定向" - } +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() { @@ -832,6 +778,7 @@ add_firewall_rule() { 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" @@ -1122,43 +1079,7 @@ 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" ] && { @@ -1183,6 +1104,15 @@ add_firewall_rule() { fi } + if ([ "$TCP_NODE" != "nil" ] && [ -n "${LOCALHOST_TCP_PROXY_MODE}" ]) || ([ "$UDP_NODE" != "nil" ] && [ -n "${LOCALHOST_UDP_PROXY_MODE}" ]); then + [ -n "$DNS_REDIRECT_PORT" ] && { + nft "add rule $NFTABLE_NAME nat_output ip protocol udp oif lo udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW\"" + nft "add rule $NFTABLE_NAME nat_output ip protocol tcp oif lo tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW\"" + nft "add rule $NFTABLE_NAME nat_output meta l4proto udp oif lo udp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW\"" + nft "add rule $NFTABLE_NAME nat_output meta l4proto tcp oif lo tcp dport 53 counter redirect to :$DNS_REDIRECT_PORT comment \"PSW\"" + } + fi + [ -n "${LOCALHOST_TCP_PROXY_MODE}" -o -n "${LOCALHOST_UDP_PROXY_MODE}" ] && { [ "$TCP_PROXY_DROP_PORTS" != "disable" ] && { nft add rule $NFTABLE_NAME $nft_output_chain ip protocol tcp ip daddr $FAKE_IP $(factor $TCP_PROXY_DROP_PORTS "tcp dport") counter drop @@ -1340,28 +1270,20 @@ add_firewall_rule() { nft "add rule $NFTABLE_NAME mangle_output oif lo counter return comment \"PSW_OUTPUT_MANGLE\"" nft "add rule $NFTABLE_NAME mangle_output meta mark 1 counter return comment \"PSW_OUTPUT_MANGLE\"" - - dns_hijack } # 加载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 "防火墙规则加载完成!" } @@ -1386,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 @@ -1395,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 @@ -1506,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/applications/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh b/applications/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh index a43f895a859..6fc5aa5fadf 100755 --- a/applications/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh +++ b/applications/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 @@ -183,4 +182,3 @@ start() { } start $@ - diff --git a/applications/luci-app-passwall/root/usr/share/passwall/subscribe.lua b/applications/luci-app-passwall/root/usr/share/passwall/subscribe.lua index 7ab0e5cc7b5..f34c9299d52 100755 --- a/applications/luci-app-passwall/root/usr/share/passwall/subscribe.lua +++ b/applications/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