luci-app-passwall2: sync upstream

last commit: 83558f5163
This commit is contained in:
actions 2024-07-18 03:00:09 +08:00
parent 9ed9b3c51f
commit 3e216255a6
23 changed files with 453 additions and 177 deletions

View File

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

View File

@ -2,24 +2,32 @@
module("luci.controller.passwall2", package.seeall) module("luci.controller.passwall2", package.seeall)
local api = require "luci.passwall2.api" local api = require "luci.passwall2.api"
local appname = api.appname local appname = api.appname -- not available
local ucic = luci.model.uci.cursor() local uci = luci.model.uci.cursor() -- in funtion index()
local http = require "luci.http" local http = require "luci.http"
local util = require "luci.util" local util = require "luci.util"
local i18n = require "luci.i18n" local i18n = require "luci.i18n"
function index() 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}).dependent = true
entry({"admin", "services", appname, "reset_config"}, call("reset_config")).leaf = 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, "show"}, call("show_menu")).leaf = true
entry({"admin", "services", appname, "hide"}, call("hide_menu")).leaf = true entry({"admin", "services", appname, "hide"}, call("hide_menu")).leaf = true
if not nixio.fs.access("/etc/config/passwall2") then return end local e
if nixio.fs.access("/etc/config/passwall2_show") then if uci:get(appname, "@global[0]", "hide_from_luci") ~= "1" then
e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), _("PassWall 2"), -1) e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), _("Pass Wall"), -1)
e.dependent = true else
e.acl_depends = { "luci-app-passwall2" } e = entry({"admin", "services", appname}, alias("admin", "services", appname, "settings"), nil, -1)
end end
e.dependent = true
e.acl_depends = { "luci-app-passwall2" }
--[[ Client ]] --[[ Client ]]
entry({"admin", "services", appname, "settings"}, cbi(appname .. "/client/global"), _("Basic Settings"), 1).dependent = true 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 entry({"admin", "services", appname, "node_list"}, cbi(appname .. "/client/node_list"), _("Node List"), 2).dependent = true
@ -88,14 +96,16 @@ function reset_config()
end end
function show_menu() 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("rm -rf /tmp/luci-*")
luci.sys.call("/etc/init.d/rpcd restart >/dev/null") luci.sys.call("/etc/init.d/rpcd restart >/dev/null")
luci.http.redirect(api.url()) luci.http.redirect(api.url())
end end
function hide_menu() 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("rm -rf /tmp/luci-*")
luci.sys.call("/etc/init.d/rpcd restart >/dev/null") luci.sys.call("/etc/init.d/rpcd restart >/dev/null")
luci.http.redirect(luci.dispatcher.build_url("admin", "status", "overview")) 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 id = luci.http.formvalue("id")
local key = luci.http.formvalue("key") local key = luci.http.formvalue("key")
if id and id ~= "" and key and key ~= "" then 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 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) table.remove(new_list, i)
end end
end end
@ -123,8 +133,8 @@ function socks_autoswitch_add_node()
table.insert(new_list, e.id) table.insert(new_list, e.id)
end end
end end
ucic:set_list(appname, id, "autoswitch_backup_node", new_list) uci:set_list(appname, id, "autoswitch_backup_node", new_list)
ucic:commit(appname) uci:commit(appname)
end end
luci.http.redirect(api.url("socks_config", id)) luci.http.redirect(api.url("socks_config", id))
end end
@ -133,14 +143,14 @@ function socks_autoswitch_remove_node()
local id = luci.http.formvalue("id") local id = luci.http.formvalue("id")
local key = luci.http.formvalue("key") local key = luci.http.formvalue("key")
if id and id ~= "" and key and key ~= "" then 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 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) table.remove(new_list, i)
end end
end end
ucic:set_list(appname, id, "autoswitch_backup_node", new_list) uci:set_list(appname, id, "autoswitch_backup_node", new_list)
ucic:commit(appname) uci:commit(appname)
end end
luci.http.redirect(api.url("socks_config", id)) luci.http.redirect(api.url("socks_config", id))
end end
@ -208,7 +218,7 @@ function socks_status()
local id = luci.http.formvalue("id") local id = luci.http.formvalue("id")
e.index = index 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 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 e.use_http = 0
if tonumber(use_http) > 0 then if tonumber(use_http) > 0 then
e.use_http = 1 e.use_http = 1
@ -279,8 +289,8 @@ function set_node()
local type = luci.http.formvalue("type") local type = luci.http.formvalue("type")
local config = luci.http.formvalue("config") local config = luci.http.formvalue("config")
local section = luci.http.formvalue("section") local section = luci.http.formvalue("section")
ucic:set(appname, type, config, section) uci:set(appname, type, config, section)
ucic:commit(appname) uci:commit(appname)
luci.sys.call("/etc/init.d/passwall2 restart > /dev/null 2>&1 &") luci.sys.call("/etc/init.d/passwall2 restart > /dev/null 2>&1 &")
luci.http.redirect(api.url("log")) luci.http.redirect(api.url("log"))
end end
@ -288,76 +298,76 @@ end
function copy_node() function copy_node()
local section = luci.http.formvalue("section") local section = luci.http.formvalue("section")
local uuid = api.gen_short_uuid() local uuid = api.gen_short_uuid()
ucic:section(appname, "nodes", uuid) uci:section(appname, "nodes", uuid)
for k, v in pairs(ucic:get_all(appname, section)) do for k, v in pairs(uci:get_all(appname, section)) do
local filter = k:find("%.") local filter = k:find("%.")
if filter and filter == 1 then if filter and filter == 1 then
else else
xpcall(function() xpcall(function()
ucic:set(appname, uuid, k, v) uci:set(appname, uuid, k, v)
end, end,
function(e) function(e)
end) end)
end end
end end
ucic:delete(appname, uuid, "add_from") uci:delete(appname, uuid, "add_from")
ucic:set(appname, uuid, "add_mode", 1) uci:set(appname, uuid, "add_mode", 1)
ucic:commit(appname) uci:commit(appname)
luci.http.redirect(api.url("node_config", uuid)) luci.http.redirect(api.url("node_config", uuid))
end end
function clear_all_nodes() function clear_all_nodes()
ucic:set(appname, '@global[0]', "enabled", "0") uci:set(appname, '@global[0]', "enabled", "0")
ucic:set(appname, '@global[0]', "node", "nil") uci:set(appname, '@global[0]', "node", "nil")
ucic:foreach(appname, "socks", function(t) uci:foreach(appname, "socks", function(t)
ucic:delete(appname, t[".name"]) uci:delete(appname, t[".name"])
ucic:set_list(appname, t[".name"], "autoswitch_backup_node", {}) uci:set_list(appname, t[".name"], "autoswitch_backup_node", {})
end) end)
ucic:foreach(appname, "haproxy_config", function(t) uci:foreach(appname, "haproxy_config", function(t)
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)
ucic:set(appname, t[".name"], "node", "default") uci:set(appname, t[".name"], "node", "default")
end) end)
ucic:foreach(appname, "nodes", function(node) uci:foreach(appname, "nodes", function(node)
ucic:delete(appname, node['.name']) uci:delete(appname, node['.name'])
end) end)
ucic:commit(appname) uci:commit(appname)
luci.sys.call("/etc/init.d/" .. appname .. " stop") luci.sys.call("/etc/init.d/" .. appname .. " stop")
end end
function delete_select_nodes() function delete_select_nodes()
local ids = luci.http.formvalue("ids") local ids = luci.http.formvalue("ids")
string.gsub(ids, '[^' .. "," .. ']+', function(w) string.gsub(ids, '[^' .. "," .. ']+', function(w)
if (ucic:get(appname, "@global[0]", "node") or "nil") == w then if (uci:get(appname, "@global[0]", "node") or "nil") == w then
ucic:set(appname, '@global[0]', "node", "nil") uci:set(appname, '@global[0]', "node", "nil")
end end
ucic:foreach(appname, "socks", function(t) uci:foreach(appname, "socks", function(t)
if t["node"] == w then if t["node"] == w then
ucic:delete(appname, t[".name"]) uci:delete(appname, t[".name"])
end 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 for i = #auto_switch_node_list, 1, -1 do
if w == auto_switch_node_list[i] then if w == auto_switch_node_list[i] then
table.remove(auto_switch_node_list, i) table.remove(auto_switch_node_list, i)
end end
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) end)
ucic:foreach(appname, "haproxy_config", function(t) uci:foreach(appname, "haproxy_config", function(t)
if t["lbss"] == w then if t["lbss"] == w then
ucic:delete(appname, t[".name"]) uci:delete(appname, t[".name"])
end end
end) end)
ucic:foreach(appname, "acl_rule", function(t) uci:foreach(appname, "acl_rule", function(t)
if t["node"] == w then if t["node"] == w then
ucic:set(appname, t[".name"], "node", "default") uci:set(appname, t[".name"], "node", "default")
end end
end) end)
ucic:delete(appname, w) uci:delete(appname, w)
end) end)
ucic:commit(appname) uci:commit(appname)
luci.sys.call("/etc/init.d/" .. appname .. " restart > /dev/null 2>&1 &") luci.sys.call("/etc/init.d/" .. appname .. " restart > /dev/null 2>&1 &")
end end

