Skip to content

Commit b80dbfb

Browse files
xishang0128pompurin404
and
pompurin404
authored
complete DNS (#6)
Co-authored-by: pompurin404 <pompurin404@mihomo.party>
1 parent 7b7a582 commit b80dbfb

File tree

3 files changed

+178
-91
lines changed

3 files changed

+178
-91
lines changed

src/main/config/controledMihomo.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export function setControledMihomoConfig(patch: Partial<IMihomoConfig>): void {
2121
}
2222
if (patch.dns) {
2323
const oldDns = controledMihomoConfig.dns || {}
24-
const newDns = Object.assign(oldDns, patch.dns)
24+
const newDns = { ...patch.dns }
25+
newDns.enable = oldDns.enable
2526
patch.dns = newDns
2627
}
2728
if (patch.sniffer) {

src/renderer/src/pages/dns.tsx

+172-90
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ import { MdDeleteForever } from 'react-icons/md'
44
import SettingCard from '@renderer/components/base/base-setting-card'
55
import SettingItem from '@renderer/components/base/base-setting-item'
66
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
7+
import { useAppConfig } from '@renderer/hooks/use-app-config'
78
import { restartCore } from '@renderer/utils/ipc'
8-
import React, { Key, useState } from 'react'
9+
import React, { Key, ReactNode, useState } from 'react'
910

1011
const DNS: React.FC = () => {
1112
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
13+
const { appConfig, patchAppConfig } = useAppConfig()
14+
const { nameserverPolicy, useNameserverPolicy } = appConfig || {}
1215
const { dns, hosts } = controledMihomoConfig || {}
1316
const {
1417
ipv6 = false,
@@ -24,7 +27,9 @@ const DNS: React.FC = () => {
2427
'enhanced-mode': enhancedMode = 'fake-ip',
2528
'use-hosts': useHosts = false,
2629
'use-system-hosts': useSystemHosts = false,
27-
nameserver = ['https://doh.pub/dns-query', 'https://dns.alidns.com/dns-query']
30+
'respect-rules': respectRules = false,
31+
nameserver = ['https://doh.pub/dns-query', 'https://dns.alidns.com/dns-query'],
32+
'proxy-server-nameserver': proxyServerNameserver = []
2833
} = dns || {}
2934

3035
const [values, setValues] = useState({
@@ -34,45 +39,76 @@ const DNS: React.FC = () => {
3439
fakeIPRange,
3540
fakeIPFilter,
3641
useSystemHosts,
42+
respectRules,
3743
nameserver,
44+
proxyServerNameserver,
45+
useNameserverPolicy,
46+
nameserverPolicy: Object.entries(nameserverPolicy || {}).map(([domain, value]) => ({
47+
domain,
48+
value
49+
})),
3850
hosts: Object.entries(hosts || {}).map(([domain, value]) => ({ domain, value }))
3951
})
4052

4153
const handleListChange = (type: string, value: string, index: number): void => {
42-
const newValues = [...values[type]]
43-
if (index === newValues.length) {
44-
if (value.trim() !== '') {
45-
newValues.push(value)
54+
const list = [...values[type]]
55+
if (value.trim()) {
56+
if (index < list.length) {
57+
list[index] = value
58+
} else if (list.length < 4) {
59+
list.push(value)
4660
}
4761
} else {
48-
if (value.trim() === '') {
49-
newValues.splice(index, 1)
50-
} else {
51-
newValues[index] = value
52-
}
62+
list.splice(index, 1)
5363
}
54-
setValues({ ...values, [type]: newValues })
64+
setValues({ ...values, [type]: list.slice(0, 4) })
5565
}
56-
const handleHostsChange = (domain: string, value: string, index: number): void => {
57-
const processValue = (val: string): string | string[] =>
58-
val.includes(',') ? val.split(',').map((s) => s.trim()) : val.trim()
59-
const isEmpty = (d: string, v: string | string[]): boolean =>
60-
d === '' && (Array.isArray(v) ? v.every((item) => item === '') : v === '')
6166

62-
const newHosts = [...values.hosts]
63-
if (!isEmpty(domain.trim(), processValue(value))) {
64-
if (index === newHosts.length) {
65-
newHosts.push({ domain: domain.trim(), value: processValue(value) })
66-
} else {
67-
newHosts[index] = { domain: domain.trim(), value: processValue(value) }
68-
}
69-
} else if (index < newHosts.length) {
70-
newHosts.splice(index, 1)
71-
}
72-
setValues({ ...values, hosts: newHosts })
67+
const renderListInputs = (type: string, placeholder: string): ReactNode => {
68+
const currentItems = values[type].slice(0, 4)
69+
const showNewLine = currentItems.length < 4 && currentItems.every((item) => item.trim() !== '')
70+
71+
return [...currentItems, ...(showNewLine ? [''] : [])].slice(0, 4).map((item, index) => (
72+
<div key={index} className="mt-2 flex">
73+
<Input
74+
fullWidth
75+
size="sm"
76+
placeholder={placeholder}
77+
value={typeof item === 'string' ? item : item.domain}
78+
onValueChange={(v) => handleListChange(type, v, index)}
79+
/>
80+
{index < values[type].length && (
81+
<Button
82+
className="ml-2"
83+
size="sm"
84+
variant="flat"
85+
color="warning"
86+
onClick={() => handleListChange(type, '', index)}
87+
>
88+
<MdDeleteForever className="text-lg" />
89+
</Button>
90+
)}
91+
</div>
92+
))
93+
}
94+
95+
const handleSubkeyChange = (type: string, domain: string, value: string, index: number): void => {
96+
const list = [...values[type]]
97+
const processedValue = value.includes(',')
98+
? value.split(',').map((s: string) => s.trim())
99+
: value.trim()
100+
if (domain || processedValue) list[index] = { domain: domain.trim(), value: processedValue }
101+
else list.splice(index, 1)
102+
setValues({ ...values, [type]: list })
73103
}
74104

75105
const onSave = async (patch: Partial<IMihomoConfig>): Promise<void> => {
106+
await patchAppConfig({
107+
nameserverPolicy: Object.fromEntries(
108+
values.nameserverPolicy.map(({ domain, value }) => [domain, value])
109+
),
110+
useNameserverPolicy: values.useNameserverPolicy
111+
})
76112
await patchControledMihomoConfig(patch)
77113
await restartCore()
78114
}
@@ -85,22 +121,29 @@ const DNS: React.FC = () => {
85121
size="sm"
86122
color="primary"
87123
onPress={() => {
88-
const hostsObject = values.hosts.reduce((acc, { domain, value }) => {
89-
if (domain) {
90-
acc[domain] = value
91-
}
92-
return acc
93-
}, {})
124+
const hostsObject = Object.fromEntries(
125+
values.hosts.map(({ domain, value }) => [domain, value])
126+
)
127+
const dnsConfig = {
128+
ipv6: values.ipv6,
129+
'fake-ip-range': values.fakeIPRange,
130+
'fake-ip-filter': values.fakeIPFilter,
131+
'enhanced-mode': values.enhancedMode,
132+
'use-hosts': values.useHosts,
133+
'use-system-hosts': values.useSystemHosts,
134+
'respect-rules': values.respectRules,
135+
nameserver: values.nameserver,
136+
'proxy-server-nameserver': values.proxyServerNameserver,
137+
fallback: [],
138+
'fallback-filter': {}
139+
}
140+
if (values.useNameserverPolicy) {
141+
dnsConfig['nameserver-policy'] = Object.fromEntries(
142+
values.nameserverPolicy.map(({ domain, value }) => [domain, value])
143+
)
144+
}
94145
onSave({
95-
dns: {
96-
ipv6: values.ipv6,
97-
'fake-ip-range': values.fakeIPRange,
98-
'fake-ip-filter': values.fakeIPFilter,
99-
'enhanced-mode': values.enhancedMode,
100-
'use-hosts': values.useHosts,
101-
'use-system-hosts': values.useSystemHosts,
102-
nameserver: values.nameserver
103-
},
146+
dns: dnsConfig,
104147
hosts: hostsObject
105148
})
106149
}}
@@ -136,28 +179,7 @@ const DNS: React.FC = () => {
136179
</SettingItem>
137180
<div className="flex flex-col items-stretch">
138181
<h3 className="select-none">真实IP回应</h3>
139-
{[...values.fakeIPFilter, ''].map((ns, index) => (
140-
<div key={index} className="mt-2 flex">
141-
<Input
142-
fullWidth
143-
size="sm"
144-
placeholder="例: +.lan"
145-
value={ns}
146-
onValueChange={(v) => handleListChange('fakeIPFilter', v, index)}
147-
/>
148-
{index < values.fakeIPFilter.length && (
149-
<Button
150-
className="ml-2"
151-
size="sm"
152-
variant="flat"
153-
color="warning"
154-
onClick={() => handleListChange('fakeIPFilter', '', index)}
155-
>
156-
<MdDeleteForever className="text-lg" />
157-
</Button>
158-
)}
159-
</div>
160-
))}
182+
{renderListInputs('fakeIPFilter', '例: +.lan')}
161183
</div>
162184
<Divider className="my-2" />
163185
</>
@@ -171,32 +193,87 @@ const DNS: React.FC = () => {
171193
}}
172194
/>
173195
</SettingItem>
196+
<SettingItem title="连接遵守规则" divider>
197+
<Switch
198+
size="sm"
199+
isSelected={values.respectRules}
200+
onValueChange={(v) => {
201+
setValues({ ...values, respectRules: v })
202+
}}
203+
/>
204+
</SettingItem>
205+
206+
<div className="flex flex-col items-stretch">
207+
<h3 className="select-none">代理节点域名解析</h3>
208+
{renderListInputs('proxyServerNameserver', '例: tls://223.5.5.5')}
209+
</div>
210+
<Divider className="my-2" />
174211
<div className="flex flex-col items-stretch">
175212
<h3 className="select-none">DNS服务器</h3>
176-
{[...values.nameserver, ''].map((ns, index) => (
177-
<div key={index} className="mt-2 flex">
178-
<Input
179-
fullWidth
180-
size="sm"
181-
placeholder="例: tls://223.5.5.5"
182-
value={ns}
183-
onValueChange={(v) => handleListChange('nameserver', v, index)}
184-
/>
185-
{index < values.nameserver.length && (
186-
<Button
187-
className="ml-2"
188-
size="sm"
189-
variant="flat"
190-
color="warning"
191-
onClick={() => handleListChange('nameserver', '', index)}
192-
>
193-
<MdDeleteForever className="text-lg" />
194-
</Button>
195-
)}
196-
</div>
197-
))}
213+
{renderListInputs('nameserver', '例: tls://223.5.5.5')}
198214
</div>
199215
<Divider className="my-2" />
216+
<SettingItem title="覆盖DNS策略" divider>
217+
<Switch
218+
size="sm"
219+
isSelected={values.useNameserverPolicy}
220+
onValueChange={(v) => {
221+
setValues({ ...values, useNameserverPolicy: v })
222+
}}
223+
/>
224+
</SettingItem>
225+
{values.useNameserverPolicy && (
226+
<div className="flex flex-col items-stretch">
227+
<div className="flex flex-col items-stretch">
228+
<h3 className="mb-2"></h3>
229+
{[...values.nameserverPolicy, { domain: '', value: '' }].map(
230+
({ domain, value }, index) => (
231+
<div key={index} className="flex mb-2">
232+
<div className="flex-[4]">
233+
<Input
234+
size="sm"
235+
fullWidth
236+
placeholder="域名"
237+
value={domain}
238+
onValueChange={(v) =>
239+
handleSubkeyChange(
240+
'nameserverPolicy',
241+
v,
242+
Array.isArray(value) ? value.join(',') : value,
243+
index
244+
)
245+
}
246+
/>
247+
</div>
248+
<span className="select-none mx-2">:</span>
249+
<div className="flex-[6] flex">
250+
<Input
251+
size="sm"
252+
fullWidth
253+
placeholder="DNS服务器"
254+
value={Array.isArray(value) ? value.join(',') : value}
255+
onValueChange={(v) =>
256+
handleSubkeyChange('nameserverPolicy', domain, v, index)
257+
}
258+
/>
259+
{index < values.nameserverPolicy.length && (
260+
<Button
261+
size="sm"
262+
color="warning"
263+
variant="flat"
264+
className="ml-2"
265+
onClick={() => handleSubkeyChange('nameserverPolicy', '', '', index)}
266+
>
267+
<MdDeleteForever className="text-lg" />
268+
</Button>
269+
)}
270+
</div>
271+
</div>
272+
)
273+
)}
274+
</div>
275+
</div>
276+
)}
200277
<SettingItem title="使用系统hosts" divider>
201278
<Switch
202279
size="sm"
@@ -227,7 +304,12 @@ const DNS: React.FC = () => {
227304
placeholder="域名"
228305
value={domain}
229306
onValueChange={(v) =>
230-
handleHostsChange(v, Array.isArray(value) ? value.join(',') : value, index)
307+
handleSubkeyChange(
308+
'hosts',
309+
v,
310+
Array.isArray(value) ? value.join(',') : value,
311+
index
312+
)
231313
}
232314
/>
233315
</div>
@@ -238,15 +320,15 @@ const DNS: React.FC = () => {
238320
fullWidth
239321
placeholder="域名或IP"
240322
value={Array.isArray(value) ? value.join(',') : value}
241-
onValueChange={(v) => handleHostsChange(domain, v, index)}
323+
onValueChange={(v) => handleSubkeyChange('hosts', domain, v, index)}
242324
/>
243325
{index < values.hosts.length && (
244326
<Button
245327
size="sm"
246328
color="warning"
247329
variant="flat"
248330
className="ml-2"
249-
onClick={() => handleHostsChange('', '', index)}
331+
onClick={() => handleSubkeyChange('hosts', '', '', index)}
250332
>
251333
<MdDeleteForever className="text-lg" />
252334
</Button>

src/shared/types.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ interface IAppConfig {
198198
delayTestUrl?: string
199199
delayTestTimeout?: number
200200
encryptedPassword?: Buffer
201+
useNameserverPolicy: boolean
202+
nameserverPolicy: { [key: string]: string | string[] }
201203
}
202204

203205
interface IMihomoTunConfig {
@@ -240,6 +242,8 @@ interface IMihomoDNSConfig {
240242
'use-system-hosts'?: boolean
241243
'respect-rules'?: boolean
242244
nameserver?: string[]
245+
fallback?: string[]
246+
'fallback-filter'?: { [key: string]: boolean | string | string[] }
243247
'proxy-server-nameserver'?: string[]
244248
'nameserver-policy'?: { [key: string]: string | string[] }
245249
}

0 commit comments

Comments
 (0)