diff --git a/Cargo.lock b/Cargo.lock index 080d959d1..c18416c52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1079,7 +1079,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "clash-verge" -version = "2.5.4" +version = "2.5.5" dependencies = [ "aes-gcm", "anyhow", diff --git a/Changelog.md b/Changelog.md index ec0d50ca4..fc1ca120a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,106 +1,14 @@ -## v2.5.4 +## v2.5.5
🐞 修复问题 -- 修复首页代理组和节点下拉菜单:再次点击无法收起或误选、小窗口显示不全、切换模式后意外展开 -- 修复系统代理切换失败后,开关状态显示错误的问题 -- 修复代理守卫失败后反复重试且没有提示的问题 -- 修复未开启系统代理时,启动仍提示代理错误的问题 -- 修复恢复备份后未按备份设置关闭系统代理的问题 -- 修复服务模式下操作超时后,后续操作报错或状态异常的问题 -- 修复部分节点显示「Unknown」或无法测试延迟的问题 -- 修复 `PASS-RULE` 节点被错误隐藏的问题 -- 修复重启内核后未恢复上次所选节点的问题 -- 修复部分代理组和首页图标无法显示、页面报错的问题 -- 修复同时修改端口、TUN 等设置时,部分修改丢失的问题 -- 修复 TUN 模式下 IPv6 Fake-IP 默认地址范围错误的问题 -- 修复切换节点时应用可能卡住的问题 -- 修复订阅文件被误删、删除或排序后列表异常的问题 -- 修复订阅自动更新失败无提示、重启后更新时间延后及状态误报的问题 -- 修复订阅编辑器因节点名称为空而崩溃、因格式错误而丢失内容的问题 -- 修复 DNS 编辑器空内容报错、初始值覆盖已有设置的问题 -- 修复关闭自动检查更新后,手动检查更新无效的问题 -- 修复应用冷启动或从轻量模式打开界面时, 系统代理被重复设置的问题 - -**🖥️ Windows** - -- 修复 Windows 管理员运行时,服务权限校验失败后无法继续使用代理的问题 -- 修复 Windows 便携版或 Scoop 安装后服务内核无法启动的问题 -- 修复 Windows 系统代理设置偶发失败的问题 -- 修复 Windows 关机被应用阻止的问题 -- 修复 Windows 服务模式下 TUN 使用 system/mixed 堆栈时无法接管流量的问题,防火墙放行规则改为自动添加 -- 修复 Windows 配置中 GEO 规则较多时,首次启动内核失败的问题 - -**🍎 macOS** - -- 修复 macOS 内核更新失败后无法启动的问题 -- 修复 macOS 需要管理员授权或开机自启时,系统代理设置失败的问题 -- 修复 macOS 切换显示器后托盘速率样式不同步的问题 - -**🐧 Linux** - -- 修复 Linux 安装或卸载服务时授权失败的问题 -- 修复 Fedora 等启用 SELinux 的系统更新后服务无法启动的问题 - -**🍎/🐧 macOS/Linux** - -- 修复 macOS/Linux 系统代理绕过规则未正确生效的问题 -- 修复 macOS/Linux 因旧版服务缓存权限异常而无法记住节点的问题 - -
- -
- ✨ 新增功能 - -- 新增混合代理端口自动避让,被占用时临时使用其他端口 -- 新增系统代理和 TUN 权限引导,可直接安装服务并恢复原设置 -- 新增服务模式多用户隔离,支持旧版服务升级迁移 -- 新增手动取消节点固定功能 -- 新增代理组标题栏拖动调整,可交换组名和工具栏的位置 -- 新增前置规则与后置规则互相移动功能 -- 新增 DNS 覆写保护:订阅含自定义 DNS 时先确认,订阅更新后自动关闭覆写 -- 新增代理页排查提示,方便检查订阅和内核状态 -- 新增订阅更新频率提醒,间隔不足 24 小时时提示 -- 新增启动失败提示,显示原因并保存启动日志 -- 新增 TUN「Mips」堆栈选项,需配合 mihomo v1.19.31 及以上内核 - -**🍎 macOS** - -- 新增 macOS Liquid Glass 风格图标 -- 新增 macOS 多用户启动保护,避免多个实例冲突 - -**🐧 Linux** - -- 新增 Linux 系统主题跟随,自动切换深浅色外观 +- 修复 DNS 覆写:空内容报错、初始值覆盖已有设置、已填写字段残留原配置、空字段在高级编辑器中缺失
🚀 优化改进 -- 优化首页节点菜单关闭时的刷新性能 -- 优化 TUN 配置优先级:界面设置优先,其他选项仍可通过订阅、覆写和脚本调整 -- 优化 DNS 覆写:仅覆盖已填写的字段和已开启的开关,留空或关闭的项保留订阅设置 -- 优化系统代理失败后的恢复流程,保持系统设置和界面状态一致 -- 优化错误提示,支持复制完整原因,托盘和快捷键操作失败时也会提醒 -- 优化代理列表刷新、排序和页面切换速度 -- 优化首页节点操作,显示节点固定状态 -- 优化外部链接检查,仅允许打开 HTTP/HTTPS 网页 -- 优化更新说明排版,支持表格和提示框 -- 优化搜索框聚焦、界面字体和拖动排序动画 -- 优化后台连接和托盘刷新,降低资源占用 -- 优化解锁检测,支持同时检测多个项目并逐项显示结果 -- 优化日志记录,减少重复信息 -- 移除便携模式,统一使用系统应用数据目录 -- 优化繁体中文、俄语翻译及语言名称显示 - -**🖥️ Windows** - -- 优化 Windows 自动更新,跳过安装语言选择 - -**🐧 Linux** - -- 优化 Linux 系统代理设置,减少额外命令依赖,并明确提示缺少的命令
diff --git a/docs/Changelog.history.md b/docs/Changelog.history.md index bd8026425..5a35fd3da 100644 --- a/docs/Changelog.history.md +++ b/docs/Changelog.history.md @@ -1,3 +1,97 @@ +## v2.5.4 + +- 修复首页代理组和节点下拉菜单:再次点击无法收起或误选、小窗口显示不全、切换模式后意外展开 +- 修复系统代理切换失败后,开关状态显示错误的问题 +- 修复代理守卫失败后反复重试且没有提示的问题 +- 修复未开启系统代理时,启动仍提示代理错误的问题 +- 修复恢复备份后未按备份设置关闭系统代理的问题 +- 修复服务模式下操作超时后,后续操作报错或状态异常的问题 +- 修复部分节点显示「Unknown」或无法测试延迟的问题 +- 修复 `PASS-RULE` 节点被错误隐藏的问题 +- 修复重启内核后未恢复上次所选节点的问题 +- 修复部分代理组和首页图标无法显示、页面报错的问题 +- 修复同时修改端口、TUN 等设置时,部分修改丢失的问题 +- 修复 TUN 模式下 IPv6 Fake-IP 默认地址范围错误的问题 +- 修复切换节点时应用可能卡住的问题 +- 修复订阅文件被误删、删除或排序后列表异常的问题 +- 修复订阅自动更新失败无提示、重启后更新时间延后及状态误报的问题 +- 修复订阅编辑器因节点名称为空而崩溃、因格式错误而丢失内容的问题 +- 修复 DNS 编辑器空内容报错、初始值覆盖已有设置的问题 +- 修复关闭自动检查更新后,手动检查更新无效的问题 +- 修复应用冷启动或从轻量模式打开界面时, 系统代理被重复设置的问题 + +**🖥️ Windows** + +- 修复 Windows 管理员运行时,服务权限校验失败后无法继续使用代理的问题 +- 修复 Windows 便携版或 Scoop 安装后服务内核无法启动的问题 +- 修复 Windows 系统代理设置偶发失败的问题 +- 修复 Windows 关机被应用阻止的问题 +- 修复 Windows 服务模式下 TUN 使用 system/mixed 堆栈时无法接管流量的问题,防火墙放行规则改为自动添加 +- 修复 Windows 配置中 GEO 规则较多时,首次启动内核失败的问题 + +**🍎 macOS** + +- 修复 macOS 内核更新失败后无法启动的问题 +- 修复 macOS 需要管理员授权或开机自启时,系统代理设置失败的问题 +- 修复 macOS 切换显示器后托盘速率样式不同步的问题 + +**🐧 Linux** + +- 修复 Linux 安装或卸载服务时授权失败的问题 +- 修复 Fedora 等启用 SELinux 的系统更新后服务无法启动的问题 + +**🍎/🐧 macOS/Linux** + +- 修复 macOS/Linux 系统代理绕过规则未正确生效的问题 +- 修复 macOS/Linux 因旧版服务缓存权限异常而无法记住节点的问题 + +- 新增混合代理端口自动避让,被占用时临时使用其他端口 +- 新增系统代理和 TUN 权限引导,可直接安装服务并恢复原设置 +- 新增服务模式多用户隔离,支持旧版服务升级迁移 +- 新增手动取消节点固定功能 +- 新增代理组标题栏拖动调整,可交换组名和工具栏的位置 +- 新增前置规则与后置规则互相移动功能 +- 新增 DNS 覆写保护:订阅含自定义 DNS 时先确认,订阅更新后自动关闭覆写 +- 新增代理页排查提示,方便检查订阅和内核状态 +- 新增订阅更新频率提醒,间隔不足 24 小时时提示 +- 新增启动失败提示,显示原因并保存启动日志 +- 新增 TUN「Mips」堆栈选项,需配合 mihomo v1.19.31 及以上内核 + +**🍎 macOS** + +- 新增 macOS Liquid Glass 风格图标 +- 新增 macOS 多用户启动保护,避免多个实例冲突 + +**🐧 Linux** + +- 新增 Linux 系统主题跟随,自动切换深浅色外观 + +- 优化首页节点菜单关闭时的刷新性能 +- 优化 TUN 配置优先级:界面设置优先,其他选项仍可通过订阅、覆写和脚本调整 +- 优化 DNS 覆写:仅覆盖已填写的字段和已开启的开关,留空或关闭的项保留订阅设置 +- 优化系统代理失败后的恢复流程,保持系统设置和界面状态一致 +- 优化错误提示,支持复制完整原因,托盘和快捷键操作失败时也会提醒 +- 优化代理列表刷新、排序和页面切换速度 +- 优化首页节点操作,显示节点固定状态 +- 优化外部链接检查,仅允许打开 HTTP/HTTPS 网页 +- 优化更新说明排版,支持表格和提示框 +- 优化搜索框聚焦、界面字体和拖动排序动画 +- 优化后台连接和托盘刷新,降低资源占用 +- 优化解锁检测,支持同时检测多个项目并逐项显示结果 +- 优化日志记录,减少重复信息 +- 移除便携模式,统一使用系统应用数据目录 +- 优化繁体中文、俄语翻译及语言名称显示 + +**🖥️ Windows** + +- 优化 Windows 自动更新,跳过安装语言选择 + +**🐧 Linux** + +- 优化 Linux 系统代理设置,减少额外命令依赖,并明确提示缺少的命令 + + + ## v2.5.2 ### 🐞 修复问题 diff --git a/package.json b/package.json index 890c85174..bc24d1485 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "clash-verge", - "version": "2.5.4", + "version": "2.5.5", "license": "GPL-3.0-only", "scripts": { "prepare": "husky || true", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5f114a521..4d3fc6fd3 100755 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clash-verge" -version = "2.5.4" +version = "2.5.5" description = "clash verge" authors = ["zzzgydi", "Tunglies", "wonfen", "MystiPanda"] license = "GPL-3.0-only" diff --git a/src-tauri/src/enhance/mod.rs b/src-tauri/src/enhance/mod.rs index c507164e3..c62aaf4d8 100644 --- a/src-tauri/src/enhance/mod.rs +++ b/src-tauri/src/enhance/mod.rs @@ -708,17 +708,9 @@ fn is_set(value: &Value) -> bool { } } -/// Overlay set fields onto base; maps merge per key, lists are leaves. +/// Configured DNS fields replace the whole value, including maps and lists. fn merge_set_fields(mut base: Mapping, overlay: Mapping) -> Mapping { for (key, value) in overlay { - let value = match (base.get_mut(&key), value) { - (Some(Value::Mapping(existing)), Value::Mapping(patch)) => { - *existing = merge_set_fields(std::mem::take(existing), patch); - continue; - } - (_, Value::Mapping(patch)) => Value::Mapping(merge_set_fields(Mapping::new(), patch)), - (_, value) => value, - }; if is_set(&value) { base.insert(key, value); } @@ -734,39 +726,45 @@ fn take_mapping(config: &mut Mapping, key: &str) -> Mapping { .unwrap_or_default() } -/// Returns the merged config and whether the page set `dns.ipv6`. -async fn apply_dns_settings(mut config: Mapping, enable_dns_settings: bool) -> (Mapping, bool) { +fn merge_dns_config(mut config: Mapping, mut dns_config: Mapping) -> (Mapping, bool) { let mut owns_ipv6 = false; + if let Some(Value::Mapping(hosts)) = dns_config.remove("hosts") + && !hosts.is_empty() + { + config.insert("hosts".into(), hosts.into()); + logging!(debug, Type::Core, "apply hosts configuration"); + } + + // Legacy layout: no `dns` root. + let dns_override = match dns_config.remove("dns") { + Some(Value::Mapping(dns)) => Some(dns), + Some(_) => None, + None => Some(dns_config), + }; + if let Some(dns_override) = dns_override { + owns_ipv6 = dns_override.get("ipv6").is_some_and(is_set); + let mut dns = merge_set_fields(take_mapping(&mut config, "dns"), dns_override); + ensure_fake_ip_range6(&mut dns); + config.insert("dns".into(), dns.into()); + logging!(debug, Type::Core, "apply dns_config.yaml"); + } + (config, owns_ipv6) +} + +/// Returns the merged config and whether the page set `dns.ipv6`. +async fn apply_dns_settings(config: Mapping, enable_dns_settings: bool) -> (Mapping, bool) { if enable_dns_settings && let Ok(app_dir) = dirs::app_home_dir() { let dns_path = app_dir.join(constants::files::DNS_CONFIG); if dns_path.exists() && let Ok(dns_yaml) = fs::read_to_string(&dns_path).await - && let Ok(mut dns_config) = serde_yaml_ng::from_str::(&dns_yaml) + && let Ok(dns_config) = serde_yaml_ng::from_str::(&dns_yaml) { - if let Some(Value::Mapping(hosts)) = dns_config.remove("hosts") { - let hosts = merge_set_fields(take_mapping(&mut config, "hosts"), hosts); - config.insert("hosts".into(), hosts.into()); - logging!(debug, Type::Core, "apply hosts configuration"); - } - - // Legacy layout: no `dns` root. - let dns_override = match dns_config.remove("dns") { - Some(Value::Mapping(dns)) => Some(dns), - Some(_) => None, - None => Some(dns_config), - }; - if let Some(dns_override) = dns_override { - owns_ipv6 = dns_override.get("ipv6").is_some_and(is_set); - let mut dns = merge_set_fields(take_mapping(&mut config, "dns"), dns_override); - ensure_fake_ip_range6(&mut dns); - config.insert("dns".into(), dns.into()); - logging!(debug, Type::Core, "apply dns_config.yaml"); - } + return merge_dns_config(config, dns_config); } } - (config, owns_ipv6) + (config, false) } /// Returns the enhanced profile, its original keys, script logs, and DNS override decision. diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 84b3c1916..c060624c0 100755 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,5 +1,5 @@ { - "version": "2.5.4", + "version": "2.5.5", "$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "bundle": { "active": true, diff --git a/src/components/setting/mods/dns-viewer.tsx b/src/components/setting/mods/dns-viewer.tsx index 5ffe6e101..c4cd75951 100644 --- a/src/components/setting/mods/dns-viewer.tsx +++ b/src/components/setting/mods/dns-viewer.tsx @@ -346,6 +346,7 @@ export function DnsViewer({ ref }: { ref?: Ref }) { 'fake-ip-filter': parseList(values.fakeIpFilter), 'default-nameserver': parseList(values.defaultNameserver), nameserver: parseList(values.nameserver), + 'nameserver-policy': parseNameserverPolicy(values.nameserverPolicy), 'direct-nameserver-follow-policy': values.directNameserverFollowPolicy, 'fallback-filter': { geoip: values.fallbackGeoip, @@ -359,11 +360,6 @@ export function DnsViewer({ ref }: { ref?: Ref }) { 'direct-nameserver': parseList(values.directNameserver), } - const policy = parseNameserverPolicy(values.nameserverPolicy) - if (Object.keys(policy).length > 0) { - dnsConfig['nameserver-policy'] = policy - } - return dnsConfig }, [values]) @@ -375,10 +371,7 @@ export function DnsViewer({ ref }: { ref?: Ref }) { config.dns = dnsConfig } - const hosts = parseHosts(values.hosts) - if (Object.keys(hosts).length > 0) { - config.hosts = hosts - } + config.hosts = parseHosts(values.hosts) setYamlContent(yaml.dump(config, { forceQuotes: true })) }, [generateDnsConfig, values.hosts]) @@ -507,10 +500,7 @@ export function DnsViewer({ ref }: { ref?: Ref }) { config.dns = dnsConfig } - const hosts = parseHosts(values.hosts) - if (Object.keys(hosts).length > 0) { - config.hosts = hosts - } + config.hosts = parseHosts(values.hosts) } else { const parsedConfig = yaml.load(yamlContent) if (typeof parsedConfig !== 'object' || parsedConfig === null) {