mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-11-14 12:18:06 +08:00
update 2026-10-14 17:13:24
This commit is contained in:
1 parent
79897976d6
commit
e75bfefc80
345 files changed
+1076
-91524
No files matched your search
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
||||
-include $(dir $(lastword $(MAKEFILE_LIST)))../version.mk
|
||||
|
||||
PKG_NAME:=easytier-noweb
|
||||
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.6.4)
|
||||
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.7.0)
|
||||
|
||||
ifeq ($(ARCH),mipsel)
|
||||
APP_ARCH:=mipsel
|
||||
|
||||
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
||||
-include $(dir $(lastword $(MAKEFILE_LIST)))../version.mk
|
||||
|
||||
PKG_NAME:=easytier
|
||||
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.6.4)
|
||||
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.7.0)
|
||||
|
||||
ifeq ($(ARCH),mipsel)
|
||||
APP_ARCH:=mipsel
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
-include $(dir $(lastword $(MAKEFILE_LIST)))../version.mk
|
||||
|
||||
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.6.4)
|
||||
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.7.0)
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
LUCI_TITLE:=LuCI support for EasyTier
|
||||
LUCI_DEPENDS:=+kmod-tun +luci-compat
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
@@ -163,7 +163,7 @@ function get_upload_config()
|
||||
easytierbin = uci:get_first("easytier", "easytier", "easytierbin") or "/usr/bin/easytier-core",
|
||||
webbin = uci:get_first("easytier", "easytier", "webbin") or "/usr/bin/easytier-web",
|
||||
github_proxys = {},
|
||||
fallback_version = uci:get_first("easytier", "easytier", "fallback_version") or "v2.6.4"
|
||||
fallback_version = uci:get_first("easytier", "easytier", "fallback_version") or "v2.7.0"
|
||||
}
|
||||
|
||||
-- 读取代理列表(list 类型)
|
||||
@@ -200,7 +200,7 @@ function save_upload_config()
|
||||
-- 保存配置
|
||||
uci:set("easytier", "@easytier[0]", "easytierbin", data.easytierbin or "/usr/bin/easytier-core")
|
||||
uci:set("easytier", "@easytier[0]", "webbin", data.webbin or "/usr/bin/easytier-web")
|
||||
uci:set("easytier", "@easytier[0]", "fallback_version", data.fallback_version or "v2.6.4")
|
||||
uci:set("easytier", "@easytier[0]", "fallback_version", data.fallback_version or "v2.7.0")
|
||||
|
||||
-- 删除旧的代理列表
|
||||
uci:delete("easytier", "@easytier[0]", "github_proxys")
|
||||
@@ -595,69 +595,130 @@ function clear_version_cache()
|
||||
luci.http.write("OK")
|
||||
end
|
||||
|
||||
-- 连接信息各分区与 easytier-cli 子命令的对应关系。
|
||||
-- 实测每调用一次 easytier-cli 都要新起一个进程,单次进程启动开销约 200ms(路由器上更慢),
|
||||
-- RPC 往返本身只要几毫秒,因此耗时几乎完全取决于进程个数,改为按分区按需加载。
|
||||
local CONNINFO_CLI_PARTS = {
|
||||
node = "node",
|
||||
peer = "peer",
|
||||
route = "route",
|
||||
connector = "connector",
|
||||
stun = "stun",
|
||||
peer_center = "peer-center",
|
||||
vpn_portal = "vpn-portal",
|
||||
proxy = "proxy",
|
||||
acl = "acl stats",
|
||||
mapped_listener = "mapped-listener",
|
||||
stats = "stats",
|
||||
}
|
||||
-- cmdline 只读本地 /proc,不需要 easytier-cli
|
||||
local CONNINFO_LOCAL_PARTS = { cmdline = true }
|
||||
|
||||
-- 分区结果的短时缓存,避免轮询与手动刷新、来回切换分区时重复起进程
|
||||
local CONNINFO_CACHE_DIR = "/tmp/easytier_conninfo"
|
||||
local CONNINFO_CACHE_TTL = 3
|
||||
|
||||
local function read_conninfo_cache(name)
|
||||
local handle = io.open(CONNINFO_CACHE_DIR .. "/" .. name, "r")
|
||||
if not handle then
|
||||
return nil
|
||||
end
|
||||
local content = handle:read("*all") or ""
|
||||
handle:close()
|
||||
local ts, data = content:match("^(%d+)\n([%s%S]*)$")
|
||||
if not ts or (os.time() - tonumber(ts)) > CONNINFO_CACHE_TTL then
|
||||
return nil
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
local function write_conninfo_cache(name, data)
|
||||
luci.sys.call("mkdir -p " .. CONNINFO_CACHE_DIR)
|
||||
local handle = io.open(CONNINFO_CACHE_DIR .. "/" .. name, "w")
|
||||
if handle then
|
||||
handle:write(tostring(os.time()) .. "\n" .. data)
|
||||
handle:close()
|
||||
end
|
||||
end
|
||||
|
||||
function act_conninfo()
|
||||
local e = {}
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local easytierbin = uci:get_first("easytier", "easytier", "easytierbin") or "/usr/bin/easytier-core"
|
||||
local clibin = easytierbin:gsub("easytier%-core$", "easytier-cli")
|
||||
|
||||
local process_status = luci.sys.exec("pgrep easytier-core")
|
||||
|
||||
if process_status ~= "" then
|
||||
-- 获取各类CLI信息
|
||||
local function get_cli_output(cmd)
|
||||
local handle = io.popen(clibin .. " " .. cmd .. " 2>&1")
|
||||
if handle then
|
||||
local result = handle:read("*all")
|
||||
handle:close()
|
||||
return result or ""
|
||||
|
||||
-- 解析要加载的分区,前端只请求当前显示的分区;
|
||||
-- 不传 parts 时加载除 stun 以外的所有分区(stun 会实时访问 STUN 服务器,单次实测约 3 秒)
|
||||
local parts = luci.http.formvalue("parts")
|
||||
local want_cli, want_local = {}, {}
|
||||
if parts and parts ~= "" then
|
||||
for name in parts:gmatch("[%w_]+") do
|
||||
if CONNINFO_CLI_PARTS[name] then
|
||||
want_cli[name] = true
|
||||
elseif CONNINFO_LOCAL_PARTS[name] then
|
||||
want_local[name] = true
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
e.node = get_cli_output("node")
|
||||
e.peer = get_cli_output("peer")
|
||||
e.connector = get_cli_output("connector")
|
||||
e.stun = get_cli_output("stun")
|
||||
e.route = get_cli_output("route")
|
||||
e.peer_center = get_cli_output("peer-center")
|
||||
e.vpn_portal = get_cli_output("vpn-portal")
|
||||
e.proxy = get_cli_output("proxy")
|
||||
e.acl = get_cli_output("acl stats")
|
||||
e.mapped_listener = get_cli_output("mapped-listener")
|
||||
e.stats = get_cli_output("stats")
|
||||
|
||||
-- 获取启动参数
|
||||
local cmdhandle = io.popen("cat /proc/$(pidof easytier-core)/cmdline 2>/dev/null | tr '\\0' ' '")
|
||||
if cmdhandle then
|
||||
e.cmdline = cmdhandle:read("*all") or ""
|
||||
cmdhandle:close()
|
||||
else
|
||||
e.cmdline = ""
|
||||
else
|
||||
for name in pairs(CONNINFO_CLI_PARTS) do
|
||||
if name ~= "stun" then
|
||||
want_cli[name] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- 检查是否使用配置文件启动
|
||||
if e.cmdline:match("%-%-config%-file") or e.cmdline:match("%-c%s+/") then
|
||||
e.config_file = safe_read_file("/etc/easytier/config.toml") or ""
|
||||
else
|
||||
e.config_file = ""
|
||||
for name in pairs(CONNINFO_LOCAL_PARTS) do
|
||||
want_local[name] = true
|
||||
end
|
||||
end
|
||||
|
||||
local process_status = luci.sys.exec("pgrep easytier-core")
|
||||
|
||||
if process_status ~= "" then
|
||||
-- 只运行被请求的分区,命中缓存的分区直接复用结果
|
||||
for name in pairs(want_cli) do
|
||||
local cached = read_conninfo_cache(name)
|
||||
if cached then
|
||||
e[name] = cached
|
||||
else
|
||||
local handle = io.popen(clibin .. " " .. CONNINFO_CLI_PARTS[name] .. " 2>&1")
|
||||
local result = ""
|
||||
if handle then
|
||||
result = handle:read("*all") or ""
|
||||
handle:close()
|
||||
end
|
||||
e[name] = result
|
||||
write_conninfo_cache(name, result)
|
||||
end
|
||||
end
|
||||
|
||||
if want_local.cmdline then
|
||||
-- 获取启动参数
|
||||
local cmdhandle = io.popen("cat /proc/$(pidof easytier-core)/cmdline 2>/dev/null | tr '\\0' ' '")
|
||||
if cmdhandle then
|
||||
e.cmdline = cmdhandle:read("*all") or ""
|
||||
cmdhandle:close()
|
||||
else
|
||||
e.cmdline = ""
|
||||
end
|
||||
|
||||
-- 检查是否使用配置文件启动,配置内容随本次响应一起返回,前端无需再请求一次
|
||||
if e.cmdline:match("%-%-config%-file") or e.cmdline:match("%-c%s+/") then
|
||||
e.config_file = safe_read_file("/etc/easytier/config.toml") or ""
|
||||
else
|
||||
e.config_file = ""
|
||||
end
|
||||
end
|
||||
else
|
||||
local errMsg = i18n.translate("Error: Program not running! Please start the program and refresh")
|
||||
e.node = errMsg
|
||||
e.peer = errMsg
|
||||
e.connector = errMsg
|
||||
e.stun = errMsg
|
||||
e.route = errMsg
|
||||
e.peer_center = errMsg
|
||||
e.vpn_portal = errMsg
|
||||
e.proxy = errMsg
|
||||
e.acl = errMsg
|
||||
e.mapped_listener = errMsg
|
||||
e.stats = errMsg
|
||||
e.cmdline = errMsg
|
||||
for name in pairs(want_cli) do
|
||||
e[name] = errMsg
|
||||
end
|
||||
if want_local.cmdline then
|
||||
e.cmdline = errMsg
|
||||
end
|
||||
-- 未运行时清掉缓存,避免下次启动后读到旧的错误输出
|
||||
luci.sys.call("rm -rf " .. CONNINFO_CACHE_DIR)
|
||||
end
|
||||
|
||||
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(e)
|
||||
end
|
||||
@@ -682,6 +743,11 @@ function get_web_config()
|
||||
web_geoip_db = uci:get_first("easytier", "easytier", "web_geoip_db") or "",
|
||||
web_disable_registration = uci:get_first("easytier", "easytier", "web_disable_registration") or "0",
|
||||
web_allow_auto_create_user = uci:get_first("easytier", "easytier", "web_allow_auto_create_user") or "0",
|
||||
-- EasyTier 2.7.0 新增的 web 参数
|
||||
web_heartbeat_min_response_ms = uci:get_first("easytier", "easytier", "web_heartbeat_min_response_ms") or "",
|
||||
web_heartbeat_timeout_ms = uci:get_first("easytier", "easytier", "web_heartbeat_timeout_ms") or "",
|
||||
web_gateway_peer_url = uci:get_first("easytier", "easytier", "web_gateway_peer_url") or "",
|
||||
web_gateway_relay_data = uci:get_first("easytier", "easytier", "web_gateway_relay_data") or "0",
|
||||
web_weblog = uci:get_first("easytier", "easytier", "web_weblog") or "off",
|
||||
-- OIDC配置
|
||||
web_oidc_enabled = uci:get_first("easytier", "easytier", "web_oidc_enabled") or "0",
|
||||
@@ -723,6 +789,11 @@ function save_web_config()
|
||||
local web_geoip_db = http.formvalue("web_geoip_db") or ""
|
||||
local web_disable_registration = http.formvalue("web_disable_registration") or "0"
|
||||
local web_allow_auto_create_user = http.formvalue("web_allow_auto_create_user") or "0"
|
||||
-- EasyTier 2.7.0 新增的 web 参数
|
||||
local web_heartbeat_min_response_ms = http.formvalue("web_heartbeat_min_response_ms") or ""
|
||||
local web_heartbeat_timeout_ms = http.formvalue("web_heartbeat_timeout_ms") or ""
|
||||
local web_gateway_peer_url = http.formvalue("web_gateway_peer_url") or ""
|
||||
local web_gateway_relay_data = http.formvalue("web_gateway_relay_data") or "0"
|
||||
local web_weblog = http.formvalue("web_weblog") or "off"
|
||||
-- OIDC
|
||||
local web_oidc_enabled = http.formvalue("web_oidc_enabled") or "0"
|
||||
@@ -756,6 +827,11 @@ function save_web_config()
|
||||
uci:set("easytier", "@easytier[0]", "web_geoip_db", web_geoip_db)
|
||||
uci:set("easytier", "@easytier[0]", "web_disable_registration", web_disable_registration)
|
||||
uci:set("easytier", "@easytier[0]", "web_allow_auto_create_user", web_allow_auto_create_user)
|
||||
-- EasyTier 2.7.0 新增的 web 参数
|
||||
uci:set("easytier", "@easytier[0]", "web_heartbeat_min_response_ms", web_heartbeat_min_response_ms)
|
||||
uci:set("easytier", "@easytier[0]", "web_heartbeat_timeout_ms", web_heartbeat_timeout_ms)
|
||||
uci:set("easytier", "@easytier[0]", "web_gateway_peer_url", web_gateway_peer_url)
|
||||
uci:set("easytier", "@easytier[0]", "web_gateway_relay_data", web_gateway_relay_data)
|
||||
uci:set("easytier", "@easytier[0]", "web_weblog", web_weblog)
|
||||
-- OIDC
|
||||
uci:set("easytier", "@easytier[0]", "web_oidc_enabled", web_oidc_enabled)
|
||||
|
||||
@@ -45,10 +45,11 @@ end
|
||||
|
||||
web_config = s:taboption("general", Value, "web_config", translate("Web Server Address"),
|
||||
translate("Web configuration server address. (-w parameter)<br>"
|
||||
.. "For a self-hosted Web server, use the format: udp://server_address:22020/username<br>"
|
||||
.. "For the official Web server, use the format: username<br>"
|
||||
.. "Since EasyTier 2.7.0 a full URL is required, the token-only shorthand is no longer supported<br>"
|
||||
.. "Self-hosted Web server, use the format: udp://server_address:22020/username<br>"
|
||||
.. "Official Web server, use the format: udp://config-server.easytier.cn:22020/username<br>"
|
||||
.. "Official Web Console: <a href='https://easytier.cn/web'>easytier.cn/web</a>"))
|
||||
web_config.placeholder = "admin"
|
||||
web_config.placeholder = "udp://config-server.easytier.cn:22020/my-token"
|
||||
web_config:depends("etcmd", "web")
|
||||
|
||||
network_name = s:taboption("general", Value, "network_name", translate("Network Name"),
|
||||
@@ -199,13 +200,53 @@ instance_name = s:taboption("privacy", Value, "instance_name", translate("Instan
|
||||
instance_name.placeholder = "default"
|
||||
instance_name:depends("etcmd", "etcmd")
|
||||
|
||||
vpn_portal = s:taboption("privacy", Value, "vpn_portal", translate("VPN Portal URL"),
|
||||
translate("Defines the URL of the VPN portal, allowing other VPN clients to connect.<br>"
|
||||
.. "Example: wg://0.0.0.0:11011/10.14.14.0/24 means the VPN portal is a WireGuard server listening on vpn."
|
||||
.. "example.com:11010, and the VPN clients are in the 10.14.14.0/24 network (--vpn-portal parameter)"))
|
||||
vpn_portal.placeholder = "wg://0.0.0.0:11011/10.14.14.0/24"
|
||||
vpn_portal = s:taboption("privacy", Value, "vpn_portal", translate("VPN Portal Listen Address"),
|
||||
translate("WireGuard VPN portal listen address, allowing other VPN clients to connect.<br>"
|
||||
.. "Since EasyTier 2.7.0 only wg://HOST:PORT is accepted; the client network can no longer be "
|
||||
.. "appended to the URL, please add each client in \"VPN Portal Clients\" below "
|
||||
.. "(--vpn-portal parameter)"))
|
||||
vpn_portal.placeholder = "wg://0.0.0.0:11011"
|
||||
vpn_portal.validate = function(self, value, section)
|
||||
value = value and tostring(value):match("^%s*(.-)%s*$") or ""
|
||||
if value == "" then return value end
|
||||
-- EasyTier 2.7.0 起不再允许把客户端网段写在 URL 里,这里提前拦截,避免核心启动失败
|
||||
if not (value:match("^wg://%d+%.%d+%.%d+%.%d+:%d+$") or value:match("^wg://%[[%x:]+%]:%d+$")) then
|
||||
return nil, translate("Only wg://HOST:PORT is accepted since EasyTier 2.7.0, please fill the client network into \"VPN Portal Clients\"")
|
||||
end
|
||||
return value
|
||||
end
|
||||
vpn_portal:depends("etcmd", "etcmd")
|
||||
|
||||
vpn_portal_clients = s:taboption("privacy", DynamicList, "vpn_portal_clients", translate("VPN Portal Clients"),
|
||||
translate("One WireGuard client per entry in the form NAME=CIDR, for example client1=10.14.14.1/24.<br>"
|
||||
.. "NAME may contain letters, digits and dashes only; the address must be a usable host address "
|
||||
.. "inside the client network. (--vpn-portal-client parameter)"))
|
||||
vpn_portal_clients.placeholder = "client1=10.14.14.1/24"
|
||||
vpn_portal_clients.validate = function(self, value, section)
|
||||
if type(value) == "table" then
|
||||
local i
|
||||
for i = 1, #value do
|
||||
local item = value[i] and tostring(value[i]):match("^%s*(.-)%s*$") or ""
|
||||
if item ~= "" then
|
||||
-- 与 easytier-core 的校验保持一致:名称只能是字母数字与短横线,地址必须是 主机/前缀
|
||||
if not item:match("^[%w][%w%-]*=[%d%.]+/%d+$") then
|
||||
return nil, translate("Invalid client, expected NAME=CIDR, for example client1=10.14.14.1/24")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return value
|
||||
end
|
||||
vpn_portal_clients:depends("etcmd", "etcmd")
|
||||
|
||||
vpn_portal_private_key = s:taboption("privacy", Value, "vpn_portal_private_key", translate("VPN Portal Private Key"),
|
||||
translate("Base64 encoded 32-byte WireGuard private key of the portal.<br>"
|
||||
.. "Required since EasyTier 2.7.0, the portal will not start without it. "
|
||||
.. "It is handed to easytier-core through an environment variable so that it never shows up in the process list. "
|
||||
.. "(--vpn-portal-private-key parameter)"))
|
||||
vpn_portal_private_key.password = true
|
||||
vpn_portal_private_key:depends("etcmd", "etcmd")
|
||||
|
||||
mtu = s:taboption("privacy", Value, "mtu", translate("MTU"),
|
||||
translate("MTU for the TUN device, default is 1380 when unencrypted, and 1360 when encrypted"))
|
||||
mtu.datatype = "range(1,1500)"
|
||||
@@ -314,6 +355,23 @@ socks_port.datatype = "range(1,65535)"
|
||||
socks_port.placeholder = "1080"
|
||||
socks_port:depends("etcmd", "etcmd")
|
||||
|
||||
disable_upnp = s:taboption("privacy", Flag, "disable_upnp", translate("Disable UPnP"),
|
||||
translate("EasyTier 2.7.0 tries to map listener ports through UPnP/NAT-PMP by default. "
|
||||
.. "Enable this to turn the automatic port mapping off. (--disable-upnp parameter)"))
|
||||
disable_upnp:depends("etcmd", "etcmd")
|
||||
|
||||
stun_servers = s:taboption("privacy", DynamicList, "stun_servers", translate("STUN Servers"),
|
||||
translate("Custom UDP STUN servers used for NAT type detection and hole punching. "
|
||||
.. "Leave empty to use the built-in defaults. (--stun-servers parameter)"))
|
||||
stun_servers.placeholder = "stun.miwifi.com:3478"
|
||||
stun_servers:depends("etcmd", "etcmd")
|
||||
|
||||
tcp_stun_servers = s:taboption("privacy", DynamicList, "tcp_stun_servers", translate("STUN Servers (TCP)"),
|
||||
translate("Custom TCP STUN servers used for NAT type detection and hole punching. "
|
||||
.. "Leave empty to use the built-in defaults. (--tcp-stun-servers parameter)"))
|
||||
tcp_stun_servers.placeholder = "stun.miwifi.com:3478"
|
||||
tcp_stun_servers:depends("etcmd", "etcmd")
|
||||
|
||||
disable_p2p = s:taboption("privacy", Flag, "disable_p2p", translate("Disable P2P"),
|
||||
translate("Disable P2P communication; only use nodes specified by -p to forward packets (--disable-p2p parameter)"))
|
||||
disable_p2p:depends("etcmd", "etcmd")
|
||||
@@ -322,6 +380,15 @@ p2p_only = s:taboption("privacy", Flag, "p2p_only", translate("P2P only"),
|
||||
translate("only communicate with peers that already establish p2p connection. (--p2p-only parameter)"))
|
||||
p2p_only:depends("etcmd", "etcmd")
|
||||
|
||||
lazy_p2p = s:taboption("privacy", Flag, "lazy_p2p", translate("Lazy P2P"),
|
||||
translate("Only try to establish P2P connections when traffic actually needs to be forwarded. "
|
||||
.. "(--lazy-p2p parameter)"))
|
||||
lazy_p2p:depends("etcmd", "etcmd")
|
||||
|
||||
need_p2p = s:taboption("privacy", Flag, "need_p2p", translate("Need P2P"),
|
||||
translate("Require a P2P connection before forwarding traffic through relays. (--need-p2p parameter)"))
|
||||
need_p2p:depends("etcmd", "etcmd")
|
||||
|
||||
disable_udp = s:taboption("privacy", Flag, "disable_udp", translate("Disable UDP"),
|
||||
translate("Disable UDP hole punching (--disable-udp-hole-punching parameter)"))
|
||||
disable_udp:depends("etcmd", "etcmd")
|
||||
@@ -373,6 +440,14 @@ relay_kcp = s:taboption("privacy", Flag, "relay_kcp", translate("Relay foreign n
|
||||
translate("If true, allow relay kcp packets from foreign network. default is false (not forward foreign network kcp packets). (--enable-relay-foreign-network-kcp parameter)"))
|
||||
relay_kcp:depends("etcmd", "etcmd")
|
||||
|
||||
disable_relay_quic = s:taboption("privacy", Flag, "disable_relay_quic", translate("Disable relay quic"),
|
||||
translate("If true, disable relaying quic packets, avoiding consuming too much bandwidth. (--disable-relay-quic parameter)"))
|
||||
disable_relay_quic:depends("etcmd", "etcmd")
|
||||
|
||||
relay_quic = s:taboption("privacy", Flag, "relay_quic", translate("Relay foreign network quic"),
|
||||
translate("If true, allow relaying quic packets from foreign networks. (--enable-relay-foreign-network-quic parameter)"))
|
||||
relay_quic:depends("etcmd", "etcmd")
|
||||
|
||||
quic_proxy = s:taboption("privacy", Flag, "quic_proxy", translate("Enable QUIC Proxy"),
|
||||
translate("Proxy tcp streams with QUIC, improving the latency and throughput on the network with udp packet loss.<br>"
|
||||
.. "All nodes in the virtual network must be using EasyTier version v2.3.2 or higher for this feature. "
|
||||
@@ -396,6 +471,12 @@ accept_dns = s:taboption("privacy", Flag, "accept_dns", translate("Enable Magic
|
||||
.. "Magic DNS will modify your system DNS settings, please enable with caution. (--accept-dns parameter)"))
|
||||
accept_dns:depends("etcmd", "etcmd")
|
||||
|
||||
tld_dns_zone = s:taboption("privacy", Value, "tld_dns_zone", translate("Magic DNS Zone"),
|
||||
translate("Top level DNS zone used by Magic DNS, default is et.net. Only takes effect when Magic DNS is enabled. "
|
||||
.. "(--tld-dns-zone parameter)"))
|
||||
tld_dns_zone.placeholder = "et.net."
|
||||
tld_dns_zone:depends("accept_dns", "1")
|
||||
|
||||
private_mode = s:taboption("privacy", Flag, "private_mode", translate("Enable Private Mode"),
|
||||
translate("When enabled, nodes with a different network name and password are not allowed to handshake or "
|
||||
.. "relay via this node. (--private-mode parameter)"))
|
||||
@@ -406,6 +487,17 @@ foreign_relay_bps_limit = s:taboption("privacy", Value, "foreign_relay_bps_limit
|
||||
.. "(--foreign-relay-bps-limit parameter)"))
|
||||
foreign_relay_bps_limit:depends("etcmd", "etcmd")
|
||||
|
||||
instance_recv_bps_limit = s:taboption("privacy", Value, "instance_recv_bps_limit", translate("Instance Receive Rate Limit"),
|
||||
translate("the maximum inbound bps limit for this network instance, default is no limit. "
|
||||
.. "unit: BPS (bytes per second). (--instance-recv-bps-limit parameter)"))
|
||||
instance_recv_bps_limit:depends("etcmd", "etcmd")
|
||||
|
||||
socket_mark = s:taboption("privacy", Value, "socket_mark", translate("Socket Mark"),
|
||||
translate("Set SO_MARK on all underlay sockets, Linux only and requires CAP_NET_ADMIN. "
|
||||
.. "Usually used together with policy routing. (--socket-mark parameter)"))
|
||||
socket_mark.datatype = "range(0,4294967295)"
|
||||
socket_mark:depends("etcmd", "etcmd")
|
||||
|
||||
extra_args = s:taboption("privacy", DynamicList, "extra_args", translate("Extra Parameters"),
|
||||
translate("Additional command-line arguments passed to the backend process"))
|
||||
extra_args.placeholder = "--tcp-whitelist=80"
|
||||
|
||||
@@ -900,18 +900,133 @@ var translations = {
|
||||
// Stats指标名称翻译
|
||||
"traffic_control_bytes_rx": "<%:Traffic Control Bytes RX%>",
|
||||
"traffic_control_bytes_tx": "<%:Traffic Control Bytes TX%>",
|
||||
"traffic_control_bytes_forwarded": "<%:Traffic Control Bytes Forwarded%>",
|
||||
"traffic_control_bytes_rx_by_instance": "<%:Traffic Control Bytes RX By Instance%>",
|
||||
"traffic_control_bytes_tx_by_instance": "<%:Traffic Control Bytes TX By Instance%>",
|
||||
"traffic_control_packets_rx": "<%:Traffic Control Packets RX%>",
|
||||
"traffic_control_packets_tx": "<%:Traffic Control Packets TX%>",
|
||||
"traffic_control_packets_forwarded": "<%:Traffic Control Packets Forwarded%>",
|
||||
"traffic_control_packets_rx_by_instance": "<%:Traffic Control Packets RX By Instance%>",
|
||||
"traffic_control_packets_tx_by_instance": "<%:Traffic Control Packets TX By Instance%>",
|
||||
"traffic_bytes_rx_by_instance": "<%:Traffic Bytes RX By Instance%>",
|
||||
"traffic_bytes_tx_by_instance": "<%:Traffic Bytes TX By Instance%>",
|
||||
"traffic_packets_rx_by_instance": "<%:Traffic Packets RX By Instance%>",
|
||||
"traffic_packets_tx_by_instance": "<%:Traffic Packets TX By Instance%>",
|
||||
"traffic_bytes_foreign_forward_rx": "<%:Traffic Bytes Foreign Forward RX%>",
|
||||
"traffic_bytes_foreign_forward_tx": "<%:Traffic Bytes Foreign Forward TX%>",
|
||||
"traffic_bytes_foreign_forward_forwarded": "<%:Traffic Bytes Foreign Forward Forwarded%>",
|
||||
"traffic_packets_foreign_forward_rx": "<%:Traffic Packets Foreign Forward RX%>",
|
||||
"traffic_packets_foreign_forward_tx": "<%:Traffic Packets Foreign Forward TX%>",
|
||||
"traffic_packets_foreign_forward_forwarded": "<%:Traffic Packets Foreign Forward Forwarded%>",
|
||||
"peer_rpc_errors": "<%:Peer RPC Errors%>",
|
||||
"tcp_proxy_connect": "<%:TCP Proxy Connect%>",
|
||||
"udp_broadcast_relay_packets_captured": "<%:UDP Broadcast Relay Packets Captured%>",
|
||||
"udp_broadcast_relay_packets_forwarded": "<%:UDP Broadcast Relay Packets Forwarded%>",
|
||||
"udp_broadcast_relay_packets_forward_failed": "<%:UDP Broadcast Relay Packets Forward Failed%>",
|
||||
"udp_broadcast_relay_packets_ignored": "<%:UDP Broadcast Relay Packets Ignored%>",
|
||||
"vpn_portal_client": "<%:VPN Portal Client%>",
|
||||
"vpn_portal_client_bytes_rx": "<%:VPN Portal Client Bytes RX%>",
|
||||
"vpn_portal_client_bytes_tx": "<%:VPN Portal Client Bytes TX%>",
|
||||
"vpn_portal_client_packets_rx": "<%:VPN Portal Client Packets RX%>",
|
||||
"vpn_portal_client_packets_tx": "<%:VPN Portal Client Packets TX%>",
|
||||
// Stats 标签(Labels 列)字段翻译
|
||||
"compression_algo": "<%:Compression Algorithm%>",
|
||||
"direction": "<%:Direction%>",
|
||||
"dst_ip": "<%:Destination IP%>",
|
||||
"mapped_dst_ip": "<%:Mapped Destination IP%>",
|
||||
"error_type": "<%:Error Type%>",
|
||||
"protocol": "<%:Protocol%>",
|
||||
"from_instance_id": "<%:From Instance ID%>",
|
||||
"to_instance_id": "<%:To Instance ID%>"
|
||||
};
|
||||
|
||||
var currentTab = 'node';
|
||||
var isRefreshing = false;
|
||||
|
||||
// 连接信息分区表:id 为 TAB 元素后缀,key 为后端 api_conninfo?parts= 使用的分区名
|
||||
var connInfoSections = [
|
||||
{id: 'node', key: 'node'},
|
||||
{id: 'peer', key: 'peer'},
|
||||
{id: 'route', key: 'route'},
|
||||
{id: 'connector', key: 'connector'},
|
||||
{id: 'stun', key: 'stun'},
|
||||
{id: 'peercenter', key: 'peer_center'},
|
||||
{id: 'vpnportal', key: 'vpn_portal'},
|
||||
{id: 'proxy', key: 'proxy'},
|
||||
{id: 'acl', key: 'acl'},
|
||||
{id: 'mappedlistener', key: 'mapped_listener'},
|
||||
{id: 'stats', key: 'stats'},
|
||||
{id: 'cmdline', key: 'cmdline'}
|
||||
];
|
||||
|
||||
// 已经成功加载过的分区,切换 TAB 时命中就不再请求
|
||||
var connInfoLoaded = {};
|
||||
// 待请求的分区队列:同一时刻只允许一个请求在跑,避免一次性起一堆 easytier-cli 进程
|
||||
var connInfoQueue = [];
|
||||
var connInfoBusy = false;
|
||||
// 最近一次响应中的配置文件内容,供"命令行"分区直接使用
|
||||
var lastConfigFile = null;
|
||||
|
||||
// ACL 统计是 core 直接输出的英文结构体文本(core 侧没有多语言),
|
||||
// 字段名单独放在这里精确匹配,避免 name / bytes 这类通用词影响其它卡片
|
||||
var aclFieldTranslations = {
|
||||
"name": "<%:Name%>",
|
||||
"prio": "<%:Priority%>",
|
||||
"action": "<%:Action%>",
|
||||
"enabled": "<%:Enabled%>",
|
||||
"proto": "<%:Protocol%>",
|
||||
"ports": "<%:Ports%>",
|
||||
"src_ports": "<%:Source Ports%>",
|
||||
"src_ips": "<%:Source IPs%>",
|
||||
"dst_ips": "<%:Destination IPs%>",
|
||||
"stateful": "<%:Stateful%>",
|
||||
"rate": "<%:Rate Limit%>",
|
||||
"burst": "<%:Burst Limit%>",
|
||||
"pkts": "<%:Packets%>",
|
||||
"bytes": "<%:Bytes%>",
|
||||
"src": "<%:Source Address%>",
|
||||
"dst": "<%:Destination Address%>",
|
||||
"state": "<%:State%>",
|
||||
"created": "<%:Created%>",
|
||||
"last_seen": "<%:Last Seen%>"
|
||||
};
|
||||
|
||||
// ACL 规则里的枚举取值
|
||||
var aclValueTranslations = {
|
||||
"Allow": "<%:Allow%>",
|
||||
"Drop": "<%:Drop (no response)%>",
|
||||
"Noop": "<%:Noop%>",
|
||||
"Any": "<%:Any%>",
|
||||
"Unspecified": "<%:Unspecified%>",
|
||||
"New": "<%:New%>",
|
||||
"Established": "<%:Established%>",
|
||||
"Related": "<%:Related%>",
|
||||
"Invalid": "<%:Invalid%>",
|
||||
"<default/none>": "<%:Default / None%>"
|
||||
};
|
||||
|
||||
// 翻译 ACL 统计文本:先翻译枚举取值,再翻译字段名
|
||||
function translateAclStats(content) {
|
||||
var text = content;
|
||||
|
||||
text = text.replace(/\baction: (Noop|Allow|Drop)\b/g, function(m, v) {
|
||||
return 'action: ' + (aclValueTranslations[v] || v);
|
||||
});
|
||||
text = text.replace(/\bproto: (Unspecified|Icmpv6|Tcp|Udp|Icmp|Any)\b/g, function(m, v) {
|
||||
return 'proto: ' + (aclValueTranslations[v] || v);
|
||||
});
|
||||
text = text.replace(/\bstate: (New|Established|Related|Invalid)\b/g, function(m, v) {
|
||||
return 'state: ' + (aclValueTranslations[v] || v);
|
||||
});
|
||||
|
||||
text = text.replace(/\b(name|prio|action|enabled|proto|ports|src_ports|src_ips|dst_ips|stateful|rate|burst|pkts|bytes|src|dst|state|created|last_seen): /g,
|
||||
function(m, field) {
|
||||
return (aclFieldTranslations[field] || field) + ': ';
|
||||
});
|
||||
|
||||
text = text.replace(/<default\/none>/g, aclValueTranslations['<default/none>'] || '<default/none>');
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
function tr(text) {
|
||||
return translations[text] || text;
|
||||
@@ -996,37 +1111,16 @@ function parseTable(content, tabName) {
|
||||
var html = renderCopyablePre(content);
|
||||
|
||||
// 检查是否使用配置文件启动
|
||||
if (content.indexOf('--config-file') !== -1 || content.match(/-c\s+\//)) {
|
||||
XHR.get('<%=url("admin/vpn/easytier/api_conninfo")%>', null, function(x, data) {
|
||||
if (data && data.config_file) {
|
||||
var configDiv = document.createElement('div');
|
||||
configDiv.className = 'et-pre';
|
||||
configDiv.style.marginTop = '16px';
|
||||
configDiv.style.borderTop = '2px solid var(--border-color)';
|
||||
configDiv.style.paddingTop = '16px';
|
||||
|
||||
var title = document.createElement('div');
|
||||
title.style.fontWeight = '600';
|
||||
title.style.marginBottom = '8px';
|
||||
title.style.color = 'var(--primary-color)';
|
||||
title.textContent = tr('Configuration File Content') + ':';
|
||||
|
||||
var contentDiv = document.createElement('pre');
|
||||
contentDiv.style.margin = '0';
|
||||
contentDiv.style.whiteSpace = 'pre-wrap';
|
||||
contentDiv.style.overflowWrap = 'anywhere';
|
||||
contentDiv.style.wordBreak = 'break-word';
|
||||
contentDiv.textContent = data.config_file;
|
||||
|
||||
configDiv.appendChild(title);
|
||||
configDiv.appendChild(contentDiv);
|
||||
|
||||
var container = document.getElementById('tab_cmdline');
|
||||
if (container) {
|
||||
container.appendChild(configDiv);
|
||||
}
|
||||
}
|
||||
});
|
||||
// 配置文件内容随 cmdline 分区一起返回,这里不再单独请求一次 api_conninfo
|
||||
if ((content.indexOf('--config-file') !== -1 || content.match(/-c\s+\//)) && lastConfigFile) {
|
||||
html += '<div class="et-pre" style="margin-top:16px;border-top:2px solid var(--border-color);padding-top:16px;">' +
|
||||
'<div style="font-weight:600;margin-bottom:8px;color:var(--primary-color);">' +
|
||||
escapeHtml(tr('Configuration File Content')) + ':' +
|
||||
'</div>' +
|
||||
'<pre style="margin:0;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;">' +
|
||||
escapeHtml(lastConfigFile) +
|
||||
'</pre>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
return html;
|
||||
@@ -1091,7 +1185,12 @@ function parseTable(content, tabName) {
|
||||
translatedContent = translatedContent.replace(/###############\s*([^#]+)\s*###############/g, function(match, p1) {
|
||||
return '############### ' + tr(p1.trim()) + ' ###############';
|
||||
});
|
||||
|
||||
|
||||
// ACL 统计的结构体字段名与枚举取值按精确规则翻译
|
||||
if (tabName === 'acl') {
|
||||
translatedContent = translateAclStats(translatedContent);
|
||||
}
|
||||
|
||||
return '<div class="et-pre">' + (translatedContent.indexOf('<svg') !== -1 || translatedContent.indexOf('<span') !== -1 ? translatedContent : escapeHtml(translatedContent)) + '</div>';
|
||||
}
|
||||
|
||||
@@ -1179,96 +1278,157 @@ function parseTable(content, tabName) {
|
||||
}
|
||||
|
||||
function switchTab(tabName) {
|
||||
if (isRefreshing) return;
|
||||
|
||||
var tabs = document.querySelectorAll('.et-tab');
|
||||
var contents = document.querySelectorAll('.et-tab-content');
|
||||
|
||||
|
||||
tabs.forEach(function(tab) {
|
||||
tab.classList.remove('active');
|
||||
});
|
||||
contents.forEach(function(content) {
|
||||
content.classList.remove('active');
|
||||
});
|
||||
|
||||
|
||||
var activeTab = document.querySelector('.et-tab[data-tab="' + tabName + '"]');
|
||||
var activeContent = document.getElementById('tab_' + tabName);
|
||||
|
||||
|
||||
if (activeTab && activeContent) {
|
||||
activeTab.classList.add('active');
|
||||
activeContent.classList.add('active');
|
||||
currentTab = tabName;
|
||||
// 按需加载:只请求当前显示的分区,没有加载过才发起请求
|
||||
queueConnInfo([tabName], false);
|
||||
}
|
||||
}
|
||||
|
||||
// 把 TAB 名换算成后端分区名
|
||||
function connInfoKeyOfTab(tabName) {
|
||||
for (var i = 0; i < connInfoSections.length; i++) {
|
||||
if (connInfoSections[i].id === tabName) {
|
||||
return connInfoSections[i].key;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 分区加载失败(超时/网络错误)时给出提示,避免加载动画一直转下去
|
||||
function reportConnInfoError(keys) {
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var sec = null;
|
||||
for (var j = 0; j < connInfoSections.length; j++) {
|
||||
if (connInfoSections[j].key === keys[i]) sec = connInfoSections[j];
|
||||
}
|
||||
if (!sec) continue;
|
||||
var el = document.getElementById('tab_' + sec.id);
|
||||
if (el) {
|
||||
el.innerHTML = '<div class="et-error"><%:Loading timed out. Please click Refresh to try again.%></div>';
|
||||
el.setAttribute('data-loaded', '1');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 把分区加入请求队列
|
||||
function queueConnInfo(tabNames, force) {
|
||||
var changed = false;
|
||||
for (var i = 0; i < tabNames.length; i++) {
|
||||
var key = connInfoKeyOfTab(tabNames[i]);
|
||||
if (!key) continue;
|
||||
if (!force && connInfoLoaded[key]) continue;
|
||||
if (connInfoQueue.indexOf(key) !== -1) continue;
|
||||
connInfoQueue.push(key);
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
pumpConnInfoQueue();
|
||||
}
|
||||
}
|
||||
|
||||
// 依次请求队列里的分区,同一时刻只允许一个请求在跑,
|
||||
// 避免一次起多个 easytier-cli 进程把路由器拖慢
|
||||
function pumpConnInfoQueue() {
|
||||
if (connInfoBusy || connInfoQueue.length === 0) return;
|
||||
|
||||
var keys = connInfoQueue;
|
||||
connInfoQueue = [];
|
||||
connInfoBusy = true;
|
||||
setRefreshBtnBusy(true);
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
var finished = false;
|
||||
|
||||
var onDone = function(data) {
|
||||
if (finished) return;
|
||||
finished = true;
|
||||
connInfoBusy = false;
|
||||
setRefreshBtnBusy(false);
|
||||
if (data) {
|
||||
if (typeof data.config_file === 'string') {
|
||||
lastConfigFile = data.config_file;
|
||||
}
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
connInfoLoaded[keys[i]] = true;
|
||||
}
|
||||
updateConnInfo(data);
|
||||
} else {
|
||||
reportConnInfoError(keys);
|
||||
}
|
||||
// 继续处理下一个分区
|
||||
pumpConnInfoQueue();
|
||||
};
|
||||
|
||||
xhr.open('GET', '<%=url("admin", "vpn", "easytier", "api_conninfo")%>?parts=' + encodeURIComponent(keys.join(',')), true);
|
||||
xhr.timeout = 20000;
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState !== 4) return;
|
||||
var data = null;
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
data = JSON.parse(xhr.responseText);
|
||||
} catch (e) {
|
||||
data = null;
|
||||
}
|
||||
}
|
||||
onDone(data);
|
||||
};
|
||||
xhr.ontimeout = function() { onDone(null); };
|
||||
xhr.onerror = function() { onDone(null); };
|
||||
xhr.onabort = function() { onDone(null); };
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function setRefreshBtnBusy(busy) {
|
||||
var btn = document.getElementById('et_conninfo_refresh');
|
||||
if (!btn) return;
|
||||
var btnText = btn.querySelector('span');
|
||||
btn.disabled = busy;
|
||||
if (busy) {
|
||||
btn.classList.add('loading');
|
||||
if (btnText) btnText.textContent = '<%:Refreshing...%>';
|
||||
} else {
|
||||
btn.classList.remove('loading');
|
||||
if (btnText) btnText.textContent = '<%:Refresh%>';
|
||||
}
|
||||
}
|
||||
|
||||
function refreshConnInfo() {
|
||||
if (isRefreshing) return;
|
||||
|
||||
isRefreshing = true;
|
||||
var btn = document.getElementById('et_conninfo_refresh');
|
||||
var btnText = btn.querySelector('span');
|
||||
var originalText = btnText.textContent;
|
||||
|
||||
btn.disabled = true;
|
||||
btn.classList.add('loading');
|
||||
btnText.textContent = '<%:Refreshing...%>';
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', '<%=url("admin", "vpn", "easytier", "api_conninfo")%>', true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4) {
|
||||
isRefreshing = false;
|
||||
btn.disabled = false;
|
||||
btn.classList.remove('loading');
|
||||
btnText.textContent = originalText;
|
||||
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
var data = JSON.parse(xhr.responseText);
|
||||
updateConnInfo(data);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse response:', e);
|
||||
}
|
||||
}
|
||||
// 手动刷新:立即刷新当前显示的分区,其余分区标记失效,切过去时再重新加载,
|
||||
// 这样点一次刷新不会同时起十几个 easytier-cli 进程
|
||||
var activeKey = connInfoKeyOfTab(currentTab);
|
||||
for (var i = 0; i < connInfoSections.length; i++) {
|
||||
if (connInfoSections[i].key !== activeKey) {
|
||||
delete connInfoLoaded[connInfoSections[i].key];
|
||||
}
|
||||
};
|
||||
xhr.onerror = function() {
|
||||
isRefreshing = false;
|
||||
btn.disabled = false;
|
||||
btn.classList.remove('loading');
|
||||
btnText.textContent = originalText;
|
||||
};
|
||||
xhr.onabort = function() {
|
||||
isRefreshing = false;
|
||||
btn.disabled = false;
|
||||
btn.classList.remove('loading');
|
||||
btnText.textContent = originalText;
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
queueConnInfo([currentTab], true);
|
||||
}
|
||||
|
||||
function updateConnInfo(data) {
|
||||
if (!data) return;
|
||||
|
||||
var sections = [
|
||||
{id: 'node', key: 'node'},
|
||||
{id: 'peer', key: 'peer'},
|
||||
{id: 'route', key: 'route'},
|
||||
{id: 'connector', key: 'connector'},
|
||||
{id: 'stun', key: 'stun'},
|
||||
{id: 'peercenter', key: 'peer_center'},
|
||||
{id: 'vpnportal', key: 'vpn_portal'},
|
||||
{id: 'proxy', key: 'proxy'},
|
||||
{id: 'acl', key: 'acl'},
|
||||
{id: 'mappedlistener', key: 'mapped_listener'},
|
||||
{id: 'stats', key: 'stats'},
|
||||
{id: 'cmdline', key: 'cmdline'}
|
||||
];
|
||||
|
||||
sections.forEach(function(sec) {
|
||||
|
||||
connInfoSections.forEach(function(sec) {
|
||||
var el = document.getElementById('tab_' + sec.id);
|
||||
if (el && data[sec.key] !== undefined) {
|
||||
el.innerHTML = parseTable(data[sec.key], sec.id);
|
||||
el.setAttribute('data-loaded', '1');
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1290,9 +1450,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
// 加载贡献者
|
||||
loadContributors();
|
||||
|
||||
// 初始加载数据
|
||||
refreshConnInfo();
|
||||
|
||||
// 初始只加载当前显示的分区,其余分区等切过去时再按需请求
|
||||
queueConnInfo([currentTab], false);
|
||||
|
||||
// 定时刷新:只刷新当前显示的分区,不再每次把十几个 easytier-cli 全部跑一遍。
|
||||
// 间隔取 10 秒,低性能设备上也能跑得过来(单次只起一个进程)
|
||||
window.setInterval(function() {
|
||||
if (document.hidden) return;
|
||||
queueConnInfo([currentTab], true);
|
||||
}, 10000);
|
||||
});
|
||||
|
||||
// 贡献者轮播管理 (ES5)
|
||||
@@ -1506,11 +1673,6 @@ function loadContributors() {
|
||||
contributorsCarousel.init();
|
||||
}
|
||||
|
||||
// 自动刷新
|
||||
XHR.poll(5, '<%=url("admin", "vpn", "easytier", "api_conninfo")%>', null, function(x, data) {
|
||||
if (!isRefreshing && data) {
|
||||
updateConnInfo(data);
|
||||
}
|
||||
});
|
||||
// 自动刷新已改为只刷新当前显示的分区,见上方 DOMContentLoaded 中的定时器
|
||||
//]]>
|
||||
</script>
|
||||
@@ -383,7 +383,7 @@ local translate = i18n.translate
|
||||
<select id="fallback_version_select" class="config-input" style="display:none;width:100%;">
|
||||
<option value=""><%=translate("Loading versions...")%></option>
|
||||
</select>
|
||||
<input type="text" id="fallback_version" class="config-input" placeholder="v2.6.4" style="display:none;width:100%;">
|
||||
<input type="text" id="fallback_version" class="config-input" placeholder="v2.7.0" style="display:none;width:100%;">
|
||||
</div>
|
||||
<button type="button" class="upload-btn" onclick="showDownloadModal()" style="padding:8px 16px;min-width:auto;flex-shrink:0;">
|
||||
<%=translate("Online Download")%>
|
||||
@@ -758,14 +758,14 @@ function loadConfig() {
|
||||
proxyList = Array.isArray(proxys) ? proxys : [];
|
||||
|
||||
renderProxyList();
|
||||
versionManager.setVersion(config.fallback_version || 'v2.6.4');
|
||||
versionManager.setVersion(config.fallback_version || 'v2.7.0');
|
||||
|
||||
// 保存原始配置
|
||||
originalConfig = {
|
||||
easytierbin: config.easytierbin || '/usr/bin/easytier-core',
|
||||
webbin: config.webbin || '/usr/bin/easytier-web',
|
||||
github_proxys: JSON.stringify(proxyList),
|
||||
fallback_version: config.fallback_version || 'v2.6.4'
|
||||
fallback_version: config.fallback_version || 'v2.7.0'
|
||||
};
|
||||
|
||||
checkDiskSpace('easytierbin');
|
||||
@@ -843,7 +843,7 @@ function getCurrentConfig() {
|
||||
easytierbin: document.getElementById('easytierbin').value || '/usr/bin/easytier-core',
|
||||
webbin: document.getElementById('webbin').value || '/usr/bin/easytier-web',
|
||||
github_proxys: JSON.stringify(proxyList),
|
||||
fallback_version: versionManager.getCurrentVersion() || 'v2.6.4'
|
||||
fallback_version: versionManager.getCurrentVersion() || 'v2.7.0'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -868,7 +868,7 @@ function saveConfig() {
|
||||
easytierbin: document.getElementById('easytierbin').value || '/usr/bin/easytier-core',
|
||||
webbin: document.getElementById('webbin').value || '/usr/bin/easytier-web',
|
||||
github_proxys: proxyList,
|
||||
fallback_version: versionManager.getCurrentVersion() || 'v2.6.4'
|
||||
fallback_version: versionManager.getCurrentVersion() || 'v2.7.0'
|
||||
};
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
@@ -677,6 +677,35 @@ input:disabled + .slider {
|
||||
<span class="description"><%:Automatically create local user when easytier-core connects with an unknown username%>. (--allow-auto-create-user <%:parameter%>)</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="web_heartbeat_min_response_ms"><%:Heartbeat Minimum Response Time (ms)%></label>
|
||||
<input type="number" class="form-control" id="web_heartbeat_min_response_ms" name="web_heartbeat_min_response_ms" placeholder="3500">
|
||||
<span class="description"><%:Minimum heartbeat response delay used by the config server when measuring client latency%>. (--heartbeat-min-response-ms <%:parameter%>)</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="web_heartbeat_timeout_ms"><%:Heartbeat Timeout (ms)%></label>
|
||||
<input type="number" class="form-control" id="web_heartbeat_timeout_ms" name="web_heartbeat_timeout_ms" placeholder="15000">
|
||||
<span class="description"><%:How long a client may stay silent before the config server marks it offline%>. (--heartbeat-timeout-ms <%:parameter%>)</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="web_gateway_peer_url"><%:Gateway Peer URL%></label>
|
||||
<input type="text" class="form-control" id="web_gateway_peer_url" name="web_gateway_peer_url" placeholder="tcp://public.easytier.top:11010">
|
||||
<span class="description"><%:Peer URL used by this web instance when it works as a gateway%>. (--gateway-peer-url <%:parameter%>)</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="checkbox-wrapper">
|
||||
<label for="web_gateway_relay_data"><%:Gateway Relay Data%></label>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="web_gateway_relay_data" name="web_gateway_relay_data">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<span class="description"><%:Allow this web gateway instance to relay data traffic%>. (--gateway-relay-data <%:parameter%>)</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="web_weblog"><%:Log Level%></label>
|
||||
<select class="form-control" id="web_weblog" name="web_weblog">
|
||||
@@ -905,6 +934,11 @@ function loadConfig() {
|
||||
document.getElementById('web_geoip_db').value = data.web_geoip_db || '';
|
||||
document.getElementById('web_disable_registration').checked = data.web_disable_registration === '1';
|
||||
document.getElementById('web_allow_auto_create_user').checked = data.web_allow_auto_create_user === '1';
|
||||
// EasyTier 2.7.0 新增的 web 参数
|
||||
document.getElementById('web_heartbeat_min_response_ms').value = data.web_heartbeat_min_response_ms || '';
|
||||
document.getElementById('web_heartbeat_timeout_ms').value = data.web_heartbeat_timeout_ms || '';
|
||||
document.getElementById('web_gateway_peer_url').value = data.web_gateway_peer_url || '';
|
||||
document.getElementById('web_gateway_relay_data').checked = data.web_gateway_relay_data === '1';
|
||||
document.getElementById('web_weblog').value = data.web_weblog || 'off';
|
||||
|
||||
// OIDC配置
|
||||
@@ -953,6 +987,11 @@ function getCurrentConfig() {
|
||||
web_geoip_db: document.getElementById('web_geoip_db').value,
|
||||
web_disable_registration: document.getElementById('web_disable_registration').checked ? '1' : '0',
|
||||
web_allow_auto_create_user: document.getElementById('web_allow_auto_create_user').checked ? '1' : '0',
|
||||
// EasyTier 2.7.0 新增的 web 参数
|
||||
web_heartbeat_min_response_ms: document.getElementById('web_heartbeat_min_response_ms').value,
|
||||
web_heartbeat_timeout_ms: document.getElementById('web_heartbeat_timeout_ms').value,
|
||||
web_gateway_peer_url: document.getElementById('web_gateway_peer_url').value,
|
||||
web_gateway_relay_data: document.getElementById('web_gateway_relay_data').checked ? '1' : '0',
|
||||
web_weblog: document.getElementById('web_weblog').value,
|
||||
// OIDC
|
||||
web_oidc_enabled: document.getElementById('web_oidc_enabled').checked ? '1' : '0',
|
||||
|
||||
@@ -906,10 +906,12 @@ msgstr ""
|
||||
|
||||
#: applications/luci-app-easytier/luasrc/model/cbi/easytier.lua:65
|
||||
msgid ""
|
||||
"Web configuration server address. (-w parameter)<br>For a self-hosted Web "
|
||||
"server, use the format: udp://server_address:22020/username<br>For the "
|
||||
"official Web server, use the format: username<br>Official Web Console: <a "
|
||||
"href='https://easytier.cn/web'>easytier.cn/web</a>"
|
||||
"Web configuration server address. (-w parameter)<br>Since EasyTier 2.7.0 a "
|
||||
"full URL is required, the token-only shorthand is no longer supported<br>Self-"
|
||||
"hosted Web server, use the format: udp://server_address:22020/username<br>"
|
||||
"Official Web server, use the format: udp://config-server.easytier.cn:22020/"
|
||||
"username<br>Official Web Console: <a href='https://easytier.cn/web'>easytier."
|
||||
"cn/web</a>"
|
||||
msgstr ""
|
||||
|
||||
#: applications/luci-app-easytier/luasrc/model/cbi/easytier.lua:365
|
||||
@@ -1412,3 +1414,111 @@ msgstr ""
|
||||
|
||||
msgid "Duplicate extra parameter"
|
||||
msgstr ""
|
||||
|
||||
msgid "VPN Portal Listen Address"
|
||||
msgstr ""
|
||||
|
||||
msgid "WireGuard VPN portal listen address, allowing other VPN clients to connect.<br>Since EasyTier 2.7.0 only wg://HOST:PORT is accepted; the client network can no longer be appended to the URL, please add each client in \"VPN Portal Clients\" below (--vpn-portal parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only wg://HOST:PORT is accepted since EasyTier 2.7.0, please fill the client network into \"VPN Portal Clients\""
|
||||
msgstr ""
|
||||
|
||||
msgid "VPN Portal Clients"
|
||||
msgstr ""
|
||||
|
||||
msgid "One WireGuard client per entry in the form NAME=CIDR, for example client1=10.14.14.1/24.<br>NAME may contain letters, digits and dashes only; the address must be a usable host address inside the client network. (--vpn-portal-client parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Invalid client, expected NAME=CIDR, for example client1=10.14.14.1/24"
|
||||
msgstr ""
|
||||
|
||||
msgid "VPN Portal Private Key"
|
||||
msgstr ""
|
||||
|
||||
msgid "Base64 encoded 32-byte WireGuard private key of the portal.<br>Required since EasyTier 2.7.0, the portal will not start without it. It is handed to easytier-core through an environment variable so that it never shows up in the process list. (--vpn-portal-private-key parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Disable relay quic"
|
||||
msgstr ""
|
||||
|
||||
msgid "If true, disable relaying quic packets, avoiding consuming too much bandwidth. (--disable-relay-quic parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Relay foreign network quic"
|
||||
msgstr ""
|
||||
|
||||
msgid "If true, allow relaying quic packets from foreign networks. (--enable-relay-foreign-network-quic parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Magic DNS Zone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Top level DNS zone used by Magic DNS, default is et.net. Only takes effect when Magic DNS is enabled. (--tld-dns-zone parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Instance Receive Rate Limit"
|
||||
msgstr ""
|
||||
|
||||
msgid "the maximum inbound bps limit for this network instance, default is no limit. unit: BPS (bytes per second). (--instance-recv-bps-limit parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Socket Mark"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set SO_MARK on all underlay sockets, Linux only and requires CAP_NET_ADMIN. Usually used together with policy routing. (--socket-mark parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lazy P2P"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only try to establish P2P connections when traffic actually needs to be forwarded. (--lazy-p2p parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Need P2P"
|
||||
msgstr ""
|
||||
|
||||
msgid "Require a P2P connection before forwarding traffic through relays. (--need-p2p parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Disable UPnP"
|
||||
msgstr ""
|
||||
|
||||
msgid "EasyTier 2.7.0 tries to map listener ports through UPnP/NAT-PMP by default. Enable this to turn the automatic port mapping off. (--disable-upnp parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "STUN Servers"
|
||||
msgstr ""
|
||||
|
||||
msgid "Custom UDP STUN servers used for NAT type detection and hole punching. Leave empty to use the built-in defaults. (--stun-servers parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "STUN Servers (TCP)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Custom TCP STUN servers used for NAT type detection and hole punching. Leave empty to use the built-in defaults. (--tcp-stun-servers parameter)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Heartbeat Minimum Response Time (ms)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Minimum heartbeat response delay used by the config server when measuring client latency"
|
||||
msgstr ""
|
||||
|
||||
msgid "Heartbeat Timeout (ms)"
|
||||
msgstr ""
|
||||
|
||||
msgid "How long a client may stay silent before the config server marks it offline"
|
||||
msgstr ""
|
||||
|
||||
msgid "Gateway Peer URL"
|
||||
msgstr ""
|
||||
|
||||
msgid "Peer URL used by this web instance when it works as a gateway"
|
||||
msgstr ""
|
||||
|
||||
msgid "Gateway Relay Data"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow this web gateway instance to relay data traffic"
|
||||
msgstr ""
|
||||
@@ -818,12 +818,15 @@ msgstr "Web服务器地址"
|
||||
|
||||
#: applications/luci-app-easytier/luasrc/model/cbi/easytier.lua:65
|
||||
msgid ""
|
||||
"Web configuration server address. (-w parameter)<br>For a self-hosted Web "
|
||||
"server, use the format: udp://server_address:22020/username<br>For the "
|
||||
"official Web server, use the format: username<br>Official Web Console: <a "
|
||||
"href='https://easytier.cn/web'>easytier.cn/web</a>"
|
||||
"Web configuration server address. (-w parameter)<br>Since EasyTier 2.7.0 a "
|
||||
"full URL is required, the token-only shorthand is no longer supported<br>Self-"
|
||||
"hosted Web server, use the format: udp://server_address:22020/username<br>"
|
||||
"Official Web server, use the format: udp://config-server.easytier.cn:22020/"
|
||||
"username<br>Official Web Console: <a href='https://easytier.cn/web'>easytier."
|
||||
"cn/web</a>"
|
||||
msgstr ""
|
||||
"Web配置服务器地址。(-w 参数)<br>自建Web服务器 输入格式:udp://服务器地址:22020/账户名<br>官方Web服务器 输入格式:账户名 <br>"
|
||||
"Web配置服务器地址。(-w 参数)<br>EasyTier 2.7.0 起必须填写完整 URL,不再支持仅填 token 的简写方式<br>"
|
||||
"自建Web服务器 输入格式:udp://服务器地址:22020/账户名<br>官方Web服务器 输入格式:udp://config-server.easytier.cn:22020/账户名<br>"
|
||||
"官方Web控制台:<a href='https://easytier.cn/web' target='_blank'>https://easytier.cn/web</a>"
|
||||
|
||||
#: applications/luci-app-easytier/luasrc/model/cbi/easytier.lua:365
|
||||
@@ -1663,6 +1666,9 @@ msgstr "节点中心服务不可用,此功能要求网络中包含多个节点
|
||||
msgid "Refreshing..."
|
||||
msgstr "正在刷新..."
|
||||
|
||||
msgid "Loading timed out. Please click Refresh to try again."
|
||||
msgstr "加载超时,请点击刷新重试。"
|
||||
|
||||
msgid "Failed to parse response:"
|
||||
msgstr "解析响应失败:"
|
||||
|
||||
@@ -1802,9 +1808,174 @@ msgstr "按实例统计接收数据包"
|
||||
msgid "Traffic Control Packets TX By Instance"
|
||||
msgstr "按实例统计发送数据包"
|
||||
|
||||
msgid "Traffic Control Bytes Forwarded"
|
||||
msgstr "流量控制转发字节数"
|
||||
|
||||
msgid "Traffic Control Packets Forwarded"
|
||||
msgstr "流量控制转发数据包"
|
||||
|
||||
msgid "Traffic Bytes RX By Instance"
|
||||
msgstr "按实例统计接收字节数(总计)"
|
||||
|
||||
msgid "Traffic Bytes TX By Instance"
|
||||
msgstr "按实例统计发送字节数(总计)"
|
||||
|
||||
msgid "Traffic Packets RX By Instance"
|
||||
msgstr "按实例统计接收数据包(总计)"
|
||||
|
||||
msgid "Traffic Packets TX By Instance"
|
||||
msgstr "按实例统计发送数据包(总计)"
|
||||
|
||||
msgid "Traffic Bytes Foreign Forward RX"
|
||||
msgstr "跨网中转接收字节数"
|
||||
|
||||
msgid "Traffic Bytes Foreign Forward TX"
|
||||
msgstr "跨网中转发送字节数"
|
||||
|
||||
msgid "Traffic Bytes Foreign Forward Forwarded"
|
||||
msgstr "跨网中转转发字节数"
|
||||
|
||||
msgid "Traffic Packets Foreign Forward RX"
|
||||
msgstr "跨网中转接收数据包"
|
||||
|
||||
msgid "Traffic Packets Foreign Forward TX"
|
||||
msgstr "跨网中转发送数据包"
|
||||
|
||||
msgid "Traffic Packets Foreign Forward Forwarded"
|
||||
msgstr "跨网中转转发数据包"
|
||||
|
||||
msgid "Peer RPC Errors"
|
||||
msgstr "节点 RPC 错误数"
|
||||
|
||||
msgid "TCP Proxy Connect"
|
||||
msgstr "TCP 代理连接数"
|
||||
|
||||
msgid "UDP Broadcast Relay Packets Captured"
|
||||
msgstr "UDP 广播中继捕获数据包"
|
||||
|
||||
msgid "UDP Broadcast Relay Packets Forwarded"
|
||||
msgstr "UDP 广播中继转发数据包"
|
||||
|
||||
msgid "UDP Broadcast Relay Packets Forward Failed"
|
||||
msgstr "UDP 广播中继转发失败数据包"
|
||||
|
||||
msgid "UDP Broadcast Relay Packets Ignored"
|
||||
msgstr "UDP 广播中继忽略数据包"
|
||||
|
||||
msgid "VPN Portal Client"
|
||||
msgstr "VPN 门户客户端"
|
||||
|
||||
msgid "VPN Portal Client Bytes RX"
|
||||
msgstr "VPN 门户客户端接收字节数"
|
||||
|
||||
msgid "VPN Portal Client Bytes TX"
|
||||
msgstr "VPN 门户客户端发送字节数"
|
||||
|
||||
msgid "VPN Portal Client Packets RX"
|
||||
msgstr "VPN 门户客户端接收数据包"
|
||||
|
||||
msgid "VPN Portal Client Packets TX"
|
||||
msgstr "VPN 门户客户端发送数据包"
|
||||
|
||||
msgid "From Instance ID"
|
||||
msgstr "来源实例ID"
|
||||
|
||||
msgid "Direction"
|
||||
msgstr "方向"
|
||||
|
||||
msgid "Destination IP"
|
||||
msgstr "目标 IP"
|
||||
|
||||
msgid "Mapped Destination IP"
|
||||
msgstr "映射后目标 IP"
|
||||
|
||||
msgid "Error Type"
|
||||
msgstr "错误类型"
|
||||
|
||||
msgid "Protocol"
|
||||
msgstr "协议"
|
||||
|
||||
msgid "Name"
|
||||
msgstr "名称"
|
||||
|
||||
msgid "Priority"
|
||||
msgstr "优先级"
|
||||
|
||||
msgid "Action"
|
||||
msgstr "动作"
|
||||
|
||||
msgid "Enabled"
|
||||
msgstr "已启用"
|
||||
|
||||
msgid "Ports"
|
||||
msgstr "端口"
|
||||
|
||||
msgid "Source Ports"
|
||||
msgstr "源端口"
|
||||
|
||||
msgid "Source IPs"
|
||||
msgstr "源 IP"
|
||||
|
||||
msgid "Destination IPs"
|
||||
msgstr "目标 IP"
|
||||
|
||||
msgid "Stateful"
|
||||
msgstr "有状态"
|
||||
|
||||
msgid "Rate Limit"
|
||||
msgstr "速率限制"
|
||||
|
||||
msgid "Burst Limit"
|
||||
msgstr "突发限制"
|
||||
|
||||
msgid "Packets"
|
||||
msgstr "数据包数"
|
||||
|
||||
msgid "Bytes"
|
||||
msgstr "字节数"
|
||||
|
||||
msgid "Source Address"
|
||||
msgstr "源地址"
|
||||
|
||||
msgid "Destination Address"
|
||||
msgstr "目标地址"
|
||||
|
||||
msgid "Created"
|
||||
msgstr "创建时间"
|
||||
|
||||
msgid "Last Seen"
|
||||
msgstr "最近活跃"
|
||||
|
||||
msgid "Allow"
|
||||
msgstr "允许"
|
||||
|
||||
msgid "Drop (no response)"
|
||||
msgstr "丢弃(不回应)"
|
||||
|
||||
msgid "Noop"
|
||||
msgstr "不处理"
|
||||
|
||||
msgid "Any"
|
||||
msgstr "任意"
|
||||
|
||||
msgid "Unspecified"
|
||||
msgstr "未指定"
|
||||
|
||||
msgid "New"
|
||||
msgstr "新建"
|
||||
|
||||
msgid "Established"
|
||||
msgstr "已建立"
|
||||
|
||||
msgid "Related"
|
||||
msgstr "关联"
|
||||
|
||||
msgid "Invalid"
|
||||
msgstr "无效"
|
||||
|
||||
msgid "Default / None"
|
||||
msgstr "默认 / 无"
|
||||
|
||||
msgid "To Instance ID"
|
||||
msgstr "目标实例ID"
|
||||
|
||||
@@ -2107,3 +2278,111 @@ msgstr "数据库重置成功"
|
||||
|
||||
msgid "Restart service to apply changes?"
|
||||
msgstr "重启服务以生效?"
|
||||
|
||||
msgid "VPN Portal Listen Address"
|
||||
msgstr "VPN 门户监听地址"
|
||||
|
||||
msgid "WireGuard VPN portal listen address, allowing other VPN clients to connect.<br>Since EasyTier 2.7.0 only wg://HOST:PORT is accepted; the client network can no longer be appended to the URL, please add each client in \"VPN Portal Clients\" below (--vpn-portal parameter)"
|
||||
msgstr "WireGuard VPN 门户监听地址,允许其他 VPN 客户端接入。<br>EasyTier 2.7.0 起只接受 wg://主机:端口,客户端网段不能再写在地址里,请在下方“VPN 门户客户端”中逐个添加(--vpn-portal 参数)"
|
||||
|
||||
msgid "Only wg://HOST:PORT is accepted since EasyTier 2.7.0, please fill the client network into \"VPN Portal Clients\""
|
||||
msgstr "EasyTier 2.7.0 起只接受 wg://主机:端口,请把客户端网段填写到“VPN 门户客户端”中"
|
||||
|
||||
msgid "VPN Portal Clients"
|
||||
msgstr "VPN 门户客户端"
|
||||
|
||||
msgid "One WireGuard client per entry in the form NAME=CIDR, for example client1=10.14.14.1/24.<br>NAME may contain letters, digits and dashes only; the address must be a usable host address inside the client network. (--vpn-portal-client parameter)"
|
||||
msgstr "每条一个 WireGuard 客户端,格式为 名称=CIDR,例如 client1=10.14.14.1/24。<br>名称只能包含字母、数字和短横线;地址必须是该网段内可用的主机地址(--vpn-portal-client 参数)"
|
||||
|
||||
msgid "Invalid client, expected NAME=CIDR, for example client1=10.14.14.1/24"
|
||||
msgstr "客户端格式错误,应为 名称=CIDR,例如 client1=10.14.14.1/24"
|
||||
|
||||
msgid "VPN Portal Private Key"
|
||||
msgstr "VPN 门户私钥"
|
||||
|
||||
msgid "Base64 encoded 32-byte WireGuard private key of the portal.<br>Required since EasyTier 2.7.0, the portal will not start without it. It is handed to easytier-core through an environment variable so that it never shows up in the process list. (--vpn-portal-private-key parameter)"
|
||||
msgstr "门户的 WireGuard 私钥(base64 编码的 32 字节)。<br>EasyTier 2.7.0 起必填,未填写时门户不会启动。私钥通过环境变量传给 easytier-core,不会出现在进程列表中(--vpn-portal-private-key 参数)"
|
||||
|
||||
msgid "Disable relay quic"
|
||||
msgstr "禁用转发 QUIC"
|
||||
|
||||
msgid "If true, disable relaying quic packets, avoiding consuming too much bandwidth. (--disable-relay-quic parameter)"
|
||||
msgstr "开启后禁止转发 QUIC 报文,避免占用过多带宽(--disable-relay-quic 参数)"
|
||||
|
||||
msgid "Relay foreign network quic"
|
||||
msgstr "转发外部网络 QUIC"
|
||||
|
||||
msgid "If true, allow relaying quic packets from foreign networks. (--enable-relay-foreign-network-quic parameter)"
|
||||
msgstr "开启后允许转发来自其他网络的 QUIC 报文(--enable-relay-foreign-network-quic 参数)"
|
||||
|
||||
msgid "Magic DNS Zone"
|
||||
msgstr "魔法 DNS 区域"
|
||||
|
||||
msgid "Top level DNS zone used by Magic DNS, default is et.net. Only takes effect when Magic DNS is enabled. (--tld-dns-zone parameter)"
|
||||
msgstr "魔法 DNS 使用的顶级域名区域,默认 et.net.,仅在启用魔法 DNS 时生效(--tld-dns-zone 参数)"
|
||||
|
||||
msgid "Instance Receive Rate Limit"
|
||||
msgstr "实例接收限速"
|
||||
|
||||
msgid "the maximum inbound bps limit for this network instance, default is no limit. unit: BPS (bytes per second). (--instance-recv-bps-limit parameter)"
|
||||
msgstr "本网络实例的整体入站限速,默认不限速,单位字节每秒(--instance-recv-bps-limit 参数)"
|
||||
|
||||
msgid "Socket Mark"
|
||||
msgstr "Socket Mark"
|
||||
|
||||
msgid "Set SO_MARK on all underlay sockets, Linux only and requires CAP_NET_ADMIN. Usually used together with policy routing. (--socket-mark parameter)"
|
||||
msgstr "为所有底层套接字设置 SO_MARK,仅 Linux 支持且需要 CAP_NET_ADMIN 权限,通常配合策略路由使用(--socket-mark 参数)"
|
||||
|
||||
msgid "Lazy P2P"
|
||||
msgstr "延迟 P2P"
|
||||
|
||||
msgid "Only try to establish P2P connections when traffic actually needs to be forwarded. (--lazy-p2p parameter)"
|
||||
msgstr "仅在有实际数据需要转发时才尝试建立 P2P 连接(--lazy-p2p 参数)"
|
||||
|
||||
msgid "Need P2P"
|
||||
msgstr "强制 P2P"
|
||||
|
||||
msgid "Require a P2P connection before forwarding traffic through relays. (--need-p2p parameter)"
|
||||
msgstr "必须建立 P2P 连接后才允许通过中继转发数据(--need-p2p 参数)"
|
||||
|
||||
msgid "Disable UPnP"
|
||||
msgstr "禁用 UPnP"
|
||||
|
||||
msgid "EasyTier 2.7.0 tries to map listener ports through UPnP/NAT-PMP by default. Enable this to turn the automatic port mapping off. (--disable-upnp parameter)"
|
||||
msgstr "EasyTier 2.7.0 默认会尝试通过 UPnP/NAT-PMP 自动映射监听端口,开启本项可关闭自动端口映射(--disable-upnp 参数)"
|
||||
|
||||
msgid "STUN Servers"
|
||||
msgstr "STUN 服务器"
|
||||
|
||||
msgid "Custom UDP STUN servers used for NAT type detection and hole punching. Leave empty to use the built-in defaults. (--stun-servers parameter)"
|
||||
msgstr "用于 NAT 类型探测与打洞的自定义 UDP STUN 服务器,留空则使用内置默认值(--stun-servers 参数)"
|
||||
|
||||
msgid "STUN Servers (TCP)"
|
||||
msgstr "STUN 服务器(TCP)"
|
||||
|
||||
msgid "Custom TCP STUN servers used for NAT type detection and hole punching. Leave empty to use the built-in defaults. (--tcp-stun-servers parameter)"
|
||||
msgstr "用于 NAT 类型探测与打洞的自定义 TCP STUN 服务器,留空则使用内置默认值(--tcp-stun-servers 参数)"
|
||||
|
||||
msgid "Heartbeat Minimum Response Time (ms)"
|
||||
msgstr "心跳最小响应时间(毫秒)"
|
||||
|
||||
msgid "Minimum heartbeat response delay used by the config server when measuring client latency"
|
||||
msgstr "配置服务器测量客户端延迟时使用的心跳最小响应延迟"
|
||||
|
||||
msgid "Heartbeat Timeout (ms)"
|
||||
msgstr "心跳超时时间(毫秒)"
|
||||
|
||||
msgid "How long a client may stay silent before the config server marks it offline"
|
||||
msgstr "客户端多久无心跳后会被配置服务器标记为离线"
|
||||
|
||||
msgid "Gateway Peer URL"
|
||||
msgstr "网关对等节点地址"
|
||||
|
||||
msgid "Peer URL used by this web instance when it works as a gateway"
|
||||
msgstr "本 Web 实例作为网关时使用的对等节点地址"
|
||||
|
||||
msgid "Gateway Relay Data"
|
||||
msgstr "网关转发数据"
|
||||
|
||||
msgid "Allow this web gateway instance to relay data traffic"
|
||||
msgstr "允许本 Web 网关实例转发数据流量"
|
||||
@@ -3,6 +3,8 @@ instance_id = "f9f05421-7c6b-47d6-a67d-4d58d49f51d8"
|
||||
dhcp = true
|
||||
listeners = []
|
||||
exit_nodes = []
|
||||
# 注意:顶层配置结构里没有 rpc_portal 字段,该行会被 easytier-core 静默忽略。
|
||||
# RPC 端口只能通过命令行 -r 指定(本插件的“RPC 端口”选项),保持默认即可。
|
||||
rpc_portal = "0.0.0.0:15888"
|
||||
|
||||
[network_identity]
|
||||
@@ -12,4 +14,18 @@ network_secret = "mysecret"
|
||||
[[peer]]
|
||||
uri = "tcp://public.easytier.top:11010"
|
||||
|
||||
# EasyTier 2.7.0 起 WireGuard 门户写法(默认关闭,需要时取消注释)
|
||||
# 旧版把客户端网段写在 wireguard_listen 之外的 client_cidr 键已不再支持,会导致配置文件解析失败。
|
||||
# 门户私钥为 base64 编码的 32 字节,2.7.0 起必须填写,否则门户监听不会启动。
|
||||
# [vpn_portal_config]
|
||||
# enabled = true
|
||||
# wireguard_listen = "0.0.0.0:51820"
|
||||
# wireguard_private_key = ""
|
||||
#
|
||||
# [[vpn_portal_config.clients]]
|
||||
# name = "client1"
|
||||
# virtual_ip = "10.14.14.1/24"
|
||||
# groups = []
|
||||
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ check_bin() {
|
||||
# 如果获取失败,从 UCI 配置或使用默认版本
|
||||
if [ -z "$tag" ]; then
|
||||
tag=$(uci -q get easytier.@easytier[0].fallback_version)
|
||||
[ -z "$tag" ] && tag="v2.6.4"
|
||||
[ -z "$tag" ] && tag="v2.7.0"
|
||||
fi
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 开始在线下载${tag}版本,${proxy}https://github.com/EasyTier/EasyTier/releases/download/${tag}/easytier-linux-${cpucore}-${tag}.zip下载较慢耐心等候" >>/tmp/easytier.log
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 开始在线下载${tag}版本,${proxy}https://github.com/EasyTier/EasyTier/releases/download/${tag}/easytier-linux-${cpucore}-${tag}.zip下载较慢耐心等候" >>/tmp/easytierweb.log
|
||||
@@ -167,7 +167,10 @@ check_config() {
|
||||
wireguard_port=$(cat $config_file | grep "wireguard_listen = " | awk -F ":" '{print $2}'| tr -d '/", ')
|
||||
log="$(uci -q get easytier.@easytier[0].log || echo off)"
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 检测配置文件可用性 ${easytierbin} --check-config --config-file ${config_file}" >>/tmp/easytier.log
|
||||
${easytierbin} --check-config --config-file ${config_file} >> /tmp/easytier.log 2>&1 &
|
||||
${easytierbin} --check-config --config-file ${config_file} >> /tmp/easytier.log 2>&1
|
||||
if [ "$?" != "0" ] ; then
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 配置文件 ${config_file} 校验失败,请查看上方 easytier-core 的报错。EasyTier 2.7.0 起配置校验更严格:旧的 [vpn_portal_config] client_cidr 写法与 [flags] 中的未知键都会导致解析失败" >>/tmp/easytier.log
|
||||
fi
|
||||
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 开始运行 ${easytierbin} -c ${config_file}" >>/tmp/easytier.log
|
||||
procd_open_instance
|
||||
@@ -218,6 +221,8 @@ get_etconfig() {
|
||||
desvice_name="$(uci -q get easytier.@easytier[0].desvice_name)"
|
||||
instance_name="$(uci -q get easytier.@easytier[0].instance_name)"
|
||||
vpn_portal="$(uci -q get easytier.@easytier[0].vpn_portal)"
|
||||
vpn_portal_clients="$(uci -q get easytier.@easytier[0].vpn_portal_clients)"
|
||||
vpn_portal_private_key="$(uci -q get easytier.@easytier[0].vpn_portal_private_key)"
|
||||
mtu="$(uci -q get easytier.@easytier[0].mtu)"
|
||||
default_protocol="$(uci -q get easytier.@easytier[0].default_protocol)"
|
||||
disable_encryption="$(uci -q get easytier.@easytier[0].disable_encryption || echo 0)"
|
||||
@@ -263,7 +268,18 @@ get_etconfig() {
|
||||
auto_config_interface="$(uci -q get easytier.@easytier[0].auto_config_interface || echo 1)"
|
||||
interface_netmask="$(uci -q get easytier.@easytier[0].interface_netmask)"
|
||||
auto_config_firewall="$(uci -q get easytier.@easytier[0].auto_config_firewall || echo 1)"
|
||||
|
||||
# EasyTier 2.7.0 新增参数
|
||||
tld_dns_zone="$(uci -q get easytier.@easytier[0].tld_dns_zone)"
|
||||
instance_recv_bps_limit="$(uci -q get easytier.@easytier[0].instance_recv_bps_limit)"
|
||||
socket_mark="$(uci -q get easytier.@easytier[0].socket_mark)"
|
||||
disable_upnp="$(uci -q get easytier.@easytier[0].disable_upnp || echo 0)"
|
||||
lazy_p2p="$(uci -q get easytier.@easytier[0].lazy_p2p || echo 0)"
|
||||
need_p2p="$(uci -q get easytier.@easytier[0].need_p2p || echo 0)"
|
||||
disable_relay_quic="$(uci -q get easytier.@easytier[0].disable_relay_quic || echo 0)"
|
||||
relay_quic="$(uci -q get easytier.@easytier[0].relay_quic || echo 0)"
|
||||
stun_servers="$(uci -q get easytier.@easytier[0].stun_servers)"
|
||||
tcp_stun_servers="$(uci -q get easytier.@easytier[0].tcp_stun_servers)"
|
||||
|
||||
}
|
||||
|
||||
set_firewall() {
|
||||
@@ -449,7 +465,8 @@ start_et() {
|
||||
procd_open_instance "easytier_core"
|
||||
get_tz
|
||||
[ -z "$SET_TZ" ] || procd_set_param env TZ="$SET_TZ"
|
||||
core_cmd=""
|
||||
# 门户私钥通过环境变量下发给 easytier-core,避免出现在进程命令行(状态页会展示命令行)
|
||||
[ -z "$vpn_portal_private_key" ] || procd_set_param env ET_VPN_PORTAL_PRIVATE_KEY="$vpn_portal_private_key"
|
||||
if [ "$etcmd" = "etcmd" ] ; then
|
||||
#默认方式启动
|
||||
[ -z "$network_name" ] || core_cmd="${core_cmd} --network-name $(shell_quote "$network_name")"
|
||||
@@ -536,12 +553,46 @@ start_et() {
|
||||
[ "$listenermode" = "ON" ] || core_cmd="${core_cmd} --no-listener"
|
||||
[ -z "$desvice_name" ] || core_cmd="${core_cmd} --hostname $(shell_quote "$desvice_name")"
|
||||
[ -z "$instance_name" ] || core_cmd="${core_cmd} -m $instance_name"
|
||||
[ -z "$vpn_portal" ] || core_cmd="${core_cmd} --vpn-portal $vpn_portal"
|
||||
# EasyTier 2.7.0 起 --vpn-portal 只接受 wg://主机:端口,客户端必须逐个具名枚举
|
||||
if [ -n "$vpn_portal" ]; then
|
||||
case "$vpn_portal" in
|
||||
wg://*/*)
|
||||
# 旧版把客户端网段写在 URL path 里,2.7.0 会直接拒绝并让进程退出,这里跳过门户并提示用户修改
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : VPN 门户地址 ${vpn_portal} 是 2.6.4 旧写法,EasyTier 2.7.0 起只接受 wg://主机:端口,已跳过门户启动;请在界面把客户端网段填入 VPN 门户客户端列表" >>/tmp/easytier.log
|
||||
;;
|
||||
wg://*)
|
||||
if [ -z "$vpn_portal_private_key" ]; then
|
||||
# 2.7.0 起门户必须有私钥,否则门户监听会启动失败并连带整个实例退出
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 已配置 VPN 门户但未填写门户私钥,EasyTier 2.7.0 起门户必须有私钥,已跳过门户启动;请在界面填写 VPN 门户私钥" >>/tmp/easytier.log
|
||||
else
|
||||
core_cmd="${core_cmd} --vpn-portal $vpn_portal"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : VPN 门户地址 ${vpn_portal} 格式不正确,应为 wg://主机:端口,已跳过门户启动" >>/tmp/easytier.log
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
# 门户具名客户端,格式 名称=地址/前缀,可配置多条
|
||||
if [ -n "$vpn_portal_clients" ]; then
|
||||
if [[ "$(grep "list vpn_portal_clients" /etc/config/easytier | awk '{print $3}' | wc -l)" -eq 1 ]]; then
|
||||
core_cmd="${core_cmd} --vpn-portal-client $vpn_portal_clients"
|
||||
else
|
||||
for vpn_portal_client in $(cat /etc/config/easytier | grep 'list vpn_portal_clients' | awk -F 'list vpn_portal_clients' '{print $2}' | sed "s/'/\n/g" | tr -d " ' "); do
|
||||
core_cmd="${core_cmd} --vpn-portal-client $vpn_portal_client"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
[ -z "$mtu" ] || core_cmd="${core_cmd} --mtu $mtu"
|
||||
[ "$default_protocol" = "-" ] || core_cmd="${core_cmd} --default-protocol $default_protocol"
|
||||
[ -z "$tunname" ] || core_cmd="${core_cmd} --dev-name $tunname"
|
||||
[ "$disable_encryption" = "0" ] || core_cmd="${core_cmd} -u"
|
||||
[ "$multi_thread" = "0" ] || core_cmd="${core_cmd} --multi-thread"
|
||||
# 2.7.0 起 multi_thread 的默认值由 false 改为 true,这里始终显式传值,保证升级后行为与界面勾选一致
|
||||
if [ "$multi_thread" = "0" ]; then
|
||||
core_cmd="${core_cmd} --multi-thread false"
|
||||
else
|
||||
core_cmd="${core_cmd} --multi-thread true"
|
||||
fi
|
||||
[ -z "$multi_thread_count" ] || core_cmd="${core_cmd} --multi-thread-count $multi_thread_count"
|
||||
[ "$no_tun" = "0" ] || core_cmd="${core_cmd} --no-tun"
|
||||
[ "$smoltcp" = "0" ] || core_cmd="${core_cmd} --use-smoltcp"
|
||||
@@ -571,8 +622,28 @@ start_et() {
|
||||
[ "$disable_sym" = "0" ] || core_cmd="${core_cmd} --disable-sym-hole-punching"
|
||||
[ "$disable_relay_kcp" = "0" ] || core_cmd="${core_cmd} --disable-relay-kcp true"
|
||||
[ "$relay_kcp" = "0" ] || core_cmd="${core_cmd} --enable-relay-foreign-network-kcp true"
|
||||
[ "$disable_relay_quic" = "0" ] || core_cmd="${core_cmd} --disable-relay-quic true"
|
||||
[ "$relay_quic" = "0" ] || core_cmd="${core_cmd} --enable-relay-foreign-network-quic true"
|
||||
[ -z "$udp_white_port" ] || core_cmd="${core_cmd} --udp-whitelist $udp_white_port"
|
||||
[ -z "$tcp_white_port" ] || core_cmd="${core_cmd} --tcp-whitelist $tcp_white_port"
|
||||
# EasyTier 2.7.0 新增的常用参数
|
||||
[ -z "$tld_dns_zone" ] || core_cmd="${core_cmd} --tld-dns-zone $tld_dns_zone"
|
||||
[ -z "$instance_recv_bps_limit" ] || core_cmd="${core_cmd} --instance-recv-bps-limit $instance_recv_bps_limit"
|
||||
[ -z "$socket_mark" ] || core_cmd="${core_cmd} --socket-mark $socket_mark"
|
||||
[ "$disable_upnp" = "0" ] || core_cmd="${core_cmd} --disable-upnp"
|
||||
[ "$lazy_p2p" = "0" ] || core_cmd="${core_cmd} --lazy-p2p"
|
||||
[ "$need_p2p" = "0" ] || core_cmd="${core_cmd} --need-p2p"
|
||||
# 自定义 STUN 服务器,可配置多条
|
||||
if [ -n "$stun_servers" ] ; then
|
||||
for stun_server in $(cat /etc/config/easytier | grep 'list stun_servers' | awk -F 'list stun_servers' '{print $2}' | sed "s/'/\n/g" | tr -d " ' "); do
|
||||
core_cmd="${core_cmd} --stun-servers $stun_server"
|
||||
done
|
||||
fi
|
||||
if [ -n "$tcp_stun_servers" ] ; then
|
||||
for tcp_stun_server in $(cat /etc/config/easytier | grep 'list tcp_stun_servers' | awk -F 'list tcp_stun_servers' '{print $2}' | sed "s/'/\n/g" | tr -d " ' "); do
|
||||
core_cmd="${core_cmd} --tcp-stun-servers $tcp_stun_server"
|
||||
done
|
||||
fi
|
||||
if [ -n "$extra_args" ] ; then
|
||||
while IFS= read -r extra_arg; do
|
||||
[ -n "$extra_arg" ] && core_cmd="${core_cmd} $extra_arg"
|
||||
@@ -595,7 +666,18 @@ EOF
|
||||
fi
|
||||
et_uuid="$(cat /etc/easytier/et_machine_id | tr -d ' \n')"
|
||||
[ -z "$et_uuid" ] || core_cmd="${core_cmd} --machine-id $et_uuid"
|
||||
[ -z "$web_config" ] || core_cmd="${core_cmd} -w $web_config"
|
||||
# EasyTier 2.7.0 起 -w 必须填写完整 URL(例如 udp://config-server.easytier.cn:22020/账户名),
|
||||
# 旧版只填账户名的写法会解析失败并让整个进程退出,这里跳过 Web 客户端并提示用户修改
|
||||
case "$web_config" in
|
||||
"")
|
||||
;;
|
||||
*://*)
|
||||
core_cmd="${core_cmd} -w $web_config"
|
||||
;;
|
||||
*)
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : Web 服务器地址 ${web_config} 不是完整 URL,EasyTier 2.7.0 起必须填写完整地址(例如 udp://config-server.easytier.cn:22020/账户名),已跳过 Web 客户端启动;请在界面把 Web 服务器地址改为完整地址" >>/tmp/easytier.log
|
||||
;;
|
||||
esac
|
||||
[ -z "$desvice_name" ] || core_cmd="${core_cmd} --hostname $(shell_quote "$desvice_name")"
|
||||
fi
|
||||
procd_set_param command /bin/sh -c "
|
||||
@@ -623,7 +705,10 @@ EOF
|
||||
procd_set_param limits nofile="1000000 1000000"
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_set_param respawn
|
||||
# procd 进程守护参数:threshold=3600 秒、timeout=5 秒、retry=20 次
|
||||
# 存活满 1 小时后崩溃计数归零;1 小时内崩溃超过 20 次(即第 21 次)才判定崩溃循环并放弃拉起,
|
||||
# 避免参数配置错误这类必然失败的场景无限重启刷日志、空烧 CPU
|
||||
procd_set_param respawn 3600 5 20
|
||||
procd_close_instance
|
||||
|
||||
# 不再自动放行 SOCKS5 端口到 WAN —— 无认证 SOCKS5 代理暴露给公网有严重安全风险
|
||||
@@ -691,6 +776,11 @@ start_web() {
|
||||
html_addr="$(uci -q get easytier.@easytier[0].web_html_addr)"
|
||||
disable_registration="$(uci -q get easytier.@easytier[0].web_disable_registration || echo 0)"
|
||||
allow_auto_create_user="$(uci -q get easytier.@easytier[0].web_allow_auto_create_user || echo 0)"
|
||||
# EasyTier 2.7.0 新增的 web 参数
|
||||
heartbeat_min_response_ms="$(uci -q get easytier.@easytier[0].web_heartbeat_min_response_ms)"
|
||||
heartbeat_timeout_ms="$(uci -q get easytier.@easytier[0].web_heartbeat_timeout_ms)"
|
||||
gateway_peer_url="$(uci -q get easytier.@easytier[0].web_gateway_peer_url)"
|
||||
gateway_relay_data="$(uci -q get easytier.@easytier[0].web_gateway_relay_data || echo 0)"
|
||||
# OIDC配置
|
||||
oidc_enabled="$(uci -q get easytier.@easytier[0].web_oidc_enabled || echo 0)"
|
||||
oidc_issuer_url="$(uci -q get easytier.@easytier[0].web_oidc_issuer_url)"
|
||||
@@ -729,6 +819,11 @@ start_web() {
|
||||
[ -n "$html_addr" ] && [ "$html_addr" != "0.0.0.0" ] && web_cmd="${web_cmd} --web-server-addr $html_addr"
|
||||
[ "$disable_registration" = "1" ] && web_cmd="${web_cmd} --disable-registration"
|
||||
[ "$allow_auto_create_user" = "1" ] && web_cmd="${web_cmd} --allow-auto-create-user"
|
||||
# EasyTier 2.7.0 新增的 web 参数
|
||||
[ -z "$heartbeat_min_response_ms" ] || web_cmd="${web_cmd} --heartbeat-min-response-ms $heartbeat_min_response_ms"
|
||||
[ -z "$heartbeat_timeout_ms" ] || web_cmd="${web_cmd} --heartbeat-timeout-ms $heartbeat_timeout_ms"
|
||||
[ -z "$gateway_peer_url" ] || web_cmd="${web_cmd} --gateway-peer-url $gateway_peer_url"
|
||||
[ "$gateway_relay_data" = "1" ] && web_cmd="${web_cmd} --gateway-relay-data true"
|
||||
# OIDC配置参数
|
||||
if [ "$oidc_enabled" = "1" ] ; then
|
||||
[ -z "$oidc_issuer_url" ] || web_cmd="${web_cmd} --oidc-issuer-url $oidc_issuer_url"
|
||||
@@ -773,7 +868,9 @@ start_web() {
|
||||
"
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_set_param respawn
|
||||
# procd 进程守护参数:threshold=3600 秒、timeout=5 秒、retry=20 次
|
||||
# 存活满 1 小时后崩溃计数归零;1 小时内崩溃超过 20 次(即第 21 次)才判定崩溃循环并放弃拉起
|
||||
procd_set_param respawn 3600 5 20
|
||||
procd_close_instance
|
||||
if [ ! -z "$web_port" ] && [ "$fw_web" = "1" ] ; then
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 添加防火墙规则 easytier_web 放行服务端口 ${web_port} " >>/tmp/easytierweb.log
|
||||
|
||||
@@ -42,7 +42,7 @@ get_latest_version() {
|
||||
# 如果获取失败,从 UCI 配置或使用默认版本
|
||||
if [ -z "$tag" ]; then
|
||||
tag=$(uci -q get easytier.@easytier[0].fallback_version)
|
||||
[ -z "$tag" ] && tag="v2.6.2"
|
||||
[ -z "$tag" ] && tag="v2.7.0"
|
||||
fi
|
||||
|
||||
echo "$tag"
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
# This file is the single source of truth for the EasyTier version
|
||||
# Used by: easytier/Makefile, luci-app-easytier/Makefile, init.d/easytier
|
||||
|
||||
EASYTIER_VERSION=2.6.4
|
||||
EASYTIER_VERSION=2.7.0
|
||||
Reference in new issue
Block a user