update 2026-05-16 10:31:14

This commit is contained in:
action 2026-05-16 10:31:14 +08:00
parent bd9bd22957
commit 75b8154d3a
13 changed files with 197 additions and 75 deletions

View File

@ -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.2)
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.6.4)
ifeq ($(ARCH),mipsel)
APP_ARCH:=mipsel
@ -36,6 +36,8 @@ PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
include $(INCLUDE_DIR)/package.mk
RSTRIP:=:
define Package/$(PKG_NAME)
SECTION:=net
CATEGORY:=Network
@ -63,8 +65,10 @@ endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/easytier-core $(1)/usr/bin/easytier-core
$(INSTALL_BIN) $(PKG_BUILD_DIR)/easytier-cli $(1)/usr/bin/easytier-cli
$(CP) $(PKG_BUILD_DIR)/easytier-core $(1)/usr/bin/
chmod 0755 $(1)/usr/bin/easytier-core
$(CP) $(PKG_BUILD_DIR)/easytier-cli $(1)/usr/bin/
chmod 0755 $(1)/usr/bin/easytier-cli
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@ -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.2)
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.6.4)
ifeq ($(ARCH),mipsel)
APP_ARCH:=mipsel

View File

@ -7,7 +7,7 @@
include $(TOPDIR)/rules.mk
-include $(dir $(lastword $(MAKEFILE_LIST)))../version.mk
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.6.2)
PKG_VERSION:=$(or $(EASYTIER_VERSION),2.6.4)
PKG_RELEASE:=1
LUCI_TITLE:=LuCI support for EasyTier

View File

@ -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.2"
fallback_version = uci:get_first("easytier", "easytier", "fallback_version") or "v2.6.4"
}
-- 读取代理列表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.2")
uci:set("easytier", "@easytier[0]", "fallback_version", data.fallback_version or "v2.6.4")
-- 删除旧的代理列表
uci:delete("easytier", "@easytier[0]", "github_proxys")

View File