View File

@ -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.4.4", "8.8.4.4 (Google)")
o:value("8.8.8.8", "8.8.8.8 (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("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.220.220", "208.67.220.220 (OpenDNS)")
o:value("208.67.222.222", "208.67.222.222 (OpenDNS)") o:value("208.67.222.222", "208.67.222.222 (OpenDNS)")
o:depends("remote_dns_protocol", "tcp") 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://1.1.1.2/dns-query", "CloudFlare-Security")
o:value("https://8.8.4.4/dns-query", "Google 8844") 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://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://208.67.222.222/dns-query", "OpenDNS")
o:value("https://dns.adguard.com/dns-query,176.103.130.130", "AdGuard") 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") o:value("https://doh.libredns.gr/dns-query,116.202.176.26", "LibreDNS")

View File

@ -52,7 +52,7 @@ local doh_validate = function(self, value, t)
for i = 1, #val do for i = 1, #val do
local v = val[i] local v = val[i]
if v then if v then
if not datatypes.ipmask4(v) then if not datatypes.ipmask4(v) and not datatypes.ipmask6(v) then
flag = 1 flag = 1
end end
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.default = 1070
node_socks_port.datatype = "port" 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")) s:tab("DNS", translate("DNS"))
o = s:taboption("DNS", ListValue, "remote_dns_protocol", translate("Remote DNS Protocol")) 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.4.4", "8.8.4.4 (Google)")
o:value("8.8.8.8", "8.8.8.8 (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("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.220.220", "208.67.220.220 (OpenDNS)")
o:value("208.67.222.222", "208.67.222.222 (OpenDNS)") o:value("208.67.222.222", "208.67.222.222 (OpenDNS)")
o:depends("remote_dns_protocol", "tcp") 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://1.1.1.2/dns-query", "CloudFlare-Security")
o:value("https://8.8.4.4/dns-query", "Google 8844") 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://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://208.67.222.222/dns-query", "OpenDNS")
o:value("https://dns.adguard.com/dns-query,176.103.130.130", "AdGuard") 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") o:value("https://doh.libredns.gr/dns-query,116.202.176.26", "LibreDNS")

View File

@ -46,6 +46,9 @@ o = s:option(Value, "console_port", translate("Console Port"), translate(
o.default = "1188" o.default = "1188"
o:depends("balancing_enable", true) 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 ---- Health Check Type
o = s:option(ListValue, "health_check_type", translate("Health Check Type")) o = s:option(ListValue, "health_check_type", translate("Health Check Type"))
o.default = "passwall_logic" o.default = "passwall_logic"

View File

@ -126,25 +126,48 @@ o = s:option(Flag, "auto_update", translate("Enable auto update subscribe"))
o.default = 0 o.default = 0
o.rmempty = false o.rmempty = false
---- Week update rules ---- 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")) o:value(7, translate("Every day"))
for e = 1, 6 do o:value(e, translate("Week") .. e) end o:value(1, translate("Every Monday"))
o:value(0, translate("Week") .. translate("day")) o:value(2, translate("Every Tuesday"))
o.default = 0 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:depends("auto_update", true)
o.rmempty = true
---- Day update rules ---- Time Update
o = s:option(ListValue, "time_update", translate("Day update rules")) o = s:option(ListValue, "time_update", translate("Update Time(every day)"))
for e = 0, 23 do o:value(e, e .. translate("oclock")) end for t = 0, 23 do o:value(t, t .. ":00") end
o.default = 0 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 = 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.default = "sing-box/9.9.9"
o:value("curl") 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") 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") 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") o:value("Passwall2/OpenWrt", "PassWall2")
o:value("sing-box/9.9.9", "Xboard(V2board)")
return m return m

View File

@ -160,27 +160,20 @@ if has_xray then
o.default = "10-20" o.default = "10-20"
o:depends("fragment", true) 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 = 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 = 1 o.default = 0
o.rmempty = false
o = s_xray:option(Flag, "route_only", translate("Sniffing Route Only")) o = s_xray:option(Flag, "route_only", translate("Sniffing Route Only"))
o.default = 0 o.default = 0
o:depends("sniffing", true) o:depends("sniffing", true)
local domains_excluded = string.format("/usr/share/%s/domains_excluded", appname) 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.rows = 15
o.wrap = "off" o.wrap = "off"
o.cfgvalue = function(self, section) return fs.readfile(domains_excluded) or "" end 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.write = function(self, section, value) fs.writefile(domains_excluded, value:gsub("\r\n", "\n")) end
o.remove = function(self, section) o:depends({sniffing_override_dest = true})
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 = s_xray:option(Value, "buffer_size", translate("Buffer Size"), translate("Buffer size for every connection (kB)")) o = s_xray:option(Value, "buffer_size", translate("Buffer Size"), translate("Buffer size for every connection (kB)"))
o.datatype = "uinteger" o.datatype = "uinteger"

View File

@ -30,18 +30,40 @@ o.default = 0
o.rmempty = false o.rmempty = false
---- Week Update ---- 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")) o:value(7, translate("Every day"))
for e = 1, 6 do o:value(e, translate("Week") .. e) end o:value(1, translate("Every Monday"))
o:value(0, translate("Week") .. translate("day")) o:value(2, translate("Every Tuesday"))
o.default = 0 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:depends("auto_update", true)
o.rmempty = true
---- Time Update ---- Time Update
o = s:option(ListValue, "time_update", translate("Day update rules")) o = s:option(ListValue, "time_update", translate("Update Time(every day)"))
for e = 0, 23 do o:value(e, e .. translate("oclock")) end for t = 0, 23 do o:value(t, t .. ":00") end
o.default = 0 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"), "<a style='color: red'>" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "</a>") s = m:section(TypedSection, "shunt_rules", "Sing-Box/Xray " .. translate("Shunt Rule"), "<a style='color: red'>" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "</a>")
s.template = "cbi/tblsection" s.template = "cbi/tblsection"

View File

@ -107,11 +107,13 @@ domain_list.rows = 10
domain_list.wrap = "off" domain_list.wrap = "off"
domain_list.validate = function(self, value) domain_list.validate = function(self, value)
local hosts= {} 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 for index, host in ipairs(hosts) do
local flag = 1 local flag = 1
local tmp_host = host 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 flag = 0
elseif host:find("domain:.") and host:find("domain:.") == 1 then elseif host:find("domain:.") and host:find("domain:.") == 1 then
tmp_host = host:gsub("domain:", "") tmp_host = host:gsub("domain:", "")
@ -144,10 +146,11 @@ ip_list.rows = 10
ip_list.wrap = "off" ip_list.wrap = "off"
ip_list.validate = function(self, value) ip_list.validate = function(self, value)
local ipmasks= {} 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 for index, ipmask in ipairs(ipmasks) do
if ipmask:find("geoip:") and ipmask:find("geoip:") == 1 then if ipmask:find("geoip:") and ipmask:find("geoip:") == 1 and not ipmask:find("%s") then
elseif ipmask:find("ext:") and ipmask:find("ext:") == 1 then elseif ipmask:find("ext:") and ipmask:find("ext:") == 1 and not ipmask:find("%s") then
elseif ipmask:find("#") and ipmask:find("#") == 1 then elseif ipmask:find("#") and ipmask:find("#") == 1 then
else else
if not (datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask)) then if not (datatypes.ipmask4(ipmask) or datatypes.ipmask6(ipmask)) then

View File

@ -42,6 +42,9 @@ if auto_switch_tip then
socks_node.description = auto_switch_tip socks_node.description = auto_switch_tip
end 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 local n = 1
uci:foreach(appname, "socks", function(s) uci:foreach(appname, "socks", function(s)
if s[".name"] == section then if s[".name"] == section then

View File

@ -27,6 +27,7 @@ local header_type_list = {
"none", "srtp", "utp", "wechat-video", "dtls", "wireguard" "none", "srtp", "utp", "wechat-video", "dtls", "wireguard"
} }
local xray_version = api.get_app_version("xray")
-- [[ Xray ]] -- [[ Xray ]]
s.fields["type"]:value(type_name, "Xray") s.fields["type"]:value(type_name, "Xray")
@ -106,11 +107,13 @@ o:value("leastPing")
o.default = "leastPing" o.default = "leastPing"
-- Fallback Node -- 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")) local o = s:option(ListValue, option_name("fallback_node"), translate("Fallback Node"))
o:depends({ [option_name("balancingStrategy")] = "leastPing" }) if api.compare_versions(xray_version, ">=", "1.8.12") then
o:value("",translate("Null")) o:depends({ [option_name("protocol")] = "_balancing" })
o.default = "" else
o:depends({ [option_name("balancingStrategy")] = "leastPing" })
end
local function check_fallback_chain(fb) local function check_fallback_chain(fb)
for k, v in pairs(fallback_table) do for k, v in pairs(fallback_table) do
if v.fallback == fb then if v.fallback == fb then
@ -128,19 +131,34 @@ if api.compare_versions(api.get_app_version("xray"), ">=", "1.8.10") then
end end
-- 探测地址 -- 探测地址
local o = s:option(Flag, option_name("useCustomProbeUrl"), translate("Use Custome Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL.")) local 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."))
o:depends({ [option_name("balancingStrategy")] = "leastPing" }) ucpu:depends({ [option_name("balancingStrategy")] = "leastPing" })
local o = s:option(Value, option_name("probeUrl"), translate("Probe URL")) local pu = s:option(Value, option_name("probeUrl"), translate("Probe URL"))
o:depends({ [option_name("useCustomProbeUrl")] = true }) pu:depends({ [option_name("useCustomProbeUrl")] = true })
o.default = "https://www.google.com/generate_204" pu:value("https://cp.cloudflare.com/", "Cloudflare")
o.description = translate("The URL used to detect the connection status.") 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")) local pi = s:option(Value, option_name("probeInterval"), translate("Probe Interval"))
o:depends({ [option_name("balancingStrategy")] = "leastPing" }) pi:depends({ [option_name("balancingStrategy")] = "leastPing" })
o.default = "1m" pi.default = "1m"
o.description = translate("The interval between initiating probes. Every time this time elapses, a server status check is performed on a server. The time format is numbers + units, such as '10s', '2h45m', and the supported time units are <code>ns</code>, <code>us</code>, <code>ms</code>, <code>s</code>, <code>m</code>, <code>h</code>, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively.") 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 <code>ns</code>, <code>us</code>, <code>ms</code>, <code>s</code>, <code>m</code>, <code>h</code>, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively.")
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 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 = s:option(ListValue, option_name("alpn"), translate("alpn"))
o.default = "default" o.default = "default"
o:value("default", translate("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("h2,http/1.1")
o:value("h3")
o:value("h2") o:value("h2")
o:value("http/1.1") o:value("http/1.1")
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false }) o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
@ -379,6 +400,7 @@ o:value("ds", "DomainSocket")
o:value("quic", "QUIC") o:value("quic", "QUIC")
o:value("grpc", "gRPC") o:value("grpc", "gRPC")
o:value("httpupgrade", "HttpUpgrade") o:value("httpupgrade", "HttpUpgrade")
o:value("splithttp", "SplitHTTP")
o:depends({ [option_name("protocol")] = "vmess" }) o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" }) o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "socks" }) o:depends({ [option_name("protocol")] = "socks" })
@ -401,7 +423,7 @@ o = s:option(Value, option_name("wireguard_mtu"), translate("MTU"))
o.default = "1420" o.default = "1420"
o:depends({ [option_name("protocol")] = "wireguard" }) 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 = s:option(Value, option_name("wireguard_reserved"), translate("Reserved"), translate("Decimal numbers separated by \",\" or Base64-encoded strings."))
o:depends({ [option_name("protocol")] = "wireguard" }) o:depends({ [option_name("protocol")] = "wireguard" })
end end
@ -544,6 +566,14 @@ o = s:option(Value, option_name("httpupgrade_path"), translate("HttpUpgrade Path
o.placeholder = "/" o.placeholder = "/"
o:depends({ [option_name("transport")] = "httpupgrade" }) 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 ]]-- -- [[ Mux ]]--
o = s:option(Flag, option_name("mux"), translate("Mux")) o = s:option(Flag, option_name("mux"), translate("Mux"))
o:depends({ [option_name("protocol")] = "vmess" }) o:depends({ [option_name("protocol")] = "vmess" })

View File

@ -154,7 +154,10 @@ o:depends({ [option_name("reality")] = true })
o = s:option(ListValue, option_name("alpn"), translate("alpn")) o = s:option(ListValue, option_name("alpn"), translate("alpn"))
o.default = "h2,http/1.1" 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("h2,http/1.1")
o:value("h3")
o:value("h2") o:value("h2")
o:value("http/1.1") o:value("http/1.1")
o:depends({ [option_name("tls")] = true }) o:depends({ [option_name("tls")] = true })
@ -165,7 +168,6 @@ o:depends({ [option_name("tls")] = true })
--o:depends({ [option_name("tls")] = true }) --o:depends({ [option_name("tls")] = true })
-- [[ TLS部分 ]] -- -- [[ TLS部分 ]] --
o = s:option(FileUpload, option_name("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem") 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.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem"
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false }) o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
@ -203,6 +205,7 @@ o:value("ds", "DomainSocket")
o:value("quic", "QUIC") o:value("quic", "QUIC")
o:value("grpc", "gRPC") o:value("grpc", "gRPC")
o:value("httpupgrade", "HttpUpgrade") o:value("httpupgrade", "HttpUpgrade")
o:value("splithttp", "SplitHTTP")
o:depends({ [option_name("protocol")] = "vmess" }) o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" }) o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "socks" }) o:depends({ [option_name("protocol")] = "socks" })
@ -210,7 +213,6 @@ o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "trojan" }) o:depends({ [option_name("protocol")] = "trojan" })
-- [[ WebSocket部分 ]]-- -- [[ WebSocket部分 ]]--
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host")) o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
o:depends({ [option_name("transport")] = "ws" }) o:depends({ [option_name("transport")] = "ws" })
@ -226,13 +228,28 @@ o.placeholder = "/"
o:depends({ [option_name("transport")] = "httpupgrade" }) o:depends({ [option_name("transport")] = "httpupgrade" })
-- [[ HTTP/2部分 ]]-- -- [[ HTTP/2部分 ]]--
o = s:option(Value, option_name("h2_host"), translate("HTTP/2 Host")) o = s:option(Value, option_name("h2_host"), translate("HTTP/2 Host"))
o:depends({ [option_name("transport")] = "h2" }) o:depends({ [option_name("transport")] = "h2" })
o = s:option(Value, option_name("h2_path"), translate("HTTP/2 Path")) o = s:option(Value, option_name("h2_path"), translate("HTTP/2 Path"))
o:depends({ [option_name("transport")] = "h2" }) 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部分 ]]--
-- 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" }) o:depends({ [option_name("tcp_guise")] = "http" })
-- [[ mKCP部分 ]]-- -- [[ mKCP部分 ]]--
o = s:option(ListValue, option_name("mkcp_guise"), translate("Camouflage Type"), translate('<br />none: default, no masquerade, data sent is packets with no characteristics.<br />srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).<br />utp: packets disguised as uTP will be recognized as bittorrent downloaded data.<br />wechat-video: packets disguised as WeChat video calls.<br />dtls: disguised as DTLS 1.2 packet.<br />wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)')) o = s:option(ListValue, option_name("mkcp_guise"), translate("Camouflage Type"), translate('<br />none: default, no masquerade, data sent is packets with no characteristics.<br />srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).<br />utp: packets disguised as uTP will be recognized as bittorrent downloaded data.<br />wechat-video: packets disguised as WeChat video calls.<br />dtls: disguised as DTLS 1.2 packet.<br />wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)'))
for a, t in ipairs(header_type_list) do o:value(t) end for a, t in ipairs(header_type_list) do o:value(t) end
o:depends({ [option_name("transport")] = "mkcp" }) 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" }) o:depends({ [option_name("transport")] = "mkcp" })
-- [[ DomainSocket部分 ]]-- -- [[ DomainSocket部分 ]]--
o = s:option(Value, option_name("ds_path"), "Path", translate("A legal file path. This file must not exist before running.")) 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" }) 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 = s:option(DynamicList, option_name("fallback_list"), "Fallback", translate("dest,path"))
o:depends({ [option_name("fallback")] = true }) 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.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!")) o = s:option(Flag, option_name("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))

