diff --git a/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js b/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js
index d958ab6a..052bcaea 100644
--- a/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js
+++ b/luci-app-dockerman/htdocs/luci-static/resources/view/dockerman/container_new.js
@@ -251,6 +251,7 @@ return dm2.dv.extend({
let dnet = this.section.getOption('network').getUIElement(section_id).getValue();
const disallowed = builtInNetworks.has(dnet);
if (disallowed) return _('Only for user-defined networks');
+ return true;
};
o = s.option(form.Value, 'ipv4', _('IPv4 Address'));
diff --git a/luci-app-momo/Makefile b/luci-app-momo/Makefile
index 620a5453..c063ebef 100644
--- a/luci-app-momo/Makefile
+++ b/luci-app-momo/Makefile
@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.1.1
-PKG_RELEASE:=2
+PKG_RELEASE:=3
LUCI_TITLE:=LuCI Support for momo
LUCI_DEPENDS:=+luci-base +momo
diff --git a/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js b/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js
index 7eafe9e0..22641512 100644
--- a/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js
+++ b/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js
@@ -24,6 +24,34 @@ return view.extend({
m = new form.Map('momo');
+ s = m.section(form.NamedSection, 'log', 'log', _('Log Cleanup'));
+
+ o = s.option(form.Flag, 'log_cleanup_enabled', _('Scheduled Log Cleanup'));
+ o.rmempty = false;
+
+ o = s.option(form.Value, 'log_cleanup_cron_expression', _('Log Cleanup Cron Expression'));
+ o.retain = true;
+ o.rmempty = false;
+ o.placeholder = '0 4 * * *';
+ o.depends('log_cleanup_enabled', '1');
+ o.description = _('Run unconditional log cleanup at the configured cron schedule.');
+
+ o = s.option(form.Flag, 'log_cleanup_size_enabled', _('Size-based Log Cleanup'));
+ o.rmempty = false;
+
+ o = s.option(form.Value, 'log_cleanup_size_check_cron_expression', _('Log Size Check Cron Expression'));
+ o.retain = true;
+ o.rmempty = false;
+ o.placeholder = '*/30 * * * *';
+ o.depends('log_cleanup_size_enabled', '1');
+ o.description = _('Check log size at the configured cron schedule before cleaning up.');
+
+ o = s.option(form.Value, 'log_cleanup_size_mb', _('Log Cleanup Size Threshold (MB)'));
+ o.datatype = 'uinteger';
+ o.placeholder = '50';
+ o.depends('log_cleanup_size_enabled', '1');
+ o.description = _('Clear app, core and debug logs when their total size reaches this threshold.');
+
s = m.section(form.NamedSection, 'placeholder', 'placeholder', _('Log'));
s.tab('app_log', _('App Log'));
@@ -119,8 +147,5 @@ return view.extend({
};
return m.render();
- },
- handleSaveApply: null,
- handleSave: null,
- handleReset: null
-});
\ No newline at end of file
+ }
+});
diff --git a/luci-app-momo/po/templates/momo.pot b/luci-app-momo/po/templates/momo.pot
index d2eafbb4..3b4e7bde 100644
--- a/luci-app-momo/po/templates/momo.pot
+++ b/luci-app-momo/po/templates/momo.pot
@@ -425,3 +425,39 @@ msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:128
msgid "procd Config"
msgstr ""
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:47
+msgid "Check log size at the configured cron schedule before cleaning up."
+msgstr ""
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:53
+msgid "Clear app, core and debug logs when their total size reaches this threshold."
+msgstr ""
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:27
+msgid "Log Cleanup"
+msgstr ""
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:32
+msgid "Log Cleanup Cron Expression"
+msgstr ""
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:49
+msgid "Log Cleanup Size Threshold (MB)"
+msgstr ""
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:42
+msgid "Log Size Check Cron Expression"
+msgstr ""
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:37
+msgid "Run unconditional log cleanup at the configured cron schedule."
+msgstr ""
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:29
+msgid "Scheduled Log Cleanup"
+msgstr ""
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:39
+msgid "Size-based Log Cleanup"
+msgstr ""
diff --git a/luci-app-momo/po/zh_Hans/momo.po b/luci-app-momo/po/zh_Hans/momo.po
index 43ded6ef..6ee9ae13 100644
--- a/luci-app-momo/po/zh_Hans/momo.po
+++ b/luci-app-momo/po/zh_Hans/momo.po
@@ -432,3 +432,39 @@ msgstr "用户代理(UA)"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:128
msgid "procd Config"
msgstr "procd 配置"
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:47
+msgid "Check log size at the configured cron schedule before cleaning up."
+msgstr "按设定的 Cron 周期检查日志大小,满足条件后再清理。"
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:53
+msgid "Clear app, core and debug logs when their total size reaches this threshold."
+msgstr "当插件日志、核心日志和调试日志总大小达到该阈值时自动清理。"
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:27
+msgid "Log Cleanup"
+msgstr "日志清理"
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:32
+msgid "Log Cleanup Cron Expression"
+msgstr "日志清理 Cron 表达式"
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:49
+msgid "Log Cleanup Size Threshold (MB)"
+msgstr "日志清理大小阈值(MB)"
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:42
+msgid "Log Size Check Cron Expression"
+msgstr "日志大小检查 Cron 表达式"
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:37
+msgid "Run unconditional log cleanup at the configured cron schedule."
+msgstr "按设定的 Cron 时间无条件执行日志清理。"
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:29
+msgid "Scheduled Log Cleanup"
+msgstr "定时日志清理"
+
+#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:39
+msgid "Size-based Log Cleanup"
+msgstr "按大小触发日志清理"
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/hysteria2.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/hysteria2.lua
index e06eb72d..0aa837c1 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/hysteria2.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/hysteria2.lua
@@ -32,9 +32,10 @@ o = s:option(Value, _n("hop"), translate("Port hopping range"))
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
o.rewrite_option = o.option
-o = s:option(Value, _n("hop_interval"), translate("Hop Interval"), translate("Example:") .. "30s (≥5s)")
-o.placeholder = "30s"
-o.default = "30s"
+o = s:option(Value, _n("hop_interval"), translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
+o.datatype = "or(uinteger,portrange)"
+o.placeholder = "30"
+o.default = "30"
o.rewrite_option = o.option
o = s:option(Value, _n("obfs"), translate("Obfs Password"))
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua
index 0701c514..891ed102 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua
@@ -305,9 +305,10 @@ o = s:option(Value, _n("hysteria2_hop"), translate("Port hopping range"))
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
o:depends({ [_n("protocol")] = "hysteria2" })
-o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval"), translate("Example:") .. "30s (≥5s)")
-o.placeholder = "30s"
-o.default = "30s"
+o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
+o.datatype = "or(uinteger,portrange)"
+o.placeholder = "30"
+o.default = "30"
o:depends({ [_n("protocol")] = "hysteria2" })
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua
index 58a6a9ab..95c0a2a0 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua
@@ -278,9 +278,10 @@ if singbox_tags:find("with_quic") then
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
o:depends({ [_n("protocol")] = "hysteria" })
- o = s:option(Value, _n("hysteria_hop_interval"), translate("Hop Interval"), translate("Example:") .. "30s (≥5s)")
- o.placeholder = "30s"
- o.default = "30s"
+ o = s:option(Value, _n("hysteria_hop_interval"), translate("Hop Interval(second)"), translate("Example:") .. "30 (≥5)")
+ o.datatype = "uinteger"
+ o.placeholder = "30"
+ o.default = "30"
o:depends({ [_n("protocol")] = "hysteria" })
o = s:option(Value, _n("hysteria_obfs"), translate("Obfs Password"))
@@ -362,9 +363,10 @@ if singbox_tags:find("with_quic") then
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
o:depends({ [_n("protocol")] = "hysteria2" })
- o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval"), translate("Example:") .. "30s (≥5s)")
- o.placeholder = "30s"
- o.default = "30s"
+ o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval(Second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
+ o.datatype = "or(uinteger,portrange)"
+ o.placeholder = "30"
+ o.default = "30"
o:depends({ [_n("protocol")] = "hysteria2" })
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
diff --git a/luci-app-passwall/luasrc/passwall/util_hysteria2.lua b/luci-app-passwall/luasrc/passwall/util_hysteria2.lua
index 9d2db50a..817ae978 100644
--- a/luci-app-passwall/luasrc/passwall/util_hysteria2.lua
+++ b/luci-app-passwall/luasrc/passwall/util_hysteria2.lua
@@ -64,16 +64,27 @@ function gen_config(var)
server = server,
transport = {
type = "udp",
- udp = {
- hopInterval = (function()
- local HopIntervalStr = tostring(node.hysteria2_hop_interval or "30s")
- local HopInterval = tonumber(HopIntervalStr:match("^%d+"))
- if HopInterval and HopInterval >= 5 then
- return tostring(HopInterval) .. "s"
- end
- return "30s"
- end)(),
- }
+ udp = node.hysteria2_hop and (function()
+ local udp = {}
+ local t = node.hysteria2_hop_interval
+ if not t then return nil end
+ if t:find("-", 1, true) then
+ local min, max = t:match("^(%d+)%-(%d+)$")
+ min = tonumber(min)
+ max = tonumber(max)
+ if min and max then
+ min = (min >= 5) and min or 5
+ max = (max >= min) and max or min
+ udp.minHopInterval = min .. "s"
+ udp.maxHopInterval = max .. "s"
+ return udp
+ end
+ end
+ t = tonumber((t or "30"):match("^%d+"))
+ t = (t and t >= 5) and t or 30
+ udp.hopInterval = t .. "s"
+ return udp
+ end)() or nil
},
obfs = (node.hysteria2_obfs) and {
type = "salamander",
diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua
index 71313fed..9bb79dee 100644
--- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua
+++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua
@@ -421,7 +421,7 @@ function gen_outbound(flag, node, tag, proxy_table)
server_ports = next(server_ports) and server_ports or nil,
hop_interval = (function()
if not next(server_ports) then return nil end
- local v = tonumber((node.hysteria_hop_interval or "30s"):match("^%d+"))
+ local v = tonumber((node.hysteria_hop_interval or "30"):match("^%d+"))
return (v and v >= 5) and (v .. "s") or "30s"
end)(),
up_mbps = tonumber(node.hysteria_up_mbps),
@@ -474,13 +474,30 @@ function gen_outbound(flag, node, tag, proxy_table)
end
end
end
+ local interval, interval_max
+ if next(server_ports) then
+ interval = "30s"
+ local t = node.hysteria2_hop_interval or "30s"
+ if t:find("-", 1, true) then
+ local min, max = t:match("^(%d+)%-(%d+)$")
+ min = tonumber(min)
+ max = tonumber(max)
+ if min and max then
+ min = (min >= 5) and min or 5
+ max = (max >= min) and max or min
+ interval = min .. "s"
+ interval_max = max .. "s"
+ end
+ else
+ t = tonumber(t:match("^%d+"))
+ t = (t and t >= 5) and t or 30
+ interval = t .. "s"
+ end
+ end
protocol_table = {
server_ports = next(server_ports) and server_ports or nil,
- hop_interval = (function()
- if not next(server_ports) then return nil end
- local v = tonumber((node.hysteria2_hop_interval or "30s"):match("^%d+"))
- return (v and v >= 5) and (v .. "s") or "30s"
- end)(),
+ hop_interval = interval,
+ hop_interval_max = interval_max,
up_mbps = (node.hysteria2_up_mbps and tonumber(node.hysteria2_up_mbps)) and tonumber(node.hysteria2_up_mbps) or nil,
down_mbps = (node.hysteria2_down_mbps and tonumber(node.hysteria2_down_mbps)) and tonumber(node.hysteria2_down_mbps) or nil,
obfs = node.hysteria2_obfs_type and {
diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua
index 87d0690a..2ad66e8f 100644
--- a/luci-app-passwall/luasrc/passwall/util_xray.lua
+++ b/luci-app-passwall/luasrc/passwall/util_xray.lua
@@ -284,7 +284,19 @@ function gen_outbound(flag, node, tag, proxy_table)
udpHop = (node.hysteria2_hop) and {
ports = string.gsub(node.hysteria2_hop, ":", "-"),
interval = (function(v)
- v = tonumber((v or "30s"):match("^%d+"))
+ if not v then return 30 end
+ if v:find("-", 1, true) then
+ local min, max = v:match("^(%d+)%-(%d+)$")
+ min = tonumber(min)
+ max = tonumber(max)
+ if min and max then
+ min = (min >= 5) and min or 5
+ max = (max >= min) and max or min
+ return min .. "-" .. max
+ end
+ return 30
+ end
+ v = tonumber((v or "30"):match("^%d+"))
return (v and v >= 5) and v or 30
end)(node.hysteria2_hop_interval)
} or nil,
diff --git a/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm b/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm
index f04021a9..2feb6729 100644
--- a/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm
+++ b/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm
@@ -962,7 +962,11 @@ table td, .table .td {
} else {
innerHTML = innerHTML.split("{{tcping}}").join('---');
}
- innerHTML = innerHTML.split("{{url_test}}").join('<%:Test%>');
+ if (o["protocol"] && o["protocol"] !== '_shunt') {
+ innerHTML = innerHTML.split("{{url_test}}").join('<%:Test%>');
+ } else {
+ innerHTML = innerHTML.split("{{url_test}}").join('---');
+ }
innerHTML = innerHTML.split("{{id}}").join(o[".name"]);
innerHTML = innerHTML.split("{{group}}").join(o["group"] || "");
let node_remarks = get_remarks_name(o);
diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po
index 720bf3e9..93a40372 100644
--- a/luci-app-passwall/po/zh-cn/passwall.po
+++ b/luci-app-passwall/po/zh-cn/passwall.po
@@ -1807,14 +1807,14 @@ msgstr "缓冲区大小"
msgid "Buffer size for every connection (kB)"
msgstr "每一个连接的缓冲区大小(kB)"
-msgid "Handshake Timeout"
-msgstr "握手超时 "
-
msgid "Idle Timeout"
-msgstr "空闲超时 "
+msgstr "空闲超时"
-msgid "Hop Interval"
-msgstr "端口跳跃时间 "
+msgid "Hop Interval(second)"
+msgstr "端口跳跃间隔(秒)"
+
+msgid "Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."
+msgstr "支持固定值或随机范围(如 30 或 5-30),最小 5 秒。"
msgid "HeartbeatPeriod(second)"
msgstr "心跳周期(单位:秒)"
diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/hysteria2.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/hysteria2.lua
index 7a0e38f2..f50db48a 100644
--- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/hysteria2.lua
+++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/hysteria2.lua
@@ -29,9 +29,10 @@ o = s:option(Value, _n("hop"), translate("Port hopping range"))
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
o.rewrite_option = o.option
-o = s:option(Value, _n("hop_interval"), translate("Hop Interval"), translate("Example:") .. "30s (≥5s)")
-o.placeholder = "30s"
-o.default = "30s"
+o = s:option(Value, _n("hop_interval"), translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
+o.datatype = "or(uinteger,portrange)"
+o.placeholder = "30"
+o.default = "30"
o.rewrite_option = o.option
o = s:option(Value, _n("obfs"), translate("Obfs Password"))
diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua
index 804b270e..ef70a93c 100644
--- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua
+++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua
@@ -295,6 +295,7 @@ o = s:option(ListValue, _n("flow"), translate("flow"))
o.default = ""
o:value("", translate("Disable"))
o:value("xtls-rprx-vision")
+o:value("xtls-rprx-vision-udp443")
o:depends({ [_n("protocol")] = "vless" })
---- [[hysteria2]]
@@ -302,9 +303,10 @@ o = s:option(Value, _n("hysteria2_hop"), translate("Port hopping range"))
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
o:depends({ [_n("protocol")] = "hysteria2" })
-o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval"), translate("Example:") .. "30s (≥5s)")
-o.placeholder = "30s"
-o.default = "30s"
+o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
+o.datatype = "or(uinteger,portrange)"
+o.placeholder = "30"
+o.default = "30"
o:depends({ [_n("protocol")] = "hysteria2" })
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua
index 4524e81a..a69ac4fd 100644
--- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua
+++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua
@@ -315,9 +315,10 @@ if singbox_tags:find("with_quic") then
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
o:depends({ [_n("protocol")] = "hysteria" })
- o = s:option(Value, _n("hysteria_hop_interval"), translate("Hop Interval"), translate("Example:") .. "30s (≥5s)")
- o.placeholder = "30s"
- o.default = "30s"
+ o = s:option(Value, _n("hysteria_hop_interval"), translate("Hop Interval(second)"), translate("Example:") .. "30 (≥5)")
+ o.datatype = "uinteger"
+ o.placeholder = "30"
+ o.default = "30"
o:depends({ [_n("protocol")] = "hysteria" })
o = s:option(Value, _n("hysteria_obfs"), translate("Obfs Password"))
@@ -399,9 +400,10 @@ if singbox_tags:find("with_quic") then
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
o:depends({ [_n("protocol")] = "hysteria2" })
- o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval"), translate("Example:") .. "30s (≥5s)")
- o.placeholder = "30s"
- o.default = "30s"
+ o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval(Second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
+ o.datatype = "or(uinteger,portrange)"
+ o.placeholder = "30"
+ o.default = "30"
o:depends({ [_n("protocol")] = "hysteria2" })
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
diff --git a/luci-app-passwall2/luasrc/passwall2/api.lua b/luci-app-passwall2/luasrc/passwall2/api.lua
index 169892c9..3a3e43ef 100644
--- a/luci-app-passwall2/luasrc/passwall2/api.lua
+++ b/luci-app-passwall2/luasrc/passwall2/api.lua
@@ -1561,3 +1561,34 @@ function cleanEmptyTables(t)
end
return next(t) and t or nil
end
+
+function get_dnsmasq_server_domain()
+ local dnsmasq_server = uci:get("dhcp", "@dnsmasq[0]", "server")
+ local dnsmasq_server_t = {}
+ if dnsmasq_server and #dnsmasq_server > 0 then
+ for k, v in ipairs(dnsmasq_server) do
+ if v:find("/") then
+ local split1 = split(v, "/")
+ if #split1 > 2 then
+ local domain = split1[2]
+ local upstream_dns = split1[#split1]
+ local upstream_dns_server
+ local upstream_dns_port = "53"
+ local dns_split = split(upstream_dns, "#")
+ if #dns_split > 1 then
+ upstream_dns_server = dns_split[1]
+ upstream_dns_port = dns_split[#dns_split]
+ else
+ upstream_dns_server = upstream_dns
+ end
+ dnsmasq_server_t[domain] = {
+ dnsmasq_dns = upstream_dns,
+ server = upstream_dns_server,
+ port = tonumber(upstream_dns_port)
+ }
+ end
+ end
+ end
+ end
+ return dnsmasq_server_t
+end
\ No newline at end of file
diff --git a/luci-app-passwall2/luasrc/passwall2/util_hysteria2.lua b/luci-app-passwall2/luasrc/passwall2/util_hysteria2.lua
index 51d310d6..a06928a4 100644
--- a/luci-app-passwall2/luasrc/passwall2/util_hysteria2.lua
+++ b/luci-app-passwall2/luasrc/passwall2/util_hysteria2.lua
@@ -61,16 +61,27 @@ function gen_config(var)
server = server,
transport = {
type = "udp",
- udp = {
- hopInterval = (function()
- local HopIntervalStr = tostring(node.hysteria2_hop_interval or "30s")
- local HopInterval = tonumber(HopIntervalStr:match("^%d+"))
- if HopInterval and HopInterval >= 5 then
- return tostring(HopInterval) .. "s"
- end
- return "30s"
- end)(),
- }
+ udp = node.hysteria2_hop and (function()
+ local udp = {}
+ local t = node.hysteria2_hop_interval
+ if not t then return nil end
+ if t:find("-", 1, true) then
+ local min, max = t:match("^(%d+)%-(%d+)$")
+ min = tonumber(min)
+ max = tonumber(max)
+ if min and max then
+ min = (min >= 5) and min or 5
+ max = (max >= min) and max or min
+ udp.minHopInterval = min .. "s"
+ udp.maxHopInterval = max .. "s"
+ return udp
+ end
+ end
+ t = tonumber((t or "30"):match("^%d+"))
+ t = (t and t >= 5) and t or 30
+ udp.hopInterval = t .. "s"
+ return udp
+ end)() or nil
},
obfs = (node.hysteria2_obfs) and {
type = "salamander",
diff --git a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua
index fa250870..a76de67a 100644
--- a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua
+++ b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua
@@ -153,7 +153,7 @@ function gen_outbound(flag, node, tag, proxy_table)
server = node.address,
server_port = tonumber(node.port),
domain_resolver = {
- server = "direct",
+ server = "local",
strategy = node.domain_strategy
},
detour = node.detour,
@@ -436,7 +436,7 @@ function gen_outbound(flag, node, tag, proxy_table)
server_ports = next(server_ports) and server_ports or nil,
hop_interval = (function()
if not next(server_ports) then return nil end
- local v = tonumber((node.hysteria_hop_interval or "30s"):match("^%d+"))
+ local v = tonumber((node.hysteria_hop_interval or "30"):match("^%d+"))
return (v and v >= 5) and (v .. "s") or "30s"
end)(),
up_mbps = tonumber(node.hysteria_up_mbps),
@@ -489,13 +489,30 @@ function gen_outbound(flag, node, tag, proxy_table)
end
end
end
+ local interval, interval_max
+ if next(server_ports) then
+ interval = "30s"
+ local t = node.hysteria2_hop_interval or "30s"
+ if t:find("-", 1, true) then
+ local min, max = t:match("^(%d+)%-(%d+)$")
+ min = tonumber(min)
+ max = tonumber(max)
+ if min and max then
+ min = (min >= 5) and min or 5
+ max = (max >= min) and max or min
+ interval = min .. "s"
+ interval_max = max .. "s"
+ end
+ else
+ t = tonumber(t:match("^%d+"))
+ t = (t and t >= 5) and t or 30
+ interval = t .. "s"
+ end
+ end
protocol_table = {
server_ports = next(server_ports) and server_ports or nil,
- hop_interval = (function()
- if not next(server_ports) then return nil end
- local v = tonumber((node.hysteria2_hop_interval or "30s"):match("^%d+"))
- return (v and v >= 5) and (v .. "s") or "30s"
- end)(),
+ hop_interval = interval,
+ hop_interval_max = interval_max,
up_mbps = (node.hysteria2_up_mbps and tonumber(node.hysteria2_up_mbps)) and tonumber(node.hysteria2_up_mbps) or nil,
down_mbps = (node.hysteria2_down_mbps and tonumber(node.hysteria2_down_mbps)) and tonumber(node.hysteria2_down_mbps) or nil,
obfs = node.hysteria2_obfs_type and {
@@ -901,7 +918,7 @@ function gen_config_server(node)
outbound = require("luci.passwall2.util_sing-box").gen_outbound(nil, outbound_node_t, "outbound")
end
if outbound then
- route.final = "outbound"
+ route.final = outbound.tag
table.insert(outbounds, 1, outbound)
end
end
@@ -913,6 +930,14 @@ function gen_config_server(node)
timestamp = true,
--output = logfile,
},
+ dns = {
+ servers = {
+ {
+ type = "local",
+ tag = "local"
+ }
+ }
+ },
inbounds = { inbound },
outbounds = outbounds,
route = route
@@ -973,7 +998,7 @@ function gen_config(var)
local no_run = var["no_run"]
local dns_domain_rules = {}
- local dns = nil
+ local dns = {}
local inbounds = {}
local outbounds = {}
local rule_set_table = {}
@@ -1661,16 +1686,21 @@ function gen_config(var)
route.final = COMMON.default_outbound_tag
end
- if dns_listen_port then
- dns = {
- servers = {},
- rules = {},
- disable_cache = (dns_cache and dns_cache == "0") and true or false,
- disable_expire = false, -- Disable DNS cache expiration.
- independent_cache = false, -- Make each DNS server's cache independent for specific purposes. If enabled, it will slightly reduce performance.
- reverse_mapping = true, -- After responding to a DNS query, a reverse mapping of the IP address is stored to provide the domain name for routing purposes.
- }
+ dns = {
+ servers = {},
+ rules = {},
+ disable_cache = (dns_cache and dns_cache == "0") and true or false,
+ disable_expire = false, -- Disable DNS cache expiration.
+ independent_cache = false, -- Make each DNS server's cache independent for specific purposes. If enabled, it will slightly reduce performance.
+ reverse_mapping = true, -- After responding to a DNS query, a reverse mapping of the IP address is stored to provide the domain name for routing purposes.
+ }
+ table.insert(dns.servers, {
+ type = "local",
+ tag = "local"
+ })
+
+ if dns_listen_port then
local dns_host = ""
if flag == "global" then
dns_host = uci:get(appname, "@global[0]", "dns_hosts") or ""
@@ -1802,8 +1832,8 @@ function gen_config(var)
end)
if #domain > 0 then
table.insert(dns_domain_rules, 1, {
- outboundTag = "direct",
- domain = domain
+ domain = domain,
+ outboundTag = "direct"
})
end
@@ -1825,6 +1855,42 @@ function gen_config(var)
})
end
+ local dnsmasq_server_domain = api.get_dnsmasq_server_domain()
+ if next(dnsmasq_server_domain) then
+ local new_dns_servers = {}
+ for domain, v in pairs(dnsmasq_server_domain) do
+ if not new_dns_servers[v.dnsmasq_dns] then
+ new_dns_servers[v.dnsmasq_dns] = {
+ server = {
+ tag = v.dnsmasq_dns,
+ type = "udp",
+ server = v.server,
+ server_port = v.port,
+ detour = "direct",
+ },
+ rule = {
+ action = "route",
+ domain_suffix = {},
+ server = v.dnsmasq_dns,
+ strategy = direct_strategy,
+ },
+ }
+ end
+ table.insert(new_dns_servers[v.dnsmasq_dns].rule.domain_suffix, domain)
+ end
+ for k, v in pairs(new_dns_servers) do
+ table.insert(dns.servers, v.server)
+ table.insert(dns.rules, 1, v.rule)
+ table.insert(route.rules, 1, {
+ action = "route",
+ network = v.server.type,
+ ip_cidr = v.server.server,
+ port = v.server.server_port,
+ outbound = "direct",
+ })
+ end
+ end
+
local default_dns_flag = "remote"
if node_id and redir_port then
local node = get_node_by_id(node_id)
@@ -1843,7 +1909,7 @@ function gen_config(var)
if value.outboundTag and (value.domain or value.domain_suffix or value.domain_keyword or value.domain_regex or value.rule_set) then
local dns_rule = {
action = "route",
- server = value.outboundTag,
+ server = value.server or value.outboundTag,
domain = (value.domain and #value.domain > 0) and value.domain or nil,
domain_suffix = (value.domain_suffix and #value.domain_suffix > 0) and value.domain_suffix or nil,
domain_keyword = (value.domain_keyword and #value.domain_keyword > 0) and value.domain_keyword or nil,
@@ -1917,7 +1983,7 @@ function gen_config(var)
listen_port = tonumber(dns_listen_port),
}
table.insert(inbounds, dns_in_inbound)
- table.insert(route.rules, {
+ table.insert(route.rules, 1, {
action = "sniff",
inbound = dns_in_inbound.tag
})
@@ -1961,15 +2027,6 @@ function gen_config(var)
end
end
- if not dns then
- dns = {
- servers = {{
- type = "local",
- tag = "direct"
- }}
- }
- end
-
if next(ech_domain) ~= nil then
table.insert(dns.servers, {
tag = "ech-dns",
@@ -2018,7 +2075,7 @@ function gen_config(var)
tag = "direct",
routing_mark = 255,
domain_resolver = {
- server = "direct",
+ server = "local",
strategy = "prefer_ipv6"
}
})
@@ -2026,6 +2083,9 @@ function gen_config(var)
if not value["_flag_proxy_tag"] and not value.detour and value["_id"] and value.server and value.server_port and not no_run then
sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list"))
end
+ if value.detour then
+ value.domain_resolver = nil
+ end
for k, v in pairs(config.outbounds[index]) do
if k:find("_") == 1 then
config.outbounds[index][k] = nil
@@ -2039,7 +2099,7 @@ function gen_config(var)
if value.type == "wireguard" then
-- https://sing-box.sagernet.org/migration/#migrate-wireguard-outbound-to-endpoint
local endpoint = {
- type = "wireguard",
+ type = value.type,
tag = value.tag,
system = value.system_interface,
name = value.interface_name,
@@ -2056,10 +2116,7 @@ function gen_config(var)
reserved = value.reserved
}
},
- domain_resolver = {
- server = "direct",
- strategy = value.domain_strategy
- },
+ domain_resolver = value.domain_resolver,
detour = value.detour
}
endpoints[#endpoints + 1] = endpoint
diff --git a/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/luci-app-passwall2/luasrc/passwall2/util_xray.lua
index 6093ad4f..81304d57 100644
--- a/luci-app-passwall2/luasrc/passwall2/util_xray.lua
+++ b/luci-app-passwall2/luasrc/passwall2/util_xray.lua
@@ -280,7 +280,19 @@ function gen_outbound(flag, node, tag, proxy_table)
udpHop = (node.hysteria2_hop) and {
ports = string.gsub(node.hysteria2_hop, ":", "-"),
interval = (function(v)
- v = tonumber((v or "30s"):match("^%d+"))
+ if not v then return 30 end
+ if v:find("-", 1, true) then
+ local min, max = v:match("^(%d+)%-(%d+)$")
+ min = tonumber(min)
+ max = tonumber(max)
+ if min and max then
+ min = (min >= 5) and min or 5
+ max = (max >= min) and max or min
+ return min .. "-" .. max
+ end
+ return 30
+ end
+ v = tonumber((v or "30"):match("^%d+"))
return (v and v >= 5) and v or 30
end)(node.hysteria2_hop_interval)
} or nil,
@@ -694,6 +706,14 @@ function gen_config_server(node)
end
end
+ for index, value in ipairs(config.outbounds) do
+ for k, v in pairs(config.outbounds[index]) do
+ if k:find("_") == 1 then
+ config.outbounds[index][k] = nil
+ end
+ end
+ end
+
return config
end
@@ -734,7 +754,7 @@ function gen_config(var)
local no_run = var["no_run"]
local dns_domain_rules = {}
- local dns = nil
+ local dns = {}
local fakedns = nil
local inbounds = {}
local outbounds = {}
@@ -1063,17 +1083,17 @@ function gen_config(var)
local to_node = get_node_by_id(node.to_node)
if to_node then
-- Landing Node not support use special node.
- if to_node.protocol:find("^_") then
+ if to_node.protocol and to_node.protocol:find("^_") then
to_node = nil
end
end
if to_node then
local to_outbound
if to_node.type ~= "Xray" then
- local tag = to_node[".name"]
+ local in_tag = "inbound_" .. to_node[".name"] .. "_" .. tostring(outbound.tag)
local new_port = api.get_new_port()
table.insert(inbounds, {
- tag = tag,
+ tag = in_tag,
listen = "127.0.0.1",
port = new_port,
protocol = "dokodemo-door",
@@ -1085,11 +1105,11 @@ function gen_config(var)
to_node.address = "127.0.0.1"
to_node.port = new_port
table.insert(rules, 1, {
- inboundTag = {tag},
+ inboundTag = {in_tag},
outboundTag = outbound.tag
})
- to_outbound = gen_outbound(node[".name"], to_node, tag, {
- tag = tag,
+ to_outbound = gen_outbound(node[".name"], to_node, to_node[".name"], {
+ tag = to_node[".name"],
run_socks_instance = not no_run
})
else
@@ -1365,13 +1385,31 @@ function gen_config(var)
}
end
end
-
+
+ dns = {
+ tag = "dns-global",
+ hosts = {},
+ disableCache = (dns_cache and dns_cache == "0") and true or false,
+ disableFallback = true,
+ disableFallbackIfMatch = true,
+ servers = {},
+ queryStrategy = "UseIP"
+ }
+
+ local dns_servers = {}
+
+ table.insert(dns_servers, {
+ server = {
+ tag = "local",
+ address = "localhost"
+ }
+ })
+
if dns_listen_port then
local direct_dns_tag = "dns-in-direct"
local remote_dns_tag = "dns-in-remote"
local remote_fakedns_tag = "dns-in-remote-fakedns"
local default_dns_tag = "dns-in-default"
- local dns_servers = {}
local _remote_dns_proto = "tcp"
@@ -1382,16 +1420,6 @@ function gen_config(var)
}
end
- dns = {
- tag = "dns-global",
- hosts = {},
- disableCache = (dns_cache and dns_cache == "0") and true or false,
- disableFallback = true,
- disableFallbackIfMatch = true,
- servers = {},
- queryStrategy = "UseIP"
- }
-
local dns_host = ""
if flag == "global" then
dns_host = uci:get(appname, "@global[0]", "dns_hosts") or ""
@@ -1510,6 +1538,39 @@ function gen_config(var)
})
end
end
+
+ local dnsmasq_server_domain = api.get_dnsmasq_server_domain()
+ if next(dnsmasq_server_domain) then
+ local new_dns_servers = {}
+ for domain, v in pairs(dnsmasq_server_domain) do
+ if not new_dns_servers[v.dnsmasq_dns] then
+ new_dns_servers[v.dnsmasq_dns] = {
+ server = {
+ tag = v.dnsmasq_dns,
+ address = v.server,
+ port = v.port,
+ queryStrategy = (direct_dns_query_strategy and direct_dns_query_strategy ~= "") and direct_dns_query_strategy or "UseIP"
+ },
+ domain = {}
+ }
+ end
+ table.insert(new_dns_servers[v.dnsmasq_dns].domain, domain)
+ end
+ for k, v in pairs(new_dns_servers) do
+ table.insert(dns_domain_rules, 1, {
+ shunt_rule_name = k,
+ outboundTag = "direct",
+ dns_server = v.server,
+ domain = v.domain
+ })
+ table.insert(routing.rules, 1, {
+ network = "udp",
+ ip = v.server.address,
+ port = v.server.port,
+ outboundTag = "direct"
+ })
+ end
+ end
if dns_listen_port then
table.insert(inbounds, {
@@ -1590,7 +1651,9 @@ function gen_config(var)
if value.domain and value.outboundTag then
local dns_server = nil
local dns_outboundTag = value.outboundTag
- if value.outboundTag == "direct" then
+ if value.dns_server then
+ dns_server = api.clone(value.dns_server)
+ elseif value.outboundTag == "direct" then
dns_server = api.clone(_direct_dns)
else
if value.fakedns then
@@ -1657,15 +1720,6 @@ function gen_config(var)
table.insert(routing.rules, default_rule)
end
- local dns_hosts_len = 0
- for key, value in pairs(dns.hosts) do
- dns_hosts_len = dns_hosts_len + 1
- end
-
- if dns_hosts_len == 0 then
- dns.hosts = nil
- end
-
local content = flag .. node_id .. jsonc.stringify(routing.rules)
if api.cacheFileCompareToLogic(CACHE_TEXT_FILE, content) == false then
--clear ipset/nftset
@@ -1701,6 +1755,10 @@ function gen_config(var)
end
end
+ if not next(dns.hosts) then
+ dns.hosts = nil
+ end
+
if redir_port then
local inbound = {
port = tonumber(redir_port),
diff --git a/luci-app-passwall2/luasrc/view/passwall2/node_config/link_share_man.htm b/luci-app-passwall2/luasrc/view/passwall2/node_config/link_share_man.htm
index 53ff4c46..d1941043 100644
--- a/luci-app-passwall2/luasrc/view/passwall2/node_config/link_share_man.htm
+++ b/luci-app-passwall2/luasrc/view/passwall2/node_config/link_share_man.htm
@@ -1455,7 +1455,7 @@ local current_node = map:get(section)
opt.set(dom_prefix + 'port', m.port || "443");
opt.set(dom_prefix + 'encryption', queryParam.encryption || "none");
- opt.set(dom_prefix + 'flow', (queryParam.flow || '').replace('-udp443', ''));
+ opt.set(dom_prefix + 'flow', queryParam.flow || '');
if (queryParam.security) {
if (queryParam.security == "tls") {
opt.set(dom_prefix + 'tls', true);
diff --git a/luci-app-passwall2/luasrc/view/passwall2/node_list/node_list.htm b/luci-app-passwall2/luasrc/view/passwall2/node_list/node_list.htm
index 532e0b10..d067da1e 100644
--- a/luci-app-passwall2/luasrc/view/passwall2/node_list/node_list.htm
+++ b/luci-app-passwall2/luasrc/view/passwall2/node_list/node_list.htm
@@ -963,7 +963,11 @@ table td, .table .td {
} else {
innerHTML = innerHTML.split("{{tcping}}").join('---');
}
- innerHTML = innerHTML.split("{{url_test}}").join('<%:Test%>');
+ if (o["address"] && o["port"]) {
+ innerHTML = innerHTML.split("{{url_test}}").join('<%:Test%>');
+ } else {
+ innerHTML = innerHTML.split("{{url_test}}").join('---');
+ }
innerHTML = innerHTML.split("{{id}}").join(o[".name"]);
innerHTML = innerHTML.split("{{group}}").join(o["group"] || "");
let node_remarks = get_remarks_name(o);
diff --git a/luci-app-passwall2/po/fa/passwall2.po b/luci-app-passwall2/po/fa/passwall2.po
index 177d1409..2d7dab7b 100644
--- a/luci-app-passwall2/po/fa/passwall2.po
+++ b/luci-app-passwall2/po/fa/passwall2.po
@@ -1638,14 +1638,14 @@ msgstr "اندازه بافر"
msgid "Buffer size for every connection (kB)"
msgstr "اندازه بافر برای هر اتصال (کیلوبایت)"
-msgid "Handshake Timeout"
-msgstr "مهلت زمانی دست تکان دادن"
-
msgid "Idle Timeout"
msgstr "مهلت زمانی بیکاری"
-msgid "Hop Interval"
-msgstr "بازه پرش (Hop)"
+msgid "Hop Interval(second)"
+msgstr "فاصله پرش (ثانیه)"
+
+msgid "Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."
+msgstr "از یک مقدار ثابت یا یک محدوده تصادفی (مثلاً 30، 5-30)، حداقل 5، پشتیبانی میکند."
msgid "HeartbeatPeriod(second)"
msgstr "دوره ضربان قلب (ثانیه)"
diff --git a/luci-app-passwall2/po/ru/passwall2.po b/luci-app-passwall2/po/ru/passwall2.po
index c413809f..fd19b737 100644
--- a/luci-app-passwall2/po/ru/passwall2.po
+++ b/luci-app-passwall2/po/ru/passwall2.po
@@ -1639,14 +1639,14 @@ msgstr "Размер буфера"
msgid "Buffer size for every connection (kB)"
msgstr "Размер буфера для каждого соединения (КБ)"
-msgid "Handshake Timeout"
-msgstr "Тайм-аут рукопожатия"
-
msgid "Idle Timeout"
msgstr "Тайм-аут простоя"
-msgid "Hop Interval"
-msgstr "Интервал смены порта"
+msgid "Hop Interval(second)"
+msgstr "Интервал прыжков (секунды)"
+
+msgid "Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."
+msgstr "Поддерживается фиксированное значение или случайный диапазон (например, 30, 5-30), минимум 5."
msgid "HeartbeatPeriod(second)"
msgstr "Период heartbeat-пакетов (сек)"
diff --git a/luci-app-passwall2/po/zh-cn/passwall2.po b/luci-app-passwall2/po/zh-cn/passwall2.po
index 75397943..c9d5ec1d 100644
--- a/luci-app-passwall2/po/zh-cn/passwall2.po
+++ b/luci-app-passwall2/po/zh-cn/passwall2.po
@@ -1630,14 +1630,14 @@ msgstr "缓冲区大小"
msgid "Buffer size for every connection (kB)"
msgstr "每一个连接的缓冲区大小(kB)"
-msgid "Handshake Timeout"
-msgstr "握手超时 "
-
msgid "Idle Timeout"
-msgstr "空闲超时 "
+msgstr "空闲超时"
-msgid "Hop Interval"
-msgstr "端口跳跃时间 "
+msgid "Hop Interval(second)"
+msgstr "端口跳跃间隔(秒)"
+
+msgid "Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."
+msgstr "支持固定值或随机范围(如 30 或 5-30),最小 5 秒。"
msgid "HeartbeatPeriod(second)"
msgstr "心跳周期(单位:秒)"
diff --git a/luci-app-passwall2/po/zh-tw/passwall2.po b/luci-app-passwall2/po/zh-tw/passwall2.po
index a5bbe351..9ffae2b5 100644
--- a/luci-app-passwall2/po/zh-tw/passwall2.po
+++ b/luci-app-passwall2/po/zh-tw/passwall2.po
@@ -1630,14 +1630,14 @@ msgstr "缓衝区大小"
msgid "Buffer size for every connection (kB)"
msgstr "每一個連接的缓衝区大小(kB)"
-msgid "Handshake Timeout"
-msgstr "握手超時 "
-
msgid "Idle Timeout"
-msgstr "空闲超時 "
+msgstr "空闲超時"
-msgid "Hop Interval"
-msgstr "端口跳跃時間 "
+msgid "Hop Interval(second)"
+msgstr "端口跳躍間隔(秒)"
+
+msgid "Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."
+msgstr "支援固定值或隨機範圍(如 30 或 5-30),最小 5 秒。"
msgid "HeartbeatPeriod(second)"
msgstr "心跳周期(單位:秒)"
diff --git a/luci-app-passwall2/root/usr/share/passwall2/app.sh b/luci-app-passwall2/root/usr/share/passwall2/app.sh
index b45e0401..1f5b73eb 100755
--- a/luci-app-passwall2/root/usr/share/passwall2/app.sh
+++ b/luci-app-passwall2/root/usr/share/passwall2/app.sh
@@ -1169,6 +1169,7 @@ start() {
export XRAY_LOCATION_ASSET=$V2RAY_LOCATION_ASSET
export ENABLE_DEPRECATED_GEOSITE=true
export ENABLE_DEPRECATED_GEOIP=true
+ export SS_SYSTEM_DNS_RESOLVER_FORCE_BUILTIN=1
ulimit -n 65535
start_haproxy
start_socks
@@ -1237,6 +1238,7 @@ stop() {
pgrep -af "${CONFIG}/" | awk '! /app\.sh|subscribe\.lua|rule_update\.lua|tasks\.sh|server_app\.lua|ujail/{print $1}' | xargs kill -9 >/dev/null 2>&1
unset V2RAY_LOCATION_ASSET
unset XRAY_LOCATION_ASSET
+ unset SS_SYSTEM_DNS_RESOLVER_FORCE_BUILTIN
stop_crontab
rm -rf $GLOBAL_DNSMASQ_CONF
rm -rf $GLOBAL_DNSMASQ_CONF_PATH
diff --git a/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua b/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua
index c15d7d37..9fab4d10 100644
--- a/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua
+++ b/luci-app-passwall2/root/usr/share/passwall2/helper_dnsmasq.lua
@@ -272,7 +272,7 @@ function add_rule(var)
local function process_address(address)
if address == "engage.cloudflareclient.com" then return end
if datatypes.hostname(address) then
- set_domain_dns(address, fwd_dns)
+ --set_domain_dns(address, fwd_dns)
set_domain_ipset(address, setflag_4 .. "passwall2_vps," .. setflag_6 .. "passwall2_vps6")
end
end
diff --git a/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua b/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua
index 624d2ecb..7a2ae59e 100755
--- a/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua
+++ b/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua
@@ -1216,10 +1216,8 @@ local function processData(szType, content, add_mode, group)
result.httpupgrade_host = params.host
result.httpupgrade_path = params.path
end
-
result.encryption = params.encryption or "none"
-
- result.flow = params.flow and params.flow:gsub("-udp443", "") or nil
+ result.flow = params.flow
result.tls = "0"
if params.security == "tls" or params.security == "reality" then
diff --git a/momo/Makefile b/momo/Makefile
index 8dbcd7c1..21f165b5 100644
--- a/momo/Makefile
+++ b/momo/Makefile
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=momo
PKG_VERSION:=2026.03.29
-PKG_RELEASE:=4
+PKG_RELEASE:=5
PKG_LICENSE:=GPL-3.0+
PKG_MAINTAINER:=Joseph Mory
diff --git a/momo/files/momo.conf b/momo/files/momo.conf
index a03a832b..15710b93 100644
--- a/momo/files/momo.conf
+++ b/momo/files/momo.conf
@@ -8,6 +8,13 @@ config config 'config'
option 'test_profile' '1'
option 'core_only' '0'
+config log 'log'
+ option 'log_cleanup_enabled' '0'
+ option 'log_cleanup_cron_expression' '0 4 * * *'
+ option 'log_cleanup_size_enabled' '0'
+ option 'log_cleanup_size_check_cron_expression' '*/30 * * * *'
+ option 'log_cleanup_size_mb' '50'
+
config procd 'procd'
option 'fast_reload' '0'
diff --git a/momo/files/momo.init b/momo/files/momo.init
index 4b6aabba..e3a11d2e 100644
--- a/momo/files/momo.init
+++ b/momo/files/momo.init
@@ -9,6 +9,8 @@ PROG="/usr/bin/sing-box"
. "$IPKG_INSTROOT/etc/momo/scripts/include.sh"
extra_command 'update_subscription' 'Update subscription by section id'
+extra_command 'cleanup_logs' 'Cleanup logs immediately'
+extra_command 'check_log_cleanup' 'Cleanup logs if size threshold is reached'
boot_func() {
# prepare files
@@ -56,11 +58,17 @@ start_service() {
# get config
## app config
local scheduled_restart cron_expression profile test_profile core_only
+ local log_cleanup_enabled log_cleanup_cron_expression log_cleanup_size_enabled log_cleanup_size_check_cron_expression log_cleanup_size_mb
config_get_bool scheduled_restart "config" "scheduled_restart" 0
config_get cron_expression "config" "cron_expression"
config_get profile "config" "profile"
config_get_bool test_profile "config" "test_profile" 0
config_get_bool core_only "config" "core_only" 0
+ config_get_bool log_cleanup_enabled "log" "log_cleanup_enabled" 0
+ config_get log_cleanup_cron_expression "log" "log_cleanup_cron_expression"
+ config_get_bool log_cleanup_size_enabled "log" "log_cleanup_size_enabled" 0
+ config_get log_cleanup_size_check_cron_expression "log" "log_cleanup_size_check_cron_expression"
+ config_get log_cleanup_size_mb "log" "log_cleanup_size_mb" 0
## procd config
### general
local fast_reload
@@ -194,9 +202,23 @@ start_service() {
procd_close_instance
# cron
+ local cron_reload; cron_reload=0
if [ "$scheduled_restart" = 1 ] && [ -n "$cron_expression" ]; then
log "App" "Set scheduled restart."
- echo "$cron_expression /etc/init.d/momo restart #momo" >> "/etc/crontabs/root"
+ echo "$cron_expression /etc/init.d/momo restart #momo_scheduled_restart" >> "/etc/crontabs/root"
+ cron_reload=1
+ fi
+ if [ "$log_cleanup_enabled" = 1 ] && [ -n "$log_cleanup_cron_expression" ]; then
+ log "Log" "Set scheduled log cleanup."
+ echo "$log_cleanup_cron_expression /etc/init.d/momo cleanup_logs > /dev/null 2>&1 #momo_log_cleanup_time" >> "/etc/crontabs/root"
+ cron_reload=1
+ fi
+ if [ "$log_cleanup_size_enabled" = 1 ] && [ -n "$log_cleanup_size_check_cron_expression" ] && [ "${log_cleanup_size_mb:-0}" -gt 0 ]; then
+ log "Log" "Set size-based log cleanup check."
+ echo "$log_cleanup_size_check_cron_expression /etc/init.d/momo check_log_cleanup > /dev/null 2>&1 #momo_log_cleanup_size" >> "/etc/crontabs/root"
+ cron_reload=1
+ fi
+ if [ "$cron_reload" = 1 ]; then
/etc/init.d/cron restart
fi
# set started flag
@@ -405,6 +427,46 @@ cleanup() {
/etc/init.d/cron restart
}
+cleanup_logs() {
+ prepare_files
+ run_log_cleanup "scheduled trigger"
+}
+
+check_log_cleanup() {
+ prepare_files
+ config_load momo
+
+ local log_cleanup_size_enabled log_cleanup_size_mb total_size_bytes threshold_size_bytes
+ config_get_bool log_cleanup_size_enabled "log" "log_cleanup_size_enabled" 0
+ config_get log_cleanup_size_mb "log" "log_cleanup_size_mb" 0
+
+ if [ "$log_cleanup_size_enabled" != 1 ] || [ "${log_cleanup_size_mb:-0}" -le 0 ]; then
+ return
+ fi
+
+ total_size_bytes=$(get_total_log_size)
+ threshold_size_bytes=$((log_cleanup_size_mb * 1024 * 1024))
+
+ if [ "$total_size_bytes" -lt "$threshold_size_bytes" ]; then
+ return
+ fi
+
+ run_log_cleanup "size threshold ${log_cleanup_size_mb} MB reached" "$total_size_bytes"
+}
+
+run_log_cleanup() {
+ local reason previous_size
+ reason="$1"
+ previous_size="$2"
+
+ if [ -z "$previous_size" ]; then
+ previous_size=$(get_total_log_size)
+ fi
+
+ clear_log
+ log "Log" "Cleanup executed: ${reason}. Previous total size: $(format_filesize "$previous_size")."
+}
+
update_subscription() {
local subscription_section; subscription_section="$1"
if [ -z "$subscription_section" ]; then
diff --git a/momo/files/scripts/include.sh b/momo/files/scripts/include.sh
index feac9a8a..18e8e6c2 100644
--- a/momo/files/scripts/include.sh
+++ b/momo/files/scripts/include.sh
@@ -118,6 +118,9 @@ prepare_files() {
if [ ! -f "$CORE_LOG_PATH" ]; then
touch "$CORE_LOG_PATH"
fi
+ if [ ! -f "$DEBUG_LOG_PATH" ]; then
+ touch "$DEBUG_LOG_PATH"
+ fi
if [ ! -d "$TEMP_DIR" ]; then
mkdir -p "$TEMP_DIR"
fi
@@ -126,6 +129,26 @@ prepare_files() {
clear_log() {
echo -n > "$APP_LOG_PATH"
echo -n > "$CORE_LOG_PATH"
+ echo -n > "$DEBUG_LOG_PATH"
+}
+
+get_filesize() {
+ local path; path="$1"
+ if [ ! -f "$path" ]; then
+ echo 0
+ return
+ fi
+ wc -c < "$path" | tr -d '[:space:]'
+}
+
+get_total_log_size() {
+ local total_size path path_size
+ total_size=0
+ for path in "$APP_LOG_PATH" "$CORE_LOG_PATH" "$DEBUG_LOG_PATH"; do
+ path_size=$(get_filesize "$path")
+ total_size=$((total_size + path_size))
+ done
+ echo "$total_size"
}
log() {
diff --git a/momo/files/uci-defaults/migrate.sh b/momo/files/uci-defaults/migrate.sh
index 2f47856a..20e3ce4f 100644
--- a/momo/files/uci-defaults/migrate.sh
+++ b/momo/files/uci-defaults/migrate.sh
@@ -25,6 +25,45 @@ procd=$(uci -q get momo.procd); [ -z "$procd" ] && {
dummy_device=$(uci -q get momo.routing.dummy_device); [ -z "$dummy_device" ] && uci set momo.routing.dummy_device=momo-dummy
+# since v1.1.2
+
+section_log=$(uci -q get momo.log); [ -z "$section_log" ] && uci set momo.log=log
+
+log_cleanup_enabled=$(uci -q get momo.log.log_cleanup_enabled)
+[ -z "$log_cleanup_enabled" ] && {
+ log_cleanup_enabled=$(uci -q get momo.config.log_cleanup_enabled)
+ [ -n "$log_cleanup_enabled" ] && uci set momo.log.log_cleanup_enabled=$log_cleanup_enabled || uci set momo.log.log_cleanup_enabled=0
+}
+uci -q del momo.config.log_cleanup_enabled
+
+log_cleanup_cron_expression=$(uci -q get momo.log.log_cleanup_cron_expression)
+[ -z "$log_cleanup_cron_expression" ] && {
+ log_cleanup_cron_expression=$(uci -q get momo.config.log_cleanup_cron_expression)
+ [ -n "$log_cleanup_cron_expression" ] && uci set momo.log.log_cleanup_cron_expression="$log_cleanup_cron_expression" || uci set momo.log.log_cleanup_cron_expression='0 4 * * *'
+}
+uci -q del momo.config.log_cleanup_cron_expression
+
+log_cleanup_size_enabled=$(uci -q get momo.log.log_cleanup_size_enabled)
+[ -z "$log_cleanup_size_enabled" ] && {
+ log_cleanup_size_enabled=$(uci -q get momo.config.log_cleanup_size_enabled)
+ [ -n "$log_cleanup_size_enabled" ] && uci set momo.log.log_cleanup_size_enabled=$log_cleanup_size_enabled || uci set momo.log.log_cleanup_size_enabled=0
+}
+uci -q del momo.config.log_cleanup_size_enabled
+
+log_cleanup_size_check_cron_expression=$(uci -q get momo.log.log_cleanup_size_check_cron_expression)
+[ -z "$log_cleanup_size_check_cron_expression" ] && {
+ log_cleanup_size_check_cron_expression=$(uci -q get momo.config.log_cleanup_size_check_cron_expression)
+ [ -n "$log_cleanup_size_check_cron_expression" ] && uci set momo.log.log_cleanup_size_check_cron_expression="$log_cleanup_size_check_cron_expression" || uci set momo.log.log_cleanup_size_check_cron_expression='*/30 * * * *'
+}
+uci -q del momo.config.log_cleanup_size_check_cron_expression
+
+log_cleanup_size_mb=$(uci -q get momo.log.log_cleanup_size_mb)
+[ -z "$log_cleanup_size_mb" ] && {
+ log_cleanup_size_mb=$(uci -q get momo.config.log_cleanup_size_mb)
+ [ -n "$log_cleanup_size_mb" ] && uci set momo.log.log_cleanup_size_mb=$log_cleanup_size_mb || uci set momo.log.log_cleanup_size_mb=50
+}
+uci -q del momo.config.log_cleanup_size_mb
+
# commit
uci commit momo