update 2026-08-25 00:29:42

This commit is contained in:
action committed 2026-08-25 00:29:42 +08:00
1 parent 0f2308381e
commit c37bb21446
44 files changed
+4642 -4640

No files matched your search

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 389 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 640 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 550 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 547 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 659 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

@@ -25,25 +25,25 @@ o:value("https://wifi.vivo.com.cn/generate_204", "VIVO (CN)")
o.default = o.keylist[3] o.default = o.keylist[3]
if true then if true then
m:appendTemplate("/node_list/node_list") m:appendTemplate("/node_list/node_list")
if luci.http.formvalue("cbi.submit") == "1" then if luci.http.formvalue("cbi.submit") == "1" then
local group_order = {} local group_order = {}
group_order = luci.http.formvaluetable("group.order") group_order = luci.http.formvaluetable("group.order")
if group_order then if group_order then
for k, v in pairs(group_order) do for k, v in pairs(group_order) do
if v and v~= "" then if v and v~= "" then
local new_order = {} local new_order = {}
string.gsub(v, "[^" .. " " .. "]+", function(w) string.gsub(v, "[^" .. " " .. "]+", function(w)
new_order[#new_order + 1] = w new_order[#new_order + 1] = w
end) end)
for idx, name in ipairs(new_order) do for idx, name in ipairs(new_order) do
m.uci:reorder(m.config, name, idx - 1) m.uci:reorder(m.config, name, idx - 1)
end end
end end
end end
end end
end end
end end
return api.return_map(m) return api.return_map(m)
@@ -117,9 +117,9 @@ end
o = s:option(DummyValue, "_update", translate("Manual subscription All")) o = s:option(DummyValue, "_update", translate("Manual subscription All"))
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return string.format([[ return string.format([[
<input type="button" class="btn cbi-button cbi-button-apply" onclick="ManualSubscribeAll()" value="%s" />]], <input type="button" class="btn cbi-button cbi-button-apply" onclick="ManualSubscribeAll()" value="%s" />]],
translate("Manual subscription All")) translate("Manual subscription All"))
end end
s = m:section(TypedSection, "subscribe_list", "", "<font color='red'>" .. translate("When adding a new subscription, please save and apply before manually subscribing. If you only change the subscription URL, you can subscribe manually, and the system will save it automatically.") .. "</font>") s = m:section(TypedSection, "subscribe_list", "", "<font color='red'>" .. translate("When adding a new subscription, please save and apply before manually subscribing. If you only change the subscription URL, you can subscribe manually, and the system will save it automatically.") .. "</font>")
@@ -215,9 +215,9 @@ end
o = s:option(DummyValue, "_update", translate("Manual subscription")) o = s:option(DummyValue, "_update", translate("Manual subscription"))
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return string.format([[ return string.format([[
<input type="button" class="btn cbi-button cbi-button-apply" onclick="ManualSubscribe('%s')" value="%s" />]], <input type="button" class="btn cbi-button cbi-button-apply" onclick="ManualSubscribe('%s')" value="%s" />]],
section, translate("Manual subscription")) section, translate("Manual subscription"))
end end
m:appendTemplate("/cbi/sortable", {sectiontype = s.sectiontype}) m:appendTemplate("/cbi/sortable", {sectiontype = s.sectiontype})
@@ -161,6 +161,7 @@ local function start()
end) end)
if firewall_num > 0 then if firewall_num > 0 then
api.uci_save(uci, "firewall", true, true) api.uci_save(uci, "firewall", true, true)
cmd("/etc/init.d/firewall reload >/dev/null 2>&1")
end end
end end
@@ -176,6 +177,7 @@ local function stop()
end) end)
if num > 0 then if num > 0 then
api.uci_save(uci, "firewall", true, true) api.uci_save(uci, "firewall", true, true)
cmd("/etc/init.d/firewall reload >/dev/null 2>&1")
end end
end end
cmd(string.format("rm -rf %s %s", CONFIG_PATH, LOG_APP_FILE)) cmd(string.format("rm -rf %s %s", CONFIG_PATH, LOG_APP_FILE))
@@ -916,12 +916,12 @@ function gen_config(var)
if xray_settings.fragment == "1" then if xray_settings.fragment == "1" then
local lengths, delays = {}, {} local lengths, delays = {}, {}
api.trim(xray_settings.fragment_lengths):gsub("[^,]+", function(w) api.trim(xray_settings.fragment_lengths):gsub("[^,]+", function(w)
w = w:gsub("%s+", "") w = w:gsub("%s+", "")
if w ~= "" then lengths[#lengths+1] = w end if w ~= "" then lengths[#lengths+1] = w end
end) end)
api.trim(xray_settings.fragment_delays):gsub("[^,]+", function(w) api.trim(xray_settings.fragment_delays):gsub("[^,]+", function(w)
w = w:gsub("%s+", "") w = w:gsub("%s+", "")
if w ~= "" then delays[#delays+1] = w end if w ~= "" then delays[#delays+1] = w end
end) end)
fragment_table = { fragment_table = {
type = "fragment", type = "fragment",
@@ -534,7 +534,7 @@
//自定义框 //自定义框
function v_customEnter(cbid, labelSpan, hiddenInput, searchInput, panel, listContainer, customInput) { function v_customEnter(cbid, labelSpan, hiddenInput, searchInput, panel, listContainer, customInput) {
let inputValue = customInput.value.trim(); let inputValue = customInput.value.trim();
if (!inputValue) { if (!inputValue) {
return; return;
} }
const existingItems = listContainer.querySelectorAll('li[data-key="' + inputValue + '"]'); const existingItems = listContainer.querySelectorAll('li[data-key="' + inputValue + '"]');
@@ -3,42 +3,42 @@ local map = self.map
local api = map.api local api = map.api
-%> -%>
<style> <style>
.dns-con { .dns-con {
padding: 1rem; padding: 1rem;
} }
.faq-title { .faq-title {
color: var(--primary); color: var(--primary);
font-weight: bolder; font-weight: bolder;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
display: inline-block; display: inline-block;
} }
.reset-title { .reset-title {
color: var(--primary); color: var(--primary);
font-weight: bolder; font-weight: bolder;
margin-bottom: 0.3rem; margin-bottom: 0.3rem;
display: inline-block; display: inline-block;
margin-top: 1.2rem; margin-top: 1.2rem;
text-decoration: underline; text-decoration: underline;
} }
.dns-item { .dns-item {
margin-bottom: 0.8rem; margin-bottom: 0.8rem;
line-height:1.2rem; line-height:1.2rem;
} }
.dns-list { .dns-list {
text-indent:1rem; text-indent:1rem;
line-height: 1.2rem; line-height: 1.2rem;
} }
</style> </style>
<div class="dns-con"> <div class="dns-con">
<div id="faq_dns"> <div id="faq_dns">
<ul> <ul>
<b class="faq-title"><%:DNS related issues:%></b> <b class="faq-title"><%:DNS related issues:%></b>
<li class="dns-item">1. <span><%:Certain browsers such as Chrome have built-in DNS service, which may affect DNS resolution settings. You can go to 'Settings -> Privacy and security -> Use secure DNS' menu to turn it off.%></span></li> <li class="dns-item">1. <span><%:Certain browsers such as Chrome have built-in DNS service, which may affect DNS resolution settings. You can go to 'Settings -> Privacy and security -> Use secure DNS' menu to turn it off.%></span></li>
<li class="dns-item">2. <span><%:If you are unable to access the internet after reboot, please try clearing the cache of your terminal devices (make sure to close all open browser application windows first, this step is especially important):%></span> <li class="dns-item">2. <span><%:If you are unable to access the internet after reboot, please try clearing the cache of your terminal devices (make sure to close all open browser application windows first, this step is especially important):%></span>
<ul><li class="dns-list"> ◦ <span><%:For Windows systems, open Command Prompt and run the command 'ipconfig /flushdns'.%></span></li> <ul><li class="dns-list"> ◦ <span><%:For Windows systems, open Command Prompt and run the command 'ipconfig /flushdns'.%></span></li>
<li class="dns-list"> ◦ <span><%:For Mac systems, open Terminal and run the command 'sudo killall -HUP mDNSResponder'.%></span></li> <li class="dns-list"> ◦ <span><%:For Mac systems, open Terminal and run the command 'sudo killall -HUP mDNSResponder'.%></span></li>
<li class="dns-list"> ◦ <span><%:For mobile devices, you can clear it by reconnecting to the network, such as toggling Airplane Mode and reconnecting to WiFi.%></span></li> <li class="dns-list"> ◦ <span><%:For mobile devices, you can clear it by reconnecting to the network, such as toggling Airplane Mode and reconnecting to WiFi.%></span></li>
</ul> </ul>
</li> </li>
<li class="dns-item">3. <span><%:Please make sure your device's network settings point both the DNS server and default gateway to this router, to ensure DNS queries are properly routed.%></span></li> <li class="dns-item">3. <span><%:Please make sure your device's network settings point both the DNS server and default gateway to this router, to ensure DNS queries are properly routed.%></span></li>
</ul> </ul>
@@ -58,7 +58,7 @@ local api = map.api
} }
var dom = document.getElementById("faq_reset"); var dom = document.getElementById("faq_reset");
if (dom) { if (dom) {
var li = ""; var li = "";
li += "<a href='#' class='reset-title' onclick='hide()'>" + "<%: Hide in main menu:%>"+ "</a>" + "<br />" + "<%: Browser access: %>" + "<a href='#' onclick='hide()'>" + hide_url + "</a>" + "<br />"; li += "<a href='#' class='reset-title' onclick='hide()'>" + "<%: Hide in main menu:%>"+ "</a>" + "<br />" + "<%: Browser access: %>" + "<a href='#' onclick='hide()'>" + hide_url + "</a>" + "<br />";
li += "<a href='#' class='reset-title'>" + "<%: Show in main menu:%>"+ "</a>" + "<br />" +"<%: Browser access: %>" + "<a href='#'>" + show_url + "</a>" + "<br />"; li += "<a href='#' class='reset-title'>" + "<%: Show in main menu:%>"+ "</a>" + "<br />" +"<%: Browser access: %>" + "<a href='#'>" + show_url + "</a>" + "<br />";
@@ -43,7 +43,7 @@ table td, .table .td {
z-index: 99; z-index: 99;
text-align: center; text-align: center;
background: white; background: white;
box-shadow: darkgrey 10px 10px 30px 5px; box-shadow: darkgrey 10px 10px 30px 5px;
text-align: center; text-align: center;
padding: 0.5em; padding: 0.5em;
} }
@@ -55,8 +55,8 @@ table td, .table .td {
.ping a, .ping a,
.ping_value a, .ping_value a,
.tcping_value a { .tcping_value a {
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
@@ -15,8 +15,8 @@ table th, .table .th {
table td, .table .td { table td, .table .td {
text-align: center; text-align: center;
/* white-space: nowrap; */ /* white-space: nowrap; */
word-break: keep-all; word-break: keep-all;
} }
.td.cbi-section-actions { .td.cbi-section-actions {
@@ -75,7 +75,7 @@ local api = map.api
if (!value) { if (!value) {
alert("<%:Please enter query content!%>"); alert("<%:Please enter query content!%>");
return; return;
} }
lookup_btn.disabled = true; lookup_btn.disabled = true;
extract_btn.disabled = true; extract_btn.disabled = true;
btn.value = '<%:Querying%>'; btn.value = '<%:Querying%>';
@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
if [ -e "/etc/config/ucitrack" ]; then if [ -e "/etc/config/ucitrack" ]; then
uci -q batch <<-EOF uci -q batch <<-EOF
delete ucitrack.@passwall[-1] delete ucitrack.@passwall[-1]
add ucitrack passwall add ucitrack passwall
set ucitrack.@passwall[-1].init=passwall set ucitrack.@passwall[-1].init=passwall
@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
if [ -e "/etc/config/ucitrack" ]; then if [ -e "/etc/config/ucitrack" ]; then
uci -q batch <<-EOF uci -q batch <<-EOF
delete ucitrack.@passwall_server[-1] delete ucitrack.@passwall_server[-1]
add ucitrack passwall_server add ucitrack passwall_server
set ucitrack.@passwall_server[-1].init=passwall_server set ucitrack.@passwall_server[-1].init=passwall_server
File diff suppressed because it is too large. Load diff
@@ -6,13 +6,13 @@ local geo_dir = (api.uci_get_c("@global_rules[0]", "v2ray_location_asset") or "/
local geosite_path = geo_dir .. "/geosite.dat" local geosite_path = geo_dir .. "/geosite.dat"
local geoip_path = geo_dir .. "/geoip.dat" local geoip_path = geo_dir .. "/geoip.dat"
if fs.access(geosite_path) and fs.access(geoip_path) then if fs.access(geosite_path) and fs.access(geoip_path) then
f = SimpleForm(api.c_config) f = SimpleForm(api.c_config)
f.reset = false f.reset = false
f.submit = false f.submit = false
local obj = Template(api.appname .. "/rule/geoview") local obj = Template(api.appname .. "/rule/geoview")
obj.api = api obj.api = api
f:append(obj) f:append(obj)
end end
return f return f
@@ -25,25 +25,25 @@ o:value("https://wifi.vivo.com.cn/generate_204", "VIVO (CN)")
o.default = o.keylist[3] o.default = o.keylist[3]
if true then if true then
m:appendTemplate("/node_list/node_list") m:appendTemplate("/node_list/node_list")
if luci.http.formvalue("cbi.submit") == "1" then if luci.http.formvalue("cbi.submit") == "1" then
local group_order = {} local group_order = {}
group_order = luci.http.formvaluetable("group.order") group_order = luci.http.formvaluetable("group.order")
if group_order then if group_order then
for k, v in pairs(group_order) do for k, v in pairs(group_order) do
if v and v~= "" then if v and v~= "" then
local new_order = {} local new_order = {}
string.gsub(v, "[^" .. " " .. "]+", function(w) string.gsub(v, "[^" .. " " .. "]+", function(w)
new_order[#new_order + 1] = w new_order[#new_order + 1] = w
end) end)
for idx, name in ipairs(new_order) do for idx, name in ipairs(new_order) do
m.uci:reorder(m.config, name, idx - 1) m.uci:reorder(m.config, name, idx - 1)
end end
end end
end end
end end
end end
end end
return api.return_map(m) return api.return_map(m)
@@ -112,8 +112,8 @@ end
o = s:option(DummyValue, "_update", translate("Manual subscription All")) o = s:option(DummyValue, "_update", translate("Manual subscription All"))
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return string.format([[ return string.format([[
<input type="button" class="btn cbi-button cbi-button-apply" onclick="ManualSubscribeAll()" value="%s" />]], <input type="button" class="btn cbi-button cbi-button-apply" onclick="ManualSubscribeAll()" value="%s" />]],
translate("Manual subscription All")) translate("Manual subscription All"))
end end
@@ -210,8 +210,8 @@ end
o = s:option(DummyValue, "_update", translate("Manual subscription")) o = s:option(DummyValue, "_update", translate("Manual subscription"))
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(self, section) o.cfgvalue = function(self, section)
return string.format([[ return string.format([[
<input type="button" class="btn cbi-button cbi-button-apply" onclick="ManualSubscribe('%s')" value="%s" />]], <input type="button" class="btn cbi-button cbi-button-apply" onclick="ManualSubscribe('%s')" value="%s" />]],
section, translate("Manual subscription")) section, translate("Manual subscription"))
end end
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1,68 +1,68 @@
if not api.is_finded("sslocal") then if not api.is_finded("sslocal") then
return return
end end
-- [[ Shadowsocks Rust ]] -- [[ Shadowsocks Rust ]]
local m, s1 = ... local m, s1 = ...
local type_name = "SS-Rust" local type_name = "SS-Rust"
s1.fields["type"]:value(type_name, "Shadowsocks Rust") s1.fields["type"]:value(type_name, "Shadowsocks Rust")
if s1.val["type"] ~= type_name then if s1.val["type"] ~= type_name then
return return
end end
local s = NamedSection(m, arg[1], "server") local s = NamedSection(m, arg[1], "server")
s.type_name = type_name s.type_name = type_name
s.option_prefix = "ssrust_" s.option_prefix = "ssrust_"
local ssrust_encrypt_method_list = { local ssrust_encrypt_method_list = {
"none", "plain", "none", "plain",
"aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha8-poly1305", "2022-blake3-chacha20-poly1305" "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha8-poly1305", "2022-blake3-chacha20-poly1305"
} }
o = s:option(Value, "address", translate("Address (Support Domain Name)")) o = s:option(Value, "address", translate("Address (Support Domain Name)"))
o = s:option(Value, "port", translate("Port")) o = s:option(Value, "port", translate("Port"))
o.datatype = "port" o.datatype = "port"
o = s:option(Value, "password", translate("Password")) o = s:option(Value, "password", translate("Password"))
o.password = true o.password = true
o = s:option(Value, "method", translate("Encrypt Method")) o = s:option(Value, "method", translate("Encrypt Method"))
for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end
o = s:option(Value, "timeout", translate("Connection Timeout")) o = s:option(Value, "timeout", translate("Connection Timeout"))
o.datatype = "uinteger" o.datatype = "uinteger"
o.default = 300 o.default = 300
o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"), translate("Need node support required")) o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"), translate("Need node support required"))
o.default = 0 o.default = 0
o = s:option(Flag, "plugin_enabled", translate("plugin")) o = s:option(Flag, "plugin_enabled", translate("plugin"))
o.default = 0 o.default = 0
o = s:option(Value, "plugin", "SIP003 " .. translate("plugin"), translate("Supports custom SIP003 plugins, Make sure the plugin is installed.")) o = s:option(Value, "plugin", "SIP003 " .. translate("plugin"), translate("Supports custom SIP003 plugins, Make sure the plugin is installed."))
o.default = "none" o.default = "none"
o:value("none", translate("none")) o:value("none", translate("none"))
if api.is_finded("xray-plugin") then o:value("xray-plugin") end if api.is_finded("xray-plugin") then o:value("xray-plugin") end
if api.is_finded("v2ray-plugin") then o:value("v2ray-plugin") end if api.is_finded("v2ray-plugin") then o:value("v2ray-plugin") end
if api.is_finded("obfs-local") then o:value("obfs-local") end if api.is_finded("obfs-local") then o:value("obfs-local") end
if api.is_finded("shadow-tls") then o:value("shadow-tls") end if api.is_finded("shadow-tls") then o:value("shadow-tls") end
o:depends({ plugin_enabled = true }) o:depends({ plugin_enabled = true })
o.validate = function(self, value, t) o.validate = function(self, value, t)
if value and value ~= "" and value ~= "none" then if value and value ~= "" and value ~= "none" then
if not api.is_finded(value) then if not api.is_finded(value) then
return nil, value .. ": " .. translate("Can't find this file!") return nil, value .. ": " .. translate("Can't find this file!")
else else
return value return value
end end
end end
return nil return nil
end end
o = s:option(Value, "plugin_opts", translate("opts")) o = s:option(Value, "plugin_opts", translate("opts"))
o:depends({ plugin_enabled = true }) o:depends({ plugin_enabled = true })
api.luci_types(s1, s) api.luci_types(s1, s)
@@ -1,66 +1,66 @@
if not api.is_finded("ssr-local") then if not api.is_finded("ssr-local") then
return return
end end
-- [[ ShadowsocksR Libev ]] -- [[ ShadowsocksR Libev ]]
local m, s1 = ... local m, s1 = ...
local type_name = "SSR" local type_name = "SSR"
s1.fields["type"]:value(type_name, "ShadowsocksR Libev") s1.fields["type"]:value(type_name, "ShadowsocksR Libev")
if s1.val["type"] ~= type_name then if s1.val["type"] ~= type_name then
return return
end end
local s = NamedSection(m, arg[1], "server") local s = NamedSection(m, arg[1], "server")
s.type_name = type_name s.type_name = type_name
s.option_prefix = "ssr_" s.option_prefix = "ssr_"
local ssr_encrypt_method_list = { local ssr_encrypt_method_list = {
"none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb", "none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb",
"aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr",
"bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb",
"cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20", "cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20",
"chacha20-ietf" "chacha20-ietf"
} }
local ssr_protocol_list = { local ssr_protocol_list = {
"origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple", "origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple",
"auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5", "auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5",
"auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c", "auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c",
"auth_chain_d", "auth_chain_e", "auth_chain_f" "auth_chain_d", "auth_chain_e", "auth_chain_f"
} }
local ssr_obfs_list = { local ssr_obfs_list = {
"plain", "http_simple", "http_post", "random_head", "tls_simple", "plain", "http_simple", "http_post", "random_head", "tls_simple",
"tls1.0_session_auth", "tls1.2_ticket_auth" "tls1.0_session_auth", "tls1.2_ticket_auth"
} }
o = s:option(Value, "address", translate("Address (Support Domain Name)")) o = s:option(Value, "address", translate("Address (Support Domain Name)"))
o = s:option(Value, "port", translate("Port")) o = s:option(Value, "port", translate("Port"))
o.datatype = "port" o.datatype = "port"
o = s:option(Value, "password", translate("Password")) o = s:option(Value, "password", translate("Password"))
o.password = true o.password = true
o = s:option(ListValue, "method", translate("Encrypt Method")) o = s:option(ListValue, "method", translate("Encrypt Method"))
for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end
o = s:option(ListValue, "protocol", translate("Protocol")) o = s:option(ListValue, "protocol", translate("Protocol"))
for a, t in ipairs(ssr_protocol_list) do o:value(t) end for a, t in ipairs(ssr_protocol_list) do o:value(t) end
o = s:option(Value, "protocol_param", translate("Protocol_param")) o = s:option(Value, "protocol_param", translate("Protocol_param"))
o = s:option(ListValue, "obfs", translate("Obfs")) o = s:option(ListValue, "obfs", translate("Obfs"))
for a, t in ipairs(ssr_obfs_list) do o:value(t) end for a, t in ipairs(ssr_obfs_list) do o:value(t) end
o = s:option(Value, "obfs_param", translate("Obfs_param")) o = s:option(Value, "obfs_param", translate("Obfs_param"))
o = s:option(Value, "timeout", translate("Connection Timeout")) o = s:option(Value, "timeout", translate("Connection Timeout"))
o.datatype = "uinteger" o.datatype = "uinteger"
o.default = 300 o.default = 300
o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"), translate("Need node support required")) o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"), translate("Need node support required"))
o.default = 0 o.default = 0
api.luci_types(s1, s) api.luci_types(s1, s)
@@ -39,7 +39,7 @@ for filename in api.fs.dir(types_dir) do
table.insert(type_table, filename) table.insert(type_table, filename)
end end
table.sort(type_table, function(a, b) table.sort(type_table, function(a, b)
return a < b return a < b
end) end)
for index, value in ipairs(type_table) do for index, value in ipairs(type_table) do
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -1,90 +1,90 @@
if not api.is_finded("ssserver") then if not api.is_finded("ssserver") then
return return
end end
-- [[ Shadowsocks Rust ]] -- [[ Shadowsocks Rust ]]
local m, s1 = ... local m, s1 = ...
local type_name = "SS-Rust" local type_name = "SS-Rust"
s1.fields["type"]:value(type_name, translate("Shadowsocks Rust")) s1.fields["type"]:value(type_name, translate("Shadowsocks Rust"))
if not s1.val["type"] then if not s1.val["type"] then
s1.val["type"] = type_name s1.val["type"] = type_name
end end
if s1.val["type"] and s1.val["type"] ~= type_name then if s1.val["type"] and s1.val["type"] ~= type_name then
return return
end end
local s = NamedSection(m, arg[1], "server") local s = NamedSection(m, arg[1], "server")
s.type_name = type_name s.type_name = type_name
s.option_prefix = "ssrust_" s.option_prefix = "ssrust_"
local ssrust_encrypt_method_list = { local ssrust_encrypt_method_list = {
"plain", "none", "plain", "none",
"aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha8-poly1305", "2022-blake3-chacha20-poly1305" "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha8-poly1305", "2022-blake3-chacha20-poly1305"
} }
o = s:option(Flag, "custom", translate("Use Custom Config")) o = s:option(Flag, "custom", translate("Use Custom Config"))
o = s:option(TextValue, "custom_config", translate("Custom Config") .. " (JSON)") o = s:option(TextValue, "custom_config", translate("Custom Config") .. " (JSON)")
o.rows = 10 o.rows = 10
o.wrap = "off" o.wrap = "off"
o:depends({ custom = true }) o:depends({ custom = true })
o.datatype = "json" o.datatype = "json"
local o_validate = o.validate local o_validate = o.validate
o.validate = function(self, value) o.validate = function(self, value)
local v = o_validate(self, value) local v = o_validate(self, value)
if v then return v end if v then return v end
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end end
o.custom_cfgvalue = function(self, section, value) o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str") local config_str = m:get(section, "config_str")
if config_str then if config_str then
return api.base64Decode(config_str) return api.base64Decode(config_str)
end end
end end
o.custom_write = function(self, section, value) o.custom_write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "") m:set(section, "config_str", api.base64Encode(value) or "")
end end
o = s:option(Value, "port", translate("Listen Port")) o = s:option(Value, "port", translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(ListValue, "user", translate("User")) o = s:option(ListValue, "user", translate("User"))
for i, v in ipairs(user_list) do for i, v in ipairs(user_list) do
o:value(v[".name"], v.username) o:value(v[".name"], v.username)
end end
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(ListValue, "method", translate("Encrypt Method")) o = s:option(ListValue, "method", translate("Encrypt Method"))
for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(Value, "timeout", translate("Connection Timeout")) o = s:option(Value, "timeout", translate("Connection Timeout"))
o.datatype = "uinteger" o.datatype = "uinteger"
o.default = 300 o.default = 300
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open")) o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"))
o.default = "0" o.default = "0"
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(Flag, "firewall_allow", translate("Firewall Allow")) o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0" o.default = "0"
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(Value, "firewall_allow_src", translate("Source zone")) o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true o.nocreate = true
o.allowany = true o.allowany = true
o.default = "wan" o.default = "wan"
o.template = "cbi/firewall_zonelist" o.template = "cbi/firewall_zonelist"
o:depends({ custom = false, firewall_allow = true }) o:depends({ custom = false, firewall_allow = true })
o = s:option(Flag, "log", translate("Log")) o = s:option(Flag, "log", translate("Log"))
o.default = "1" o.default = "1"
o.rmempty = false o.rmempty = false
api.luci_types(s1, s) api.luci_types(s1, s)
@@ -1,121 +1,121 @@
if not api.is_finded("ssr-server") then if not api.is_finded("ssr-server") then
return return
end end
-- [[ ShadowsocksR ]] -- [[ ShadowsocksR ]]
local m, s1 = ... local m, s1 = ...
local type_name = "SSR" local type_name = "SSR"
s1.fields["type"]:value(type_name, translate("ShadowsocksR")) s1.fields["type"]:value(type_name, translate("ShadowsocksR"))
if not s1.val["type"] then if not s1.val["type"] then
s1.val["type"] = type_name s1.val["type"] = type_name
end end
if s1.val["type"] and s1.val["type"] ~= type_name then if s1.val["type"] and s1.val["type"] ~= type_name then
return return
end end
local s = NamedSection(m, arg[1], "server") local s = NamedSection(m, arg[1], "server")
s.type_name = type_name s.type_name = type_name
s.option_prefix = "ssr_" s.option_prefix = "ssr_"
local ssr_encrypt_method_list = { local ssr_encrypt_method_list = {
"none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb", "none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb",
"aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr",
"bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb",
"cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20", "cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20",
"chacha20-ietf" "chacha20-ietf"
} }
local ssr_protocol_list = { local ssr_protocol_list = {
"origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple", "origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple",
"auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5", "auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5",
"auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c", "auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c",
"auth_chain_d", "auth_chain_e", "auth_chain_f" "auth_chain_d", "auth_chain_e", "auth_chain_f"
} }
local ssr_obfs_list = { local ssr_obfs_list = {
"plain", "http_simple", "http_post", "random_head", "tls_simple", "plain", "http_simple", "http_post", "random_head", "tls_simple",
"tls1.0_session_auth", "tls1.2_ticket_auth" "tls1.0_session_auth", "tls1.2_ticket_auth"
} }
o = s:option(Flag, "custom", translate("Use Custom Config")) o = s:option(Flag, "custom", translate("Use Custom Config"))
o = s:option(TextValue, "custom_config", translate("Custom Config") .. " (JSON)") o = s:option(TextValue, "custom_config", translate("Custom Config") .. " (JSON)")
o.rows = 10 o.rows = 10
o.wrap = "off" o.wrap = "off"
o:depends({ custom = true }) o:depends({ custom = true })
o.datatype = "json" o.datatype = "json"
local o_validate = o.validate local o_validate = o.validate
o.validate = function(self, value) o.validate = function(self, value)
local v = o_validate(self, value) local v = o_validate(self, value)
if v then return v end if v then return v end
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end end
o.custom_cfgvalue = function(self, section, value) o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str") local config_str = m:get(section, "config_str")
if config_str then if config_str then
return api.base64Decode(config_str) return api.base64Decode(config_str)
end end
end end
o.custom_write = function(self, section, value) o.custom_write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "") m:set(section, "config_str", api.base64Encode(value) or "")
end end
o = s:option(Value, "port", translate("Listen Port")) o = s:option(Value, "port", translate("Listen Port"))
o.datatype = "port" o.datatype = "port"
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(ListValue, "user", translate("User")) o = s:option(ListValue, "user", translate("User"))
for i, v in ipairs(user_list) do for i, v in ipairs(user_list) do
o:value(v[".name"], v.username) o:value(v[".name"], v.username)
end end
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(ListValue, "method", translate("Encrypt Method")) o = s:option(ListValue, "method", translate("Encrypt Method"))
for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(ListValue, "protocol", translate("Protocol")) o = s:option(ListValue, "protocol", translate("Protocol"))
for a, t in ipairs(ssr_protocol_list) do o:value(t) end for a, t in ipairs(ssr_protocol_list) do o:value(t) end
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(Value, "protocol_param", translate("Protocol_param")) o = s:option(Value, "protocol_param", translate("Protocol_param"))
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(ListValue, "obfs", translate("Obfs")) o = s:option(ListValue, "obfs", translate("Obfs"))
for a, t in ipairs(ssr_obfs_list) do o:value(t) end for a, t in ipairs(ssr_obfs_list) do o:value(t) end
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(Value, "obfs_param", translate("Obfs_param")) o = s:option(Value, "obfs_param", translate("Obfs_param"))
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(Value, "timeout", translate("Connection Timeout")) o = s:option(Value, "timeout", translate("Connection Timeout"))
o.datatype = "uinteger" o.datatype = "uinteger"
o.default = 300 o.default = 300
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open")) o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"))
o.default = "0" o.default = "0"
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(Flag, "udp_forward", translate("UDP Forward")) o = s:option(Flag, "udp_forward", translate("UDP Forward"))
o.default = "1" o.default = "1"
o.rmempty = false o.rmempty = false
o = s:option(Flag, "firewall_allow", translate("Firewall Allow")) o = s:option(Flag, "firewall_allow", translate("Firewall Allow"))
o.default = "0" o.default = "0"
o:depends({ custom = false }) o:depends({ custom = false })
o = s:option(Value, "firewall_allow_src", translate("Source zone")) o = s:option(Value, "firewall_allow_src", translate("Source zone"))
o.nocreate = true o.nocreate = true
o.allowany = true o.allowany = true
o.default = "wan" o.default = "wan"
o.template = "cbi/firewall_zonelist" o.template = "cbi/firewall_zonelist"
o:depends({ custom = false, firewall_allow = true }) o:depends({ custom = false, firewall_allow = true })
o = s:option(Flag, "log", translate("Log")) o = s:option(Flag, "log", translate("Log"))
o.default = "1" o.default = "1"
o.rmempty = false o.rmempty = false
api.luci_types(s1, s) api.luci_types(s1, s)
+8 -8
View File
@@ -464,14 +464,14 @@ datatypes.json = is_json
function is_timehhmm(str) function is_timehhmm(str)
local hour, minute = string.match(str, "^(%d?%d):(%d%d)$") local hour, minute = string.match(str, "^(%d?%d):(%d%d)$")
if hour and minute then if hour and minute then
hour = tonumber(hour) hour = tonumber(hour)
minute = tonumber(minute) minute = tonumber(minute)
if hour >= 0 and hour <= 23 and minute >= 0 and minute <= 59 then if hour >= 0 and hour <= 23 and minute >= 0 and minute <= 59 then
return true return true
end end
end end
return false return false
end end
datatypes.timehhmm = is_timehhmm datatypes.timehhmm = is_timehhmm
@@ -922,12 +922,12 @@ function gen_config(var)
if xray_settings.fragment == "1" then if xray_settings.fragment == "1" then
local lengths, delays = {}, {} local lengths, delays = {}, {}
api.trim(xray_settings.fragment_lengths):gsub("[^,]+", function(w) api.trim(xray_settings.fragment_lengths):gsub("[^,]+", function(w)
w = w:gsub("%s+", "") w = w:gsub("%s+", "")
if w ~= "" then lengths[#lengths+1] = w end if w ~= "" then lengths[#lengths+1] = w end
end) end)
api.trim(xray_settings.fragment_delays):gsub("[^,]+", function(w) api.trim(xray_settings.fragment_delays):gsub("[^,]+", function(w)
w = w:gsub("%s+", "") w = w:gsub("%s+", "")
if w ~= "" then delays[#delays+1] = w end if w ~= "" then delays[#delays+1] = w end
end) end)
fragment_table = { fragment_table = {
type = "fragment", type = "fragment",
@@ -534,7 +534,7 @@
//自定义框 //自定义框
function v_customEnter(cbid, labelSpan, hiddenInput, searchInput, panel, listContainer, customInput) { function v_customEnter(cbid, labelSpan, hiddenInput, searchInput, panel, listContainer, customInput) {
let inputValue = customInput.value.trim(); let inputValue = customInput.value.trim();
if (!inputValue) { if (!inputValue) {
return; return;
} }
const existingItems = listContainer.querySelectorAll('li[data-key="' + inputValue + '"]'); const existingItems = listContainer.querySelectorAll('li[data-key="' + inputValue + '"]');
@@ -3,28 +3,28 @@ local map = self.map
local api = map.api local api = map.api
-%> -%>
<style> <style>
.dns-con { .dns-con {
padding: 1rem; padding: 1rem;
} }
.faq-title { .faq-title {
color: var(--primary); color: var(--primary);
font-weight: bolder; font-weight: bolder;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
display: inline-block; display: inline-block;
} }
.reset-title { .reset-title {
color: var(--primary); color: var(--primary);
font-weight: bolder; font-weight: bolder;
margin-bottom: 0.3rem; margin-bottom: 0.3rem;
display: inline-block; display: inline-block;
margin-top: 1.2rem; margin-top: 1.2rem;
text-decoration: underline; text-decoration: underline;
} }
.dns-item { .dns-item {
margin-bottom: 0.8rem; margin-bottom: 0.8rem;
line-height:1.2rem; line-height:1.2rem;
} }
.dns-list { .dns-list {
text-indent:1rem; text-indent:1rem;
line-height: 1.2rem; line-height: 1.2rem;
} }
@@ -32,13 +32,13 @@ local api = map.api
<div class="dns-con"> <div class="dns-con">
<div id="faq_dns"> <div id="faq_dns">
<ul> <ul>
<b class="faq-title"><%:DNS related issues:%></b> <b class="faq-title"><%:DNS related issues:%></b>
<li class="dns-item">1. <span><%:Certain browsers such as Chrome have built-in DNS service, which may affect DNS resolution settings. You can go to 'Settings -> Privacy and security -> Use secure DNS' menu to turn it off.%></span></li> <li class="dns-item">1. <span><%:Certain browsers such as Chrome have built-in DNS service, which may affect DNS resolution settings. You can go to 'Settings -> Privacy and security -> Use secure DNS' menu to turn it off.%></span></li>
<li class="dns-item">2. <span><%:If you are unable to access the internet after reboot, please try clearing the cache of your terminal devices (make sure to close all open browser application windows first, this step is especially important):%></span> <li class="dns-item">2. <span><%:If you are unable to access the internet after reboot, please try clearing the cache of your terminal devices (make sure to close all open browser application windows first, this step is especially important):%></span>
<ul><li class="dns-list"> ◦ <span><%:For Windows systems, open Command Prompt and run the command 'ipconfig /flushdns'.%></span></li> <ul><li class="dns-list"> ◦ <span><%:For Windows systems, open Command Prompt and run the command 'ipconfig /flushdns'.%></span></li>
<li class="dns-list"> ◦ <span><%:For Mac systems, open Terminal and run the command 'sudo killall -HUP mDNSResponder'.%></span></li> <li class="dns-list"> ◦ <span><%:For Mac systems, open Terminal and run the command 'sudo killall -HUP mDNSResponder'.%></span></li>
<li class="dns-list"> ◦ <span><%:For mobile devices, you can clear it by reconnecting to the network, such as toggling Airplane Mode and reconnecting to WiFi.%></span></li> <li class="dns-list"> ◦ <span><%:For mobile devices, you can clear it by reconnecting to the network, such as toggling Airplane Mode and reconnecting to WiFi.%></span></li>
</ul> </ul>
</li> </li>
<li class="dns-item">3. <span><%:Please make sure your device's network settings point both the DNS server and default gateway to this router, to ensure DNS queries are properly routed.%></span></li> <li class="dns-item">3. <span><%:Please make sure your device's network settings point both the DNS server and default gateway to this router, to ensure DNS queries are properly routed.%></span></li>
</ul> </ul>
@@ -58,7 +58,7 @@ local api = map.api
} }
var dom = document.getElementById("faq_reset"); var dom = document.getElementById("faq_reset");
if (dom) { if (dom) {
var li = ""; var li = "";
li += "<a href='#' class='reset-title' onclick='hide()'>" + "<%: Hide in main menu:%>"+ "</a>" + "<br />" + "<%: Browser access: %>" + "<a href='#' onclick='hide()'>" + hide_url + "</a>" + "<br />"; li += "<a href='#' class='reset-title' onclick='hide()'>" + "<%: Hide in main menu:%>"+ "</a>" + "<br />" + "<%: Browser access: %>" + "<a href='#' onclick='hide()'>" + hide_url + "</a>" + "<br />";
li += "<a href='#' class='reset-title'>" + "<%: Show in main menu:%>"+ "</a>" + "<br />" +"<%: Browser access: %>" + "<a href='#'>" + show_url + "</a>" + "<br />"; li += "<a href='#' class='reset-title'>" + "<%: Show in main menu:%>"+ "</a>" + "<br />" +"<%: Browser access: %>" + "<a href='#'>" + show_url + "</a>" + "<br />";
@@ -29,8 +29,8 @@ table th, .table .th {
table td, .table .td { table td, .table .td {
text-align: center; text-align: center;
/* white-space: nowrap; */ /* white-space: nowrap; */
word-break: keep-all; word-break: keep-all;
} }
#set_node_div { #set_node_div {
@@ -41,7 +41,7 @@ table td, .table .td {
z-index: 99; z-index: 99;
text-align: center; text-align: center;
background: white; background: white;
box-shadow: darkgrey 10px 10px 30px 5px; box-shadow: darkgrey 10px 10px 30px 5px;
text-align: center; text-align: center;
padding: 0.5em; padding: 0.5em;
} }
@@ -53,8 +53,8 @@ table td, .table .td {
.ping a, .ping a,
.ping_value a, .ping_value a,
.tcping_value a { .tcping_value a {
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
@@ -74,7 +74,7 @@ local api = self.api
if (!value) { if (!value) {
alert("<%:Please enter query content!%>"); alert("<%:Please enter query content!%>");
return; return;
} }
lookup_btn.disabled = true; lookup_btn.disabled = true;
extract_btn.disabled = true; extract_btn.disabled = true;
btn.value = '<%:Querying%>'; btn.value = '<%:Querying%>';
@@ -11,8 +11,8 @@ table th, .table .th {
table td, .table .td { table td, .table .td {
text-align: center; text-align: center;
/* white-space: nowrap; */ /* white-space: nowrap; */
word-break: keep-all; word-break: keep-all;
} }
.td.cbi-section-actions { .td.cbi-section-actions {
@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
if [ -e "/etc/config/ucitrack" ]; then if [ -e "/etc/config/ucitrack" ]; then
uci -q batch <<-EOF uci -q batch <<-EOF
delete ucitrack.@passwall2[-1] delete ucitrack.@passwall2[-1]
add ucitrack passwall2 add ucitrack passwall2
set ucitrack.@passwall2[-1].init=passwall2 set ucitrack.@passwall2[-1].init=passwall2
@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
if [ -e "/etc/config/ucitrack" ]; then if [ -e "/etc/config/ucitrack" ]; then
uci -q batch <<-EOF uci -q batch <<-EOF
delete ucitrack.@passwall2_server[-1] delete ucitrack.@passwall2_server[-1]
add ucitrack passwall2_server add ucitrack passwall2_server
set ucitrack.@passwall2_server[-1].init=passwall2_server set ucitrack.@passwall2_server[-1].init=passwall2_server
@@ -1,371 +1,371 @@
local api = require "luci.passwall2.api" local api = require "luci.passwall2.api"
local c_config = api.c_config local c_config = api.c_config
local sys = api.sys local sys = api.sys
local jsonc = api.jsonc local jsonc = api.jsonc
local fs = api.fs local fs = api.fs
local datatypes = api.datatypes local datatypes = api.datatypes
local TMP = {} local TMP = {}
local function tinsert(table_name, val) local function tinsert(table_name, val)
if table_name and type(table_name) == "table" then if table_name and type(table_name) == "table" then
if not TMP[table_name] then if not TMP[table_name] then
TMP[table_name] = {} TMP[table_name] = {}
end end
if TMP[table_name][val] then if TMP[table_name][val] then
return false return false
end end
table.insert(table_name, val) table.insert(table_name, val)
TMP[table_name][val] = true TMP[table_name][val] = true
return true return true
end end
return false return false
end end
local function backup_servers() local function backup_servers()
local DNSMASQ_DNS = api.uci_get("dhcp", "@dnsmasq[0]", "server") local DNSMASQ_DNS = api.uci_get("dhcp", "@dnsmasq[0]", "server")
if DNSMASQ_DNS and #DNSMASQ_DNS > 0 then if DNSMASQ_DNS and #DNSMASQ_DNS > 0 then
api.uci_set_c("@global[0]", "dnsmasq_servers", DNSMASQ_DNS) api.uci_set_c("@global[0]", "dnsmasq_servers", DNSMASQ_DNS)
api.uci_save_c(true) api.uci_save_c(true)
end end
end end
local function restore_servers() local function restore_servers()
local dns_table = {} local dns_table = {}
local DNSMASQ_DNS = api.uci_get("dhcp", "@dnsmasq[0]", "server") local DNSMASQ_DNS = api.uci_get("dhcp", "@dnsmasq[0]", "server")
if DNSMASQ_DNS and #DNSMASQ_DNS > 0 then if DNSMASQ_DNS and #DNSMASQ_DNS > 0 then
for k, v in ipairs(DNSMASQ_DNS) do for k, v in ipairs(DNSMASQ_DNS) do
tinsert(dns_table, v) tinsert(dns_table, v)
end end
end end
local OLD_SERVER = api.uci_get_c("@global[0]", "dnsmasq_servers") local OLD_SERVER = api.uci_get_c("@global[0]", "dnsmasq_servers")
if OLD_SERVER and #OLD_SERVER > 0 then if OLD_SERVER and #OLD_SERVER > 0 then
for k, v in ipairs(OLD_SERVER) do for k, v in ipairs(OLD_SERVER) do
tinsert(dns_table, v) tinsert(dns_table, v)
end end
api.uci_del_c("@global[0]", "dnsmasq_servers") api.uci_del_c("@global[0]", "dnsmasq_servers")
api.uci_save_c(true) api.uci_save_c(true)
end end
if dns_table and #dns_table > 0 then if dns_table and #dns_table > 0 then
api.uci_set("dhcp", "@dnsmasq[0]", "server", dns_table) api.uci_set("dhcp", "@dnsmasq[0]", "server", dns_table)
api.uci_save(nil, "dhcp", true) api.uci_save(nil, "dhcp", true)
end end
end end
function stretch() function stretch()
local dnsmasq_server = api.uci_get("dhcp", "@dnsmasq[0]", "server") local dnsmasq_server = api.uci_get("dhcp", "@dnsmasq[0]", "server")
local dnsmasq_noresolv = api.uci_get("dhcp", "@dnsmasq[0]", "noresolv") local dnsmasq_noresolv = api.uci_get("dhcp", "@dnsmasq[0]", "noresolv")
local _flag local _flag
if dnsmasq_server and #dnsmasq_server > 0 then if dnsmasq_server and #dnsmasq_server > 0 then
for k, v in ipairs(dnsmasq_server) do for k, v in ipairs(dnsmasq_server) do
if not v:find("/") then if not v:find("/") then
_flag = true _flag = true
end end
end end
end end
if not _flag and dnsmasq_noresolv == "1" then if not _flag and dnsmasq_noresolv == "1" then
api.uci_del("dhcp", "@dnsmasq[0]", "noresolv") api.uci_del("dhcp", "@dnsmasq[0]", "noresolv")
local RESOLVFILE = "/tmp/resolv.conf.d/resolv.conf.auto" local RESOLVFILE = "/tmp/resolv.conf.d/resolv.conf.auto"
local file = io.open(RESOLVFILE, "r") local file = io.open(RESOLVFILE, "r")
if not file then if not file then
RESOLVFILE = "/tmp/resolv.conf.auto" RESOLVFILE = "/tmp/resolv.conf.auto"
else else
local size = file:seek("end") local size = file:seek("end")
file:close() file:close()
if size == 0 then if size == 0 then
RESOLVFILE = "/tmp/resolv.conf.auto" RESOLVFILE = "/tmp/resolv.conf.auto"
end end
end end
api.uci_set("dhcp", "@dnsmasq[0]", "resolvfile", RESOLVFILE) api.uci_set("dhcp", "@dnsmasq[0]", "resolvfile", RESOLVFILE)
api.uci_save(nil, "dhcp", true) api.uci_save(nil, "dhcp", true)
end end
end end
function restart(var) function restart(var)
local LOG = var["LOG"] local LOG = var["LOG"]
sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1") sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1")
if LOG == "1" then if LOG == "1" then
api.log(0, api.i18n.translate("Restart dnsmasq service.")) api.log(0, api.i18n.translate("Restart dnsmasq service."))
end end
end end
function logic_restart(var) function logic_restart(var)
local LOG = var["LOG"] local LOG = var["LOG"]
local DEFAULT_DNS = api.get_cache_var("DEFAULT_DNS") local DEFAULT_DNS = api.get_cache_var("DEFAULT_DNS")
if DEFAULT_DNS then if DEFAULT_DNS then
backup_servers() backup_servers()
--sys.call("sed -i '/list server/d' /etc/config/dhcp >/dev/null 2>&1") --sys.call("sed -i '/list server/d' /etc/config/dhcp >/dev/null 2>&1")
local dns_table = {} local dns_table = {}
local dnsmasq_server = api.uci_get("dhcp", "@dnsmasq[0]", "server") local dnsmasq_server = api.uci_get("dhcp", "@dnsmasq[0]", "server")
if dnsmasq_server and #dnsmasq_server > 0 then if dnsmasq_server and #dnsmasq_server > 0 then
for k, v in ipairs(dnsmasq_server) do for k, v in ipairs(dnsmasq_server) do
if v:find("/") then if v:find("/") then
tinsert(dns_table, v) tinsert(dns_table, v)
end end
end end
api.uci_set("dhcp", "@dnsmasq[0]", "server", dns_table) api.uci_set("dhcp", "@dnsmasq[0]", "server", dns_table)
api.uci_save(nil, "dhcp", true) api.uci_save(nil, "dhcp", true)
end end
sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1") sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1")
restore_servers() restore_servers()
else else
sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1") sys.call("/etc/init.d/dnsmasq restart >/dev/null 2>&1")
end end
if LOG == "1" then if LOG == "1" then
api.log(0, api.i18n.translate("Restart dnsmasq service.")) api.log(0, api.i18n.translate("Restart dnsmasq service."))
end end
end end
function copy_instance(var) function copy_instance(var)
local LISTEN_PORT = var["LISTEN_PORT"] local LISTEN_PORT = var["LISTEN_PORT"]
local TMP_DNSMASQ_PATH = var["TMP_DNSMASQ_PATH"] local TMP_DNSMASQ_PATH = var["TMP_DNSMASQ_PATH"]
local conf_lines = {} local conf_lines = {}
local DEFAULT_DNSMASQ_CFGID = sys.exec("echo -n $(uci -q show dhcp.@dnsmasq[0] | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')") local DEFAULT_DNSMASQ_CFGID = sys.exec("echo -n $(uci -q show dhcp.@dnsmasq[0] | awk 'NR==1 {split($0, conf, /[.=]/); print conf[2]}')")
for line in io.lines("/tmp/etc/dnsmasq.conf." .. DEFAULT_DNSMASQ_CFGID) do for line in io.lines("/tmp/etc/dnsmasq.conf." .. DEFAULT_DNSMASQ_CFGID) do
local filter local filter
if line:find("passwall2") then filter = true end if line:find("passwall2") then filter = true end
if line:find("ubus") then filter = true end if line:find("ubus") then filter = true end
if line:find("dhcp") then filter = true end if line:find("dhcp") then filter = true end
if line:find("server=") == 1 then filter = true end if line:find("server=") == 1 then filter = true end
if line:find("port=") == 1 then filter = true end if line:find("port=") == 1 then filter = true end
if line:find("conf%-dir=") == 1 then if line:find("conf%-dir=") == 1 then
filter = true filter = true
if TMP_DNSMASQ_PATH then if TMP_DNSMASQ_PATH then
local tmp_path = line:sub(1 + #"conf-dir=") local tmp_path = line:sub(1 + #"conf-dir=")
sys.call(string.format("cp -r %s/* %s/ 2>/dev/null", tmp_path, TMP_DNSMASQ_PATH)) sys.call(string.format("cp -r %s/* %s/ 2>/dev/null", tmp_path, TMP_DNSMASQ_PATH))
end end
end end
if line:find("address=") == 1 or (line:find("server=") == 1 and line:find("/")) then filter = nil end if line:find("address=") == 1 or (line:find("server=") == 1 and line:find("/")) then filter = nil end
if not filter then if not filter then
tinsert(conf_lines, line) tinsert(conf_lines, line)
end end
end end
tinsert(conf_lines, "port=" .. LISTEN_PORT) tinsert(conf_lines, "port=" .. LISTEN_PORT)
if TMP_DNSMASQ_PATH then if TMP_DNSMASQ_PATH then
sys.call("rm -rf " .. TMP_DNSMASQ_PATH .. "/*passwall2*") sys.call("rm -rf " .. TMP_DNSMASQ_PATH .. "/*passwall2*")
end end
if var["return"] == "1" then if var["return"] == "1" then
return conf_lines return conf_lines
end end
if #conf_lines > 0 then if #conf_lines > 0 then
local DNSMASQ_CONF = var["DNSMASQ_CONF"] local DNSMASQ_CONF = var["DNSMASQ_CONF"]
local conf_out = io.open(DNSMASQ_CONF, "a") local conf_out = io.open(DNSMASQ_CONF, "a")
conf_out:write(table.concat(conf_lines, "\n")) conf_out:write(table.concat(conf_lines, "\n"))
conf_out:write("\n") conf_out:write("\n")
conf_out:close() conf_out:close()
end end
end end
function add_rule(var) function add_rule(var)
local FLAG = var["FLAG"] local FLAG = var["FLAG"]
local TMP_DNSMASQ_PATH = var["TMP_DNSMASQ_PATH"] local TMP_DNSMASQ_PATH = var["TMP_DNSMASQ_PATH"]
local DNSMASQ_CONF_FILE = var["DNSMASQ_CONF_FILE"] local DNSMASQ_CONF_FILE = var["DNSMASQ_CONF_FILE"]
local LISTEN_PORT = var["LISTEN_PORT"] local LISTEN_PORT = var["LISTEN_PORT"]
local DEFAULT_DNS = var["DEFAULT_DNS"] local DEFAULT_DNS = var["DEFAULT_DNS"]
local LOCAL_DNS = var["LOCAL_DNS"] local LOCAL_DNS = var["LOCAL_DNS"]
local TUN_DNS = var["TUN_DNS"] local TUN_DNS = var["TUN_DNS"]
local NFTFLAG = var["NFTFLAG"] local NFTFLAG = var["NFTFLAG"]
local CACHE_PATH = api.CACHE_PATH local CACHE_PATH = api.CACHE_PATH
local CACHE_FLAG = "dnsmasq_" .. FLAG local CACHE_FLAG = "dnsmasq_" .. FLAG
local CACHE_DNS_PATH = CACHE_PATH .. "/" .. CACHE_FLAG local CACHE_DNS_PATH = CACHE_PATH .. "/" .. CACHE_FLAG
local CACHE_TEXT_FILE = CACHE_DNS_PATH .. ".txt" local CACHE_TEXT_FILE = CACHE_DNS_PATH .. ".txt"
local list1 = {} local list1 = {}
local function check_dns(domain, dns) local function check_dns(domain, dns)
if domain == "" or domain:find("#") then if domain == "" or domain:find("#") then
return false return false
end end
if not dns then if not dns then
return return
end end
for k,v in ipairs(list1[domain].dns) do for k,v in ipairs(list1[domain].dns) do
if dns == v then if dns == v then
return true return true
end end
end end
return false return false
end end
local function check_ipset(domain, ipset) local function check_ipset(domain, ipset)
if domain == "" or domain:find("#") then if domain == "" or domain:find("#") then
return false return false
end end
if not ipset then if not ipset then
return return
end end
for k,v in ipairs(list1[domain].ipsets) do for k,v in ipairs(list1[domain].ipsets) do
if ipset == v then if ipset == v then
return true return true
end end
end end
return false return false
end end
local function set_domain_dns(domain, dns) local function set_domain_dns(domain, dns)
if domain == "" or domain:find("#") then if domain == "" or domain:find("#") then
return return
end end
if not dns then if not dns then
return return
end end
if not list1[domain] then if not list1[domain] then
list1[domain] = { list1[domain] = {
dns = {}, dns = {},
ipsets = {} ipsets = {}
} }
end end
for line in string.gmatch(dns, '[^' .. "," .. ']+') do for line in string.gmatch(dns, '[^' .. "," .. ']+') do
if not check_dns(domain, line) then if not check_dns(domain, line) then
table.insert(list1[domain].dns, line) table.insert(list1[domain].dns, line)
end end
end end
end end
local function set_domain_ipset(domain, ipset) local function set_domain_ipset(domain, ipset)
if domain == "" or domain:find("#") then if domain == "" or domain:find("#") then
return return
end end
if not ipset then if not ipset then
return return
end end
if not list1[domain] then if not list1[domain] then
list1[domain] = { list1[domain] = {
dns = {}, dns = {},
ipsets = {} ipsets = {}
} }
end end
for line in string.gmatch(ipset, '[^' .. "," .. ']+') do for line in string.gmatch(ipset, '[^' .. "," .. ']+') do
if not check_ipset(domain, line) then if not check_ipset(domain, line) then
table.insert(list1[domain].ipsets, line) table.insert(list1[domain].ipsets, line)
end end
end end
end end
local cache_text = "" local cache_text = ""
local nodes_address_md5 = sys.exec("echo -n $(uci show %s | grep '\\.address') | md5sum" % c_config) local nodes_address_md5 = sys.exec("echo -n $(uci show %s | grep '\\.address') | md5sum" % c_config)
local new_text = TMP_DNSMASQ_PATH .. DNSMASQ_CONF_FILE .. DEFAULT_DNS .. LOCAL_DNS .. TUN_DNS .. nodes_address_md5 .. NFTFLAG local new_text = TMP_DNSMASQ_PATH .. DNSMASQ_CONF_FILE .. DEFAULT_DNS .. LOCAL_DNS .. TUN_DNS .. nodes_address_md5 .. NFTFLAG
if fs.access(CACHE_TEXT_FILE) then if fs.access(CACHE_TEXT_FILE) then
for line in io.lines(CACHE_TEXT_FILE) do for line in io.lines(CACHE_TEXT_FILE) do
cache_text = line cache_text = line
end end
end end
if cache_text ~= new_text then if cache_text ~= new_text then
api.remove(CACHE_DNS_PATH .. "*") api.remove(CACHE_DNS_PATH .. "*")
end end
local dnsmasq_default_dns = TUN_DNS local dnsmasq_default_dns = TUN_DNS
local setflag_4= (NFTFLAG == "1") and "4#inet#passwall2#" or "" local setflag_4= (NFTFLAG == "1") and "4#inet#passwall2#" or ""
local setflag_6= (NFTFLAG == "1") and "6#inet#passwall2#" or "" local setflag_6= (NFTFLAG == "1") and "6#inet#passwall2#" or ""
if not fs.access(CACHE_DNS_PATH) then if not fs.access(CACHE_DNS_PATH) then
fs.mkdir(CACHE_DNS_PATH) fs.mkdir(CACHE_DNS_PATH)
local fwd_dns local fwd_dns
-- Always use domestic DNS to resolve node domain names -- Always use domestic DNS to resolve node domain names
if true then if true then
fwd_dns = LOCAL_DNS fwd_dns = LOCAL_DNS
api.uci_foreach_c("nodes", function(t) api.uci_foreach_c("nodes", function(t)
local function process_address(address) local function process_address(address)
address = (address or ""):lower() address = (address or ""):lower()
if address == "engage.cloudflareclient.com" then return end if address == "engage.cloudflareclient.com" then return end
if datatypes.hostname(address) then if datatypes.hostname(address) then
set_domain_dns(address, fwd_dns) set_domain_dns(address, fwd_dns)
set_domain_ipset(address, setflag_4 .. "psw2_vps," .. setflag_6 .. "psw2_vps6") set_domain_ipset(address, setflag_4 .. "psw2_vps," .. setflag_6 .. "psw2_vps6")
end end
end end
process_address(t.address) process_address(t.address)
process_address(t.download_address) process_address(t.download_address)
end) end)
end end
if list1 and next(list1) then if list1 and next(list1) then
local server_out = io.open(CACHE_DNS_PATH .. "/001-server.conf", "a") local server_out = io.open(CACHE_DNS_PATH .. "/001-server.conf", "a")
local ipset_out = io.open(CACHE_DNS_PATH .. "/ipset.conf", "a") local ipset_out = io.open(CACHE_DNS_PATH .. "/ipset.conf", "a")
local set_name = "ipset" local set_name = "ipset"
if NFTFLAG == "1" then if NFTFLAG == "1" then
set_name = "nftset" set_name = "nftset"
end end
for key, value in pairs(list1) do for key, value in pairs(list1) do
if value.dns and #value.dns > 0 then if value.dns and #value.dns > 0 then
for i, dns in ipairs(value.dns) do for i, dns in ipairs(value.dns) do
server_out:write(string.format("server=/.%s/%s", key, dns) .. "\n") server_out:write(string.format("server=/.%s/%s", key, dns) .. "\n")
end end
end end
if value.ipsets and #value.ipsets > 0 then if value.ipsets and #value.ipsets > 0 then
local ipsets_str = "" local ipsets_str = ""
for i, ipset in ipairs(value.ipsets) do for i, ipset in ipairs(value.ipsets) do
ipsets_str = ipsets_str .. ipset .. "," ipsets_str = ipsets_str .. ipset .. ","
end end
ipsets_str = ipsets_str:sub(1, #ipsets_str - 1) ipsets_str = ipsets_str:sub(1, #ipsets_str - 1)
ipset_out:write(string.format("%s=/.%s/%s", set_name, key, ipsets_str) .. "\n") ipset_out:write(string.format("%s=/.%s/%s", set_name, key, ipsets_str) .. "\n")
end end
end end
server_out:close() server_out:close()
ipset_out:close() ipset_out:close()
end end
local f_out = io.open(CACHE_TEXT_FILE, "a") local f_out = io.open(CACHE_TEXT_FILE, "a")
f_out:write(new_text) f_out:write(new_text)
f_out:close() f_out:close()
end end
api.remove(TMP_DNSMASQ_PATH) api.remove(TMP_DNSMASQ_PATH)
fs.symlink(CACHE_DNS_PATH, TMP_DNSMASQ_PATH) fs.symlink(CACHE_DNS_PATH, TMP_DNSMASQ_PATH)
if DNSMASQ_CONF_FILE ~= "nil" then if DNSMASQ_CONF_FILE ~= "nil" then
local conf_lines = {} local conf_lines = {}
if LISTEN_PORT then if LISTEN_PORT then
--Copy dnsmasq instance --Copy dnsmasq instance
conf_lines = copy_instance({ conf_lines = copy_instance({
["LISTEN_PORT"] = LISTEN_PORT, ["LISTEN_PORT"] = LISTEN_PORT,
["TMP_DNSMASQ_PATH"] = TMP_DNSMASQ_PATH, ["TMP_DNSMASQ_PATH"] = TMP_DNSMASQ_PATH,
["return"] = "1" ["return"] = "1"
}) })
--dhcp.leases to hostsMore actions --dhcp.leases to hostsMore actions
local hosts = api.CACHE_PATH .. "/dhcp-hosts" local hosts = api.CACHE_PATH .. "/dhcp-hosts"
sys.call("touch " .. hosts) sys.call("touch " .. hosts)
tinsert(conf_lines, "addn-hosts=" .. hosts) tinsert(conf_lines, "addn-hosts=" .. hosts)
else else
--Modify the default dnsmasq service --Modify the default dnsmasq service
end end
tinsert(conf_lines, string.format("conf-dir=%s", TMP_DNSMASQ_PATH)) tinsert(conf_lines, string.format("conf-dir=%s", TMP_DNSMASQ_PATH))
if dnsmasq_default_dns then if dnsmasq_default_dns then
for s in string.gmatch(dnsmasq_default_dns, '[^' .. "," .. ']+') do for s in string.gmatch(dnsmasq_default_dns, '[^' .. "," .. ']+') do
tinsert(conf_lines, string.format("server=%s", s)) tinsert(conf_lines, string.format("server=%s", s))
end end
tinsert(conf_lines, "all-servers") tinsert(conf_lines, "all-servers")
tinsert(conf_lines, "no-poll") tinsert(conf_lines, "no-poll")
tinsert(conf_lines, "no-resolv") tinsert(conf_lines, "no-resolv")
if FLAG == "default" then if FLAG == "default" then
api.set_cache_var("DEFAULT_DNS", DEFAULT_DNS) api.set_cache_var("DEFAULT_DNS", DEFAULT_DNS)
end end
end end
if #conf_lines > 0 then if #conf_lines > 0 then
local conf_out = io.open(DNSMASQ_CONF_FILE, "a") local conf_out = io.open(DNSMASQ_CONF_FILE, "a")
conf_out:write(table.concat(conf_lines, "\n")) conf_out:write(table.concat(conf_lines, "\n"))
conf_out:write("\n") conf_out:write("\n")
conf_out:close() conf_out:close()
end end
end end
end end
_G.stretch = stretch _G.stretch = stretch
_G.restart = restart _G.restart = restart
_G.logic_restart = logic_restart _G.logic_restart = logic_restart
_G.copy_instance = copy_instance _G.copy_instance = copy_instance
_G.add_rule = add_rule _G.add_rule = add_rule
if arg[1] then if arg[1] then
local func =_G[arg[1]] local func =_G[arg[1]]
if func then if func then
local var = nil local var = nil
if arg[2] then if arg[2] then
var = jsonc.parse(arg[2]) var = jsonc.parse(arg[2])
end end
func(var) func(var)
end end
end end
@@ -1,6 +1,6 @@
if #arg > 0 then if #arg > 0 then
local api = require "luci.passwall2.api" local api = require "luci.passwall2.api"
local str = arg[1] local str = arg[1]
table.remove(arg, 1) table.remove(arg, 1)
print(api.i18n.translatef(str, unpack(arg))) print(api.i18n.translatef(str, unpack(arg)))
end end
@@ -891,7 +891,7 @@ add_firewall_rule() {
del_firewall_rule() { del_firewall_rule() {
for nft in "dstnat" "srcnat" "nat_output" "mangle_prerouting" "mangle_output"; do for nft in "dstnat" "srcnat" "nat_output" "mangle_prerouting" "mangle_output"; do
local handles=$(nft -a list chain $NFTABLE_NAME ${nft} 2>/dev/null | grep -E "PSW2_" | awk -F '# handle ' '{print$2}') local handles=$(nft -a list chain $NFTABLE_NAME ${nft} 2>/dev/null | grep -E "PSW2_" | awk -F '# handle ' '{print$2}')
for handle in $handles; do for handle in $handles; do
nft delete rule $NFTABLE_NAME ${nft} handle ${handle} 2>/dev/null nft delete rule $NFTABLE_NAME ${nft} handle ${handle} 2>/dev/null
done done