mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-11-02 04:43:56 +08:00
update 2026-08-08 00:47:38
This commit is contained in:
1 parent
8bad7f08b8
commit
9298d4285a
38 files changed
+1289
-395
No files matched your search
@@ -89,9 +89,8 @@ if has_xray or has_singbox then
|
|||||||
o.rmempty = false
|
o.rmempty = false
|
||||||
o.description = "<ul>"
|
o.description = "<ul>"
|
||||||
.. "<li>" .. translate("Experimental feature.") .. "</li>"
|
.. "<li>" .. translate("Experimental feature.") .. "</li>"
|
||||||
.. "<li>" .. "1." .. translate("Analyzes and preloads GeoIP/Geosite data to enhance the shunt performance of Sing-box/Xray.") .. "</li>"
|
.. "<li>" .. "1." .. translate("Parses and preloads GeoIP/Geosite data to improve Sing-box/Xray routing performance.") .. "</li>"
|
||||||
.. "<li>" .. "2." .. translate("Once enabled, the rule list can support GeoIP/Geosite rules.") .. "</li>"
|
.. "<li>" .. "2." .. translate("Once enabled, the rule list can support GeoIP/Geosite rules.") .. "</li>"
|
||||||
.. "<li>" .. translate("Note: Increases resource usage; Geosite analysis is only supported in ChinaDNS-NG and SmartDNS modes.") .. "</li>"
|
|
||||||
.. "</ul>"
|
.. "</ul>"
|
||||||
function o.write(self, section, value)
|
function o.write(self, section, value)
|
||||||
local old = m:get(section, self.option) or "0"
|
local old = m:get(section, self.option) or "0"
|
||||||
|
|||||||
@@ -1085,15 +1085,12 @@ msgstr "启用此选项后手动更新时,即使没有新版本也会从现有 G
|
|||||||
msgid "Enable Geo Data Parsing"
|
msgid "Enable Geo Data Parsing"
|
||||||
msgstr "开启 Geo 数据解析"
|
msgstr "开启 Geo 数据解析"
|
||||||
|
|
||||||
msgid "Analyzes and preloads GeoIP/Geosite data to enhance the shunt performance of Sing-box/Xray."
|
msgid "Parses and preloads GeoIP/Geosite data to improve Sing-box/Xray routing performance."
|
||||||
msgstr "分析和预加载 GeoIP/Geosite 数据,以增强 Sing-box/Xray 的分流效果。"
|
msgstr "解析和预加载 GeoIP/Geosite 数据,以增强 Sing-box/Xray 的分流效果。"
|
||||||
|
|
||||||
msgid "Once enabled, the rule list can support GeoIP/Geosite rules."
|
msgid "Once enabled, the rule list can support GeoIP/Geosite rules."
|
||||||
msgstr "启用后,规则列表可以支持 GeoIP/Geosite 规则。"
|
msgstr "启用后,规则列表可以支持 GeoIP/Geosite 规则。"
|
||||||
|
|
||||||
msgid "Note: Increases resource usage; Geosite analysis is only supported in ChinaDNS-NG and SmartDNS modes."
|
|
||||||
msgstr "注:会增加一些系统资源的开销,仅在 ChinaDNS-NG 和 SmartDNS 模式下支持分析 Geosite 。"
|
|
||||||
|
|
||||||
msgid "Shunt Rule"
|
msgid "Shunt Rule"
|
||||||
msgstr "分流规则"
|
msgstr "分流规则"
|
||||||
|
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ if USE_DIRECT_LIST == "1" and not fs.access(file_direct_host) then
|
|||||||
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
||||||
else
|
else
|
||||||
line = api.get_std_domain(line)
|
line = api.get_std_domain(line)
|
||||||
if line ~= "" and not line:find("#") then
|
if line ~= "" and not line:find("#") and not line:find(":") then
|
||||||
insert_unique(direct_domain, line, lookup_direct_domain)
|
insert_unique(direct_domain, line, lookup_direct_domain)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -277,7 +277,7 @@ if USE_PROXY_LIST == "1" and not fs.access(file_proxy_host) then
|
|||||||
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
||||||
else
|
else
|
||||||
line = api.get_std_domain(line)
|
line = api.get_std_domain(line)
|
||||||
if line ~= "" and not line:find("#") then
|
if line ~= "" and not line:find("#") and not line:find(":") then
|
||||||
insert_unique(proxy_domain, line, lookup_proxy_domain)
|
insert_unique(proxy_domain, line, lookup_proxy_domain)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -398,7 +398,7 @@ if IS_SHUNT_NODE then
|
|||||||
|
|
||||||
local domain_list = s.domain_list or ""
|
local domain_list = s.domain_list or ""
|
||||||
for line in string.gmatch(domain_list, "[^\r\n]+") do
|
for line in string.gmatch(domain_list, "[^\r\n]+") do
|
||||||
if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("ext:") then
|
if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("ext:") and not line:find("rule-set:") and not line:find("rs:") then
|
||||||
if line:find("geosite:") then
|
if line:find("geosite:") then
|
||||||
line = string.match(line, ":([^:]+)$")
|
line = string.match(line, ":([^:]+)$")
|
||||||
if _node_id == "_direct" then
|
if _node_id == "_direct" then
|
||||||
|
|||||||
@@ -181,10 +181,15 @@ function add_rule(var)
|
|||||||
local CACHE_TEXT_FILE = CACHE_DNS_PATH .. ".txt"
|
local CACHE_TEXT_FILE = CACHE_DNS_PATH .. ".txt"
|
||||||
local USE_CHINADNS_NG = "0"
|
local USE_CHINADNS_NG = "0"
|
||||||
local IS_SHUNT_NODE = uci:get(appname, TCP_NODE, "protocol") == "_shunt"
|
local IS_SHUNT_NODE = uci:get(appname, TCP_NODE, "protocol") == "_shunt"
|
||||||
|
local USE_GEOVIEW = uci:get(appname, "@global_rules[0]", "enable_geoview")
|
||||||
|
|
||||||
local list1 = {}
|
local list1 = {}
|
||||||
local excluded_domain = {}
|
local excluded_domain = {}
|
||||||
|
|
||||||
|
if not api.is_finded("geoview") then
|
||||||
|
USE_GEOVIEW = "0"
|
||||||
|
end
|
||||||
|
|
||||||
local function log(...)
|
local function log(...)
|
||||||
if NO_LOGIC_LOG == "1" then
|
if NO_LOGIC_LOG == "1" then
|
||||||
return
|
return
|
||||||
@@ -301,6 +306,21 @@ function add_rule(var)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function foreach_geosite(list_arg, callback)
|
||||||
|
local geosite_path = uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"
|
||||||
|
geosite_path = geosite_path:match("^(.*)/") .. "/geosite.dat"
|
||||||
|
if not fs.access(geosite_path) then return end
|
||||||
|
local bin = api.finded_com("geoview")
|
||||||
|
if not (bin and list_arg) then return end
|
||||||
|
local cmd = string.format("%q -type geosite -action extract -input %q -list %q -lowmem=true", bin, geosite_path, list_arg)
|
||||||
|
local pipe = io.popen(cmd)
|
||||||
|
if not pipe then return end
|
||||||
|
for line in pipe:lines() do
|
||||||
|
if line ~= "" then callback(line) end
|
||||||
|
end
|
||||||
|
pipe:close()
|
||||||
|
end
|
||||||
|
|
||||||
local cache_text = ""
|
local cache_text = ""
|
||||||
local nodes_address_md5 = sys.exec("echo -n $(uci show passwall | grep '\\.address') | md5sum")
|
local nodes_address_md5 = sys.exec("echo -n $(uci show passwall | grep '\\.address') | md5sum")
|
||||||
local new_rules = sys.exec("echo -n $(find /usr/share/passwall/rules -type f | xargs md5sum)")
|
local new_rules = sys.exec("echo -n $(find /usr/share/passwall/rules -type f | xargs md5sum)")
|
||||||
@@ -347,16 +367,28 @@ function add_rule(var)
|
|||||||
|
|
||||||
--屏蔽列表
|
--屏蔽列表
|
||||||
if USE_CHINADNS_NG == "0" and USE_BLOCK_LIST == "1" then
|
if USE_CHINADNS_NG == "0" and USE_BLOCK_LIST == "1" then
|
||||||
|
local geosite_arg = ""
|
||||||
local f = io.open("/usr/share/passwall/rules/block_host")
|
local f = io.open("/usr/share/passwall/rules/block_host")
|
||||||
if f then
|
if f then
|
||||||
for line in f:lines() do
|
for line in f:lines() do
|
||||||
line = api.get_std_domain(line)
|
if not line:find("#") and line:find("geosite:") then
|
||||||
if line ~= "" and not line:find("#") and not line:find(":") then
|
line = string.match(line, ":([^:]+)$")
|
||||||
set_domain_address(line, "")
|
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
||||||
|
else
|
||||||
|
line = api.get_std_domain(line)
|
||||||
|
if line ~= "" and not line:find("#") and not line:find(":") then
|
||||||
|
set_domain_address(line, "")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
f:close()
|
f:close()
|
||||||
end
|
end
|
||||||
|
if USE_GEOVIEW == "1" and geosite_arg ~= "" then
|
||||||
|
foreach_geosite(geosite_arg, function(line)
|
||||||
|
set_domain_address(line, "")
|
||||||
|
end)
|
||||||
|
log(" - 解析[屏蔽列表] Geosite 到屏蔽域名表(blocklist)完成")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local fwd_dns
|
local fwd_dns
|
||||||
@@ -400,88 +432,124 @@ function add_rule(var)
|
|||||||
|
|
||||||
--直连(白名单)列表
|
--直连(白名单)列表
|
||||||
if USE_DIRECT_LIST == "1" then
|
if USE_DIRECT_LIST == "1" then
|
||||||
if fs.access("/usr/share/passwall/rules/direct_host") then
|
fwd_dns = LOCAL_DNS
|
||||||
fwd_dns = LOCAL_DNS
|
if USE_CHINADNS_NG == "1" then
|
||||||
if USE_CHINADNS_NG == "1" then
|
fwd_dns = nil
|
||||||
fwd_dns = nil
|
end
|
||||||
end
|
if fwd_dns then
|
||||||
if fwd_dns then
|
local sets = {
|
||||||
local sets = {
|
setflag_4 .. "psw_white",
|
||||||
setflag_4 .. "psw_white",
|
setflag_6 .. "psw_white6"
|
||||||
setflag_6 .. "psw_white6"
|
}
|
||||||
}
|
--始终用国内DNS解析直连(白名单)列表
|
||||||
--始终用国内DNS解析直连(白名单)列表
|
local geosite_arg = ""
|
||||||
for line in io.lines("/usr/share/passwall/rules/direct_host") do
|
local f = io.open("/usr/share/passwall/rules/direct_host")
|
||||||
line = api.get_std_domain(line)
|
if f then
|
||||||
if line ~= "" and not line:find("#") and not line:find(":") then
|
for line in f:lines() do
|
||||||
add_excluded_domain(line)
|
if not line:find("#") and line:find("geosite:") then
|
||||||
set_domain_dns(line, fwd_dns)
|
line = string.match(line, ":([^:]+)$")
|
||||||
set_domain_ipset(line, table.concat(sets, ","))
|
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
||||||
|
else
|
||||||
|
line = api.get_std_domain(line)
|
||||||
|
if line ~= "" and not line:find("#") and not line:find(":") then
|
||||||
|
add_excluded_domain(line)
|
||||||
|
set_domain_dns(line, fwd_dns)
|
||||||
|
set_domain_ipset(line, table.concat(sets, ","))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
f:close()
|
||||||
log(string.format(" - 域名白名单(whitelist):%s", fwd_dns or "默认"))
|
log(string.format(" - 域名白名单(whitelist):%s", fwd_dns or "默认"))
|
||||||
end
|
end
|
||||||
|
if USE_GEOVIEW == "1" and geosite_arg ~= "" then
|
||||||
|
foreach_geosite(geosite_arg, function(line)
|
||||||
|
add_excluded_domain(line)
|
||||||
|
set_domain_dns(line, fwd_dns)
|
||||||
|
set_domain_ipset(line, table.concat(sets, ","))
|
||||||
|
end)
|
||||||
|
log(" - 解析[直连列表] Geosite 到域名白名单(whitelist)完成")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--代理(黑名单)列表
|
--代理(黑名单)列表
|
||||||
if USE_PROXY_LIST == "1" then
|
if USE_PROXY_LIST == "1" then
|
||||||
if fs.access("/usr/share/passwall/rules/proxy_host") then
|
fwd_dns = TUN_DNS
|
||||||
fwd_dns = TUN_DNS
|
if USE_CHINADNS_NG == "1" then
|
||||||
if USE_CHINADNS_NG == "1" then
|
fwd_dns = nil
|
||||||
fwd_dns = nil
|
end
|
||||||
|
if fwd_dns then
|
||||||
|
local set_name = "psw_black"
|
||||||
|
local set6_name = "psw_black6"
|
||||||
|
if FLAG ~= "default" then
|
||||||
|
set_name = "psw_" .. FLAG .. "_black"
|
||||||
|
set6_name = "psw_" .. FLAG .. "_black6"
|
||||||
end
|
end
|
||||||
if fwd_dns then
|
local sets = {
|
||||||
local set_name = "psw_black"
|
setflag_4 .. set_name
|
||||||
local set6_name = "psw_black6"
|
}
|
||||||
if FLAG ~= "default" then
|
if NO_PROXY_IPV6 ~= "1" then
|
||||||
set_name = "psw_" .. FLAG .. "_black"
|
table.insert(sets, setflag_6 .. set6_name)
|
||||||
set6_name = "psw_" .. FLAG .. "_black6"
|
end
|
||||||
end
|
--始终使用远程DNS解析代理(黑名单)列表
|
||||||
local sets = {
|
local geosite_arg = ""
|
||||||
setflag_4 .. set_name
|
local f = io.open("/usr/share/passwall/rules/proxy_host")
|
||||||
}
|
if f then
|
||||||
if NO_PROXY_IPV6 ~= "1" then
|
for line in f:lines() do
|
||||||
table.insert(sets, setflag_6 .. set6_name)
|
if not line:find("#") and line:find("geosite:") then
|
||||||
end
|
line = string.match(line, ":([^:]+)$")
|
||||||
--始终使用远程DNS解析代理(黑名单)列表
|
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
||||||
for line in io.lines("/usr/share/passwall/rules/proxy_host") do
|
else
|
||||||
line = api.get_std_domain(line)
|
line = api.get_std_domain(line)
|
||||||
if line ~= "" and not line:find("#") and not line:find(":") then
|
if line ~= "" and not line:find("#") and not line:find(":") then
|
||||||
add_excluded_domain(line)
|
add_excluded_domain(line)
|
||||||
if NO_PROXY_IPV6 == "1" then
|
if NO_PROXY_IPV6 == "1" then
|
||||||
set_domain_address(line, "::")
|
set_domain_address(line, "::")
|
||||||
|
end
|
||||||
|
set_domain_dns(line, fwd_dns)
|
||||||
|
set_domain_ipset(line, table.concat(sets, ","))
|
||||||
end
|
end
|
||||||
set_domain_dns(line, fwd_dns)
|
|
||||||
set_domain_ipset(line, table.concat(sets, ","))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
f:close()
|
||||||
log(string.format(" - 代理域名表(blacklist):%s", fwd_dns or "默认"))
|
log(string.format(" - 代理域名表(blacklist):%s", fwd_dns or "默认"))
|
||||||
end
|
end
|
||||||
|
if USE_GEOVIEW == "1" and geosite_arg ~= "" then
|
||||||
|
foreach_geosite(geosite_arg, function(line)
|
||||||
|
add_excluded_domain(line)
|
||||||
|
if NO_PROXY_IPV6 == "1" then
|
||||||
|
set_domain_address(line, "::")
|
||||||
|
end
|
||||||
|
set_domain_dns(line, fwd_dns)
|
||||||
|
set_domain_ipset(line, table.concat(sets, ","))
|
||||||
|
end)
|
||||||
|
log(" - 解析[代理列表] Geosite 到代理域名表(blacklist)完成")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--GFW列表
|
--GFW列表
|
||||||
if USE_GFW_LIST == "1" then
|
if USE_GFW_LIST == "1" then
|
||||||
if fs.access("/usr/share/passwall/rules/gfwlist") then
|
fwd_dns = TUN_DNS
|
||||||
fwd_dns = TUN_DNS
|
if USE_CHINADNS_NG == "1" then
|
||||||
if USE_CHINADNS_NG == "1" then
|
fwd_dns = nil
|
||||||
fwd_dns = nil
|
end
|
||||||
|
if fwd_dns then
|
||||||
|
local set_name = "psw_gfw"
|
||||||
|
local set6_name = "psw_gfw6"
|
||||||
|
if FLAG ~= "default" then
|
||||||
|
set_name = "psw_" .. FLAG .. "_gfw"
|
||||||
|
set6_name = "psw_" .. FLAG .. "_gfw6"
|
||||||
end
|
end
|
||||||
if fwd_dns then
|
local sets = {
|
||||||
local set_name = "psw_gfw"
|
setflag_4 .. set_name
|
||||||
local set6_name = "psw_gfw6"
|
}
|
||||||
if FLAG ~= "default" then
|
if NO_PROXY_IPV6 ~= "1" then
|
||||||
set_name = "psw_" .. FLAG .. "_gfw"
|
table.insert(sets, setflag_6 .. set6_name)
|
||||||
set6_name = "psw_" .. FLAG .. "_gfw6"
|
end
|
||||||
end
|
local f = io.open("/usr/share/passwall/rules/gfwlist")
|
||||||
local sets = {
|
if f then
|
||||||
setflag_4 .. set_name
|
for line in f:lines() do
|
||||||
}
|
|
||||||
if NO_PROXY_IPV6 ~= "1" then
|
|
||||||
table.insert(sets, setflag_6 .. set6_name)
|
|
||||||
end
|
|
||||||
for line in io.lines("/usr/share/passwall/rules/gfwlist") do
|
|
||||||
if line ~= "" and not line:find("#") and not check_excluded_domain(line) then
|
if line ~= "" and not line:find("#") and not check_excluded_domain(line) then
|
||||||
if NO_PROXY_IPV6 == "1" then
|
if NO_PROXY_IPV6 == "1" then
|
||||||
set_domain_address(line, "::")
|
set_domain_address(line, "::")
|
||||||
@@ -494,6 +562,7 @@ function add_rule(var)
|
|||||||
set_domain_ipset(line, table.concat(sets, ","))
|
set_domain_ipset(line, table.concat(sets, ","))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
f:close()
|
||||||
log(string.format(" - 防火墙域名表(gfwlist):%s", fwd_dns or "默认"))
|
log(string.format(" - 防火墙域名表(gfwlist):%s", fwd_dns or "默认"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -501,30 +570,31 @@ function add_rule(var)
|
|||||||
|
|
||||||
--中国列表
|
--中国列表
|
||||||
if CHN_LIST ~= "0" then
|
if CHN_LIST ~= "0" then
|
||||||
if fs.access("/usr/share/passwall/rules/chnlist") then
|
fwd_dns = nil
|
||||||
|
if CHN_LIST == "direct" then
|
||||||
|
fwd_dns = LOCAL_DNS
|
||||||
|
end
|
||||||
|
if CHN_LIST == "proxy" then
|
||||||
|
fwd_dns = TUN_DNS
|
||||||
|
end
|
||||||
|
if USE_CHINADNS_NG == "1" then
|
||||||
fwd_dns = nil
|
fwd_dns = nil
|
||||||
if CHN_LIST == "direct" then
|
end
|
||||||
fwd_dns = LOCAL_DNS
|
if fwd_dns then
|
||||||
end
|
local sets = {
|
||||||
|
setflag_4 .. "psw_chn",
|
||||||
|
setflag_6 .. "psw_chn6"
|
||||||
|
}
|
||||||
if CHN_LIST == "proxy" then
|
if CHN_LIST == "proxy" then
|
||||||
fwd_dns = TUN_DNS
|
if NO_PROXY_IPV6 == "1" then
|
||||||
end
|
sets = {
|
||||||
if USE_CHINADNS_NG == "1" then
|
setflag_4 .. "psw_chn"
|
||||||
fwd_dns = nil
|
}
|
||||||
end
|
|
||||||
if fwd_dns then
|
|
||||||
local sets = {
|
|
||||||
setflag_4 .. "psw_chn",
|
|
||||||
setflag_6 .. "psw_chn6"
|
|
||||||
}
|
|
||||||
if CHN_LIST == "proxy" then
|
|
||||||
if NO_PROXY_IPV6 == "1" then
|
|
||||||
sets = {
|
|
||||||
setflag_4 .. "psw_chn"
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
for line in io.lines("/usr/share/passwall/rules/chnlist") do
|
end
|
||||||
|
local f = io.open("/usr/share/passwall/rules/chnlist")
|
||||||
|
if f then
|
||||||
|
for line in f:lines() do
|
||||||
if line ~= "" and not line:find("#") and not check_excluded_domain(line) then
|
if line ~= "" and not line:find("#") and not check_excluded_domain(line) then
|
||||||
if CHN_LIST == "proxy" and NO_PROXY_IPV6 == "1" then
|
if CHN_LIST == "proxy" and NO_PROXY_IPV6 == "1" then
|
||||||
set_domain_address(line, "::")
|
set_domain_address(line, "::")
|
||||||
@@ -537,6 +607,7 @@ function add_rule(var)
|
|||||||
set_domain_ipset(line, table.concat(sets, ","))
|
set_domain_ipset(line, table.concat(sets, ","))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
f:close()
|
||||||
log(string.format(" - 中国域名表(chnroute):%s", fwd_dns or "默认"))
|
log(string.format(" - 中国域名表(chnroute):%s", fwd_dns or "默认"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -590,21 +661,40 @@ function add_rule(var)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local domain_list = s.domain_list or ""
|
local domain_list = s.domain_list or ""
|
||||||
|
local geosite_arg = ""
|
||||||
for line in string.gmatch(domain_list, "[^\r\n]+") do
|
for line in string.gmatch(domain_list, "[^\r\n]+") do
|
||||||
if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("geosite:") and not line:find("ext:") then
|
if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("ext:") and not line:find("rule-set:") and not line:find("rs:") then
|
||||||
if line:find("domain:") or line:find("full:") then
|
if line:find("geosite:") then
|
||||||
line = string.match(line, ":([^:]+)$")
|
line = string.match(line, ":([^:]+)$")
|
||||||
end
|
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
||||||
line = api.get_std_domain(line)
|
else
|
||||||
add_excluded_domain(line)
|
if line:find("domain:") or line:find("full:") then
|
||||||
|
line = string.match(line, ":([^:]+)$")
|
||||||
|
end
|
||||||
|
line = api.get_std_domain(line)
|
||||||
|
add_excluded_domain(line)
|
||||||
|
|
||||||
|
if no_ipv6 then
|
||||||
|
set_domain_address(line, "::")
|
||||||
|
end
|
||||||
|
set_domain_dns(line, fwd_dns)
|
||||||
|
set_domain_ipset(line, table.concat(sets, ","))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if USE_GFW_LIST == "1" and CHN_LIST == "0" and USE_GEOVIEW == "1" and geosite_arg ~= "" then --仅GFW模式解析geosite
|
||||||
|
foreach_geosite(geosite_arg, function(line)
|
||||||
|
add_excluded_domain(line)
|
||||||
if no_ipv6 then
|
if no_ipv6 then
|
||||||
set_domain_address(line, "::")
|
set_domain_address(line, "::")
|
||||||
end
|
end
|
||||||
set_domain_dns(line, fwd_dns)
|
set_domain_dns(line, fwd_dns)
|
||||||
set_domain_ipset(line, table.concat(sets, ","))
|
set_domain_ipset(line, table.concat(sets, ","))
|
||||||
end
|
end)
|
||||||
|
log(string.format(" - 解析分流规则(%s) Geosite 完成", s.remarks))
|
||||||
end
|
end
|
||||||
|
|
||||||
if _node_id ~= "_direct" then
|
if _node_id ~= "_direct" then
|
||||||
log(string.format(" - Sing-Box/Xray分流规则(%s):%s", s.remarks, fwd_dns or "默认"))
|
log(string.format(" - Sing-Box/Xray分流规则(%s):%s", s.remarks, fwd_dns or "默认"))
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -388,7 +388,7 @@ if USE_DIRECT_LIST == "1" and not fs.access(file_direct_host) then
|
|||||||
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
||||||
else
|
else
|
||||||
line = api.get_std_domain(line)
|
line = api.get_std_domain(line)
|
||||||
if line ~= "" and not line:find("#") then
|
if line ~= "" and not line:find("#") and not line:find(":") then
|
||||||
insert_unique(direct_domain, line, lookup_direct_domain)
|
insert_unique(direct_domain, line, lookup_direct_domain)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -440,7 +440,7 @@ if USE_PROXY_LIST == "1" and not fs.access(file_proxy_host) then
|
|||||||
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
geosite_arg = geosite_arg .. (geosite_arg ~= "" and "," or "") .. line
|
||||||
else
|
else
|
||||||
line = api.get_std_domain(line)
|
line = api.get_std_domain(line)
|
||||||
if line ~= "" and not line:find("#") then
|
if line ~= "" and not line:find("#") and not line:find(":") then
|
||||||
insert_unique(proxy_domain, line, lookup_proxy_domain)
|
insert_unique(proxy_domain, line, lookup_proxy_domain)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -566,7 +566,7 @@ if IS_SHUNT_NODE then
|
|||||||
|
|
||||||
local domain_list = s.domain_list or ""
|
local domain_list = s.domain_list or ""
|
||||||
for line in string.gmatch(domain_list, "[^\r\n]+") do
|
for line in string.gmatch(domain_list, "[^\r\n]+") do
|
||||||
if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("ext:") then
|
if line ~= "" and not line:find("#") and not line:find("regexp:") and not line:find("ext:") and not line:find("rule-set:") and not line:find("rs:") then
|
||||||
if line:find("geosite:") then
|
if line:find("geosite:") then
|
||||||
line = string.match(line, ":([^:]+)$")
|
line = string.match(line, ":([^:]+)$")
|
||||||
if _node_id == "_direct" then
|
if _node_id == "_direct" then
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=luci-app-passwall2
|
PKG_NAME:=luci-app-passwall2
|
||||||
PKG_VERSION:=26.7.16
|
PKG_VERSION:=26.8.7
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
function arraysEqual(a, b) {
|
||||||
|
if (a === b) return true;
|
||||||
|
if (a == null || b == null) return false;
|
||||||
|
if (a.length !== b.length) return false;
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
if (a[i] !== b[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitForElement(selector, callback) {
|
||||||
|
const el = document.querySelector(selector);
|
||||||
|
if (el) return callback(el);
|
||||||
|
const observer = new MutationObserver(() => {
|
||||||
|
const el = document.querySelector(selector);
|
||||||
|
if (el) {
|
||||||
|
observer.disconnect();
|
||||||
|
callback(el);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_current_url() {
|
||||||
|
return window.location.origin + window.location.pathname;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOption(config, section, opt) {
|
||||||
|
let obj;
|
||||||
|
const id = `cbid.${config}.${section}.${opt}`;
|
||||||
|
obj = document.getElementsByName(id)[0] || document.getElementById(id);
|
||||||
|
if (obj) {
|
||||||
|
const combobox = document.getElementById('cbi.combobox.' + id);
|
||||||
|
if (combobox) {
|
||||||
|
obj.combobox = combobox;
|
||||||
|
}
|
||||||
|
const div = document.getElementById(id);
|
||||||
|
if (div && div.getElementsByTagName("li").length > 0) {
|
||||||
|
obj = div;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -79,8 +79,8 @@ function index()
|
|||||||
entry({"admin", "services", appname, "connect_status"}, call("connect_status")).leaf = true
|
entry({"admin", "services", appname, "connect_status"}, call("connect_status")).leaf = true
|
||||||
entry({"admin", "services", appname, "ping_node"}, call("ping_node")).leaf = true
|
entry({"admin", "services", appname, "ping_node"}, call("ping_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "urltest_node"}, call("urltest_node")).leaf = true
|
entry({"admin", "services", appname, "urltest_node"}, call("urltest_node")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "update_config"}, call("update_config")).leaf = true
|
||||||
entry({"admin", "services", appname, "add_node"}, call("add_node")).leaf = true
|
entry({"admin", "services", appname, "add_node"}, call("add_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "update_node"}, call("update_node")).leaf = true
|
|
||||||
entry({"admin", "services", appname, "set_node"}, call("set_node")).leaf = true
|
entry({"admin", "services", appname, "set_node"}, call("set_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "copy_node"}, call("copy_node")).leaf = true
|
entry({"admin", "services", appname, "copy_node"}, call("copy_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true
|
entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true
|
||||||
@@ -96,6 +96,10 @@ function index()
|
|||||||
entry({"admin", "services", appname, "subscribe_manual"}, call("subscribe_manual")).leaf = true
|
entry({"admin", "services", appname, "subscribe_manual"}, call("subscribe_manual")).leaf = true
|
||||||
entry({"admin", "services", appname, "subscribe_manual_all"}, call("subscribe_manual_all")).leaf = true
|
entry({"admin", "services", appname, "subscribe_manual_all"}, call("subscribe_manual_all")).leaf = true
|
||||||
entry({"admin", "services", appname, "flush_set"}, call("flush_set")).leaf = true
|
entry({"admin", "services", appname, "flush_set"}, call("flush_set")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "get_shunt_rules"}, call("get_shunt_rules")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "add_shunt_rule"}, call("add_shunt_rule")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "delete_select_shunt_rules"}, call("delete_select_shunt_rules")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "save_shunt_rule_order"}, call("save_shunt_rule_order")).leaf = true
|
||||||
|
|
||||||
--[[Components update]]
|
--[[Components update]]
|
||||||
entry({"admin", "services", appname, "check_passwall2"}, call("app_check")).leaf = true
|
entry({"admin", "services", appname, "check_passwall2"}, call("app_check")).leaf = true
|
||||||
@@ -369,6 +373,23 @@ function urltest_node()
|
|||||||
http_write_json(e)
|
http_write_json(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function update_config()
|
||||||
|
local id = http.formvalue("id") -- Node id
|
||||||
|
local data = http.formvalue("data") -- json new Data
|
||||||
|
if id and data then
|
||||||
|
local data_t = jsonParse(data) or {}
|
||||||
|
if next(data_t) then
|
||||||
|
for k, v in pairs(data_t) do
|
||||||
|
uci:set(appname, id, k, v)
|
||||||
|
end
|
||||||
|
api.uci_save(uci, appname)
|
||||||
|
http_write_json_ok()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
http_write_json_error()
|
||||||
|
end
|
||||||
|
|
||||||
function add_node()
|
function add_node()
|
||||||
local redirect = http.formvalue("redirect")
|
local redirect = http.formvalue("redirect")
|
||||||
|
|
||||||
@@ -391,23 +412,6 @@ function add_node()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function update_node()
|
|
||||||
local id = http.formvalue("id") -- Node id
|
|
||||||
local data = http.formvalue("data") -- json new Data
|
|
||||||
if id and data then
|
|
||||||
local data_t = jsonParse(data) or {}
|
|
||||||
if next(data_t) then
|
|
||||||
for k, v in pairs(data_t) do
|
|
||||||
uci:set(appname, id, k, v)
|
|
||||||
end
|
|
||||||
api.uci_save(uci, appname)
|
|
||||||
http_write_json_ok()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
http_write_json_error()
|
|
||||||
end
|
|
||||||
|
|
||||||
function set_node()
|
function set_node()
|
||||||
local type = http.formvalue("type")
|
local type = http.formvalue("type")
|
||||||
local config = http.formvalue("config")
|
local config = http.formvalue("config")
|
||||||
@@ -968,3 +972,87 @@ function fetch_certsha256()
|
|||||||
local data = api.fetch_cert_sha256(address, port, sni, 5)
|
local data = api.fetch_cert_sha256(address, port, sni, 5)
|
||||||
http_write_json(data ~= "" and { code = 1, data = data } or { code = 0 })
|
http_write_json(data ~= "" and { code = 1, data = data } or { code = 0 })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function get_shunt_rules()
|
||||||
|
local id = http.formvalue("id")
|
||||||
|
local result = {}
|
||||||
|
|
||||||
|
if id then
|
||||||
|
result = uci:get_all(appname, id)
|
||||||
|
else
|
||||||
|
local default_items = {}
|
||||||
|
local other_items = {}
|
||||||
|
uci:foreach(appname, "shunt_rules", function(t)
|
||||||
|
if not t.group or t.group == "" then
|
||||||
|
default_items[#default_items + 1] = t
|
||||||
|
else
|
||||||
|
other_items[#other_items + 1] = t
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
for i = 1, #default_items do result[#result + 1] = default_items[i] end
|
||||||
|
for i = 1, #other_items do result[#result + 1] = other_items[i] end
|
||||||
|
end
|
||||||
|
http_write_json(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
function add_shunt_rule()
|
||||||
|
local add_name = http.formvalue("add_name")
|
||||||
|
local redirect = http.formvalue("redirect")
|
||||||
|
|
||||||
|
local uuid = add_name
|
||||||
|
if add_name then
|
||||||
|
local has = uci:get(appname, uuid)
|
||||||
|
if has then
|
||||||
|
http_write_json_error({ message = "This ID already exists." })
|
||||||
|
return
|
||||||
|
end
|
||||||
|
else
|
||||||
|
uuid = api.gen_short_uuid()
|
||||||
|
end
|
||||||
|
uci:section(appname, "shunt_rules", uuid)
|
||||||
|
|
||||||
|
local group = http.formvalue("group")
|
||||||
|
if group and group ~= "default" then
|
||||||
|
uci:set(appname, uuid, "group", group)
|
||||||
|
end
|
||||||
|
|
||||||
|
if redirect == "1" then
|
||||||
|
api.uci_save(uci, appname)
|
||||||
|
http.redirect(api.url("shunt_rules", uuid))
|
||||||
|
else
|
||||||
|
api.uci_save(uci, appname)
|
||||||
|
http_write_json_ok({uuid = uuid, redirect_url = api.url("shunt_rules", uuid)})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function delete_select_shunt_rules()
|
||||||
|
local ids = http.formvalue("ids")
|
||||||
|
local redirect = http.formvalue("redirect")
|
||||||
|
string.gsub(ids, '[^' .. "," .. ']+', function(w)
|
||||||
|
uci:foreach(appname, "nodes", function(s)
|
||||||
|
if s["protocol"] and s["protocol"] == "_shunt" then
|
||||||
|
uci:delete(appname, s[".name"], w)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
uci:delete(appname, w)
|
||||||
|
end)
|
||||||
|
if redirect == "1" then
|
||||||
|
api.uci_save(uci, appname)
|
||||||
|
http.redirect(api.url("rule"))
|
||||||
|
else
|
||||||
|
api.uci_save(uci, appname, true, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function save_shunt_rule_order()
|
||||||
|
local ids = http.formvalue("ids") or ""
|
||||||
|
local new_order = {}
|
||||||
|
for id in ids:gmatch("([^,]+)") do
|
||||||
|
new_order[#new_order + 1] = id
|
||||||
|
end
|
||||||
|
for idx, name in ipairs(new_order) do
|
||||||
|
luci.sys.call(string.format("uci -q reorder %s.%s=%d", appname, name, idx - 1))
|
||||||
|
end
|
||||||
|
api.sh_uci_commit(appname)
|
||||||
|
http_write_json({ status = "ok" })
|
||||||
|
end
|
||||||
@@ -101,6 +101,7 @@ if (has_singbox or has_xray) and #nodes_table > 0 then
|
|||||||
if current_node.protocol == "_shunt" then
|
if current_node.protocol == "_shunt" then
|
||||||
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall2/client/include/shunt_options.lua")
|
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall2/client/include/shunt_options.lua")
|
||||||
setfenv(shunt_lua, getfenv(1))(m, s, {
|
setfenv(shunt_lua, getfenv(1))(m, s, {
|
||||||
|
s_cfgid = s:cfgsections()[1],
|
||||||
node_id = current_node_id,
|
node_id = current_node_id,
|
||||||
node = current_node,
|
node = current_node,
|
||||||
socks_list = socks_list,
|
socks_list = socks_list,
|
||||||
|
|||||||
@@ -4,9 +4,17 @@ if not data.node_id or not data.node then
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local s_cfgid = data.s_cfgid
|
||||||
local current_node_id = data.node_id
|
local current_node_id = data.node_id
|
||||||
local node_list = data.node_list or api.get_node_list()
|
local node_list = data.node_list or api.get_node_list()
|
||||||
|
|
||||||
|
local groups = {}
|
||||||
|
m.uci:foreach(appname, "shunt_rules", function(s)
|
||||||
|
if s.group and s.group ~= "" then
|
||||||
|
groups[s.group] = true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
local function get_cfgvalue()
|
local function get_cfgvalue()
|
||||||
return function(self, section)
|
return function(self, section)
|
||||||
return m:get(current_node_id, self.option)
|
return m:get(current_node_id, self.option)
|
||||||
@@ -106,15 +114,27 @@ if api.is_finded("geoview") then
|
|||||||
.. "</ul>"
|
.. "</ul>"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
shunt_group = add_option(ListValue, "shunt_group", translate("Group Name"))
|
||||||
|
shunt_group:value("", translate("default"))
|
||||||
|
for k, v in pairs(groups) do
|
||||||
|
shunt_group:value(k)
|
||||||
|
end
|
||||||
|
|
||||||
|
local shunt_group_val = m:get(current_node_id, "shunt_group") or ""
|
||||||
|
shunt_group_val = shunt_group_val:lower()
|
||||||
local shunt_rules = {}
|
local shunt_rules = {}
|
||||||
m.uci:foreach(appname, "shunt_rules", function(e)
|
m.uci:foreach(appname, "shunt_rules", function(e)
|
||||||
e.id = e[".name"]
|
local group = e.group or ""
|
||||||
e.remarks = e.remarks or e[".name"]
|
group = group:lower()
|
||||||
e["_node_option"] = e[".name"]
|
if group == shunt_group_val then
|
||||||
e["_node_default"] = ""
|
e.id = e[".name"]
|
||||||
e["_fakedns_option"] = e[".name"] .. "_fakedns"
|
e.remarks = e.remarks or e[".name"]
|
||||||
e["_proxy_tag_option"] = e[".name"] .. "_proxy_tag"
|
e["_node_option"] = e[".name"]
|
||||||
table.insert(shunt_rules, e)
|
e["_node_default"] = ""
|
||||||
|
e["_fakedns_option"] = e[".name"] .. "_fakedns"
|
||||||
|
e["_proxy_tag_option"] = e[".name"] .. "_proxy_tag"
|
||||||
|
table.insert(shunt_rules, e)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
table.insert(shunt_rules, {
|
table.insert(shunt_rules, {
|
||||||
id = ".default",
|
id = ".default",
|
||||||
@@ -199,6 +219,8 @@ end
|
|||||||
|
|
||||||
local footer = Template(appname .. "/include/shunt_options")
|
local footer = Template(appname .. "/include/shunt_options")
|
||||||
footer.api = api
|
footer.api = api
|
||||||
|
footer.config = m.config
|
||||||
footer.id = current_node_id
|
footer.id = current_node_id
|
||||||
|
footer.s_cfgid = s_cfgid or current_node_id
|
||||||
footer.normal_list = api.jsonc.stringify(node_list.normal_list)
|
footer.normal_list = api.jsonc.stringify(node_list.normal_list)
|
||||||
m:append(footer)
|
m:append(footer)
|
||||||
@@ -135,6 +135,9 @@ s.template = "cbi/tblsection"
|
|||||||
s.extedit = api.url("node_subscribe_config", "%s")
|
s.extedit = api.url("node_subscribe_config", "%s")
|
||||||
function s.create(e, t)
|
function s.create(e, t)
|
||||||
local id = TypedSection.create(e, t)
|
local id = TypedSection.create(e, t)
|
||||||
|
uci:set(appname, id, "hysteria_up_mbps", "100")
|
||||||
|
uci:set(appname, id, "hysteria_down_mbps", "100")
|
||||||
|
api.uci_save(uci, appname)
|
||||||
luci.http.redirect(e.extedit:format(id))
|
luci.http.redirect(e.extedit:format(id))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -223,11 +223,9 @@ if #hysteria2_type > 0 then
|
|||||||
|
|
||||||
o = s:option(Value, "hysteria_up_mbps", "Hy/Hy2 " .. translate("Max upload Mbps"))
|
o = s:option(Value, "hysteria_up_mbps", "Hy/Hy2 " .. translate("Max upload Mbps"))
|
||||||
o.datatype = "uinteger"
|
o.datatype = "uinteger"
|
||||||
o.default = "100"
|
|
||||||
|
|
||||||
o = s:option(Value, "hysteria_down_mbps", "Hy/Hy2 " .. translate("Max download Mbps"))
|
o = s:option(Value, "hysteria_down_mbps", "Hy/Hy2 " .. translate("Max download Mbps"))
|
||||||
o.datatype = "uinteger"
|
o.datatype = "uinteger"
|
||||||
o.default = "100"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
o = s:option(Flag, "boot_update", translate("Update Once on Boot"), translate("Updates the subscription the first time runs automatically after each system boot."))
|
o = s:option(Flag, "boot_update", translate("Update Once on Boot"), translate("Updates the subscription the first time runs automatically after each system boot."))
|
||||||
|
|||||||
@@ -88,31 +88,6 @@ end
|
|||||||
|
|
||||||
s:append(Template(appname .. "/rule/rule_version"))
|
s:append(Template(appname .. "/rule/rule_version"))
|
||||||
|
|
||||||
local cfgname = "shunt_rules"
|
s:append(Template(appname .. "/rule/shunt_rule_list"))
|
||||||
s = m:section(TypedSection, cfgname, "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.anonymous = false
|
|
||||||
s.addremove = true
|
|
||||||
s.sortable = true
|
|
||||||
s.extedit = api.url("shunt_rules", "%s")
|
|
||||||
function s.create(e, t)
|
|
||||||
TypedSection.create(e, t)
|
|
||||||
luci.http.redirect(e.extedit:format(t))
|
|
||||||
end
|
|
||||||
function s.remove(e, t)
|
|
||||||
m.uci:foreach(appname, "nodes", function(s)
|
|
||||||
if s["protocol"] and s["protocol"] == "_shunt" then
|
|
||||||
m:del(s[".name"], t)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
TypedSection.remove(e, t)
|
|
||||||
end
|
|
||||||
|
|
||||||
o = s:option(DummyValue, "remarks", translate("Remarks"))
|
|
||||||
|
|
||||||
local sortable = Template(appname .. "/cbi/sortable")
|
|
||||||
sortable.api = api
|
|
||||||
sortable.target_cfgname = cfgname
|
|
||||||
m:append(sortable)
|
|
||||||
|
|
||||||
return api.return_map(m)
|
return api.return_map(m)
|
||||||
@@ -45,6 +45,19 @@ function clean_text(text)
|
|||||||
:gsub("[ \t]*\n[ \t]*", "\n")
|
:gsub("[ \t]*\n[ \t]*", "\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local remarks_lookup = {}
|
||||||
|
local groups = {}
|
||||||
|
m.uci:foreach(appname, "shunt_rules", function(s)
|
||||||
|
if s[".name"] ~= arg[1] then
|
||||||
|
if s.remarks then
|
||||||
|
remarks_lookup[s.remarks] = s[".name"]
|
||||||
|
end
|
||||||
|
if s.group and s.group ~= "" then
|
||||||
|
groups[s.group] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
s = m:section(NamedSection, arg[1], "shunt_rules", "")
|
s = m:section(NamedSection, arg[1], "shunt_rules", "")
|
||||||
s.addremove = false
|
s.addremove = false
|
||||||
s.dynamic = false
|
s.dynamic = false
|
||||||
@@ -57,9 +70,34 @@ remarks.validate = function(self, value, section)
|
|||||||
if value == "" then
|
if value == "" then
|
||||||
return nil, translate("Remark cannot be empty.")
|
return nil, translate("Remark cannot be empty.")
|
||||||
end
|
end
|
||||||
|
if remarks_lookup[value] then
|
||||||
|
return nil, translate("This remark already exists, please change a new remark.")
|
||||||
|
end
|
||||||
return value
|
return value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
o = s:option(Value, "group", translate("Group Name"))
|
||||||
|
o.default = ""
|
||||||
|
o:value("", translate("default"))
|
||||||
|
for k, v in pairs(groups) do
|
||||||
|
o:value(k)
|
||||||
|
end
|
||||||
|
o.write = function(self, section, value)
|
||||||
|
value = api.trim(value)
|
||||||
|
local lower = value:lower()
|
||||||
|
|
||||||
|
if lower == "" or lower == "default" then
|
||||||
|
return m:del(section, self.option)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, v in ipairs(self.keylist or {}) do
|
||||||
|
if v:lower() == lower then
|
||||||
|
return m:set(section, self.option, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
m:set(section, self.option, value)
|
||||||
|
end
|
||||||
|
|
||||||
protocol = s:option(MultiValue, "protocol", translate("Protocol"))
|
protocol = s:option(MultiValue, "protocol", translate("Protocol"))
|
||||||
protocol:value("http")
|
protocol:value("http")
|
||||||
protocol:value("tls")
|
protocol:value("tls")
|
||||||
|
|||||||
@@ -109,10 +109,12 @@ o.rewrite_option = o.option
|
|||||||
o = s:option(Value, _n("recv_window_conn"), translate("QUIC connection receive window"))
|
o = s:option(Value, _n("recv_window_conn"), translate("QUIC connection receive window"))
|
||||||
o.rewrite_option = o.option
|
o.rewrite_option = o.option
|
||||||
|
|
||||||
o = s:option(Value, _n("idle_timeout"), translate("Idle Timeout"), translate("Example:") .. "30s (4s~120s)")
|
o = s:option(Value, _n("idle_timeout"), translate("Idle Timeout"), translate("Units:seconds") .. " (4~120)")
|
||||||
|
o.datatype = "range(4,120)"
|
||||||
o.rewrite_option = o.option
|
o.rewrite_option = o.option
|
||||||
|
|
||||||
o = s:option(Value, _n("keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Example:") .. "10s (2s~60s)")
|
o = s:option(Value, _n("keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Units:seconds") .. " (2~60)")
|
||||||
|
o.datatype = "range(2,60)"
|
||||||
o.rewrite_option = o.option
|
o.rewrite_option = o.option
|
||||||
|
|
||||||
o = s:option(Flag, _n("disable_mtu_discovery"), translate("Disable MTU detection"))
|
o = s:option(Flag, _n("disable_mtu_discovery"), translate("Disable MTU detection"))
|
||||||
|
|||||||
@@ -394,10 +394,12 @@ o:depends({ [_n("protocol")] = "hysteria2" })
|
|||||||
o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps"))
|
o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps"))
|
||||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||||
|
|
||||||
o = s:option(Value, _n("hysteria2_idle_timeout"), translate("Idle Timeout"), translate("Example:") .. "30s (4s~120s)")
|
o = s:option(Value, _n("hysteria2_idle_timeout"), translate("Idle Timeout"), translate("Units:seconds") .. " (4~120)")
|
||||||
|
o.datatype = "range(4,120)"
|
||||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||||
|
|
||||||
o = s:option(Value, _n("hysteria2_keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Example:") .. "10s (2s~60s)")
|
o = s:option(Value, _n("hysteria2_keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Units:seconds") .. " (2~60)")
|
||||||
|
o.datatype = "range(2,60)"
|
||||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||||
|
|
||||||
o = s:option(Flag, _n("hysteria2_disable_mtu_discovery"), translate("Disable MTU detection"))
|
o = s:option(Flag, _n("hysteria2_disable_mtu_discovery"), translate("Disable MTU detection"))
|
||||||
@@ -803,6 +805,9 @@ o:value("", translate("Auto"))
|
|||||||
o:value("UseIPv4", translate("IPv4 Only"))
|
o:value("UseIPv4", translate("IPv4 Only"))
|
||||||
o:value("UseIPv6", translate("IPv6 Only"))
|
o:value("UseIPv6", translate("IPv6 Only"))
|
||||||
|
|
||||||
|
o = s:option(Flag, _n("happy_eyeballs"), translate("Enable Happy Eyeballs"), translate("Attempts IPv4 and IPv6 simultaneously; automatically uses the faster connection."))
|
||||||
|
o.default = 0
|
||||||
|
|
||||||
local protocols = s.fields[_n("protocol")].keylist
|
local protocols = s.fields[_n("protocol")].keylist
|
||||||
if #protocols > 0 then
|
if #protocols > 0 then
|
||||||
for i, v in ipairs(protocols) do
|
for i, v in ipairs(protocols) do
|
||||||
@@ -814,7 +819,11 @@ if #protocols > 0 then
|
|||||||
s.fields[_n("address")]:depends(depends_condition)
|
s.fields[_n("address")]:depends(depends_condition)
|
||||||
s.fields[_n("port")]:depends(depends_condition)
|
s.fields[_n("port")]:depends(depends_condition)
|
||||||
s.fields[_n("domain_resolver")]:depends(depends_condition)
|
s.fields[_n("domain_resolver")]:depends(depends_condition)
|
||||||
s.fields[_n("domain_strategy")]:depends(depends_condition)
|
s.fields[_n("happy_eyeballs")]:depends(depends_condition)
|
||||||
|
|
||||||
|
local strategy_depends = api.clone(depends_condition)
|
||||||
|
strategy_depends[_n("happy_eyeballs")] = false
|
||||||
|
s.fields[_n("domain_strategy")]:depends(strategy_depends)
|
||||||
|
|
||||||
if v ~= "hysteria2" then
|
if v ~= "hysteria2" then
|
||||||
s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v })
|
s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v })
|
||||||
|
|||||||
@@ -457,10 +457,12 @@ if singbox_tags:find("with_quic") then
|
|||||||
o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps"))
|
o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps"))
|
||||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||||
|
|
||||||
o = s:option(Value, _n("hysteria2_idle_timeout"), translate("Idle Timeout"), translate("Example:") .. "30s (4s~120s)")
|
o = s:option(Value, _n("hysteria2_idle_timeout"), translate("Idle Timeout"), translate("Units:seconds") .. " (4~120)")
|
||||||
|
o.datatype = "range(4,120)"
|
||||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||||
|
|
||||||
o = s:option(Value, _n("hysteria2_keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Example:") .. "10s (2s~60s)")
|
o = s:option(Value, _n("hysteria2_keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Units:seconds") .. " (2~60)")
|
||||||
|
o.datatype = "range(2,60)"
|
||||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||||
|
|
||||||
o = s:option(Flag, _n("hysteria2_disable_mtu_discovery"), translate("Disable MTU detection"))
|
o = s:option(Flag, _n("hysteria2_disable_mtu_discovery"), translate("Disable MTU detection"))
|
||||||
@@ -629,6 +631,10 @@ if singbox_tags:find("with_utls") then
|
|||||||
o:depends({ [_n("reality")] = true })
|
o:depends({ [_n("reality")] = true })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
o = s:option(Flag, _n("anytls_disable_reuse"), translate("Disable TLS Reuse"))
|
||||||
|
o.default = 0
|
||||||
|
o:depends({ [_n("protocol")] = "anytls" })
|
||||||
|
|
||||||
o = s:option(ListValue, _n("transport"), translate("Transport"))
|
o = s:option(ListValue, _n("transport"), translate("Transport"))
|
||||||
o:value("tcp", "TCP")
|
o:value("tcp", "TCP")
|
||||||
o:value("http", "HTTP")
|
o:value("http", "HTTP")
|
||||||
|
|||||||
@@ -1170,7 +1170,7 @@ function to_extract(app_name, file, subfix)
|
|||||||
exec("/bin/rm", {"-f", file})
|
exec("/bin/rm", {"-f", file})
|
||||||
return {
|
return {
|
||||||
code = 1,
|
code = 1,
|
||||||
error = i18n.translate("Not installed %s, Can't unzip!" % { tools_name })
|
error = i18n.translatef("Not installed %s, Can't unzip!", tools_name)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1383,8 +1383,6 @@ function set_apply_on_parse(map)
|
|||||||
if old then old(self) end
|
if old then old(self) end
|
||||||
map:set("@global[0]", "timestamp", os.time())
|
map:set("@global[0]", "timestamp", os.time())
|
||||||
end
|
end
|
||||||
local cbi = require "luci.cbi"
|
|
||||||
map:append(cbi.Template(appname .. "/cbi/optimize_cbi_ui"))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -647,6 +647,8 @@ function gen_outbound(flag, node, tag, proxy_table)
|
|||||||
idle_session_check_interval = "30s",
|
idle_session_check_interval = "30s",
|
||||||
idle_session_timeout = "30s",
|
idle_session_timeout = "30s",
|
||||||
min_idle_session = 5,
|
min_idle_session = 5,
|
||||||
|
disable_reuse = (node.anytls_disable_reuse == "1") and true or nil,
|
||||||
|
client_metadata = api.compare_versions(local_version, ">=", "1.13.16") and "anytls/0.0.13" or nil,
|
||||||
tls = tls
|
tls = tls
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -1599,6 +1601,9 @@ function gen_config(var)
|
|||||||
|
|
||||||
--shunt rule
|
--shunt rule
|
||||||
uci:foreach(appname, "shunt_rules", function(e)
|
uci:foreach(appname, "shunt_rules", function(e)
|
||||||
|
if node["shunt_group"] ~= e.group then
|
||||||
|
return
|
||||||
|
end
|
||||||
local outboundTag = gen_shunt_node(e[".name"])
|
local outboundTag = gen_shunt_node(e[".name"])
|
||||||
if outboundTag and e.remarks then
|
if outboundTag and e.remarks then
|
||||||
if outboundTag == "default" then
|
if outboundTag == "default" then
|
||||||
|
|||||||
@@ -170,9 +170,15 @@ function gen_outbound(flag, node, tag, proxy_table)
|
|||||||
mark = 255,
|
mark = 255,
|
||||||
domainStrategy = node.domain_strategy or "UseIP",
|
domainStrategy = node.domain_strategy or "UseIP",
|
||||||
tcpFastOpen = (node.tcp_fast_open == "1") and true or nil,
|
tcpFastOpen = (node.tcp_fast_open == "1") and true or nil,
|
||||||
tcpMptcp = (node.tcpMptcp == "1") and true or nil
|
tcpMptcp = (node.tcpMptcp == "1") and true or nil,
|
||||||
|
happyEyeballs = (node.happy_eyeballs == "1") and {
|
||||||
|
TryDelayMs = 250,
|
||||||
|
PrioritizeIPv6 = false,
|
||||||
|
Interleave = 1,
|
||||||
|
MaxConcurrentTry = 4
|
||||||
|
} or nil
|
||||||
},
|
},
|
||||||
network = node.transport,
|
[(api.compare_versions(xray_version, "<", "26.7.11")) and "network" or "method"] = node.transport, -- Todo: Remove version check and "network"
|
||||||
security = node.stream_security,
|
security = node.stream_security,
|
||||||
tlsSettings = (node.stream_security == "tls") and {
|
tlsSettings = (node.stream_security == "tls") and {
|
||||||
serverName = node.tls_serverName,
|
serverName = node.tls_serverName,
|
||||||
@@ -659,7 +665,7 @@ function gen_config_server(node)
|
|||||||
protocol = node.protocol,
|
protocol = node.protocol,
|
||||||
settings = settings,
|
settings = settings,
|
||||||
streamSettings = {
|
streamSettings = {
|
||||||
network = node.transport,
|
[(api.compare_versions(xray_version, "<", "26.7.11")) and "network" or "method"] = node.transport, -- Todo: Remove version check and "network"
|
||||||
security = "none",
|
security = "none",
|
||||||
tlsSettings = ("1" == node.tls) and {
|
tlsSettings = ("1" == node.tls) and {
|
||||||
disableSystemRoot = false,
|
disableSystemRoot = false,
|
||||||
@@ -1073,6 +1079,10 @@ function gen_config(var)
|
|||||||
if outboundTag then
|
if outboundTag then
|
||||||
valid_nodes[#valid_nodes + 1] = outboundTag
|
valid_nodes[#valid_nodes + 1] = outboundTag
|
||||||
end
|
end
|
||||||
|
-- Check if balancing node duplicates fallback node
|
||||||
|
if _node.fallback_node == blc_node_id then
|
||||||
|
_node.fallback_node = nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if #valid_nodes == 0 then return nil end
|
if #valid_nodes == 0 then return nil end
|
||||||
@@ -1392,6 +1402,9 @@ function gen_config(var)
|
|||||||
|
|
||||||
--shunt rule
|
--shunt rule
|
||||||
uci:foreach(appname, "shunt_rules", function(e)
|
uci:foreach(appname, "shunt_rules", function(e)
|
||||||
|
if node["shunt_group"] ~= e.group then
|
||||||
|
return
|
||||||
|
end
|
||||||
local outboundTag = gen_shunt_node(e[".name"])
|
local outboundTag = gen_shunt_node(e[".name"])
|
||||||
if outboundTag and e.remarks then
|
if outboundTag and e.remarks then
|
||||||
if outboundTag == "default" then
|
if outboundTag == "default" then
|
||||||
|
|||||||
@@ -1 +1,18 @@
|
|||||||
<!-- map footer -->
|
<!-- map footer -->
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
setTimeout(updateElements, 200);
|
||||||
|
function updateElements() {
|
||||||
|
// Remove extra line breaks between the value control and its description.
|
||||||
|
document.querySelectorAll("div.cbi-value-description").forEach(function(descDiv) {
|
||||||
|
var prev = descDiv.previousSibling;
|
||||||
|
while (prev && prev.nodeType === Node.TEXT_NODE && prev.textContent.trim() === "") {
|
||||||
|
prev = prev.previousSibling;
|
||||||
|
}
|
||||||
|
if (prev && prev.nodeType === Node.ELEMENT_NODE && prev.tagName === "BR") {
|
||||||
|
prev.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -1,2 +1,24 @@
|
|||||||
<!-- map header -->
|
<!-- map header -->
|
||||||
<script src="<%=resource%>/view/<%=self.api.appname%>/cbi.js"></script>
|
<script src="<%=resource%>/view/<%=self.api.appname%>/cbi.js"></script>
|
||||||
|
<script src="<%=resource%>/view/<%=self.api.appname%>/func.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
//<![CDATA[
|
||||||
|
function update_config(cfgid, data, redirect_url) {
|
||||||
|
XHR.get('<%=self.api.url("update_config")%>', {
|
||||||
|
id: cfgid,
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
},
|
||||||
|
function(x, data) {
|
||||||
|
if (x && x.status == 200 && data.code == 1) {
|
||||||
|
if (redirect_url) {
|
||||||
|
window.location.href = redirect_url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert("<%:Error%>");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<script type="text/javascript">
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
setTimeout(updateElements, 200);
|
|
||||||
function updateElements() {
|
|
||||||
document.querySelectorAll("input.btn.cbi-button.cbi-button-up").forEach(function(btn) {
|
|
||||||
btn.value = "<%:Move up%>";
|
|
||||||
});
|
|
||||||
document.querySelectorAll("input.btn.cbi-button.cbi-button-down").forEach(function(btn) {
|
|
||||||
btn.value = "<%:Move down%>";
|
|
||||||
});
|
|
||||||
document.querySelectorAll("div.cbi-value-description").forEach(function(descDiv) {
|
|
||||||
var prev = descDiv.previousSibling;
|
|
||||||
while (prev && prev.nodeType === Node.TEXT_NODE && prev.textContent.trim() === "") {
|
|
||||||
prev = prev.previousSibling;
|
|
||||||
}
|
|
||||||
if (prev && prev.nodeType === Node.ELEMENT_NODE && prev.tagName === "BR") {
|
|
||||||
prev.remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -207,7 +207,7 @@ local appname = api.appname
|
|||||||
let new_val = el.target.value
|
let new_val = el.target.value
|
||||||
const new_hasItem = shunt_list.find(element => element.id == new_val);
|
const new_hasItem = shunt_list.find(element => element.id == new_val);
|
||||||
if (new_hasItem) {
|
if (new_hasItem) {
|
||||||
XHR.get('<%=api.url("update_node")%>', {
|
XHR.get('<%=api.url("update_config")%>', {
|
||||||
id: "<%=self.global_cfgid%>",
|
id: "<%=self.global_cfgid%>",
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
node: new_val
|
node: new_val
|
||||||
|
|||||||
@@ -53,6 +53,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
waitForElement('select[name*="<%=self.config%>"][name*="shunt_group"]', function(el) {
|
||||||
|
let o_val = el.value;
|
||||||
|
el.addEventListener("change", () => {
|
||||||
|
el.blur();
|
||||||
|
if (o_val != el.value) {
|
||||||
|
let save = true;
|
||||||
|
if (save) {
|
||||||
|
update_config("<%=self.id%>", {
|
||||||
|
shunt_group: getOption("<%=self.config%>", "<%=self.s_cfgid%>", "shunt_group").value,
|
||||||
|
}, get_current_url());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
document.addEventListener("DOMContentLoaded", () => setTimeout(() => {
|
document.addEventListener("DOMContentLoaded", () => setTimeout(() => {
|
||||||
refresh_depends();
|
refresh_depends();
|
||||||
const table_dom = document.getElementById("cbi-passwall2-shunt_option_list");
|
const table_dom = document.getElementById("cbi-passwall2-shunt_option_list");
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<%
|
|
||||||
local api = self.api
|
|
||||||
-%>
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
//<![CDATA[
|
//<![CDATA[
|
||||||
|
let node_id = "<%=self.section%>";
|
||||||
|
let node_config_url = '<%=self.api.url("node_config")%>/' + node_id;
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
waitForElement('select[name*="<%=self.config%>"][name*="type"]', function(el) {
|
waitForElement('select[name*="<%=self.config%>"][name*="type"]', function(el) {
|
||||||
let o_val = el.value;
|
let o_val = el.value;
|
||||||
@@ -11,13 +11,18 @@ local api = self.api
|
|||||||
if (o_val != el.value) {
|
if (o_val != el.value) {
|
||||||
let save = true;
|
let save = true;
|
||||||
if (save) {
|
if (save) {
|
||||||
//document.getElementsByClassName('cbi-button-save')[0].click();
|
/*
|
||||||
update_node({
|
const saveBtn = document.getElementsByClassName('cbi-button-save');
|
||||||
remarks: getOption("remarks").value,
|
if (saveBtn && saveBtn.length > 0) {
|
||||||
group: getOption("group").value,
|
saveBtn[saveBtn.length - 1].click();
|
||||||
type: getOption("type").value,
|
}
|
||||||
|
*/
|
||||||
|
update_config(node_id, {
|
||||||
|
remarks: getOption("<%=self.config%>", "<%=self.section%>", "remarks").value,
|
||||||
|
group: getOption("<%=self.config%>", "<%=self.section%>", "group").value,
|
||||||
|
type: getOption("<%=self.config%>", "<%=self.section%>", "type").value,
|
||||||
protocol: ''
|
protocol: ''
|
||||||
});
|
}, node_config_url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -31,12 +36,17 @@ local api = self.api
|
|||||||
let name = name_split[name_split.length - 1];
|
let name = name_split[name_split.length - 1];
|
||||||
let save = true;
|
let save = true;
|
||||||
if (save) {
|
if (save) {
|
||||||
//document.getElementsByClassName('cbi-button-save')[0].click();
|
/*
|
||||||
update_node({
|
const saveBtn = document.getElementsByClassName('cbi-button-save');
|
||||||
remarks: getOption("remarks").value,
|
if (saveBtn && saveBtn.length > 0) {
|
||||||
group: getOption("group").value,
|
saveBtn[saveBtn.length - 1].click();
|
||||||
protocol: getOption(name).value
|
}
|
||||||
});
|
*/
|
||||||
|
update_config(node_id, {
|
||||||
|
remarks: getOption("<%=self.config%>", "<%=self.section%>", "remarks").value,
|
||||||
|
group: getOption("<%=self.config%>", "<%=self.section%>", "group").value,
|
||||||
|
protocol: getOption("<%=self.config%>", "<%=self.section%>", name).value,
|
||||||
|
}, node_config_url);
|
||||||
} else {
|
} else {
|
||||||
window.location.href = node_config_url + "?select_proto=" + el.value;
|
window.location.href = node_config_url + "?select_proto=" + el.value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +1,11 @@
|
|||||||
<%
|
|
||||||
local api = self.api
|
|
||||||
-%>
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
//<![CDATA[
|
//<![CDATA[
|
||||||
let node_id = "<%=self.section%>";
|
|
||||||
let node_config_url = '<%=api.url("node_config")%>/' + node_id;
|
|
||||||
|
|
||||||
function waitForElement(selector, callback) {
|
|
||||||
const el = document.querySelector(selector);
|
|
||||||
if (el) return callback(el);
|
|
||||||
const observer = new MutationObserver(() => {
|
|
||||||
const el = document.querySelector(selector);
|
|
||||||
if (el) {
|
|
||||||
observer.disconnect();
|
|
||||||
callback(el);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
observer.observe(document.body, { childList: true, subtree: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
function getOption(opt) {
|
|
||||||
var obj;
|
|
||||||
var id = 'cbid.<%=self.config%>.' + node_id + '.' + opt;
|
|
||||||
obj = document.getElementsByName(id)[0] || document.getElementById(id);
|
|
||||||
if (obj) {
|
|
||||||
var combobox = document.getElementById('cbi.combobox.' + id);
|
|
||||||
if (combobox) {
|
|
||||||
obj.combobox = combobox;
|
|
||||||
}
|
|
||||||
var div = document.getElementById(id);
|
|
||||||
if (div && div.getElementsByTagName("li").length > 0) {
|
|
||||||
obj = div;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function update_node(data) {
|
|
||||||
XHR.get('<%=api.url("update_node")%>', {
|
|
||||||
id: node_id,
|
|
||||||
data: JSON.stringify(data)
|
|
||||||
},
|
|
||||||
function(x, data) {
|
|
||||||
if (x && x.status == 200 && data.code == 1) {
|
|
||||||
window.location.href = node_config_url;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
alert("<%:Error%>");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetchCertSha256(el) {
|
function fetchCertSha256(el) {
|
||||||
if (el.getAttribute("data-loading") === "1") return;
|
if (el.getAttribute("data-loading") === "1") return;
|
||||||
el.setAttribute("data-loading", "1");
|
el.setAttribute("data-loading", "1");
|
||||||
el.style.pointerEvents = "none";
|
el.style.pointerEvents = "none";
|
||||||
el.style.color = "red";
|
el.style.color = "red";
|
||||||
XHR.get('<%=api.url("fetch_certsha256")%>', { id: node_id }, function(x, res) {
|
XHR.get('<%=self.api.url("fetch_certsha256")%>', { id: "<%=self.section%>" }, function(x, res) {
|
||||||
el.setAttribute("data-loading", "0");
|
el.setAttribute("data-loading", "0");
|
||||||
el.style.pointerEvents = "";
|
el.style.pointerEvents = "";
|
||||||
el.style.color = "";
|
el.style.color = "";
|
||||||
|
|||||||
@@ -1750,7 +1750,7 @@ local current_node = map:get(section)
|
|||||||
opt.set(dom_prefix + 'tls', true);
|
opt.set(dom_prefix + 'tls', true);
|
||||||
opt.set(dom_prefix + 'reality', false);
|
opt.set(dom_prefix + 'reality', false);
|
||||||
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
|
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
|
||||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
|
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || queryParam.peer || '');
|
||||||
opt.set(dom_prefix + 'tls_allowInsecure', !((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0'));
|
opt.set(dom_prefix + 'tls_allowInsecure', !((queryParam.allowinsecure ?? '0') === '0' && (queryParam.insecure ?? '0') === '0'));
|
||||||
if (queryParam.fp && queryParam.fp.trim() != "") {
|
if (queryParam.fp && queryParam.fp.trim() != "") {
|
||||||
opt.set(dom_prefix + 'utls', true);
|
opt.set(dom_prefix + 'utls', true);
|
||||||
@@ -1761,7 +1761,7 @@ local current_node = map:get(section)
|
|||||||
opt.set(dom_prefix + 'tls', true);
|
opt.set(dom_prefix + 'tls', true);
|
||||||
opt.set(dom_prefix + 'reality', true);
|
opt.set(dom_prefix + 'reality', true);
|
||||||
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
|
opt.set(dom_prefix + 'alpn', queryParam.alpn || 'default');
|
||||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
|
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || queryParam.peer || '');
|
||||||
if (queryParam.fp && queryParam.fp.trim() != "") {
|
if (queryParam.fp && queryParam.fp.trim() != "") {
|
||||||
opt.set(dom_prefix + 'utls', true);
|
opt.set(dom_prefix + 'utls', true);
|
||||||
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
|
opt.set(dom_prefix + 'fingerprint', queryParam.fp);
|
||||||
|
|||||||
@@ -0,0 +1,475 @@
|
|||||||
|
<%
|
||||||
|
local api = require "luci.passwall2.api"
|
||||||
|
local appname = api.appname
|
||||||
|
local uci = api.uci
|
||||||
|
-%>
|
||||||
|
<script src="<%=resource%>/view/<%=appname%>/Sortable.min.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
table th, .table .th {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td, .table .td {
|
||||||
|
text-align: center;
|
||||||
|
/* white-space: nowrap; */
|
||||||
|
word-break: keep-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td.cbi-section-actions {
|
||||||
|
text-align: right !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shunt_rule-wrapper {
|
||||||
|
align-items: center;
|
||||||
|
display: inline-flex !important;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cbi-tabmenu > li {
|
||||||
|
margin-right: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cbi-tabmenu > li:last-child {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shunt_rule-wrapper .drag-handle {
|
||||||
|
cursor: grab !important;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 100;
|
||||||
|
padding: 0 !important;
|
||||||
|
line-height: inherit;
|
||||||
|
user-select: none;
|
||||||
|
align-self: stretch;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shunt_rule-wrapper .drag-handle:hover {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable flex for small screens*/
|
||||||
|
@media screen and (max-width: 1152px) {
|
||||||
|
.cbi-section-table-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cbi-section-table-titles {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td-actions {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
border-top-width: 0 !important;
|
||||||
|
flex: 1 1 350px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shrink actionbar even further for mobile devices */
|
||||||
|
@media screen and (max-width: 500px) {
|
||||||
|
.shunt_rule-wrapper {
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cbi-button {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
margin-right: 1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td-actions {
|
||||||
|
padding-left: 5px!important;
|
||||||
|
padding-right: 5px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortable-chosen {
|
||||||
|
background-color: rgba(220, 235, 245, 0.4) !important;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortable-ghost {
|
||||||
|
background: #cce5ff !important;
|
||||||
|
height: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dragging-row {
|
||||||
|
background-color: rgba(131, 191, 255, 0.7) !important;
|
||||||
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<% if api.is_js_luci() then -%>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var cbi_t = [];
|
||||||
|
function cbi_t_add(section, tab) {
|
||||||
|
var t = document.getElementById('tab.' + section + '.' + tab);
|
||||||
|
var c = document.getElementById('container.' + section + '.' + tab);
|
||||||
|
|
||||||
|
if( t && c ) {
|
||||||
|
cbi_t[section] = (cbi_t[section] || [ ]);
|
||||||
|
cbi_t[section][tab] = { 'tab': t, 'container': c, 'cid': c.id };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cbi_t_switch(section, tab) {
|
||||||
|
if( cbi_t[section] && cbi_t[section][tab] ) {
|
||||||
|
// Before switching tabs, first deselect all currently active tabs.
|
||||||
|
var o = cbi_t[section][tab];
|
||||||
|
var h = document.getElementById('tab.' + section);
|
||||||
|
for( var tid in cbi_t[section] ) {
|
||||||
|
var o2 = cbi_t[section][tid];
|
||||||
|
if( o.tab.id != o2.tab.id ) {
|
||||||
|
o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab( |$)/, " cbi-tab-disabled ");
|
||||||
|
o2.container.style.display = 'none';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(h) h.value = tab;
|
||||||
|
o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab-disabled( |$)/, " cbi-tab ");
|
||||||
|
o2.container.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<%- end %>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
//<![CDATA[
|
||||||
|
function toPage(action, cbi_id) {
|
||||||
|
if (action == "add") {
|
||||||
|
const dom = document.getElementsByClassName("cbi-tab")[0];
|
||||||
|
const current_group = dom ? (dom.getAttribute("group_name") || "default") : "default";
|
||||||
|
const add_name_val = document.getElementById("add_name_" + current_group).value;
|
||||||
|
if (add_name_val.length > 1) {
|
||||||
|
XHR.get('<%=api.url("add_shunt_rule")%>', {
|
||||||
|
add_name: add_name_val,
|
||||||
|
group: current_group
|
||||||
|
},
|
||||||
|
function(x, result) {
|
||||||
|
if (x && x.status === 200) {
|
||||||
|
if (result.code == 1) {
|
||||||
|
window.location.href = result.data.redirect_url;
|
||||||
|
} else {
|
||||||
|
alert(result.data.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert("<%:Save failed!%>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (action == "edit") {
|
||||||
|
window.location.href='<%=api.url("shunt_rules")%>/' + cbi_id;
|
||||||
|
}
|
||||||
|
if (action == "del") {
|
||||||
|
window.location.href = '<%=api.url("delete_select_shunt_rules")%>' + "?redirect=1&ids=" + cbi_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function row_top(btn, group) {
|
||||||
|
const row = btn.closest("tr");
|
||||||
|
if (!row) return;
|
||||||
|
const parent = row.parentNode;
|
||||||
|
let firstDataRow = parent.querySelector("tr:not(.cbi-section-table-titles)");
|
||||||
|
if (firstDataRow && firstDataRow !== row) {
|
||||||
|
parent.insertBefore(row, firstDataRow);
|
||||||
|
let save_order_btn = document.getElementById("save_order_btn_" + group);
|
||||||
|
if (save_order_btn) {
|
||||||
|
const new_order = get_shunt_rule_order(group);
|
||||||
|
if (!arraysEqual(new_order, origin_group_shunt_rule_order[group])) {
|
||||||
|
save_order_btn.style.display = null;
|
||||||
|
} else {
|
||||||
|
save_order_btn.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_shunt_rule_order(group) {
|
||||||
|
let table = document.getElementById("cbi-<%=appname%>-shunt_rules-" + group + "-table");
|
||||||
|
if (!table) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let rows = table.querySelectorAll("tr.cbi-section-table-row");
|
||||||
|
if (!rows || rows.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var ids = [];
|
||||||
|
rows.forEach(function(row) {
|
||||||
|
var id = row.id.replace("cbi-<%=appname%>-", "");
|
||||||
|
ids.push(id);
|
||||||
|
});
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
function save_current_page_order(group) {
|
||||||
|
var table = document.getElementById("cbi-<%=appname%>-shunt_rules-" + group + "-table");
|
||||||
|
if (!table) {
|
||||||
|
alert("<%:No table!%>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var rows = table.querySelectorAll("tr.cbi-section-table-row");
|
||||||
|
if (!rows || rows.length === 0) {
|
||||||
|
alert("<%:No shunt_rules!%>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var btn = document.getElementById("save_order_btn_" + group);
|
||||||
|
if (btn) {
|
||||||
|
btn.style.display = "none";
|
||||||
|
btn.disabled = true;
|
||||||
|
}
|
||||||
|
var ids = [];
|
||||||
|
rows.forEach(function(row) {
|
||||||
|
var id = row.id.replace("cbi-<%=appname%>-", "");
|
||||||
|
ids.push(id);
|
||||||
|
});
|
||||||
|
XHR.get('<%=api.url("save_shunt_rule_order")%>', {
|
||||||
|
group: group,
|
||||||
|
ids: ids.join(",")
|
||||||
|
},
|
||||||
|
function(x, result) {
|
||||||
|
if (btn) {
|
||||||
|
btn.style.display = null;
|
||||||
|
btn.disabled = false;
|
||||||
|
}
|
||||||
|
if (x && x.status === 200) {
|
||||||
|
origin_group_shunt_rule_order[group] = get_shunt_rule_order(group);
|
||||||
|
alert("<%:Saved current page order successfully.%>");
|
||||||
|
if (btn) {
|
||||||
|
btn.style.display = "none";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert("<%:Save failed!%>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function arraysEqual(a, b) {
|
||||||
|
if (a === b) return true;
|
||||||
|
if (a == null || b == null) return false;
|
||||||
|
if (a.length !== b.length) return false;
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
if (a[i] !== b[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// List drag and rearrange
|
||||||
|
function initSortableForTable(table) {
|
||||||
|
if (!table) return null;
|
||||||
|
let group = table.id.replace("cbi-<%=appname%>-shunt_rules-", "").replace("-table", "")
|
||||||
|
var root = table.querySelector('tbody') || table;
|
||||||
|
if (root._sortable_initialized) return root._sortable_instance;
|
||||||
|
root._sortable_initialized = true;
|
||||||
|
var opts = {
|
||||||
|
handle: ".drag-handle",
|
||||||
|
draggable: "tr.cbi-section-table-row",
|
||||||
|
animation: 150,
|
||||||
|
ghostClass: "dragging-row",
|
||||||
|
fallbackOnBody: true,
|
||||||
|
forceFallback: false,
|
||||||
|
swapThreshold: 0.65,
|
||||||
|
onEnd: function (evt) {
|
||||||
|
//save_current_page_order(group); // Auto save
|
||||||
|
let save_order_btn = document.getElementById("save_order_btn_" + group);
|
||||||
|
if (save_order_btn) {
|
||||||
|
const new_order = get_shunt_rule_order(group);
|
||||||
|
if (!arraysEqual(new_order, origin_group_shunt_rule_order[group])) {
|
||||||
|
save_order_btn.style.display = null;
|
||||||
|
} else {
|
||||||
|
save_order_btn.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
var instance = Sortable.create(root, opts);
|
||||||
|
root._sortable_instance = instance;
|
||||||
|
return instance;
|
||||||
|
} catch (err) {
|
||||||
|
root._sortable_initialized = false;
|
||||||
|
console.error("Sortable init failed:", err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initAllSortable(group_shunt_rules) {
|
||||||
|
if (typeof Sortable === 'undefined') {
|
||||||
|
var retries = 0;
|
||||||
|
var maxRetries = 25;
|
||||||
|
var t = setInterval(function () {
|
||||||
|
retries++;
|
||||||
|
if (typeof Sortable !== 'undefined') {
|
||||||
|
clearInterval(t);
|
||||||
|
for (var group in group_shunt_rules) {
|
||||||
|
var table = document.getElementById("cbi-<%=appname%>-shunt_rules-" + group + "-table");
|
||||||
|
initSortableForTable(table);
|
||||||
|
}
|
||||||
|
} else if (retries >= maxRetries) {
|
||||||
|
clearInterval(t);
|
||||||
|
}
|
||||||
|
}, 200);
|
||||||
|
} else {
|
||||||
|
for (var group in group_shunt_rules) {
|
||||||
|
var table = document.getElementById("cbi-<%=appname%>-shunt_rules-" + group + "-table");
|
||||||
|
initSortableForTable(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function escape_html(s) {
|
||||||
|
return s.replace(/[&<>"']/g, c => ({
|
||||||
|
"&":"&", "<":"<", ">":">", '"':""", "'":"'"
|
||||||
|
}[c]));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/template" id="shunt_rules-table-template">
|
||||||
|
<fieldset class="cbi-section cbi-tblsection" id="cbi-<%=appname%>-shunt_rules-{{group}}-fieldset">
|
||||||
|
<table class="table cbi-section-table" id="cbi-<%=appname%>-shunt_rules-{{group}}-table" style="">
|
||||||
|
<tr class="tr cbi-section-table-titles anonymous">
|
||||||
|
<th class="th cbi-section-table-cell" style="width:30%">ID</th>
|
||||||
|
<th class="th cbi-section-table-cell" style="width:30%"><%:Remarks%></th>
|
||||||
|
<th class="th cbi-section-table-cell cbi-section-actions"></th>
|
||||||
|
</tr>
|
||||||
|
{{shunt_rule-tr}}
|
||||||
|
</table>
|
||||||
|
<div class="cbi-section-create cbi-tblsection-create">
|
||||||
|
<input type="text" id="add_name_{{group}}">
|
||||||
|
<input class="cbi-button cbi-button-add" type="button" value="<%:Add%>" onclick="toPage('add')">
|
||||||
|
<input class="cbi-button cbi-button-apply" style="display: none" type="button" id="save_order_btn_{{group}}" value="<%:Save Order%>" onclick="save_current_page_order('{{group}}')">
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/template" id="shunt_rule-tr-template">
|
||||||
|
<tr class="tr cbi-section-table-row" id="cbi-<%=appname%>-{{id}}">
|
||||||
|
<td class="td cbi-value-field"><h3>{{id}}</h3></td>
|
||||||
|
<td class="td cbi-value-field">{{remarks}}</td>
|
||||||
|
<td class="td cbi-section-table-cell nowrap cbi-section-actions td-actions">
|
||||||
|
<div class="shunt_rule-wrapper">
|
||||||
|
<input class="btn cbi-button cbi-button-edit" type="button" value="<%:To Top%>" onclick="row_top(this, '{{group}}')" title="<%:To Top%>"/>
|
||||||
|
<input class="btn cbi-button cbi-button-edit" type="button" value="<%:Edit%>" onclick="toPage('edit', '{{id}}')" alt="<%:Edit%>" title="<%:Edit%>">
|
||||||
|
<input class="btn cbi-button cbi-button-remove" type="button" value="<%:Delete%>" onclick="toPage('del', '{{id}}')" alt="<%:Delete%>" title="<%:Delete%>">
|
||||||
|
<span class="drag-handle center" title="<%:Drag to reorder%>">⠿</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<fieldset class="cbi-section">
|
||||||
|
<legend>Sing-Box/Xray <%:Shunt Rule%></legend>
|
||||||
|
<div class="cbi-section-descr"><a style="color: red"><%:Please note attention to the priority, the higher the order, the higher the priority.%></a></div>
|
||||||
|
<div id="shunt_rule_list"></div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function loadNodeList() {
|
||||||
|
XHR.get('<%=api.url("get_shunt_rules")%>', null, function(x, result) {
|
||||||
|
var shunt_rule_list = result
|
||||||
|
|
||||||
|
var group_shunt_rules = {}
|
||||||
|
for (let i = 0; i < shunt_rule_list.length; i++) {
|
||||||
|
let _shunt_rule = shunt_rule_list[i]
|
||||||
|
if (!_shunt_rule.group || _shunt_rule.group === "") {
|
||||||
|
_shunt_rule.group = "default"
|
||||||
|
}
|
||||||
|
if (!group_shunt_rules[_shunt_rule.group]) {
|
||||||
|
group_shunt_rules[_shunt_rule.group] = []
|
||||||
|
}
|
||||||
|
group_shunt_rules[_shunt_rule.group].push(_shunt_rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tab_ul_li_html = '';
|
||||||
|
var tab_content_html = '';
|
||||||
|
var shunt_rules_table_template = document.getElementById("shunt_rules-table-template");
|
||||||
|
var shunt_rule_template = document.getElementById("shunt_rule-tr-template");
|
||||||
|
var default_group = null
|
||||||
|
for (let group in group_shunt_rules) {
|
||||||
|
if (default_group == null)
|
||||||
|
default_group = group
|
||||||
|
|
||||||
|
var table_html = "";
|
||||||
|
if (true) {
|
||||||
|
var new_shunt_rules_table_dom = shunt_rules_table_template.cloneNode(true);
|
||||||
|
var _html = new_shunt_rules_table_dom.innerHTML;
|
||||||
|
_html = _html.split("{{group}}").join(group);
|
||||||
|
var shunt_rule_tr_html = "";
|
||||||
|
for (var i = 0; i < group_shunt_rules[group].length; i++) {
|
||||||
|
let o = group_shunt_rules[group][i]
|
||||||
|
var newDom = shunt_rule_template.cloneNode(true);
|
||||||
|
newDom.classList.add("cbi-rowstyle-" + (i % 2 + 1));
|
||||||
|
var innerHTML = newDom.innerHTML;
|
||||||
|
innerHTML = innerHTML.split("{{id}}").join(o[".name"]);
|
||||||
|
innerHTML = innerHTML.split("{{group}}").join(o["group"] || "");
|
||||||
|
innerHTML = innerHTML.split("{{remarks}}").join(o["remarks"] || "");
|
||||||
|
|
||||||
|
shunt_rule_tr_html += innerHTML
|
||||||
|
}
|
||||||
|
_html = _html.split("{{shunt_rule-tr}}").join(shunt_rule_tr_html);
|
||||||
|
table_html = _html;
|
||||||
|
}
|
||||||
|
|
||||||
|
var group_name = group
|
||||||
|
if (group === "default") {
|
||||||
|
group_name = "<%:default%>"
|
||||||
|
}
|
||||||
|
|
||||||
|
tab_ul_li_html +=
|
||||||
|
'<li group_name="' + group + '" id="tab.<%=appname%>.shunt_rules.' + group + '" class="cbi-tab">' +
|
||||||
|
'<a onclick="this.blur(); return cbi_t_switch(\'<%=appname%>.shunt_rules\', \'' + group + '\')" href="<%=REQUEST_URI%>?tab.<%=appname%>.shunt_rules=' + group + '">' + escape_html(group_name) + " | " + "<font style='color: red'>" + group_shunt_rules[group].length + '</font></a>' +
|
||||||
|
'</li>'
|
||||||
|
tab_content_html +=
|
||||||
|
'<div class="cbi-tabcontainer" id="container.<%=appname%>.shunt_rules.' + group + '" style="display: none;">' +
|
||||||
|
'' + table_html +
|
||||||
|
'</div>'
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTabDOM(li, content) {
|
||||||
|
let tab_ul_html = '<ul class="cbi-tabmenu">';
|
||||||
|
let tab_content_html = '<fieldset class="cbi-section-shunt_rule cbi-section-shunt_rule-tabbed" id="cbi-<%=appname%>-shunt_rules">';
|
||||||
|
if (li) {
|
||||||
|
tab_ul_html += li;
|
||||||
|
}
|
||||||
|
if (content) {
|
||||||
|
tab_content_html += content;
|
||||||
|
}
|
||||||
|
tab_ul_html += '</ul>';
|
||||||
|
tab_content_html += '</fieldset>';
|
||||||
|
return tab_ul_html + tab_content_html;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("shunt_rule_list").innerHTML = addTabDOM(tab_ul_li_html, tab_content_html);
|
||||||
|
|
||||||
|
for (let group in group_shunt_rules) {
|
||||||
|
cbi_t_add("<%=appname%>.shunt_rules", group)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (default_group) {
|
||||||
|
cbi_t_switch("<%=appname%>.shunt_rules", default_group)
|
||||||
|
}
|
||||||
|
|
||||||
|
origin_group_shunt_rule_order = {};
|
||||||
|
for (let group in group_shunt_rules) {
|
||||||
|
origin_group_shunt_rule_order[group] = get_shunt_rule_order(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
initAllSortable(group_shunt_rules);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadNodeList();
|
||||||
|
|
||||||
|
//]]>
|
||||||
|
</script>
|
||||||
@@ -1750,6 +1750,12 @@ msgstr "حل مشکل DNS دامنه"
|
|||||||
msgid "If the node address is a domain name, this DNS will be used for resolution."
|
msgid "If the node address is a domain name, this DNS will be used for resolution."
|
||||||
msgstr "اگر آدرس گره یک نام دامنه باشد، از این DNS برای حل مسئله استفاده خواهد شد."
|
msgstr "اگر آدرس گره یک نام دامنه باشد، از این DNS برای حل مسئله استفاده خواهد شد."
|
||||||
|
|
||||||
|
msgid "Enable Happy Eyeballs"
|
||||||
|
msgstr "فعال کردن چشمهای خوشحال"
|
||||||
|
|
||||||
|
msgid "Attempts IPv4 and IPv6 simultaneously; automatically uses the faster connection."
|
||||||
|
msgstr "IPv4 و IPv6 را همزمان امتحان میکند؛ بهطور خودکار از اتصال سریعتر استفاده میکند."
|
||||||
|
|
||||||
msgid "Supports only Xray or Sing-box node types."
|
msgid "Supports only Xray or Sing-box node types."
|
||||||
msgstr "فقط گرههای نوع Xray یا Sing-box پشتیبانی میشوند."
|
msgstr "فقط گرههای نوع Xray یا Sing-box پشتیبانی میشوند."
|
||||||
|
|
||||||
@@ -2413,3 +2419,9 @@ msgstr "اندازه بسته Gecko (حداکثر)"
|
|||||||
|
|
||||||
msgid "valid time (hh:mm)"
|
msgid "valid time (hh:mm)"
|
||||||
msgstr "زمان معتبر (ساعت:میلیمتر)"
|
msgstr "زمان معتبر (ساعت:میلیمتر)"
|
||||||
|
|
||||||
|
msgid "Disable TLS Reuse"
|
||||||
|
msgstr "غیرفعال کردن استفاده مجدد از TLS"
|
||||||
|
|
||||||
|
msgid "Not Set"
|
||||||
|
msgstr "تنظیم نشده"
|
||||||
@@ -1751,6 +1751,12 @@ msgstr "Разрешение DNS-запросов для домена"
|
|||||||
msgid "If the node address is a domain name, this DNS will be used for resolution."
|
msgid "If the node address is a domain name, this DNS will be used for resolution."
|
||||||
msgstr "Если адрес узла является доменным именем, для разрешения будет использоваться этот DNS-сервер."
|
msgstr "Если адрес узла является доменным именем, для разрешения будет использоваться этот DNS-сервер."
|
||||||
|
|
||||||
|
msgid "Enable Happy Eyeballs"
|
||||||
|
msgstr "Включить счастливые глаза"
|
||||||
|
|
||||||
|
msgid "Attempts IPv4 and IPv6 simultaneously; automatically uses the faster connection."
|
||||||
|
msgstr "Одновременно пытается использовать IPv4 и IPv6; автоматически выбирает более быстрое соединение."
|
||||||
|
|
||||||
msgid "Supports only Xray or Sing-box node types."
|
msgid "Supports only Xray or Sing-box node types."
|
||||||
msgstr "Поддерживаются только узлы типа Xray или Sing-box."
|
msgstr "Поддерживаются только узлы типа Xray или Sing-box."
|
||||||
|
|
||||||
@@ -2411,3 +2417,9 @@ msgstr "Размер упаковки Gecko (макс)"
|
|||||||
|
|
||||||
msgid "valid time (hh:mm)"
|
msgid "valid time (hh:mm)"
|
||||||
msgstr "Время действия (чч:мм)"
|
msgstr "Время действия (чч:мм)"
|
||||||
|
|
||||||
|
msgid "Disable TLS Reuse"
|
||||||
|
msgstr "Отключить повторное использование TLS"
|
||||||
|
|
||||||
|
msgid "Not Set"
|
||||||
|
msgstr "Не задано"
|
||||||
@@ -1736,6 +1736,12 @@ msgstr "域名 DNS 解析"
|
|||||||
msgid "If the node address is a domain name, this DNS will be used for resolution."
|
msgid "If the node address is a domain name, this DNS will be used for resolution."
|
||||||
msgstr "如果节点地址是域名,则将使用此 DNS 进行解析。"
|
msgstr "如果节点地址是域名,则将使用此 DNS 进行解析。"
|
||||||
|
|
||||||
|
msgid "Enable Happy Eyeballs"
|
||||||
|
msgstr "启用 Happy Eyeballs"
|
||||||
|
|
||||||
|
msgid "Attempts IPv4 and IPv6 simultaneously; automatically uses the faster connection."
|
||||||
|
msgstr "同时尝试 IPv4 和 IPv6 连接,自动使用更快的连接。"
|
||||||
|
|
||||||
msgid "Supports only Xray or Sing-box node types."
|
msgid "Supports only Xray or Sing-box node types."
|
||||||
msgstr "仅支持 Xray 或 Sing-box 类型节点。"
|
msgstr "仅支持 Xray 或 Sing-box 类型节点。"
|
||||||
|
|
||||||
@@ -2399,3 +2405,9 @@ msgstr "Gecko 包大小(最大)"
|
|||||||
|
|
||||||
msgid "valid time (hh:mm)"
|
msgid "valid time (hh:mm)"
|
||||||
msgstr "有效时间(hh:mm)"
|
msgstr "有效时间(hh:mm)"
|
||||||
|
|
||||||
|
msgid "Disable TLS Reuse"
|
||||||
|
msgstr "禁用 TLS 连接复用"
|
||||||
|
|
||||||
|
msgid "Not Set"
|
||||||
|
msgstr "未设置"
|
||||||
@@ -1742,6 +1742,12 @@ msgstr "域名 DNS 解析"
|
|||||||
msgid "If the node address is a domain name, this DNS will be used for resolution."
|
msgid "If the node address is a domain name, this DNS will be used for resolution."
|
||||||
msgstr "如果節點地址是域名,則將使用此 DNS 進行解析。"
|
msgstr "如果節點地址是域名,則將使用此 DNS 進行解析。"
|
||||||
|
|
||||||
|
msgid "Enable Happy Eyeballs"
|
||||||
|
msgstr "啓用 Happy Eyeballs"
|
||||||
|
|
||||||
|
msgid "Attempts IPv4 and IPv6 simultaneously; automatically uses the faster connection."
|
||||||
|
msgstr "同時嘗試 IPv4 和 IPv6 鏈接,自動使用更快的鏈接。"
|
||||||
|
|
||||||
msgid "Supports only Xray or Sing-box node types."
|
msgid "Supports only Xray or Sing-box node types."
|
||||||
msgstr "僅支援 Xray 或 Sing-box 類型節點。"
|
msgstr "僅支援 Xray 或 Sing-box 類型節點。"
|
||||||
|
|
||||||
@@ -2405,3 +2411,9 @@ msgstr "Gecko 包大小(最大)"
|
|||||||
|
|
||||||
msgid "valid time (hh:mm)"
|
msgid "valid time (hh:mm)"
|
||||||
msgstr "有效時間(hh:mm)"
|
msgstr "有效時間(hh:mm)"
|
||||||
|
|
||||||
|
msgid "Disable TLS Reuse"
|
||||||
|
msgstr "禁用 TLS 連接復用"
|
||||||
|
|
||||||
|
msgid "Not Set"
|
||||||
|
msgstr "未設置"
|
||||||
@@ -59,51 +59,6 @@ config global_subscribe
|
|||||||
|
|
||||||
config global_singbox
|
config global_singbox
|
||||||
|
|
||||||
config shunt_rules 'China'
|
|
||||||
option remarks 'China'
|
|
||||||
option network 'tcp,udp'
|
|
||||||
option domain_list 'geosite:cn'
|
|
||||||
option ip_list 'geoip:cn'
|
|
||||||
|
|
||||||
config shunt_rules 'Iran'
|
|
||||||
option remarks 'Iran'
|
|
||||||
option network 'tcp,udp'
|
|
||||||
option domain_list 'geosite:ir
|
|
||||||
#rule-set:remote:https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geosite-ir.srs'
|
|
||||||
option ip_list 'geoip:ir
|
|
||||||
#rule-set:remote:https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geoip-ir.srs'
|
|
||||||
|
|
||||||
config shunt_rules 'Russia_Block'
|
|
||||||
option remarks 'Russia_Block'
|
|
||||||
option network 'tcp,udp'
|
|
||||||
option domain_list 'geosite:ru-blocked
|
|
||||||
#rule-set:remote:https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/refs/heads/release/sing-box/rule-set-geosite/geosite-ru-blocked.srs'
|
|
||||||
option ip_list 'geoip:ru-blocked
|
|
||||||
#rule-set:remote:https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/refs/heads/release/sing-box/rule-set-geoip/geoip-ru-blocked.srs'
|
|
||||||
|
|
||||||
config shunt_rules 'Russia'
|
|
||||||
option remarks 'Russia'
|
|
||||||
option network 'tcp,udp'
|
|
||||||
option ip_list 'geoip:ru
|
|
||||||
#rule-set:remote:https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/refs/heads/release/sing-box/rule-set-geoip/geoip-ru.srs'
|
|
||||||
|
|
||||||
config shunt_rules 'PrivateIP'
|
|
||||||
option remarks 'PrivateIP'
|
|
||||||
option network 'tcp,udp'
|
|
||||||
option ip_list '10.0.0.0/8
|
|
||||||
127.0.0.0/8
|
|
||||||
198.51.100.0/24
|
|
||||||
192.0.0.0/24
|
|
||||||
169.254.0.0/16
|
|
||||||
224.0.0.0/3
|
|
||||||
192.168.0.0/16
|
|
||||||
192.88.99.0/24
|
|
||||||
100.64.0.0/10
|
|
||||||
172.16.0.0/12
|
|
||||||
0.0.0.0/8
|
|
||||||
192.0.2.0/24
|
|
||||||
203.0.113.0/24'
|
|
||||||
|
|
||||||
config nodes 'examplenode'
|
config nodes 'examplenode'
|
||||||
option remarks 'Example'
|
option remarks 'Example'
|
||||||
option type 'Xray'
|
option type 'Xray'
|
||||||
@@ -126,3 +81,151 @@ config nodes 'rulenode'
|
|||||||
option domainMatcher 'hybrid'
|
option domainMatcher 'hybrid'
|
||||||
option write_ipset_direct '1'
|
option write_ipset_direct '1'
|
||||||
option enable_geoview_ip '1'
|
option enable_geoview_ip '1'
|
||||||
|
option shunt_group 'CN'
|
||||||
|
|
||||||
|
config shunt_rules 'DirectFront'
|
||||||
|
option remarks 'DirectFront'
|
||||||
|
option network 'tcp,udp'
|
||||||
|
option domain_list 'domain:ip233.cn'
|
||||||
|
option group 'CN'
|
||||||
|
|
||||||
|
config shunt_rules 'ProxyFront'
|
||||||
|
option remarks 'ProxyFront'
|
||||||
|
option network 'tcp,udp'
|
||||||
|
option domain_list 'domain:www.gstatic.com
|
||||||
|
domain:ssl.gstatic.com
|
||||||
|
domain:fonts.gstatic.com'
|
||||||
|
option group 'CN'
|
||||||
|
|
||||||
|
config shunt_rules 'DirectGame'
|
||||||
|
option remarks 'DirectGame'
|
||||||
|
option domain_list '# steam直连域名获取国内CDN走国内线路下载
|
||||||
|
cm.steampowered.com
|
||||||
|
steamserver.net
|
||||||
|
|
||||||
|
# steam国内CDN华为云
|
||||||
|
steampipe.steamcontent.tnkjmec.com
|
||||||
|
# steam国内CDN白山云
|
||||||
|
st.dl.eccdnx.com
|
||||||
|
st.dl.bscstorage.net
|
||||||
|
st.dl.pinyuncloud.com
|
||||||
|
# steam国内CDN新流云(原金山云)(支持ipv6)
|
||||||
|
dl.steam.clngaa.com
|
||||||
|
# steam国内CDN网宿
|
||||||
|
cdn.mileweb.cs.steampowered.com.8686c.com
|
||||||
|
cdn-ws.content.steamchina.com
|
||||||
|
# steam国内CDN腾讯云 (蒸汽中国独占)
|
||||||
|
cdn-qc.content.steamchina.com
|
||||||
|
# steam国内CDN阿里云(支持ipv6)
|
||||||
|
cdn-ali.content.steamchina.com
|
||||||
|
xz.pphimalayanrt.com
|
||||||
|
lv.queniujq.cn
|
||||||
|
alibaba.cdn.steampipe.steamcontent.com
|
||||||
|
|
||||||
|
# 国内游戏geosite域名
|
||||||
|
geosite:category-games@cn'
|
||||||
|
option ip_list '# steam直连IP
|
||||||
|
45.121.184.0/24
|
||||||
|
103.10.124.0/23
|
||||||
|
103.28.54.0/24
|
||||||
|
146.66.152.0/24
|
||||||
|
146.66.155.0/24
|
||||||
|
153.254.86.0/24
|
||||||
|
155.133.224.0/22
|
||||||
|
155.133.230.0/24
|
||||||
|
155.133.232.0/23
|
||||||
|
155.133.234.0/24
|
||||||
|
155.133.236.0/22
|
||||||
|
155.133.240.0/23
|
||||||
|
155.133.244.0/23
|
||||||
|
155.133.246.0/24
|
||||||
|
155.133.248.0/21
|
||||||
|
162.254.192.0/21
|
||||||
|
185.25.182.0/23
|
||||||
|
190.217.32.0/22
|
||||||
|
192.69.96.0/22
|
||||||
|
205.196.6.0/24
|
||||||
|
208.64.200.0/22
|
||||||
|
208.78.164.0/22
|
||||||
|
205.185.194.0/24'
|
||||||
|
option network 'tcp,udp'
|
||||||
|
option group 'CN'
|
||||||
|
|
||||||
|
config shunt_rules 'ProxyGame'
|
||||||
|
option remarks 'ProxyGame'
|
||||||
|
option domain_list '# steam 商店/客服/聊天/网页布局/API/二维码/Google云同步 代理URL
|
||||||
|
steamcommunity.com
|
||||||
|
www.steamcommunity.com
|
||||||
|
store.steampowered.com
|
||||||
|
checkout.steampowered.com
|
||||||
|
api.steampowered.com
|
||||||
|
help.steampowered.com
|
||||||
|
login.steampowered.com
|
||||||
|
store.akamai.steamstatic.com
|
||||||
|
steambroadcast.akamaized.net
|
||||||
|
steamvideo-a.akamaihd.net
|
||||||
|
steamusercontent-a.akamaihd.net
|
||||||
|
steamstore-a.akamaihd.net
|
||||||
|
steamcommunity-a.akamaihd.net
|
||||||
|
steamcdn-a.akamaihd.net
|
||||||
|
steamuserimages-a.akamaihd.net
|
||||||
|
community.akamai.steamstatic.com
|
||||||
|
avatars.akamai.steamstatic.com
|
||||||
|
community.steamstatic.com
|
||||||
|
cdn.akamai.steamstatic.com
|
||||||
|
avatars.steamstatic.com
|
||||||
|
shared.akamai.steamstatic.com
|
||||||
|
clan.akamai.steamstatic.com
|
||||||
|
cdn.cloudflare.steamstatic.com
|
||||||
|
community.cloudflare.steamstatic.com
|
||||||
|
store.cloudflare.steamstatic.com
|
||||||
|
avatars.cloudflare.steamstatic.com
|
||||||
|
clan.cloudflare.steamstatic.com
|
||||||
|
shared.cloudflare.steamstatic.com
|
||||||
|
steam-chat.com
|
||||||
|
steamcloud-ugc.storage.googleapis.com
|
||||||
|
steamcloud-eu-ams.storage.googleapis.com
|
||||||
|
steamcloud-eu-fra.storage.googleapis.com
|
||||||
|
steamcloud-finland.storage.googleapis.com
|
||||||
|
steamcloud-saopaulo.storage.googleapis.com
|
||||||
|
steamcloud-singapore.storage.googleapis.com
|
||||||
|
steamcloud-sydney.storage.googleapis.com
|
||||||
|
steamcloud-taiwan.storage.googleapis.com
|
||||||
|
steamcloud-eu.storage.googleapis.com
|
||||||
|
domain:blizzard.com
|
||||||
|
geosite:category-games'
|
||||||
|
option network 'tcp,udp'
|
||||||
|
option group 'CN'
|
||||||
|
|
||||||
|
config shunt_rules 'CN'
|
||||||
|
option remarks 'CN'
|
||||||
|
option domain_list 'geosite:cn'
|
||||||
|
option ip_list 'geoip:cn'
|
||||||
|
option network 'tcp,udp'
|
||||||
|
option group 'CN'
|
||||||
|
|
||||||
|
config shunt_rules 'Iran'
|
||||||
|
option remarks 'Iran'
|
||||||
|
option network 'tcp,udp'
|
||||||
|
option domain_list 'geosite:ir
|
||||||
|
#rule-set:remote:https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geosite-ir.srs'
|
||||||
|
option ip_list 'geoip:ir
|
||||||
|
#rule-set:remote:https://raw.githubusercontent.com/Chocolate4U/Iran-sing-box-rules/rule-set/geoip-ir.srs'
|
||||||
|
option group 'IR'
|
||||||
|
|
||||||
|
config shunt_rules 'Russia_Block'
|
||||||
|
option remarks 'Russia_Block'
|
||||||
|
option network 'tcp,udp'
|
||||||
|
option domain_list 'geosite:ru-blocked
|
||||||
|
#rule-set:remote:https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/refs/heads/release/sing-box/rule-set-geosite/geosite-ru-blocked.srs'
|
||||||
|
option ip_list 'geoip:ru-blocked
|
||||||
|
#rule-set:remote:https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/refs/heads/release/sing-box/rule-set-geoip/geoip-ru-blocked.srs'
|
||||||
|
option group 'RU'
|
||||||
|
|
||||||
|
config shunt_rules 'Russia'
|
||||||
|
option remarks 'Russia'
|
||||||
|
option network 'tcp,udp'
|
||||||
|
option ip_list 'geoip:ru
|
||||||
|
#rule-set:remote:https://raw.githubusercontent.com/runetfreedom/russia-v2ray-rules-dat/refs/heads/release/sing-box/rule-set-geoip/geoip-ru.srs'
|
||||||
|
option group 'RU'
|
||||||
|
|
||||||
@@ -189,7 +189,9 @@ gen_shunt_list() {
|
|||||||
local default_outbound="redirect"
|
local default_outbound="redirect"
|
||||||
[ "$default_node" = "_direct" ] && default_outbound="direct"
|
[ "$default_node" = "_direct" ] && default_outbound="direct"
|
||||||
local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
|
local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
|
||||||
|
local shunt_group=$(config_n_get $node shunt_group)
|
||||||
for shunt_id in $shunt_ids; do
|
for shunt_id in $shunt_ids; do
|
||||||
|
[ "${shunt_group}" != "$(config_n_get ${shunt_id} group)" ] && continue
|
||||||
local shunt_node=$(config_n_get ${node} "${shunt_id}")
|
local shunt_node=$(config_n_get ${node} "${shunt_id}")
|
||||||
[ -n "$shunt_node" ] && {
|
[ -n "$shunt_node" ] && {
|
||||||
local ipset_v4="psw2_${node}_${shunt_id}"
|
local ipset_v4="psw2_${node}_${shunt_id}"
|
||||||
@@ -702,15 +704,13 @@ add_firewall_rule() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
$ipt_n -N PSW2
|
$ipt_n -N PSW2
|
||||||
$ipt_n -A PSW2 $(dst $IPSET_DIRECT) -j RETURN
|
|
||||||
$ipt_n -A PSW2 $(dst $IPSET_VPS) -j RETURN
|
$ipt_n -A PSW2 $(dst $IPSET_VPS) -j RETURN
|
||||||
$ipt_n -A PSW2 $(comment "WAN_IP_RETURN") $(dst $IPSET_WAN) -j RETURN
|
$ipt_n -A PSW2 $(comment "WAN_IP_RETURN") $(dst $IPSET_WAN) -j RETURN
|
||||||
|
|
||||||
[ "$accept_icmp" = "1" ] && insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "-p icmp -j PSW2"
|
[ "$accept_icmp" = "1" ] && insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "$(dst $IPSET_DIRECT !) -p icmp -j PSW2"
|
||||||
[ -z "${is_tproxy}" ] && insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "-p tcp -j PSW2"
|
[ -z "${is_tproxy}" ] && insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "$(dst $IPSET_DIRECT !) -p tcp -j PSW2"
|
||||||
|
|
||||||
$ipt_n -N PSW2_OUTPUT
|
$ipt_n -N PSW2_OUTPUT
|
||||||
$ipt_n -A PSW2_OUTPUT $(dst $IPSET_DIRECT) -j RETURN
|
|
||||||
$ipt_n -A PSW2_OUTPUT $(dst $IPSET_VPS) -j RETURN
|
$ipt_n -A PSW2_OUTPUT $(dst $IPSET_VPS) -j RETURN
|
||||||
$ipt_n -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
$ipt_n -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
||||||
|
|
||||||
@@ -722,10 +722,6 @@ add_firewall_rule() {
|
|||||||
$ipt_n -I PREROUTING -m set --match-set $IPSET_DIRECT src -j PSW2_DNS
|
$ipt_n -I PREROUTING -m set --match-set $IPSET_DIRECT src -j PSW2_DNS
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$ipt_m -N PSW2_DIVERT
|
|
||||||
$ipt_m -A PSW2_DIVERT -j MARK --set-mark ${FWMARK}
|
|
||||||
$ipt_m -A PSW2_DIVERT -j ACCEPT
|
|
||||||
|
|
||||||
$ipt_m -N PSW2_RULE
|
$ipt_m -N PSW2_RULE
|
||||||
$ipt_m -A PSW2_RULE -j CONNMARK --restore-mark
|
$ipt_m -A PSW2_RULE -j CONNMARK --restore-mark
|
||||||
$ipt_m -A PSW2_RULE -m mark --mark ${FWMARK} -j RETURN
|
$ipt_m -A PSW2_RULE -m mark --mark ${FWMARK} -j RETURN
|
||||||
@@ -734,17 +730,16 @@ add_firewall_rule() {
|
|||||||
$ipt_m -A PSW2_RULE -j CONNMARK --save-mark
|
$ipt_m -A PSW2_RULE -j CONNMARK --save-mark
|
||||||
|
|
||||||
$ipt_m -N PSW2
|
$ipt_m -N PSW2
|
||||||
$ipt_m -A PSW2 $(dst $IPSET_DIRECT) -j RETURN
|
# Socket Only TCP, UDP Invalid.
|
||||||
|
$ipt_m -A PSW2 -p tcp -m socket -j MARK --set-mark ${FWMARK}
|
||||||
|
$ipt_m -A PSW2 -p tcp -m socket -j ACCEPT
|
||||||
$ipt_m -A PSW2 $(dst $IPSET_VPS) -j RETURN
|
$ipt_m -A PSW2 $(dst $IPSET_VPS) -j RETURN
|
||||||
$ipt_m -A PSW2 $(comment "WAN_IP_RETURN") $(dst $IPSET_WAN) -j RETURN
|
$ipt_m -A PSW2 $(comment "WAN_IP_RETURN") $(dst $IPSET_WAN) -j RETURN
|
||||||
$ipt_m -A PSW2 -m conntrack --ctdir REPLY -j RETURN
|
$ipt_m -A PSW2 -m conntrack --ctdir REPLY -j RETURN
|
||||||
|
|
||||||
insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "-j PSW2"
|
insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "$(dst $IPSET_DIRECT !) -j PSW2"
|
||||||
# Only TCP, UDP Invalid.
|
|
||||||
insert_rule_before "$ipt_m" "PREROUTING" "PSW2" "-p tcp -m socket -j PSW2_DIVERT"
|
|
||||||
|
|
||||||
$ipt_m -N PSW2_OUTPUT
|
$ipt_m -N PSW2_OUTPUT
|
||||||
$ipt_m -A PSW2_OUTPUT $(dst $IPSET_DIRECT) -j RETURN
|
|
||||||
$ipt_m -A PSW2_OUTPUT $(dst $IPSET_VPS) -j RETURN
|
$ipt_m -A PSW2_OUTPUT $(dst $IPSET_VPS) -j RETURN
|
||||||
$ipt_m -A PSW2_OUTPUT -m conntrack --ctdir REPLY -j RETURN
|
$ipt_m -A PSW2_OUTPUT -m conntrack --ctdir REPLY -j RETURN
|
||||||
$ipt_m -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
$ipt_m -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
||||||
@@ -754,12 +749,10 @@ add_firewall_rule() {
|
|||||||
|
|
||||||
[ "$accept_icmpv6" = "1" ] && {
|
[ "$accept_icmpv6" = "1" ] && {
|
||||||
$ip6t_n -N PSW2
|
$ip6t_n -N PSW2
|
||||||
$ip6t_n -A PSW2 $(dst $IPSET_DIRECT6) -j RETURN
|
|
||||||
$ip6t_n -A PSW2 $(dst $IPSET_VPS6) -j RETURN
|
$ip6t_n -A PSW2 $(dst $IPSET_VPS6) -j RETURN
|
||||||
$ip6t_n -A PREROUTING -p ipv6-icmp -j PSW2
|
$ip6t_n -A PREROUTING $(dst $IPSET_DIRECT6 !) -p ipv6-icmp -j PSW2
|
||||||
|
|
||||||
$ip6t_n -N PSW2_OUTPUT
|
$ip6t_n -N PSW2_OUTPUT
|
||||||
$ip6t_n -A PSW2_OUTPUT $(dst $IPSET_DIRECT6) -j RETURN
|
|
||||||
$ip6t_n -A PSW2_OUTPUT $(dst $IPSET_VPS6) -j RETURN
|
$ip6t_n -A PSW2_OUTPUT $(dst $IPSET_VPS6) -j RETURN
|
||||||
$ip6t_n -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
$ip6t_n -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
||||||
}
|
}
|
||||||
@@ -772,10 +765,6 @@ add_firewall_rule() {
|
|||||||
$ip6t_n -I PREROUTING -m set --match-set $IPSET_DIRECT6 src -j PSW2_DNS
|
$ip6t_n -I PREROUTING -m set --match-set $IPSET_DIRECT6 src -j PSW2_DNS
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$ip6t_m -N PSW2_DIVERT
|
|
||||||
$ip6t_m -A PSW2_DIVERT -j MARK --set-mark ${FWMARK}
|
|
||||||
$ip6t_m -A PSW2_DIVERT -j ACCEPT
|
|
||||||
|
|
||||||
$ip6t_m -N PSW2_RULE
|
$ip6t_m -N PSW2_RULE
|
||||||
$ip6t_m -A PSW2_RULE -j CONNMARK --restore-mark
|
$ip6t_m -A PSW2_RULE -j CONNMARK --restore-mark
|
||||||
$ip6t_m -A PSW2_RULE -m mark --mark ${FWMARK} -j RETURN
|
$ip6t_m -A PSW2_RULE -m mark --mark ${FWMARK} -j RETURN
|
||||||
@@ -784,18 +773,17 @@ add_firewall_rule() {
|
|||||||
$ip6t_m -A PSW2_RULE -j CONNMARK --save-mark
|
$ip6t_m -A PSW2_RULE -j CONNMARK --save-mark
|
||||||
|
|
||||||
$ip6t_m -N PSW2
|
$ip6t_m -N PSW2
|
||||||
$ip6t_m -A PSW2 $(dst $IPSET_DIRECT6) -j RETURN
|
# Socket Only TCP, UDP Invalid.
|
||||||
|
$ip6t_m -A PSW2 -p tcp -m socket -j MARK --set-mark ${FWMARK}
|
||||||
|
$ip6t_m -A PSW2 -p tcp -m socket -j ACCEPT
|
||||||
$ip6t_m -A PSW2 $(dst $IPSET_VPS6) -j RETURN
|
$ip6t_m -A PSW2 $(dst $IPSET_VPS6) -j RETURN
|
||||||
$ip6t_m -A PSW2 $(comment "WAN6_IP_RETURN") $(dst $IPSET_WAN6) -j RETURN
|
$ip6t_m -A PSW2 $(comment "WAN6_IP_RETURN") $(dst $IPSET_WAN6) -j RETURN
|
||||||
$ip6t_m -A PSW2 -m conntrack --ctdir REPLY -j RETURN
|
$ip6t_m -A PSW2 -m conntrack --ctdir REPLY -j RETURN
|
||||||
|
|
||||||
insert_rule_before "$ip6t_m" "PREROUTING" "mwan3" "-j PSW2"
|
insert_rule_before "$ip6t_m" "PREROUTING" "mwan3" "$(dst $IPSET_DIRECT6 !) -j PSW2"
|
||||||
# Only TCP, UDP Invalid.
|
|
||||||
insert_rule_before "$ip6t_m" "PREROUTING" "PSW2" "-p tcp -m socket -j PSW2_DIVERT"
|
|
||||||
|
|
||||||
$ip6t_m -N PSW2_OUTPUT
|
$ip6t_m -N PSW2_OUTPUT
|
||||||
$ip6t_m -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
$ip6t_m -A PSW2_OUTPUT -m mark --mark 255 -j RETURN
|
||||||
$ip6t_m -A PSW2_OUTPUT $(dst $IPSET_DIRECT6) -j RETURN
|
|
||||||
$ip6t_m -A PSW2_OUTPUT $(dst $IPSET_VPS6) -j RETURN
|
$ip6t_m -A PSW2_OUTPUT $(dst $IPSET_VPS6) -j RETURN
|
||||||
$ip6t_m -A PSW2_OUTPUT -m conntrack --ctdir REPLY -j RETURN
|
$ip6t_m -A PSW2_OUTPUT -m conntrack --ctdir REPLY -j RETURN
|
||||||
|
|
||||||
@@ -860,14 +848,14 @@ add_firewall_rule() {
|
|||||||
# Loading local router proxy TCP
|
# Loading local router proxy TCP
|
||||||
if [ -n "$NODE" ] && [ "$TCP_LOCALHOST_PROXY" = "1" ]; then
|
if [ -n "$NODE" ] && [ "$TCP_LOCALHOST_PROXY" = "1" ]; then
|
||||||
[ "$accept_icmp" = "1" ] && {
|
[ "$accept_icmp" = "1" ] && {
|
||||||
$ipt_n -A OUTPUT -p icmp -j PSW2_OUTPUT
|
$ipt_n -A OUTPUT $(dst $IPSET_DIRECT !) -p icmp -j PSW2_OUTPUT
|
||||||
$ipt_n -A PSW2_OUTPUT -p icmp -d $FAKE_IP $(REDIRECT)
|
$ipt_n -A PSW2_OUTPUT -p icmp -d $FAKE_IP $(REDIRECT)
|
||||||
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_n -A PSW2_OUTPUT -p icmp" "$(REDIRECT)"
|
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_n -A PSW2_OUTPUT -p icmp" "$(REDIRECT)"
|
||||||
$ipt_n -A PSW2_OUTPUT -p icmp $(REDIRECT)
|
$ipt_n -A PSW2_OUTPUT -p icmp $(REDIRECT)
|
||||||
}
|
}
|
||||||
|
|
||||||
[ "$accept_icmpv6" = "1" ] && {
|
[ "$accept_icmpv6" = "1" ] && {
|
||||||
$ip6t_n -A OUTPUT -p ipv6-icmp -j PSW2_OUTPUT
|
$ip6t_n -A OUTPUT $(dst $IPSET_DIRECT6 !) -p ipv6-icmp -j PSW2_OUTPUT
|
||||||
$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp -d $FAKE_IP_6 $(REDIRECT)
|
$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp -d $FAKE_IP_6 $(REDIRECT)
|
||||||
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp" "$(REDIRECT)"
|
add_shunt_t_rule "${SHUNT_LIST6}" "$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp" "$(REDIRECT)"
|
||||||
$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp $(REDIRECT)
|
$ip6t_n -A PSW2_OUTPUT -p ipv6-icmp $(REDIRECT)
|
||||||
@@ -882,11 +870,11 @@ add_firewall_rule() {
|
|||||||
$ipt_tmp -A PSW2_OUTPUT -p tcp -d $FAKE_IP ${ipt_j}
|
$ipt_tmp -A PSW2_OUTPUT -p tcp -d $FAKE_IP ${ipt_j}
|
||||||
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_tmp -A PSW2_OUTPUT -p tcp" "${ipt_j}" $TCP_REDIR_PORTS
|
add_shunt_t_rule "${SHUNT_LIST4}" "$ipt_tmp -A PSW2_OUTPUT -p tcp" "${ipt_j}" $TCP_REDIR_PORTS
|
||||||
add_port_rules "$ipt_tmp -A PSW2_OUTPUT -p tcp" $TCP_REDIR_PORTS "${ipt_j}"
|
add_port_rules "$ipt_tmp -A PSW2_OUTPUT -p tcp" $TCP_REDIR_PORTS "${ipt_j}"
|
||||||
[ -z "${is_tproxy}" ] && $ipt_n -A OUTPUT -p tcp -j PSW2_OUTPUT
|
[ -z "${is_tproxy}" ] && $ipt_n -A OUTPUT $(dst $IPSET_DIRECT !) -p tcp -j PSW2_OUTPUT
|
||||||
[ -n "${is_tproxy}" ] && {
|
[ -n "${is_tproxy}" ] && {
|
||||||
$ipt_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo $(REDIRECT $REDIR_PORT TPROXY)
|
$ipt_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo $(REDIRECT $REDIR_PORT TPROXY)
|
||||||
$ipt_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo -j RETURN
|
$ipt_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo -j RETURN
|
||||||
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -p tcp -j PSW2_OUTPUT"
|
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT !) -p tcp -j PSW2_OUTPUT"
|
||||||
}
|
}
|
||||||
|
|
||||||
[ "$PROXY_IPV6" == "1" ] && {
|
[ "$PROXY_IPV6" == "1" ] && {
|
||||||
@@ -895,7 +883,7 @@ add_firewall_rule() {
|
|||||||
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p tcp" $TCP_REDIR_PORTS "-j PSW2_RULE"
|
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p tcp" $TCP_REDIR_PORTS "-j PSW2_RULE"
|
||||||
$ip6t_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo $(REDIRECT $REDIR_PORT TPROXY)
|
$ip6t_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo $(REDIRECT $REDIR_PORT TPROXY)
|
||||||
$ip6t_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo -j RETURN
|
$ip6t_m -A PSW2 $(comment "${comment_l}") -p tcp -i lo -j RETURN
|
||||||
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -p tcp -j PSW2_OUTPUT"
|
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT6 !) -p tcp -j PSW2_OUTPUT"
|
||||||
}
|
}
|
||||||
|
|
||||||
[ -d "${TMP_IFACE_PATH}" ] && {
|
[ -d "${TMP_IFACE_PATH}" ] && {
|
||||||
@@ -913,7 +901,7 @@ add_firewall_rule() {
|
|||||||
add_port_rules "$ipt_m -A PSW2_OUTPUT -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
|
add_port_rules "$ipt_m -A PSW2_OUTPUT -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
|
||||||
$ipt_m -A PSW2 $(comment "${comment_l}") -p udp -i lo $(REDIRECT $REDIR_PORT TPROXY)
|
$ipt_m -A PSW2 $(comment "${comment_l}") -p udp -i lo $(REDIRECT $REDIR_PORT TPROXY)
|
||||||
$ipt_m -A PSW2 $(comment "${comment_l}") -p udp -i lo -j RETURN
|
$ipt_m -A PSW2 $(comment "${comment_l}") -p udp -i lo -j RETURN
|
||||||
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -p udp -j PSW2_OUTPUT"
|
insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT !) -p udp -j PSW2_OUTPUT"
|
||||||
|
|
||||||
[ "$PROXY_IPV6" == "1" ] && {
|
[ "$PROXY_IPV6" == "1" ] && {
|
||||||
$ip6t_m -A PSW2_OUTPUT -p udp -d $FAKE_IP_6 -j PSW2_RULE
|
$ip6t_m -A PSW2_OUTPUT -p udp -d $FAKE_IP_6 -j PSW2_RULE
|
||||||
@@ -921,7 +909,7 @@ add_firewall_rule() {
|
|||||||
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
|
add_port_rules "$ip6t_m -A PSW2_OUTPUT -p udp" $UDP_REDIR_PORTS "-j PSW2_RULE"
|
||||||
$ip6t_m -A PSW2 $(comment "${comment_l}") -p udp -i lo $(REDIRECT $REDIR_PORT TPROXY)
|
$ip6t_m -A PSW2 $(comment "${comment_l}") -p udp -i lo $(REDIRECT $REDIR_PORT TPROXY)
|
||||||
$ip6t_m -A PSW2 $(comment "${comment_l}") -p udp -i lo -j RETURN
|
$ip6t_m -A PSW2 $(comment "${comment_l}") -p udp -i lo -j RETURN
|
||||||
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -p udp -j PSW2_OUTPUT"
|
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) $(dst $IPSET_DIRECT6 !) -p udp -j PSW2_OUTPUT"
|
||||||
}
|
}
|
||||||
|
|
||||||
[ -d "${TMP_IFACE_PATH}" ] && {
|
[ -d "${TMP_IFACE_PATH}" ] && {
|
||||||
@@ -938,8 +926,10 @@ add_firewall_rule() {
|
|||||||
$ip6t_m -I OUTPUT $(comment "mangle-OUTPUT-PSW2") -o lo -j RETURN
|
$ip6t_m -I OUTPUT $(comment "mangle-OUTPUT-PSW2") -o lo -j RETURN
|
||||||
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -m mark --mark ${FWMARK} -j RETURN"
|
insert_rule_before "$ip6t_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW2) -m mark --mark ${FWMARK} -j RETURN"
|
||||||
|
|
||||||
$ipt_m -A PSW2 -p udp --dport 53 -j RETURN
|
$ipt_m -A PSW2 -p tcp --dport 53 -j ACCEPT
|
||||||
$ip6t_m -A PSW2 -p udp --dport 53 -j RETURN
|
$ipt_m -A PSW2 -p udp --dport 53 -j ACCEPT
|
||||||
|
$ip6t_m -A PSW2 -p tcp --dport 53 -j ACCEPT
|
||||||
|
$ip6t_m -A PSW2 -p udp --dport 53 -j ACCEPT
|
||||||
}
|
}
|
||||||
|
|
||||||
load_acl
|
load_acl
|
||||||
@@ -970,7 +960,7 @@ del_firewall_rule() {
|
|||||||
$ipt -D $chain $index 2>/dev/null
|
$ipt -D $chain $index 2>/dev/null
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
for chain in "PSW2" "PSW2_OUTPUT" "PSW2_DIVERT" "PSW2_DNS" "PSW2_RULE"; do
|
for chain in "PSW2" "PSW2_OUTPUT" "PSW2_DNS" "PSW2_RULE"; do
|
||||||
$ipt -F $chain 2>/dev/null
|
$ipt -F $chain 2>/dev/null
|
||||||
$ipt -X $chain 2>/dev/null
|
$ipt -X $chain 2>/dev/null
|
||||||
done
|
done
|
||||||
@@ -1004,7 +994,7 @@ gen_include() {
|
|||||||
[ -z "${_ipt}" ] && return
|
[ -z "${_ipt}" ] && return
|
||||||
|
|
||||||
echo "*$2"
|
echo "*$2"
|
||||||
${_ipt}-save -t $2 | grep "PSW2" | grep -v "\-j PSW2$" | grep -v "socket \-j PSW2_DIVERT$" | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
|
${_ipt}-save -t $2 | grep "PSW2" | grep -v "\-j PSW2$" | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
|
||||||
echo 'COMMIT'
|
echo 'COMMIT'
|
||||||
}
|
}
|
||||||
local __ipt=""
|
local __ipt=""
|
||||||
@@ -1017,11 +1007,10 @@ gen_include() {
|
|||||||
$(extract_rules 4 mangle)
|
$(extract_rules 4 mangle)
|
||||||
EOT
|
EOT
|
||||||
|
|
||||||
[ "$accept_icmp" = "1" ] && \$(${MY_PATH} insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "-p icmp -j PSW2")
|
[ "$accept_icmp" = "1" ] && \$(${MY_PATH} insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "$(dst $IPSET_DIRECT !) -p icmp -j PSW2")
|
||||||
[ -z "${is_tproxy}" ] && \$(${MY_PATH} insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "-p tcp -j PSW2")
|
[ -z "${is_tproxy}" ] && \$(${MY_PATH} insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "$(dst $IPSET_DIRECT !) -p tcp -j PSW2")
|
||||||
|
|
||||||
\$(${MY_PATH} insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "-j PSW2")
|
\$(${MY_PATH} insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "$(dst $IPSET_DIRECT !) -j PSW2")
|
||||||
\$(${MY_PATH} insert_rule_before "$ipt_m" "PREROUTING" "PSW2" "-p tcp -m socket -j PSW2_DIVERT")
|
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1035,10 +1024,9 @@ gen_include() {
|
|||||||
$(extract_rules 6 mangle)
|
$(extract_rules 6 mangle)
|
||||||
EOT
|
EOT
|
||||||
|
|
||||||
[ "$accept_icmpv6" = "1" ] && $ip6t_n -A PREROUTING -p ipv6-icmp -j PSW2
|
[ "$accept_icmpv6" = "1" ] && $ip6t_n -A PREROUTING $(dst $IPSET_DIRECT6 !) -p ipv6-icmp -j PSW2
|
||||||
|
|
||||||
\$(${MY_PATH} insert_rule_before "$ip6t_m" "PREROUTING" "mwan3" "-j PSW2")
|
\$(${MY_PATH} insert_rule_before "$ip6t_m" "PREROUTING" "mwan3" "$(dst $IPSET_DIRECT6 !) -j PSW2")
|
||||||
\$(${MY_PATH} insert_rule_before "$ip6t_m" "PREROUTING" "PSW2" "-p tcp -m socket -j PSW2_DIVERT")
|
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,7 +231,9 @@ gen_shunt_list() {
|
|||||||
local default_outbound="redirect"
|
local default_outbound="redirect"
|
||||||
[ "$default_node" = "_direct" ] && default_outbound="direct"
|
[ "$default_node" = "_direct" ] && default_outbound="direct"
|
||||||
local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
|
local shunt_ids=$(uci show $CONFIG | grep "=shunt_rules" | awk -F '.' '{print $2}' | awk -F '=' '{print $1}')
|
||||||
|
local shunt_group=$(config_n_get $node shunt_group)
|
||||||
for shunt_id in $shunt_ids; do
|
for shunt_id in $shunt_ids; do
|
||||||
|
[ "${shunt_group}" != "$(config_n_get ${shunt_id} group)" ] && continue
|
||||||
local shunt_node=$(config_n_get ${node} "${shunt_id}")
|
local shunt_node=$(config_n_get ${node} "${shunt_id}")
|
||||||
[ -n "$shunt_node" ] && {
|
[ -n "$shunt_node" ] && {
|
||||||
local nftset_v4="psw2_${node}_${shunt_id}"
|
local nftset_v4="psw2_${node}_${shunt_id}"
|
||||||
@@ -700,13 +702,13 @@ add_firewall_rule() {
|
|||||||
|
|
||||||
for ip in $(cat /usr/share/passwall2/direct_ip | tr -s "\r\n" "\n" | grep -v "^#" | sed -e "/^$/d"); do
|
for ip in $(cat /usr/share/passwall2/direct_ip | tr -s "\r\n" "\n" | grep -v "^#" | sed -e "/^$/d"); do
|
||||||
if [[ "$ip" == *::* ]]; then
|
if [[ "$ip" == *::* ]]; then
|
||||||
echo "$ip" | insert_nftset $NFTSET_DIRECT6 0
|
echo "$ip" | insert_nftset $NFTSET_DIRECT6 "-1"
|
||||||
elif [[ "$ip" == "geoip:"* ]]; then
|
elif [[ "$ip" == "geoip:"* ]]; then
|
||||||
local _geoip_code=$(echo $ip | awk -F ':' '{print $2}')
|
local _geoip_code=$(echo $ip | awk -F ':' '{print $2}')
|
||||||
get_geoip $_geoip_code ipv4 | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_DIRECT "0"
|
get_geoip $_geoip_code ipv4 | grep -E "(\.((2(5[0-5]|[0-4][0-9]))|[0-1]?[0-9]{1,2})){3}" | insert_nftset $NFTSET_DIRECT "-1"
|
||||||
get_geoip $_geoip_code ipv6 | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_DIRECT6 "0"
|
get_geoip $_geoip_code ipv6 | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}" | insert_nftset $NFTSET_DIRECT6 "-1"
|
||||||
else
|
else
|
||||||
echo "$ip" | insert_nftset $NFTSET_DIRECT 0
|
echo "$ip" | insert_nftset $NFTSET_DIRECT "-1"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -726,14 +728,14 @@ add_firewall_rule() {
|
|||||||
update_wan_sets
|
update_wan_sets
|
||||||
|
|
||||||
[ -n "$ISP_DNS" ] && {
|
[ -n "$ISP_DNS" ] && {
|
||||||
echo "$ISP_DNS" | insert_nftset $NFTSET_DIRECT 0
|
echo "$ISP_DNS" | insert_nftset $NFTSET_DIRECT "-1"
|
||||||
for ispip in $ISP_DNS; do
|
for ispip in $ISP_DNS; do
|
||||||
log_i18n 1 "$(i18n "Add ISP %s DNS to the whitelist: %s" "IPv4" "${ispip}")"
|
log_i18n 1 "$(i18n "Add ISP %s DNS to the whitelist: %s" "IPv4" "${ispip}")"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
[ -n "$ISP_DNS6" ] && {
|
[ -n "$ISP_DNS6" ] && {
|
||||||
echo $ISP_DNS6 | insert_nftset $NFTSET_DIRECT6 0
|
echo $ISP_DNS6 | insert_nftset $NFTSET_DIRECT6 "-1"
|
||||||
for ispip6 in $ISP_DNS6; do
|
for ispip6 in $ISP_DNS6; do
|
||||||
log_i18n 1 "$(i18n "Add ISP %s DNS to the whitelist: %s" "IPv6" "${ispip6}")"
|
log_i18n 1 "$(i18n "Add ISP %s DNS to the whitelist: %s" "IPv6" "${ispip6}")"
|
||||||
done
|
done
|
||||||
@@ -762,11 +764,6 @@ add_firewall_rule() {
|
|||||||
nft_output_chain="PSW2_OUTPUT_MANGLE"
|
nft_output_chain="PSW2_OUTPUT_MANGLE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
nft "add chain $NFTABLE_NAME PSW2_DIVERT"
|
|
||||||
nft "flush chain $NFTABLE_NAME PSW2_DIVERT"
|
|
||||||
# Only TCP, UDP Invalid.
|
|
||||||
nft "add rule $NFTABLE_NAME PSW2_DIVERT meta l4proto tcp socket transparent 1 mark set ${FWMARK} counter accept"
|
|
||||||
|
|
||||||
nft "add chain $NFTABLE_NAME PSW2_DNS"
|
nft "add chain $NFTABLE_NAME PSW2_DNS"
|
||||||
nft "flush chain $NFTABLE_NAME PSW2_DNS"
|
nft "flush chain $NFTABLE_NAME PSW2_DNS"
|
||||||
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
|
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
|
||||||
@@ -790,33 +787,29 @@ add_firewall_rule() {
|
|||||||
#ipv4 tproxy mode and udp
|
#ipv4 tproxy mode and udp
|
||||||
nft "add chain $NFTABLE_NAME PSW2_MANGLE"
|
nft "add chain $NFTABLE_NAME PSW2_MANGLE"
|
||||||
nft "flush chain $NFTABLE_NAME PSW2_MANGLE"
|
nft "flush chain $NFTABLE_NAME PSW2_MANGLE"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip daddr @$NFTSET_DIRECT counter return"
|
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip daddr @$NFTSET_VPS counter return"
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip daddr @$NFTSET_VPS counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE ct direction reply counter return"
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE ct direction reply counter return"
|
||||||
|
|
||||||
nft "add chain $NFTABLE_NAME PSW2_OUTPUT_MANGLE"
|
nft "add chain $NFTABLE_NAME PSW2_OUTPUT_MANGLE"
|
||||||
nft "flush chain $NFTABLE_NAME PSW2_OUTPUT_MANGLE"
|
nft "flush chain $NFTABLE_NAME PSW2_OUTPUT_MANGLE"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip daddr @$NFTSET_DIRECT counter return"
|
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip daddr @$NFTSET_VPS counter return"
|
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip daddr @$NFTSET_VPS counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ct direction reply counter return"
|
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ct direction reply counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE meta mark 255 counter return"
|
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE meta mark 255 counter return"
|
||||||
|
|
||||||
# jump chains
|
# jump chains
|
||||||
nft "add rule $NFTABLE_NAME mangle_prerouting counter jump PSW2_DIVERT"
|
# Only TCP, UDP Invalid.
|
||||||
nft "add rule $NFTABLE_NAME mangle_prerouting ip protocol udp counter jump PSW2_MANGLE"
|
nft "add rule $NFTABLE_NAME mangle_prerouting meta nfproto ipv4 meta l4proto tcp socket transparent 1 mark set ${FWMARK} counter accept"
|
||||||
[ -n "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME mangle_prerouting ip protocol tcp counter jump PSW2_MANGLE"
|
nft "add rule $NFTABLE_NAME mangle_prerouting ip daddr != @$NFTSET_DIRECT ip protocol udp counter jump PSW2_MANGLE"
|
||||||
|
[ -n "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME mangle_prerouting ip daddr != @$NFTSET_DIRECT ip protocol tcp counter jump PSW2_MANGLE"
|
||||||
|
|
||||||
#ipv4 tcp redirect mode
|
#ipv4 tcp redirect mode
|
||||||
[ -z "${is_tproxy}" ] && {
|
[ -z "${is_tproxy}" ] && {
|
||||||
nft "add chain $NFTABLE_NAME PSW2_NAT"
|
nft "add chain $NFTABLE_NAME PSW2_NAT"
|
||||||
nft "flush chain $NFTABLE_NAME PSW2_NAT"
|
nft "flush chain $NFTABLE_NAME PSW2_NAT"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_NAT ip daddr @$NFTSET_DIRECT counter return"
|
|
||||||
nft "add rule $NFTABLE_NAME PSW2_NAT ip daddr @$NFTSET_VPS counter return"
|
nft "add rule $NFTABLE_NAME PSW2_NAT ip daddr @$NFTSET_VPS counter return"
|
||||||
nft "add rule $NFTABLE_NAME dstnat ip protocol tcp counter jump PSW2_NAT"
|
nft "add rule $NFTABLE_NAME dstnat ip daddr != @$NFTSET_DIRECT ip protocol tcp counter jump PSW2_NAT"
|
||||||
|
|
||||||
nft "add chain $NFTABLE_NAME PSW2_OUTPUT_NAT"
|
nft "add chain $NFTABLE_NAME PSW2_OUTPUT_NAT"
|
||||||
nft "flush chain $NFTABLE_NAME PSW2_OUTPUT_NAT"
|
nft "flush chain $NFTABLE_NAME PSW2_OUTPUT_NAT"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_NAT ip daddr @$NFTSET_DIRECT counter return"
|
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_NAT ip daddr @$NFTSET_VPS counter return"
|
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_NAT ip daddr @$NFTSET_VPS counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_NAT meta mark 255 counter return"
|
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_NAT meta mark 255 counter return"
|
||||||
}
|
}
|
||||||
@@ -825,16 +818,16 @@ add_firewall_rule() {
|
|||||||
if [ "$accept_icmp" = "1" ]; then
|
if [ "$accept_icmp" = "1" ]; then
|
||||||
nft "add chain $NFTABLE_NAME PSW2_ICMP_REDIRECT"
|
nft "add chain $NFTABLE_NAME PSW2_ICMP_REDIRECT"
|
||||||
nft "flush chain $NFTABLE_NAME PSW2_ICMP_REDIRECT"
|
nft "flush chain $NFTABLE_NAME PSW2_ICMP_REDIRECT"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT ip daddr @$NFTSET_DIRECT counter return"
|
|
||||||
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT ip daddr @$NFTSET_VPS counter return"
|
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT ip daddr @$NFTSET_VPS counter return"
|
||||||
|
|
||||||
[ "$accept_icmpv6" = "1" ] && {
|
[ "$accept_icmpv6" = "1" ] && {
|
||||||
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT ip6 daddr @$NFTSET_DIRECT6 counter return"
|
|
||||||
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT ip6 daddr @$NFTSET_VPS6 counter return"
|
nft "add rule $NFTABLE_NAME PSW2_ICMP_REDIRECT ip6 daddr @$NFTSET_VPS6 counter return"
|
||||||
}
|
}
|
||||||
|
|
||||||
nft "add rule $NFTABLE_NAME dstnat meta l4proto {icmp,icmpv6} counter jump PSW2_ICMP_REDIRECT"
|
nft "add rule $NFTABLE_NAME dstnat ip daddr != @$NFTSET_DIRECT meta l4proto icmp counter jump PSW2_ICMP_REDIRECT"
|
||||||
nft "add rule $NFTABLE_NAME nat_output meta l4proto {icmp,icmpv6} counter jump PSW2_ICMP_REDIRECT"
|
nft "add rule $NFTABLE_NAME dstnat ip6 daddr != @$NFTSET_DIRECT6 meta l4proto icmpv6 counter jump PSW2_ICMP_REDIRECT"
|
||||||
|
nft "add rule $NFTABLE_NAME nat_output ip daddr != @$NFTSET_DIRECT meta l4proto icmp counter jump PSW2_ICMP_REDIRECT"
|
||||||
|
nft "add rule $NFTABLE_NAME nat_output ip6 daddr != @$NFTSET_DIRECT6 meta l4proto icmpv6 counter jump PSW2_ICMP_REDIRECT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#ipv4 wan_ip
|
#ipv4 wan_ip
|
||||||
@@ -847,13 +840,11 @@ add_firewall_rule() {
|
|||||||
#ipv6 tproxy mode and udp
|
#ipv6 tproxy mode and udp
|
||||||
nft "add chain $NFTABLE_NAME PSW2_MANGLE_V6"
|
nft "add chain $NFTABLE_NAME PSW2_MANGLE_V6"
|
||||||
nft "flush chain $NFTABLE_NAME PSW2_MANGLE_V6"
|
nft "flush chain $NFTABLE_NAME PSW2_MANGLE_V6"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 ip6 daddr @$NFTSET_DIRECT6 counter return"
|
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 ct direction reply counter return"
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 ct direction reply counter return"
|
||||||
|
|
||||||
nft "add chain $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6"
|
nft "add chain $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6"
|
||||||
nft "flush chain $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6"
|
nft "flush chain $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_DIRECT6 counter return"
|
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
|
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ct direction reply counter return"
|
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 ct direction reply counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta mark 255 counter return"
|
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta mark 255 counter return"
|
||||||
@@ -874,8 +865,10 @@ add_firewall_rule() {
|
|||||||
|
|
||||||
# jump chains
|
# jump chains
|
||||||
[ "$PROXY_IPV6" == "1" ] && {
|
[ "$PROXY_IPV6" == "1" ] && {
|
||||||
nft "add rule $NFTABLE_NAME mangle_prerouting meta nfproto {ipv6} counter jump PSW2_MANGLE_V6"
|
# Only TCP, UDP Invalid.
|
||||||
nft "add rule $NFTABLE_NAME mangle_output meta nfproto {ipv6} counter jump PSW2_OUTPUT_MANGLE_V6 comment \"PSW2_OUTPUT_MANGLE\""
|
nft "add rule $NFTABLE_NAME mangle_prerouting meta nfproto ipv6 meta l4proto tcp socket transparent 1 mark set ${FWMARK} counter accept"
|
||||||
|
nft "add rule $NFTABLE_NAME mangle_prerouting ip6 daddr != @$NFTSET_DIRECT6 meta nfproto {ipv6} counter jump PSW2_MANGLE_V6"
|
||||||
|
nft "add rule $NFTABLE_NAME mangle_output ip6 daddr != @$NFTSET_DIRECT6 meta nfproto {ipv6} counter jump PSW2_OUTPUT_MANGLE_V6 comment \"PSW2_OUTPUT_MANGLE\""
|
||||||
|
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 ip6 daddr @$NFTSET_WAN6 counter return comment \"WAN6_IP_RETURN\""
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 ip6 daddr @$NFTSET_WAN6 counter return comment \"WAN6_IP_RETURN\""
|
||||||
|
|
||||||
@@ -948,11 +941,11 @@ add_firewall_rule() {
|
|||||||
nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp ip daddr $FAKE_IP ${nft_j}"
|
nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp ip daddr $FAKE_IP ${nft_j}"
|
||||||
add_shunt_t_rule "${SHUNT_LIST4}" "nft add rule $NFTABLE_NAME $nft_chain ip protocol tcp $(factor $TCP_REDIR_PORTS "tcp dport") ip daddr" "${nft_j}"
|
add_shunt_t_rule "${SHUNT_LIST4}" "nft add rule $NFTABLE_NAME $nft_chain ip protocol tcp $(factor $TCP_REDIR_PORTS "tcp dport") ip daddr" "${nft_j}"
|
||||||
nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp $(factor $TCP_REDIR_PORTS "tcp dport") ${nft_j}"
|
nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp $(factor $TCP_REDIR_PORTS "tcp dport") ${nft_j}"
|
||||||
[ -z "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME nat_output ip protocol tcp counter jump PSW2_OUTPUT_NAT"
|
[ -z "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME nat_output ip daddr != @$NFTSET_DIRECT ip protocol tcp counter jump PSW2_OUTPUT_NAT"
|
||||||
[ -n "${is_tproxy}" ] && {
|
[ -n "${is_tproxy}" ] && {
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp iif lo $(REDIRECT $REDIR_PORT TPROXY4) comment \"${comment_l}\""
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp iif lo $(REDIRECT $REDIR_PORT TPROXY4) comment \"${comment_l}\""
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp iif lo counter return comment \"${comment_l}\""
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp iif lo counter return comment \"${comment_l}\""
|
||||||
nft "add rule $NFTABLE_NAME mangle_output ip protocol tcp counter jump PSW2_OUTPUT_MANGLE comment \"PSW2_OUTPUT_MANGLE\""
|
nft "add rule $NFTABLE_NAME mangle_output ip daddr != @$NFTSET_DIRECT ip protocol tcp counter jump PSW2_OUTPUT_MANGLE comment \"PSW2_OUTPUT_MANGLE\""
|
||||||
}
|
}
|
||||||
|
|
||||||
[ "$PROXY_IPV6" == "1" ] && {
|
[ "$PROXY_IPV6" == "1" ] && {
|
||||||
@@ -978,7 +971,7 @@ add_firewall_rule() {
|
|||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol udp $(factor $UDP_REDIR_PORTS "udp dport") counter jump PSW2_RULE"
|
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE ip protocol udp $(factor $UDP_REDIR_PORTS "udp dport") counter jump PSW2_RULE"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp iif lo $(REDIRECT $REDIR_PORT TPROXY4) comment \"${comment_l}\""
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp iif lo $(REDIRECT $REDIR_PORT TPROXY4) comment \"${comment_l}\""
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp iif lo counter return comment \"${comment_l}\""
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp iif lo counter return comment \"${comment_l}\""
|
||||||
nft "add rule $NFTABLE_NAME mangle_output ip protocol udp counter jump PSW2_OUTPUT_MANGLE comment \"PSW2_OUTPUT_MANGLE\""
|
nft "add rule $NFTABLE_NAME mangle_output ip daddr != @$NFTSET_DIRECT ip protocol udp counter jump PSW2_OUTPUT_MANGLE comment \"PSW2_OUTPUT_MANGLE\""
|
||||||
|
|
||||||
[ "$PROXY_IPV6" == "1" ] && {
|
[ "$PROXY_IPV6" == "1" ] && {
|
||||||
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp ip6 daddr $FAKE_IP_6 jump PSW2_RULE"
|
nft "add rule $NFTABLE_NAME PSW2_OUTPUT_MANGLE_V6 meta l4proto udp ip6 daddr $FAKE_IP_6 jump PSW2_RULE"
|
||||||
@@ -996,11 +989,13 @@ add_firewall_rule() {
|
|||||||
}
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
nft "add rule $NFTABLE_NAME mangle_output oif lo counter return comment \"PSW2_OUTPUT_MANGLE\""
|
nft "add rule $NFTABLE_NAME mangle_output ip daddr != @$NFTSET_DIRECT oif lo counter return comment \"PSW2_OUTPUT_MANGLE\""
|
||||||
nft "add rule $NFTABLE_NAME mangle_output meta mark ${FWMARK} counter return comment \"PSW2_OUTPUT_MANGLE\""
|
nft "add rule $NFTABLE_NAME mangle_output ip daddr != @$NFTSET_DIRECT meta mark ${FWMARK} counter return comment \"PSW2_OUTPUT_MANGLE\""
|
||||||
|
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp udp dport 53 counter return"
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol tcp tcp dport 53 counter accept"
|
||||||
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp udp dport 53 counter return"
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE ip protocol udp udp dport 53 counter accept"
|
||||||
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto tcp tcp dport 53 counter accept"
|
||||||
|
nft "add rule $NFTABLE_NAME PSW2_MANGLE_V6 meta l4proto udp udp dport 53 counter accept"
|
||||||
}
|
}
|
||||||
|
|
||||||
load_acl
|
load_acl
|
||||||
|
|||||||
@@ -126,7 +126,11 @@ test_auto_switch() {
|
|||||||
# If the current node is not found, or if the current node is the last node, then take the first node.
|
# If the current node is not found, or if the current node is the last node, then take the first node.
|
||||||
[ -z "$new_node" ] && new_node="$first_node"
|
[ -z "$new_node" ] && new_node="$first_node"
|
||||||
local msg2="$(i18n "next backup node")"
|
local msg2="$(i18n "next backup node")"
|
||||||
[ "$now_node" = "$main_node" ] && msg2="$(i18n "backup node")"
|
if [ "$new_node" = "$main_node" ]; then
|
||||||
|
msg2="$(i18n "main node")"
|
||||||
|
else
|
||||||
|
[ "$now_node" = "$main_node" ] && msg2="$(i18n "backup node")"
|
||||||
|
fi
|
||||||
msg="$(i18n "switch to %s test detect!" "${msg2}")"
|
msg="$(i18n "switch to %s test detect!" "${msg2}")"
|
||||||
else
|
else
|
||||||
# When there is only one backup node, poll with the primary node.
|
# When there is only one backup node, poll with the primary node.
|
||||||
@@ -138,11 +142,6 @@ test_auto_switch() {
|
|||||||
log_i18n 0 "Socks switch detection: %s 【%s:[%s]】 abnormal, %s" "${id}" "$(config_n_get $now_node type)" "$(config_n_get $now_node remarks)" "${msg}"
|
log_i18n 0 "Socks switch detection: %s 【%s:[%s]】 abnormal, %s" "${id}" "$(config_n_get $now_node type)" "$(config_n_get $now_node remarks)" "${msg}"
|
||||||
test_node ${new_node}
|
test_node ${new_node}
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
# [ "$restore_switch" = "0" ] && {
|
|
||||||
# uci set $CONFIG.${id}.node=$new_node
|
|
||||||
# [ -z "$(echo $b_nodes | grep $main_node)" ] && uci add_list $CONFIG.${id}.autoswitch_backup_node=$main_node
|
|
||||||
# uci commit $CONFIG
|
|
||||||
# }
|
|
||||||
check_process
|
check_process
|
||||||
log_i18n 0 "Socks switch detection: %s 【%s:[%s]】 normal, switch to this node!" "${id}" "$(config_n_get $new_node type)" "$(config_n_get $new_node remarks)"
|
log_i18n 0 "Socks switch detection: %s 【%s:[%s]】 normal, switch to this node!" "${id}" "$(config_n_get $new_node type)" "$(config_n_get $new_node remarks)"
|
||||||
$APP_FILE socks_node_switch flag=${id} new_node=${new_node}
|
$APP_FILE socks_node_switch flag=${id} new_node=${new_node}
|
||||||
@@ -171,6 +170,10 @@ start() {
|
|||||||
backup_node_num=$(printf "%s\n" "$backup_node" | wc -w)
|
backup_node_num=$(printf "%s\n" "$backup_node" | wc -w)
|
||||||
if [ "$backup_node_num" -eq 1 ]; then
|
if [ "$backup_node_num" -eq 1 ]; then
|
||||||
[ "$main_node" = "$backup_node" ] && return
|
[ "$main_node" = "$backup_node" ] && return
|
||||||
|
elif [ "$backup_node_num" -gt 1 ]; then
|
||||||
|
[ "$restore_switch" != "1" ] && {
|
||||||
|
[ -z "$(echo $backup_node | grep -F "$main_node")" ] && backup_node="${backup_node} ${main_node}"
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -768,6 +768,9 @@ local function parseClashNode(node, add_mode, group, sub_cfg)
|
|||||||
result.reality_publicKey = node["reality-opts"]["public-key"]
|
result.reality_publicKey = node["reality-opts"]["public-key"]
|
||||||
result.reality_shortId = node["reality-opts"]["short-id"]
|
result.reality_shortId = node["reality-opts"]["short-id"]
|
||||||
end
|
end
|
||||||
|
if node["disable-reuse"] then
|
||||||
|
result.anytls_disable_reuse = "1"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if not result.remarks or result.remarks == "" then
|
if not result.remarks or result.remarks == "" then
|
||||||
if result.address and result.port then
|
if result.address and result.port then
|
||||||
@@ -1865,7 +1868,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
|||||||
end
|
end
|
||||||
if params.security == "tls" or params.security == "reality" then
|
if params.security == "tls" or params.security == "reality" then
|
||||||
result.tls = "1"
|
result.tls = "1"
|
||||||
result.tls_serverName = params.sni
|
result.tls_serverName = params.sni or params.peer
|
||||||
result.alpn = params.alpn
|
result.alpn = params.alpn
|
||||||
if params.fp and params.fp ~= "" then
|
if params.fp and params.fp ~= "" then
|
||||||
result.utls = "1"
|
result.utls = "1"
|
||||||
|
|||||||
Reference in new issue
Block a user