try to set dns

This commit is contained in:
pompurin404 2024-09-01 20:43:03 +08:00
parent bb60d9dcfb
commit 90f5db2b7c
No known key found for this signature in database
5 changed files with 114 additions and 9 deletions

View File

@ -2,6 +2,10 @@
- 1.2.x YAML覆写语法有所变动请更新后参考文档进行修改
### New Features
- MacOS 支持自动设置系统DNS
### Performance Improvements
- 优化规则/代理页面性能

View File

@ -7,7 +7,12 @@ import {
mihomoWorkDir
} from '../utils/dirs'
import { generateProfile } from './factory'
import { getAppConfig, patchAppConfig, patchControledMihomoConfig } from '../config'
import {
getAppConfig,
getControledMihomoConfig,
patchAppConfig,
patchControledMihomoConfig
} from '../config'
import { dialog, safeStorage } from 'electron'
import { pauseWebsockets, startMihomoTraffic } from './mihomoApi'
import { writeFile } from 'fs/promises'
@ -18,12 +23,16 @@ let child: ChildProcess
let retry = 10
export async function startCore(): Promise<void> {
const { core = 'mihomo' } = await getAppConfig()
const { core = 'mihomo', autoSetDNS = true } = await getAppConfig()
const { tun } = await getControledMihomoConfig()
const corePath = mihomoCorePath(core)
await autoGrantCorePermition(corePath)
await generateProfile()
await checkProfile()
stopCore()
await stopCore()
if (tun?.enable && autoSetDNS) {
await setPublicDNS()
}
child = spawn(corePath, ['-d', mihomoWorkDir()])
child.on('close', async (code, signal) => {
await writeFile(logPath(), `[Manager]: Core closed, code: ${code}, signal: ${signal}\n`, {
@ -34,13 +43,13 @@ export async function startCore(): Promise<void> {
retry--
await restartCore()
} else {
stopCore()
await stopCore()
}
})
return new Promise((resolve, reject) => {
child.stdout?.on('data', async (data) => {
if (data.toString().includes('updater: finished')) {
stopCore()
await stopCore()
await startCore()
}
if (data.toString().includes('configure tun interface: operation not permitted')) {
@ -54,7 +63,7 @@ export async function startCore(): Promise<void> {
resolve(await startCore())
} else {
dialog.showErrorBox('内核连接失败', '请尝试更改外部控制端口后重启内核')
stopCore()
await stopCore()
reject('External controller listen error')
}
}
@ -69,7 +78,13 @@ export async function startCore(): Promise<void> {
})
}
export function stopCore(): void {
export async function stopCore(): Promise<void> {
try {
await recoverDNS()
} catch (error) {
// todo
}
if (child) {
child.removeAllListeners()
child.kill('SIGINT')
@ -149,3 +164,72 @@ export async function manualGrantCorePermition(password?: string): Promise<void>
export function isEncryptionAvailable(): boolean {
return safeStorage.isEncryptionAvailable()
}
async function getDefaultService(password?: string): Promise<string> {
const execPromise = promisify(exec)
let sudo = ''
if (password) sudo = `echo "${password}" | sudo -S `
const { stdout: deviceOut } = await execPromise(`${sudo}route -n get default`)
let device = deviceOut.split('\n').find((s) => s.includes('interface:'))
device = device?.trim().split(' ').slice(1).join(' ')
if (!device) throw new Error('Get device failed')
const { stdout: hardwareOut } = await execPromise(`${sudo}networksetup -listallhardwareports`)
const hardware = hardwareOut
.split('Ethernet Address:')
.find((s) => s.includes(`Device: ${device}`))
if (!hardware) throw new Error('Get hardware failed')
for (const line of hardware.split('\n')) {
if (line.startsWith('Hardware Port:')) {
return line.trim().split(' ').slice(2).join(' ')
}
}
throw new Error('Get service failed')
}
async function getOriginDNS(password?: string): Promise<void> {
const execPromise = promisify(exec)
let sudo = ''
if (password) sudo = `echo "${password}" | sudo -S `
const service = await getDefaultService(password)
const { stdout: dns } = await execPromise(`${sudo}networksetup -getdnsservers ${service}`)
if (dns.startsWith("There aren't any DNS Servers set on")) {
await patchAppConfig({ originDNS: 'Empty' })
} else {
await patchAppConfig({ originDNS: dns.trim().replace(/\n/g, ' ') })
}
}
async function setDNS(dns: string, password?: string): Promise<void> {
const service = await getDefaultService(password)
let sudo = ''
if (password) sudo = `echo "${password}" | sudo -S `
const execPromise = promisify(exec)
await execPromise(`${sudo}networksetup -setdnsservers ${service} ${dns}`)
// todo
}
async function setPublicDNS(): Promise<void> {
if (process.platform !== 'darwin') return
const { originDNS, encryptedPassword } = await getAppConfig()
if (!originDNS) {
let password: string | undefined
if (encryptedPassword && isEncryptionAvailable()) {
password = safeStorage.decryptString(Buffer.from(encryptedPassword))
}
await getOriginDNS(password)
await setDNS('223.5.5.5', password)
}
}
async function recoverDNS(): Promise<void> {
if (process.platform !== 'darwin') return
const { originDNS, encryptedPassword } = await getAppConfig()
if (originDNS) {
let password: string | undefined
if (encryptedPassword && isEncryptionAvailable()) {
password = safeStorage.decryptString(Buffer.from(encryptedPassword))
}
await setDNS(originDNS, password)
await patchAppConfig({ originDNS: undefined })
}
}

View File

@ -68,9 +68,9 @@ app.on('window-all-closed', (e) => {
// }
})
app.on('before-quit', () => {
app.on('before-quit', async () => {
pauseWebsockets()
stopCore()
await stopCore()
triggerSysProxy(false)
app.exit()
})

View File

@ -7,9 +7,12 @@ import { manualGrantCorePermition, restartCore, setupFirewall } from '@renderer/
import { platform } from '@renderer/utils/init'
import React, { Key, useState } from 'react'
import BasePasswordModal from '@renderer/components/base/base-password-modal'
import { useAppConfig } from '@renderer/hooks/use-app-config'
const Tun: React.FC = () => {
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
const { appConfig, patchAppConfig } = useAppConfig()
const { autoSetDNS = true } = appConfig || {}
const { tun } = controledMihomoConfig || {}
const [loading, setLoading] = useState(false)
const [openPasswordModal, setOpenPasswordModal] = useState(false)
@ -137,6 +140,18 @@ const Tun: React.FC = () => {
</Button>
</SettingItem>
)}
{platform === 'darwin' && (
<SettingItem title="自动设置系统DNS" divider>
<Switch
size="sm"
isSelected={autoSetDNS}
onValueChange={async (v) => {
await patchAppConfig({ autoSetDNS: v })
}}
/>
</SettingItem>
)}
<SettingItem title="Tun 模式堆栈" divider>
<Tabs
size="sm"

View File

@ -217,6 +217,8 @@ interface IAppConfig {
proxyDisplayOrder: 'default' | 'delay' | 'name'
envType?: 'bash' | 'cmd' | 'powershell'
proxyCols: 'auto' | '1' | '2' | '3' | '4'
autoSetDNS?: boolean
originDNS?: string
useWindowFrame: boolean
proxyInTray: boolean
siderOrder: string[]