update 2026-06-04 00:28:20

This commit is contained in:
action
2026-06-04 00:28:20 +08:00
parent a3dfac28a4
commit 623cdab94c
36 changed files with 468 additions and 228 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
include $(TOPDIR)/rules.mk
PKG_VERSION:=1.2.0
PKG_VERSION:=1.2.1
LUCI_TITLE:=LuCI Support for momo
LUCI_DEPENDS:=+luci-base +momo
@@ -134,6 +134,12 @@ return view.extend({
s.tab('rlimit', _('RLIMIT Config'));
o = s.taboption('rlimit', form.Value, 'rlimit_nproc_soft', _('Number of Processes Soft Limit'));
o.datatype = 'uinteger';
o = s.taboption('rlimit', form.Value, 'rlimit_nproc_hard', _('Number of Processes Hard Limit'));
o.datatype = 'uinteger';
o = s.taboption('rlimit', form.Value, 'rlimit_address_space_soft', _('Address Space Size Soft Limit'));
o.datatype = 'uinteger';
o.placeholder = _('Unlimited');
@@ -164,6 +170,16 @@ return view.extend({
o = s.taboption('rlimit', form.Value, 'rlimit_nofile_hard', _('Number of Open Files Hard Limit'));
o.datatype = 'uinteger';
s.tab('environment_variable', _('Environment Variable Config'));
o = s.taboption('environment_variable', form.Value, 'env_go_max_procs', 'GOMAXPROCS');
o.datatype = 'uinteger';
o.placeholder = _('Unlimited');
o = s.taboption('environment_variable', form.Value, 'env_go_mem_limit', 'GOMEMLIMIT');
o.datatype = 'uinteger';
o.placeholder = _('Unlimited');
return m.render();
}
});
@@ -28,6 +28,9 @@ return view.extend({
s.tab('log_config', _('Log Config'));
o = s.taboption('log_config', form.Flag, 'clear_at_stop', _('Clear At Stop'));
o.rmempty = false;
o = s.taboption('log_config', form.Flag, 'scheduled_clear', _('Scheduled Clear'));
o.rmempty = false;
+44 -26
View File
@@ -14,11 +14,11 @@ msgstr ""
msgid "Access Control"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:141
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:147
msgid "Address Space Size Hard Limit"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:137
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:143
msgid "Address Space Size Soft Limit"
msgstr ""
@@ -32,7 +32,7 @@ msgstr ""
msgid "App Config"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:53
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:56
msgid "App Log"
msgstr ""
@@ -92,8 +92,12 @@ msgstr ""
msgid "Choose Profile"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:57
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:90
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:31
msgid "Clear At Stop"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:60
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:93
msgid "Clear Log"
msgstr ""
@@ -102,7 +106,7 @@ msgstr ""
msgid "Commonly Used Port"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:86
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:89
msgid "Core Log"
msgstr ""
@@ -151,7 +155,7 @@ msgstr ""
msgid "DNS Strategy"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:119
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:122
msgid "Debug Log"
msgstr ""
@@ -206,6 +210,10 @@ msgstr ""
msgid "Enable"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:173
msgid "Environment Variable Config"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/profile.js:50
msgid "Expire At"
msgstr ""
@@ -231,7 +239,7 @@ msgstr ""
msgid "General Config"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:123
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:126
msgid "Generate & Download"
msgstr ""
@@ -243,11 +251,11 @@ msgstr ""
msgid "Group"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:149
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:155
msgid "Heap Size Hard Limit"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:145
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:151
msgid "Heap Size Soft Limit"
msgstr ""
@@ -358,14 +366,22 @@ msgstr ""
msgid "Not Running"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:164
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:170
msgid "Number of Open Files Hard Limit"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:161
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:167
msgid "Number of Open Files Soft Limit"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:140
msgid "Number of Processes Hard Limit"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:137
msgid "Number of Processes Soft Limit"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:89
msgid "Open Dashboard"
msgstr ""
@@ -438,19 +454,19 @@ msgstr ""
msgid "Running"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:31
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:34
msgid "Scheduled Clear"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:34
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:37
msgid "Scheduled Clear Cron"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:39
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:42
msgid "Scheduled Clear Size Limit"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:45
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:48
msgid "Scheduled Clear Size Limit Unit"
msgstr ""
@@ -462,16 +478,16 @@ msgstr ""
msgid "Scheduled Restart Cron"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:80
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:113
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:83
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:116
msgid "Scroll To Bottom"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:157
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:163
msgid "Stack Size Hard Limit"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:153
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:159
msgid "Stack Size Soft Limit"
msgstr ""
@@ -554,12 +570,14 @@ msgstr ""
msgid "UI Path"
msgstr ""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:139
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:143
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:147
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:151
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:155
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:159
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:145
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:149
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:153
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:157
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:161
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:165
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:177
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:181
msgid "Unlimited"
msgstr ""
+46 -60
View File
@@ -21,11 +21,11 @@ msgstr "API 密码"
msgid "Access Control"
msgstr "访问控制"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:141
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:147
msgid "Address Space Size Hard Limit"
msgstr "地址空间大小硬限制"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:137
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:143
msgid "Address Space Size Soft Limit"
msgstr "地址空间大小软限制"
@@ -39,7 +39,7 @@ msgstr "全部端口"
msgid "App Config"
msgstr "插件配置"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:53
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:56
msgid "App Log"
msgstr "插件日志"
@@ -99,8 +99,12 @@ msgstr "选择文件"
msgid "Choose Profile"
msgstr "选择配置文件"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:57
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:90
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:31
msgid "Clear At Stop"
msgstr "停止时清空"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:60
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:93
msgid "Clear Log"
msgstr "清空日志"
@@ -109,7 +113,7 @@ msgstr "清空日志"
msgid "Commonly Used Port"
msgstr "常用端口"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:86
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:89
msgid "Core Log"
msgstr "核心日志"
@@ -158,7 +162,7 @@ msgstr "DNS 反向映射"
msgid "DNS Strategy"
msgstr "DNS 策略"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:119
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:122
msgid "Debug Log"
msgstr "调试日志"
@@ -213,6 +217,10 @@ msgstr "编辑器"
msgid "Enable"
msgstr "启用"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:173
msgid "Environment Variable Config"
msgstr "环境变量配置"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/profile.js:50
msgid "Expire At"
msgstr "到期时间"
@@ -238,7 +246,7 @@ msgstr "文件:"
msgid "General Config"
msgstr "全局配置"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:123
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:126
msgid "Generate & Download"
msgstr "生成并下载"
@@ -250,11 +258,11 @@ msgstr "授予访问 momo 程序的权限"
msgid "Group"
msgstr "用户组"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:149
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:155
msgid "Heap Size Hard Limit"
msgstr "堆大小硬限制"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:145
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:151
msgid "Heap Size Soft Limit"
msgstr "堆大小软限制"
@@ -365,14 +373,22 @@ msgstr "NTP 服务端口"
msgid "Not Running"
msgstr "未在运行"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:164
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:170
msgid "Number of Open Files Hard Limit"
msgstr "打开文件数量硬限制"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:161
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:167
msgid "Number of Open Files Soft Limit"
msgstr "打开文件数量软限制"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:140
msgid "Number of Processes Hard Limit"
msgstr "进程数硬限制"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:137
msgid "Number of Processes Soft Limit"
msgstr "进程数软限制"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:89
msgid "Open Dashboard"
msgstr "打开面板"
@@ -445,19 +461,19 @@ msgstr "路由器代理"
msgid "Running"
msgstr "运行中"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:31
msgid "Scheduled Clear"
msgstr "定时清除""
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:34
msgid "Scheduled Clear"
msgstr "定时清空"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:37
msgid "Scheduled Clear Cron"
msgstr "Cron 表达式"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:39
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:42
msgid "Scheduled Clear Size Limit"
msgstr "日志大小上限"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:45
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:48
msgid "Scheduled Clear Size Limit Unit"
msgstr "日志大小上限单位"
@@ -469,16 +485,16 @@ msgstr "定时重启"
msgid "Scheduled Restart Cron"
msgstr "Cron 表达式"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:80
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:113
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:83
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/log.js:116
msgid "Scroll To Bottom"
msgstr "滚动到底部"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:157
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:163
msgid "Stack Size Hard Limit"
msgstr "栈大小硬限制"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:153
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:159
msgid "Stack Size Soft Limit"
msgstr "栈大小软限制"
@@ -561,12 +577,14 @@ msgstr "UI 下载地址"
msgid "UI Path"
msgstr "UI 路径"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:139
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:143
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:147
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:151
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:155
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:159
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:145
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:149
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:153
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:157
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:161
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:165
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:177
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:181
msgid "Unlimited"
msgstr "无限制"
@@ -626,35 +644,3 @@ msgstr "用户代理(UA"
#: applications/luci-app-momo/htdocs/luci-static/resources/view/momo/app.js:128
msgid "procd Config"
msgstr "procd 配置"
#~ msgid "Cron Expression"
#~ msgstr "Cron 表达式"
#~ msgid "Check log size at the configured cron schedule before cleaning up."
#~ msgstr "按设定的 Cron 周期检查日志大小,满足条件后再清理。"
#~ msgid ""
#~ "Clear app, core and debug logs when their total size reaches this "
#~ "threshold."
#~ msgstr "当插件日志、核心日志和调试日志总大小达到该阈值时自动清理。"
#~ msgid "Log Cleanup"
#~ msgstr "日志清理"
#~ msgid "Log Cleanup Cron Expression"
#~ msgstr "日志清理 Cron 表达式"
#~ msgid "Log Cleanup Size Threshold (MB)"
#~ msgstr "日志清理大小阈值(MB"
#~ msgid "Log Size Check Cron Expression"
#~ msgstr "日志大小检查 Cron 表达式"
#~ msgid "Run unconditional log cleanup at the configured cron schedule."
#~ msgstr "按设定的 Cron 时间无条件执行日志清理。"
#~ msgid "Scheduled Log Cleanup"
#~ msgstr "定时日志清理"
#~ msgid "Size-based Log Cleanup"
#~ msgstr "按大小触发日志清理"
@@ -1067,10 +1067,12 @@ function fetch_certsha256()
local id = http.formvalue("id") or ""
local address = (id ~= "") and uci:get(appname, id, "address") or ""
local port = (id ~= "") and uci:get(appname, id, "port") or 0
if id == "" or address == "" or not api.datatypes.hostname(address) or port == 0 then
local sni = (id ~= "") and uci:get(appname, id, "tls_serverName") or ""
sni = (sni ~= "") and sni or address
if address == "" or port == 0 then
http_write_json_error()
return
end
local data = api.fetch_cert_sha256(address, port, 5)
local data = api.fetch_cert_sha256(address, port, sni, 5)
http_write_json(data ~= "" and { code = 1, data = data } or { code = 0 })
end
+13 -21
View File
@@ -1570,31 +1570,23 @@ function cleanEmptyTables(t)
return next(t) and t or nil
end
function fetch_cert_sha256(host, port, timeout)
if not host or not datatypes.hostname(host) then return "" end
function fetch_cert_sha256(host, port, sni, timeout)
if not host then return "" end
port = tonumber(port) or 443
sni = sni or host
timeout = tonumber(timeout) or 5
local xray = finded_com("xray")
local cmd
if xray then
cmd = string.format(
"timeout %d %q tls ping %s:%d 2>/dev/null " ..
"| awk 'tolower($0) ~ /without sni/ {f=1} tolower($0) ~ /with sni/ {f=0} " ..
"f && tolower($0) ~ /cert.*leaf.*sha256/ {sub(/.*:/,\"\"); gsub(/[[:space:]]/,\"\"); print; exit}'",
timeout, xray, host, port
)
else
cmd = string.format(
"timeout %d openssl s_client -connect %s:%d -servername %s -showcerts </dev/null 2>/dev/null " ..
"| awk 'BEGIN{c=0}/BEGIN CERT/{c++} c==1{print} /END CERT/{if(c==1)exit}' " ..
"| openssl x509 -outform der 2>/dev/null " ..
"| sha256sum 2>/dev/null",
timeout, host, port, host
)
end
local cmd = string.format(
"timeout %d openssl s_client -connect %s:%d -servername %s -showcerts </dev/null 2>/dev/null " ..
"| awk 'BEGIN{c=0}/BEGIN CERT/{c++} c==1{print} /END CERT/{if(c==1)exit}' " ..
"| openssl x509 -outform der 2>/dev/null " ..
"| sha256sum 2>/dev/null",
timeout, host, port, sni
)
local out = trim(sys.exec(cmd))
local fp = out:match("^([0-9a-fA-F]+)")
if not fp then return "" end
if not fp or fp:lower():match("^e3b0c44298fc1c149afbf4c8996fb924") then
return ""
end
return fp:upper()
end
@@ -1666,7 +1666,8 @@ function gen_config(var)
invert = e.invert == "1" and true or nil
}
string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
w = api.trim(w)
if w == "" or w:find("#") == 1 then return end
if w:find("geosite:") == 1 then
local _geosite = w:sub(1 + #"geosite:") --适配srs
local t = geo_rule_set("geosite", _geosite)
@@ -1703,7 +1704,7 @@ function gen_config(var)
domain_table.fakedns = true
end
if outboundTag then
if outboundTag and (rule.domain or rule.domain_suffix or rule.domain_keyword or rule.domain_regex or rule.rule_set) then
table.insert(dns_domain_rules, api.clone(domain_table))
end
end
@@ -1712,7 +1713,8 @@ function gen_config(var)
local ip_cidr = {}
local is_private = false
string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
w = api.trim(w)
if w == "" or w:find("#") == 1 then return end
if w:find("geoip:") == 1 then
local _geoip = w:sub(1 + #"geoip:") --适配srs
if _geoip == "private" then
+19 -17
View File
@@ -498,9 +498,9 @@ function gen_config_server(node)
if node.protocol == "vmess" or node.protocol == "vless" then
if node.uuid then
local clients = {}
local users = {}
for i = 1, #node.uuid do
clients[i] = {
users[i] = {
id = node.uuid[i],
flow = (node.protocol == "vless"
and (node.tls == "1" or (node.decryption and node.decryption ~= "" and node.decryption ~= "none"))
@@ -508,7 +508,7 @@ function gen_config_server(node)
}
end
settings = {
clients = clients,
users = users,
decryption = (node.protocol == "vless") and ((node.decryption and node.decryption ~= "") and node.decryption or "none") or nil
}
end
@@ -516,7 +516,7 @@ function gen_config_server(node)
settings = {
udp = ("1" == node.udp_forward) and true or false,
auth = ("1" == node.auth) and "password" or "noauth",
accounts = ("1" == node.auth) and {
users = ("1" == node.auth) and {
{
user = node.username,
pass = node.password
@@ -526,7 +526,7 @@ function gen_config_server(node)
elseif node.protocol == "http" then
settings = {
allowTransparent = false,
accounts = ("1" == node.auth) and {
users = ("1" == node.auth) and {
{
user = node.username,
pass = node.password
@@ -544,20 +544,20 @@ function gen_config_server(node)
}
elseif node.protocol == "trojan" then
if node.uuid then
local clients = {}
local users = {}
for i = 1, #node.uuid do
clients[i] = {
users[i] = {
password = node.uuid[i],
}
end
settings = {
clients = clients
users = users
}
end
elseif node.protocol == "hysteria2" then
settings = {
version = 2,
clients = node.hysteria2_auth_password and {
users = node.hysteria2_auth_password and {
{ auth = node.hysteria2_auth_password }
}
}
@@ -946,7 +946,7 @@ function gen_config(var)
end
if local_socks_username and local_socks_password and local_socks_username ~= "" and local_socks_password ~= "" then
inbound.settings.auth = "password"
inbound.settings.accounts = {
inbound.settings.users = {
{
user = local_socks_username,
pass = local_socks_password
@@ -963,7 +963,7 @@ function gen_config(var)
settings = {allowTransparent = false}
}
if local_http_username and local_http_password and local_http_username ~= "" and local_http_password ~= "" then
inbound.settings.accounts = {
inbound.settings.users = {
{
user = local_http_username,
pass = local_http_password
@@ -1422,7 +1422,8 @@ function gen_config(var)
}
domains = {}
string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
w = api.trim(w)
if w == "" or w:find("#") == 1 then return end
if w:find("rule-set:", 1, true) == 1 or w:find("rs:") == 1 then return end
table.insert(domains, w)
table.insert(domain_table.domain, w)
@@ -1430,16 +1431,17 @@ function gen_config(var)
if inner_fakedns == "1" and node[e[".name"] .. "_fakedns"] == "1" and #domains > 0 then
domain_table.fakedns = true
end
if outbound_tag then
if #domains == 0 then domains = nil end
if outbound_tag and domains then
table.insert(dns_domain_rules, api.clone(domain_table))
end
if #domains == 0 then domains = nil end
end
local ip = nil
if e.ip_list then
ip = {}
string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w)
if w:find("#") == 1 then return end
w = api.trim(w)
if w == "" or w:find("#") == 1 then return end
if w:find("rule-set:", 1, true) == 1 or w:find("rs:") == 1 then return end
table.insert(ip, w)
end)
@@ -2036,7 +2038,7 @@ function gen_proto_config(var)
}
if local_socks_username and local_socks_password and local_socks_username ~= "" and local_socks_password ~= "" then
inbound.settings.auth = "password"
inbound.settings.accounts = {
inbound.settings.users = {
{
user = local_socks_username,
pass = local_socks_password
@@ -2056,7 +2058,7 @@ function gen_proto_config(var)
}
}
if local_http_username and local_http_password and local_http_username ~= "" and local_http_password ~= "" then
inbound.settings.accounts = {
inbound.settings.users = {
{
user = local_http_username,
pass = local_http_password
+1 -1
View File
@@ -6,7 +6,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2
PKG_VERSION:=26.5.19
PKG_VERSION:=26.6.3
PKG_RELEASE:=1
PKG_PO_VERSION:=$(PKG_VERSION)
@@ -22,7 +22,6 @@ function index()
local appname = api.appname -- global definitions not available
local uci = api.uci -- in function index()
entry({"admin", "services", appname}).dependent = true
entry({"admin", "services", appname, "reset_config"}, call("reset_config")).leaf = true
entry({"admin", "services", appname, "show"}, call("show_menu")).leaf = true
entry({"admin", "services", appname, "hide"}, call("hide_menu")).leaf = true
local e
@@ -109,6 +108,7 @@ function index()
--[[Backup]]
entry({"admin", "services", appname, "create_backup"}, call("create_backup")).leaf = true
entry({"admin", "services", appname, "restore_backup"}, call("restore_backup")).leaf = true
entry({"admin", "services", appname, "reset_config"}, call("reset_config")).leaf = true
--[[geoview]]
entry({"admin", "services", appname, "geo_view"}, call("geo_view")).leaf = true
@@ -130,6 +130,8 @@ local function http_write_json_error(data)
end
function reset_config()
uci:revert(appname)
luci.sys.call("echo '' > /tmp/log/passwall2.log")
luci.sys.call('/etc/init.d/passwall2 stop')
luci.sys.call('[ -f "/usr/share/passwall2/0_default_config" ] && cp -f /usr/share/passwall2/0_default_config /etc/config/passwall2')
http.redirect(api.url())
@@ -745,6 +747,7 @@ function restore_backup()
fp:write(decoded)
fp:close()
if chunk_index + 1 == total_chunks then
uci:revert(appname)
api.sys.call("echo '' > /tmp/log/passwall2.log")
api.log(0, string.format(" * PassWall2 %s", i18n.translate("Configuration file uploaded successfully…")))
local temp_dir = '/tmp/passwall2_bak'
@@ -72,7 +72,7 @@ end
m:append(Template(appname .. "/global/status"))
global_cfgid = m:get("@global[0]")[".name"]
global_cfgid = (m:get("@global[0]") or {})[".name"] or ""
s = m:section(TypedSection, "global")
s.anonymous = true
@@ -59,11 +59,13 @@ o.rewrite_option = o.option
o = s:option(ListValue, _n("obfs_type"), translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:value("gecko")
o.rewrite_option = o.option
o = s:option(Value, _n("obfs_password"), translate("Obfs Password"))
o.rewrite_option = o.option
o:depends({ [_n("obfs_type")] = "salamander" })
o:depends({ [_n("obfs_type")] = "gecko" })
o = s:option(Flag, _n("fast_open"), translate("Fast Open"))
o.default = "0"
@@ -339,13 +339,28 @@ o:depends({ [_n("protocol")] = "vless" })
---- [[hysteria2]]
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:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
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:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
o = s:option(Flag, _n("hysteria2_realms"), translate("Realms"))
o.default = "0"
if api.compare_versions(xray_version, ">", "26.5.9") then
o:depends({ [_n("protocol")] = "hysteria2"})
else
o:depends({ [_n("protocol")] = "__hide"})
end
o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
o:depends({ [_n("hysteria2_realms")] = "1" })
o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN"))
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
o:depends({ [_n("hysteria2_realms")] = "1" })
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
o.password = true
@@ -354,10 +369,12 @@ o:depends({ [_n("protocol")] = "hysteria2"})
o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:value("gecko")
o:depends({ [_n("protocol")] = "hysteria2" })
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
o:depends({ [_n("protocol")] = "hysteria2" })
@@ -431,11 +448,26 @@ if api.compare_versions(xray_version, ">=", "26.1.31") then
o:depends({ [_n("protocol")] = "hysteria2" })
end
o = s:option(Flag, _n("ech"), translate("ECH"))
o = s:option(Flag, _n("tls_certificate"), translate("TLS Certificate (PEM)"))
o.default = "0"
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o:depends({ [_n("protocol")] = "hysteria2" })
o = s:option(TextValue, _n("tls_certificate_pem"), " ", translate("Full certificate (chain), PEM format."))
o.default = ""
o.rows = 5
o.wrap = "off"
o:depends({ [_n("tls_certificate")] = true })
o.validate = function(self, value)
value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
return value
end
o = s:option(Flag, _n("ech"), translate("ECH"))
o.default = "0"
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
o = s:option(TextValue, _n("ech_config"), translate("ECH Config"))
o.default = ""
o.rows = 5
@@ -706,7 +738,7 @@ o:depends({ [_n("protocol")] = "vless" })
o:depends({ [_n("protocol")] = "trojan" })
o:depends({ [_n("protocol")] = "shadowsocks" })
o:depends({ [_n("protocol")] = "wireguard" })
o:depends({ [_n("protocol")] = "hysteria2" })
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
o = s:option(TextValue, _n("finalmask"), " ")
o:depends({ [_n("use_finalmask")] = true })
@@ -775,10 +807,14 @@ local protocols = s.fields[_n("protocol")].keylist
if #protocols > 0 then
for i, v in ipairs(protocols) do
if not v:find("^_") then
s.fields[_n("address")]:depends({ [_n("protocol")] = v })
s.fields[_n("port")]:depends({ [_n("protocol")] = v })
s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v })
s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v })
local depends_condition = { [_n("protocol")] = v }
if v == "hysteria2" then
depends_condition[_n("hysteria2_realms")] = false
end
s.fields[_n("address")]:depends(depends_condition)
s.fields[_n("port")]:depends(depends_condition)
s.fields[_n("domain_resolver")]:depends(depends_condition)
s.fields[_n("domain_strategy")]:depends(depends_condition)
if v ~= "hysteria2" then
s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v })
@@ -801,7 +837,7 @@ if not load_shunt_options then
o:value("2", translate("Landing Node"))
o1 = s:option(ListValue, _n("preproxy_node"), translate("Preproxy Node"), translate("Only support a layer of proxy."))
o1:depends({ [_n("chain_proxy")] = "1" })
o1:depends({ [_n("chain_proxy")] = "1", [_n("hysteria2_realms")] = false })
o1.template = appname .. "/cbi/nodes_listvalue"
o1.group = {}
@@ -813,7 +849,7 @@ if not load_shunt_options then
end
o2 = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Only support a layer of proxy."))
o2:depends({ [_n("chain_proxy")] = "2" })
o2:depends({ [_n("chain_proxy")] = "2", [_n("hysteria2_realms")] = false })
o2.template = appname .. "/cbi/nodes_listvalue"
o2.group = {}
@@ -423,10 +423,12 @@ if singbox_tags:find("with_quic") then
o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:value("gecko")
o:depends({ [_n("protocol")] = "hysteria2" })
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
o:depends({ [_n("protocol")] = "hysteria2" })
@@ -531,6 +533,24 @@ o:depends({ [_n("protocol")] = "hysteria"})
o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "hysteria2" })
o = s:option(Flag, _n("tls_certificate"), translate("TLS Certificate (PEM)"))
o.default = "0"
o:depends({ [_n("tls")] = true, [_n("reality")] = false })
o:depends({ [_n("protocol")] = "hysteria"})
o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "hysteria2" })
o:depends({ [_n("protocol")] = "naive" })
o = s:option(TextValue, _n("tls_certificate_pem"), " ", translate("Full certificate (chain), PEM format."))
o.default = ""
o.rows = 5
o.wrap = "off"
o:depends({ [_n("tls_certificate")] = true })
o.validate = function(self, value)
value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
return value
end
o = s:option(Flag, _n("ech"), translate("ECH"))
o.default = "0"
o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false })
@@ -48,12 +48,14 @@ o:depends({ [_n("custom")] = false })
o = s:option(ListValue, _n("obfs_type"), translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:value("gecko")
o.rewrite_option = o.option
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("obfs_password"), translate("Obfs Password"))
o.rewrite_option = o.option
o:depends({ [_n("obfs_type")] = "salamander" })
o:depends({ [_n("obfs_type")] = "gecko" })
o = s:option(Flag, _n("udp"), translate("UDP"))
o.default = "1"
@@ -127,6 +127,17 @@ o:value("xtls-rprx-vision")
o:depends({ [_n("protocol")] = "vless" })
---- [[ hysteria2 ]]
o = s:option(Flag, _n("hysteria2_realms"), translate("Realms"))
o.default = "0"
o:depends({ [_n("protocol")] = "hysteria2"})
o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
o:depends({ [_n("hysteria2_realms")] = "1" })
o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN"))
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
o:depends({ [_n("hysteria2_realms")] = "1" })
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
o.password = true
o:depends({ [_n("protocol")] = "hysteria2"})
@@ -134,10 +145,12 @@ o:depends({ [_n("protocol")] = "hysteria2"})
o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:value("gecko")
o:depends({ [_n("protocol")] = "hysteria2" })
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control"))
o.default = 0
@@ -210,7 +223,8 @@ function o.write(self, section, value)
end
o = s:option(ListValue, _n("alpn"), translate("alpn"))
o.default = "h2,http/1.1"
o.default = "default"
o:value("default", translate("Default"))
o:value("h3")
o:value("h2")
o:value("h3,h2")
@@ -378,7 +392,7 @@ o:depends({ [_n("custom")] = false, [_n("protocol")] = "vless" })
o:depends({ [_n("custom")] = false, [_n("protocol")] = "trojan" })
o:depends({ [_n("custom")] = false, [_n("protocol")] = "shadowsocks" })
o:depends({ [_n("custom")] = false, [_n("protocol")] = "wireguard" })
o:depends({ [_n("custom")] = false, [_n("protocol")] = "hysteria2" })
o:depends({ [_n("custom")] = false, [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
o = s:option(TextValue, _n("finalmask"), "FinalMask JSON")
o:depends({ [_n("use_finalmask")] = true })
@@ -175,10 +175,12 @@ if singbox_tags:find("with_quic") then
o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:value("gecko")
o:depends({ [_n("protocol")] = "hysteria2" })
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
o:depends({ [_n("hysteria2_obfs_type")] = "gecko" })
o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control"), translate("Commands the client to use the BBR flow control algorithm"))
o.default = 0
@@ -154,12 +154,14 @@ function base64Encode(text)
end
function UrlEncode(szText)
if type(szText) ~= "string" then return "" end
return szText:gsub("([^%w%-_%.%~])", function(c)
return string.format("%%%02X", string.byte(c))
end)
end
function UrlDecode(szText)
if type(szText) ~= "string" then return "" end
return szText and szText:gsub("%+", " "):gsub("%%(%x%x)", function(h)
return string.char(tonumber(h, 16))
end) or nil
@@ -20,8 +20,8 @@ function gen_config_server(node)
key = node.tls_keyFile,
},
obfs = (node.hysteria2_obfs_type and node.hysteria2_obfs_password) and {
type = "salamander",
salamander = {
type = node.hysteria2_obfs_type,
[node.hysteria2_obfs_type] = {
password = node.hysteria2_obfs_password
}
} or nil,
@@ -101,8 +101,8 @@ function gen_config(var)
end)() or nil
},
obfs = (node.hysteria2_obfs_type and node.hysteria2_obfs_password) and {
type = "salamander",
salamander = {
type = node.hysteria2_obfs_type,
[node.hysteria2_obfs_type] = {
password = node.hysteria2_obfs_password
}
} or nil,
@@ -255,6 +255,7 @@ function gen_outbound(flag, node, tag, proxy_table)
--max_version = "1.3",
fragment = fragment,
record_fragment = record_fragment,
certificate = (node.tls_certificate == "1" and node.tls_certificate_pem ~= "") and split(node.tls_certificate_pem, "\n") or nil,
ech = (node.ech == "1") and (function()
local function get_ech_domain(s) --兼容xray "域名+DNS" 格式ech
local domain, dns = s:match("^([^+]+)%+(.+)$")
@@ -73,8 +73,8 @@ function gen_outbound(flag, node, tag, proxy_table)
local run_socks_instance = true
if proxy_table ~= nil and type(proxy_table) == "table" then
proxy_tag = proxy_table.tag or nil
fragment = proxy_table.fragment or nil
noise = proxy_table.noise or nil
fragment = (proxy_table.fragment and not node.hysteria2_realms) and true or nil
noise = (proxy_table.noise and not node.hysteria2_realms) and true or nil
run_socks_instance = proxy_table.run_socks_instance
end
@@ -189,7 +189,11 @@ function gen_outbound(flag, node, tag, proxy_table)
if not node.tls_CertByName then return "" end
return node.tls_CertByName
end)(),
echConfigList = (node.ech == "1") and node.ech_config or nil
echConfigList = (node.ech == "1") and node.ech_config or nil,
certificates = (node.tls_certificate == "1" and node.tls_certificate_pem ~= "") and {
certificate = api.split(node.tls_certificate_pem, "\n"),
usage = "verify"
} or nil
} or nil,
realitySettings = (node.stream_security == "reality") and {
serverName = node.tls_serverName,
@@ -298,14 +302,36 @@ function gen_outbound(flag, node, tag, proxy_table)
udp[#udp+1] = c
finalmask.udp = udp
elseif TP == "hysteria" then
local udp = {}
if node.hysteria2_obfs_type and node.hysteria2_obfs_type ~= "" then
finalmask.udp = {{
type = node.hysteria2_obfs_type,
local o = {
type = "salamander",
settings = node.hysteria2_obfs_password and {
password = node.hysteria2_obfs_password
password = node.hysteria2_obfs_password,
packetSize = node.hysteria2_obfs_type == "gecko" and "512-1200" or nil
} or nil
}}
}
udp[#udp+1] = o
end
if node.hysteria2_realms then
local realm = api.parse_realm_uri(node.hysteria2_realm_url)
local url, stun
if realm then
if realm.token and realm.server_url and realm.realm_id then
url = "realm://" .. realm.token .. "@" .. realm.server_url .. "/" .. realm.realm_id
end
stun = realm.stun_servers or node.hysteria2_realm_stun
end
local r = {
type = "realm",
settings = {
url = url,
stunServers = stun
}
}
udp[#udp+1] = r
end
finalmask.udp = udp
local up = tonumber(node.hysteria2_up_mbps) or 0
local down = tonumber(node.hysteria2_down_mbps) or 0
finalmask.quicParams = {
@@ -415,6 +441,13 @@ function gen_outbound(flag, node, tag, proxy_table)
if node.protocol == "wireguard" then
result.settings.kernelMode = false
if node.finalmask and node.finalmask ~= "" then
local ok, fm = pcall(jsonc.parse, api.base64Decode(node.finalmask))
if ok and type(fm) == "table" then
result.streamSettings = result.streamSettings or {}
result.streamSettings.finalmask = fm
end
end
end
local alpn = {}
@@ -487,9 +520,9 @@ function gen_config_server(node)
if node.protocol == "vmess" or node.protocol == "vless" then
if node.uuid then
local clients = {}
local users = {}
for i = 1, #node.uuid do
clients[i] = {
users[i] = {
id = node.uuid[i],
flow = (node.protocol == "vless"
and (node.tls == "1" or (node.decryption and node.decryption ~= "" and node.decryption ~= "none"))
@@ -497,7 +530,7 @@ function gen_config_server(node)
}
end
settings = {
clients = clients,
users = users,
decryption = (node.protocol == "vless") and ((node.decryption and node.decryption ~= "") and node.decryption or "none") or nil
}
end
@@ -505,7 +538,7 @@ function gen_config_server(node)
settings = {
udp = ("1" == node.udp_forward) and true or false,
auth = ("1" == node.auth) and "password" or "noauth",
accounts = ("1" == node.auth) and {
users = ("1" == node.auth) and {
{
user = node.username,
pass = node.password
@@ -515,7 +548,7 @@ function gen_config_server(node)
elseif node.protocol == "http" then
settings = {
allowTransparent = false,
accounts = ("1" == node.auth) and {
users = ("1" == node.auth) and {
{
user = node.username,
pass = node.password
@@ -533,20 +566,20 @@ function gen_config_server(node)
}
elseif node.protocol == "trojan" then
if node.uuid then
local clients = {}
local users = {}
for i = 1, #node.uuid do
clients[i] = {
password = node.uuid[i]
users[i] = {
password = node.uuid[i],
}
end
settings = {
clients = clients
users = users
}
end
elseif node.protocol == "hysteria2" then
settings = {
version = 2,
clients = node.hysteria2_auth_password and {
users = node.hysteria2_auth_password and {
{ auth = node.hysteria2_auth_password }
}
}
@@ -724,14 +757,36 @@ function gen_config_server(node)
udp[#udp+1] = c
finalmask.udp = udp
elseif node.transport == "hysteria" then
local udp = {}
if node.hysteria2_obfs_type and node.hysteria2_obfs_type ~= "" then
finalmask.udp = {{
type = node.hysteria2_obfs_type,
local o = {
type = "salamander",
settings = node.hysteria2_obfs_password and {
password = node.hysteria2_obfs_password
password = node.hysteria2_obfs_password,
packetSize = node.hysteria2_obfs_type == "gecko" and "512-1200" or nil
} or nil
}}
}
udp[#udp+1] = o
end
if node.hysteria2_realms then
local realm = api.parse_realm_uri(node.hysteria2_realm_url)
local url, stun
if realm then
if realm.token and realm.server_url and realm.realm_id then
url = "realm://" .. realm.token .. "@" .. realm.server_url .. "/" .. realm.realm_id
end
stun = realm.stun_servers or node.hysteria2_realm_stun
end
local r = {
type = "realm",
settings = {
url = url,
stunServers = stun
}
}
udp[#udp+1] = r
end
finalmask.udp = udp
local ignore = tonumber(node.hysteria2_ignore_client_bandwidth) == 1
local up = (not ignore) and tonumber(node.hysteria2_up_mbps) or 0
local down = (not ignore) and tonumber(node.hysteria2_down_mbps) or 0
@@ -761,7 +816,7 @@ function gen_config_server(node)
}
local alpn = {}
if node.alpn then
if node.alpn and node.alpn ~= "default" then
string.gsub(node.alpn, '[^' .. "," .. ']+', function(w)
table.insert(alpn, w)
end)
@@ -907,7 +962,7 @@ function gen_config(var)
end
if local_socks_username and local_socks_password and local_socks_username ~= "" and local_socks_password ~= "" then
inbound.settings.auth = "password"
inbound.settings.accounts = {
inbound.settings.users = {
{
user = local_socks_username,
pass = local_socks_password
@@ -925,7 +980,7 @@ function gen_config(var)
settings = {allowTransparent = false}
}
if local_http_username and local_http_password and local_http_username ~= "" and local_http_password ~= "" then
inbound.settings.accounts = {
inbound.settings.users = {
{
user = local_http_username,
pass = local_http_password
@@ -2047,7 +2102,7 @@ function gen_proto_config(var)
}
if local_socks_username and local_socks_password and local_socks_username ~= "" and local_socks_password ~= "" then
inbound.settings.auth = "password"
inbound.settings.accounts = {
inbound.settings.users = {
{
user = local_socks_username,
pass = local_socks_password
@@ -2067,7 +2122,7 @@ function gen_proto_config(var)
}
}
if local_http_username and local_http_password and local_http_username ~= "" and local_http_password ~= "" then
inbound.settings.accounts = {
inbound.settings.users = {
{
user = local_http_username,
pass = local_http_password
@@ -150,12 +150,9 @@ local api = require "luci.passwall2.api"
if (confirm("<%: Do you want to restore the client to default settings?%>")) {
setTimeout(function () {
if (confirm("<%: Are you sure you want to restore the client to default settings?%>")) {
var xhr1 = new XMLHttpRequest();
xhr1.open("GET",'<%= api.url("clear_log") %>', false);
xhr1.send();
var xhr2 = new XMLHttpRequest();
xhr2.open("GET",'<%= api.url("reset_config") %>', false);
xhr2.send();
const xhr = new XMLHttpRequest();
xhr.open("GET",'<%= api.url("reset_config") %>', false);
xhr.send();
window.location.href = '<%= api.url("log") %>'
}
}, 1000);
@@ -600,7 +600,7 @@ local current_node = map:get(section)
v_password = opt.get("hysteria2_auth_password");
var dom_obfs = opt.get("hysteria2_obfs_password");
if (dom_obfs && dom_obfs.value != "") {
params += "&obfs=" + "salamander";
params += opt.query("obfs", "hysteria2_obfs_type");
params += opt.query("obfs-password", "hysteria2_obfs_password");
}
params += opt.query("mport", "hysteria2_hop");
@@ -1598,7 +1598,7 @@ local current_node = map:get(section)
opt.set(dom_prefix + 'protocol', "hysteria2");
opt.set(dom_prefix + 'hysteria2_auth_password', decodeURIComponent(password));
if (queryParam["obfs-password"] || queryParam["obfs_password"]) {
opt.set(dom_prefix + 'hysteria2_obfs_type', "salamander");
opt.set(dom_prefix + 'hysteria2_obfs_type', queryParam.obfs || "salamander");
opt.set(dom_prefix + 'hysteria2_obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]);
}
opt.set(dom_prefix + 'hysteria2_hop', queryParam.mport || "");
@@ -1609,7 +1609,7 @@ local current_node = map:get(section)
dom_prefix = "hysteria2_"
opt.set(dom_prefix + 'auth_password', decodeURIComponent(password));
if (queryParam["obfs-password"] || queryParam["obfs_password"]) {
opt.set(dom_prefix + 'obfs_type', "salamander");
opt.set(dom_prefix + 'obfs_type', queryParam.obfs || "salamander");
opt.set(dom_prefix + 'obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]);
}
opt.set(dom_prefix + 'hop', queryParam.mport || "");
+8 -2
View File
@@ -1656,6 +1656,12 @@ msgstr "نام گواهی TLS (CertName)"
msgid "TLS is used to verify the leaf certificate name."
msgstr "TLS برای تأیید نام گواهی برگ (Leaf Certificate) استفاده می‌شود."
msgid "TLS Certificate (PEM)"
msgstr "گواهی TLS (PEM)"
msgid "Full certificate (chain), PEM format."
msgstr "گواهی کامل (زنجیره‌ای)، فرمت PEM."
msgid "ECH Config"
msgstr "پیکربندی ECH"
@@ -2281,8 +2287,8 @@ msgstr "نادیده گرفتن گره %s به دلیل ناسازگاری با
msgid "Skip node: %s. Because Sing-Box does not support the %s protocol's %s transmission method, Xray needs to be used instead."
msgstr "صرف‌نظر از گره: %s. زیرا Sing-Box از روش انتقال %s پروتکل %s پشتیبانی نمی‌کند، باید به جای آن از Xray استفاده شود."
msgid "Xray unsupport %s plugin."
msgstr "Xray از افزونه %s پشتیبانی نمی‌کند."
msgid "%s unsupport SS %s plugin."
msgstr "%s از افزونه %s پشتیبانی نمی‌کند."
msgid "Plugin options Incomplete."
msgstr "گزینه‌های افزونه ناقص است."
+8 -2
View File
@@ -1657,6 +1657,12 @@ msgstr "Имя TLS-сертификата (CertName)"
msgid "TLS is used to verify the leaf certificate name."
msgstr "Используется TLS для проверки имени конечного сертификата."
msgid "TLS Certificate (PEM)"
msgstr "Сертификат TLS (PEM)"
msgid "Full certificate (chain), PEM format."
msgstr "Полный сертификат (цепочка), формат PEM."
msgid "ECH Config"
msgstr "Конфигурация ECH"
@@ -2279,8 +2285,8 @@ msgstr "Пропуск сервера %s: несовместимость с яд
msgid "Skip node: %s. Because Sing-Box does not support the %s protocol's %s transmission method, Xray needs to be used instead."
msgstr "Пропуск сервера: %s. Sing-Box не поддерживает метод передачи %s протокола %s, необходимо использовать Xray."
msgid "Xray unsupport %s plugin."
msgstr "Xray не поддерживает плагин %s."
msgid "%s unsupport SS %s plugin."
msgstr "%s не поддерживает плагин %s."
msgid "Plugin options Incomplete."
msgstr "Опции плагина указаны не полностью."
+8 -2
View File
@@ -1648,6 +1648,12 @@ msgstr "TLS 证书名称(CertName"
msgid "TLS is used to verify the leaf certificate name."
msgstr "TLS 用于验证 leaf 证书的 name。"
msgid "TLS Certificate (PEM)"
msgstr "TLS 证书(PEM"
msgid "Full certificate (chain), PEM format."
msgstr "完整证书(链),PEM 格式。"
msgid "ECH Config"
msgstr "ECH 配置"
@@ -2267,8 +2273,8 @@ msgstr "跳过 %s 节点,因未适配到 %s 核心程序,或未正确设置
msgid "Skip node: %s. Because Sing-Box does not support the %s protocol's %s transmission method, Xray needs to be used instead."
msgstr "跳过节点:%s,因 Sing-Box 不支持 %s 协议的 %s 传输方式,需更换 Xray。"
msgid "Xray unsupport %s plugin."
msgstr "Xray 不支持 %s 插件。"
msgid "%s unsupport SS %s plugin."
msgstr "%s 不支持 %s 插件。"
msgid "Plugin options Incomplete."
msgstr "插件选项不完整。"
+8 -2
View File
@@ -1648,6 +1648,12 @@ msgstr "TLS 憑證名稱(CertName"
msgid "TLS is used to verify the leaf certificate name."
msgstr "TLS 用於驗證 leaf 憑證的 name。"
msgid "TLS Certificate (PEM)"
msgstr "TLS 憑證(PEM"
msgid "Full certificate (chain), PEM format."
msgstr "完整憑證(鏈),PEM 格式。"
msgid "ECH Config"
msgstr "ECH 配置"
@@ -2273,8 +2279,8 @@ msgstr "跳過 %s 節點,因未適配到 %s 核心程序,或未正確設置
msgid "Skip node: %s. Because Sing-Box does not support the %s protocol's %s transmission method, Xray needs to be used instead."
msgstr "跳過節點:%s,因 Sing-Box 不支持 %s 協議的 %s 傳輸方式,需更換 Xray。"
msgid "Xray unsupport %s plugin."
msgstr "Xray 不支持 %s 插件。"
msgid "%s unsupport SS %s plugin."
msgstr "%s 不支持 %s 插件。"
msgid "Plugin options Incomplete."
msgstr "插件選項不完整。"
@@ -1012,9 +1012,10 @@ acl_app() {
[ -n "$items" ] && {
local index=0
local item
local redir_port dns_port dnsmasq_port
local redir_port dns_port dnsmasq_port socks_port
local ipt_tmp msg msg2
redir_port=11200
socks_port=11600
dns_port=11300
dnsmasq_port=${GLOBAL_DNSMASQ_PORT:-11400}
for item in $items; do
@@ -1098,12 +1099,13 @@ acl_app() {
set_cache_var "ACL_${sid}_default" "1"
else
redir_port=$(get_new_port $(expr $redir_port + 1))
socks_port=$(get_new_port $(expr $socks_port + 1))
local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
if [ -n "${type}" ]; then
config_file=$TMP_ACL_PATH/${node}_TCP_UDP_DNS_${redir_port}.json
dns_port=$(get_new_port $(expr $dns_port + 1))
local acl_socks_port=$(get_new_port $(expr $redir_port + $index))
local acl_socks_port=$socks_port
local run_func
[ -n "${XRAY_BIN}" ] && run_func="run_xray"
[ -n "${SINGBOX_BIN}" ] && run_func="run_singbox"
@@ -528,36 +528,50 @@ local function parseClashNode(node, add_mode, group, sub_cfg)
elseif node.plugin == "v2ray-plugin" then
result.plugin = "v2ray-plugin"
end
if node["plugin-opts"] then
if node.plugin == "obfs" then
local plugin_opts = ""
local opts_mode = node["plugin-opts"].mode
if opts_mode then
plugin_opts = plugin_opts .. "obfs=" .. opts_mode .. ";"
if result.plugin then
result.plugin_enabled = "1"
if result.type == 'Xray' then
if result.plugin ~= "obfs-local" then
result.plugin_enabled = nil
result.error_msg = i18n.translatef("%s unsupport SS %s plugin.", "Xray", result.plugin)
end
local opts_host = node["plugin-opts"].host
if opts_host then
plugin_opts = plugin_opts .. "obfs-host=" .. opts_host
elseif result.type == 'sing-box' then
if result.plugin ~= "obfs-local" and result.plugin ~= "v2ray-plugin" then
result.plugin_enabled = nil
result.error_msg = i18n.translatef("%s unsupport SS %s plugin.", "Sing-Box", result.plugin)
end
result.plugin_opts = plugin_opts
elseif node.plugin == "v2ray-plugin" then
local plugin_opts = ""
local opts_mode = node["plugin-opts"].mode
local opts_tls = node["plugin-opts"].tls
if opts_tls then
plugin_opts = plugin_opts .. "tls;"
end
if node["plugin-opts"] and result.plugin_enabled == "1" then
if node.plugin == "obfs" then
local plugin_opts = ""
local opts_mode = node["plugin-opts"].mode
if opts_mode then
plugin_opts = plugin_opts .. "obfs=" .. opts_mode .. ";"
end
local opts_host = node["plugin-opts"].host
if opts_host then
plugin_opts = plugin_opts .. "obfs-host=" .. opts_host
end
result.plugin_opts = plugin_opts
elseif node.plugin == "v2ray-plugin" then
local plugin_opts = ""
local opts_mode = node["plugin-opts"].mode
local opts_tls = node["plugin-opts"].tls
if opts_tls then
plugin_opts = plugin_opts .. "tls;"
end
local opts_skip_cert_verify = node["plugin-opts"]["skip-cert-verify"]
local opts_host = node["plugin-opts"].host
if opts_host then
plugin_opts = plugin_opts .. "host=" .. opts_host .. ";"
end
local opts_path = node["plugin-opts"].path
local opts_mux = node["plugin-opts"].mux
if node["plugin-opts"].headers then
--todo
end
result.plugin_opts = plugin_opts
end
local opts_skip_cert_verify = node["plugin-opts"]["skip-cert-verify"]
local opts_host = node["plugin-opts"].host
if opts_host then
plugin_opts = plugin_opts .. "host=" .. opts_host .. ";"
end
local opts_path = node["plugin-opts"].path
local opts_mux = node["plugin-opts"].mux
if node["plugin-opts"].headers then
--todo
end
result.plugin_opts = plugin_opts
end
end
elseif node.type == 'ssr' then
@@ -961,6 +975,11 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.tls = "0"
end
if info.ech and info.ech ~= "" then
result.ech = "1"
result.ech_config = info.ech
end
result.tcp_fast_open = info.tfo
info.fm = (info.fm and info.fm ~= "") and UrlDecode(info.fm) or nil
@@ -1090,7 +1109,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
if result.type == 'Xray' then
-- The obfs-local plugin converts data to a format supported by xray.
if result.plugin ~= "obfs-local" then
result.error_msg = i18n.translatef("Xray unsupport %s plugin.", result.plugin)
result.error_msg = i18n.translatef("%s unsupport SS %s plugin.", "Xray", result.plugin)
else
local obfs = result.plugin_opts:match("obfs=([^;]+)") or ""
local obfs_host = result.plugin_opts:match("obfs%-host=([^;]+)") or ""
@@ -1110,6 +1129,12 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.plugin = nil
result.plugin_opts = nil
end
elseif result.type == 'sing-box' then
if result.plugin ~= "obfs-local" and result.plugin ~= "v2ray-plugin" then
result.error_msg = i18n.translatef("%s unsupport SS %s plugin.", "Sing-Box", result.plugin)
else
result.plugin_enabled = "1"
end
else
result.plugin_enabled = "1"
end
@@ -1223,7 +1248,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
local insecure = params.allowinsecure or params.allowInsecure or params.insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
result.uot = params.udp
elseif (params.type ~= "tcp" and params.type ~= "raw") and (params.headerType and params.headerType ~= "none") then
else
result.error_msg = i18n.translatef("Please replace Xray or Sing-Box to support more transmission methods in Shadowsocks.")
end
end
@@ -1684,7 +1709,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.hysteria2_down_mbps = params.downmbps or sub_hy_down_mbps
result.hysteria2_hop = params.mport
if params["obfs-password"] or params["obfs_password"] then
result.hysteria2_obfs_type = "salamander"
result.hysteria2_obfs_type = params.obfs or "salamander"
result.hysteria2_obfs_password = params["obfs-password"] or params["obfs_password"]
end
@@ -1818,6 +1843,10 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.reality_publicKey = params.pbk or nil
result.reality_shortId = params.sid or nil
end
if params.ech and params.ech ~= "" then
result.ech = "1"
result.ech_config = params.ech
end
end
result.port = port
local insecure = params.allowinsecure or params.insecure
+1 -1
View File
@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=momo
PKG_VERSION:=2026.04.09
PKG_VERSION:=2026.06.03
PKG_RELEASE:=1
PKG_LICENSE:=GPL-3.0+
+1
View File
@@ -121,6 +121,7 @@ config routing 'routing'
option 'dummy_device' 'momo-dummy'
config log 'log'
option 'clear_at_stop' '1'
option 'scheduled_clear' '1'
option 'scheduled_clear_cron' '*/5 * * * *'
option 'scheduled_clear_size_limit' '1'
+23 -1
View File
@@ -67,7 +67,9 @@ start_service() {
local fast_reload
config_get_bool fast_reload "procd" "fast_reload" 0
### rlimit
local rlimit_address_space_soft rlimit_address_space_hard rlimit_data_soft rlimit_data_hard rlimit_stack_soft rlimit_stack_hard rlimit_nofile_soft rlimit_nofile_hard
local rlimit_nproc_soft rlimit_nproc_hard rlimit_address_space_soft rlimit_address_space_hard rlimit_data_soft rlimit_data_hard rlimit_stack_soft rlimit_stack_hard rlimit_nofile_soft rlimit_nofile_hard
config_get rlimit_nproc_soft "procd" "rlimit_nproc_soft" "$(ulimit -Su)"
config_get rlimit_nproc_hard "procd" "rlimit_nproc_hard" "$(ulimit -Hu)"
config_get rlimit_address_space_soft "procd" "rlimit_address_space_soft"
config_get rlimit_address_space_hard "procd" "rlimit_address_space_hard"
config_get rlimit_data_soft "procd" "rlimit_data_soft"
@@ -76,6 +78,10 @@ start_service() {
config_get rlimit_stack_hard "procd" "rlimit_stack_hard"
config_get rlimit_nofile_soft "procd" "rlimit_nofile_soft" "$(ulimit -Sn)"
config_get rlimit_nofile_hard "procd" "rlimit_nofile_hard" "$(ulimit -Hn)"
### environment variable
local env_go_max_procs env_go_mem_limit
config_get env_go_max_procs "procd" "env_go_max_procs"
config_get env_go_mem_limit "procd" "env_go_mem_limit"
## core config
local redirect_inbound_tag tproxy_inbound_tag tun_inbound_tag dns_inbound_tag fake_ip_dns_server_tag
config_get redirect_inbound_tag "core" "redirect_inbound_tag"
@@ -133,6 +139,8 @@ start_service() {
log "Mixin" "Mixin config."
ucode -S "$MIXIN_UC"
fi
# format profile
$PROG -c "$RUN_PROFILE_PATH" format -w
# check profile
if [ "$core_only" = 0 ] && [ "$proxy_enabled" = 1 ]; then
log "Profile" "Checking..."
@@ -197,11 +205,16 @@ start_service() {
fi
procd_set_param pidfile "$PID_FILE_PATH"
procd_set_param respawn
procd_append_param limits nproc="${rlimit_nproc_soft} ${rlimit_nproc_hard}"
procd_append_param limits as="${rlimit_address_space_soft:-unlimited} ${rlimit_address_space_hard:-unlimited}"
procd_append_param limits data="${rlimit_data_soft:-unlimited} ${rlimit_data_hard:-unlimited}"
procd_append_param limits stack="${rlimit_stack_soft:-unlimited} ${rlimit_stack_hard:-unlimited}"
procd_append_param limits nofile="${rlimit_nofile_soft} ${rlimit_nofile_hard}"
procd_append_param env GOMAXPROCS="$env_go_max_procs"
procd_append_param env GOMEMLIMIT="$env_go_mem_limit"
procd_close_instance
# cron
local reload_cron; reload_cron=0
@@ -379,11 +392,20 @@ cleanup() {
# load config
config_load momo
# get config
## log config
local log_clear_at_stop
config_get_bool log_clear_at_stop "log" "clear_at_stop" 0
## routing config
local tproxy_route_table tun_route_table dummy_device
config_get tproxy_route_table "routing" "tproxy_route_table" "80"
config_get tun_route_table "routing" "tun_route_table" "81"
config_get dummy_device "routing" "dummy_device" "momo-dummy"
# clear logs if needed
if [ "$log_clear_at_stop" = 1 ]; then
echo -n > "$APP_LOG_PATH"
echo -n > "$CORE_LOG_PATH"
log "Log" "Logs are cleared due to clear at stop is enabled."
fi
# delete routing policy
ip -4 rule del table "$tproxy_route_table" > /dev/null 2>&1
ip -4 rule del table "$tun_route_table" > /dev/null 2>&1
+3
View File
@@ -51,6 +51,9 @@ section_mixin=$(uci -q get momo.mixin); [ -z "$section_mixin" ] && {
uci set momo.mixin.external_control_ui_download_url='https://github.com/Zephyruso/zashboard/releases/latest/download/dist-cdn-fonts.zip'
}
# since v1.2.1
config_clear_at_stop=$(uci -q get momo.log.clear_at_stop); [ -z "$config_clear_at_stop" ] && uci set momo.log.clear_at_stop=1
# commit
uci commit momo
+4
View File
@@ -248,6 +248,7 @@ table inet momo {
}
{% if (router_proxy): %}
{% if (length(dns_hijack_nfproto) > 0): %}
chain router_dns_hijack {
{% for (let access_control in router_access_control): %}
{% if (length(access_control['user']) == 0 && length(access_control['group']) == 0 && length(access_control['cgroup']) == 0): %}
@@ -267,6 +268,7 @@ table inet momo {
{% endif %}
{% endfor %}
}
{% endif %}
{% if (tcp_mode == 'redirect'): %}
chain router_redirect {
@@ -360,6 +362,7 @@ table inet momo {
{% endif %}
{% if (lan_proxy): %}
{% if (length(dns_hijack_nfproto) > 0): %}
chain lan_dns_hijack {
{% for (let access_control in lan_access_control): %}
{% if (length(access_control['ip']) == 0 && length(access_control['ip6']) == 0 && length(access_control['mac']) == 0): %}
@@ -381,6 +384,7 @@ table inet momo {
{% endif %}
{% endfor %}
}
{% endif %}
{% if (tcp_mode == 'redirect'): %}
chain lan_redirect {
+2 -2
View File
@@ -21,13 +21,13 @@ define Download/geoip
HASH:=e9002979e0df72bce1c8751ff70725386594c551db684b7a232935b8b2bb8aa2
endef
GEOSITE_VER:=20260602145358
GEOSITE_VER:=20260603121550
GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER)
define Download/geosite
URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/
URL_FILE:=dlc.dat
FILE:=$(GEOSITE_FILE)
HASH:=92d535187e8a2eee0a3cfb3ed22e481884c4fb93a7ab903e30b26ca405fa530b
HASH:=fab7cce3d3009121a88939d616f0366d3067741dce21424b627426cbd17f1e62
endef
GEOSITE_IRAN_VER:=202606010205