View File

@ -365,7 +365,7 @@ o = s:option(Value, option_name("tcpbrutal_down_mbps"), translate("Max download
o.default = "50" o.default = "50"
o:depends({ [option_name("tcpbrutal")] = true }) 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.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!")) o = s:option(Flag, option_name("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))

View File

@ -202,6 +202,10 @@ function gen_outbound(flag, node, tag, proxy_table)
path = node.httpupgrade_path or "/", path = node.httpupgrade_path or "/",
host = node.httpupgrade_host host = node.httpupgrade_host
} or nil, } or nil,
splithttpSettings = (node.transport == "splithttp") and {
path = node.splithttp_path or "/",
host = node.splithttp_host
} or nil,
} or nil, } or nil,
settings = { settings = {
vnext = (node.protocol == "vmess" or node.protocol == "vless") and { vnext = (node.protocol == "vmess" or node.protocol == "vless") and {
@ -477,6 +481,12 @@ function gen_config_server(node)
path = node.httpupgrade_path or "/", path = node.httpupgrade_path or "/",
host = node.httpupgrade_host host = node.httpupgrade_host
} or nil, } 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 = { sockopt = {
acceptProxyProtocol = (node.acceptProxyProtocol and node.acceptProxyProtocol == "1") and true or false 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}, settings = {network = "tcp,udp", followRedirect = true},
streamSettings = {sockopt = {tproxy = "tproxy"}}, streamSettings = {sockopt = {tproxy = "tproxy"}},
sniffing = { 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"}, destOverride = {"http", "tls", "quic", (remote_dns_fake) and "fakedns"},
metadataOnly = false, metadataOnly = false,
routeOnly = (xray_settings.sniffing == "1" and xray_settings.route_only == "1") and true or nil, routeOnly = node.protocol == "_shunt" and xray_settings.sniffing_override_dest ~= "1" or nil,
domainsExcluded = (xray_settings.sniffing == "1" and xray_settings.route_only == "0") and get_domain_excluded() or nil domainsExcluded = xray_settings.sniffing_override_dest == "1" and get_domain_excluded() or nil
} }
} }
local tcp_inbound = api.clone(inbound) local tcp_inbound = api.clone(inbound)
@ -682,9 +692,7 @@ function gen_config(var)
end end
end end
end end
if fallback_node_id == "" then if fallback_node_id == "" then fallback_node_id = nil end
fallback_node_id = nil
end
if fallback_node_id then if fallback_node_id then
local is_new_node = true local is_new_node = true
for _, outbound in ipairs(outbounds) do for _, outbound in ipairs(outbounds) do
@ -720,7 +728,7 @@ function gen_config(var)
fallbackTag = fallback_node_id, fallbackTag = fallback_node_id,
strategy = { type = _node.balancingStrategy or "random" } strategy = { type = _node.balancingStrategy or "random" }
}) })
if _node.balancingStrategy == "leastPing" then if _node.balancingStrategy == "leastPing" or fallback_node_id then
if not observatory then if not observatory then
observatory = { observatory = {
subjectSelector = { "blc-" }, subjectSelector = { "blc-" },
@ -962,6 +970,7 @@ function gen_config(var)
if outboundTag and outboundTag ~= "nil" then if outboundTag and outboundTag ~= "nil" then
table.insert(dns_domain_rules, api.clone(domain_table)) table.insert(dns_domain_rules, api.clone(domain_table))
end end
if #domains == 0 then domains = nil end
end end
local ip = nil local ip = nil
if e.ip_list then if e.ip_list then
@ -970,6 +979,7 @@ function gen_config(var)
if w:find("#") == 1 then return end if w:find("#") == 1 then return end
table.insert(ip, w) table.insert(ip, w)
end) end)
if #ip == 0 then ip = nil end
end end
local source = nil local source = nil
if e.source then if e.source then

