From 3e216255a65d1ac9ab4123989cba991d7acd5017 Mon Sep 17 00:00:00 2001 From: actions Date: Thu, 18 Jul 2024 03:00:09 +0800 Subject: [PATCH] luci-app-passwall2: sync upstream last commit: https://github.com/xiaorouji/openwrt-passwall2/commit/83558f51638e9783aee8452618eda4bc5425f958 --- luci-app-passwall2/Makefile | 2 +- .../luasrc/controller/passwall2.lua | 112 ++++++++++-------- .../model/cbi/passwall2/client/acl_config.lua | 4 +- .../model/cbi/passwall2/client/global.lua | 10 +- .../model/cbi/passwall2/client/haproxy.lua | 3 + .../client/node_subscribe_config.lua | 51 +++++--- .../model/cbi/passwall2/client/other.lua | 21 ++-- .../model/cbi/passwall2/client/rule.lua | 36 ++++-- .../cbi/passwall2/client/shunt_rules.lua | 13 +- .../cbi/passwall2/client/socks_config.lua | 3 + .../model/cbi/passwall2/client/type/ray.lua | 60 +++++++--- .../model/cbi/passwall2/server/type/ray.lua | 27 ++++- .../cbi/passwall2/server/type/sing-box.lua | 2 +- .../luasrc/passwall2/util_xray.lua | 24 ++-- luci-app-passwall2/po/zh-cn/passwall2.po | 59 +++++---- .../root/etc/uci-defaults/luci-passwall2 | 8 +- .../root/usr/share/passwall2/0_default_config | 3 +- .../root/usr/share/passwall2/app.sh | 80 +++++++++---- .../root/usr/share/passwall2/haproxy.lua | 9 +- .../root/usr/share/passwall2/nftables.sh | 3 +- .../root/usr/share/passwall2/rule_update.lua | 16 ++- .../root/usr/share/passwall2/subscribe.lua | 9 +- .../root/usr/share/passwall2/tasks.sh | 75 ++++++++++++ 23 files changed, 453 insertions(+), 177 deletions(-) create mode 100755 luci-app-passwall2/root/usr/share/passwall2/tasks.sh diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 92c5ab933..52acb40ff 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 -PKG_VERSION:=1.29-1 +PKG_VERSION:=1.30-1 PKG_RELEASE:= PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/luasrc/controller/passwall2.lua b/luci-app-passwall2/luasrc/controller/passwall2.lua index 14fed7fec..b5c0bdee8 100644 --- a/luci-app-passwall2/luasrc/controller/passwall2.lua +++ b/luci-app-passwall2/luasrc/controller/passwall2.lua @@ -2,24 +2,32 @@ module("luci.controller.passwall2", package.seeall) local api = require "luci.passwall2.api" -local appname = api.appname -local ucic = luci.model.uci.cursor() +local appname = api.appname -- not available +local uci = luci.model.uci.cursor() -- in funtion index() local http = require "luci.http" local util = require "luci.util" local i18n = require "luci.i18n" function index() - appname = require "luci.passwall2.api".appname + if not nixio.fs.access("/etc/config/passwall2") then + if nixio.fs.access("/usr/share/passwall2/0_default_config") then + luci.sys.call('cp -f /usr/share/passwall2/0_default_config /etc/config/passwall2') + else return end + end + local appname = "passwall2" -- global definitions not available + local uci = luci.model.uci.cursor() -- in function index() entry({"admin", "services", appname}).dependent = true entry({"admin", "services", appname, "reset_config"}, call("reset_config")).leaf = true entry({"admin", "services", appname, "show"}, call("show_menu")).leaf = true entry({"admin", "services", appname, "hide"}, call("hide_menu")).leaf = true - if not nixio.fs.access("/etc/config/passwall2") then return end - if nixio.fs.access("/etc/config/passwall2_show") then - e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), _("PassWall 2"), -1) - e.dependent = true - e.acl_depends = { "luci-app-passwall2" } + local e + if uci:get(appname, "@global[0]", "hide_from_luci") ~= "1" then + e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), _("Pass Wall"), -1) + else + e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), nil, -1) end + e.dependent = true + e.acl_depends = { "luci-app-passwall2" } --[[ Client ]] entry({"admin", "services", appname, "settings"}, cbi(appname .. "/client/global"), _("Basic Settings"), 1).dependent = true entry({"admin", "services", appname, "node_list"}, cbi(appname .. "/client/node_list"), _("Node List"), 2).dependent = true @@ -88,14 +96,16 @@ function reset_config() end function show_menu() - luci.sys.call("touch /etc/config/passwall2_show") + uci:delete(appname, "@global[0]", "hide_from_luci") + uci:commit(appname) luci.sys.call("rm -rf /tmp/luci-*") luci.sys.call("/etc/init.d/rpcd restart >/dev/null") luci.http.redirect(api.url()) end function hide_menu() - luci.sys.call("rm -rf /etc/config/passwall2_show") + uci:set(appname, "@global[0]", "hide_from_luci","1") + uci:commit(appname) luci.sys.call("rm -rf /tmp/luci-*") luci.sys.call("/etc/init.d/rpcd restart >/dev/null") luci.http.redirect(luci.dispatcher.build_url("admin", "status", "overview")) @@ -112,9 +122,9 @@ function socks_autoswitch_add_node() local id = luci.http.formvalue("id") local key = luci.http.formvalue("key") if id and id ~= "" and key and key ~= "" then - local new_list = ucic:get(appname, id, "autoswitch_backup_node") or {} + local new_list = uci:get(appname, id, "autoswitch_backup_node") or {} for i = #new_list, 1, -1 do - if (ucic:get(appname, new_list[i], "remarks") or ""):find(key) then + if (uci:get(appname, new_list[i], "remarks") or ""):find(key) then table.remove(new_list, i) end end @@ -123,8 +133,8 @@ function socks_autoswitch_add_node() table.insert(new_list, e.id) end end - ucic:set_list(appname, id, "autoswitch_backup_node", new_list) - ucic:commit(appname) + uci:set_list(appname, id, "autoswitch_backup_node", new_list) + uci:commit(appname) end luci.http.redirect(api.url("socks_config", id)) end @@ -133,14 +143,14 @@ function socks_autoswitch_remove_node() local id = luci.http.formvalue("id") local key = luci.http.formvalue("key") if id and id ~= "" and key and key ~= "" then - local new_list = ucic:get(appname, id, "autoswitch_backup_node") or {} + local new_list = uci:get(appname, id, "autoswitch_backup_node") or {} for i = #new_list, 1, -1 do - if (ucic:get(appname, new_list[i], "remarks") or ""):find(key) then + if (uci:get(appname, new_list[i], "remarks") or ""):find(key) then table.remove(new_list, i) end end - ucic:set_list(appname, id, "autoswitch_backup_node", new_list) - ucic:commit(appname) + uci:set_list(appname, id, "autoswitch_backup_node", new_list) + uci:commit(appname) end luci.http.redirect(api.url("socks_config", id)) end @@ -208,7 +218,7 @@ function socks_status() local id = luci.http.formvalue("id") e.index = index e.socks_status = luci.sys.call(string.format("/bin/busybox top -bn1 | grep -v -E 'grep|acl/|acl_' | grep '%s/bin/' | grep '%s' | grep 'SOCKS_' > /dev/null", appname, id)) == 0 - local use_http = ucic:get(appname, id, "http_port") or 0 + local use_http = uci:get(appname, id, "http_port") or 0 e.use_http = 0 if tonumber(use_http) > 0 then e.use_http = 1 @@ -279,8 +289,8 @@ function set_node() local type = luci.http.formvalue("type") local config = luci.http.formvalue("config") local section = luci.http.formvalue("section") - ucic:set(appname, type, config, section) - ucic:commit(appname) + uci:set(appname, type, config, section) + uci:commit(appname) luci.sys.call("/etc/init.d/passwall2 restart > /dev/null 2>&1 &") luci.http.redirect(api.url("log")) end @@ -288,76 +298,76 @@ end function copy_node() local section = luci.http.formvalue("section") local uuid = api.gen_short_uuid() - ucic:section(appname, "nodes", uuid) - for k, v in pairs(ucic:get_all(appname, section)) do + uci:section(appname, "nodes", uuid) + for k, v in pairs(uci:get_all(appname, section)) do local filter = k:find("%.") if filter and filter == 1 then else xpcall(function() - ucic:set(appname, uuid, k, v) + uci:set(appname, uuid, k, v) end, function(e) end) end end - ucic:delete(appname, uuid, "add_from") - ucic:set(appname, uuid, "add_mode", 1) - ucic:commit(appname) + uci:delete(appname, uuid, "add_from") + uci:set(appname, uuid, "add_mode", 1) + uci:commit(appname) luci.http.redirect(api.url("node_config", uuid)) end function clear_all_nodes() - ucic:set(appname, '@global[0]', "enabled", "0") - ucic:set(appname, '@global[0]', "node", "nil") - ucic:foreach(appname, "socks", function(t) - ucic:delete(appname, t[".name"]) - ucic:set_list(appname, t[".name"], "autoswitch_backup_node", {}) + uci:set(appname, '@global[0]', "enabled", "0") + uci:set(appname, '@global[0]', "node", "nil") + uci:foreach(appname, "socks", function(t) + uci:delete(appname, t[".name"]) + uci:set_list(appname, t[".name"], "autoswitch_backup_node", {}) end) - ucic:foreach(appname, "haproxy_config", function(t) - ucic:delete(appname, t[".name"]) + uci:foreach(appname, "haproxy_config", function(t) + uci:delete(appname, t[".name"]) end) - ucic:foreach(appname, "acl_rule", function(t) - ucic:set(appname, t[".name"], "node", "default") + uci:foreach(appname, "acl_rule", function(t) + uci:set(appname, t[".name"], "node", "default") end) - ucic:foreach(appname, "nodes", function(node) - ucic:delete(appname, node['.name']) + uci:foreach(appname, "nodes", function(node) + uci:delete(appname, node['.name']) end) - ucic:commit(appname) + uci:commit(appname) luci.sys.call("/etc/init.d/" .. appname .. " stop") end function delete_select_nodes() local ids = luci.http.formvalue("ids") string.gsub(ids, '[^' .. "," .. ']+', function(w) - if (ucic:get(appname, "@global[0]", "node") or "nil") == w then - ucic:set(appname, '@global[0]', "node", "nil") + if (uci:get(appname, "@global[0]", "node") or "nil") == w then + uci:set(appname, '@global[0]', "node", "nil") end - ucic:foreach(appname, "socks", function(t) + uci:foreach(appname, "socks", function(t) if t["node"] == w then - ucic:delete(appname, t[".name"]) + uci:delete(appname, t[".name"]) end - local auto_switch_node_list = ucic:get(appname, t[".name"], "autoswitch_backup_node") or {} + local auto_switch_node_list = uci:get(appname, t[".name"], "autoswitch_backup_node") or {} for i = #auto_switch_node_list, 1, -1 do if w == auto_switch_node_list[i] then table.remove(auto_switch_node_list, i) end end - ucic:set_list(appname, t[".name"], "autoswitch_backup_node", auto_switch_node_list) + uci:set_list(appname, t[".name"], "autoswitch_backup_node", auto_switch_node_list) end) - ucic:foreach(appname, "haproxy_config", function(t) + uci:foreach(appname, "haproxy_config", function(t) if t["lbss"] == w then - ucic:delete(appname, t[".name"]) + uci:delete(appname, t[".name"]) end end) - ucic:foreach(appname, "acl_rule", function(t) + uci:foreach(appname, "acl_rule", function(t) if t["node"] == w then - ucic:set(appname, t[".name"], "node", "default") + uci:set(appname, t[".name"], "node", "default") end end) - ucic:delete(appname, w) + uci:delete(appname, w) end) - ucic:commit(appname) + uci:commit(appname) luci.sys.call("/etc/init.d/" .. appname .. " restart > /dev/null 2>&1 &") end diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl_config.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl_config.lua index fc686b5cb..12ec9960b 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl_config.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/acl_config.lua @@ -217,6 +217,7 @@ o:value("1.1.1.2", "1.1.1.2 (CloudFlare-Security)") o:value("8.8.4.4", "8.8.4.4 (Google)") o:value("8.8.8.8", "8.8.8.8 (Google)") o:value("9.9.9.9", "9.9.9.9 (Quad9-Recommended)") +o:value("149.112.112.112", "149.112.112.112 (Quad9-Recommended)") o:value("208.67.220.220", "208.67.220.220 (OpenDNS)") o:value("208.67.222.222", "208.67.222.222 (OpenDNS)") o:depends("remote_dns_protocol", "tcp") @@ -228,7 +229,8 @@ o:value("https://1.1.1.1/dns-query", "CloudFlare") o:value("https://1.1.1.2/dns-query", "CloudFlare-Security") o:value("https://8.8.4.4/dns-query", "Google 8844") o:value("https://8.8.8.8/dns-query", "Google 8888") -o:value("https://9.9.9.9/dns-query", "Quad9-Recommended") +o:value("https://9.9.9.9/dns-query", "Quad9-Recommended 9.9.9.9") +o:value("https://149.112.112.112/dns-query", "Quad9-Recommended 149.112.112.112") o:value("https://208.67.222.222/dns-query", "OpenDNS") o:value("https://dns.adguard.com/dns-query,176.103.130.130", "AdGuard") o:value("https://doh.libredns.gr/dns-query,116.202.176.26", "LibreDNS") diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua index 29823e1c2..07b3dfd83 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua @@ -52,7 +52,7 @@ local doh_validate = function(self, value, t) for i = 1, #val do local v = val[i] if v then - if not datatypes.ipmask4(v) then + if not datatypes.ipmask4(v) and not datatypes.ipmask6(v) then flag = 1 end end @@ -238,6 +238,10 @@ node_socks_port = s:taboption("Main", Value, "node_socks_port", translate("Node" node_socks_port.default = 1070 node_socks_port.datatype = "port" +node_socks_bind_local = s:taboption("Main", Flag, "node_socks_bind_local", translate("Node") .. " Socks " .. translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) +node_socks_bind_local.default = "1" +node_socks_bind_local:depends({ node = "nil", ["!reverse"] = true }) + s:tab("DNS", translate("DNS")) o = s:taboption("DNS", ListValue, "remote_dns_protocol", translate("Remote DNS Protocol")) @@ -254,6 +258,7 @@ o:value("1.1.1.2", "1.1.1.2 (CloudFlare-Security)") o:value("8.8.4.4", "8.8.4.4 (Google)") o:value("8.8.8.8", "8.8.8.8 (Google)") o:value("9.9.9.9", "9.9.9.9 (Quad9-Recommended)") +o:value("149.112.112.112", "149.112.112.112 (Quad9-Recommended)") o:value("208.67.220.220", "208.67.220.220 (OpenDNS)") o:value("208.67.222.222", "208.67.222.222 (OpenDNS)") o:depends("remote_dns_protocol", "tcp") @@ -266,7 +271,8 @@ o:value("https://1.1.1.1/dns-query", "CloudFlare") o:value("https://1.1.1.2/dns-query", "CloudFlare-Security") o:value("https://8.8.4.4/dns-query", "Google 8844") o:value("https://8.8.8.8/dns-query", "Google 8888") -o:value("https://9.9.9.9/dns-query", "Quad9-Recommended") +o:value("https://9.9.9.9/dns-query", "Quad9-Recommended 9.9.9.9") +o:value("https://149.112.112.112/dns-query", "Quad9-Recommended 149.112.112.112") o:value("https://208.67.222.222/dns-query", "OpenDNS") o:value("https://dns.adguard.com/dns-query,176.103.130.130", "AdGuard") o:value("https://doh.libredns.gr/dns-query,116.202.176.26", "LibreDNS") diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/haproxy.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/haproxy.lua index 65192afdb..f15240250 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/haproxy.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/haproxy.lua @@ -46,6 +46,9 @@ o = s:option(Value, "console_port", translate("Console Port"), translate( o.default = "1188" o:depends("balancing_enable", true) +o = s:option(Flag, "bind_local", translate("Haproxy Port") .. " " .. translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) +o.default = "0" + ---- Health Check Type o = s:option(ListValue, "health_check_type", translate("Health Check Type")) o.default = "passwall_logic" diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe_config.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe_config.lua index a11cd1670..9f88ff268 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe_config.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/node_subscribe_config.lua @@ -126,25 +126,48 @@ o = s:option(Flag, "auto_update", translate("Enable auto update subscribe")) o.default = 0 o.rmempty = false ----- Week update rules -o = s:option(ListValue, "week_update", translate("Week update rules")) +---- Week Update +o = s:option(ListValue, "week_update", translate("Update Mode")) +o:value(8, translate("Loop Mode")) o:value(7, translate("Every day")) -for e = 1, 6 do o:value(e, translate("Week") .. e) end -o:value(0, translate("Week") .. translate("day")) -o.default = 0 +o:value(1, translate("Every Monday")) +o:value(2, translate("Every Tuesday")) +o:value(3, translate("Every Wednesday")) +o:value(4, translate("Every Thursday")) +o:value(5, translate("Every Friday")) +o:value(6, translate("Every Saturday")) +o:value(0, translate("Every Sunday")) +o.default = 7 o:depends("auto_update", true) +o.rmempty = true ----- Day update rules -o = s:option(ListValue, "time_update", translate("Day update rules")) -for e = 0, 23 do o:value(e, e .. translate("oclock")) end +---- Time Update +o = s:option(ListValue, "time_update", translate("Update Time(every day)")) +for t = 0, 23 do o:value(t, t .. ":00") end o.default = 0 -o:depends("auto_update", true) +o:depends("week_update", "0") +o:depends("week_update", "1") +o:depends("week_update", "2") +o:depends("week_update", "3") +o:depends("week_update", "4") +o:depends("week_update", "5") +o:depends("week_update", "6") +o:depends("week_update", "7") +o.rmempty = true + +---- Interval Update +o = s:option(ListValue, "interval_update", translate("Update Interval(hour)")) +for t = 1, 24 do o:value(t, t .. " " .. translate("hour")) end +o.default = 2 +o:depends("week_update", "8") +o.rmempty = true o = s:option(Value, "user_agent", translate("User-Agent")) -o.default = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0" -o:value("curl") -o:value("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0") -o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0") -o:value("Passwall2/OpenWrt") +o.default = "sing-box/9.9.9" +o:value("curl", "Curl Default") +o:value("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0", "Edge for Linux") +o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0", "Edge for Windows") +o:value("Passwall2/OpenWrt", "PassWall2") +o:value("sing-box/9.9.9", "Xboard(V2board)") return m diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua index fb697493f..16545f0dd 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/other.lua @@ -151,36 +151,29 @@ if has_xray then o:value("1-3", "1-3") o:value("1-5", "1-5") o:depends("fragment", true) - + o = s_xray:option(Value, "fragment_length", translate("Fragment Length"), translate("Fragmented packet length (byte)")) o.default = "100-200" o:depends("fragment", true) - + o = s_xray:option(Value, "fragment_interval", translate("Fragment Interval"), translate("Fragmentation interval (ms)")) o.default = "10-20" o:depends("fragment", true) - - o = s_xray:option(Flag, "sniffing", translate("Sniffing"), translate("When using the shunt, must be enabled, otherwise the shunt will invalid.")) - o.default = 1 - o.rmempty = false + + o = s_xray:option(Flag, "sniffing_override_dest", translate("Override the connection destination address"), translate("Override the connection destination address with the sniffed domain.")) + o.default = 0 o = s_xray:option(Flag, "route_only", translate("Sniffing Route Only")) o.default = 0 o:depends("sniffing", true) local domains_excluded = string.format("/usr/share/%s/domains_excluded", appname) - o = s_xray:option(TextValue, "no_sniffing_hosts", translate("No Sniffing Lists"), translate("Hosts added into No Sniffing Lists will not resolve again on server.")) + 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.")) o.rows = 15 o.wrap = "off" o.cfgvalue = function(self, section) return fs.readfile(domains_excluded) or "" end o.write = function(self, section, value) fs.writefile(domains_excluded, value:gsub("\r\n", "\n")) end - o.remove = function(self, section) - local route_only_value = s_xray.fields["route_only"] and s_xray.fields["route_only"]:formvalue(section) or nil - if not route_only_value or route_only_value == "0" then - fs.writefile(domains_excluded, "") - end - end - o:depends({sniffing = true, route_only = false}) + o:depends({sniffing_override_dest = true}) o = s_xray:option(Value, "buffer_size", translate("Buffer Size"), translate("Buffer size for every connection (kB)")) o.datatype = "uinteger" diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/rule.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/rule.lua index 12fd1f2fc..e8aeba77b 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/rule.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/rule.lua @@ -30,18 +30,40 @@ o.default = 0 o.rmempty = false ---- Week Update -o = s:option(ListValue, "week_update", translate("Week update rules")) +o = s:option(ListValue, "week_update", translate("Update Mode")) +o:value(8, translate("Loop Mode")) o:value(7, translate("Every day")) -for e = 1, 6 do o:value(e, translate("Week") .. e) end -o:value(0, translate("Week") .. translate("day")) -o.default = 0 +o:value(1, translate("Every Monday")) +o:value(2, translate("Every Tuesday")) +o:value(3, translate("Every Wednesday")) +o:value(4, translate("Every Thursday")) +o:value(5, translate("Every Friday")) +o:value(6, translate("Every Saturday")) +o:value(0, translate("Every Sunday")) +o.default = 7 o:depends("auto_update", true) +o.rmempty = true ---- Time Update -o = s:option(ListValue, "time_update", translate("Day update rules")) -for e = 0, 23 do o:value(e, e .. translate("oclock")) end +o = s:option(ListValue, "time_update", translate("Update Time(every day)")) +for t = 0, 23 do o:value(t, t .. ":00") end o.default = 0 -o:depends("auto_update", true) +o:depends("week_update", "0") +o:depends("week_update", "1") +o:depends("week_update", "2") +o:depends("week_update", "3") +o:depends("week_update", "4") +o:depends("week_update", "5") +o:depends("week_update", "6") +o:depends("week_update", "7") +o.rmempty = true + +---- Interval Update +o = s:option(ListValue, "interval_update", translate("Update Interval(hour)")) +for t = 1, 24 do o:value(t, t .. " " .. translate("hour")) end +o.default = 2 +o:depends("week_update", "8") +o.rmempty = true s = m:section(TypedSection, "shunt_rules", "Sing-Box/Xray " .. translate("Shunt Rule"), "" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "") s.template = "cbi/tblsection" diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/shunt_rules.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/shunt_rules.lua index 9676ffc11..b5ce3b73f 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/shunt_rules.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/shunt_rules.lua @@ -107,11 +107,13 @@ domain_list.rows = 10 domain_list.wrap = "off" domain_list.validate = function(self, value) local hosts= {} - string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(hosts, w) end) + value = value:gsub("^%s+", ""):gsub("%s+$","\n"):gsub("\r\n","\n"):gsub("[ \t]*\n[ \t]*", "\n") + string.gsub(value, "[^\r\n]+", function(w) table.insert(hosts, w) end) for index, host in ipairs(hosts) do local flag = 1 local tmp_host = host - if host:find("regexp:") and host:find("regexp:") == 1 then + if not host:find("#") and host:find("%s") then + elseif host:find("regexp:") and host:find("regexp:") == 1 then flag = 0 elseif host:find("domain:.") and host:find("domain:.") == 1 then tmp_host = host:gsub("domain:", "") @@ -144,10 +146,11 @@ ip_list.rows = 10 ip_list.wrap = "off" ip_list.validate = function(self, value) local ipmasks= {} - string.gsub(value, '[^' .. "\r\n" .. ']+', function(w) table.insert(ipmasks, w) end) + value = value:gsub("^%s+", ""):gsub("%s+$","\n"):gsub("\r\n","\n"):gsub("[ \t]*\n[ \t]*", "\n") + string.gsub(value, "[^\r\n]+", function(w) table.insert(ipmasks, w) end) for index, ipmask in ipairs(ipmasks) do - if ipmask:find("geoip:") and ipmask:find("geoip:") == 1 then - elseif ipmask:find("ext:") and ipmask:find("ext:") == 1 then + if ipmask:find("geoip:") and ipmask:find("geoip:") == 1 and not ipmask:find("%s") then + elseif ipmask:find("ext:") and ipmask:find("ext:") == 1 and not ipmask:find("%s") then elseif ipmask:find("#") and ipmask:find("#") == 1 then else if not (datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask)) then diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/socks_config.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/socks_config.lua index 8b8fe19cb..09352ed14 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/socks_config.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/socks_config.lua @@ -42,6 +42,9 @@ if auto_switch_tip then socks_node.description = auto_switch_tip end +o = s:option(Flag, "bind_local", translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) +o.default = "0" + local n = 1 uci:foreach(appname, "socks", function(s) if s[".name"] == section then diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua index 803a38bc2..3fcad8cce 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua @@ -27,6 +27,7 @@ local header_type_list = { "none", "srtp", "utp", "wechat-video", "dtls", "wireguard" } +local xray_version = api.get_app_version("xray") -- [[ Xray ]] s.fields["type"]:value(type_name, "Xray") @@ -106,11 +107,13 @@ o:value("leastPing") o.default = "leastPing" -- Fallback Node -if api.compare_versions(api.get_app_version("xray"), ">=", "1.8.10") then +if api.compare_versions(xray_version, ">=", "1.8.10") then local o = s:option(ListValue, option_name("fallback_node"), translate("Fallback Node")) - o:depends({ [option_name("balancingStrategy")] = "leastPing" }) - o:value("",translate("Null")) - o.default = "" + if api.compare_versions(xray_version, ">=", "1.8.12") then + o:depends({ [option_name("protocol")] = "_balancing" }) + else + o:depends({ [option_name("balancingStrategy")] = "leastPing" }) + end local function check_fallback_chain(fb) for k, v in pairs(fallback_table) do if v.fallback == fb then @@ -128,19 +131,34 @@ if api.compare_versions(api.get_app_version("xray"), ">=", "1.8.10") then end -- 探测地址 -local o = s:option(Flag, option_name("useCustomProbeUrl"), translate("Use Custome Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL.")) -o:depends({ [option_name("balancingStrategy")] = "leastPing" }) +local ucpu = s:option(Flag, option_name("useCustomProbeUrl"), translate("Use Custome Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL.")) +ucpu:depends({ [option_name("balancingStrategy")] = "leastPing" }) -local o = s:option(Value, option_name("probeUrl"), translate("Probe URL")) -o:depends({ [option_name("useCustomProbeUrl")] = true }) -o.default = "https://www.google.com/generate_204" -o.description = translate("The URL used to detect the connection status.") +local pu = s:option(Value, option_name("probeUrl"), translate("Probe URL")) +pu:depends({ [option_name("useCustomProbeUrl")] = true }) +pu:value("https://cp.cloudflare.com/", "Cloudflare") +pu:value("https://www.gstatic.com/generate_204", "Gstatic") +pu:value("https://www.google.com/generate_204", "Google") +pu:value("https://www.youtube.com/generate_204", "YouTube") +pu:value("https://connect.rom.miui.com/generate_204", "MIUI (CN)") +pu:value("https://connectivitycheck.platform.hicloud.com/generate_204", "HiCloud (CN)") +pu.default = "https://www.google.com/generate_204" +pu.description = translate("The URL used to detect the connection status.") -- 探测间隔 -local o = s:option(Value, option_name("probeInterval"), translate("Probe Interval")) -o:depends({ [option_name("balancingStrategy")] = "leastPing" }) -o.default = "1m" -o.description = translate("The interval between initiating probes. Every time this time elapses, a server status check is performed on a server. The time format is numbers + units, such as '10s', '2h45m', and the supported time units are ns, us, ms, s, m, h, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively.") +local pi = s:option(Value, option_name("probeInterval"), translate("Probe Interval")) +pi:depends({ [option_name("balancingStrategy")] = "leastPing" }) +pi.default = "1m" +pi.description = translate("The interval between initiating probes. Every time this time elapses, a server status check is performed on a server. The time format is numbers + units, such as '10s', '2h45m', and the supported time units are ns, us, ms, s, m, h, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively.") + +if api.compare_versions(xray_version, ">=", "1.8.12") then + ucpu:depends({ [option_name("protocol")] = "_balancing" }) + pi:depends({ [option_name("protocol")] = "_balancing" }) +else + ucpu:depends({ [option_name("balancingStrategy")] = "leastPing" }) + pi:depends({ [option_name("balancingStrategy")] = "leastPing" }) +end + -- [[ 分流模块 ]] if #nodes_table > 0 then @@ -323,7 +341,10 @@ o:depends({ [option_name("tls")] = true, [option_name("transport")] = "grpc" }) o = s:option(ListValue, option_name("alpn"), translate("alpn")) o.default = "default" o:value("default", translate("Default")) +o:value("h3,h2,http/1.1") +o:value("h3,h2") o:value("h2,http/1.1") +o:value("h3") o:value("h2") o:value("http/1.1") o:depends({ [option_name("tls")] = true, [option_name("reality")] = false }) @@ -379,6 +400,7 @@ o:value("ds", "DomainSocket") o:value("quic", "QUIC") o:value("grpc", "gRPC") o:value("httpupgrade", "HttpUpgrade") +o:value("splithttp", "SplitHTTP") o:depends({ [option_name("protocol")] = "vmess" }) o:depends({ [option_name("protocol")] = "vless" }) o:depends({ [option_name("protocol")] = "socks" }) @@ -401,7 +423,7 @@ o = s:option(Value, option_name("wireguard_mtu"), translate("MTU")) o.default = "1420" o:depends({ [option_name("protocol")] = "wireguard" }) -if api.compare_versions(api.get_app_version("xray"), ">=", "1.8.0") then +if api.compare_versions(xray_version, ">=", "1.8.0") then o = s:option(Value, option_name("wireguard_reserved"), translate("Reserved"), translate("Decimal numbers separated by \",\" or Base64-encoded strings.")) o:depends({ [option_name("protocol")] = "wireguard" }) end @@ -544,6 +566,14 @@ o = s:option(Value, option_name("httpupgrade_path"), translate("HttpUpgrade Path o.placeholder = "/" o:depends({ [option_name("transport")] = "httpupgrade" }) +-- [[ SplitHTTP部分 ]]-- +o = s:option(Value, option_name("splithttp_host"), translate("SplitHTTP Host")) +o:depends({ [option_name("transport")] = "splithttp" }) + +o = s:option(Value, option_name("splithttp_path"), translate("SplitHTTP Path")) +o.placeholder = "/" +o:depends({ [option_name("transport")] = "splithttp" }) + -- [[ Mux ]]-- o = s:option(Flag, option_name("mux"), translate("Mux")) o:depends({ [option_name("protocol")] = "vmess" }) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua index 1f352ad92..bf11e18ec 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua @@ -154,7 +154,10 @@ o:depends({ [option_name("reality")] = true }) o = s:option(ListValue, option_name("alpn"), translate("alpn")) o.default = "h2,http/1.1" +o:value("h3,h2,http/1.1") +o:value("h3,h2") o:value("h2,http/1.1") +o:value("h3") o:value("h2") o:value("http/1.1") o:depends({ [option_name("tls")] = true }) @@ -165,7 +168,6 @@ o:depends({ [option_name("tls")] = true }) --o:depends({ [option_name("tls")] = true }) -- [[ TLS部分 ]] -- - o = s:option(FileUpload, option_name("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem") o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem" o:depends({ [option_name("tls")] = true, [option_name("reality")] = false }) @@ -203,6 +205,7 @@ o:value("ds", "DomainSocket") o:value("quic", "QUIC") o:value("grpc", "gRPC") o:value("httpupgrade", "HttpUpgrade") +o:value("splithttp", "SplitHTTP") o:depends({ [option_name("protocol")] = "vmess" }) o:depends({ [option_name("protocol")] = "vless" }) o:depends({ [option_name("protocol")] = "socks" }) @@ -210,7 +213,6 @@ o:depends({ [option_name("protocol")] = "shadowsocks" }) o:depends({ [option_name("protocol")] = "trojan" }) -- [[ WebSocket部分 ]]-- - o = s:option(Value, option_name("ws_host"), translate("WebSocket Host")) o:depends({ [option_name("transport")] = "ws" }) @@ -226,13 +228,28 @@ o.placeholder = "/" o:depends({ [option_name("transport")] = "httpupgrade" }) -- [[ HTTP/2部分 ]]-- - o = s:option(Value, option_name("h2_host"), translate("HTTP/2 Host")) o:depends({ [option_name("transport")] = "h2" }) o = s:option(Value, option_name("h2_path"), translate("HTTP/2 Path")) o:depends({ [option_name("transport")] = "h2" }) +-- [[ SplitHTTP部分 ]]-- +o = s:option(Value, option_name("splithttp_host"), translate("SplitHTTP Host")) +o:depends({ [option_name("transport")] = "splithttp" }) + +o = s:option(Value, option_name("splithttp_path"), translate("SplitHTTP Path")) +o.placeholder = "/" +o:depends({ [option_name("transport")] = "splithttp" }) + +o = s:option(Value, option_name("splithttp_maxuploadsize"), translate("maxUploadSize")) +o.default = "1000000" +o:depends({ [option_name("transport")] = "splithttp" }) + +o = s:option(Value, option_name("splithttp_maxconcurrentuploads"), translate("maxConcurrentUploads")) +o.default = "10" +o:depends({ [option_name("transport")] = "splithttp" }) + -- [[ TCP部分 ]]-- -- TCP伪装 @@ -250,7 +267,6 @@ o = s:option(DynamicList, option_name("tcp_guise_http_path"), translate("HTTP Pa o:depends({ [option_name("tcp_guise")] = "http" }) -- [[ mKCP部分 ]]-- - o = s:option(ListValue, option_name("mkcp_guise"), translate("Camouflage Type"), translate('
none: default, no masquerade, data sent is packets with no characteristics.
srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).
utp: packets disguised as uTP will be recognized as bittorrent downloaded data.
wechat-video: packets disguised as WeChat video calls.
dtls: disguised as DTLS 1.2 packet.
wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)')) for a, t in ipairs(header_type_list) do o:value(t) end o:depends({ [option_name("transport")] = "mkcp" }) @@ -286,7 +302,6 @@ o = s:option(Value, option_name("mkcp_seed"), translate("KCP Seed")) o:depends({ [option_name("transport")] = "mkcp" }) -- [[ DomainSocket部分 ]]-- - o = s:option(Value, option_name("ds_path"), "Path", translate("A legal file path. This file must not exist before running.")) o:depends({ [option_name("transport")] = "ds" }) @@ -334,7 +349,7 @@ o:depends({ [option_name("fallback")] = true }) o = s:option(DynamicList, option_name("fallback_list"), "Fallback", translate("dest,path")) o:depends({ [option_name("fallback")] = true }) -o = s:option(Flag, option_name("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed locally, It is recommended to turn on when using reverse proxies or be fallback.")) +o = s:option(Flag, option_name("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) o.default = "0" o = s:option(Flag, option_name("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!")) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua index 1f520c6a4..2169a99c8 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua @@ -365,7 +365,7 @@ o = s:option(Value, option_name("tcpbrutal_down_mbps"), translate("Max download o.default = "50" o:depends({ [option_name("tcpbrutal")] = true }) -o = s:option(Flag, option_name("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed locally, It is recommended to turn on when using reverse proxies or be fallback.")) +o = s:option(Flag, option_name("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) o.default = "0" o = s:option(Flag, option_name("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!")) diff --git a/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/luci-app-passwall2/luasrc/passwall2/util_xray.lua index fff4b05ba..c7ceb105a 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -202,6 +202,10 @@ function gen_outbound(flag, node, tag, proxy_table) path = node.httpupgrade_path or "/", host = node.httpupgrade_host } or nil, + splithttpSettings = (node.transport == "splithttp") and { + path = node.splithttp_path or "/", + host = node.splithttp_host + } or nil, } or nil, settings = { vnext = (node.protocol == "vmess" or node.protocol == "vless") and { @@ -477,6 +481,12 @@ function gen_config_server(node) path = node.httpupgrade_path or "/", host = node.httpupgrade_host } or nil, + splithttpSettings = (node.transport == "splithttp") and { + path = node.splithttp_path or "/", + host = node.splithttp_host, + maxUploadSize = node.splithttp_maxuploadsize, + maxConcurrentUploads = node.splithttp_maxconcurrentuploads + } or nil, sockopt = { acceptProxyProtocol = (node.acceptProxyProtocol and node.acceptProxyProtocol == "1") and true or false } @@ -623,11 +633,11 @@ function gen_config(var) settings = {network = "tcp,udp", followRedirect = true}, streamSettings = {sockopt = {tproxy = "tproxy"}}, sniffing = { - enabled = xray_settings.sniffing == "1" and true or false, + enabled = xray_settings.sniffing_override_dest == "1" or node.protocol == "_shunt", destOverride = {"http", "tls", "quic", (remote_dns_fake) and "fakedns"}, metadataOnly = false, - routeOnly = (xray_settings.sniffing == "1" and xray_settings.route_only == "1") and true or nil, - domainsExcluded = (xray_settings.sniffing == "1" and xray_settings.route_only == "0") and get_domain_excluded() or nil + 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 } } local tcp_inbound = api.clone(inbound) @@ -682,9 +692,7 @@ function gen_config(var) end end end - if fallback_node_id == "" then - fallback_node_id = nil - end + if fallback_node_id == "" then fallback_node_id = nil end if fallback_node_id then local is_new_node = true for _, outbound in ipairs(outbounds) do @@ -720,7 +728,7 @@ function gen_config(var) fallbackTag = fallback_node_id, strategy = { type = _node.balancingStrategy or "random" } }) - if _node.balancingStrategy == "leastPing" then + if _node.balancingStrategy == "leastPing" or fallback_node_id then if not observatory then observatory = { subjectSelector = { "blc-" }, @@ -962,6 +970,7 @@ function gen_config(var) if outboundTag and outboundTag ~= "nil" then table.insert(dns_domain_rules, api.clone(domain_table)) end + if #domains == 0 then domains = nil end end local ip = nil if e.ip_list then @@ -970,6 +979,7 @@ function gen_config(var) if w:find("#") == 1 then return end table.insert(ip, w) end) + if #ip == 0 then ip = nil end end local source = nil if e.source then diff --git a/luci-app-passwall2/po/zh-cn/passwall2.po b/luci-app-passwall2/po/zh-cn/passwall2.po index 82446882e..47d50158e 100644 --- a/luci-app-passwall2/po/zh-cn/passwall2.po +++ b/luci-app-passwall2/po/zh-cn/passwall2.po @@ -640,12 +640,6 @@ msgstr "劫持ICMPv6 (IPv6 PING)" msgid "Sniffing" msgstr "流量嗅探" -msgid "When using the shunt, must be enabled, otherwise the shunt will invalid." -msgstr "使用分流时,必须启用,否则分流将无效。" - -msgid "Sniffing Route Only" -msgstr "流量嗅探只供路由使用" - msgid "TCP Proxy Way" msgstr "TCP代理方式" @@ -775,23 +769,44 @@ msgstr "手动更新" msgid "Enable auto update rules" msgstr "开启自动更新规则" -msgid "Week update rules" -msgstr "更新时间星期" +msgid "Update Time(every day)" +msgstr "更新时间(每天)" -msgid "Day update rules" -msgstr "更新时间小时" +msgid "Update Interval(hour)" +msgstr "更新间隔(小时)" + +msgid "Update Mode" +msgstr "更新模式" + +msgid "Loop Mode" +msgstr "循环" msgid "Every day" msgstr "每天" -msgid "day" -msgstr "日" +msgid "Every Monday" +msgstr "每周一" -msgid "Week" -msgstr "周" +msgid "Every Tuesday" +msgstr "每周二" -msgid "oclock" -msgstr "点" +msgid "Every Wednesday" +msgstr "每周三" + +msgid "Every Thursday" +msgstr "每周四" + +msgid "Every Friday" +msgstr "每周五" + +msgid "Every Saturday" +msgstr "每周六" + +msgid "Every Sunday" +msgstr "每周日" + +msgid "hour" +msgstr "小时" msgid "Location of V2ray/Xray asset" msgstr "V2ray/Xray 资源文件目录" @@ -1243,8 +1258,8 @@ msgstr "接口" msgid "Bind Local" msgstr "本机监听" -msgid "When selected, it can only be accessed locally, It is recommended to turn on when using reverse proxies or be fallback." -msgstr "当勾选时,只能由本机访问此端口,当想被反向代理或被回落时建议勾选此项。" +msgid "When selected, it can only be accessed localhost." +msgstr "当勾选时,只能本机访问。" msgid "Accept LAN Access" msgstr "接受局域网访问" @@ -1390,11 +1405,11 @@ msgstr "无子连接时的健康检查" msgid "Initial Windows Size" msgstr "初始窗口大小" -msgid "No Sniffing Lists" -msgstr "不进行流量嗅探的域名列表" +msgid "Excluded Domains" +msgstr "排除域名" -msgid "Hosts added into No Sniffing Lists will not resolve again on server." -msgstr "加入的域名不会再次在服务器解析。" +msgid "If the traffic sniffing result is in this list, the destination address will not be overridden." +msgstr "如果流量嗅探结果在此列表中,则不会覆盖目标地址。" msgid "Buffer Size" msgstr "缓冲区大小" diff --git a/luci-app-passwall2/root/etc/uci-defaults/luci-passwall2 b/luci-app-passwall2/root/etc/uci-defaults/luci-passwall2 index 6ec65ccd3..cb52b9cc3 100755 --- a/luci-app-passwall2/root/etc/uci-defaults/luci-passwall2 +++ b/luci-app-passwall2/root/etc/uci-defaults/luci-passwall2 @@ -31,11 +31,17 @@ uci -q batch <<-EOF >/dev/null commit uhttpd EOF -touch /etc/config/passwall2_show >/dev/null 2>&1 [ ! -s "/etc/config/passwall2" ] && cp -f /usr/share/passwall2/0_default_config /etc/config/passwall2 chmod +x /usr/share/passwall2/*.sh +[ -e "/etc/config/passwall2_show" ] && rm -rf /etc/config/passwall2_show + +[ "$(uci -q get passwall2.@global_xray[0].sniffing)" == "1" ] && [ "$(uci -q get passwall2.@global_xray[0].route_only)" != "1" ] && uci -q set passwall2.@global_xray[0].sniffing_override_dest=1 +uci -q delete passwall2.@global_xray[0].sniffing +uci -q delete passwall2.@global_xray[0].route_only +uci -q commit passwall2 + rm -f /tmp/luci-indexcache rm -rf /tmp/luci-modulecache/ killall -HUP rpcd 2>/dev/null diff --git a/luci-app-passwall2/root/usr/share/passwall2/0_default_config b/luci-app-passwall2/root/usr/share/passwall2/0_default_config index f129cc36b..5f5b8d049 100644 --- a/luci-app-passwall2/root/usr/share/passwall2/0_default_config +++ b/luci-app-passwall2/root/usr/share/passwall2/0_default_config @@ -36,8 +36,7 @@ config global_forwarding option ipv6_tproxy '0' config global_xray - option sniffing '1' - option route_only '0' + option sniffing_override_dest '0' config global_other option auto_detection_time 'tcping' diff --git a/luci-app-passwall2/root/usr/share/passwall2/app.sh b/luci-app-passwall2/root/usr/share/passwall2/app.sh index 22aa7b41c..92c98d128 100644 --- a/luci-app-passwall2/root/usr/share/passwall2/app.sh +++ b/luci-app-passwall2/root/usr/share/passwall2/app.sh @@ -202,14 +202,15 @@ check_port_exists() { } check_depends() { + local depends local tables=${1} if [ "$tables" == "iptables" ]; then for depends in "iptables-mod-tproxy" "iptables-mod-socket" "iptables-mod-iprange" "iptables-mod-conntrack-extra" "kmod-ipt-nat"; do - [ -z "$(opkg status ${depends} 2>/dev/null | grep 'Status' | awk -F ': ' '{print $2}' 2>/dev/null)" ] && echolog "$tables透明代理基础依赖 $depends 未安装..." + [ -s "/usr/lib/opkg/info/${depends}.control" ] || echolog "$tables透明代理基础依赖 $depends 未安装..." done else for depends in "kmod-nft-socket" "kmod-nft-tproxy" "kmod-nft-nat"; do - [ -z "$(opkg status ${depends} 2>/dev/null | grep 'Status' | awk -F ': ' '{print $2}' 2>/dev/null)" ] && echolog "$tables透明代理基础依赖 $depends 未安装..." + [ -s "/usr/lib/opkg/info/${depends}.control" ] || echolog "$tables透明代理基础依赖 $depends 未安装..." done fi } @@ -540,7 +541,7 @@ run_socks() { [ "$http_port" != "0" ] && { http_flag=1 config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") - local _extra_param="-local_http_port $http_port" + local _extra_param="-local_http_address $bind -local_http_port $http_port" } [ -n "$relay_port" ] && _extra_param="${_extra_param} -server_host $server_host -server_port $port" [ "${log_file}" != "/dev/null" ] && { @@ -548,17 +549,17 @@ run_socks() { [ "$loglevel" = "warning" ] && loglevel="warn" _extra_param="${_extra_param} -log 1 -loglevel $loglevel -logfile $log_file" } - lua $UTIL_SINGBOX gen_config -flag SOCKS_$flag -node $node -local_socks_port $socks_port ${_extra_param} > $config_file + lua $UTIL_SINGBOX gen_config -flag SOCKS_$flag -node $node -local_socks_address $bind -local_socks_port $socks_port ${_extra_param} > $config_file ln_run "$(first_type $(config_t_get global_app singbox_file) sing-box)" "sing-box" /dev/null run -c "$config_file" ;; xray) [ "$http_port" != "0" ] && { http_flag=1 config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") - local _extra_param="-local_http_port $http_port" + local _extra_param="-local_http_address $bind -local_http_port $http_port" } [ -n "$relay_port" ] && _extra_param="${_extra_param} -server_host $server_host -server_port $port" - lua $UTIL_XRAY gen_config -flag SOCKS_$flag -node $node -local_socks_port $socks_port ${_extra_param} > $config_file + lua $UTIL_XRAY gen_config -flag SOCKS_$flag -node $node -local_socks_address $bind -local_socks_port $socks_port ${_extra_param} > $config_file ln_run "$(first_type $(config_t_get global_app xray_file) xray)" "xray" $log_file run -c "$config_file" ;; naiveproxy) @@ -566,29 +567,29 @@ run_socks() { ln_run "$(first_type naive)" naive $log_file "$config_file" ;; ssr) - lua $UTIL_SS gen_config -node $node -local_addr "0.0.0.0" -local_port $socks_port -server_host $server_host -server_port $port > $config_file + lua $UTIL_SS gen_config -node $node -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $port > $config_file ln_run "$(first_type ssr-local)" "ssr-local" $log_file -c "$config_file" -v -u ;; ss) - lua $UTIL_SS gen_config -node $node -local_addr "0.0.0.0" -local_port $socks_port -server_host $server_host -server_port $port -mode tcp_and_udp > $config_file + lua $UTIL_SS gen_config -node $node -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $port -mode tcp_and_udp > $config_file ln_run "$(first_type ss-local)" "ss-local" $log_file -c "$config_file" -v ;; ss-rust) [ "$http_port" != "0" ] && { http_flag=1 config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") - local _extra_param="-local_http_port $http_port" + local _extra_param="-local_http_address $bind -local_http_port $http_port" } - lua $UTIL_SS gen_config -node $node -local_socks_port $socks_port -server_host $server_host -server_port $port ${_extra_param} > $config_file + lua $UTIL_SS gen_config -node $node -local_socks_address $bind -local_socks_port $socks_port -server_host $server_host -server_port $port ${_extra_param} > $config_file ln_run "$(first_type sslocal)" "sslocal" $log_file -c "$config_file" -v ;; hysteria2) [ "$http_port" != "0" ] && { http_flag=1 config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") - local _extra_param="-local_http_port $http_port" + local _extra_param="-local_http_address $bind -local_http_port $http_port" } - lua $UTIL_HYSTERIA2 gen_config -node $node -local_socks_port $socks_port -server_host $server_host -server_port $port ${_extra_param} > $config_file + lua $UTIL_HYSTERIA2 gen_config -node $node -local_socks_address $bind -local_socks_port $socks_port -server_host $server_host -server_port $port ${_extra_param} > $config_file ln_run "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client ;; tuic) @@ -627,6 +628,9 @@ socks_node_switch() { cmd=$(cat ${TMP_SCRIPT_FUNC_PATH}/${filename}) [ -n "$(echo $cmd | grep "${flag}")" ] && rm -f ${TMP_SCRIPT_FUNC_PATH}/${filename} done + local bind_local=$(config_n_get $flag bind_local 0) + local bind="0.0.0.0" + [ "$bind_local" = "1" ] && bind="127.0.0.1" local port=$(config_n_get $flag port) local config_file="SOCKS_${flag}.json" local log_file="SOCKS_${flag}.log" @@ -635,7 +639,7 @@ socks_node_switch() { local http_port=$(config_n_get $flag http_port 0) local http_config_file="HTTP2SOCKS_${flag}.json" LOG_FILE="/dev/null" - run_socks flag=$flag node=$new_node bind=0.0.0.0 socks_port=$port config_file=$config_file http_port=$http_port http_config_file=$http_config_file log_file=$log_file + 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} } } @@ -692,7 +696,10 @@ run_global() { V2RAY_ARGS="${V2RAY_ARGS} log_file=${V2RAY_LOG} config_file=${V2RAY_CONFIG}" node_socks_port=$(config_t_get global node_socks_port 1070) - V2RAY_ARGS="${V2RAY_ARGS} socks_port=${node_socks_port}" + node_socks_bind_local=$(config_t_get global node_socks_bind_local 1) + node_socks_bind="127.0.0.1" + [ "${node_socks_bind_local}" != "1" ] && node_socks_bind="0.0.0.0" + V2RAY_ARGS="${V2RAY_ARGS} socks_address=${node_socks_bind} socks_port=${node_socks_port}" echo "127.0.0.1:$node_socks_port" > $TMP_ACL_PATH/default/SOCKS_server node_http_port=$(config_t_get global node_http_port 0) @@ -722,6 +729,9 @@ start_socks() { [ "$enabled" == "0" ] && continue local node=$(config_n_get $id node nil) [ "$node" == "nil" ] && continue + local bind_local=$(config_n_get $id bind_local 0) + local bind="0.0.0.0" + [ "$bind_local" = "1" ] && bind="127.0.0.1" local port=$(config_n_get $id port) local config_file="SOCKS_${id}.json" local log_file="SOCKS_${id}.log" @@ -729,7 +739,7 @@ start_socks() { [ "$log" == "0" ] && log_file="" local http_port=$(config_n_get $id http_port 0) local http_config_file="HTTP2SOCKS_${id}.json" - run_socks flag=$id node=$node bind=0.0.0.0 socks_port=$port config_file=$config_file http_port=$http_port http_config_file=$http_config_file log_file=$log_file + 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} #自动切换逻辑 @@ -749,19 +759,36 @@ clean_log() { } clean_crontab() { + [ -f "/tmp/lock/${CONFIG}_cron.lock" ] && return touch /etc/crontabs/root #sed -i "/${CONFIG}/d" /etc/crontabs/root >/dev/null 2>&1 sed -i "/$(echo "/etc/init.d/${CONFIG}" | sed 's#\/#\\\/#g')/d" /etc/crontabs/root >/dev/null 2>&1 sed -i "/$(echo "lua ${APP_PATH}/rule_update.lua log" | sed 's#\/#\\\/#g')/d" /etc/crontabs/root >/dev/null 2>&1 sed -i "/$(echo "lua ${APP_PATH}/subscribe.lua start" | sed 's#\/#\\\/#g')/d" /etc/crontabs/root >/dev/null 2>&1 + + pgrep -af "${CONFIG}/" | awk '/tasks\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1 + rm -rf /tmp/lock/${CONFIG}_tasks.lock } start_crontab() { + if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then + start_daemon=$(config_t_get global_delay start_daemon 0) + [ "$start_daemon" = "1" ] && $APP_PATH/monitor.sh > /dev/null 2>&1 & + fi + + [ -f "/tmp/lock/${CONFIG}_cron.lock" ] && { + rm -rf "/tmp/lock/${CONFIG}_cron.lock" + echolog "当前为计划任务自动运行,不重新配置定时任务。" + return + } + clean_crontab + [ "$ENABLED" != 1 ] && { /etc/init.d/cron restart return } + auto_on=$(config_t_get global_delay auto_on 0) if [ "$auto_on" = "1" ]; then time_off=$(config_t_get global_delay time_off) @@ -787,7 +814,11 @@ start_crontab() { if [ "$autoupdate" = "1" ]; then local t="0 $dayupdate * * $weekupdate" [ "$weekupdate" = "7" ] && t="0 $dayupdate * * *" - echo "$t lua $APP_PATH/rule_update.lua log > /dev/null 2>&1 &" >>/etc/crontabs/root + if [ "$weekupdate" = "8" ]; then + update_loop=1 + else + echo "$t lua $APP_PATH/rule_update.lua log all cron > /dev/null 2>&1 &" >>/etc/crontabs/root + fi echolog "配置定时任务:自动更新规则。" fi @@ -808,17 +839,23 @@ start_crontab() { for name in $(ls ${TMP_SUB_PATH}); do week_update=$(echo $name | awk -F '_' '{print $1}') time_update=$(echo $name | awk -F '_' '{print $2}') + cfgids=$(echo -n $(cat ${TMP_SUB_PATH}/${name}) | sed 's# #,#g') local t="0 $time_update * * $week_update" [ "$week_update" = "7" ] && t="0 $time_update * * *" - cfgids=$(echo -n $(cat ${TMP_SUB_PATH}/${name}) | sed 's# #,#g') - echo "$t lua $APP_PATH/subscribe.lua start $cfgids > /dev/null 2>&1 &" >>/etc/crontabs/root + if [ "$week_update" = "8" ]; then + update_loop=1 + else + echo "$t lua $APP_PATH/subscribe.lua start $cfgids cron > /dev/null 2>&1 &" >>/etc/crontabs/root + fi done rm -rf $TMP_SUB_PATH } if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then - start_daemon=$(config_t_get global_delay start_daemon 0) - [ "$start_daemon" = "1" ] && $APP_PATH/monitor.sh > /dev/null 2>&1 & + [ "$update_loop" = "1" ] && { + $APP_PATH/tasks.sh > /dev/null 2>&1 & + echolog "自动更新:启动循环更新进程。" + } else echolog "运行于非代理模式,仅允许服务启停的定时任务。" fi @@ -827,6 +864,7 @@ start_crontab() { } stop_crontab() { + [ -f "/tmp/lock/${CONFIG}_cron.lock" ] && return clean_crontab /etc/init.d/cron restart #echolog "清除定时执行命令。" @@ -1075,7 +1113,7 @@ stop() { delete_ip2route kill_all v2ray-plugin obfs-local pgrep -f "sleep.*(6s|9s|58s)" | xargs kill -9 >/dev/null 2>&1 - pgrep -af "${CONFIG}/" | awk '! /app\.sh|subscribe\.lua|rule_update\.lua/{print $1}' | xargs kill -9 >/dev/null 2>&1 + pgrep -af "${CONFIG}/" | awk '! /app\.sh|subscribe\.lua|rule_update\.lua|tasks\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1 unset V2RAY_LOCATION_ASSET unset XRAY_LOCATION_ASSET stop_crontab diff --git a/luci-app-passwall2/root/usr/share/passwall2/haproxy.lua b/luci-app-passwall2/root/usr/share/passwall2/haproxy.lua index 59fb75202..6eb3fd673 100644 --- a/luci-app-passwall2/root/usr/share/passwall2/haproxy.lua +++ b/luci-app-passwall2/root/usr/share/passwall2/haproxy.lua @@ -35,6 +35,9 @@ local haproxy_dns = var["-dns"] or "119.29.29.29:53,223.5.5.5:53" local cpu_thread = sys.exec('echo -n $(cat /proc/cpuinfo | grep "processor" | wc -l)') or "1" local health_check_type = uci:get(appname, "@global_haproxy[0]", "health_check_type") or "tcp" local health_check_inter = uci:get(appname, "@global_haproxy[0]", "health_check_inter") or "10" +local bind_local = uci:get(appname, "@global_haproxy[0]", "bind_local") or "0" +local bind_address = "0.0.0.0" +if bind_local == "1" then bind_address = "127.0.0.1" end log("HAPROXY 负载均衡...") fs.mkdir(haproxy_path) @@ -159,14 +162,14 @@ end table.sort(sortTable, function(a,b) return (a < b) end) for i, port in pairs(sortTable) do - log(" + 入口 0.0.0.0:%s..." % port) + log(" + 入口 %s:%s" % {bind_address, port}) f_out:write("\n" .. string.format([[ listen %s - bind 0.0.0.0:%s + bind %s:%s mode tcp balance roundrobin -]], port, port)) +]], port, bind_address, port)) if health_check_type == "passwall_logic" then f_out:write(string.format([[ diff --git a/luci-app-passwall2/root/usr/share/passwall2/nftables.sh b/luci-app-passwall2/root/usr/share/passwall2/nftables.sh index 7242b7071..18e518938 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/nftables.sh +++ b/luci-app-passwall2/root/usr/share/passwall2/nftables.sh @@ -724,7 +724,8 @@ add_firewall_rule() { WAN_IP=$(get_wan_ip) if [ -n "${WAN_IP}" ]; then - [ -n "${is_tproxy}" ] && nft "add rule inet fw4 PSW2_MANGLE ip daddr ${WAN_IP} counter return comment \"WAN_IP_RETURN\"" || nft "add rule inet fw4 PSW2_NAT ip daddr ${WAN_IP} counter return comment \"WAN_IP_RETURN\"" + nft "add rule inet fw4 PSW2_MANGLE ip daddr ${WAN_IP} counter return comment \"WAN_IP_RETURN\"" + [ -z "${is_tproxy}" ] && nft "add rule inet fw4 PSW2_NAT ip daddr ${WAN_IP} counter return comment \"WAN_IP_RETURN\"" fi unset WAN_IP diff --git a/luci-app-passwall2/root/usr/share/passwall2/rule_update.lua b/luci-app-passwall2/root/usr/share/passwall2/rule_update.lua index 953c18f59..60e55fdc1 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/rule_update.lua +++ b/luci-app-passwall2/root/usr/share/passwall2/rule_update.lua @@ -8,6 +8,8 @@ local jsonc = require "luci.jsonc" local name = 'passwall2' local api = require "luci.passwall2.api" local arg1 = arg[1] +local arg2 = arg[2] +local arg3 = arg[3] local reboot = 0 local geoip_update = 0 @@ -20,6 +22,10 @@ local geosite_api = ucic:get_first(name, 'global_rules', "geosite_url", "https:/ -- local use_nft = ucic:get(name, "@global_forwarding[0]", "use_nft") or "0" +if arg3 == "cron" then + arg2 = nil +end + local log = function(...) if arg1 then if arg1 == "log" then @@ -145,8 +151,8 @@ local function fetch_geosite() return 0 end -if arg[2] then - string.gsub(arg[2], '[^' .. "," .. ']+', function(w) +if arg2 then + string.gsub(arg2, '[^' .. "," .. ']+', function(w) if w == "geoip" then geoip_update = 1 end @@ -184,6 +190,12 @@ ucic:save(name) luci.sys.call("uci commit " .. name) if reboot == 1 then + if arg3 == "cron" then + if not nixio.fs.access("/var/lock/" .. name .. ".lock") then + luci.sys.call("touch /tmp/lock/" .. name .. "_cron.lock") + end + end + log("重启服务,应用新的规则。") if use_nft == "1" then luci.sys.call("sh /usr/share/" .. name .. "/nftables.sh flush_nftset_reload > /dev/null 2>&1 &") diff --git a/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua b/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua index 6c6a5cdf7..1fd64fa08 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua +++ b/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua @@ -816,7 +816,7 @@ local function processData(szType, content, add_mode, add_from) end result.remarks = UrlDecode(alias) - local dat = split(content, '%?') + local dat = split(content:gsub("/%?", "?"), '%?') local host_port = dat[1] local params = {} for _, v in pairs(split(dat[2], '&')) do @@ -1157,6 +1157,13 @@ local function update_node(manual) uci:commit(appname) end + + if arg[3] == "cron" then + if not nixio.fs.access("/var/lock/" .. appname .. ".lock") then + luci.sys.call("touch /tmp/lock/" .. appname .. "_cron.lock") + end + end + luci.sys.call("/etc/init.d/" .. appname .. " restart > /dev/null 2>&1 &") end diff --git a/luci-app-passwall2/root/usr/share/passwall2/tasks.sh b/luci-app-passwall2/root/usr/share/passwall2/tasks.sh new file mode 100755 index 000000000..c8d915abe --- /dev/null +++ b/luci-app-passwall2/root/usr/share/passwall2/tasks.sh @@ -0,0 +1,75 @@ +#!/bin/sh + +## 循环更新脚本 + +CONFIG=passwall2 +APP_PATH=/usr/share/$CONFIG +TMP_PATH=/tmp/etc/$CONFIG +LOCK_FILE=/tmp/lock/${CONFIG}_tasks.lock +CFG_UPDATE_INT=0 + +config_n_get() { + local ret=$(uci -q get "${CONFIG}.${1}.${2}" 2>/dev/null) + echo "${ret:=$3}" +} + +config_t_get() { + local index=${4:-0} + local ret=$(uci -q get "${CONFIG}.@${1}[${index}].${2}" 2>/dev/null) + echo "${ret:=${3}}" +} + +exec 99>"$LOCK_FILE" +flock -n 99 +if [ "$?" != 0 ]; then + exit 0 +fi + +while true +do + + if [ "$CFG_UPDATE_INT" -ne 0 ]; then + + autoupdate=$(config_t_get global_rules auto_update) + weekupdate=$(config_t_get global_rules week_update) + hourupdate=$(config_t_get global_rules interval_update) + hourupdate=$(expr "$hourupdate" \* 60) + if [ "$autoupdate" = "1" ]; then + [ "$weekupdate" = "8" ] && { + [ "$(expr "$CFG_UPDATE_INT" % "$hourupdate")" -eq 0 ] && lua $APP_PATH/rule_update.lua log all cron > /dev/null 2>&1 & + } + fi + + TMP_SUB_PATH=$TMP_PATH/sub_tasks + mkdir -p $TMP_SUB_PATH + for item in $(uci show ${CONFIG} | grep "=subscribe_list" | cut -d '.' -sf 2 | cut -d '=' -sf 1); do + if [ "$(config_n_get $item auto_update 0)" = "1" ]; then + cfgid=$(uci show ${CONFIG}.$item | head -n 1 | cut -d '.' -sf 2 | cut -d '=' -sf 1) + remark=$(config_n_get $item remark) + week_update=$(config_n_get $item week_update) + hour_update=$(config_n_get $item interval_update) + echo "$cfgid" >> $TMP_SUB_PATH/${week_update}_${hour_update} + fi + done + + [ -d "${TMP_SUB_PATH}" ] && { + for name in $(ls ${TMP_SUB_PATH}); do + week_update=$(echo $name | awk -F '_' '{print $1}') + hour_update=$(echo $name | awk -F '_' '{print $2}') + hour_update=$(expr "$hour_update" \* 60) + cfgids=$(echo -n $(cat ${TMP_SUB_PATH}/${name}) | sed 's# #,#g') + [ "$week_update" = "8" ] && { + [ "$(expr "$CFG_UPDATE_INT" % "$hour_update")" -eq 0 ] && lua $APP_PATH/subscribe.lua start $cfgids cron > /dev/null 2>&1 & + } + + done + rm -rf $TMP_SUB_PATH + } + + fi + + CFG_UPDATE_INT=$(expr "$CFG_UPDATE_INT" + 10) + + sleep 600 + +done 2>/dev/null