🦄 Sync 2026-04-07 20:32:07

This commit is contained in:
github-actions[bot] 2026-04-07 20:32:07 +08:00
parent 5dddf79b1b
commit 6c4fe80788
34 changed files with 604 additions and 161 deletions

View File

@ -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'));

View File

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

View File

@ -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
});
}
});

View File

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

View File

@ -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 "按大小触发日志清理"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -962,7 +962,11 @@ table td, .table .td {
} else {
innerHTML = innerHTML.split("{{tcping}}").join('<span class="tcping_value" cbiid="{{id}}"><a href="javascript:void(0)" style="color:inherit">---</a></span>');
}
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:urltest_node(\'{{id}}\', this)" title="<%:TLS handshake test, latency for reference only%>"><%:Test%></a></span>');
if (o["protocol"] && o["protocol"] !== '_shunt') {
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:urltest_node(\'{{id}}\', this)" title="<%:TLS handshake test, latency for reference only%>"><%:Test%></a></span>');
} else {
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping" cbiid="{{id}}">---</span>');
}
innerHTML = innerHTML.split("{{id}}").join(o[".name"]);
innerHTML = innerHTML.split("{{group}}").join(o["group"] || "");
let node_remarks = get_remarks_name(o);

View File

@ -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 "心跳周期(单位:秒)"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -963,7 +963,11 @@ table td, .table .td {
} else {
innerHTML = innerHTML.split("{{tcping}}").join('<span class="tcping_value" cbiid="{{id}}"><a href="javascript:void(0)" style="color:inherit">---</a></span>');
}
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:urltest_node(\'{{id}}\', this)"><%:Test%></a></span>');
if (o["address"] && o["port"]) {
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:urltest_node(\'{{id}}\', this)"><%:Test%></a></span>');
} else {
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping_value"><a href="javascript:void(0)" style="color:inherit">---</a></span>');
}
innerHTML = innerHTML.split("{{id}}").join(o[".name"]);
innerHTML = innerHTML.split("{{group}}").join(o["group"] || "");
let node_remarks = get_remarks_name(o);

View File

@ -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 "دوره ضربان قلب (ثانیه)"

View File

@ -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-пакетов (сек)"

View File

@ -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 "心跳周期(单位:秒)"

View File

@ -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 "心跳周期(單位:秒)"

View File

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

View File

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

View File

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

View File

@ -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 <morytyann@gmail.com>

View File

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

View File

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

View File

@ -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() {

View File

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