refactor: restructure DNS setting logic

This commit is contained in:
wonfen
2025-03-08 11:25:00 +08:00
parent eddcf209c1
commit e27a32395a
10 changed files with 404 additions and 69 deletions

View File

@@ -77,3 +77,142 @@ pub async fn clash_api_get_proxy_delay(
pub async fn test_delay(url: String) -> CmdResult<u32> {
Ok(feat::test_delay(url).await.unwrap_or(10000u32))
}
/// 保存DNS配置到单独文件
#[tauri::command]
pub async fn save_dns_config(dns_config: Mapping) -> CmdResult {
use crate::utils::dirs;
use serde_yaml;
use std::fs;
// 获取DNS配置文件路径
let dns_path = dirs::app_home_dir().map_err(|e| e.to_string())?
.join("dns_config.yaml");
// 保存DNS配置到文件
let yaml_str = serde_yaml::to_string(&dns_config).map_err(|e| e.to_string())?;
fs::write(&dns_path, yaml_str).map_err(|e| e.to_string())?;
log::info!(target: "app", "DNS config saved to {:?}", dns_path);
Ok(())
}
/// 应用或撤销DNS配置
#[tauri::command]
pub fn apply_dns_config(apply: bool) -> CmdResult {
use crate::utils::dirs;
use crate::core::{handle, CoreManager};
use crate::config::Config;
use tauri::async_runtime;
// 使用spawn来处理异步操作
async_runtime::spawn(async move {
if apply {
// 读取DNS配置文件
let dns_path = match dirs::app_home_dir() {
Ok(path) => path.join("dns_config.yaml"),
Err(e) => {
log::error!(target: "app", "Failed to get home dir: {}", e);
return;
}
};
if !dns_path.exists() {
log::warn!(target: "app", "DNS config file not found");
return;
}
let dns_yaml = match std::fs::read_to_string(&dns_path) {
Ok(content) => content,
Err(e) => {
log::error!(target: "app", "Failed to read DNS config: {}", e);
return;
}
};
// 解析DNS配置并创建patch
let patch_config = match serde_yaml::from_str::<serde_yaml::Mapping>(&dns_yaml) {
Ok(config) => {
let mut patch = serde_yaml::Mapping::new();
patch.insert("dns".into(), config.into());
patch
},
Err(e) => {
log::error!(target: "app", "Failed to parse DNS config: {}", e);
return;
}
};
log::info!(target: "app", "Applying DNS config from file");
// 重新生成配置确保DNS配置被正确应用
// 这里不调用patch_clash以避免将DNS配置写入config.yaml
Config::runtime().latest().patch_config(patch_config.clone());
// 首先重新生成配置
if let Err(err) = Config::generate().await {
log::error!(target: "app", "Failed to regenerate config with DNS: {}", err);
return;
}
// 然后应用新配置
if let Err(err) = CoreManager::global().update_config().await {
log::error!(target: "app", "Failed to apply config with DNS: {}", err);
} else {
log::info!(target: "app", "DNS config successfully applied");
handle::Handle::refresh_clash();
}
} else {
// 当关闭DNS设置时不需要对配置进行任何修改
// 直接重新生成配置让enhance函数自动跳过DNS配置的加载
log::info!(target: "app", "DNS settings disabled, regenerating config");
// 重新生成配置
if let Err(err) = Config::generate().await {
log::error!(target: "app", "Failed to regenerate config: {}", err);
return;
}
// 应用新配置
match CoreManager::global().update_config().await {
Ok(_) => {
log::info!(target: "app", "Config regenerated successfully");
handle::Handle::refresh_clash();
},
Err(err) => {
log::error!(target: "app", "Failed to apply regenerated config: {}", err);
}
}
}
});
Ok(())
}
/// 检查DNS配置文件是否存在
#[tauri::command]
pub fn check_dns_config_exists() -> CmdResult<bool> {
use crate::utils::dirs;
let dns_path = dirs::app_home_dir().map_err(|e| e.to_string())?
.join("dns_config.yaml");
Ok(dns_path.exists())
}
/// 获取DNS配置文件内容
#[tauri::command]
pub async fn get_dns_config_content() -> CmdResult<String> {
use crate::utils::dirs;
use std::fs;
let dns_path = dirs::app_home_dir().map_err(|e| e.to_string())?
.join("dns_config.yaml");
if !dns_path.exists() {
return Err("DNS config file not found".into());
}
let content = fs::read_to_string(&dns_path).map_err(|e| e.to_string())?;
Ok(content)
}

View File

@@ -38,56 +38,7 @@ impl IClashTemp {
tun.insert("strict-route".into(), false.into());
tun.insert("auto-detect-interface".into(), true.into());
tun.insert("dns-hijack".into(), vec!["any:53"].into());
// 添加默认的DNS配置
let mut dns = Mapping::new();
dns.insert("enable".into(), true.into());
dns.insert("listen".into(), ":53".into());
dns.insert("enhanced-mode".into(), "fake-ip".into());
dns.insert("fake-ip-range".into(), "198.18.0.1/16".into());
dns.insert("fake-ip-filter-mode".into(), "blacklist".into());
dns.insert("prefer-h3".into(), false.into());
dns.insert("respect-rules".into(), false.into());
dns.insert("use-hosts".into(), false.into());
dns.insert("use-system-hosts".into(), false.into());
// 添加fake-ip-filter
dns.insert("fake-ip-filter".into(), vec![
"*.lan", "*.local", "*.arpa", "time.*.com", "ntp.*.com", "time.*.com",
"+.market.xiaomi.com", "localhost.ptlogin2.qq.com", "*.msftncsi.com", "www.msftconnecttest.com"
].into());
// 添加nameserver相关配置
dns.insert("default-nameserver".into(), vec!["223.6.6.6", "8.8.8.8"].into());
dns.insert("nameserver".into(), vec![
"8.8.8.8", "https://doh.pub/dns-query", "https://dns.alidns.com/dns-query"
].into());
// 添加fallback配置
dns.insert("fallback".into(), vec![
"https://dns.alidns.com/dns-query", "https://dns.google/dns-query", "https://cloudflare-dns.com/dns-query"
].into());
// 添加proxy-server-nameserver
dns.insert("proxy-server-nameserver".into(), vec![
"https://doh.pub/dns-query", "https://dns.alidns.com/dns-query"
].into());
// 添加direct-nameserver
dns.insert("direct-nameserver".into(), Vec::<String>::new().into());
dns.insert("direct-nameserver-follow-policy".into(), false.into());
// 添加nameserver-policy (空对象)
dns.insert("nameserver-policy".into(), Mapping::new().into());
// 添加fallback-filter
let mut fallback_filter = Mapping::new();
fallback_filter.insert("geoip".into(), true.into());
fallback_filter.insert("geoip-code".into(), "CN".into());
fallback_filter.insert("ipcidr".into(), vec!["240.0.0.0/4", "0.0.0.0/32"].into());
fallback_filter.insert("domain".into(), vec!["+.google.com", "+.facebook.com", "+.youtube.com"].into());
dns.insert("fallback-filter".into(), fallback_filter.into());
#[cfg(not(target_os = "windows"))]
map.insert("redir-port".into(), 7895.into());
#[cfg(target_os = "linux")]
@@ -104,7 +55,6 @@ impl IClashTemp {
cors_map.insert("allow-origins".into(), vec!["*"].into());
map.insert("secret".into(), "".into());
map.insert("tun".into(), tun.into());
map.insert("dns".into(), dns.into());
map.insert("external-controller-cors".into(), cors_map.into());
map.insert("unified-delay".into(), true.into());
Self(map)

View File

@@ -70,6 +70,9 @@ pub struct IVerge {
/// enable proxy guard
pub enable_proxy_guard: Option<bool>,
/// enable dns settings - this controls whether dns_config.yaml is applied
pub enable_dns_settings: Option<bool>,
/// always use default bypass
pub use_default_bypass: Option<bool>,
@@ -287,6 +290,7 @@ impl IVerge {
enable_tray_speed: Some(true),
enable_global_hotkey: Some(true),
enable_lite_mode: Some(false),
enable_dns_settings: Some(true),
..Self::default()
}
}
@@ -369,6 +373,7 @@ impl IVerge {
patch!(webdav_password);
patch!(enable_tray_speed);
patch!(enable_lite_mode);
patch!(enable_dns_settings);
}
/// 在初始化前尝试拿到单例端口的值
@@ -458,6 +463,7 @@ pub struct IVergeResponse {
pub webdav_password: Option<String>,
pub enable_tray_speed: Option<bool>,
pub enable_lite_mode: Option<bool>,
pub enable_dns_settings: Option<bool>,
}
impl From<IVerge> for IVergeResponse {
@@ -521,6 +527,7 @@ impl From<IVerge> for IVergeResponse {
webdav_password: verge.webdav_password,
enable_tray_speed: verge.enable_tray_speed,
enable_lite_mode: verge.enable_lite_mode,
enable_dns_settings: verge.enable_dns_settings,
}
}
}

View File

@@ -25,7 +25,7 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
// config.yaml 的订阅
let clash_config = { Config::clash().latest().0.clone() };
let (clash_core, enable_tun, enable_builtin, socks_enabled, http_enabled) = {
let (clash_core, enable_tun, enable_builtin, socks_enabled, http_enabled, enable_dns_settings) = {
let verge = Config::verge();
let verge = verge.latest();
(
@@ -34,6 +34,7 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
verge.enable_builtin_enhanced.unwrap_or(true),
verge.verge_socks_enabled.unwrap_or(false),
verge.verge_http_enabled.unwrap_or(false),
verge.enable_dns_settings.unwrap_or(false),
)
};
#[cfg(not(target_os = "windows"))]
@@ -262,6 +263,27 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
config = use_tun(config, enable_tun).await;
config = use_sort(config);
// 应用独立的DNS配置如果启用
if enable_dns_settings {
use crate::utils::dirs;
use std::fs;
// 尝试读取dns_config.yaml
if let Ok(app_dir) = dirs::app_home_dir() {
let dns_path = app_dir.join("dns_config.yaml");
if dns_path.exists() {
if let Ok(dns_yaml) = fs::read_to_string(&dns_path) {
if let Ok(dns_config) = serde_yaml::from_str::<serde_yaml::Mapping>(&dns_yaml) {
// 将DNS配置合并到最终配置中
config.insert("dns".into(), dns_config.into());
log::info!(target: "app", "apply dns_config.yaml");
}
}
}
}
}
let mut exists_set = HashSet::new();
exists_set.extend(exists_keys);
exists_keys = exists_set.into_iter().collect();

View File

@@ -163,6 +163,10 @@ pub fn run() {
cmd::copy_clash_env,
cmd::get_proxies,
cmd::get_providers_proxies,
cmd::save_dns_config,
cmd::apply_dns_config,
cmd::check_dns_config_exists,
cmd::get_dns_config_content,
// verge
cmd::get_verge_config,
cmd::patch_verge_config,

View File

@@ -133,6 +133,81 @@ pub fn delete_log() -> Result<()> {
Ok(())
}
/// 初始化DNS配置文件
fn init_dns_config() -> Result<()> {
use serde_yaml::Value;
// 获取默认DNS配置
let default_dns_config = serde_yaml::Mapping::from_iter([
("enable".into(), Value::Bool(true)),
("listen".into(), Value::String(":53".into())),
("enhanced-mode".into(), Value::String("fake-ip".into())),
("fake-ip-range".into(), Value::String("198.18.0.1/16".into())),
("fake-ip-filter-mode".into(), Value::String("blacklist".into())),
("prefer-h3".into(), Value::Bool(false)),
("respect-rules".into(), Value::Bool(false)),
("use-hosts".into(), Value::Bool(false)),
("use-system-hosts".into(), Value::Bool(false)),
("fake-ip-filter".into(), Value::Sequence(vec![
Value::String("*.lan".into()),
Value::String("*.local".into()),
Value::String("*.arpa".into()),
Value::String("time.*.com".into()),
Value::String("ntp.*.com".into()),
Value::String("time.*.com".into()),
Value::String("+.market.xiaomi.com".into()),
Value::String("localhost.ptlogin2.qq.com".into()),
Value::String("*.msftncsi.com".into()),
Value::String("www.msftconnecttest.com".into()),
])),
("default-nameserver".into(), Value::Sequence(vec![
Value::String("223.6.6.6".into()),
Value::String("8.8.8.8".into()),
])),
("nameserver".into(), Value::Sequence(vec![
Value::String("8.8.8.8".into()),
Value::String("https://doh.pub/dns-query".into()),
Value::String("https://dns.alidns.com/dns-query".into()),
])),
("fallback".into(), Value::Sequence(vec![
Value::String("https://dns.alidns.com/dns-query".into()),
Value::String("https://dns.google/dns-query".into()),
Value::String("https://cloudflare-dns.com/dns-query".into()),
])),
("nameserver-policy".into(), Value::Mapping(serde_yaml::Mapping::new())),
("proxy-server-nameserver".into(), Value::Sequence(vec![
Value::String("https://doh.pub/dns-query".into()),
Value::String("https://dns.alidns.com/dns-query".into()),
])),
("direct-nameserver".into(), Value::Sequence(vec![])),
("direct-nameserver-follow-policy".into(), Value::Bool(false)),
("fallback-filter".into(), Value::Mapping(serde_yaml::Mapping::from_iter([
("geoip".into(), Value::Bool(true)),
("geoip-code".into(), Value::String("CN".into())),
("ipcidr".into(), Value::Sequence(vec![
Value::String("240.0.0.0/4".into()),
Value::String("0.0.0.0/32".into()),
])),
("domain".into(), Value::Sequence(vec![
Value::String("+.google.com".into()),
Value::String("+.facebook.com".into()),
Value::String("+.youtube.com".into()),
])),
]))),
]);
// 检查DNS配置文件是否存在
let app_dir = dirs::app_home_dir()?;
let dns_path = app_dir.join("dns_config.yaml");
if !dns_path.exists() {
log::info!(target: "app", "Creating default DNS config file");
help::save_yaml(&dns_path, &default_dns_config, Some("# Clash Verge DNS Config"))?;
}
Ok(())
}
/// Initialize all the config files
/// before tauri setup
pub fn init_config() -> Result<()> {
@@ -173,6 +248,9 @@ pub fn init_config() -> Result<()> {
<Result<()>>::Ok(())
}));
// 初始化DNS配置文件
let _ = init_dns_config();
Ok(())
}