@ -56,12 +56,6 @@ network_name = s:taboption("general", Value, "network_name", translate("Network
network_name.password = true
network_name.placeholder = "easytier-name"
network_name.maxlength = 64
network_name.validate = function(self, value)
if value and value ~= "" and value:match("[^%w%-_]") then
return nil, translate("Only alphanumeric characters, hyphens and underscores allowed")
end
return value
end
network_name:depends("etcmd", "etcmd")
network_secret = s:taboption("general", Value, "network_secret", translate("Network Secret"),
@ -412,9 +406,28 @@ foreign_relay_bps_limit = s:taboption("privacy", Value, "foreign_relay_bps_limit
.. "(--foreign-relay-bps-limit parameter)"))
foreign_relay_bps_limit:depends("etcmd", "etcmd")
extra_args = s:taboption("privacy", Value, "extra_args", translate("Extra Parameters"),
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 --udp-whitelist 53"
extra_args.placeholder = "--tcp-whitelist=80"
extra_args.validate = function(self, value, section)
if type(value) == "table" then
local seen = {}
local i
for i = 1, #value do
local arg = value[i]
if arg then
arg = tostring(arg):match("^%s*(.-)%s*$")
if arg ~= "" then
if seen[arg] then
return nil, translate("Duplicate extra parameter") .. ": " .. arg
end
seen[arg] = true
end
end
end
end
return value
end
extra_args:depends("etcmd", "etcmd")
log = s:taboption("general", ListValue, "log", translate("Program Log"),

View File

@ -370,6 +370,8 @@ local uci = require 'luci.model.uci'.cursor()
border-radius: 12px;
white-space: pre-wrap;
word-wrap: break-word;
overflow-wrap: anywhere;
word-break: break-word;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 13px;
color: var(--text-primary);
@ -377,6 +379,34 @@ local uci = require 'luci.model.uci'.cursor()
line-height: 1.5;
}
.et-command-panel {
position: relative;
}
.et-command-toolbar {
display: flex;
justify-content: flex-end;
margin-bottom: 8px;
}
.et-copy-btn {
display: inline-flex;
align-items: center;
padding: 5px 10px;
background: var(--tab-active);
color: #fff;
border: 1px solid var(--tab-active);
border-radius: 6px;
cursor: pointer;
font-size: 12px;
font-weight: 500;
line-height: 1.4;
}
.et-copy-btn:hover {
opacity: 0.9;
}
@media (max-width: 768px) {
.et-conninfo-header {
flex-direction: column;
@ -893,6 +923,50 @@ function escapeHtml(text) {
return div.innerHTML;
}
function copyTextFromElement(elementId, button) {
var el = document.getElementById(elementId);
if (!el) return;
var text = el.textContent || el.innerText || '';
function markCopied() {
if (!button) return;
var oldText = button.textContent;
button.textContent = '<%:Copied%>';
window.setTimeout(function() {
button.textContent = oldText;
}, 1500);
}
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(text).then(markCopied);
return;
}
var textarea = document.createElement('textarea');
textarea.value = text;
textarea.setAttribute('readonly', 'readonly');
textarea.style.position = 'fixed';
textarea.style.left = '-9999px';
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
markCopied();
} finally {
document.body.removeChild(textarea);
}
}
function renderCopyablePre(content, className) {
var id = 'et_copy_' + Math.random().toString(36).slice(2);
return '<div class="et-command-panel">' +
'<div class="et-command-toolbar">' +
'<button type="button" class="et-copy-btn" onclick="copyTextFromElement(\'' + id + '\', this); return false;"><%:Copy%></button>' +
'</div>' +
'<div id="' + id + '" class="' + (className || 'et-pre') + '">' + escapeHtml(content) + '</div>' +
'</div>';
}
function parseTable(content, tabName) {
if (!content || content.trim() === '') {
return '<div class="et-empty"><%:No data available%></div>';
@ -916,6 +990,47 @@ function parseTable(content, tabName) {
if (content.indexOf('Error: Invalid service name: "PeerCenterRpc"') !== -1) {
return '<div class="et-error"><%:Peer Center service not available. This feature requires multiple nodes in the network.%></div>';
}
// 启动参数可能包含管道符等特殊字符,必须先于表格解析处理。
if (tabName === 'cmdline') {
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);
}
}
});
}
return html;
}
// 连接失败错误处理
if (content.indexOf('failed to get peer manager client') !== -1 ||
@ -948,46 +1063,6 @@ function parseTable(content, tabName) {
var lines = content.split(/\r?\n/).filter(function(l) { return l.trim() !== ''; });
if (lines.length === 0 || lines[0].indexOf('|') === -1) {
// 启动参数不翻译
if (tabName === 'cmdline') {
var html = '<div class="et-pre">' + escapeHtml(content) + '</div>';
// 检查是否使用配置文件启动
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.wordBreak = 'break-all';
contentDiv.textContent = data.config_file;
configDiv.appendChild(title);
configDiv.appendChild(contentDiv);
var container = document.querySelector('.et-tab-content[data-tab="cmdline"]');
if (container) {
container.appendChild(configDiv);
}
}
});
}
return html;
}
// 对非表格内容进行全面翻译处理
var translatedContent = content;

View File

@ -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.2" style="display:none;width:100%;">
<input type="text" id="fallback_version" class="config-input" placeholder="v2.6.4" 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.2');
versionManager.setVersion(config.fallback_version || 'v2.6.4');
// 保存原始配置
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.2'
fallback_version: config.fallback_version || 'v2.6.4'
};
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.2'
fallback_version: versionManager.getCurrentVersion() || 'v2.6.4'
};
}
@ -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.2'
fallback_version: versionManager.getCurrentVersion() || 'v2.6.4'
};
var xhr = new XMLHttpRequest();

View File

@ -1403,3 +1403,12 @@ msgstr ""
msgid "GEOIP Database Path"
msgstr ""
msgid "Copy"
msgstr ""
msgid "Copied"
msgstr ""
msgid "Duplicate extra parameter"
msgstr ""

View File