View File

@ -640,12 +640,6 @@ msgstr "劫持ICMPv6 (IPv6 PING)"
msgid "Sniffing" msgid "Sniffing"
msgstr "流量嗅探" msgstr "流量嗅探"
msgid "When using the shunt, must be enabled, otherwise the shunt will invalid."
msgstr "使用分流时,必须启用,否则分流将无效。"
msgid "Sniffing Route Only"
msgstr "流量嗅探只供路由使用"
msgid "TCP Proxy Way" msgid "TCP Proxy Way"
msgstr "TCP代理方式" msgstr "TCP代理方式"
@ -775,23 +769,44 @@ msgstr "手动更新"
msgid "Enable auto update rules" msgid "Enable auto update rules"
msgstr "开启自动更新规则" msgstr "开启自动更新规则"
msgid "Week update rules" msgid "Update Time(every day)"
msgstr "更新时间星期" msgstr "更新时间(每天)"
msgid "Day update rules" msgid "Update Interval(hour)"
msgstr "更新时间小时" msgstr "更新间隔(小时)"
msgid "Update Mode"
msgstr "更新模式"
msgid "Loop Mode"
msgstr "循环"
msgid "Every day" msgid "Every day"
msgstr "每天" msgstr "每天"
msgid "day" msgid "Every Monday"
msgstr "日" msgstr "每周一"
msgid "Week" msgid "Every Tuesday"
msgstr "周" msgstr ""
msgid "oclock" msgid "Every Wednesday"
msgstr "点" 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" msgid "Location of V2ray/Xray asset"
msgstr "V2ray/Xray 资源文件目录" msgstr "V2ray/Xray 资源文件目录"
@ -1243,8 +1258,8 @@ msgstr "接口"
msgid "Bind Local" msgid "Bind Local"
msgstr "本机监听" msgstr "本机监听"
msgid "When selected, it can only be accessed locally, It is recommended to turn on when using reverse proxies or be fallback." msgid "When selected, it can only be accessed localhost."
msgstr "当勾选时,只能本机访问此端口,当想被反向代理或被回落时建议勾选此项。" msgstr "当勾选时,只能本机访问。"
msgid "Accept LAN Access" msgid "Accept LAN Access"
msgstr "接受局域网访问" msgstr "接受局域网访问"
@ -1390,11 +1405,11 @@ msgstr "无子连接时的健康检查"
msgid "Initial Windows Size" msgid "Initial Windows Size"
msgstr "初始窗口大小" msgstr "初始窗口大小"
msgid "No Sniffing Lists" msgid "Excluded Domains"
msgstr "不进行流量嗅探的域名列表" msgstr "排除域名"
msgid "Hosts added into No Sniffing Lists will not resolve again on server." msgid "If the traffic sniffing result is in this list, the destination address will not be overridden."
msgstr "加入的域名不会再次在服务器解析。" msgstr "如果流量嗅探结果在此列表中,则不会覆盖目标地址。"
msgid "Buffer Size" msgid "Buffer Size"
msgstr "缓冲区大小" msgstr "缓冲区大小"

