diff --git a/src-tauri/src/cmd/clash.rs b/src-tauri/src/cmd/clash.rs index e57826f6..8302c73f 100644 --- a/src-tauri/src/cmd/clash.rs +++ b/src-tauri/src/cmd/clash.rs @@ -77,3 +77,142 @@ pub async fn clash_api_get_proxy_delay( pub async fn test_delay(url: String) -> CmdResult { 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::(&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 { + 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 { + 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) +} diff --git a/src-tauri/src/config/clash.rs b/src-tauri/src/config/clash.rs index 8a42e1fc..abd4da42 100644 --- a/src-tauri/src/config/clash.rs +++ b/src-tauri/src/config/clash.rs @@ -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::::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) diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs index c416a4da..a266416e 100644 --- a/src-tauri/src/config/verge.rs +++ b/src-tauri/src/config/verge.rs @@ -70,6 +70,9 @@ pub struct IVerge { /// enable proxy guard pub enable_proxy_guard: Option, + /// enable dns settings - this controls whether dns_config.yaml is applied + pub enable_dns_settings: Option, + /// always use default bypass pub use_default_bypass: Option, @@ -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, pub enable_tray_speed: Option, pub enable_lite_mode: Option, + pub enable_dns_settings: Option, } impl From for IVergeResponse { @@ -521,6 +527,7 @@ impl From 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, } } } diff --git a/src-tauri/src/enhance/mod.rs b/src-tauri/src/enhance/mod.rs index 11355e87..607e9fd7 100644 --- a/src-tauri/src/enhance/mod.rs +++ b/src-tauri/src/enhance/mod.rs @@ -25,7 +25,7 @@ pub async fn enhance() -> (Mapping, Vec, HashMap) { // 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, HashMap) { 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, HashMap) { 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::(&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(); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index b8a9ee33..ae40966c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -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, diff --git a/src-tauri/src/utils/init.rs b/src-tauri/src/utils/init.rs index b46d1d0c..91d18e60 100644 --- a/src-tauri/src/utils/init.rs +++ b/src-tauri/src/utils/init.rs @@ -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<()> { >::Ok(()) })); + // 初始化DNS配置文件 + let _ = init_dns_config(); + Ok(()) } diff --git a/src/components/setting/mods/dns-viewer.tsx b/src/components/setting/mods/dns-viewer.tsx index 48884339..ad081642 100644 --- a/src/components/setting/mods/dns-viewer.tsx +++ b/src/components/setting/mods/dns-viewer.tsx @@ -22,6 +22,7 @@ import yaml from "js-yaml"; import MonacoEditor from "react-monaco-editor"; import { useThemeMode } from "@/services/states"; import getSystem from "@/utils/get-system"; +import { invoke } from "@tauri-apps/api/core"; const Item = styled(ListItem)(({ theme }) => ({ padding: "8px 0", @@ -145,11 +146,109 @@ export const DnsViewer = forwardRef((props, ref) => { useImperativeHandle(ref, () => ({ open: () => { setOpen(true); - resetToDefaults(); + // 获取DNS配置文件并初始化表单 + initDnsConfig(); }, close: () => setOpen(false), })); + // 初始化DNS配置 + const initDnsConfig = async () => { + try { + // 尝试从dns_config.yaml文件读取配置 + const dnsConfigExists = await invoke( + "check_dns_config_exists", + {}, + ); + + if (dnsConfigExists) { + // 如果存在配置文件,加载其内容 + const dnsConfig = await invoke("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 = () => { setValues({ @@ -396,6 +495,7 @@ export const DnsViewer = forwardRef((props, ref) => { return dnsConfig; }; + // 处理保存操作 const onSave = useLockFn(async () => { try { let dnsConfig; @@ -412,8 +512,15 @@ export const DnsViewer = forwardRef((props, ref) => { dnsConfig = parsedConfig; } - await patchClash({ dns: dnsConfig }); - mutateClash(); + // 不直接应用到clash配置,而是保存到单独文件 + await invoke("save_dns_config", { dnsConfig }); + + // 如果DNS开关当前是打开的,则需要应用新的DNS配置 + if (clash?.dns?.enable) { + await invoke("apply_dns_config", { apply: true }); + mutateClash(); // 刷新UI + } + setOpen(false); Notice.success(t("DNS settings saved")); } catch (err: any) { diff --git a/src/components/setting/setting-clash.tsx b/src/components/setting/setting-clash.tsx index faf80ea9..8045176e 100644 --- a/src/components/setting/setting-clash.tsx +++ b/src/components/setting/setting-clash.tsx @@ -1,4 +1,4 @@ -import { useRef } from "react"; +import { useRef, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { TextField, Select, MenuItem, Typography } from "@mui/material"; import { @@ -22,6 +22,9 @@ import { updateGeoData } from "@/services/api"; import { TooltipIcon } from "@/components/base/base-tooltip-icon"; import { NetworkInterfaceViewer } from "./mods/network-interface-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"; @@ -45,6 +48,10 @@ const SettingClash = ({ onError }: Props) => { const { enable_random_port = false, verge_mixed_port } = verge ?? {}; + // 独立跟踪DNS设置开关状态 + const [dnsSettingsEnabled, setDnsSettingsEnabled] = useState(false); + const { addListener } = useListen(); + const webRef = useRef(null); const portRef = useRef(null); const ctrlRef = useRef(null); @@ -52,6 +59,12 @@ const SettingClash = ({ onError }: Props) => { const networkRef = useRef(null); const dnsRef = useRef(null); + // 初始化时从verge配置中加载DNS设置开关状态 + useEffect(() => { + const dnsSettingsState = verge?.enable_dns_settings ?? false; + setDnsSettingsEnabled(dnsSettingsState); + }, [verge]); + const onSwitchFormat = (_e: any, value: boolean) => value; const onChangeData = (patch: Partial) => { 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 ( @@ -111,16 +143,12 @@ const SettingClash = ({ onError }: Props) => { /> } > - onChangeData({ dns: { ...dns, enable: e } })} - onGuard={(e) => patchClash({ dns: { enable: e } })} - > - - + {/* 使用独立状态,不再依赖dns?.enable */} + handleDnsToggle(checked)} + /> diff --git a/src/locales/zh.json b/src/locales/zh.json index e24f6066..b070b108 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -194,7 +194,7 @@ "Test URL": "测试地址", "Settings": "设置", "System Setting": "系统设置", - "Tun Mode": "TUN(虚拟网卡)模式", + "Tun Mode": "TUN(虚拟网卡)模式", "TUN requires Service Mode": "TUN 模式需要服务", "Install Service": "安装服务", "Reset to Default": "重置为默认值", @@ -502,6 +502,5 @@ "Fallback IP CIDR": "回退 IP CIDR", "IP CIDRs not using fallback servers": "不使用回退服务器的 IP CIDR,用逗号分隔", "Fallback Domain": "回退域名", - "Domains using fallback servers": "使用回退服务器的域名,用逗号分隔", - "Fallback Geosite": "回退 Geosite" + "Domains using fallback servers": "使用回退服务器的域名,用逗号分隔" } diff --git a/src/services/types.d.ts b/src/services/types.d.ts index c0dd017d..18a0fea9 100644 --- a/src/services/types.d.ts +++ b/src/services/types.d.ts @@ -739,6 +739,7 @@ interface IVergeConfig { enable_silent_start?: boolean; enable_system_proxy?: boolean; enable_global_hotkey?: boolean; + enable_dns_settings?: boolean; proxy_auto_config?: boolean; pac_file_content?: string; enable_random_port?: boolean;