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