🏅 Sync 2026-10-21 14:22:54

This commit is contained in:
github-actions[bot] committed 2026-10-21 14:22:54 +08:00
1 parent 0b7c0117b8
commit f608112d08
29 files changed
+752 -371

No files matched your search

+2 -5
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=gately
PKG_VERSION:=0.5.3
PKG_RELEASE:=2
PKG_RELEASE:=3
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/wangwanjie/gately/tar.gz/v$(PKG_VERSION)?
@@ -20,14 +20,11 @@ PKG_BUILD_DEPENDS:=golang/host node/host node-pnpm/host
PKG_BUILD_PARALLEL:=1
PKG_BUILD_FLAGS:=no-mips16
BUILD_DATE:=$(shell date -u -d "@$(SOURCE_DATE_EPOCH)" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date -u +"%Y-%m-%dT%H:%M:%SZ")
GO_PKG:=github.com/wangwanjie/gately
GO_PKG_BUILD_PKG:=$(GO_PKG)/cmd/gately
GO_PKG_LDFLAGS_X:=\
$(GO_PKG)/internal/version.Version=v$(PKG_VERSION) \
$(GO_PKG)/internal/version.Commit=$(PKG_VERSION) \
$(GO_PKG)/internal/version.BuildDate=$(BUILD_DATE)
$(GO_PKG)/internal/version.Commit=$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk
+1 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-daede
PKG_VERSION:=1.15
PKG_RELEASE:=53
PKG_RELEASE:=54
PKG_MAINTAINER:=kenzok8
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
@@ -425,14 +425,11 @@ return view.extend({
btn.disabled = true;
} else if (updatable) {
meta = _('installed') + ': ' + entry.r.installed + ' → ' + _('latest') + ': ' + entry.r.latest;
} else if (cmp < 0) {
meta = _('installed') + ': ' + entry.r.installed + ' · ' + _('feed version older: %s').format(entry.r.latest);
btn.disabled = true;
} else {
meta = _('installed') + ': ' + entry.r.installed + ' · ' + _('up to date');
btn.disabled = true;
}
const uncertain = entry.r.installed && (indexState !== 'success' || !entry.r.latest || cmp < 0);
const uncertain = entry.r.installed && (indexState !== 'success' || !entry.r.latest);
pkgBody.appendChild(mkRow(
updatable ? '↑' : (uncertain ? '⚠' : (entry.r.installed ? '✓' : '✗')),
updatable ? 'dd-up-new' : (uncertain ? 'dd-up-warn' : (entry.r.installed ? 'dd-up-ok' : 'dd-up-err')),
-3
View File
@@ -329,9 +329,6 @@ msgstr "正在刷新软件源"
msgid "package not found in configured feeds"
msgstr "当前软件源中没有此包"
msgid "feed version older: %s"
msgstr "软件源版本较旧:%s"
msgid "Unavailable"
msgstr "不可用"
-11
View File
@@ -8,20 +8,9 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-gately
PKG_VERSION:=1.0.1
PKG_RELEASE:=1
LUCI_TITLE:=LuCI Support for Gately
LUCI_DEPENDS:=+gately
LUCI_PKGARCH:=all
define Package/$(PKG_NAME)/postinst
#!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] || {
(sleep 1; /etc/init.d/rpcd reload) >/dev/null 2>&1 &
}
exit 0
endef
define Package/$(PKG_NAME)/prerm
#!/bin/sh
@@ -41,6 +41,12 @@ return view.extend({
return Promise.all(self.pendingTasks);
}).then(function() {
return uci.save();
}).then(function() {
return callSetConfig('commit_uci', '');
}).then(function() {
if (ui.changes && typeof ui.changes.setIndicator === 'function') {
ui.changes.setIndicator(0);
}
}).catch(function(err) {
ui.addNotification(null, E('p', err.message || String(err)), 'error');
return Promise.reject(err);
@@ -50,13 +56,14 @@ return view.extend({
handleSaveApply: function(ev, mode) {
var self = this;
return this.handleSave(ev).then(function() {
return ui.changes.apply(mode == '0');
}).then(function() {
var enabled = uci.get('gately', 'main', 'enabled');
var action = (enabled === '1') ? 'restart' : 'stop';
ui.showModal(null, [ E('p', { class: 'spinning' }, _('Updating configuration and restarting service...')) ]);
return callService(action).then(function() {
ui.hideModal();
if (ui.changes && typeof ui.changes.setIndicator === 'function') {
ui.changes.setIndicator(0);
}
ui.addNotification(null, E('p', _('Configuration updated successfully')), 'info');
uci.unload('gately');
return self.load().then(function(data) {
@@ -69,32 +76,6 @@ return view.extend({
});
},
handleUpdate: function(key, value) {
ui.showModal(null, [ E('p', { class: 'spinning' }, _('Updating configuration and restarting service...')) ]);
var self = this;
return callSetConfig(key, value).then(function(res) {
if (res && res.ret === 0) {
var enabled = uci.get('gately', 'main', 'enabled');
var action = (enabled === '1') ? 'restart' : 'stop';
return callService(action).then(function() {
ui.hideModal();
ui.addNotification(null, E('p', _('Configuration updated successfully')), 'info');
uci.unload('gately');
return self.load().then(function(data) {
return self.render(data);
}).then(function(node) {
var mapEl = document.querySelector('.cbi-map');
if (mapEl && mapEl.parentNode) dom.content(mapEl.parentNode, node);
});
});
} else {
ui.hideModal();
ui.addNotification(null, E('p', (res && res.error) ? res.error : _('Failed to update configuration')), 'error');
}
});
},
render: function(data) {
var self = this;
var baseConf = (data[1] && data[1].base_conf) ? data[1].base_conf : {};
@@ -189,16 +170,6 @@ return view.extend({
self.queueSetConfig('switch_Internetaccess', false);
};
// Reset Auth
o = s.option(form.Button, '_reset_auth', _('Reset Account and Password'));
o.inputtitle = _('Reset to Default (admin / admin123456)');
o.inputstyle = 'negative';
o.onclick = ui.createHandlerFn(self, function() {
if (confirm(_('Are you sure you want to reset the admin account and password to default (admin / admin123456)?'))) {
return self.handleUpdate('reset_auth_info', '');
}
});
return m.render();
}
});
@@ -9,35 +9,6 @@ var callGetInfo = rpc.declare({ object: 'luci.gately', method: 'get_info', expec
var callGetStatus = rpc.declare({ object: 'luci.gately', method: 'get_status', expect: { } });
var callService = rpc.declare({ object: 'luci.gately', method: 'service', params: ['action'], expect: { } });
function pad2(n) {
return (n < 10 ? '0' : '') + n;
}
function formatBuildDate(raw) {
if (!raw || raw === '-' || raw === 'unknown') return '-';
var str = String(raw).trim();
var d = null;
if (/^\d{9,13}$/.test(str)) {
var ts = parseInt(str, 10);
if (str.length <= 10) ts *= 1000;
d = new Date(ts);
} else {
var parsed = Date.parse(str);
if (!isNaN(parsed)) {
d = new Date(parsed);
}
}
if (d && !isNaN(d.getTime())) {
return d.getFullYear() + '-' +
pad2(d.getMonth() + 1) + '-' +
pad2(d.getDate()) + ' ' +
pad2(d.getHours()) + ':' +
pad2(d.getMinutes()) + ':' +
pad2(d.getSeconds());
}
return str;
}
return view.extend({
load: function() {
return callGetInfo();
@@ -118,8 +89,11 @@ return view.extend({
el = document.getElementById('_gatelyArch');
if (el) dom.content(el, info.gatelyArch || '-');
el = document.getElementById('_gatelyDate');
if (el) dom.content(el, formatBuildDate(gatelyInfo.Date));
el = document.getElementById('_gatelyUser');
if (el) dom.content(el, info.adminUser || 'admin');
el = document.getElementById('_gatelyPassword');
if (el) dom.content(el, info.adminPassword || 'admin123456');
if (info.running && info.adminPort) {
var url = 'http://' + window.location.hostname + ':' + info.adminPort + (info.adminSafeUrl || '');
@@ -179,8 +153,12 @@ return view.extend({
E('td', { class: 'td left', id: '_gatelyArch' }, info.gatelyArch || '-')
]),
E('tr', { class: 'tr' }, [
E('td', { class: 'td left' }, _('Compile Time')),
E('td', { class: 'td left', id: '_gatelyDate' }, formatBuildDate(gatelyInfo.Date))
E('td', { class: 'td left' }, _('Admin Account')),
E('td', { class: 'td left', id: '_gatelyUser' }, info.adminUser || 'admin')
]),
E('tr', { class: 'tr' }, [
E('td', { class: 'td left' }, _('Admin Password')),
E('td', { class: 'td left', id: '_gatelyPassword' }, info.adminPassword || 'admin123456')
]),
E('tr', { class: 'tr' }, [
E('td', { class: 'td left' }, _('Admin Panel')),
+4 -10
View File
@@ -52,7 +52,10 @@ msgstr ""
msgid "Architecture"
msgstr ""
msgid "Compile Time"
msgid "Admin Account"
msgstr ""
msgid "Admin Password"
msgstr ""
msgid "Admin Panel"
@@ -109,15 +112,6 @@ msgstr ""
msgid "Allow Internet Access"
msgstr ""
msgid "Reset Account and Password"
msgstr ""
msgid "Reset to Default (admin / admin123456)"
msgstr ""
msgid "Are you sure you want to reset the admin account and password to default (admin / admin123456)?"
msgstr ""
msgid "Updating configuration and restarting service..."
msgstr ""
+5 -11
View File
@@ -52,8 +52,11 @@ msgstr "当前版本"
msgid "Architecture"
msgstr "系统架构"
msgid "Compile Time"
msgstr "构建时间"
msgid "Admin Account"
msgstr "管理员账号"
msgid "Admin Password"
msgstr "管理员密码"
msgid "Admin Panel"
msgstr "管理后台"
@@ -109,15 +112,6 @@ msgstr "安全入口不能以 /api 或 /assets 开头,且不能包含空格、
msgid "Allow Internet Access"
msgstr "允许外网访问管理后台"
msgid "Reset Account and Password"
msgstr "重置账号与密码"
msgid "Reset to Default (admin / admin123456)"
msgstr "恢复默认认证 (admin / admin123456)"
msgid "Are you sure you want to reset the admin account and password to default (admin / admin123456)?"
msgstr "确定要将管理员账号和密码恢复为默认值 (admin / admin123456) 吗?"
msgid "Updating configuration and restarting service..."
msgstr "正在更新配置并重启服务..."
@@ -34,11 +34,11 @@ function is_running() {
function get_version_info() {
if (!access(BIN_PATH, 'x')) {
return { version: '-', commit: '-', buildDate: '-', go: '-' };
return { version: '-', commit: '-', go: '-' };
}
let p = popen(BIN_PATH + ' -version 2>/dev/null');
if (!p) {
return { version: '-', commit: '-', buildDate: '-', go: '-' };
return { version: '-', commit: '-', go: '-' };
}
let raw = trim(p.read('all') || '');
p.close();
@@ -84,6 +84,20 @@ function write_gately_json(configdir, settings) {
}
// Gately stores admin account in <configdir>/account.json (accountName = "account")
function read_account_json(configdir) {
let path = configdir + '/account.json';
if (!access(path, 'r')) {
return {};
}
let content = readfile(path);
if (!content) return {};
try {
return json(content);
} catch (e) {
return {};
}
}
function clear_account_json(configdir) {
let acc_file = configdir + '/account.json';
if (access(acc_file, 'f')) {
@@ -136,6 +150,7 @@ const methods = {
let ver = get_version_info();
let arch = get_arch();
let settings = read_gately_json(uci_cfg.configdir);
let account = read_account_json(uci_cfg.configdir);
let effective_listen = settings.listen || ':16680';
let admin_port = parse_port_from_listen(effective_listen);
@@ -144,15 +159,18 @@ const methods = {
safe_path = '/' + safe_path;
}
let lan_only = (settings.lanOnly === true);
let admin_user = account.username || 'admin';
let admin_password = uci_cfg.initial_password || 'admin123456';
return {
running: st.running,
pid: st.pid,
gatelyArch: arch,
adminUser: admin_user,
adminPassword: admin_password,
gatelyInfo: sprintf('%J', {
Version: ver.version || '-',
Commit: ver.commit || '-',
Date: ver.buildDate || '-',
Go: ver.go || '-'
}),
adminPort: admin_port,
@@ -222,12 +240,11 @@ const methods = {
c.commit('gately');
clear_account_json(configdir);
return { ret: 0 };
} else if (key === 'reset_auth_info') {
} else if (key === 'commit_uci') {
let c = cursor();
c.load('gately');
c.set('gately', 'main', 'initial_password', 'admin123456');
c.commit('gately');
clear_account_json(configdir);
system('uci -q commit gately >/dev/null 2>&1');
return { ret: 0 };
}
@@ -239,6 +256,11 @@ const methods = {
args: { action: 'action' },
call: function(req) {
let action = req.args?.action;
let c = cursor();
c.load('gately');
c.commit('gately');
system('uci -q commit gately >/dev/null 2>&1');
if (action === 'restart' || action === 'reload') {
let res = system(INIT_SCRIPT + ' stop >/dev/null 2>&1; sleep 1; ' + INIT_SCRIPT + ' start >/dev/null 2>&1');
return { result: (res === 0), ret: res };
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-open-box
PKG_VERSION:=0.1.342
PKG_RELEASE:=38
PKG_VERSION:=0.1.343
PKG_RELEASE:=39
PKG_MAINTAINER:=liandu2024
PKG_LICENSE:=GPL-3.0-or-later
+2 -7
View File
@@ -8,14 +8,13 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.10.16
PKG_RELEASE:=342
PKG_RELEASE:=343
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \
CONFIG_PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Geoview \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_SmartDNS \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \
@@ -39,7 +38,6 @@ LUCI_DEPENDS:=+coreutils +coreutils-base64 +coreutils-nohup +coreutils-timeout +
+microsocks +resolveip +tcping +lyaml \
+ipt2socks \
+PACKAGE_$(PKG_NAME)_INCLUDE_Geoview:geoview \
+PACKAGE_$(PKG_NAME)_INCLUDE_SmartDNS:smartdns \
+PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy:haproxy \
+PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \
+PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \
@@ -88,10 +86,7 @@ config PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy
config PACKAGE_$(PKG_NAME)_INCLUDE_Geoview
bool "Include Geoview"
default y if aarch64||i386||x86_64
config PACKAGE_$(PKG_NAME)_INCLUDE_SmartDNS
bool "Include SmartDNS"
select PACKAGE_geoview
default y if aarch64||i386||x86_64
config PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy
+4 -4
View File
@@ -3,8 +3,8 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=luci-app-ssr-plus
LUCI_PKGARCH:=all
PKG_NAME:=luci-app-ssr-plus
PKG_VERSION:=196
PKG_RELEASE:=93
PKG_VERSION:=197
PKG_RELEASE:=94
PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \
@@ -119,7 +119,7 @@ endchoice
config PACKAGE_$(PKG_NAME)_INCLUDE_ChinaDNS_NG
bool "Include ChinaDNS-NG"
default y if aarch64||arm||i386||x86_64
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_MosDNS
bool "Include MosDNS"
@@ -164,7 +164,7 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_V2ray_Plugin
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client
bool "Include ShadowsocksR Libev Client"
default y
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server
bool "Include ShadowsocksR Libev Server"
@@ -474,11 +474,12 @@ if is_finded("xray") then
o:value("wireguard", translate("WireGuard"))
o:value("naive", "NaiveProxy (Xray / Cronet)")
o:value("shadowsocksr", "ShadowsocksR (Xray)")
o:value("tuic", "TUIC (Xray)")
end
if is_finded("xray") then
o:value("hysteria2", translate("Hysteria2"))
end
if is_finded("mihomo") then
if is_finded("xray") or is_finded("mihomo") then
o:value("snell", translate("Snell"))
end
o:value("socks", translate("Socks"))
@@ -926,6 +927,17 @@ end
o.rmempty = true
o.default="auto"
o = s:option(ListValue, "xray_tuic_version", "TUIC Version")
o:value("5", "v5 (UUID / Password)")
o:value("4", "v4 (Token)")
o.default = "5"
o:depends({type = "v2ray", v2ray_protocol = "tuic"})
o = s:option(Value, "xray_tuic_token", "TUIC Token")
o.password = true
o:depends({type = "v2ray", v2ray_protocol = "tuic", xray_tuic_version = "4"})
o = s:option(Value, "xray_tuic_ca", translate("Certificate File Path"))
o:depends({type = "v2ray", v2ray_protocol = "tuic"})
-- [[ TUIC ]]
-- TuicNameId
o = s:option(Value, "tuic_uuid", translate("TUIC User UUID"))
@@ -933,6 +945,7 @@ o.password = true
o.rmempty = true
o.default = uuid
o:depends("type", "tuic")
o:depends({type = "v2ray", v2ray_protocol = "tuic", xray_tuic_version = "5"})
--Tuic IP
o = s:option(Value, "tuic_ip", translate("TUIC Server IP Address"))
@@ -947,9 +960,11 @@ o.password = true
o.rmempty = true
o.default = ""
o:depends("type", "tuic")
o:depends({type = "v2ray", v2ray_protocol = "tuic", xray_tuic_version = "5"})
o = s:option(ListValue, "udp_relay_mode", translate("UDP relay mode"))
o:depends("type", "tuic")
o:depends({type = "v2ray", v2ray_protocol = "tuic"})
o:value("native", translate("native UDP characteristics"))
o:value("quic", translate("lossless UDP relay using QUIC streams"))
o.default = "native"
@@ -957,6 +972,7 @@ o.rmempty = true
o = s:option(ListValue, "congestion_control", translate("Congestion control algorithm"))
o:depends("type", "tuic")
o:depends({type = "v2ray", v2ray_protocol = "tuic"})
o:value("bbr", translate("BBR"))
o:value("cubic", translate("CUBIC"))
o:value("new_reno", translate("New Reno"))
@@ -965,12 +981,14 @@ o.rmempty = true
o = s:option(Value, "heartbeat", translate("Heartbeat interval(second)"))
o:depends("type", "tuic")
o:depends({type = "v2ray", v2ray_protocol = "tuic"})
o.datatype = "uinteger"
o.default = "3"
o.rmempty = true
o = s:option(Value, "timeout", translate("Timeout for establishing a connection to server(second)"))
o:depends("type", "tuic")
o:depends({type = "v2ray", v2ray_protocol = "tuic"})
o.datatype = "uinteger"
o.default = "8"
o.rmempty = true
@@ -1006,6 +1024,7 @@ o.rmempty = true
o = s:option(Flag, "zero_rtt_handshake", translate("Enable 0-RTT QUIC handshake"))
o:depends("type", "tuic")
o:depends({type = "v2ray", v2ray_protocol = "tuic"})
o.default = "0"
o.rmempty = true
@@ -1087,10 +1106,17 @@ o = s:option(Value, "snell_obfs_host", translate("Snell Obfs Host"))
o.rmempty = true
o:depends({type = "v2ray", v2ray_protocol = "snell"})
o = s:option(Flag, "snell_reuse", translate("Connection reuse"))
o.default = "0"
for _, version in ipairs({"4", "5"}) do
o:depends({type = "v2ray", v2ray_protocol = "snell", snell_version = version})
end
-- 传输协议
o = s:option(ListValue, "transport", translate("Transport"))
o:value("raw", "RAW (TCP)")
o:value("kcp", "mKCP")
o:value("kcptun", "Kcptun (Xray)")
o:value("ws", "WebSocket")
o:value("httpupgrade", "HTTPUpgrade")
o:value("xhttp", "XHTTP (SplitHTTP)")
@@ -1105,6 +1131,43 @@ o:depends({type = "v2ray", v2ray_protocol = "shadowsocks"})
o:depends({type = "v2ray", v2ray_protocol = "socks"})
o:depends({type = "v2ray", v2ray_protocol = "http"})
-- Native Kcptun transport (separate from mKCP and the external Kcptun client).
o = s:option(Value, "xray_kcptun_key", "Kcptun Key")
o:depends("transport", "kcptun")
o.password = true
o.rmempty = false
o = s:option(ListValue, "xray_kcptun_crypt", "Kcptun Encryption")
o:depends("transport", "kcptun")
for _, crypt in ipairs({"aes", "aes-128", "aes-192", "aes-128-gcm", "salsa20", "tea", "xor", "none", "null", "blowfish", "twofish", "cast5", "3des", "xtea"}) do o:value(crypt, crypt) end
o.default = "aes"
o = s:option(ListValue, "xray_kcptun_mode", "Kcptun Mode")
o:depends("transport", "kcptun")
for _, mode in ipairs({"normal", "fast", "fast2", "fast3", "manual"}) do o:value(mode, mode) end
o.default = "fast"
o = s:option(ListValue, "xray_kcptun_smuxver", "Kcptun smux Version")
o:depends("transport", "kcptun")
o:value("1", "v1")
o:value("2", "v2")
o.default = "1"
o = s:option(Flag, "xray_kcptun_nocomp", translate("Disable Compression"))
o:depends("transport", "kcptun")
o.default = "0"
o = s:option(Value, "xray_kcptun_conn", translate("Connections"))
o:depends("transport", "kcptun")
o.datatype = "range(1,256)"
o.default = "1"
o = s:option(TextValue, "xray_kcptun_options", "Kcptun Advanced Options (JSON)")
o:depends("transport", "kcptun")
o.rows = 4
o.rmempty = true
o.description = translate("Optional MTU, FEC, windows and expiry settings. Encryption, key, compression and smux version must match the server. This transports streams over UDP; native proxy UDP is separate.")
function o.validate(self, value, section)
if not value or value:match("^%s*$") then return "" end
local ok, parsed = pcall(luci.jsonc.parse, value)
if ok and type(parsed) == "table" and value:match("^%s*{") then return value end
return nil, translate("Must be a JSON object")
end
-- [[ RAW部分 ]]--
-- TCP伪装
o = s:option(ListValue, "tcp_guise", translate("Camouflage Type"))
@@ -1437,7 +1500,7 @@ if protocols and type(protocols) == "table" and #protocols > 0 then
if not proto:find("^_") then
if proto == "hysteria2" then
o:depends({type = "v2ray", v2ray_protocol = "hysteria2", hysteria2_realms = false})
elseif proto ~= "socks" and proto ~= "http" and proto ~= "shadowsocksr" then
elseif proto ~= "socks" and proto ~= "http" and proto ~= "shadowsocksr" and proto ~= "tuic" and proto ~= "snell" then
o:depends({type = "v2ray", v2ray_protocol = proto})
end
end
@@ -1468,6 +1531,39 @@ o.validate = function(self, value)
end
end
-- ShadowTLS wraps the existing TCP proxy protocol in Xray.
o = s:option(Flag, "xray_shadowtls", "ShadowTLS (Xray)")
o.default = "0"
for _, proto in ipairs({"vmess", "vless", "trojan", "shadowsocks"}) do
o:depends({type = "v2ray", v2ray_protocol = proto, transport = "raw", tls = false, reality = false})
end
o.description = translate("ShadowTLS protects TCP connections. The inner proxy protocol must provide encryption.")
o = s:option(ListValue, "xray_shadowtls_version", "ShadowTLS Version")
o:depends("xray_shadowtls", "1")
o:value("3", "v3")
o:value("2", "v2")
o:value("1", "v1")
o.default = "3"
o = s:option(Value, "xray_shadowtls_password", "ShadowTLS Password")
o:depends({xray_shadowtls = "1", xray_shadowtls_version = "2"})
o:depends({xray_shadowtls = "1", xray_shadowtls_version = "3"})
o.password = true
o.rmempty = false
o = s:option(Value, "xray_shadowtls_sni", "ShadowTLS SNI")
o:depends("xray_shadowtls", "1")
o.datatype = "hostname"
o.rmempty = false
o = s:option(ListValue, "xray_shadowtls_fingerprint", translate("TLS Client Fingerprint"))
o:depends("xray_shadowtls", "1")
for _, fp in ipairs({"chrome", "firefox", "safari", "ios", "android", "edge", "none"}) do o:value(fp, fp) end
o.default = "chrome"
o = s:option(Flag, "xray_shadowtls_strict", translate("TLS 1.3 Strict mode"))
o:depends({xray_shadowtls = "1", xray_shadowtls_version = "3"})
o.default = "1"
o = s:option(Flag, "xray_shadowtls_insecure", translate("Allow Insecure"))
o:depends("xray_shadowtls", "1")
o.default = "0"
-- [[ TLS ]]--
o = s:option(Flag, "tls", translate("TLS"))
o.rmempty = true
@@ -1602,6 +1698,7 @@ o:depends("tls", true)
o:depends("xtls", true)
o:depends("reality", true)
o.rmempty = true
o:depends({type = "v2ray", v2ray_protocol = "tuic"})
o:depends({type = "v2ray", v2ray_protocol = "naive"})
@@ -1631,6 +1728,7 @@ o:value("h3,h2,http/1.1")
o:value("spdy/3.1")
o:value("h3,spdy/3.1")
o:depends("type", "tuic")
o:depends({type = "v2ray", v2ray_protocol = "tuic"})
-- IP STACK PREFERENCE
o = s:option(ListValue, "ipstack_prefer", translate("IP Stack Preference"))
@@ -1648,6 +1746,7 @@ o:depends("type", "trojan")
o:depends("type", "tuic")
o.description = translate("If true, allowss insecure connection at TLS client, e.g., TLS server uses unverifiable certificates.")
o:depends("tls", true)
o:depends({type = "v2ray", v2ray_protocol = "tuic"})
if xray_version_val >= 260131 then
-- Xray 版本大于等于 26.1.31
@@ -74,6 +74,10 @@ then
end
if nixio.fs.access("/usr/bin/xray") or nixio.fs.access("/usr/libexec/xray") then
o:value("naive", "NaiveProxy (Xray)")
o:value("tuic", "TUIC (Xray)")
o:value("snell", "Snell (Xray)")
o:value("anytls", "AnyTLS (Xray)")
o:value("ssr-xray", "ShadowsocksR (Xray)")
end
o.default = "socks5"
@@ -105,6 +109,7 @@ o:depends("type", "ss")
o:depends("type", "ssr")
o:depends("type", "trojan")
o:depends("type", "shadowsocks")
o:depends("type", "ssr-xray")
-- ========== SS/SSR 协议特有 ==========
o = s:option(ListValue, "encrypt_method", translate("Encrypt Method"))
@@ -235,6 +240,8 @@ o = s:option(Value, "tls_certificateFile", translate("Certificate File Path"))
o.description = translate("e.g.: /etc/ssl/fullchain.pem")
o.rmempty = true
o:depends("tls", "1")
o:depends("type", "tuic")
o:depends("type", "anytls")
o:depends("type", "naive")
@@ -242,6 +249,8 @@ o = s:option(Value, "tls_keyFile", translate("Private Key File Path"))
o.description = translate("e.g.: /etc/ssl/private.key")
o.rmempty = true
o:depends("tls", "1")
o:depends("type", "tuic")
o:depends("type", "anytls")
-- ========== 传输层设置 (Transport) ==========
o:depends("type", "naive")
@@ -411,4 +420,61 @@ o:value("h2,h3", "HTTP/2 + HTTP/3")
o.default = "h2"
o:depends("type", "naive")
return m
-- TUIC credentials are independent of the legacy server settings.
for _, field in ipairs({{"tuic_uuid", "TUIC UUID"}, {"tuic_password", "TUIC Password"}, {"tuic_token", "TUIC v4 Token"}}) do
o = s:option(Value, field[1], field[2])
o.password = field[1] ~= "tuic_uuid"
o:depends("type", "tuic")
end
o = s:option(Value, "snell_psk", translate("Snell PSK"))
o.password = true
o:depends("type", "snell")
o = s:option(ListValue, "snell_version", translate("Snell Version"))
for _, version in ipairs({"1", "2", "3", "4", "5"}) do o:value(version, "v" .. version) end
o.default = "4"
o:depends("type", "snell")
o = s:option(ListValue, "snell_obfs", translate("Snell Obfs"))
o:value("", translate("Disable"))
o:value("http", "HTTP")
o:value("tls", "TLS")
o:depends("type", "snell")
o = s:option(Flag, "snell_udp", translate("UDP Relay"))
o.default = "1"
for _, version in ipairs({"3", "4", "5"}) do
o:depends({type = "snell", snell_version = version})
end
o = s:option(Value, "anytls_password", translate("Password"))
o.password = true
o:depends("type", "anytls")
o = s:option(TextValue, "anytls_padding", "AnyTLS Padding Scheme")
o.rows = 5
o.rmempty = true
o:depends("type", "anytls")
-- Xray SSR has its own validated registry; keep legacy libev choices intact.
o = s:option(ListValue, "ssr_method", translate("Encrypt Method"))
for _, v in ipairs({"aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "rc4-md5", "chacha20", "chacha20-ietf", "xchacha20", "none"}) do o:value(v) end
o.default = "aes-128-cfb"
o.rmempty = false
o:depends("type", "ssr-xray")
o = s:option(ListValue, "ssr_protocol", translate("Protocol"))
for _, v in ipairs({"origin", "auth_sha1_v4", "auth_aes128_md5", "auth_aes128_sha1", "auth_chain_a", "auth_chain_b"}) do o:value(v) end
o.default = "auth_aes128_sha1"
o.rmempty = false
o:depends("type", "ssr-xray")
o = s:option(Value, "ssr_protocol_param", "SSR Protocol Param")
o.description = "1001:password1,1002:password2"
o:depends("type", "ssr-xray")
o = s:option(ListValue, "ssr_obfs", translate("Obfs"))
for _, v in ipairs({"plain", "http_simple", "http_post", "random_head", "tls1.2_ticket_auth", "tls1.2_ticket_fastauth"}) do o:value(v) end
o.default = "plain"
o.rmempty = false
o:depends("type", "ssr-xray")
o = s:option(Value, "ssr_obfs_param", translate("Obfs param (optional)"))
o.description = "HTTP Host: example.com,example.org"
o:depends({type = "ssr-xray", ssr_obfs = "http_simple"})
o:depends({type = "ssr-xray", ssr_obfs = "http_post"})
return m
@@ -111,6 +111,7 @@ function o.cfgvalue(self, section)
elseif val == "vless" then return "VLESS (Xray)"
elseif val == "trojan" then return "Trojan (Xray)"
elseif val == "shadowsocks" then return "Shadowsocks (Xray)"
elseif val == "ssr-xray" then return "ShadowsocksR (Xray)"
else return val end
end
@@ -126,6 +127,7 @@ end
o = sec:option(DummyValue, "encrypt_method", translate("Encrypt Method"))
function o.cfgvalue(self, section)
if self.map:get(section, "type") == "ssr-xray" then return (self.map:get(section, "ssr_method") or "-"):upper() end
local method = self.map:get(section, "encrypt_method") or self.map:get(section, "encrypt_method_ss")
return method and method:upper() or "-"
end
+53 -10
View File
@@ -992,8 +992,10 @@ use_mihomo_for_ss_rust_server() {
}
start_v2ray_with_mihomo() {
[ "$(uci_get_by_name "$1" transport)" = "kcptun" ] && return 1
[ "$(uci_get_by_name "$1" xray_shadowtls 0)" = "1" ] && return 1
# These nodes use Xray-specific settings.
case "$(uci_get_by_name "$1" v2ray_protocol)" in naive|shadowsocksr) return 1 ;; esac
case "$(uci_get_by_name "$1" v2ray_protocol)" in naive|shadowsocksr|tuic) return 1 ;; esac
local sid="$1"
local local_port="$2"
local socks_port="$3"
@@ -1798,7 +1800,7 @@ start_udp() {
;;
v2ray)
enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "")
if [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "naive" ] && [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "shadowsocksr" ] && [ "$enable_mihomo" = "1" ] && has_mihomo_binary; then
if [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "naive" ] && [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "shadowsocksr" ] && [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "tuic" ] && [ "$enable_mihomo" = "1" ] && has_mihomo_binary; then
redir_udp=0
ARG_UDP=""
echolog "UDP TPROXY Relay:V2Ray/Xray 单节点由主 Mihomo 实例处理。"
@@ -1811,7 +1813,7 @@ start_udp() {
echolog "UDP TPROXY Relay:$($(first_type xray) version | head -1) Started!"
else
# Xray 不存在但 Mihomo 存在,回退到 Mihomo(当 enable_mihomo=0 时)
if [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "naive" ] && [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "shadowsocksr" ] && has_mihomo_binary; then
if [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "naive" ] && [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "shadowsocksr" ] && [ "$(uci_get_by_name "$UDP_RELAY_SERVER" v2ray_protocol)" != "tuic" ] && has_mihomo_binary; then
redir_udp=0
ARG_UDP=""
echolog "UDP TPROXY Relay:Xray 内核不存在,已回退到 Mihomo 内核启动。"
@@ -1962,9 +1964,6 @@ start_local() {
[ -n "$probe_instance_key" ] && instance_key="$probe_instance_key"
if [ "$enable_mihomo" = "1" ] && start_v2ray_with_mihomo "$LOCAL_SERVER" "$local_port" "$local_port" "$instance_key" "socks" "v2ray-local" "Global_Socks5"; then
:
elif [ "$(uci_get_by_name "$LOCAL_SERVER" v2ray_protocol)" = "snell" ]; then
echolog "Global_Socks5:Snell 需要 Mihomo 内核,且当前 Mihomo 启动失败。"
return 1
elif [ "$_local" = "2" ]; then
# 尝试 Xray
xray_bin="$(first_type xray)"
@@ -2250,7 +2249,14 @@ get_udp_relay_mode() {
;;
v2ray)
proto=$(uci_get_by_name "$node" v2ray_protocol)
if [ "$(uci_get_by_name "$node" transport)" = "kcptun" ]; then
case "$proto" in vmess|vless|trojan) echo "native" ;; *) echo "disabled" ;; esac
return
fi
case "$proto" in
snell)
case "$(uci_get_by_name "$node" snell_version 4)" in 1|2) echo "disabled" ;; *) echo "native" ;; esac
;;
naive)
[ "$(uci_get_by_name "$node" naive_udp_over_tcp 0)" = "1" ] && echo "native" || echo "disabled"
;;
@@ -2386,11 +2392,8 @@ Start_Run() {
enable_mihomo=$(uci_get_by_type server_subscribe enable_mihomo "")
if [ "$enable_mihomo" = "1" ] && start_v2ray_with_mihomo "$GLOBAL_SERVER" "$tcp_port" "$socks_port" "$GLOBAL_SERVER" "redir" "ssr-retcp" "Main node"; then
:
elif [ "$(uci_get_by_name "$GLOBAL_SERVER" v2ray_protocol)" = "snell" ]; then
echolog "Main node:Snell 需要 Mihomo 内核,且当前 Mihomo 启动失败。"
return 1
else
# enable_mihomo=0 或 Mihomo 启动失败(非 Snell)→ 优先使用 Xray
# enable_mihomo=0 或 Mihomo 启动失败 → 优先使用 Xray
xray_bin="$(first_type xray)"
if [ -n "$xray_bin" ]; then
gen_config_file "$GLOBAL_SERVER" "$type" 1 "$tcp_port" "$socks_port"
@@ -2752,6 +2755,46 @@ start_server() {
echolog "Server: Xray NaiveProxy Server$server_count Started!"
;;
ssr-xray)
xray_bin="$(first_type xray)"
[ -x "$xray_bin" ] || return 1
config_file="$TMP_PATH/xray-server-$server_count.json"
lua /usr/share/shadowsocksr/gen_ssr_server.lua "$1" > "$config_file" || return 1
"$xray_bin" run -test -c "$config_file" >> /var/ssrplus.log 2>&1 || return 1
ln_start_bin "$xray_bin" xray-server-$server_count run -c "$config_file"
echolog "Server: Xray ShadowsocksR Server$server_count Started!"
;;
anytls)
xray_bin="$(first_type xray)"
[ -x "$xray_bin" ] || return 1
config_file="$TMP_PATH/xray-server-$server_count.json"
lua /usr/share/shadowsocksr/gen_anytls_server.lua "$1" > "$config_file" || return 1
"$xray_bin" run -test -c "$config_file" >> /var/ssrplus.log 2>&1 || return 1
ln_start_bin "$xray_bin" xray-server-$server_count run -c "$config_file"
echolog "Server: Xray AnyTLS Server$server_count Started!"
;;
snell)
xray_bin="$(first_type xray)"
[ -x "$xray_bin" ] || return 1
config_file="$TMP_PATH/xray-server-$server_count.json"
lua /usr/share/shadowsocksr/gen_snell_server.lua "$1" > "$config_file" || return 1
"$xray_bin" run -test -c "$config_file" >> /var/ssrplus.log 2>&1 || return 1
ln_start_bin "$xray_bin" xray-server-$server_count run -c "$config_file"
echolog "Server: Xray Snell Server$server_count Started!"
;;
tuic)
xray_bin="$(first_type xray)"
[ -x "$xray_bin" ] || return 1
config_file="$TMP_PATH/xray-server-$server_count.json"
lua /usr/share/shadowsocksr/gen_tuic_server.lua "$1" > "$config_file" || return 1
"$xray_bin" run -test -c "$config_file" >> /var/ssrplus.log 2>&1 || return 1
ln_start_bin "$xray_bin" xray-server-$server_count run -c "$config_file"
echolog "Server: Xray TUIC Server$server_count Started!"
;;
vmess|vless|trojan|shadowsocks)
# Xray 服务端支持
port=$(uci_get_by_name "$1" server_port)
@@ -928,7 +928,9 @@ local function build_v2ray_mihomo_proxy(sid)
elseif protocol == "snell" then
proxy.type = "snell"
proxy.psk = get_server_field(sid, "snell_psk", "")
proxy.version = number_or_nil(get_server_field(sid, "snell_version", ""))
proxy.version = tonumber(get_server_field(sid, "snell_version", "4")) or 4
proxy.reuse = get_server_field(sid, "snell_reuse", "0") == "1"
proxy.udp = proxy.version >= 3
local obfs_mode = string_or_nil(get_server_field(sid, "snell_obfs", ""))
local obfs_host = string_or_nil(get_server_field(sid, "snell_obfs_host", ""))
if obfs_mode or obfs_host then
@@ -0,0 +1,17 @@
#!/usr/bin/lua
local uci = require("luci.model.uci").cursor()
local json = require "luci.jsonc"
local s = assert(uci:get_all("shadowsocksr", arg[1]), "missing server section")
local padding = {}
for line in (s.anytls_padding or ""):gmatch("[^\r\n]+") do padding[#padding + 1] = line end
print(json.stringify({
log = {loglevel = "warning"},
inbounds = {{listen = "::", port = assert(tonumber(s.server_port)), protocol = "anytls",
settings = {users = {{email = "user", password = assert(s.anytls_password)}},
paddingScheme = #padding > 0 and padding or nil},
streamSettings = {network = "raw", security = "tls", tlsSettings = {
certificates = {{oneTimeLoading = true, certificateFile = assert(s.tls_certificateFile), keyFile = assert(s.tls_keyFile)}}
}}
}},
outbounds = {{protocol = "freedom", settings = {}}}
}, 1))
@@ -363,6 +363,34 @@ function outbound:handleIndex(index)
trojan = function()
trojan_shadowsocks()
end,
snell = function()
outbound_settings = {
address = server.server, port = tonumber(server.server_port),
psk = server.snell_psk, version = tonumber(server.snell_version) or 4,
obfs = server.snell_obfs or "", obfsHost = server.snell_obfs_host,
reuse = server.snell_reuse == "1"
}
end,
tuic = function()
local version = tonumber(server.xray_tuic_version) or 5
local alpn = {}
for value in (server.tuic_alpn or ""):gmatch("[^,]+") do alpn[#alpn + 1] = value end
if #alpn == 0 then alpn = {"h3"} end
outbound_settings = {
address = server.server, port = tonumber(server.server_port), version = version,
token = version == 4 and server.xray_tuic_token or nil,
uuid = version == 5 and server.tuic_uuid or nil,
password = version == 5 and server.tuic_passwd or nil,
serverName = server.tls_host, certificateFile = server.xray_tuic_ca,
allowInsecure = server.insecure == "1",
alpn = alpn,
congestionControl = server.congestion_control or "cubic",
udpRelayMode = server.udp_relay_mode or "native",
heartbeatInterval = (tonumber(server.heartbeat) or 10) * 1000,
requestTimeout = (tonumber(server.timeout) or 8) * 1000,
reduceRtt = server.zero_rtt_handshake == "1"
}
end,
shadowsocksr = function()
outbound_settings = {
address = server.server, port = tonumber(server.server_port),
@@ -899,14 +927,53 @@ Xray.outbounds = {
}
}
-- Naive owns TLS/multiplexing; SSR owns obfuscation and uses native UDP.
-- Preserve Xray socket marks and dialer chains for both.
if server.v2ray_protocol == "naive" or server.v2ray_protocol == "shadowsocksr" then
-- These protocols own their framing, obfuscation and multiplexing.
-- Preserve Xray socket marks and dialer chains.
if server.v2ray_protocol == "naive" or server.v2ray_protocol == "shadowsocksr" or server.v2ray_protocol == "tuic" or server.v2ray_protocol == "snell" then
local ob = Xray.outbounds[1]
ob.streamSettings = { network = "raw", sockopt = ob.streamSettings.sockopt }
ob.mux = nil
end
if server.type == "v2ray" and server.transport == "kcptun" then
local supported = {vmess = true, vless = true, trojan = true, shadowsocks = true, socks = true, http = true}
assert(supported[server.v2ray_protocol], "Kcptun requires a supported stream proxy protocol")
assert(server.tls ~= "1" and server.reality ~= "1" and server.xtls ~= "1", "Kcptun cannot be combined with stream TLS or REALITY")
assert(server.kcp_enable ~= "1", "Native Kcptun cannot be combined with the external Kcptun client")
assert(not server.tls_flow or server.tls_flow == "", "Kcptun cannot be combined with XTLS flow")
local options = {}
if server.xray_kcptun_options and server.xray_kcptun_options:match("%S") then
assert(server.xray_kcptun_options:match("^%s*{"), "Kcptun options must be a JSON object")
options = json.parse(server.xray_kcptun_options)
assert(type(options) == "table", "Kcptun options must be a JSON object")
end
options.key = server.xray_kcptun_key
options.crypt = server.xray_kcptun_crypt or "aes"
options.mode = server.xray_kcptun_mode or "fast"
options.smuxver = tonumber(server.xray_kcptun_smuxver) or 1
options.nocomp = server.xray_kcptun_nocomp == "1"
options.conn = tonumber(server.xray_kcptun_conn) or 1
Xray.outbounds[1].streamSettings.kcptunSettings = options
end
if server.type == "v2ray" and server.xray_shadowtls == "1" then
local supported = {vmess = true, vless = true, trojan = true, shadowsocks = true}
assert(supported[server.v2ray_protocol], "ShadowTLS requires a supported TCP proxy protocol")
assert((server.transport or "raw") == "raw" or server.transport == "tcp", "ShadowTLS requires RAW/TCP")
assert(server.tls ~= "1" and server.reality ~= "1", "ShadowTLS cannot be combined with TLS or REALITY")
assert(not server.tls_flow or server.tls_flow == "", "ShadowTLS cannot be combined with XTLS flow")
local stream = Xray.outbounds[1].streamSettings
stream.security = "shadowtls"
stream.shadowtlsSettings = {
version = tonumber(server.xray_shadowtls_version) or 3,
password = server.xray_shadowtls_password,
serverName = server.xray_shadowtls_sni,
fingerprint = server.xray_shadowtls_fingerprint or "chrome",
strictMode = server.xray_shadowtls_strict ~= "0",
allowInsecure = server.xray_shadowtls_insecure == "1"
}
end
if xray_builtin_dns then
table.insert(Xray.outbounds, {
protocol = "dns",
@@ -1322,6 +1389,14 @@ function config:handleIndex(index)
chain_switch[ChainType]()
end
end,
snell = function()
outbound_settings = {
address = server.server, port = tonumber(server.server_port),
psk = server.snell_psk, version = tonumber(server.snell_version) or 4,
obfs = server.snell_obfs or "", obfsHost = server.snell_obfs_host,
reuse = server.snell_reuse == "1"
}
end,
tuic = function()
print(json.stringify(tuic, 1))
end
@@ -0,0 +1,13 @@
#!/usr/bin/lua
local uci = require("luci.model.uci").cursor()
local json = require "luci.jsonc"
local s = assert(uci:get_all("shadowsocksr", arg[1]), "missing server section")
local version = tonumber(s.snell_version) or 4
print(json.stringify({
log = {loglevel = "warning"},
inbounds = {{listen = "::", port = assert(tonumber(s.server_port)), protocol = "snell",
settings = {psk = assert(s.snell_psk), version = version,
obfs = s.snell_obfs or "", udp = version >= 3 and s.snell_udp ~= "0"}
}},
outbounds = {{protocol = "freedom", settings = {}}}
}, 1))
@@ -0,0 +1,13 @@
#!/usr/bin/lua
local uci = require("luci.model.uci").cursor()
local json = require "luci.jsonc"
local s = assert(uci:get_all("shadowsocksr", arg[1]), "missing server section")
print(json.stringify({
log = {loglevel = "warning"},
inbounds = {{listen = "::", port = assert(tonumber(s.server_port)), protocol = "shadowsocksr",
settings = {password = assert(s.password), method = s.ssr_method or "aes-128-cfb",
protocol = s.ssr_protocol or "auth_aes128_sha1", protocolParam = s.ssr_protocol_param or "",
obfs = s.ssr_obfs or "plain", obfsParam = s.ssr_obfs_param or "", network = "tcp,udp"}
}},
outbounds = {{protocol = "freedom", settings = {}}}
}, 1))
@@ -0,0 +1,19 @@
#!/usr/bin/lua
local uci = require("luci.model.uci").cursor()
local json = require "luci.jsonc"
local s = assert(uci:get_all("shadowsocksr", arg[1]), "missing server section")
local users, tokens = {}, {}
if s.tuic_uuid and s.tuic_uuid ~= "" then
users[s.tuic_uuid] = assert(s.tuic_password, "TUIC password required")
end
if s.tuic_token and s.tuic_token ~= "" then tokens[1] = s.tuic_token end
assert(next(users) or #tokens > 0, "TUIC credentials required")
print(json.stringify({
log = {loglevel = "warning"},
inbounds = {{listen = "::", port = assert(tonumber(s.server_port)), protocol = "tuic",
settings = {users = next(users) and users or nil, tokens = #tokens > 0 and tokens or nil,
certificateFile = assert(s.tls_certificateFile), keyFile = assert(s.tls_keyFile)},
streamSettings = {network = "tuic"}
}},
outbounds = {{protocol = "freedom", settings = {}}}
}, 1))
@@ -824,7 +824,9 @@ local function to_mihomo_proxy(node)
elseif node.type == "v2ray" and node.v2ray_protocol == "snell" then
proxy.type = "snell"
proxy.psk = node.snell_psk
proxy.version = tonumber(node.snell_version) or nil
proxy.version = tonumber(node.snell_version) or 4
proxy.udp = proxy.version >= 3
proxy.reuse = node.snell_reuse == "1"
local obfs_mode = string_from_value(node.snell_obfs)
local obfs_host = string_from_value(node.snell_obfs_host)
if obfs_mode or obfs_host then
@@ -1021,8 +1023,8 @@ local function processData(szType, content, cfgid)
result.fast_open = params.tfo
end
elseif szType == "snell" then
if not has_mihomo then
log("跳过 Snell 节点:本地未安装 mihomo。")
if not has_xray and not has_mihomo then
log("跳过 Snell 节点:本地未安装 Xray 或 Mihomo。")
return nil
end
@@ -1041,6 +1043,7 @@ local function processData(szType, content, cfgid)
result.snell_version = first_nonempty(params, {"version", "v"}) or "4"
result.snell_obfs = first_nonempty(params, {"obfs", "obfs-mode", "obfs_mode"})
result.snell_obfs_host = first_nonempty(params, {"obfs-host", "obfs_host", "host"})
result.snell_reuse = (params.reuse == "1" or params.reuse == "true") and "1" or "0"
if not result.snell_psk or result.snell_psk == "" then
result.server = nil
end
+2 -2
View File
@@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-trafficctl
PKG_VERSION:=1.23.0
PKG_RELEASE:=13
PKG_VERSION:=1.23.1
PKG_RELEASE:=14
PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=Denis Iusupov <yusdyr@gmail.com>
@@ -13,6 +13,12 @@ msgstr ""
msgid "%d pkts, %s dropped"
msgstr ""
msgid "%s down / %s up"
msgstr ""
msgid "%s down and %s up"
msgstr ""
msgid "%s total"
msgstr ""
@@ -46,9 +52,7 @@ msgstr ""
msgid "50 Mbit/s"
msgstr ""
msgid ""
"Accelerates routing in the kernel via nftables flowtable. Speed monitoring and t"
"raffic shaping work normally."
msgid "Accelerates routing in the kernel via nftables flowtable. Speed monitoring and traffic shaping work normally."
msgstr ""
msgid "Accumulated on the router"
@@ -81,6 +85,9 @@ msgstr ""
msgid "Adding to"
msgstr ""
msgid "Aggregate every stored period"
msgstr ""
msgid "All"
msgstr ""
@@ -96,9 +103,7 @@ msgstr ""
msgid "App"
msgstr ""
msgid ""
"Applied once, the first time a device appears on the network. A device that alre"
"ady has a limit is left alone."
msgid "Applied once, the first time a device appears on the network. A device that already has a limit is left alone."
msgstr ""
msgid "Applied — firewall reloading"
@@ -152,9 +157,7 @@ msgstr ""
msgid "Bridge port — these bytes are also counted in its bridge"
msgstr ""
msgid ""
"Bridge ports, switch conduits and ifb mirrors. Their bytes are already counted i"
"n the bridge or uplink above."
msgid "Bridge ports, switch conduits and ifb mirrors. Their bytes are already counted in the bridge or uplink above."
msgstr ""
msgid "Byte totals unavailable on this router."
@@ -283,17 +286,10 @@ msgstr ""
msgid "Devices already known:"
msgstr ""
msgid ""
"Devices keep talking to each other and to the router — only the way out is close"
"d. Traffic is stopped on the way in, so a transparent proxy on the router (podko"
"p, passwall) cannot carry it out either. Remote access that reaches the router t"
"hrough a LAN host (Tailscale, a tunnel, a jump host) stops working while this is"
" on."
msgid "Devices keep talking to each other and to the router — only the way out is closed. Traffic is stopped on the way in, so a transparent proxy on the router (podkop, passwall) cannot carry it out either. Remote access that reaches the router through a LAN host (Tailscale, a tunnel, a jump host) stops working while this is on."
msgstr ""
msgid ""
"Devices on the WiFi deny list that are still connected — those blocks are not in"
" effect on the running radio."
msgid "Devices on the WiFi deny list that are still connected — those blocks are not in effect on the running radio."
msgstr ""
msgid "Disable hardware offload (keeps software offload):"
@@ -311,6 +307,9 @@ msgstr ""
msgid "Done"
msgstr ""
msgid "Download"
msgstr ""
msgid "Download · %s"
msgstr ""
@@ -353,6 +352,12 @@ msgstr ""
msgid "Every device this router forwards for"
msgstr ""
msgid "Exact. Byte counts come from cumulative nftables counters, so they do not depend on how often the sampler runs. The TCP/UDP split is unavailable from this source."
msgstr ""
msgid "Export CSV"
msgstr ""
msgid "Ext. port"
msgstr ""
@@ -374,11 +379,10 @@ msgstr ""
msgid "Flow Offload"
msgstr ""
msgid ""
"Flow offload is active and the kernel does not support the nftables counter maps"
" trafficctl uses in that mode, so byte counters stop updating for offloaded conn"
"ections. Speeds and totals would be far too low, so they are not shown. Disablin"
"g hardware offload in Settings → Flow Offload restores them."
msgid "Flow offload is active and the kernel does not support the nftables counter maps trafficctl uses in that mode, so byte counters stop updating for offloaded connections. Speeds and totals would be far too low, so they are not shown. Disabling hardware offload in Settings → Flow Offload restores them."
msgstr ""
msgid "Flow offloading is active."
msgstr ""
msgid "Flow: /devices → select device → inline keyboard with enabled actions above"
@@ -387,9 +391,16 @@ msgstr ""
msgid "Flows"
msgstr ""
msgid ""
"Forwarded traffic only — this kernel cannot install the prerouting rule, so traf"
"fic handled by a transparent proxy on the router would not be caught."
msgid "Flush failed"
msgstr ""
msgid "Flush now"
msgstr ""
msgid "Flushing…"
msgstr ""
msgid "Forwarded traffic only — this kernel cannot install the prerouting rule, so traffic handled by a transparent proxy on the router would not be caught."
msgstr ""
msgid "Full control"
@@ -398,6 +409,9 @@ msgstr ""
msgid "Gbit/s"
msgstr ""
msgid "Give upload its own ceiling instead of matching download"
msgstr ""
msgid "Global internet cut needs nftables (fw4). This router is running iptables."
msgstr ""
@@ -428,15 +442,16 @@ msgstr ""
msgid "Hardware offload"
msgstr ""
msgid "History is not recorded by default: it writes to the router's flash on a schedule, and every other persistent store in this app was deliberately kept off that path. Enable it below."
msgstr ""
msgid "Hostname"
msgstr ""
msgid "Hostname / Dst IP"
msgstr ""
msgid ""
"How often live data is polled: speeds, graphs, drop/backlog counters, and the co"
"nnection table in device view"
msgid "How often live data is polled: speeds, graphs, drop/backlog counters, and the connection table in device view"
msgstr ""
msgid "How to get full functionality without disabling offload:"
@@ -445,10 +460,10 @@ msgstr ""
msgid "IP address"
msgstr ""
msgid ""
"If your current firmware uses fw3 (iptables) or ships a kernel older than 5.7, a"
" router with modern OpenWrt and fw4 support will have this working out of the bo"
"x."
msgid "IP-keyed"
msgstr ""
msgid "If your current firmware uses fw3 (iptables) or ships a kernel older than 5.7, a router with modern OpenWrt and fw4 support will have this working out of the box."
msgstr ""
msgid "Iface"
@@ -457,18 +472,13 @@ msgstr ""
msgid "In"
msgstr ""
msgid ""
"In this mode the kernel's conntrack, firewall, and tc are bypassed for offloaded"
" flows:"
msgid "In this mode the kernel's conntrack, firewall, and tc are bypassed for offloaded flows:"
msgstr ""
msgid "Inbound rate limit (drops packets above the rate)"
msgstr ""
msgid ""
"Inbound traffic control for DNAT port forwards and router-local open ports confi"
"gured in the firewall. Pause drops all inbound traffic on the port instantly (wi"
"thout touching the firewall config); Limit polices the inbound rate."
msgid "Inbound traffic control for DNAT port forwards and router-local open ports configured in the firewall. Pause drops all inbound traffic on the port instantly (without touching the firewall config); Limit polices the inbound rate."
msgstr ""
msgid "Inet"
@@ -501,6 +511,9 @@ msgstr ""
msgid "LAN keeps working"
msgstr ""
msgid "Last seen"
msgstr ""
msgid "Last seen: %s, %s ago"
msgstr ""
@@ -534,10 +547,7 @@ msgstr ""
msgid "Limiter (nft drop)"
msgstr ""
msgid "Limiting %s → %s (%s)…"
msgstr ""
msgid "Limiting → %s…"
msgid "Limiting"
msgstr ""
msgid "Link"
@@ -561,6 +571,9 @@ msgstr ""
msgid "Logging & Persistence"
msgstr ""
msgid "Lower bound, not a measurement. Flow offloading is active without counter support, so the kernel counters this history is built from stop moving while traffic keeps flowing. The real figures are higher by an unknown amount — use these only as a floor."
msgstr ""
msgid "MAC address"
msgstr ""
@@ -585,6 +598,9 @@ msgstr ""
msgid "New devices"
msgstr ""
msgid "No MAC address is known for this device, so its history is keyed on its IP address. If that address is reassigned, earlier traffic recorded here may belong to a different device."
msgstr ""
msgid "No action buttons enabled"
msgstr ""
@@ -597,9 +613,7 @@ msgstr ""
msgid "No activity recorded yet."
msgstr ""
msgid ""
"No baseline recorded yet. It is taken from the current leases when you switch th"
"is on."
msgid "No baseline recorded yet. It is taken from the current leases when you switch this on."
msgstr ""
msgid "No devices match filter."
@@ -617,23 +631,19 @@ msgstr ""
msgid "No port forwards or WAN-open ports are configured in the firewall."
msgstr ""
msgid "No traffic has been recorded for this period yet. The first figures appear after the next flush."
msgstr ""
msgid "None (per-flow)"
msgstr ""
msgid ""
"Not counted: flow offload is active and this router cannot provide the nftables "
"counters trafficctl uses in that mode, so the kernel byte counters stop updating"
" for offloaded connections. Any total here would be far too low. See Settings → "
"Flow Offload."
msgid "Not counted: flow offload is active and this router cannot provide the nftables counters trafficctl uses in that mode, so the kernel byte counters stop updating for offloaded connections. Any total here would be far too low. See Settings → Flow Offload."
msgstr ""
msgid "Not enough data yet"
msgstr ""
msgid ""
"Not measurable while flow offload is active: in that mode the router counts byte"
"s per address only, so traffic cannot be split by protocol. See Settings → Flow "
"Offload."
msgid "Not measurable while flow offload is active: in that mode the router counts bytes per address only, so traffic cannot be split by protocol. See Settings → Flow Offload."
msgstr ""
msgid "Note: speed is measured before shaper — bursts above limit are normal"
@@ -648,19 +658,16 @@ msgstr ""
msgid "Off"
msgstr ""
msgid ""
"Offloads routing to the hardware engine (PPE/NPU). Requires software offload. ⚠ "
"On many platforms (e.g. Mediatek Filogic) the driver does not report byte counte"
"rs back to the kernel — real-time speed monitoring will show zero."
msgid "Off."
msgstr ""
msgid "Offloads routing to the hardware engine (PPE/NPU). Requires software offload. ⚠ On many platforms (e.g. Mediatek Filogic) the driver does not report byte counters back to the kernel — real-time speed monitoring will show zero."
msgstr ""
msgid "On %s"
msgstr ""
msgid ""
"On the WiFi deny list but still connected — the block is NOT in effect on the ru"
"nning radio. Install hostapd-utils so blocks apply immediately, or restart WiFi "
"(disconnects every client)."
msgid "On the WiFi deny list but still connected — the block is NOT in effect on the running radio. Install hostapd-utils so blocks apply immediately, or restart WiFi (disconnects every client)."
msgstr ""
msgid "One bucket for the whole subnet"
@@ -711,6 +718,15 @@ msgstr ""
msgid "Pause"
msgstr ""
msgid "Per-device totals accumulated per accounting period, including devices that are not connected now. Figures survive reboots; the live view on the Devices tab does not."
msgstr ""
msgid "Period"
msgstr ""
msgid "Periods"
msgstr ""
msgid "Persist rules"
msgstr ""
@@ -738,13 +754,16 @@ msgstr ""
msgid "Protocol"
msgstr ""
msgid "Qualcomm NSS acceleration is active"
msgstr ""
msgid "Queue"
msgstr ""
msgid "Queue memory"
msgstr ""
msgid "Queued: <b style=\\\"color:var(--tc-speed)\\\">%s</b>"
msgid "Queued: <b style=\"color:var(--tc-speed)\">%s</b>"
msgstr ""
msgid "Queues excess traffic (smoother streaming, lower jitter)"
@@ -756,6 +775,9 @@ msgstr ""
msgid "Rate limiting — applies only to new connections"
msgstr ""
msgid "Rate limits and traffic shaping cannot be enforced while it is: accelerated flows bypass the Linux network stack, so rules are installed but have no effect. The toggles below do not control this — stop the ECM front end (front_end_ipv4_stop / front_end_ipv6_stop under /sys/kernel/debug/ecm) or set acceleration_engine in /etc/config/ecm, then re-apply the limit."
msgstr ""
msgid "Ratelimits"
msgstr ""
@@ -765,6 +787,9 @@ msgstr ""
msgid "Recent"
msgstr ""
msgid "Recording is paused: the last write failed."
msgstr ""
msgid "Refresh"
msgstr ""
@@ -810,6 +835,9 @@ msgstr ""
msgid "Running…"
msgstr ""
msgid "Sampled. Byte counts come from conntrack, which only reports flows that are alive when it is read — a connection that both starts and finishes between two samples is not counted. Shorten the sampling interval to narrow that gap."
msgstr ""
msgid "Save"
msgstr ""
@@ -849,7 +877,7 @@ msgstr ""
msgid "Shaped:"
msgstr ""
msgid "Shaped: <b style=\\\"color:var(--tc-speed)\\\">🌊 %s</b>"
msgid "Shaped: <b style=\"color:var(--tc-speed)\">🌊 %s</b>"
msgstr ""
msgid "Shaper"
@@ -861,12 +889,15 @@ msgstr ""
msgid "Shapes"
msgstr ""
msgid "Shaping → %s…"
msgid "Shaping"
msgstr ""
msgid "Share:"
msgstr ""
msgid "Show only this period"
msgstr ""
msgid "Show/hide token"
msgstr ""
@@ -879,6 +910,9 @@ msgstr ""
msgid "Software flow offload"
msgstr ""
msgid "Software flow offloading is active, with counter sync."
msgstr ""
msgid "Software flow offloading is active."
msgstr ""
@@ -888,18 +922,19 @@ msgstr ""
msgid "Software offload (counter)"
msgstr ""
msgid "Sort by this column"
msgstr ""
msgid "Speed Limit"
msgstr ""
msgid "Speed graph. Window = avg time. Orange dashed line = speed limit"
msgstr ""
msgid ""
"Speed is measured via nftables counters installed at a higher priority (before t"
"he flowtable), so graphs are accurate."
msgid "Speed is measured via nftables counters installed at a higher priority (before the flowtable), so graphs are accurate."
msgstr ""
msgid "Speed limit: <b style=\\\"color:var(--tc-warn)\\\">⚡ %s</b>"
msgid "Speed limit: <b style=\"color:var(--tc-warn)\">⚡ %s</b>"
msgstr ""
msgid "Speed limit: shaper (queue) or limiter (drop)"
@@ -908,6 +943,9 @@ msgstr ""
msgid "Speed monitoring — conntrack byte counters are not updated"
msgstr ""
msgid "Split up/down"
msgstr ""
msgid "State"
msgstr ""
@@ -917,20 +955,25 @@ msgstr ""
msgid "Stays off until you switch it back."
msgstr ""
msgid ""
"Store the current Poll and Window as this router's defaults, for browsers that h"
"ave not set their own"
msgid "Store"
msgstr ""
msgid "Store the current Poll and Window as this router's defaults, for browsers that have not set their own"
msgstr ""
msgid "Switch it off"
msgstr ""
msgid "Switch off"
msgstr ""
msgid "Switch on"
msgstr ""
msgid "Syslog"
msgstr ""
msgid ""
"TCP bytes transferred, accumulated on the router. Not measurable while flow offl"
"oad is active"
msgid "TCP bytes transferred, accumulated on the router. Not measurable while flow offload is active"
msgstr ""
msgid "TCP: <b>%d</b>"
@@ -951,25 +994,34 @@ msgstr ""
msgid "Test"
msgstr ""
msgid ""
"The auto-revert helper is not running; this page re-checks the deadline while it"
" is open."
msgid "The accuracy of these figures could not be determined."
msgstr ""
msgid "The auto-revert helper is not running; this page re-checks the deadline while it is open."
msgstr ""
msgid "The flowtable"
msgstr ""
msgid "The flowtable carries the"
msgstr ""
msgid "The internet cut is switched on, but its firewall rule is missing."
msgstr ""
msgid ""
"The kernel fast-paths established connections through a flowtable, bypassing con"
"ntrack byte updates for higher throughput."
msgid "The kernel fast-paths established connections through a flowtable for higher throughput."
msgstr ""
msgid ""
"The router offloads established connections from the CPU to the hardware (NIC/So"
"C), achieving 2–3× higher throughput and lower CPU usage."
msgid "The kernel fast-paths established connections through a flowtable, bypassing conntrack byte updates for higher throughput."
msgstr ""
msgid "The router offloads established connections from the CPU to the hardware (NIC/SoC), achieving 2–3× higher throughput and lower CPU usage."
msgstr ""
msgid "The store directory is not writable yet."
msgstr ""
msgid "This build of trafficctl does not have a description for the mode the router reported, so how it affects monitoring is not stated here rather than guessed at."
msgstr ""
msgid "Throttle removed"
@@ -993,9 +1045,10 @@ msgstr ""
msgid "Top talkers"
msgstr ""
msgid ""
"Total bytes transferred (download + upload), accumulated on the router. Resets o"
"n reboot; hover a cell for the start time"
msgid "Total"
msgstr ""
msgid "Total bytes transferred (download + upload), accumulated on the router. Resets on reboot; hover a cell for the start time"
msgstr ""
msgid "Total dropped"
@@ -1013,9 +1066,13 @@ msgstr ""
msgid "Traffic Control"
msgstr ""
msgid ""
"Traffic is flowing right now. It is normally re-asserted within seconds — if thi"
"s persists, switch it off and on again."
msgid "Traffic History"
msgstr ""
msgid "Traffic history is switched off. Nothing is being recorded."
msgstr ""
msgid "Traffic is flowing right now. It is normally re-asserted within seconds — if this persists, switch it off and on again."
msgstr ""
msgid "Traffic shaping (tc/HTB) — bypassed for offloaded flows"
@@ -1024,9 +1081,7 @@ msgstr ""
msgid "Traffic shaping and blocking are not affected."
msgstr ""
msgid ""
"UDP bytes transferred, accumulated on the router. Not measurable while flow offl"
"oad is active"
msgid "UDP bytes transferred, accumulated on the router. Not measurable while flow offload is active"
msgstr ""
msgid "UDP: <b>%d</b>"
@@ -1050,6 +1105,9 @@ msgstr ""
msgid "Until I switch it back"
msgstr ""
msgid "Upload"
msgstr ""
msgid "Upload · %s"
msgstr ""
@@ -1071,6 +1129,12 @@ msgstr ""
msgid "Waiting for the first byte sample."
msgstr ""
msgid "When this device last moved any traffic, not when it was last connected"
msgstr ""
msgid "While this total was being accumulated, flow offloading froze the counters it is built from. The figure is a floor, not a measurement."
msgstr ""
msgid "Whole network"
msgstr ""
@@ -1101,6 +1165,9 @@ msgstr ""
msgid "Window"
msgstr ""
msgid "Write the figures accumulated so far to the store now, without waiting for the next scheduled flush"
msgstr ""
msgid "You will need LAN or physical access to undo this — a reboot will not clear it."
msgstr ""
@@ -1110,9 +1177,15 @@ msgstr ""
msgid "all active blocks, limits, and shapes"
msgstr ""
msgid "at least"
msgstr ""
msgid "between them — one bucket for the whole subnet."
msgstr ""
msgid "between them — one bucket per direction for the whole subnet."
msgstr ""
msgid "bit/s"
msgstr ""
@@ -1146,6 +1219,9 @@ msgstr ""
msgid "date + time"
msgstr ""
msgid "days ago"
msgstr ""
msgid "device connections"
msgstr ""
@@ -1155,6 +1231,9 @@ msgstr ""
msgid "device list → tap device → action buttons"
msgstr ""
msgid "devices"
msgstr ""
msgid "disabled"
msgstr ""
@@ -1173,16 +1252,16 @@ msgstr ""
msgid "failed"
msgstr ""
msgid ""
"flag (Linux 5.7+, set automatically by fw4/nftables) periodically syncs hardware"
" byte counts back to conntrack — trafficctl detects this and all features work n"
"ormally."
msgid "flag (Linux 5.7+, set automatically by fw4), so offloaded byte counts are synced back to conntrack. Speed and totals come from conntrack as usual and are accurate — the nftables counter fallback is not needed on this router."
msgstr ""
msgid ""
"flag should sync hardware byte counts back to conntrack, but on many platforms ("
"e.g. Mediatek Filogic) the driver does not implement the stats callback, so conn"
"track counters remain frozen for active flows."
msgid "flag (Linux 5.7+, set automatically by fw4/nftables) periodically syncs hardware byte counts back to conntrack — trafficctl detects this and all features work normally."
msgstr ""
msgid "flag should sync hardware byte counts back to conntrack, but on many platforms (e.g. Mediatek Filogic) the driver does not implement the stats callback, so conntrack counters remain frozen for active flows."
msgstr ""
msgid "flush every"
msgstr ""
msgid "groups from"
@@ -1191,16 +1270,24 @@ msgstr ""
msgid "h"
msgstr ""
msgid ""
"is not one of the subnets this router monitors, so a limit on it would be accept"
"ed but never enforced. A firewall zone other than \"lan\" with masq=1 (the usual g"
"uest-VLAN setup) is excluded. Check with: uci show firewall | grep -E \"name=|mas"
"q=\""
msgid "h ago"
msgstr ""
msgid "is not one of the subnets this router monitors, so a limit on it would be accepted but never enforced. A firewall zone other than \"lan\" with masq=1 (the usual guest-VLAN setup) is excluded. Check with: uci show firewall | grep -E \"name=|masq=\""
msgstr ""
msgid "just now"
msgstr ""
msgid "kbit/s"
msgstr ""
msgid "keeping"
msgstr ""
msgid "last flush"
msgstr ""
msgid "line break"
msgstr ""
@@ -1210,6 +1297,9 @@ msgstr ""
msgid "min"
msgstr ""
msgid "min ago"
msgstr ""
msgid "network interface"
msgstr ""
@@ -1249,6 +1339,12 @@ msgstr ""
msgid "percentage of total traffic that was dropped"
msgstr ""
msgid "period"
msgstr ""
msgid "periods"
msgstr ""
msgid "pkts"
msgstr ""
@@ -1282,6 +1378,9 @@ msgstr ""
msgid "s"
msgstr ""
msgid "sampled every"
msgstr ""
msgid "saved"
msgstr ""
@@ -1312,26 +1411,23 @@ msgstr ""
msgid "under a minute"
msgstr ""
msgid "undercounted"
msgstr ""
msgid "value"
msgstr ""
msgid "↑ UL"
msgstr ""
msgid ""
"↓ / ↑ are relative to the interface: on the WAN ↓ is your download, on a LAN bri"
"dge ↓ is what the LAN sent upstream."
msgid "↑ Upload"
msgstr ""
msgid "↓ / ↑ are relative to the interface: on the WAN ↓ is your download, on a LAN bridge ↓ is what the LAN sent upstream."
msgstr ""
msgid "↓ DL"
msgstr ""
msgid ""
"🆕 <b>New device</b>\n"
"{{ name }} ({{ ip }})\n"
"MAC: <code>{{ mac }}</code>\n"
"Link: {{ link }}\n"
msgstr ""
msgid "🆕 New device\\n{{ name }} ({{ ip }})\\nMAC: {{ mac }}\\nLink: {{ link }}"
msgid "✕"
msgstr ""
@@ -758,8 +758,8 @@ msgstr "队列"
msgid "Queue memory"
msgstr "队列内存"
msgid "Queued: <b style=\\\"color:var(--tc-speed)\\\">%s</b>"
msgstr "队列中:<b style=\\\"color:var(--tc-speed)\\\">%s</b>"
msgid "Queued: <b style=\"color:var(--tc-speed)\">%s</b>"
msgstr "队列中:<b style=\"color:var(--tc-speed)\">%s</b>"
msgid "Queues excess traffic (smoother streaming, lower jitter)"
msgstr "对超额流量排队(更流畅流媒体、更低抖动)"
@@ -863,8 +863,8 @@ msgstr "已整形设备通常不会被卸载(内核会检测到 HTB qdisc)
msgid "Shaped:"
msgstr "已整形:"
msgid "Shaped: <b style=\\\"color:var(--tc-speed)\\\">🌊 %s</b>"
msgstr "已整形:<b style=\\\"color:var(--tc-speed)\\\">🌊 %s</b>"
msgid "Shaped: <b style=\"color:var(--tc-speed)\">🌊 %s</b>"
msgstr "已整形:<b style=\"color:var(--tc-speed)\">🌊 %s</b>"
msgid "Shaper"
msgstr "整形器"
@@ -913,8 +913,8 @@ msgid ""
"he flowtable), so graphs are accurate."
msgstr "速度通过安装在更高优先级(flowtable 之前)的 nftables 计数器测量,因此图表准确。"
msgid "Speed limit: <b style=\\\"color:var(--tc-warn)\\\">⚡ %s</b>"
msgstr "速度限制:<b style=\\\"color:var(--tc-warn)\\\">⚡ %s</b>"
msgid "Speed limit: <b style=\"color:var(--tc-warn)\">⚡ %s</b>"
msgstr "速度限制:<b style=\"color:var(--tc-warn)\">⚡ %s</b>"
msgid "Speed limit: shaper (queue) or limiter (drop)"
msgstr "速度限制:整形器(队列)或限速器(丢包)"
+2 -2
View File
@@ -14,8 +14,8 @@ MISE_HASH_x86_64:=3832f39c325e343f81fe3d92b2447c5d1a5eea1bc85092bb7b6c2580622264
MISE_HASH_aarch64:=06186cfbfe947049b21d58575fb0ea800cc26ed1375f20f4b678cb3a9d679437
PKG_NAME:=mise
PKG_VERSION:=2026.10.15
PKG_RELEASE:=39
PKG_VERSION:=2026.10.17
PKG_RELEASE:=40
PKG_SOURCE:=$(PKG_NAME)-v$(PKG_VERSION)-linux-$(MISE_ARCH)-musl.tar.gz
PKG_SOURCE_URL:=https://github.com/jdx/mise/releases/download/v$(PKG_VERSION)/
PKG_HASH:=skip
+86 -87
View File
@@ -1,58 +1,64 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Copyright (c) 2018-2026 Nick Peng (pymumu@gmail.com)
# This is free software, licensed under the GNU General Public License v3.
#
# Copyright (c) 2018-2023 Nick Peng (pymumu@gmail.com)
include $(TOPDIR)/rules.mk
PKG_NAME:=smartdns
PKG_VERSION:=1.2026.48.4
PKG_RELEASE:=7
PKG_VERSION:=48.4
PKG_RELEASE:=8
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://www.github.com/pymumu/smartdns.git
PKG_MIRROR_HASH:=skip
PKG_SOURCE_VERSION:=21c940edc65520849ba03544c5cf8d9cf326e680
SMARTDNS_WEBUI_VERSION:=1.0.0
SMARTDNS_WEBUI_SOURCE_PROTO:=git
SMARTDNS_WEBUI_SOURCE_URL:=https://github.com/pymumu/smartdns-webui.git
SMARTDNS_WEBUI_SOURCE_VERSION:=1c06fee693434ec7c71f06010d3f87416baba9f0
SMARTDNS_WEBUI_FILE:=smartdns-webui-$(SMARTDNS_WEBUI_VERSION).tar.gz
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/pymumu/smartdns/tar.gz/Release$(PKG_VERSION)?
PKG_HASH:=skip
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-Release$(PKG_VERSION)
PKG_MAINTAINER:=Nick Peng <pymumu@gmail.com>
PKG_LICENSE:=GPL-3.0-or-later
PKG_LICENSE_FILES:=LICENSE
PKG_CPE_ID:=cpe:/a:pymumu:smartdns
PKG_CONFIG_DEPENDS:=CONFIG_PACKAGE_smartdns-ui
PKG_BUILD_DEPENDS:=PACKAGE_smartdns-ui:node/host PACKAGE_smartdns-ui:rust-bindgen/host
PKG_BUILD_PARALLEL:=1
# node compile is slow, so do not use it, download node manually.
# PACKAGE_smartdns-ui:node/host
PKG_BUILD_DEPENDS:=PACKAGE_smartdns-ui:rust/host
RUST_PKG_FEATURES:=build-release
RUST_PKG_LOCKED:=0
include $(TOPDIR)/feeds/packages/lang/rust/rust-package.mk
include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/rust/rust-package.mk
MAKE_VARS += VER=$(PKG_VERSION)
MAKE_PATH:=src
MAKE_VARS+= VER=$(PKG_VERSION) WITH_ZLIB=0
define Package/smartdns/default
define Package/smartdns/Default
SECTION:=net
CATEGORY:=Network
SUBMENU:=IP Addresses and Names
TITLE:=smartdns
URL:=https://www.github.com/pymumu/smartdns/
endef
define Package/smartdns
$(Package/smartdns/default)
TITLE:=smartdns server
DEPENDS:=+libpthread +libopenssl +libatomic +zlib
$(call Package/smartdns/Default)
TITLE+= server
DEPENDS:=+i386:libatomic +libopenssl
endef
define Package/smartdns/description
SmartDNS is a local DNS server which accepts DNS query requests from local network clients,
gets DNS query results from multiple upstream DNS servers concurrently, and returns the fastest IP to clients.
Unlike dnsmasq's all-servers, smartdns returns the fastest IP, and encrypt DNS queries with DoT or DoH.
Unlike dnsmasq's all-servers, smartdns returns the fastest IP, and encrypt DNS queries with DoT or DoH.
endef
define Package/smartdns-ui
$(call Package/smartdns/Default)
TITLE+= dashboard
DEPENDS:=+smartdns $(RUST_ARCH_DEPENDS) @!i386
endef
define Package/smartdns-ui/description
A dashboard ui for smartdns server.
endef
define Package/smartdns/conffiles
@@ -64,80 +70,73 @@ define Package/smartdns/conffiles
/etc/smartdns/domain-forwarding.list
endef
define Download/smartdns-webui
PROTO:=git
URL:=https://github.com/pymumu/smartdns-webui.git
SOURCE_DATE:=2026-07-29
SOURCE_VERSION:=1c06fee693434ec7c71f06010d3f87416baba9f0
MIRROR_HASH:=1b718d1288f6ddbdd80e3a948dda1693fd7bc8079fdb65be121f64f23ce53849
SUBDIR:=smartdns-webui-$$$$(subst -,.,$$$$(SOURCE_DATE))~$$$$(call version_abbrev,$$$$(SOURCE_VERSION))
FILE:=$$(SUBDIR).tar.zst
endef
define Build/Prepare
$(call Build/Prepare/Default)
ifneq ($(CONFIG_PACKAGE_smartdns-ui),)
$(eval $(call Download,smartdns-webui))
$(eval $(Download/smartdns-webui))
mkdir -p $(PKG_BUILD_DIR)/smartdns-webui
zstdcat $(DL_DIR)/$(FILE) | tar -C $(PKG_BUILD_DIR)/smartdns-webui $(TAR_OPTIONS) --strip-components=1
endif
endef
define Build/Compile
$(call Build/Compile/Default)
ifneq ($(CONFIG_PACKAGE_smartdns-ui),)
( \
pushd $(PKG_BUILD_DIR) ; \
pushd smartdns-webui ; \
npm install ; \
npm run build ; \
popd ; \
pushd plugin/smartdns-ui ; \
$(CARGO_PKG_CONFIG_VARS) \
MAKEFLAGS="$(PKG_JOBS)" \
WITH_ZLIB=0 \
TARGET_CFLAGS="$(filter-out -O%,$(TARGET_CFLAGS)) $(RUSTC_CFLAGS)" \
BINDGEN_EXTRA_CLANG_ARGS="--sysroot=$(TOOLCHAIN_ROOT_DIR)" \
cargo build -v --profile $(CARGO_PKG_PROFILE) \
$(if $(strip $(RUST_PKG_FEATURES)),--features "$(strip $(RUST_PKG_FEATURES))") \
$(if $(filter --jobserver%,$(PKG_JOBS)),,-j1) \
$(CARGO_PKG_ARGS) ; \
popd ; \
popd ; \
)
endif
endef
define Package/smartdns/install
$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/config $(1)/etc/init.d
$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/config $(1)/etc/init.d
$(INSTALL_DIR) $(1)/etc/smartdns $(1)/etc/smartdns/domain-set $(1)/etc/smartdns/conf.d/
$(INSTALL_DIR) $(1)/etc/smartdns/ip-set $(1)/etc/smartdns/download
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/smartdns $(1)/usr/sbin/smartdns
$(INSTALL_BIN) $(PKG_BUILD_DIR)/package/openwrt/files/etc/init.d/smartdns $(1)/etc/init.d/smartdns
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/address.conf $(1)/etc/smartdns/address.conf
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/blacklist-ip.conf $(1)/etc/smartdns/blacklist-ip.conf
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/custom.conf $(1)/etc/smartdns/custom.conf
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/domain-block.list $(1)/etc/smartdns/domain-block.list
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/domain-forwarding.list $(1)/etc/smartdns/domain-forwarding.list
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/files/etc/config/smartdns $(1)/etc/config/smartdns
endef
define Package/smartdns-ui
$(Package/smartdns/default)
TITLE:=smartdns dashboard
DEPENDS:=+smartdns $(RUST_ARCH_DEPENDS)
endef
define Package/smartdns-ui/description
A dashboard ui for smartdns server.
endef
define Package/smartdns-ui/conffiles
/etc/config/smartdns
endef
define Package/smartdns-ui/install
$(INSTALL_DIR) $(1)/usr/lib
$(INSTALL_DIR) $(1)/etc/smartdns/conf.d/
$(INSTALL_DIR) $(1)/usr/share/smartdns/wwwroot
$(INSTALL_BIN) $(PKG_BUILD_DIR)/plugin/smartdns-ui/target/smartdns_ui.so $(1)/usr/lib/smartdns_ui.so
$(CP) $(PKG_BUILD_DIR)/smartdns-webui/out/* $(1)/usr/share/smartdns/wwwroot
endef
define Build/Compile/smartdns-webui
which npm || (echo "npm not found, please install npm first" && exit 1)
npm install --prefix $(PKG_BUILD_DIR)/smartdns-webui/
npm run build --prefix $(PKG_BUILD_DIR)/smartdns-webui/
endef
define Build/Compile/smartdns-ui
cargo install --force --locked bindgen-cli
CARGO_BUILD_ARGS="$(if $(strip $(RUST_PKG_FEATURES)),--features "$(strip $(RUST_PKG_FEATURES))") --profile $(CARGO_PKG_PROFILE)"
+$(CARGO_PKG_VARS) CARGO_BUILD_ARGS="$(CARGO_BUILD_ARGS)" CC=$(TARGET_CC) \
PATH="$$(PATH):$(CARGO_HOME)/bin" \
AWS_LC_SYS_CFLAGS="-O0" \
make -C $(PKG_BUILD_DIR)/plugin/smartdns-ui
endef
define Download/smartdns-webui
FILE:=$(SMARTDNS_WEBUI_FILE)
PROTO:=$(SMARTDNS_WEBUI_SOURCE_PROTO)
URL:=$(SMARTDNS_WEBUI_SOURCE_URL)
MIRROR_HASH:=88adb092ed7b0dc22b3964249f4969870d3b462c4d924aceb18784c0f664f16e
VERSION:=$(SMARTDNS_WEBUI_SOURCE_VERSION)
HASH:=skip
SUBDIR:=smartdns-webui
endef
$(eval $(call Download,smartdns-webui))
ifdef CONFIG_PACKAGE_smartdns-ui
define Build/Prepare
$(call Build/Prepare/Default)
$(TAR) -C $(PKG_BUILD_DIR)/ -xf $(DL_DIR)/$(SMARTDNS_WEBUI_FILE)
endef
endif
define Build/Compile
$(call Build/Compile/Default,smartdns)
ifdef CONFIG_PACKAGE_smartdns-ui
$(call Build/Compile/smartdns-ui)
$(call Build/Compile/smartdns-webui)
endif
$(INSTALL_DIR) $(1)/usr/share/smartdns
$(CP) $(PKG_BUILD_DIR)/plugin/smartdns-ui/target/$(RUSTC_TARGET_ARCH)/$(CARGO_PKG_PROFILE)/libsmartdns_ui.so $(1)/usr/lib/smartdns_ui.so
$(CP) $(PKG_BUILD_DIR)/smartdns-webui/out $(1)/usr/share/smartdns/wwwroot
endef
$(eval $(call BuildPackage,smartdns))
$(eval $(call RustBinPackage,smartdns-ui))
$(eval $(call BuildPackage,smartdns-ui))
$(eval $(call BuildPackage,smartdns-ui))