feat: add hosts settings to DNS settings and enhance DNS config validation

This commit is contained in:
wonfen
2025-05-11 22:55:31 +08:00
parent b37b121afb
commit 10576780ed
9 changed files with 239 additions and 135 deletions

View File

@@ -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()),
}
}

View File

@@ -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");
}
} }
} }
} }

View File

@@ -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,

View File

@@ -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");

View File

@@ -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

View File

@@ -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);
if (Object.keys(hosts).length > 0) {
config.hosts = hosts;
} }
// 否则从当前表单值生成
const config = generateDnsConfig();
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

View File

@@ -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",

View File

@@ -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-сервер",

View File

@@ -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": "首页设置",