@ -1267,6 +1267,15 @@ msgstr "统计数据"
msgid "Command Line"
msgstr "启动参数"
msgid "Copy"
msgstr "复制"
msgid "Copied"
msgstr "已复制"
msgid "Duplicate extra parameter"
msgstr "重复的额外参数"
msgid "IPv4 Address"
msgstr "IPv4地址"
@ -2098,4 +2107,3 @@ msgstr "数据库重置成功"
msgid "Restart service to apply changes?"
msgstr "重启服务以生效?"

View File

@ -5,3 +5,5 @@ config easytier
option auto_config_interface '1'
option auto_config_firewall '1'
option interface_netmask '255.0.0.0'
option web_enabled '0'
option webbin '/usr/bin/easytier-web'

View File

@ -71,6 +71,10 @@ get_tz() {
}
fi
shell_quote() {
printf "'%s'" "$(printf "%s" "$1" | sed "s/'/'\\\\''/g")"
}
check_bin() {
# 优先使用 UCI 配置的代理列表list 类型),否则使用默认值
local proxys=""
@ -103,10 +107,15 @@ check_bin() {
# 如果获取失败,从 UCI 配置或使用默认版本
if [ -z "$tag" ]; then
tag=$(uci -q get easytier.@easytier[0].fallback_version)
[ -z "$tag" ] && tag="v2.6.2"
[ -z "$tag" ] && tag="v2.6.4"
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
if ! command -v unzip >/dev/null 2>&1; then
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 系统缺少 unzip无法解压下载的 EasyTier 压缩包,请安装 unzip 后重试" >>/tmp/easytier.log
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 系统缺少 unzip无法解压下载的 EasyTier 压缩包,请安装 unzip 后重试" >>/tmp/easytierweb.log
return 1
fi
mkdir -p "$path"
for proxy in $proxys ; do
if curl -L -k -o /tmp/easytier.zip --connect-timeout 10 --retry 3 "${proxy}https://github.com/EasyTier/EasyTier/releases/download/${tag}/easytier-linux-${cpucore}-${tag}.zip" || \
@ -205,7 +214,6 @@ get_etconfig() {
quic_port="$(uci -q get easytier.@easytier[0].quic_port)"
peeradd="$(uci -q get easytier.@easytier[0].peeradd)"
desvice_name="$(uci -q get easytier.@easytier[0].desvice_name)"
[ -z "$desvice_name" ] || desvice_name=$(echo "$desvice_name" | sed 's/[\\$`"()|><&;]/\\&/g')
instance_name="$(uci -q get easytier.@easytier[0].instance_name)"
vpn_portal="$(uci -q get easytier.@easytier[0].vpn_portal)"
mtu="$(uci -q get easytier.@easytier[0].mtu)"
@ -442,8 +450,8 @@ start_et() {
core_cmd=""
if [ "$etcmd" = "etcmd" ] ; then
#默认方式启动
[ -z "$network_name" ] || core_cmd="${core_cmd} --network-name $network_name"
[ -z "$network_secret" ] || core_cmd="${core_cmd} --network-secret $network_secret"
[ -z "$network_name" ] || core_cmd="${core_cmd} --network-name $(shell_quote "$network_name")"
[ -z "$network_secret" ] || core_cmd="${core_cmd} --network-secret $(shell_quote "$network_secret")"
[ -z "$ipaddr" ] || core_cmd="${core_cmd} -i $ipaddr"
[ -z "$ip6addr" ] || core_cmd="${core_cmd} --ipv6 $ip6addr"
[ "$ip_dhcp" = "0" ] || core_cmd="${core_cmd} -d"
@ -524,7 +532,7 @@ start_et() {
[ -z "$quic_port" ] || core_cmd="${core_cmd} -l quic:$quic_port"
[ -z "$external_node" ] || core_cmd="${core_cmd} -e $external_node"
[ "$listenermode" = "ON" ] || core_cmd="${core_cmd} --no-listener"
[ -z "$desvice_name" ] || core_cmd="${core_cmd} --hostname $desvice_name"
[ -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"
[ -z "$mtu" ] || core_cmd="${core_cmd} --mtu $mtu"
@ -563,7 +571,13 @@ start_et() {
[ "$relay_kcp" = "0" ] || core_cmd="${core_cmd} --enable-relay-foreign-network-kcp 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"
[ -z "$extra_args" ] || core_cmd="${core_cmd} $extra_args"
if [ -n "$extra_args" ] ; then
while IFS= read -r extra_arg; do
[ -n "$extra_arg" ] && core_cmd="${core_cmd} $extra_arg"
done <<EOF
$(sed -n "s/^[[:space:]]*list[[:space:]]\\+extra_args[[:space:]]\\+'\\(.*\\)'[[:space:]]*$/\\1/p" /etc/config/easytier)
EOF
fi
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 运行 ${easytierbin} ${core_cmd} --console-log-level ${log}" >>/tmp/easytier.log
@ -580,7 +594,7 @@ start_et() {
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"
[ -z "$desvice_name" ] || core_cmd="${core_cmd} --hostname $desvice_name"
[ -z "$desvice_name" ] || core_cmd="${core_cmd} --hostname $(shell_quote "$desvice_name")"
fi
procd_set_param command /bin/sh -c "
cd /tmp ; ${easytierbin} ${core_cmd} --console-log-level ${log} >> /tmp/easytier.log 2>&1 &
@ -636,6 +650,7 @@ start_et() {
start_web() {
webbin="$(uci -q get easytier.@easytier[0].webbin)"
[ -z "$webbin" ] && webbin="/usr/bin/easytier-web" && uci -q set easytier.@easytier[0].webbin=/usr/bin/easytier-web
path=$(dirname "$webbin")
if [ -f /tmp/easytier-web-embed ] ; then
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 找到上传的easytier-web程序替换${webbin} " >>/tmp/easytierweb.log
@ -813,7 +828,7 @@ start_service() {
# 延迟重载网络配置,避免与拨号等网络事件冲突
if [ -n "$(uci changes network)" ] || [ -n "$(uci changes firewall)" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 检测到配置变更将在5秒后后台重载... " >>/tmp/easytier.log
echo "$(date '+%Y-%m-%d %H:%M:%S') easytier : 检测到配置变更将在5秒后后台重载网络、防火墙... " >>/tmp/easytier.log
(
sleep 5
# 使用锁文件防止重复重载
@ -891,4 +906,3 @@ service_triggers() {
#如果WAN网络接口上线则触发重新启动easytier
# procd_add_interface_trigger "interface.*.up" wan /etc/init.d/easytier reload
}

View File

@ -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.2
EASYTIER_VERSION=2.6.4

View File

@ -155,7 +155,6 @@ function update_adlist() {
}
if (download_failed) {
print("\x1b[1;31mRules download failed.\n");
exec_sys(`rm -rf "${ad_tmpdir}"`);
unlink(lock_file);
die("Rules download failed.");
@ -215,7 +214,6 @@ function update_geodat() {
let sum_downloaded = split(exec_sys(`sha256sum "${tmpdir}/geoip.dat"`).stdout, /[ \t\n]+/)[0];
if (sum_downloaded !== geoip_sum_remote) {
print("\x1b[1;31mgeoip.dat checksum error\n");
exec_sys(`rm -rf "${tmpdir}"`); die("geoip.dat checksum error");
}
geoip_updated = true;
@ -248,7 +246,6 @@ function update_geodat() {
let sum_downloaded = split(exec_sys(`sha256sum "${tmpdir}/geosite.dat"`).stdout, /[ \t\n]+/)[0];
if (sum_downloaded !== geosite_sum_remote) {
print("\x1b[1;31mgeosite.dat checksum error\n");
exec_sys(`rm -rf "${tmpdir}"`); die("geosite.dat checksum error");
}
geosite_updated = true;
@ -332,7 +329,7 @@ switch (action) {
print("UPDATE_FINISHED\n");
stdout.flush();
} catch (e) {
print("\x1b[1;31mUpdate failed: " + e + "\n\x1b[0m");
print("Update failed: " + e + "\n");
print("UPDATE_EXITED\n");
stdout.flush();
unlink('/var/lock/mosdns_update.lock');