feat: add hosts settings to DNS settings and enhance DNS config validation
This commit is contained in:
@@ -233,3 +233,26 @@ pub async fn get_dns_config_content() -> CmdResult<String> {
|
|||||||
let content = fs::read_to_string(&dns_path).map_err(|e| e.to_string())?;
|
let content = fs::read_to_string(&dns_path).map_err(|e| e.to_string())?;
|
||||||
Ok(content)
|
Ok(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 验证DNS配置文件
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn validate_dns_config() -> CmdResult<(bool, String)> {
|
||||||
|
use crate::core::CoreManager;
|
||||||
|
use crate::utils::dirs;
|
||||||
|
|
||||||
|
let app_dir = dirs::app_home_dir().map_err(|e| e.to_string())?;
|
||||||
|
let dns_path = app_dir.join("dns_config.yaml");
|
||||||
|
let dns_path_str = dns_path.to_str().unwrap_or_default();
|
||||||
|
|
||||||
|
if !dns_path.exists() {
|
||||||
|
return Ok((false, "DNS config file not found".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
match CoreManager::global()
|
||||||
|
.validate_config_file(dns_path_str, None)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(result) => Ok(result),
|
||||||
|
Err(e) => Err(e.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -261,16 +261,29 @@ pub async fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
|||||||
use crate::utils::dirs;
|
use crate::utils::dirs;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
// 尝试读取dns_config.yaml
|
|
||||||
if let Ok(app_dir) = dirs::app_home_dir() {
|
if let Ok(app_dir) = dirs::app_home_dir() {
|
||||||
let dns_path = app_dir.join("dns_config.yaml");
|
let dns_path = app_dir.join("dns_config.yaml");
|
||||||
|
|
||||||
if dns_path.exists() {
|
if dns_path.exists() {
|
||||||
if let Ok(dns_yaml) = fs::read_to_string(&dns_path) {
|
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) {
|
if let Ok(dns_config) = serde_yaml::from_str::<serde_yaml::Mapping>(&dns_yaml) {
|
||||||
// 将DNS配置合并到最终配置中
|
// 处理hosts配置
|
||||||
config.insert("dns".into(), dns_config.into());
|
if let Some(hosts_value) = dns_config.get("hosts") {
|
||||||
log::info!(target: "app", "apply dns_config.yaml");
|
if hosts_value.is_mapping() {
|
||||||
|
config.insert("hosts".into(), hosts_value.clone());
|
||||||
|
log::info!(target: "app", "apply hosts configuration");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(dns_value) = dns_config.get("dns") {
|
||||||
|
if let Some(dns_mapping) = dns_value.as_mapping() {
|
||||||
|
config.insert("dns".into(), dns_mapping.clone().into());
|
||||||
|
log::info!(target: "app", "apply dns_config.yaml (dns section)");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config.insert("dns".into(), dns_config.into());
|
||||||
|
log::info!(target: "app", "apply dns_config.yaml");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,6 +252,7 @@ pub fn run() {
|
|||||||
cmd::apply_dns_config,
|
cmd::apply_dns_config,
|
||||||
cmd::check_dns_config_exists,
|
cmd::check_dns_config_exists,
|
||||||
cmd::get_dns_config_content,
|
cmd::get_dns_config_content,
|
||||||
|
cmd::validate_dns_config,
|
||||||
// verge
|
// verge
|
||||||
cmd::get_verge_config,
|
cmd::get_verge_config,
|
||||||
cmd::patch_verge_config,
|
cmd::patch_verge_config,
|
||||||
|
|||||||
@@ -142,8 +142,8 @@ pub fn delete_log() -> Result<()> {
|
|||||||
fn init_dns_config() -> Result<()> {
|
fn init_dns_config() -> Result<()> {
|
||||||
use serde_yaml::Value;
|
use serde_yaml::Value;
|
||||||
|
|
||||||
// 获取默认DNS配置
|
// 创建DNS子配置
|
||||||
let default_dns_config = serde_yaml::Mapping::from_iter([
|
let dns_config = serde_yaml::Mapping::from_iter([
|
||||||
("enable".into(), Value::Bool(true)),
|
("enable".into(), Value::Bool(true)),
|
||||||
("listen".into(), Value::String(":53".into())),
|
("listen".into(), Value::String(":53".into())),
|
||||||
("enhanced-mode".into(), Value::String("fake-ip".into())),
|
("enhanced-mode".into(), Value::String("fake-ip".into())),
|
||||||
@@ -231,6 +231,12 @@ fn init_dns_config() -> Result<()> {
|
|||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// 获取默认DNS和host配置
|
||||||
|
let default_dns_config = serde_yaml::Mapping::from_iter([
|
||||||
|
("dns".into(), Value::Mapping(dns_config)),
|
||||||
|
("hosts".into(), Value::Mapping(serde_yaml::Mapping::new())),
|
||||||
|
]);
|
||||||
|
|
||||||
// 检查DNS配置文件是否存在
|
// 检查DNS配置文件是否存在
|
||||||
let app_dir = dirs::app_home_dir()?;
|
let app_dir = dirs::app_home_dir()?;
|
||||||
let dns_path = app_dir.join("dns_config.yaml");
|
let dns_path = app_dir.join("dns_config.yaml");
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ pub const ITEM_MERGE: &str = "# Profile Enhancement Merge Template for Clash Ver
|
|||||||
|
|
||||||
profile:
|
profile:
|
||||||
store-selected: true
|
store-selected: true
|
||||||
|
|
||||||
dns:
|
|
||||||
use-system-hosts: false
|
|
||||||
";
|
";
|
||||||
|
|
||||||
pub const ITEM_MERGE_EMPTY: &str = "# Profile Enhancement Merge Template for Clash Verge
|
pub const ITEM_MERGE_EMPTY: &str = "# Profile Enhancement Merge Template for Clash Verge
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
fallbackIpcidr: string;
|
fallbackIpcidr: string;
|
||||||
fallbackDomain: string;
|
fallbackDomain: string;
|
||||||
nameserverPolicy: string;
|
nameserverPolicy: string;
|
||||||
|
hosts: string; // hosts设置,独立于dns
|
||||||
}>({
|
}>({
|
||||||
enable: DEFAULT_DNS_CONFIG.enable,
|
enable: DEFAULT_DNS_CONFIG.enable,
|
||||||
listen: DEFAULT_DNS_CONFIG.listen,
|
listen: DEFAULT_DNS_CONFIG.listen,
|
||||||
@@ -139,6 +140,7 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
fallbackDomain:
|
fallbackDomain:
|
||||||
DEFAULT_DNS_CONFIG["fallback-filter"].domain?.join(", ") || "",
|
DEFAULT_DNS_CONFIG["fallback-filter"].domain?.join(", ") || "",
|
||||||
nameserverPolicy: "",
|
nameserverPolicy: "",
|
||||||
|
hosts: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
// 用于YAML编辑模式
|
// 用于YAML编辑模式
|
||||||
@@ -185,15 +187,20 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
const updateValuesFromConfig = (config: any) => {
|
const updateValuesFromConfig = (config: any) => {
|
||||||
if (!config) return;
|
if (!config) return;
|
||||||
|
|
||||||
|
// 提取dns配置
|
||||||
|
const dnsConfig = config.dns || {};
|
||||||
|
// 提取hosts配置(与dns同级)
|
||||||
|
const hostsConfig = config.hosts || {};
|
||||||
|
|
||||||
const enhancedMode =
|
const enhancedMode =
|
||||||
config["enhanced-mode"] || DEFAULT_DNS_CONFIG["enhanced-mode"];
|
dnsConfig["enhanced-mode"] || DEFAULT_DNS_CONFIG["enhanced-mode"];
|
||||||
const validEnhancedMode =
|
const validEnhancedMode =
|
||||||
enhancedMode === "fake-ip" || enhancedMode === "redir-host"
|
enhancedMode === "fake-ip" || enhancedMode === "redir-host"
|
||||||
? enhancedMode
|
? enhancedMode
|
||||||
: DEFAULT_DNS_CONFIG["enhanced-mode"];
|
: DEFAULT_DNS_CONFIG["enhanced-mode"];
|
||||||
|
|
||||||
const fakeIpFilterMode =
|
const fakeIpFilterMode =
|
||||||
config["fake-ip-filter-mode"] ||
|
dnsConfig["fake-ip-filter-mode"] ||
|
||||||
DEFAULT_DNS_CONFIG["fake-ip-filter-mode"];
|
DEFAULT_DNS_CONFIG["fake-ip-filter-mode"];
|
||||||
const validFakeIpFilterMode =
|
const validFakeIpFilterMode =
|
||||||
fakeIpFilterMode === "blacklist" || fakeIpFilterMode === "whitelist"
|
fakeIpFilterMode === "blacklist" || fakeIpFilterMode === "whitelist"
|
||||||
@@ -201,53 +208,55 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
: DEFAULT_DNS_CONFIG["fake-ip-filter-mode"];
|
: DEFAULT_DNS_CONFIG["fake-ip-filter-mode"];
|
||||||
|
|
||||||
setValues({
|
setValues({
|
||||||
enable: config.enable ?? DEFAULT_DNS_CONFIG.enable,
|
enable: dnsConfig.enable ?? DEFAULT_DNS_CONFIG.enable,
|
||||||
listen: config.listen ?? DEFAULT_DNS_CONFIG.listen,
|
listen: dnsConfig.listen ?? DEFAULT_DNS_CONFIG.listen,
|
||||||
enhancedMode: validEnhancedMode,
|
enhancedMode: validEnhancedMode,
|
||||||
fakeIpRange:
|
fakeIpRange:
|
||||||
config["fake-ip-range"] ?? DEFAULT_DNS_CONFIG["fake-ip-range"],
|
dnsConfig["fake-ip-range"] ?? DEFAULT_DNS_CONFIG["fake-ip-range"],
|
||||||
fakeIpFilterMode: validFakeIpFilterMode,
|
fakeIpFilterMode: validFakeIpFilterMode,
|
||||||
preferH3: config["prefer-h3"] ?? DEFAULT_DNS_CONFIG["prefer-h3"],
|
preferH3: dnsConfig["prefer-h3"] ?? DEFAULT_DNS_CONFIG["prefer-h3"],
|
||||||
respectRules:
|
respectRules:
|
||||||
config["respect-rules"] ?? DEFAULT_DNS_CONFIG["respect-rules"],
|
dnsConfig["respect-rules"] ?? DEFAULT_DNS_CONFIG["respect-rules"],
|
||||||
useHosts: config["use-hosts"] ?? DEFAULT_DNS_CONFIG["use-hosts"],
|
useHosts: dnsConfig["use-hosts"] ?? DEFAULT_DNS_CONFIG["use-hosts"],
|
||||||
useSystemHosts:
|
useSystemHosts:
|
||||||
config["use-system-hosts"] ?? DEFAULT_DNS_CONFIG["use-system-hosts"],
|
dnsConfig["use-system-hosts"] ??
|
||||||
ipv6: config.ipv6 ?? DEFAULT_DNS_CONFIG.ipv6,
|
DEFAULT_DNS_CONFIG["use-system-hosts"],
|
||||||
|
ipv6: dnsConfig.ipv6 ?? DEFAULT_DNS_CONFIG.ipv6,
|
||||||
fakeIpFilter:
|
fakeIpFilter:
|
||||||
config["fake-ip-filter"]?.join(", ") ??
|
dnsConfig["fake-ip-filter"]?.join(", ") ??
|
||||||
DEFAULT_DNS_CONFIG["fake-ip-filter"].join(", "),
|
DEFAULT_DNS_CONFIG["fake-ip-filter"].join(", "),
|
||||||
nameserver:
|
nameserver:
|
||||||
config.nameserver?.join(", ") ??
|
dnsConfig.nameserver?.join(", ") ??
|
||||||
DEFAULT_DNS_CONFIG.nameserver.join(", "),
|
DEFAULT_DNS_CONFIG.nameserver.join(", "),
|
||||||
fallback:
|
fallback:
|
||||||
config.fallback?.join(", ") ?? DEFAULT_DNS_CONFIG.fallback.join(", "),
|
dnsConfig.fallback?.join(", ") ?? DEFAULT_DNS_CONFIG.fallback.join(", "),
|
||||||
defaultNameserver:
|
defaultNameserver:
|
||||||
config["default-nameserver"]?.join(", ") ??
|
dnsConfig["default-nameserver"]?.join(", ") ??
|
||||||
DEFAULT_DNS_CONFIG["default-nameserver"].join(", "),
|
DEFAULT_DNS_CONFIG["default-nameserver"].join(", "),
|
||||||
proxyServerNameserver:
|
proxyServerNameserver:
|
||||||
config["proxy-server-nameserver"]?.join(", ") ??
|
dnsConfig["proxy-server-nameserver"]?.join(", ") ??
|
||||||
(DEFAULT_DNS_CONFIG["proxy-server-nameserver"]?.join(", ") || ""),
|
(DEFAULT_DNS_CONFIG["proxy-server-nameserver"]?.join(", ") || ""),
|
||||||
directNameserver:
|
directNameserver:
|
||||||
config["direct-nameserver"]?.join(", ") ??
|
dnsConfig["direct-nameserver"]?.join(", ") ??
|
||||||
(DEFAULT_DNS_CONFIG["direct-nameserver"]?.join(", ") || ""),
|
(DEFAULT_DNS_CONFIG["direct-nameserver"]?.join(", ") || ""),
|
||||||
directNameserverFollowPolicy:
|
directNameserverFollowPolicy:
|
||||||
config["direct-nameserver-follow-policy"] ??
|
dnsConfig["direct-nameserver-follow-policy"] ??
|
||||||
DEFAULT_DNS_CONFIG["direct-nameserver-follow-policy"],
|
DEFAULT_DNS_CONFIG["direct-nameserver-follow-policy"],
|
||||||
fallbackGeoip:
|
fallbackGeoip:
|
||||||
config["fallback-filter"]?.geoip ??
|
dnsConfig["fallback-filter"]?.geoip ??
|
||||||
DEFAULT_DNS_CONFIG["fallback-filter"].geoip,
|
DEFAULT_DNS_CONFIG["fallback-filter"].geoip,
|
||||||
fallbackGeoipCode:
|
fallbackGeoipCode:
|
||||||
config["fallback-filter"]?.["geoip-code"] ??
|
dnsConfig["fallback-filter"]?.["geoip-code"] ??
|
||||||
DEFAULT_DNS_CONFIG["fallback-filter"]["geoip-code"],
|
DEFAULT_DNS_CONFIG["fallback-filter"]["geoip-code"],
|
||||||
fallbackIpcidr:
|
fallbackIpcidr:
|
||||||
config["fallback-filter"]?.ipcidr?.join(", ") ??
|
dnsConfig["fallback-filter"]?.ipcidr?.join(", ") ??
|
||||||
DEFAULT_DNS_CONFIG["fallback-filter"].ipcidr.join(", "),
|
DEFAULT_DNS_CONFIG["fallback-filter"].ipcidr.join(", "),
|
||||||
fallbackDomain:
|
fallbackDomain:
|
||||||
config["fallback-filter"]?.domain?.join(", ") ??
|
dnsConfig["fallback-filter"]?.domain?.join(", ") ??
|
||||||
DEFAULT_DNS_CONFIG["fallback-filter"].domain.join(", "),
|
DEFAULT_DNS_CONFIG["fallback-filter"].domain.join(", "),
|
||||||
nameserverPolicy:
|
nameserverPolicy:
|
||||||
formatNameserverPolicy(config["nameserver-policy"]) || "",
|
formatNameserverPolicy(dnsConfig["nameserver-policy"]) || "",
|
||||||
|
hosts: formatHosts(hostsConfig) || "",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -281,99 +290,38 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
fallbackDomain:
|
fallbackDomain:
|
||||||
DEFAULT_DNS_CONFIG["fallback-filter"].domain?.join(", ") || "",
|
DEFAULT_DNS_CONFIG["fallback-filter"].domain?.join(", ") || "",
|
||||||
nameserverPolicy: "",
|
nameserverPolicy: "",
|
||||||
|
hosts: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
// 更新YAML编辑器内容
|
// 更新YAML编辑器内容
|
||||||
updateYamlFromValues(DEFAULT_DNS_CONFIG);
|
updateYamlFromValues();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 从表单值更新YAML内容
|
// 从表单值更新YAML内容
|
||||||
const updateYamlFromValues = (dnsConfig: any = null) => {
|
const updateYamlFromValues = () => {
|
||||||
// 如果提供了dnsConfig,直接使用它
|
|
||||||
if (dnsConfig) {
|
const config: Record<string, any> = {};
|
||||||
setYamlContent(yaml.dump(dnsConfig, { forceQuotes: true }));
|
|
||||||
return;
|
const dnsConfig = generateDnsConfig();
|
||||||
|
if (Object.keys(dnsConfig).length > 0) {
|
||||||
|
config.dns = dnsConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 否则从当前表单值生成
|
const hosts = parseHosts(values.hosts);
|
||||||
const config = generateDnsConfig();
|
if (Object.keys(hosts).length > 0) {
|
||||||
|
config.hosts = hosts;
|
||||||
|
}
|
||||||
|
|
||||||
setYamlContent(yaml.dump(config, { forceQuotes: true }));
|
setYamlContent(yaml.dump(config, { forceQuotes: true }));
|
||||||
};
|
};
|
||||||
|
|
||||||
// 从YAML更新表单值
|
// 从YAML更新表单值
|
||||||
const updateValuesFromYaml = () => {
|
const updateValuesFromYaml = () => {
|
||||||
try {
|
try {
|
||||||
const dnsConfig = yaml.load(yamlContent) as any;
|
const parsedYaml = yaml.load(yamlContent) as any;
|
||||||
if (!dnsConfig) return;
|
if (!parsedYaml) return;
|
||||||
|
|
||||||
const enhancedMode =
|
updateValuesFromConfig(parsedYaml);
|
||||||
dnsConfig["enhanced-mode"] || DEFAULT_DNS_CONFIG["enhanced-mode"];
|
|
||||||
// 确保enhancedMode只能是"fake-ip"或"redir-host"
|
|
||||||
const validEnhancedMode =
|
|
||||||
enhancedMode === "fake-ip" || enhancedMode === "redir-host"
|
|
||||||
? enhancedMode
|
|
||||||
: DEFAULT_DNS_CONFIG["enhanced-mode"];
|
|
||||||
|
|
||||||
const fakeIpFilterMode =
|
|
||||||
dnsConfig["fake-ip-filter-mode"] ||
|
|
||||||
DEFAULT_DNS_CONFIG["fake-ip-filter-mode"];
|
|
||||||
// 确保fakeIpFilterMode只能是"blacklist"或"whitelist"
|
|
||||||
const validFakeIpFilterMode =
|
|
||||||
fakeIpFilterMode === "blacklist" || fakeIpFilterMode === "whitelist"
|
|
||||||
? fakeIpFilterMode
|
|
||||||
: DEFAULT_DNS_CONFIG["fake-ip-filter-mode"];
|
|
||||||
|
|
||||||
setValues({
|
|
||||||
enable: dnsConfig.enable ?? DEFAULT_DNS_CONFIG.enable,
|
|
||||||
listen: dnsConfig.listen ?? DEFAULT_DNS_CONFIG.listen,
|
|
||||||
enhancedMode: validEnhancedMode,
|
|
||||||
fakeIpRange:
|
|
||||||
dnsConfig["fake-ip-range"] ?? DEFAULT_DNS_CONFIG["fake-ip-range"],
|
|
||||||
fakeIpFilterMode: validFakeIpFilterMode,
|
|
||||||
preferH3: dnsConfig["prefer-h3"] ?? DEFAULT_DNS_CONFIG["prefer-h3"],
|
|
||||||
respectRules:
|
|
||||||
dnsConfig["respect-rules"] ?? DEFAULT_DNS_CONFIG["respect-rules"],
|
|
||||||
useHosts: dnsConfig["use-hosts"] ?? DEFAULT_DNS_CONFIG["use-hosts"],
|
|
||||||
useSystemHosts:
|
|
||||||
dnsConfig["use-system-hosts"] ??
|
|
||||||
DEFAULT_DNS_CONFIG["use-system-hosts"],
|
|
||||||
ipv6: dnsConfig.ipv6 ?? DEFAULT_DNS_CONFIG.ipv6,
|
|
||||||
fakeIpFilter:
|
|
||||||
dnsConfig["fake-ip-filter"]?.join(", ") ??
|
|
||||||
DEFAULT_DNS_CONFIG["fake-ip-filter"].join(", "),
|
|
||||||
defaultNameserver:
|
|
||||||
dnsConfig["default-nameserver"]?.join(", ") ??
|
|
||||||
DEFAULT_DNS_CONFIG["default-nameserver"].join(", "),
|
|
||||||
nameserver:
|
|
||||||
dnsConfig.nameserver?.join(", ") ??
|
|
||||||
DEFAULT_DNS_CONFIG.nameserver.join(", "),
|
|
||||||
fallback:
|
|
||||||
dnsConfig.fallback?.join(", ") ??
|
|
||||||
DEFAULT_DNS_CONFIG.fallback.join(", "),
|
|
||||||
proxyServerNameserver:
|
|
||||||
dnsConfig["proxy-server-nameserver"]?.join(", ") ??
|
|
||||||
(DEFAULT_DNS_CONFIG["proxy-server-nameserver"]?.join(", ") || ""),
|
|
||||||
directNameserver:
|
|
||||||
dnsConfig["direct-nameserver"]?.join(", ") ??
|
|
||||||
(DEFAULT_DNS_CONFIG["direct-nameserver"]?.join(", ") || ""),
|
|
||||||
directNameserverFollowPolicy:
|
|
||||||
dnsConfig["direct-nameserver-follow-policy"] ??
|
|
||||||
DEFAULT_DNS_CONFIG["direct-nameserver-follow-policy"],
|
|
||||||
fallbackGeoip:
|
|
||||||
dnsConfig["fallback-filter"]?.geoip ??
|
|
||||||
DEFAULT_DNS_CONFIG["fallback-filter"].geoip,
|
|
||||||
fallbackGeoipCode:
|
|
||||||
dnsConfig["fallback-filter"]?.["geoip-code"] ??
|
|
||||||
DEFAULT_DNS_CONFIG["fallback-filter"]["geoip-code"],
|
|
||||||
fallbackIpcidr:
|
|
||||||
dnsConfig["fallback-filter"]?.ipcidr?.join(", ") ??
|
|
||||||
DEFAULT_DNS_CONFIG["fallback-filter"].ipcidr.join(", "),
|
|
||||||
fallbackDomain:
|
|
||||||
dnsConfig["fallback-filter"]?.domain?.join(", ") ??
|
|
||||||
DEFAULT_DNS_CONFIG["fallback-filter"].domain.join(", "),
|
|
||||||
nameserverPolicy:
|
|
||||||
formatNameserverPolicy(dnsConfig["nameserver-policy"]) || "",
|
|
||||||
});
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
showNotice('error', t("Invalid YAML format"));
|
showNotice('error', t("Invalid YAML format"));
|
||||||
}
|
}
|
||||||
@@ -427,18 +375,62 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 格式化hosts为字符串
|
||||||
|
const formatHosts = (hosts: any): string => {
|
||||||
|
if (!hosts || typeof hosts !== "object") return "";
|
||||||
|
|
||||||
|
let result: string[] = [];
|
||||||
|
|
||||||
|
Object.entries(hosts).forEach(([domain, value]) => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
// 处理数组格式的IP
|
||||||
|
const ipsStr = value.join(";");
|
||||||
|
result.push(`${domain}=${ipsStr}`);
|
||||||
|
} else {
|
||||||
|
// 处理单个IP或域名
|
||||||
|
result.push(`${domain}=${value}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result.join(", ");
|
||||||
|
};
|
||||||
|
|
||||||
|
// 解析hosts字符串为对象
|
||||||
|
const parseHosts = (str: string): Record<string, any> => {
|
||||||
|
const result: Record<string, any> = {};
|
||||||
|
if (!str) return result;
|
||||||
|
|
||||||
|
str.split(",").forEach((item) => {
|
||||||
|
const parts = item.trim().split("=");
|
||||||
|
if (parts.length < 2) return;
|
||||||
|
|
||||||
|
const domain = parts[0].trim();
|
||||||
|
const valueStr = parts.slice(1).join("=").trim();
|
||||||
|
|
||||||
|
// 检查是否包含多个分号分隔的IP
|
||||||
|
if (valueStr.includes(";")) {
|
||||||
|
result[domain] = valueStr
|
||||||
|
.split(";")
|
||||||
|
.map((s) => s.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
} else {
|
||||||
|
result[domain] = valueStr;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
// 初始化时设置默认YAML
|
// 初始化时设置默认YAML
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateYamlFromValues(DEFAULT_DNS_CONFIG);
|
updateYamlFromValues();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 切换编辑模式时的处理
|
// 切换编辑模式时的处理
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visualization) {
|
if (visualization) {
|
||||||
// 从YAML更新表单值
|
|
||||||
updateValuesFromYaml();
|
updateValuesFromYaml();
|
||||||
} else {
|
} else {
|
||||||
// 从表单值更新YAML
|
|
||||||
updateYamlFromValues();
|
updateYamlFromValues();
|
||||||
}
|
}
|
||||||
}, [visualization]);
|
}, [visualization]);
|
||||||
@@ -503,27 +495,63 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
// 处理保存操作
|
// 处理保存操作
|
||||||
const onSave = useLockFn(async () => {
|
const onSave = useLockFn(async () => {
|
||||||
try {
|
try {
|
||||||
let dnsConfig;
|
let config: Record<string, any>;
|
||||||
|
|
||||||
if (visualization) {
|
if (visualization) {
|
||||||
// 使用表单值
|
// 使用表单值生成配置
|
||||||
dnsConfig = generateDnsConfig();
|
config = {};
|
||||||
|
|
||||||
|
const dnsConfig = generateDnsConfig();
|
||||||
|
if (Object.keys(dnsConfig).length > 0) {
|
||||||
|
config.dns = dnsConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hosts = parseHosts(values.hosts);
|
||||||
|
if (Object.keys(hosts).length > 0) {
|
||||||
|
config.hosts = hosts;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 使用YAML编辑器的值
|
// 使用YAML编辑器的值
|
||||||
const parsedConfig = yaml.load(yamlContent);
|
const parsedConfig = yaml.load(yamlContent);
|
||||||
if (typeof parsedConfig !== "object" || parsedConfig === null) {
|
if (typeof parsedConfig !== "object" || parsedConfig === null) {
|
||||||
throw new Error(t("Invalid DNS configuration"));
|
throw new Error(t("Invalid configuration"));
|
||||||
}
|
}
|
||||||
dnsConfig = parsedConfig;
|
config = parsedConfig as Record<string, any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 不直接应用到clash配置,而是保存到单独文件
|
// 保存配置
|
||||||
await invoke("save_dns_config", { dnsConfig });
|
await invoke("save_dns_config", { dnsConfig: config });
|
||||||
|
|
||||||
|
// 验证配置
|
||||||
|
const [isValid, errorMsg] = await invoke<[boolean, string]>("validate_dns_config", {});
|
||||||
|
|
||||||
|
if (!isValid) {
|
||||||
|
let cleanErrorMsg = errorMsg;
|
||||||
|
|
||||||
|
// 提取关键错误信息
|
||||||
|
if (errorMsg.includes("level=error")) {
|
||||||
|
const errorLines = errorMsg.split('\n').filter(line =>
|
||||||
|
line.includes("level=error") ||
|
||||||
|
line.includes("level=fatal") ||
|
||||||
|
line.includes("failed")
|
||||||
|
);
|
||||||
|
|
||||||
|
if (errorLines.length > 0) {
|
||||||
|
cleanErrorMsg = errorLines.map(line => {
|
||||||
|
const msgMatch = line.match(/msg="([^"]+)"/);
|
||||||
|
return msgMatch ? msgMatch[1] : line;
|
||||||
|
}).join(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showNotice('error', t("DNS configuration error") + ": " + cleanErrorMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 如果DNS开关当前是打开的,则需要应用新的DNS配置
|
// 如果DNS开关当前是打开的,则需要应用新的DNS配置
|
||||||
if (clash?.dns?.enable) {
|
if (clash?.dns?.enable) {
|
||||||
await invoke("apply_dns_config", { apply: true });
|
await invoke("apply_dns_config", { apply: true });
|
||||||
mutateClash(); // 刷新UI
|
mutateClash();
|
||||||
}
|
}
|
||||||
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
@@ -539,15 +567,13 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
|
|
||||||
// 允许YAML编辑后立即分析和更新表单值
|
// 允许YAML编辑后立即分析和更新表单值
|
||||||
try {
|
try {
|
||||||
const dnsConfig = yaml.load(value) as any;
|
const config = yaml.load(value) as any;
|
||||||
if (dnsConfig && typeof dnsConfig === "object") {
|
if (config && typeof config === "object") {
|
||||||
// 稍微延迟更新,以避免性能问题
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
updateValuesFromYaml();
|
updateValuesFromConfig(config);
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 忽略解析错误,只有当YAML有效时才更新表单
|
|
||||||
console.log("YAML解析错误,忽略自动更新", err);
|
console.log("YAML解析错误,忽略自动更新", err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -568,7 +594,7 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
// 当可视化编辑模式下的值变化时,自动更新YAML
|
// 当可视化编辑模式下的值变化时,自动更新YAML
|
||||||
if (visualization) {
|
if (visualization) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
updateYamlFromValues(null);
|
updateYamlFromValues();
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,6 +654,13 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
|
|
||||||
{visualization ? (
|
{visualization ? (
|
||||||
<List>
|
<List>
|
||||||
|
<Typography
|
||||||
|
variant="subtitle1"
|
||||||
|
sx={{ mt: 1, mb: 1, fontWeight: "bold" }}
|
||||||
|
>
|
||||||
|
{t("DNS Settings")}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
<Item>
|
<Item>
|
||||||
<ListItemText primary={t("Enable DNS")} />
|
<ListItemText primary={t("Enable DNS")} />
|
||||||
<Switch
|
<Switch
|
||||||
@@ -714,7 +747,7 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
<Item>
|
<Item>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={t("Respect Rules")}
|
primary={t("Respect Rules")}
|
||||||
secondary={t("DNS连接遵守路由规则")}
|
secondary={t("DNS connections follow routing rules")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
edge="end"
|
edge="end"
|
||||||
@@ -750,7 +783,7 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
<Item>
|
<Item>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={t("Direct Nameserver Follow Policy")}
|
primary={t("Direct Nameserver Follow Policy")}
|
||||||
secondary={t("是否遵循nameserver-policy")}
|
secondary={t("Whether to follow nameserver policy")}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
edge="end"
|
edge="end"
|
||||||
@@ -942,6 +975,31 @@ export const DnsViewer = forwardRef<DialogRef>((props, ref) => {
|
|||||||
placeholder="+.google.com, +.facebook.com, +.youtube.com"
|
placeholder="+.google.com, +.facebook.com, +.youtube.com"
|
||||||
/>
|
/>
|
||||||
</Item>
|
</Item>
|
||||||
|
|
||||||
|
{/* Hosts 配置部分 */}
|
||||||
|
<Typography
|
||||||
|
variant="subtitle1"
|
||||||
|
sx={{ mt: 3, mb: 0, fontWeight: "bold" }}
|
||||||
|
>
|
||||||
|
{t("Hosts Settings")}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Item sx={{ flexDirection: "column", alignItems: "flex-start" }}>
|
||||||
|
<ListItemText
|
||||||
|
primary={t("Hosts")}
|
||||||
|
secondary={t("Custom domain to IP or domain mapping")}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
multiline
|
||||||
|
minRows={2}
|
||||||
|
maxRows={4}
|
||||||
|
size="small"
|
||||||
|
value={values.hosts}
|
||||||
|
onChange={handleChange("hosts")}
|
||||||
|
placeholder="*.clash.dev=127.0.0.1, alpha.clash.dev=::1, test.com=1.1.1.1;2.2.2.2, baidu.com=google.com"
|
||||||
|
/>
|
||||||
|
</Item>
|
||||||
</List>
|
</List>
|
||||||
) : (
|
) : (
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
|
|||||||
@@ -507,13 +507,13 @@
|
|||||||
"Prefer H3": "Prefer H3",
|
"Prefer H3": "Prefer H3",
|
||||||
"DNS DOH使用HTTP/3": "DNS DOH uses HTTP/3",
|
"DNS DOH使用HTTP/3": "DNS DOH uses HTTP/3",
|
||||||
"Respect Rules": "Respect Rules",
|
"Respect Rules": "Respect Rules",
|
||||||
"DNS连接遵守路由规则": "DNS connections follow routing rules",
|
"DNS connections follow routing rules": "DNS connections follow routing rules",
|
||||||
"Use Hosts": "Use Hosts",
|
"Use Hosts": "Use Hosts",
|
||||||
"Enable to resolve hosts through hosts file": "Enable to resolve hosts through hosts file",
|
"Enable to resolve hosts through hosts file": "Enable to resolve hosts through hosts file",
|
||||||
"Use System Hosts": "Use System Hosts",
|
"Use System Hosts": "Use System Hosts",
|
||||||
"Enable to resolve hosts through system hosts file": "Enable to resolve hosts through system hosts file",
|
"Enable to resolve hosts through system hosts file": "Enable to resolve hosts through system hosts file",
|
||||||
"Direct Nameserver Follow Policy": "Direct Nameserver Follow Policy",
|
"Direct Nameserver Follow Policy": "Direct Nameserver Follow Policy",
|
||||||
"是否遵循nameserver-policy": "Whether to follow nameserver policy",
|
"Whether to follow nameserver policy": "Whether to follow nameserver policy",
|
||||||
"Default Nameserver": "Default Nameserver",
|
"Default Nameserver": "Default Nameserver",
|
||||||
"Default DNS servers used to resolve DNS servers": "Default DNS servers used to resolve DNS servers",
|
"Default DNS servers used to resolve DNS servers": "Default DNS servers used to resolve DNS servers",
|
||||||
"Nameserver": "Nameserver",
|
"Nameserver": "Nameserver",
|
||||||
@@ -536,6 +536,9 @@
|
|||||||
"IP CIDRs not using fallback servers": "IP CIDRs not using fallback servers, comma separated",
|
"IP CIDRs not using fallback servers": "IP CIDRs not using fallback servers, comma separated",
|
||||||
"Fallback Domain": "Fallback Domain",
|
"Fallback Domain": "Fallback Domain",
|
||||||
"Domains using fallback servers": "Domains using fallback servers, comma separated",
|
"Domains using fallback servers": "Domains using fallback servers, comma separated",
|
||||||
|
"Hosts Settings": "Hosts Settings",
|
||||||
|
"Hosts": "Hosts",
|
||||||
|
"Custom domain to IP or domain mapping": "Custom domain to IP or domain mapping",
|
||||||
"Enable Alpha Channel": "Enable Alpha Channel",
|
"Enable Alpha Channel": "Enable Alpha Channel",
|
||||||
"Alpha versions may contain experimental features and bugs": "Alpha versions may contain experimental features and bugs",
|
"Alpha versions may contain experimental features and bugs": "Alpha versions may contain experimental features and bugs",
|
||||||
"Home Settings": "Home Settings",
|
"Home Settings": "Home Settings",
|
||||||
|
|||||||
@@ -501,13 +501,13 @@
|
|||||||
"Prefer H3": "Предпочитать H3",
|
"Prefer H3": "Предпочитать H3",
|
||||||
"DNS DOH使用HTTP/3": "DNS DOH использует http/3",
|
"DNS DOH使用HTTP/3": "DNS DOH использует http/3",
|
||||||
"Respect Rules": "Приоритизировать правила",
|
"Respect Rules": "Приоритизировать правила",
|
||||||
"DNS连接遵守路由规则": "Соединения DNS следуют правилам маршрутизации",
|
"DNS connections follow routing rules": "Соединения DNS следуют правилам маршрутизации",
|
||||||
"Use Hosts": "Использовать файл Hosts",
|
"Use Hosts": "Использовать файл Hosts",
|
||||||
"Enable to resolve hosts through hosts file": "Включить разрешение хостов через файл Hosts",
|
"Enable to resolve hosts through hosts file": "Включить разрешение хостов через файл Hosts",
|
||||||
"Use System Hosts": "Использовать системный файл Hosts",
|
"Use System Hosts": "Использовать системный файл Hosts",
|
||||||
"Enable to resolve hosts through system hosts file": "Включить разрешение хостов через системный файл Hosts",
|
"Enable to resolve hosts through system hosts file": "Включить разрешение хостов через системный файл Hosts",
|
||||||
"Direct Nameserver Follow Policy": "Прямой сервер имен следует политике",
|
"Direct Nameserver Follow Policy": "Прямой сервер имен следует политике",
|
||||||
"是否遵循nameserver-policy": "Следовать ли политике DNS-серверов",
|
"Whether to follow nameserver policy": "Следовать ли политике DNS-серверов",
|
||||||
"Default Nameserver": "DNS-сервер по умолчанию",
|
"Default Nameserver": "DNS-сервер по умолчанию",
|
||||||
"Default DNS servers used to resolve DNS servers": "DNS-серверы по умолчанию, используемые для разрешения адресов серверов DNS",
|
"Default DNS servers used to resolve DNS servers": "DNS-серверы по умолчанию, используемые для разрешения адресов серверов DNS",
|
||||||
"Nameserver": "DNS-сервер",
|
"Nameserver": "DNS-сервер",
|
||||||
|
|||||||
@@ -507,13 +507,13 @@
|
|||||||
"Prefer H3": "优先使用 HTTP/3",
|
"Prefer H3": "优先使用 HTTP/3",
|
||||||
"DNS DOH使用HTTP/3": "DNS DOH 使用 HTTP/3 协议",
|
"DNS DOH使用HTTP/3": "DNS DOH 使用 HTTP/3 协议",
|
||||||
"Respect Rules": "遵循路由规则",
|
"Respect Rules": "遵循路由规则",
|
||||||
"DNS连接遵守路由规则": "DNS 连接遵循路由规则",
|
"DNS connections follow routing rules": "DNS 连接遵循路由规则",
|
||||||
"Use Hosts": "使用 Hosts",
|
"Use Hosts": "使用 Hosts",
|
||||||
"Enable to resolve hosts through hosts file": "启用通过 hosts 文件解析域名",
|
"Enable to resolve hosts through hosts file": "启用通过 hosts 文件解析域名",
|
||||||
"Use System Hosts": "使用系统 Hosts",
|
"Use System Hosts": "使用系统 Hosts",
|
||||||
"Enable to resolve hosts through system hosts file": "启用通过系统 hosts 文件解析域名",
|
"Enable to resolve hosts through system hosts file": "启用通过系统 hosts 文件解析域名",
|
||||||
"Direct Nameserver Follow Policy": "直连域名服务器遵循策略",
|
"Direct Nameserver Follow Policy": "直连域名服务器遵循策略",
|
||||||
"是否遵循nameserver-policy": "是否遵循 nameserver-policy 设置",
|
"Whether to follow nameserver policy": "是否遵循 nameserver-policy 设置",
|
||||||
"Default Nameserver": "默认域名服务器",
|
"Default Nameserver": "默认域名服务器",
|
||||||
"Default DNS servers used to resolve DNS servers": "用于解析 DNS 服务器的默认 DNS 服务器",
|
"Default DNS servers used to resolve DNS servers": "用于解析 DNS 服务器的默认 DNS 服务器",
|
||||||
"Nameserver": "域名服务器",
|
"Nameserver": "域名服务器",
|
||||||
@@ -536,6 +536,9 @@
|
|||||||
"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": "使用回退服务器的域名,用逗号分隔",
|
||||||
|
"Hosts Settings": "Hosts 设置",
|
||||||
|
"Hosts": "Hosts",
|
||||||
|
"Custom domain to IP or domain mapping": "自定义域名到 IP 或域名的映射,用逗号分隔",
|
||||||
"Enable Alpha Channel": "启用 Alpha 通道",
|
"Enable Alpha Channel": "启用 Alpha 通道",
|
||||||
"Alpha versions may contain experimental features and bugs": "Alpha 版本可能包含实验性功能和已知问题",
|
"Alpha versions may contain experimental features and bugs": "Alpha 版本可能包含实验性功能和已知问题",
|
||||||
"Home Settings": "首页设置",
|
"Home Settings": "首页设置",
|
||||||
|
|||||||
Reference in New Issue
Block a user