View File

@ -31,11 +31,17 @@ uci -q batch <<-EOF >/dev/null
commit uhttpd commit uhttpd
EOF 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 [ ! -s "/etc/config/passwall2" ] && cp -f /usr/share/passwall2/0_default_config /etc/config/passwall2
chmod +x /usr/share/passwall2/*.sh 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 -f /tmp/luci-indexcache
rm -rf /tmp/luci-modulecache/ rm -rf /tmp/luci-modulecache/
killall -HUP rpcd 2>/dev/null killall -HUP rpcd 2>/dev/null

View File

@ -36,8 +36,7 @@ config global_forwarding
option ipv6_tproxy '0' option ipv6_tproxy '0'
config global_xray config global_xray
option sniffing '1' option sniffing_override_dest '0'
option route_only '0'
config global_other config global_other
option auto_detection_time 'tcping' option auto_detection_time 'tcping'

View File

@ -202,14 +202,15 @@ check_port_exists() {
} }
check_depends() { check_depends() {
local depends
local tables=${1} local tables=${1}
if [ "$tables" == "iptables" ]; then if [ "$tables" == "iptables" ]; then
for depends in "iptables-mod-tproxy" "iptables-mod-socket" "iptables-mod-iprange" "iptables-mod-conntrack-extra" "kmod-ipt-nat"; do 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 done
else else
for depends in "kmod-nft-socket" "kmod-nft-tproxy" "kmod-nft-nat"; do 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 done
fi fi
} }
@ -540,7 +541,7 @@ run_socks() {
[ "$http_port" != "0" ] && { [ "$http_port" != "0" ] && {
http_flag=1 http_flag=1
config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") 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" [ -n "$relay_port" ] && _extra_param="${_extra_param} -server_host $server_host -server_port $port"
[ "${log_file}" != "/dev/null" ] && { [ "${log_file}" != "/dev/null" ] && {
@ -548,17 +549,17 @@ run_socks() {
[ "$loglevel" = "warning" ] && loglevel="warn" [ "$loglevel" = "warning" ] && loglevel="warn"
_extra_param="${_extra_param} -log 1 -loglevel $loglevel -logfile $log_file" _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" ln_run "$(first_type $(config_t_get global_app singbox_file) sing-box)" "sing-box" /dev/null run -c "$config_file"
;; ;;
xray) xray)
[ "$http_port" != "0" ] && { [ "$http_port" != "0" ] && {
http_flag=1 http_flag=1
config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") 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" [ -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" ln_run "$(first_type $(config_t_get global_app xray_file) xray)" "xray" $log_file run -c "$config_file"
;; ;;
naiveproxy) naiveproxy)
@ -566,29 +567,29 @@ run_socks() {
ln_run "$(first_type naive)" naive $log_file "$config_file" ln_run "$(first_type naive)" naive $log_file "$config_file"
;; ;;
ssr) 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 ln_run "$(first_type ssr-local)" "ssr-local" $log_file -c "$config_file" -v -u
;; ;;
ss) 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 ln_run "$(first_type ss-local)" "ss-local" $log_file -c "$config_file" -v
;; ;;
ss-rust) ss-rust)
[ "$http_port" != "0" ] && { [ "$http_port" != "0" ] && {
http_flag=1 http_flag=1
config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") 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 ln_run "$(first_type sslocal)" "sslocal" $log_file -c "$config_file" -v
;; ;;
hysteria2) hysteria2)
[ "$http_port" != "0" ] && { [ "$http_port" != "0" ] && {
http_flag=1 http_flag=1
config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") 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 ln_run "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client
;; ;;
tuic) tuic)
@ -627,6 +628,9 @@ socks_node_switch() {
cmd=$(cat ${TMP_SCRIPT_FUNC_PATH}/${filename}) cmd=$(cat ${TMP_SCRIPT_FUNC_PATH}/${filename})
[ -n "$(echo $cmd | grep "${flag}")" ] && rm -f ${TMP_SCRIPT_FUNC_PATH}/${filename} [ -n "$(echo $cmd | grep "${flag}")" ] && rm -f ${TMP_SCRIPT_FUNC_PATH}/${filename}
done 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 port=$(config_n_get $flag port)
local config_file="SOCKS_${flag}.json" local config_file="SOCKS_${flag}.json"
local log_file="SOCKS_${flag}.log" 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_port=$(config_n_get $flag http_port 0)
local http_config_file="HTTP2SOCKS_${flag}.json" local http_config_file="HTTP2SOCKS_${flag}.json"
LOG_FILE="/dev/null" 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} 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}" V2RAY_ARGS="${V2RAY_ARGS} log_file=${V2RAY_LOG} config_file=${V2RAY_CONFIG}"
node_socks_port=$(config_t_get global node_socks_port 1070) 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 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) node_http_port=$(config_t_get global node_http_port 0)
@ -722,6 +729,9 @@ start_socks() {
[ "$enabled" == "0" ] && continue [ "$enabled" == "0" ] && continue
local node=$(config_n_get $id node nil) local node=$(config_n_get $id node nil)
[ "$node" == "nil" ] && continue [ "$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 port=$(config_n_get $id port)
local config_file="SOCKS_${id}.json" local config_file="SOCKS_${id}.json"
local log_file="SOCKS_${id}.log" local log_file="SOCKS_${id}.log"
@ -729,7 +739,7 @@ start_socks() {
[ "$log" == "0" ] && log_file="" [ "$log" == "0" ] && log_file=""
local http_port=$(config_n_get $id http_port 0) local http_port=$(config_n_get $id http_port 0)
local http_config_file="HTTP2SOCKS_${id}.json" 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} echo $node > $TMP_ID_PATH/socks_${id}
#自动切换逻辑 #自动切换逻辑
@ -749,19 +759,36 @@ clean_log() {
} }
clean_crontab() { clean_crontab() {
[ -f "/tmp/lock/${CONFIG}_cron.lock" ] && return
touch /etc/crontabs/root touch /etc/crontabs/root
#sed -i "/${CONFIG}/d" /etc/crontabs/root >/dev/null 2>&1 #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 "/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}/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 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() { 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 clean_crontab
[ "$ENABLED" != 1 ] && { [ "$ENABLED" != 1 ] && {
/etc/init.d/cron restart /etc/init.d/cron restart
return return
} }
auto_on=$(config_t_get global_delay auto_on 0) auto_on=$(config_t_get global_delay auto_on 0)
if [ "$auto_on" = "1" ]; then if [ "$auto_on" = "1" ]; then
time_off=$(config_t_get global_delay time_off) time_off=$(config_t_get global_delay time_off)
@ -787,7 +814,11 @@ start_crontab() {
if [ "$autoupdate" = "1" ]; then if [ "$autoupdate" = "1" ]; then
local t="0 $dayupdate * * $weekupdate" local t="0 $dayupdate * * $weekupdate"
[ "$weekupdate" = "7" ] && t="0 $dayupdate * * *" [ "$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 "配置定时任务:自动更新规则。" echolog "配置定时任务:自动更新规则。"
fi fi
@ -808,17 +839,23 @@ start_crontab() {
for name in $(ls ${TMP_SUB_PATH}); do for name in $(ls ${TMP_SUB_PATH}); do
week_update=$(echo $name | awk -F '_' '{print $1}') week_update=$(echo $name | awk -F '_' '{print $1}')
time_update=$(echo $name | awk -F '_' '{print $2}') 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" local t="0 $time_update * * $week_update"
[ "$week_update" = "7" ] && t="0 $time_update * * *" [ "$week_update" = "7" ] && t="0 $time_update * * *"
cfgids=$(echo -n $(cat ${TMP_SUB_PATH}/${name}) | sed 's# #,#g') if [ "$week_update" = "8" ]; then
echo "$t lua $APP_PATH/subscribe.lua start $cfgids > /dev/null 2>&1 &" >>/etc/crontabs/root update_loop=1
else
echo "$t lua $APP_PATH/subscribe.lua start $cfgids cron > /dev/null 2>&1 &" >>/etc/crontabs/root
fi
done done
rm -rf $TMP_SUB_PATH rm -rf $TMP_SUB_PATH
} }
if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then
start_daemon=$(config_t_get global_delay start_daemon 0) [ "$update_loop" = "1" ] && {
[ "$start_daemon" = "1" ] && $APP_PATH/monitor.sh > /dev/null 2>&1 & $APP_PATH/tasks.sh > /dev/null 2>&1 &
echolog "自动更新:启动循环更新进程。"
}
else else
echolog "运行于非代理模式,仅允许服务启停的定时任务。" echolog "运行于非代理模式,仅允许服务启停的定时任务。"
fi fi
@ -827,6 +864,7 @@ start_crontab() {
} }
stop_crontab() { stop_crontab() {
[ -f "/tmp/lock/${CONFIG}_cron.lock" ] && return
clean_crontab clean_crontab
/etc/init.d/cron restart /etc/init.d/cron restart
#echolog "清除定时执行命令。" #echolog "清除定时执行命令。"
@ -1075,7 +1113,7 @@ stop() {
delete_ip2route delete_ip2route
kill_all v2ray-plugin obfs-local kill_all v2ray-plugin obfs-local
pgrep -f "sleep.*(6s|9s|58s)" | xargs kill -9 >/dev/null 2>&1 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 V2RAY_LOCATION_ASSET
unset XRAY_LOCATION_ASSET unset XRAY_LOCATION_ASSET
stop_crontab stop_crontab

View File

@ -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 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_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 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 负载均衡...") log("HAPROXY 负载均衡...")
fs.mkdir(haproxy_path) fs.mkdir(haproxy_path)
@ -159,14 +162,14 @@ end
table.sort(sortTable, function(a,b) return (a < b) end) table.sort(sortTable, function(a,b) return (a < b) end)
for i, port in pairs(sortTable) do 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([[ f_out:write("\n" .. string.format([[
listen %s listen %s
bind 0.0.0.0:%s bind %s:%s
mode tcp mode tcp
balance roundrobin balance roundrobin
]], port, port)) ]], port, bind_address, port))
if health_check_type == "passwall_logic" then if health_check_type == "passwall_logic" then
f_out:write(string.format([[ f_out:write(string.format([[

View File

@ -724,7 +724,8 @@ add_firewall_rule() {
WAN_IP=$(get_wan_ip) WAN_IP=$(get_wan_ip)
if [ -n "${WAN_IP}" ]; then 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 fi
unset WAN_IP unset WAN_IP

View File

@ -8,6 +8,8 @@ local jsonc = require "luci.jsonc"
local name = 'passwall2' local name = 'passwall2'
local api = require "luci.passwall2.api" local api = require "luci.passwall2.api"
local arg1 = arg[1] local arg1 = arg[1]
local arg2 = arg[2]
local arg3 = arg[3]
local reboot = 0 local reboot = 0
local geoip_update = 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" local use_nft = ucic:get(name, "@global_forwarding[0]", "use_nft") or "0"
if arg3 == "cron" then
arg2 = nil
end
local log = function(...) local log = function(...)
if arg1 then if arg1 then
if arg1 == "log" then if arg1 == "log" then
@ -145,8 +151,8 @@ local function fetch_geosite()
return 0 return 0
end end
if arg[2] then if arg2 then
string.gsub(arg[2], '[^' .. "," .. ']+', function(w) string.gsub(arg2, '[^' .. "," .. ']+', function(w)
if w == "geoip" then if w == "geoip" then
geoip_update = 1 geoip_update = 1
end end
@ -184,6 +190,12 @@ ucic:save(name)
luci.sys.call("uci commit " .. name) luci.sys.call("uci commit " .. name)
if reboot == 1 then 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("重启服务,应用新的规则。") log("重启服务,应用新的规则。")
if use_nft == "1" then if use_nft == "1" then
luci.sys.call("sh /usr/share/" .. name .. "/nftables.sh flush_nftset_reload > /dev/null 2>&1 &") luci.sys.call("sh /usr/share/" .. name .. "/nftables.sh flush_nftset_reload > /dev/null 2>&1 &")

View File

@ -816,7 +816,7 @@ local function processData(szType, content, add_mode, add_from)
end end
result.remarks = UrlDecode(alias) result.remarks = UrlDecode(alias)
local dat = split(content, '%?') local dat = split(content:gsub("/%?", "?"), '%?')
local host_port = dat[1] local host_port = dat[1]
local params = {} local params = {}
for _, v in pairs(split(dat[2], '&')) do for _, v in pairs(split(dat[2], '&')) do
@ -1157,6 +1157,13 @@ local function update_node(manual)
uci:commit(appname) uci:commit(appname)
end 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 &") luci.sys.call("/etc/init.d/" .. appname .. " restart > /dev/null 2>&1 &")
end end

View File

@ -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