mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 07:03:45 +08:00
refactor: restructure DNS setting logic
This commit is contained in:
parent
eddcf209c1
commit
e27a32395a
@ -77,3 +77,142 @@ pub async fn clash_api_get_proxy_delay(
|
|||||||
pub async fn test_delay(url: String) -> CmdResult<u32> {
|
pub async fn test_delay(url: String) -> CmdResult<u32> {
|
||||||
Ok(feat::test_delay(url).await.unwrap_or(10000u32))
|
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)
|
||||||
|
}
|
||||||
|
@ -38,56 +38,7 @@ impl IClashTemp {
|
|||||||
tun.insert("strict-route".into(), false.into());
|
tun.insert("strict-route".into(), false.into());
|
||||||
tun.insert("auto-detect-interface".into(), true.into());
|
tun.insert("auto-detect-interface".into(), true.into());
|
||||||
tun.insert("dns-hijack".into(), vec!["any:53"].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"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
map.insert("redir-port".into(), 7895.into());
|
map.insert("redir-port".into(), 7895.into());
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
@ -104,7 +55,6 @@ impl IClashTemp {
|
|||||||
cors_map.insert("allow-origins".into(), vec!["*"].into());
|
cors_map.insert("allow-origins".into(), vec!["*"].into());
|
||||||
map.insert("secret".into(), "".into());
|
map.insert("secret".into(), "".into());
|
||||||
map.insert("tun".into(), tun.into());
|
map.insert("tun".into(), tun.into());
|
||||||
map.insert("dns".into(), dns.into());
|
|
||||||
map.insert("external-controller-cors".into(), cors_map.into());
|
map.insert("external-controller-cors".into(), cors_map.into());
|
||||||
map.insert("unified-delay".into(), true.into());
|
map.insert("unified-delay".into(), true.into());
|
||||||
Self(map)
|
Self(map)
|
||||||
|
@ -70,6 +70,9 @@ pub struct IVerge {
|
|||||||
/// enable proxy guard
|
/// enable proxy guard
|
||||||
pub enable_proxy_guard: Option<bool>,
|
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
|
/// always use default bypass
|
||||||
pub use_default_bypass: Option<bool>,
|
pub use_default_bypass: Option<bool>,
|
||||||
|
|
||||||
@ -287,6 +290,7 @@ impl IVerge {
|
|||||||
enable_tray_speed: Some(true),
|
enable_tray_speed: Some(true),
|
||||||
enable_global_hotkey: Some(true),
|
enable_global_hotkey: Some(true),
|
||||||
enable_lite_mode: Some(false),
|
enable_lite_mode: Some(false),
|
||||||
|
enable_dns_settings: Some(true),
|
||||||
..Self::default()
|
..Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,6 +373,7 @@ impl IVerge {
|
|||||||
patch!(webdav_password);
|
patch!(webdav_password);
|
||||||
patch!(enable_tray_speed);
|
patch!(enable_tray_speed);
|
||||||
patch!(enable_lite_mode);
|
patch!(enable_lite_mode);
|
||||||
|
patch!(enable_dns_settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 在初始化前尝试拿到单例端口的值
|
/// 在初始化前尝试拿到单例端口的值
|
||||||
@ -458,6 +463,7 @@ pub struct IVergeResponse {
|
|||||||
pub webdav_password: Option<String>,
|
pub webdav_password: Option<String>,
|
||||||
pub enable_tray_speed: Option<bool>,
|
pub enable_tray_speed: Option<bool>,
|
||||||
pub enable_lite_mode: Option<bool>,
|
pub enable_lite_mode: Option<bool>,
|
||||||
|
pub enable_dns_settings: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IVerge> for IVergeResponse {
|
impl From<IVerge> for IVergeResponse {
|
||||||
@ -521,6 +527,7 @@ impl From<IVerge> for IVergeResponse {
|
|||||||
webdav_password: verge.webdav_password,
|
webdav_password: verge.webdav_password,
|
||||||
enable_tray_speed: verge.enable_tray_speed,
|
enable_tray_speed: verge.enable_tray_speed,
|
||||||
enable_lite_mode: verge.enable_lite_mode,
|
enable_lite_mode: verge.enable_lite_mode,
|
||||||
|
enable_dns_settings: verge.enable_dns_settings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
|||||||
// config.yaml 的订阅
|
// config.yaml 的订阅
|
||||||
let clash_config = { Config::clash().latest().0.clone() };
|
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 = Config::verge();
|
||||||
let verge = verge.latest();
|
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.enable_builtin_enhanced.unwrap_or(true),
|
||||||
verge.verge_socks_enabled.unwrap_or(false),
|
verge.verge_socks_enabled.unwrap_or(false),
|
||||||
verge.verge_http_enabled.unwrap_or(false),
|
verge.verge_http_enabled.unwrap_or(false),
|
||||||
|
verge.enable_dns_settings.unwrap_or(false),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[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_tun(config, enable_tun).await;
|
||||||
config = use_sort(config);
|
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();
|
let mut exists_set = HashSet::new();
|
||||||
exists_set.extend(exists_keys);
|
exists_set.extend(exists_keys);
|
||||||
exists_keys = exists_set.into_iter().collect();
|
exists_keys = exists_set.into_iter().collect();
|
||||||
|
@ -163,6 +163,10 @@ pub fn run() {
|
|||||||
cmd::copy_clash_env,
|
cmd::copy_clash_env,
|
||||||
cmd::get_proxies,
|
cmd::get_proxies,
|
||||||
cmd::get_providers_proxies,
|
cmd::get_providers_proxies,
|
||||||
|
cmd::save_dns_config,
|
||||||
|
cmd::apply_dns_config,
|
||||||
|
cmd::check_dns_config_exists,
|
||||||
|
cmd::get_dns_config_content,
|
||||||
// verge
|
// verge
|
||||||
cmd::get_verge_config,
|
cmd::get_verge_config,
|
||||||
cmd::patch_verge_config,
|
cmd::patch_verge_config,
|
||||||
|
@ -133,6 +133,81 @@ pub fn delete_log() -> Result<()> {
|
|||||||
Ok(())
|
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
|
/// Initialize all the config files
|
||||||
/// before tauri setup
|
/// before tauri setup
|
||||||
pub fn init_config() -> Result<()> {
|
pub fn init_config() -> Result<()> {
|
||||||
@ -173,6 +248,9 @@ pub fn init_config() -> Result<()> {
|
|||||||
<Result<()>>::Ok(())
|
<Result<()>>::Ok(())
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// 初始化DNS配置文件
|
||||||
|
let _ = init_dns_config();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ import yaml from "js-yaml";
|
|||||||
import MonacoEditor from "react-monaco-editor";
|
import MonacoEditor from "react-monaco-editor";
|
||||||
import { useThemeMode } from "@/services/states";
|
import { useThemeMode } from "@/services/states";
|
||||||
import getSystem from "@/utils/get-system";
|
import getSystem from "@/utils/get-system";
|
||||||
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
|
|
||||||
const Item = styled(ListItem)(({ theme }) => ({
|
const Item = styled(ListItem)(({ theme }) => ({
|
||||||
padding: "8px 0",
|
padding: "8px 0",
|
||||||
@ -145,11 +146,109 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
open: () => {
|
open: () => {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
resetToDefaults();
|
// 获取DNS配置文件并初始化表单
|
||||||
|
initDnsConfig();
|
||||||
},
|
},
|
||||||
close: () => setOpen(false),
|
close: () => setOpen(false),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// 初始化DNS配置
|
||||||
|
const initDnsConfig = async () => {
|
||||||
|
try {
|
||||||
|
// 尝试从dns_config.yaml文件读取配置
|
||||||
|
const dnsConfigExists = await invoke<boolean>(
|
||||||
|
"check_dns_config_exists",
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dnsConfigExists) {
|
||||||
|
// 如果存在配置文件,加载其内容
|
||||||
|
const dnsConfig = await invoke<string>("get_dns_config_content", {});
|
||||||
|
const config = yaml.load(dnsConfig) as any;
|
||||||
|
|
||||||
|
// 更新表单数据
|
||||||
|
updateValuesFromConfig(config);
|
||||||
|
// 更新YAML编辑器内容
|
||||||
|
setYamlContent(dnsConfig);
|
||||||
|
} else {
|
||||||
|
// 如果不存在配置文件,使用默认值
|
||||||
|
resetToDefaults();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to initialize DNS config", err);
|
||||||
|
resetToDefaults();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 从配置对象更新表单值
|
||||||
|
const updateValuesFromConfig = (config: any) => {
|
||||||
|
if (!config) return;
|
||||||
|
|
||||||
|
const enhancedMode =
|
||||||
|
config["enhanced-mode"] || DEFAULT_DNS_CONFIG["enhanced-mode"];
|
||||||
|
const validEnhancedMode =
|
||||||
|
enhancedMode === "fake-ip" || enhancedMode === "redir-host"
|
||||||
|
? enhancedMode
|
||||||
|
: DEFAULT_DNS_CONFIG["enhanced-mode"];
|
||||||
|
|
||||||
|
const fakeIpFilterMode =
|
||||||
|
config["fake-ip-filter-mode"] ||
|
||||||
|
DEFAULT_DNS_CONFIG["fake-ip-filter-mode"];
|
||||||
|
const validFakeIpFilterMode =
|
||||||
|
fakeIpFilterMode === "blacklist" || fakeIpFilterMode === "whitelist"
|
||||||
|
? fakeIpFilterMode
|
||||||
|
: DEFAULT_DNS_CONFIG["fake-ip-filter-mode"];
|
||||||
|
|
||||||
|
setValues({
|
||||||
|
enable: config.enable ?? DEFAULT_DNS_CONFIG.enable,
|
||||||
|
listen: config.listen ?? DEFAULT_DNS_CONFIG.listen,
|
||||||
|
enhancedMode: validEnhancedMode,
|
||||||
|
fakeIpRange:
|
||||||
|
config["fake-ip-range"] ?? DEFAULT_DNS_CONFIG["fake-ip-range"],
|
||||||
|
fakeIpFilterMode: validFakeIpFilterMode,
|
||||||
|
preferH3: config["prefer-h3"] ?? DEFAULT_DNS_CONFIG["prefer-h3"],
|
||||||
|
respectRules:
|
||||||
|
config["respect-rules"] ?? DEFAULT_DNS_CONFIG["respect-rules"],
|
||||||
|
fakeIpFilter:
|
||||||
|
config["fake-ip-filter"]?.join(", ") ??
|
||||||
|
DEFAULT_DNS_CONFIG["fake-ip-filter"].join(", "),
|
||||||
|
nameserver:
|
||||||
|
config.nameserver?.join(", ") ??
|
||||||
|
DEFAULT_DNS_CONFIG.nameserver.join(", "),
|
||||||
|
fallback:
|
||||||
|
config.fallback?.join(", ") ?? DEFAULT_DNS_CONFIG.fallback.join(", "),
|
||||||
|
defaultNameserver:
|
||||||
|
config["default-nameserver"]?.join(", ") ??
|
||||||
|
DEFAULT_DNS_CONFIG["default-nameserver"].join(", "),
|
||||||
|
useHosts: config["use-hosts"] ?? DEFAULT_DNS_CONFIG["use-hosts"],
|
||||||
|
useSystemHosts:
|
||||||
|
config["use-system-hosts"] ?? DEFAULT_DNS_CONFIG["use-system-hosts"],
|
||||||
|
proxyServerNameserver:
|
||||||
|
config["proxy-server-nameserver"]?.join(", ") ??
|
||||||
|
(DEFAULT_DNS_CONFIG["proxy-server-nameserver"]?.join(", ") || ""),
|
||||||
|
directNameserver:
|
||||||
|
config["direct-nameserver"]?.join(", ") ??
|
||||||
|
(DEFAULT_DNS_CONFIG["direct-nameserver"]?.join(", ") || ""),
|
||||||
|
directNameserverFollowPolicy:
|
||||||
|
config["direct-nameserver-follow-policy"] ??
|
||||||
|
DEFAULT_DNS_CONFIG["direct-nameserver-follow-policy"],
|
||||||
|
fallbackGeoip:
|
||||||
|
config["fallback-filter"]?.geoip ??
|
||||||
|
DEFAULT_DNS_CONFIG["fallback-filter"].geoip,
|
||||||
|
fallbackGeoipCode:
|
||||||
|
config["fallback-filter"]?.["geoip-code"] ??
|
||||||
|
DEFAULT_DNS_CONFIG["fallback-filter"]["geoip-code"],
|
||||||
|
fallbackIpcidr:
|
||||||
|
config["fallback-filter"]?.ipcidr?.join(", ") ??
|
||||||
|
DEFAULT_DNS_CONFIG["fallback-filter"].ipcidr.join(", "),
|
||||||
|
fallbackDomain:
|
||||||
|
config["fallback-filter"]?.domain?.join(", ") ??
|
||||||
|
DEFAULT_DNS_CONFIG["fallback-filter"].domain.join(", "),
|
||||||
|
nameserverPolicy:
|
||||||
|
formatNameserverPolicy(config["nameserver-policy"]) || "",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 重置为默认值
|
// 重置为默认值
|
||||||
const resetToDefaults = () => {
|
const resetToDefaults = () => {
|
||||||
setValues({
|
setValues({
|
||||||
@ -396,6 +495,7 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
return dnsConfig;
|
return dnsConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理保存操作
|
||||||
const onSave = useLockFn(async () => {
|
const onSave = useLockFn(async () => {
|
||||||
try {
|
try {
|
||||||
let dnsConfig;
|
let dnsConfig;
|
||||||
@ -412,8 +512,15 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
dnsConfig = parsedConfig;
|
dnsConfig = parsedConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
await patchClash({ dns: dnsConfig });
|
// 不直接应用到clash配置,而是保存到单独文件
|
||||||
mutateClash();
|
await invoke("save_dns_config", { dnsConfig });
|
||||||
|
|
||||||
|
// 如果DNS开关当前是打开的,则需要应用新的DNS配置
|
||||||
|
if (clash?.dns?.enable) {
|
||||||
|
await invoke("apply_dns_config", { apply: true });
|
||||||
|
mutateClash(); // 刷新UI
|
||||||
|
}
|
||||||
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
Notice.success(t("DNS settings saved"));
|
Notice.success(t("DNS settings saved"));
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useRef } from "react";
|
import { useRef, useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { TextField, Select, MenuItem, Typography } from "@mui/material";
|
import { TextField, Select, MenuItem, Typography } from "@mui/material";
|
||||||
import {
|
import {
|
||||||
@ -22,6 +22,9 @@ import { updateGeoData } from "@/services/api";
|
|||||||
import { TooltipIcon } from "@/components/base/base-tooltip-icon";
|
import { TooltipIcon } from "@/components/base/base-tooltip-icon";
|
||||||
import { NetworkInterfaceViewer } from "./mods/network-interface-viewer";
|
import { NetworkInterfaceViewer } from "./mods/network-interface-viewer";
|
||||||
import { DnsViewer } from "./mods/dns-viewer";
|
import { DnsViewer } from "./mods/dns-viewer";
|
||||||
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
|
import { useLockFn } from "ahooks";
|
||||||
|
import { useListen } from "@/hooks/use-listen";
|
||||||
|
|
||||||
const isWIN = getSystem() === "windows";
|
const isWIN = getSystem() === "windows";
|
||||||
|
|
||||||
@ -45,6 +48,10 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
|
|
||||||
const { enable_random_port = false, verge_mixed_port } = verge ?? {};
|
const { enable_random_port = false, verge_mixed_port } = verge ?? {};
|
||||||
|
|
||||||
|
// 独立跟踪DNS设置开关状态
|
||||||
|
const [dnsSettingsEnabled, setDnsSettingsEnabled] = useState(false);
|
||||||
|
const { addListener } = useListen();
|
||||||
|
|
||||||
const webRef = useRef<DialogRef>(null);
|
const webRef = useRef<DialogRef>(null);
|
||||||
const portRef = useRef<DialogRef>(null);
|
const portRef = useRef<DialogRef>(null);
|
||||||
const ctrlRef = useRef<DialogRef>(null);
|
const ctrlRef = useRef<DialogRef>(null);
|
||||||
@ -52,6 +59,12 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
const networkRef = useRef<DialogRef>(null);
|
const networkRef = useRef<DialogRef>(null);
|
||||||
const dnsRef = useRef<DialogRef>(null);
|
const dnsRef = useRef<DialogRef>(null);
|
||||||
|
|
||||||
|
// 初始化时从verge配置中加载DNS设置开关状态
|
||||||
|
useEffect(() => {
|
||||||
|
const dnsSettingsState = verge?.enable_dns_settings ?? false;
|
||||||
|
setDnsSettingsEnabled(dnsSettingsState);
|
||||||
|
}, [verge]);
|
||||||
|
|
||||||
const onSwitchFormat = (_e: any, value: boolean) => value;
|
const onSwitchFormat = (_e: any, value: boolean) => value;
|
||||||
const onChangeData = (patch: Partial<IConfigData>) => {
|
const onChangeData = (patch: Partial<IConfigData>) => {
|
||||||
mutateClash((old) => ({ ...(old! || {}), ...patch }), false);
|
mutateClash((old) => ({ ...(old! || {}), ...patch }), false);
|
||||||
@ -68,6 +81,25 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 实现DNS设置开关处理函数
|
||||||
|
const handleDnsToggle = useLockFn(async (enable: boolean) => {
|
||||||
|
try {
|
||||||
|
setDnsSettingsEnabled(enable);
|
||||||
|
await patchVerge({ enable_dns_settings: enable });
|
||||||
|
await invoke("apply_dns_config", { apply: enable });
|
||||||
|
setTimeout(() => {
|
||||||
|
mutateClash();
|
||||||
|
}, 500); // 延迟500ms确保后端完成处理
|
||||||
|
} catch (err: any) {
|
||||||
|
Notice.error(err.message || err.toString());
|
||||||
|
setDnsSettingsEnabled(!enable);
|
||||||
|
await patchVerge({ enable_dns_settings: !enable }).catch(() => {
|
||||||
|
// 忽略恢复状态时的错误
|
||||||
|
});
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingList title={t("Clash Setting")}>
|
<SettingList title={t("Clash Setting")}>
|
||||||
<WebUIViewer ref={webRef} />
|
<WebUIViewer ref={webRef} />
|
||||||
@ -111,16 +143,12 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<GuardState
|
{/* 使用独立状态,不再依赖dns?.enable */}
|
||||||
value={dns?.enable ?? false}
|
<Switch
|
||||||
valueProps="checked"
|
edge="end"
|
||||||
onCatch={onError}
|
checked={dnsSettingsEnabled}
|
||||||
onFormat={onSwitchFormat}
|
onChange={(_, checked) => handleDnsToggle(checked)}
|
||||||
onChange={(e) => onChangeData({ dns: { ...dns, enable: e } })}
|
/>
|
||||||
onGuard={(e) => patchClash({ dns: { enable: e } })}
|
|
||||||
>
|
|
||||||
<Switch edge="end" />
|
|
||||||
</GuardState>
|
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
|
||||||
<SettingItem label={t("IPv6")}>
|
<SettingItem label={t("IPv6")}>
|
||||||
|
@ -194,7 +194,7 @@
|
|||||||
"Test URL": "测试地址",
|
"Test URL": "测试地址",
|
||||||
"Settings": "设置",
|
"Settings": "设置",
|
||||||
"System Setting": "系统设置",
|
"System Setting": "系统设置",
|
||||||
"Tun Mode": "TUN(虚拟网卡)模式",
|
"Tun Mode": "TUN(虚拟网卡)模式",
|
||||||
"TUN requires Service Mode": "TUN 模式需要服务",
|
"TUN requires Service Mode": "TUN 模式需要服务",
|
||||||
"Install Service": "安装服务",
|
"Install Service": "安装服务",
|
||||||
"Reset to Default": "重置为默认值",
|
"Reset to Default": "重置为默认值",
|
||||||
@ -502,6 +502,5 @@
|
|||||||
"Fallback IP CIDR": "回退 IP CIDR",
|
"Fallback IP CIDR": "回退 IP CIDR",
|
||||||
"IP CIDRs not using fallback servers": "不使用回退服务器的 IP CIDR,用逗号分隔",
|
"IP CIDRs not using fallback servers": "不使用回退服务器的 IP CIDR,用逗号分隔",
|
||||||
"Fallback Domain": "回退域名",
|
"Fallback Domain": "回退域名",
|
||||||
"Domains using fallback servers": "使用回退服务器的域名,用逗号分隔",
|
"Domains using fallback servers": "使用回退服务器的域名,用逗号分隔"
|
||||||
"Fallback Geosite": "回退 Geosite"
|
|
||||||
}
|
}
|
||||||
|
1
src/services/types.d.ts
vendored
1
src/services/types.d.ts
vendored
@ -739,6 +739,7 @@ interface IVergeConfig {
|
|||||||
enable_silent_start?: boolean;
|
enable_silent_start?: boolean;
|
||||||
enable_system_proxy?: boolean;
|
enable_system_proxy?: boolean;
|
||||||
enable_global_hotkey?: boolean;
|
enable_global_hotkey?: boolean;
|
||||||
|
enable_dns_settings?: boolean;
|
||||||
proxy_auto_config?: boolean;
|
proxy_auto_config?: boolean;
|
||||||
pac_file_content?: string;
|
pac_file_content?: string;
|
||||||
enable_random_port?: boolean;
|
enable_random_port?: boolean;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user