mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2026-02-11 04:00:32 +08:00
complete DNS (#6)
Co-authored-by: pompurin404 <pompurin404@mihomo.party>
This commit is contained in:
parent
7b7a58212b
commit
b80dbfbcfd
@ -21,7 +21,8 @@ export function setControledMihomoConfig(patch: Partial<IMihomoConfig>): void {
|
|||||||
}
|
}
|
||||||
if (patch.dns) {
|
if (patch.dns) {
|
||||||
const oldDns = controledMihomoConfig.dns || {}
|
const oldDns = controledMihomoConfig.dns || {}
|
||||||
const newDns = Object.assign(oldDns, patch.dns)
|
const newDns = { ...patch.dns }
|
||||||
|
newDns.enable = oldDns.enable
|
||||||
patch.dns = newDns
|
patch.dns = newDns
|
||||||
}
|
}
|
||||||
if (patch.sniffer) {
|
if (patch.sniffer) {
|
||||||
|
|||||||
@ -4,11 +4,14 @@ import { MdDeleteForever } from 'react-icons/md'
|
|||||||
import SettingCard from '@renderer/components/base/base-setting-card'
|
import SettingCard from '@renderer/components/base/base-setting-card'
|
||||||
import SettingItem from '@renderer/components/base/base-setting-item'
|
import SettingItem from '@renderer/components/base/base-setting-item'
|
||||||
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
||||||
|
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||||
import { restartCore } from '@renderer/utils/ipc'
|
import { restartCore } from '@renderer/utils/ipc'
|
||||||
import React, { Key, useState } from 'react'
|
import React, { Key, ReactNode, useState } from 'react'
|
||||||
|
|
||||||
const DNS: React.FC = () => {
|
const DNS: React.FC = () => {
|
||||||
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
|
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
|
||||||
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
|
const { nameserverPolicy, useNameserverPolicy } = appConfig || {}
|
||||||
const { dns, hosts } = controledMihomoConfig || {}
|
const { dns, hosts } = controledMihomoConfig || {}
|
||||||
const {
|
const {
|
||||||
ipv6 = false,
|
ipv6 = false,
|
||||||
@ -24,7 +27,9 @@ const DNS: React.FC = () => {
|
|||||||
'enhanced-mode': enhancedMode = 'fake-ip',
|
'enhanced-mode': enhancedMode = 'fake-ip',
|
||||||
'use-hosts': useHosts = false,
|
'use-hosts': useHosts = false,
|
||||||
'use-system-hosts': useSystemHosts = false,
|
'use-system-hosts': useSystemHosts = false,
|
||||||
nameserver = ['https://doh.pub/dns-query', 'https://dns.alidns.com/dns-query']
|
'respect-rules': respectRules = false,
|
||||||
|
nameserver = ['https://doh.pub/dns-query', 'https://dns.alidns.com/dns-query'],
|
||||||
|
'proxy-server-nameserver': proxyServerNameserver = []
|
||||||
} = dns || {}
|
} = dns || {}
|
||||||
|
|
||||||
const [values, setValues] = useState({
|
const [values, setValues] = useState({
|
||||||
@ -34,45 +39,76 @@ const DNS: React.FC = () => {
|
|||||||
fakeIPRange,
|
fakeIPRange,
|
||||||
fakeIPFilter,
|
fakeIPFilter,
|
||||||
useSystemHosts,
|
useSystemHosts,
|
||||||
|
respectRules,
|
||||||
nameserver,
|
nameserver,
|
||||||
|
proxyServerNameserver,
|
||||||
|
useNameserverPolicy,
|
||||||
|
nameserverPolicy: Object.entries(nameserverPolicy || {}).map(([domain, value]) => ({
|
||||||
|
domain,
|
||||||
|
value
|
||||||
|
})),
|
||||||
hosts: Object.entries(hosts || {}).map(([domain, value]) => ({ domain, value }))
|
hosts: Object.entries(hosts || {}).map(([domain, value]) => ({ domain, value }))
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleListChange = (type: string, value: string, index: number): void => {
|
const handleListChange = (type: string, value: string, index: number): void => {
|
||||||
const newValues = [...values[type]]
|
const list = [...values[type]]
|
||||||
if (index === newValues.length) {
|
if (value.trim()) {
|
||||||
if (value.trim() !== '') {
|
if (index < list.length) {
|
||||||
newValues.push(value)
|
list[index] = value
|
||||||
|
} else if (list.length < 4) {
|
||||||
|
list.push(value)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (value.trim() === '') {
|
list.splice(index, 1)
|
||||||
newValues.splice(index, 1)
|
|
||||||
} else {
|
|
||||||
newValues[index] = value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
setValues({ ...values, [type]: newValues })
|
setValues({ ...values, [type]: list.slice(0, 4) })
|
||||||
}
|
}
|
||||||
const handleHostsChange = (domain: string, value: string, index: number): void => {
|
|
||||||
const processValue = (val: string): string | string[] =>
|
|
||||||
val.includes(',') ? val.split(',').map((s) => s.trim()) : val.trim()
|
|
||||||
const isEmpty = (d: string, v: string | string[]): boolean =>
|
|
||||||
d === '' && (Array.isArray(v) ? v.every((item) => item === '') : v === '')
|
|
||||||
|
|
||||||
const newHosts = [...values.hosts]
|
const renderListInputs = (type: string, placeholder: string): ReactNode => {
|
||||||
if (!isEmpty(domain.trim(), processValue(value))) {
|
const currentItems = values[type].slice(0, 4)
|
||||||
if (index === newHosts.length) {
|
const showNewLine = currentItems.length < 4 && currentItems.every((item) => item.trim() !== '')
|
||||||
newHosts.push({ domain: domain.trim(), value: processValue(value) })
|
|
||||||
} else {
|
return [...currentItems, ...(showNewLine ? [''] : [])].slice(0, 4).map((item, index) => (
|
||||||
newHosts[index] = { domain: domain.trim(), value: processValue(value) }
|
<div key={index} className="mt-2 flex">
|
||||||
}
|
<Input
|
||||||
} else if (index < newHosts.length) {
|
fullWidth
|
||||||
newHosts.splice(index, 1)
|
size="sm"
|
||||||
}
|
placeholder={placeholder}
|
||||||
setValues({ ...values, hosts: newHosts })
|
value={typeof item === 'string' ? item : item.domain}
|
||||||
|
onValueChange={(v) => handleListChange(type, v, index)}
|
||||||
|
/>
|
||||||
|
{index < values[type].length && (
|
||||||
|
<Button
|
||||||
|
className="ml-2"
|
||||||
|
size="sm"
|
||||||
|
variant="flat"
|
||||||
|
color="warning"
|
||||||
|
onClick={() => handleListChange(type, '', index)}
|
||||||
|
>
|
||||||
|
<MdDeleteForever className="text-lg" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubkeyChange = (type: string, domain: string, value: string, index: number): void => {
|
||||||
|
const list = [...values[type]]
|
||||||
|
const processedValue = value.includes(',')
|
||||||
|
? value.split(',').map((s: string) => s.trim())
|
||||||
|
: value.trim()
|
||||||
|
if (domain || processedValue) list[index] = { domain: domain.trim(), value: processedValue }
|
||||||
|
else list.splice(index, 1)
|
||||||
|
setValues({ ...values, [type]: list })
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSave = async (patch: Partial<IMihomoConfig>): Promise<void> => {
|
const onSave = async (patch: Partial<IMihomoConfig>): Promise<void> => {
|
||||||
|
await patchAppConfig({
|
||||||
|
nameserverPolicy: Object.fromEntries(
|
||||||
|
values.nameserverPolicy.map(({ domain, value }) => [domain, value])
|
||||||
|
),
|
||||||
|
useNameserverPolicy: values.useNameserverPolicy
|
||||||
|
})
|
||||||
await patchControledMihomoConfig(patch)
|
await patchControledMihomoConfig(patch)
|
||||||
await restartCore()
|
await restartCore()
|
||||||
}
|
}
|
||||||
@ -85,22 +121,29 @@ const DNS: React.FC = () => {
|
|||||||
size="sm"
|
size="sm"
|
||||||
color="primary"
|
color="primary"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
const hostsObject = values.hosts.reduce((acc, { domain, value }) => {
|
const hostsObject = Object.fromEntries(
|
||||||
if (domain) {
|
values.hosts.map(({ domain, value }) => [domain, value])
|
||||||
acc[domain] = value
|
)
|
||||||
}
|
const dnsConfig = {
|
||||||
return acc
|
ipv6: values.ipv6,
|
||||||
}, {})
|
'fake-ip-range': values.fakeIPRange,
|
||||||
|
'fake-ip-filter': values.fakeIPFilter,
|
||||||
|
'enhanced-mode': values.enhancedMode,
|
||||||
|
'use-hosts': values.useHosts,
|
||||||
|
'use-system-hosts': values.useSystemHosts,
|
||||||
|
'respect-rules': values.respectRules,
|
||||||
|
nameserver: values.nameserver,
|
||||||
|
'proxy-server-nameserver': values.proxyServerNameserver,
|
||||||
|
fallback: [],
|
||||||
|
'fallback-filter': {}
|
||||||
|
}
|
||||||
|
if (values.useNameserverPolicy) {
|
||||||
|
dnsConfig['nameserver-policy'] = Object.fromEntries(
|
||||||
|
values.nameserverPolicy.map(({ domain, value }) => [domain, value])
|
||||||
|
)
|
||||||
|
}
|
||||||
onSave({
|
onSave({
|
||||||
dns: {
|
dns: dnsConfig,
|
||||||
ipv6: values.ipv6,
|
|
||||||
'fake-ip-range': values.fakeIPRange,
|
|
||||||
'fake-ip-filter': values.fakeIPFilter,
|
|
||||||
'enhanced-mode': values.enhancedMode,
|
|
||||||
'use-hosts': values.useHosts,
|
|
||||||
'use-system-hosts': values.useSystemHosts,
|
|
||||||
nameserver: values.nameserver
|
|
||||||
},
|
|
||||||
hosts: hostsObject
|
hosts: hostsObject
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
@ -136,28 +179,7 @@ const DNS: React.FC = () => {
|
|||||||
</SettingItem>
|
</SettingItem>
|
||||||
<div className="flex flex-col items-stretch">
|
<div className="flex flex-col items-stretch">
|
||||||
<h3 className="select-none">真实IP回应</h3>
|
<h3 className="select-none">真实IP回应</h3>
|
||||||
{[...values.fakeIPFilter, ''].map((ns, index) => (
|
{renderListInputs('fakeIPFilter', '例: +.lan')}
|
||||||
<div key={index} className="mt-2 flex">
|
|
||||||
<Input
|
|
||||||
fullWidth
|
|
||||||
size="sm"
|
|
||||||
placeholder="例: +.lan"
|
|
||||||
value={ns}
|
|
||||||
onValueChange={(v) => handleListChange('fakeIPFilter', v, index)}
|
|
||||||
/>
|
|
||||||
{index < values.fakeIPFilter.length && (
|
|
||||||
<Button
|
|
||||||
className="ml-2"
|
|
||||||
size="sm"
|
|
||||||
variant="flat"
|
|
||||||
color="warning"
|
|
||||||
onClick={() => handleListChange('fakeIPFilter', '', index)}
|
|
||||||
>
|
|
||||||
<MdDeleteForever className="text-lg" />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
<Divider className="my-2" />
|
<Divider className="my-2" />
|
||||||
</>
|
</>
|
||||||
@ -171,32 +193,87 @@ const DNS: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
<SettingItem title="连接遵守规则" divider>
|
||||||
|
<Switch
|
||||||
|
size="sm"
|
||||||
|
isSelected={values.respectRules}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
setValues({ ...values, respectRules: v })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SettingItem>
|
||||||
|
|
||||||
<div className="flex flex-col items-stretch">
|
<div className="flex flex-col items-stretch">
|
||||||
<h3 className="select-none">DNS服务器</h3>
|
<h3 className="select-none">代理节点域名解析</h3>
|
||||||
{[...values.nameserver, ''].map((ns, index) => (
|
{renderListInputs('proxyServerNameserver', '例: tls://223.5.5.5')}
|
||||||
<div key={index} className="mt-2 flex">
|
|
||||||
<Input
|
|
||||||
fullWidth
|
|
||||||
size="sm"
|
|
||||||
placeholder="例: tls://223.5.5.5"
|
|
||||||
value={ns}
|
|
||||||
onValueChange={(v) => handleListChange('nameserver', v, index)}
|
|
||||||
/>
|
|
||||||
{index < values.nameserver.length && (
|
|
||||||
<Button
|
|
||||||
className="ml-2"
|
|
||||||
size="sm"
|
|
||||||
variant="flat"
|
|
||||||
color="warning"
|
|
||||||
onClick={() => handleListChange('nameserver', '', index)}
|
|
||||||
>
|
|
||||||
<MdDeleteForever className="text-lg" />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
<Divider className="my-2" />
|
<Divider className="my-2" />
|
||||||
|
<div className="flex flex-col items-stretch">
|
||||||
|
<h3 className="select-none">DNS服务器</h3>
|
||||||
|
{renderListInputs('nameserver', '例: tls://223.5.5.5')}
|
||||||
|
</div>
|
||||||
|
<Divider className="my-2" />
|
||||||
|
<SettingItem title="覆盖DNS策略" divider>
|
||||||
|
<Switch
|
||||||
|
size="sm"
|
||||||
|
isSelected={values.useNameserverPolicy}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
setValues({ ...values, useNameserverPolicy: v })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SettingItem>
|
||||||
|
{values.useNameserverPolicy && (
|
||||||
|
<div className="flex flex-col items-stretch">
|
||||||
|
<div className="flex flex-col items-stretch">
|
||||||
|
<h3 className="mb-2"></h3>
|
||||||
|
{[...values.nameserverPolicy, { domain: '', value: '' }].map(
|
||||||
|
({ domain, value }, index) => (
|
||||||
|
<div key={index} className="flex mb-2">
|
||||||
|
<div className="flex-[4]">
|
||||||
|
<Input
|
||||||
|
size="sm"
|
||||||
|
fullWidth
|
||||||
|
placeholder="域名"
|
||||||
|
value={domain}
|
||||||
|
onValueChange={(v) =>
|
||||||
|
handleSubkeyChange(
|
||||||
|
'nameserverPolicy',
|
||||||
|
v,
|
||||||
|
Array.isArray(value) ? value.join(',') : value,
|
||||||
|
index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className="select-none mx-2">:</span>
|
||||||
|
<div className="flex-[6] flex">
|
||||||
|
<Input
|
||||||
|
size="sm"
|
||||||
|
fullWidth
|
||||||
|
placeholder="DNS服务器"
|
||||||
|
value={Array.isArray(value) ? value.join(',') : value}
|
||||||
|
onValueChange={(v) =>
|
||||||
|
handleSubkeyChange('nameserverPolicy', domain, v, index)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{index < values.nameserverPolicy.length && (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
color="warning"
|
||||||
|
variant="flat"
|
||||||
|
className="ml-2"
|
||||||
|
onClick={() => handleSubkeyChange('nameserverPolicy', '', '', index)}
|
||||||
|
>
|
||||||
|
<MdDeleteForever className="text-lg" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<SettingItem title="使用系统hosts" divider>
|
<SettingItem title="使用系统hosts" divider>
|
||||||
<Switch
|
<Switch
|
||||||
size="sm"
|
size="sm"
|
||||||
@ -227,7 +304,12 @@ const DNS: React.FC = () => {
|
|||||||
placeholder="域名"
|
placeholder="域名"
|
||||||
value={domain}
|
value={domain}
|
||||||
onValueChange={(v) =>
|
onValueChange={(v) =>
|
||||||
handleHostsChange(v, Array.isArray(value) ? value.join(',') : value, index)
|
handleSubkeyChange(
|
||||||
|
'hosts',
|
||||||
|
v,
|
||||||
|
Array.isArray(value) ? value.join(',') : value,
|
||||||
|
index
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -238,7 +320,7 @@ const DNS: React.FC = () => {
|
|||||||
fullWidth
|
fullWidth
|
||||||
placeholder="域名或IP"
|
placeholder="域名或IP"
|
||||||
value={Array.isArray(value) ? value.join(',') : value}
|
value={Array.isArray(value) ? value.join(',') : value}
|
||||||
onValueChange={(v) => handleHostsChange(domain, v, index)}
|
onValueChange={(v) => handleSubkeyChange('hosts', domain, v, index)}
|
||||||
/>
|
/>
|
||||||
{index < values.hosts.length && (
|
{index < values.hosts.length && (
|
||||||
<Button
|
<Button
|
||||||
@ -246,7 +328,7 @@ const DNS: React.FC = () => {
|
|||||||
color="warning"
|
color="warning"
|
||||||
variant="flat"
|
variant="flat"
|
||||||
className="ml-2"
|
className="ml-2"
|
||||||
onClick={() => handleHostsChange('', '', index)}
|
onClick={() => handleSubkeyChange('hosts', '', '', index)}
|
||||||
>
|
>
|
||||||
<MdDeleteForever className="text-lg" />
|
<MdDeleteForever className="text-lg" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
4
src/shared/types.d.ts
vendored
4
src/shared/types.d.ts
vendored
@ -198,6 +198,8 @@ interface IAppConfig {
|
|||||||
delayTestUrl?: string
|
delayTestUrl?: string
|
||||||
delayTestTimeout?: number
|
delayTestTimeout?: number
|
||||||
encryptedPassword?: Buffer
|
encryptedPassword?: Buffer
|
||||||
|
useNameserverPolicy: boolean
|
||||||
|
nameserverPolicy: { [key: string]: string | string[] }
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMihomoTunConfig {
|
interface IMihomoTunConfig {
|
||||||
@ -240,6 +242,8 @@ interface IMihomoDNSConfig {
|
|||||||
'use-system-hosts'?: boolean
|
'use-system-hosts'?: boolean
|
||||||
'respect-rules'?: boolean
|
'respect-rules'?: boolean
|
||||||
nameserver?: string[]
|
nameserver?: string[]
|
||||||
|
fallback?: string[]
|
||||||
|
'fallback-filter'?: { [key: string]: boolean | string | string[] }
|
||||||
'proxy-server-nameserver'?: string[]
|
'proxy-server-nameserver'?: string[]
|
||||||
'nameserver-policy'?: { [key: string]: string | string[] }
|
'nameserver-policy'?: { [key: string]: string | string[] }
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user