525 lines
18 KiB
Dart
525 lines
18 KiB
Dart
import 'dart:io';
|
||
import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
|
||
import 'package:kaer_with_panels/app/utils/kr_windows_process_util.dart';
|
||
|
||
/// Windows DNS 管理工具类
|
||
///
|
||
/// 用于在 Windows 平台上管理系统 DNS 设置
|
||
/// 主要功能:
|
||
/// 1. 备份原始 DNS 设置
|
||
/// 2. 恢复 DNS 设置
|
||
/// 3. 兜底设置为国内公共 DNS (223.5.5.5 和 114.114.114.114)
|
||
class KRWindowsDnsUtil {
|
||
/// 私有构造函数
|
||
KRWindowsDnsUtil._();
|
||
|
||
/// 单例实例
|
||
static final KRWindowsDnsUtil _instance = KRWindowsDnsUtil._();
|
||
|
||
/// 工厂构造函数
|
||
factory KRWindowsDnsUtil() => _instance;
|
||
|
||
/// 获取实例的静态方法
|
||
static KRWindowsDnsUtil get instance => _instance;
|
||
|
||
/// 原始 DNS 服务器地址(连接前备份)
|
||
List<String>? _originalDnsServers;
|
||
|
||
/// 主网络接口名称
|
||
String? _primaryInterfaceName;
|
||
|
||
/// 备份当前 DNS 设置
|
||
///
|
||
/// 在连接 VPN 之前调用,保存原始 DNS 配置
|
||
/// 返回:true-成功,false-失败
|
||
Future<bool> kr_backupDnsSettings() async {
|
||
if (!Platform.isWindows) {
|
||
KRLogUtil.kr_w('❌ 非 Windows 平台,跳过 DNS 备份', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
// 🔒 添加5秒超时保护
|
||
return await Future.value(() async {
|
||
KRLogUtil.kr_i('📦 开始备份 Windows DNS 设置...', tag: 'WindowsDNS');
|
||
|
||
// 1. 获取主网络接口
|
||
final interfaceName = await _kr_getPrimaryNetworkInterface();
|
||
if (interfaceName == null) {
|
||
KRLogUtil.kr_e('❌ 无法获取主网络接口', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
_primaryInterfaceName = interfaceName;
|
||
KRLogUtil.kr_i('🔍 主网络接口: $_primaryInterfaceName', tag: 'WindowsDNS');
|
||
|
||
// 2. 获取当前 DNS 服务器
|
||
final dnsServers = await _kr_getCurrentDnsServers(interfaceName);
|
||
|
||
// 🔧 P0修复1: 过滤掉 127.0.0.1 (sing-box 的本地 DNS)
|
||
// 原因:如果备份了 127.0.0.1,关闭 VPN 后恢复为 127.0.0.1,但 sing-box 已停止,导致 DNS 无法解析
|
||
final validDnsServers = dnsServers.where((dns) => !dns.startsWith('127.')).toList();
|
||
|
||
if (validDnsServers.isEmpty) {
|
||
KRLogUtil.kr_w('⚠️ 当前 DNS 为空或全是本地地址,设为 DHCP 自动获取', tag: 'WindowsDNS');
|
||
if (dnsServers.isNotEmpty) {
|
||
KRLogUtil.kr_i(' (已过滤的本地DNS: ${dnsServers.join(", ")})', tag: 'WindowsDNS');
|
||
}
|
||
_originalDnsServers = []; // 空列表表示 DHCP 自动获取
|
||
} else {
|
||
_originalDnsServers = validDnsServers;
|
||
KRLogUtil.kr_i('✅ 已备份有效 DNS: ${validDnsServers.join(", ")}', tag: 'WindowsDNS');
|
||
if (dnsServers.length != validDnsServers.length) {
|
||
KRLogUtil.kr_i(' (已过滤掉 ${dnsServers.length - validDnsServers.length} 个本地地址)', tag: 'WindowsDNS');
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}()).timeout(
|
||
const Duration(seconds: 5),
|
||
onTimeout: () {
|
||
KRLogUtil.kr_w('⏱️ DNS 备份操作超时(5秒),跳过备份', tag: 'WindowsDNS');
|
||
return false;
|
||
},
|
||
);
|
||
} catch (e) {
|
||
KRLogUtil.kr_e('❌ 备份 DNS 设置失败: $e', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// 恢复原始 DNS 设置
|
||
///
|
||
/// 在断开 VPN 后调用,恢复备份的 DNS 配置
|
||
/// 如果恢复失败,会自动调用兜底机制设置为公共DNS
|
||
/// 返回:true-成功,false-失败
|
||
Future<bool> kr_restoreDnsSettings() async {
|
||
if (!Platform.isWindows) {
|
||
KRLogUtil.kr_w('❌ 非 Windows 平台,跳过 DNS 恢复', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
KRLogUtil.kr_i('🔄 开始恢复 Windows DNS 设置...', tag: 'WindowsDNS');
|
||
|
||
// 🔧 P1修复: 恢复时重新检测主接口,防止网络切换导致恢复错误接口
|
||
final currentInterface = await _kr_getPrimaryNetworkInterface();
|
||
if (currentInterface == null) {
|
||
KRLogUtil.kr_e('❌ 无法检测当前网络接口,执行兜底恢复', tag: 'WindowsDNS');
|
||
return await _kr_fallbackRestoreDns();
|
||
}
|
||
|
||
// 检查接口是否变化
|
||
if (_primaryInterfaceName != null && _primaryInterfaceName != currentInterface) {
|
||
KRLogUtil.kr_w('⚠️ 网络接口已变化: $_primaryInterfaceName → $currentInterface', tag: 'WindowsDNS');
|
||
KRLogUtil.kr_w(' 执行兜底恢复以确保当前接口DNS正常', tag: 'WindowsDNS');
|
||
_primaryInterfaceName = currentInterface; // 更新为当前接口
|
||
return await _kr_fallbackRestoreDns();
|
||
}
|
||
|
||
// 使用当前检测到的接口
|
||
_primaryInterfaceName = currentInterface;
|
||
KRLogUtil.kr_i('🔍 当前网络接口: $_primaryInterfaceName', tag: 'WindowsDNS');
|
||
|
||
// 1. 检查是否有备份的DNS
|
||
if (_originalDnsServers == null) {
|
||
KRLogUtil.kr_w('⚠️ 没有备份的 DNS,执行兜底恢复', tag: 'WindowsDNS');
|
||
return await _kr_fallbackRestoreDns();
|
||
}
|
||
|
||
// 2. 恢复原始 DNS
|
||
|
||
if (_originalDnsServers!.isEmpty) {
|
||
// 原本是 DHCP 自动获取
|
||
KRLogUtil.kr_i('🔄 恢复为 DHCP 自动获取 DNS', tag: 'WindowsDNS');
|
||
final success = await _kr_setDnsToAuto(_primaryInterfaceName!);
|
||
if (!success) {
|
||
KRLogUtil.kr_w('⚠️ 恢复 DHCP 失败,执行兜底恢复', tag: 'WindowsDNS');
|
||
return await _kr_fallbackRestoreDns();
|
||
}
|
||
} else {
|
||
// 恢复指定的 DNS 服务器
|
||
KRLogUtil.kr_i('🔄 恢复原始 DNS: ${_originalDnsServers!.join(", ")}', tag: 'WindowsDNS');
|
||
final success = await _kr_setDnsServers(
|
||
_primaryInterfaceName!,
|
||
_originalDnsServers!,
|
||
);
|
||
if (!success) {
|
||
KRLogUtil.kr_w('⚠️ 恢复原始 DNS 失败,执行兜底恢复', tag: 'WindowsDNS');
|
||
return await _kr_fallbackRestoreDns();
|
||
}
|
||
}
|
||
|
||
// 3. 验证 DNS 是否恢复成功
|
||
await Future.delayed(const Duration(milliseconds: 500));
|
||
final currentDns = await _kr_getCurrentDnsServers(_primaryInterfaceName!);
|
||
KRLogUtil.kr_i('✅ 当前 DNS: ${currentDns.join(", ")}', tag: 'WindowsDNS');
|
||
|
||
// 4. 额外验证:确认 DNS 不再指向 127.0.0.1(sing-box 的本地 DNS)
|
||
final hasLocalhost = currentDns.any((dns) => dns.startsWith('127.'));
|
||
if (hasLocalhost) {
|
||
KRLogUtil.kr_w('⚠️ DNS 仍包含 127.0.0.1,可能未完全恢复', tag: 'WindowsDNS');
|
||
KRLogUtil.kr_w('⚠️ 执行兜底恢复', tag: 'WindowsDNS');
|
||
return await _kr_fallbackRestoreDns();
|
||
}
|
||
|
||
// 🔧 P2优化: 测试 DNS 解析是否真正可用
|
||
KRLogUtil.kr_i('🧪 测试 DNS 解析功能...', tag: 'WindowsDNS');
|
||
final canResolve = await _kr_testDnsResolution();
|
||
if (!canResolve) {
|
||
KRLogUtil.kr_w('⚠️ DNS 解析测试失败,执行兜底恢复', tag: 'WindowsDNS');
|
||
return await _kr_fallbackRestoreDns();
|
||
}
|
||
KRLogUtil.kr_i('✅ DNS 解析测试通过', tag: 'WindowsDNS');
|
||
|
||
return true;
|
||
} catch (e) {
|
||
KRLogUtil.kr_e('❌ 恢复 DNS 设置失败: $e', tag: 'WindowsDNS');
|
||
KRLogUtil.kr_w('⚠️ 执行兜底恢复', tag: 'WindowsDNS');
|
||
return await _kr_fallbackRestoreDns();
|
||
}
|
||
}
|
||
|
||
/// 兜底恢复:强制设置为国内公共 DNS
|
||
///
|
||
/// 当正常恢复失败时,设置为安全的公共 DNS 服务器
|
||
/// - 主 DNS: 223.5.5.5 (阿里云)
|
||
/// - 备用 DNS: 114.114.114.114 (114DNS)
|
||
Future<bool> _kr_fallbackRestoreDns() async {
|
||
try {
|
||
KRLogUtil.kr_w('🆘 执行 DNS 兜底恢复机制', tag: 'WindowsDNS');
|
||
KRLogUtil.kr_i('🔧 设置为国内公共 DNS: 223.5.5.5, 114.114.114.114', tag: 'WindowsDNS');
|
||
|
||
// 1. 获取主网络接口(如果还没有)
|
||
if (_primaryInterfaceName == null) {
|
||
_primaryInterfaceName = await _kr_getPrimaryNetworkInterface();
|
||
if (_primaryInterfaceName == null) {
|
||
KRLogUtil.kr_e('❌ 无法检测网络接口,兜底恢复失败', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 2. 设置为公共 DNS
|
||
final fallbackDns = ['223.5.5.5', '114.114.114.114'];
|
||
final success = await _kr_setDnsServers(_primaryInterfaceName!, fallbackDns);
|
||
|
||
if (success) {
|
||
KRLogUtil.kr_i('✅ 兜底 DNS 设置成功', tag: 'WindowsDNS');
|
||
|
||
// 3. 验证设置
|
||
await Future.delayed(const Duration(milliseconds: 500));
|
||
final currentDns = await _kr_getCurrentDnsServers(_primaryInterfaceName!);
|
||
KRLogUtil.kr_i('✅ 验证当前 DNS: ${currentDns.join(", ")}', tag: 'WindowsDNS');
|
||
|
||
return true;
|
||
} else {
|
||
KRLogUtil.kr_e('❌ 兜底 DNS 设置失败', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
} catch (e) {
|
||
KRLogUtil.kr_e('❌ 兜底恢复失败: $e', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// 获取主网络接口名称
|
||
///
|
||
/// 通过 netsh 命令查找处于"已连接"状态的主网络接口
|
||
/// 返回:接口名称,失败返回 null
|
||
Future<String?> _kr_getPrimaryNetworkInterface() async {
|
||
try {
|
||
// 使用 netsh 获取接口列表
|
||
final result = await KRWindowsProcessUtil.runHidden('netsh', ['interface', 'show', 'interface']);
|
||
|
||
if (result.exitCode != 0) {
|
||
KRLogUtil.kr_e('❌ 获取网络接口失败: ${result.stderr}', tag: 'WindowsDNS');
|
||
return null;
|
||
}
|
||
|
||
final output = result.stdout.toString();
|
||
final lines = output.split('\n');
|
||
|
||
// 收集所有已连接的接口
|
||
final connectedInterfaces = <String>[];
|
||
|
||
// 查找所有"已连接"的接口
|
||
// 支持中文和英文 Windows 系统
|
||
for (var line in lines) {
|
||
// 中文: "已连接", 英文: "Connected", "Enabled"
|
||
if (line.contains('已连接') ||
|
||
line.contains('Connected') ||
|
||
line.toLowerCase().contains('enabled')) {
|
||
// 跳过表头行
|
||
if (line.contains('Admin') ||
|
||
line.contains('管理') ||
|
||
line.contains('State') ||
|
||
line.contains('状态')) {
|
||
continue;
|
||
}
|
||
|
||
// 解析接口名称(最后一列)
|
||
final parts = line.trim().split(RegExp(r'\s{2,}'));
|
||
if (parts.length >= 4) {
|
||
final interfaceName = parts.last.trim();
|
||
// 排除空接口名
|
||
if (interfaceName.isNotEmpty && interfaceName.length > 1) {
|
||
connectedInterfaces.add(interfaceName);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (connectedInterfaces.isEmpty) {
|
||
KRLogUtil.kr_w('⚠️ 未找到已连接的网络接口', tag: 'WindowsDNS');
|
||
return null;
|
||
}
|
||
|
||
// 🔧 优化:优先选择有线网络(以太网),然后才是 Wi-Fi
|
||
// 有线网络通常更稳定
|
||
String? selectedInterface;
|
||
for (var interface in connectedInterfaces) {
|
||
final lowerName = interface.toLowerCase();
|
||
// 优先选择以太网
|
||
if (lowerName.contains('ethernet') ||
|
||
lowerName.contains('以太网') ||
|
||
lowerName.contains('lan') ||
|
||
lowerName.contains('local')) {
|
||
selectedInterface = interface;
|
||
KRLogUtil.kr_i('🔍 选择有线网络接口: $interface', tag: 'WindowsDNS');
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 如果没有有线网络,选择第一个(通常是 Wi-Fi)
|
||
selectedInterface ??= connectedInterfaces.first;
|
||
if (selectedInterface != connectedInterfaces.first) {
|
||
KRLogUtil.kr_d('🔍 选择网络接口: $selectedInterface', tag: 'WindowsDNS');
|
||
} else {
|
||
KRLogUtil.kr_i('🔍 选择网络接口: $selectedInterface', tag: 'WindowsDNS');
|
||
}
|
||
|
||
return selectedInterface;
|
||
} catch (e) {
|
||
KRLogUtil.kr_e('❌ 获取网络接口异常: $e', tag: 'WindowsDNS');
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// 获取指定接口的当前 DNS 服务器
|
||
///
|
||
/// 参数:
|
||
/// - interfaceName: 网络接口名称
|
||
///
|
||
/// 返回:DNS 服务器列表
|
||
Future<List<String>> _kr_getCurrentDnsServers(String interfaceName) async {
|
||
try {
|
||
final result = await KRWindowsProcessUtil.runHidden('netsh', [
|
||
'interface',
|
||
'ipv4',
|
||
'show',
|
||
'dnsservers',
|
||
'name="$interfaceName"',
|
||
]);
|
||
|
||
if (result.exitCode != 0) {
|
||
KRLogUtil.kr_e('❌ 获取 DNS 失败: ${result.stderr}', tag: 'WindowsDNS');
|
||
return [];
|
||
}
|
||
|
||
final output = result.stdout.toString();
|
||
final dnsServers = <String>[];
|
||
|
||
// 解析 DNS 服务器地址
|
||
final lines = output.split('\n');
|
||
for (var line in lines) {
|
||
// 查找 IP 地址格式的行
|
||
final ipMatch = RegExp(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b').firstMatch(line);
|
||
if (ipMatch != null) {
|
||
final ip = ipMatch.group(0)!;
|
||
// 🔧 关键修复:不过滤127.0.0.1,以便正确检测DNS是否还在使用sing-box的本地DNS
|
||
// 这样在恢复DNS时,第126行的验证才能正确检测到127.0.0.1并触发兜底恢复
|
||
dnsServers.add(ip);
|
||
}
|
||
}
|
||
|
||
KRLogUtil.kr_d('🔍 当前 DNS: ${dnsServers.join(", ")}', tag: 'WindowsDNS');
|
||
return dnsServers;
|
||
} catch (e) {
|
||
KRLogUtil.kr_e('❌ 获取 DNS 异常: $e', tag: 'WindowsDNS');
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/// 设置指定接口的 DNS 服务器
|
||
///
|
||
/// 参数:
|
||
/// - interfaceName: 网络接口名称
|
||
/// - dnsServers: DNS 服务器列表
|
||
///
|
||
/// 返回:true-成功,false-失败
|
||
Future<bool> _kr_setDnsServers(String interfaceName, List<String> dnsServers) async {
|
||
try {
|
||
if (dnsServers.isEmpty) {
|
||
KRLogUtil.kr_w('⚠️ DNS 列表为空,无法设置', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
|
||
// 1. 设置主 DNS
|
||
KRLogUtil.kr_i('🔧 设置主 DNS: ${dnsServers[0]}', tag: 'WindowsDNS');
|
||
var result = await KRWindowsProcessUtil.runHidden('netsh', [
|
||
'interface',
|
||
'ipv4',
|
||
'set',
|
||
'dnsservers',
|
||
'name="$interfaceName"',
|
||
'source=static',
|
||
'address=${dnsServers[0]}',
|
||
'validate=no',
|
||
]);
|
||
|
||
if (result.exitCode != 0) {
|
||
KRLogUtil.kr_e('❌ 设置主 DNS 失败: ${result.stderr}', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
|
||
// 2. 设置备用 DNS(如果有)
|
||
if (dnsServers.length > 1) {
|
||
for (int i = 1; i < dnsServers.length; i++) {
|
||
KRLogUtil.kr_i('🔧 设置备用 DNS ${i}: ${dnsServers[i]}', tag: 'WindowsDNS');
|
||
result = await KRWindowsProcessUtil.runHidden('netsh', [
|
||
'interface',
|
||
'ipv4',
|
||
'add',
|
||
'dnsservers',
|
||
'name="$interfaceName"',
|
||
'address=${dnsServers[i]}',
|
||
'index=${i + 1}',
|
||
'validate=no',
|
||
]);
|
||
|
||
if (result.exitCode != 0) {
|
||
KRLogUtil.kr_w('⚠️ 设置备用 DNS $i 失败: ${result.stderr}', tag: 'WindowsDNS');
|
||
// 继续设置下一个,不中断
|
||
}
|
||
}
|
||
}
|
||
|
||
// 3. 刷新 DNS 缓存
|
||
await _kr_flushDnsCache();
|
||
|
||
KRLogUtil.kr_i('✅ DNS 服务器设置完成', tag: 'WindowsDNS');
|
||
return true;
|
||
} catch (e) {
|
||
KRLogUtil.kr_e('❌ 设置 DNS 异常: $e', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// 设置 DNS 为自动获取(DHCP)
|
||
///
|
||
/// 参数:
|
||
/// - interfaceName: 网络接口名称
|
||
///
|
||
/// 返回:true-成功,false-失败
|
||
Future<bool> _kr_setDnsToAuto(String interfaceName) async {
|
||
try {
|
||
KRLogUtil.kr_i('🔧 设置 DNS 为自动获取 (DHCP)', tag: 'WindowsDNS');
|
||
|
||
final result = await KRWindowsProcessUtil.runHidden('netsh', [
|
||
'interface',
|
||
'ipv4',
|
||
'set',
|
||
'dnsservers',
|
||
'name="$interfaceName"',
|
||
'source=dhcp',
|
||
]);
|
||
|
||
if (result.exitCode != 0) {
|
||
KRLogUtil.kr_e('❌ 设置 DHCP 失败: ${result.stderr}', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
|
||
// 刷新 DNS 缓存
|
||
await _kr_flushDnsCache();
|
||
|
||
KRLogUtil.kr_i('✅ DNS 已设置为自动获取', tag: 'WindowsDNS');
|
||
return true;
|
||
} catch (e) {
|
||
KRLogUtil.kr_e('❌ 设置 DHCP 异常: $e', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// 刷新 DNS 缓存
|
||
///
|
||
/// 执行 ipconfig /flushdns 命令清空 DNS 解析缓存
|
||
Future<void> _kr_flushDnsCache() async {
|
||
try {
|
||
KRLogUtil.kr_i('🔄 刷新 DNS 缓存...', tag: 'WindowsDNS');
|
||
|
||
final result = await KRWindowsProcessUtil.runHidden('ipconfig', ['/flushdns']);
|
||
|
||
if (result.exitCode == 0) {
|
||
KRLogUtil.kr_i('✅ DNS 缓存已刷新', tag: 'WindowsDNS');
|
||
} else {
|
||
KRLogUtil.kr_w('⚠️ 刷新 DNS 缓存失败: ${result.stderr}', tag: 'WindowsDNS');
|
||
}
|
||
} catch (e) {
|
||
KRLogUtil.kr_w('⚠️ 刷新 DNS 缓存异常: $e', tag: 'WindowsDNS');
|
||
}
|
||
}
|
||
|
||
/// 🔧 P2优化: 测试 DNS 解析是否真正可用
|
||
///
|
||
/// 通过 nslookup 测试常见域名解析
|
||
/// 返回:true 表示 DNS 可用,false 表示 DNS 不可用
|
||
Future<bool> _kr_testDnsResolution() async {
|
||
try {
|
||
// 测试多个常见域名,提高成功率
|
||
final testDomains = ['www.baidu.com', 'www.qq.com', 'dns.alidns.com'];
|
||
|
||
for (var domain in testDomains) {
|
||
try {
|
||
// 使用 nslookup 测试 DNS 解析,设置 2 秒超时
|
||
final result = await KRWindowsProcessUtil.runHidden(
|
||
'nslookup',
|
||
[domain],
|
||
).timeout(
|
||
const Duration(seconds: 2),
|
||
onTimeout: () {
|
||
return ProcessResult(0, 1, '', 'Timeout');
|
||
},
|
||
);
|
||
|
||
if (result.exitCode == 0) {
|
||
final output = result.stdout.toString();
|
||
// 检查输出是否包含 IP 地址(简单验证)
|
||
if (output.contains('Address:') || output.contains('地址:')) {
|
||
KRLogUtil.kr_i('✅ DNS 解析测试通过: $domain', tag: 'WindowsDNS');
|
||
return true;
|
||
}
|
||
}
|
||
} catch (e) {
|
||
// 单个域名失败,继续测试下一个
|
||
continue;
|
||
}
|
||
}
|
||
|
||
// 所有域名都解析失败
|
||
KRLogUtil.kr_w('⚠️ 所有测试域名解析均失败', tag: 'WindowsDNS');
|
||
return false;
|
||
} catch (e) {
|
||
KRLogUtil.kr_e('❌ DNS 解析测试异常: $e', tag: 'WindowsDNS');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// 清除备份数据
|
||
///
|
||
/// 在应用退出或不需要时调用
|
||
void kr_clearBackup() {
|
||
_originalDnsServers = null;
|
||
_primaryInterfaceName = null;
|
||
KRLogUtil.kr_d('🗑️ 已清除 DNS 备份数据', tag: 'WindowsDNS');
|
||
}
|
||
}
|