mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/mihomo-party-org/clash-party.git
synced 2026-09-20 08:03:39 +08:00
fix: prevent killing unintended processes due to PID reuse in lightweight mode
This commit is contained in:
@@ -55,7 +55,8 @@ import {
|
||||
cleanupSocketFile,
|
||||
cleanupWindowsNamedPipes,
|
||||
validateWindowsPipeAccess,
|
||||
waitForCoreReady
|
||||
waitForCoreReady,
|
||||
verifyProcessOwner
|
||||
} from './process'
|
||||
import { setPublicDNS, recoverDNS } from './dns'
|
||||
|
||||
@@ -81,6 +82,7 @@ const execFilePromise = promisify(execFile)
|
||||
const ctlParam = process.platform === 'win32' ? '-ext-ctl-pipe' : '-ext-ctl-unix'
|
||||
const coreHookTimeout = 30000
|
||||
const automaticRestartDelay = 750
|
||||
const coreProcessNames = ['mihomo', 'mihomo-alpha', 'mihomo-smart'] as const
|
||||
|
||||
// 核心进程状态
|
||||
interface CoreProcessWatchdog {
|
||||
@@ -326,24 +328,27 @@ async function stopPidFileCore(): Promise<void> {
|
||||
const pid = parseInt(pidString.trim())
|
||||
if (!isNaN(pid)) {
|
||||
try {
|
||||
process.kill(pid, 0)
|
||||
process.kill(pid, 'SIGINT')
|
||||
const deadline = Date.now() + 500
|
||||
let stillRunning = true
|
||||
while (stillRunning && Date.now() < deadline) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||
try {
|
||||
process.kill(pid, 0)
|
||||
} catch {
|
||||
stillRunning = false
|
||||
if (await verifyProcessOwner(pid, coreProcessNames)) {
|
||||
process.kill(pid, 'SIGINT')
|
||||
const deadline = Date.now() + 500
|
||||
let stillRunning = true
|
||||
while (stillRunning && Date.now() < deadline) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||
try {
|
||||
process.kill(pid, 0)
|
||||
} catch {
|
||||
stillRunning = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stillRunning) {
|
||||
try {
|
||||
process.kill(pid, 'SIGKILL')
|
||||
} catch {
|
||||
// ignore
|
||||
if (stillRunning) {
|
||||
try {
|
||||
process.kill(pid, 'SIGKILL')
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
} else {
|
||||
managerLogger.info(`PID ${pid} is not a known mihomo process, skipping kill`)
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
|
||||
@@ -169,3 +169,45 @@ export async function waitForCoreReady(): Promise<void> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeProcessName(name: string): string {
|
||||
return name
|
||||
.trim()
|
||||
.replace(/\.exe$/i, '')
|
||||
.toLowerCase()
|
||||
}
|
||||
|
||||
export async function verifyProcessOwner(
|
||||
pid: number,
|
||||
expectedNames: readonly string[]
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
process.kill(pid, 0)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
let processName = ''
|
||||
if (process.platform === 'win32') {
|
||||
const { stdout } = await execFilePromise(
|
||||
'tasklist',
|
||||
['/FI', `PID eq ${pid}`, '/FO', 'CSV', '/NH'],
|
||||
{ windowsHide: true, timeout: 1000 }
|
||||
)
|
||||
const match = stdout.match(/^"([^"]+)","(\d+)"/m)
|
||||
if (!match || parseInt(match[2], 10) !== pid) return false
|
||||
processName = match[1]
|
||||
} else {
|
||||
const { stdout } = await execFilePromise('ps', ['-p', `${pid}`, '-o', 'comm='], {
|
||||
timeout: 1000
|
||||
})
|
||||
processName = stdout.trim().split(/\r?\n/, 1)[0] || ''
|
||||
}
|
||||
|
||||
const normalizedName = normalizeProcessName(processName)
|
||||
return expectedNames.some((name) => normalizeProcessName(name) === normalizedName)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { existsSync } from 'fs'
|
||||
import { readFile, rm, writeFile } from 'fs/promises'
|
||||
import { dataDir, resourcesFilesDir } from '../utils/dirs'
|
||||
import { getAppConfig } from '../config'
|
||||
import { verifyProcessOwner } from '../core/process'
|
||||
|
||||
let child: ChildProcess
|
||||
|
||||
@@ -12,7 +13,12 @@ export async function startMonitor(detached = false): Promise<void> {
|
||||
if (existsSync(path.join(dataDir(), 'monitor.pid'))) {
|
||||
const pid = parseInt(await readFile(path.join(dataDir(), 'monitor.pid'), 'utf-8'))
|
||||
try {
|
||||
process.kill(pid, 'SIGINT')
|
||||
if (!isNaN(pid)) {
|
||||
const isOwner = await verifyProcessOwner(pid, ['TrafficMonitor'])
|
||||
if (isOwner) {
|
||||
process.kill(pid, 'SIGINT')
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user