mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-23 04:09:49 +00:00
Fix : MITM
This commit is contained in:
+48
-19
@@ -11,6 +11,7 @@ const IS_WIN = process.platform === "win32";
|
||||
const { generateCert } = require("./cert/generate");
|
||||
const { installCert } = require("./cert/install");
|
||||
const { MITM_DIR } = require("./paths");
|
||||
const { log, err } = require("./logger");
|
||||
|
||||
const MITM_PORT = 443;
|
||||
const MITM_WIN_NODE_PORT = 8443;
|
||||
@@ -140,7 +141,7 @@ async function saveMitmSettings(enabled, password) {
|
||||
if (password) updates.mitmSudoEncrypted = encryptPassword(password);
|
||||
await _updateSettings(updates);
|
||||
} catch (e) {
|
||||
console.log("[MITM] Failed to save settings:", e.message);
|
||||
err(`Failed to save settings: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,8 +278,10 @@ async function getMitmStatus() {
|
||||
const dnsStatus = checkAllDNSStatus();
|
||||
const rootCACertPath = path.join(MITM_DIR, "rootCA.crt");
|
||||
const certExists = fs.existsSync(rootCACertPath);
|
||||
const { checkCertInstalled } = require("./cert/install");
|
||||
const certTrusted = certExists ? await checkCertInstalled(rootCACertPath) : false;
|
||||
|
||||
return { running, pid, certExists, dnsStatus };
|
||||
return { running, pid, certExists, certTrusted, dnsStatus };
|
||||
}
|
||||
|
||||
async function scheduleMitmRestart(apiKey) {
|
||||
@@ -288,7 +291,7 @@ async function scheduleMitmRestart(apiKey) {
|
||||
if (aliveMs >= MITM_RESTART_RESET_MS) mitmRestartCount = 0;
|
||||
|
||||
if (mitmRestartCount >= MITM_MAX_RESTARTS) {
|
||||
console.error("[MITM] Max restart attempts reached. Giving up.");
|
||||
err("Max restart attempts reached. Giving up.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -297,28 +300,28 @@ async function scheduleMitmRestart(apiKey) {
|
||||
mitmRestartCount++;
|
||||
mitmIsRestarting = true;
|
||||
|
||||
console.log(`[MITM] Restarting in ${delay / 1000}s... (${mitmRestartCount}/${MITM_MAX_RESTARTS})`);
|
||||
log(`Restarting in ${delay / 1000}s... (${mitmRestartCount}/${MITM_MAX_RESTARTS})`);
|
||||
await new Promise((r) => setTimeout(r, delay));
|
||||
|
||||
try {
|
||||
const settings = _getSettings ? await _getSettings() : null;
|
||||
if (settings && !settings.mitmEnabled) {
|
||||
console.log("[MITM] MITM disabled, skipping restart");
|
||||
log("MITM disabled, skipping restart");
|
||||
mitmIsRestarting = false;
|
||||
return;
|
||||
}
|
||||
const password = getCachedPassword() || await loadEncryptedPassword();
|
||||
if (!password && !IS_WIN) {
|
||||
console.error("[MITM] No cached password, cannot auto-restart");
|
||||
err("No cached password, cannot auto-restart");
|
||||
mitmIsRestarting = false;
|
||||
return;
|
||||
}
|
||||
await startServer(apiKey, password);
|
||||
console.log("[MITM] Restarted successfully");
|
||||
log("🔄 Restarted successfully");
|
||||
mitmRestartCount = 0;
|
||||
mitmIsRestarting = false;
|
||||
} catch (err) {
|
||||
console.error(`[MITM] Restart attempt ${mitmRestartCount}/${MITM_MAX_RESTARTS} failed:`, err.message);
|
||||
} catch (e) {
|
||||
err(`Restart attempt ${mitmRestartCount}/${MITM_MAX_RESTARTS} failed: ${e.message}`);
|
||||
mitmIsRestarting = false;
|
||||
// Schedule next retry
|
||||
scheduleMitmRestart(apiKey);
|
||||
@@ -335,7 +338,7 @@ async function startServer(apiKey, sudoPassword) {
|
||||
const savedPid = parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10);
|
||||
if (savedPid && isProcessAlive(savedPid)) {
|
||||
serverPid = savedPid;
|
||||
console.log(`[MITM] Reusing existing process PID ${savedPid}`);
|
||||
log(`♻️ Reusing existing process (PID: ${savedPid})`);
|
||||
await saveMitmSettings(true, sudoPassword);
|
||||
if (sudoPassword) setCachedPassword(sudoPassword);
|
||||
return { running: true, pid: savedPid };
|
||||
@@ -357,7 +360,7 @@ async function startServer(apiKey, sudoPassword) {
|
||||
if (portStatus === "in-use" || portStatus === "no-permission") {
|
||||
const owner = await getPort443Owner(sudoPassword);
|
||||
if (owner && owner.name === "node") {
|
||||
console.log(`[MITM] Killing orphan node process on port 443 (PID ${owner.pid})...`);
|
||||
log(`Killing orphan node process on port 443 (PID ${owner.pid})...`);
|
||||
try {
|
||||
const { execWithPassword } = require("./dns/dnsConfig");
|
||||
await execWithPassword(`kill -9 ${owner.pid}`, sudoPassword);
|
||||
@@ -377,7 +380,7 @@ async function startServer(apiKey, sudoPassword) {
|
||||
const rootCAKeyPath = path.join(MITM_DIR, "rootCA.key");
|
||||
|
||||
if (!fs.existsSync(rootCACertPath) || !fs.existsSync(rootCAKeyPath)) {
|
||||
console.log("[MITM] Generating Root CA certificate (first time or migration)...");
|
||||
log("🔐 Generating Root CA (first time)...");
|
||||
await generateCert();
|
||||
}
|
||||
|
||||
@@ -385,17 +388,20 @@ async function startServer(apiKey, sudoPassword) {
|
||||
const { checkCertInstalled } = require("./cert/install");
|
||||
const rootCATrusted = await checkCertInstalled(rootCACertPath);
|
||||
if (!rootCATrusted) {
|
||||
console.log("[MITM] Installing Root CA to system trust store...");
|
||||
log("🔐 Cert: not trusted → installing...");
|
||||
// Use provided password or cached/stored password
|
||||
const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
|
||||
if (!password && !IS_WIN) {
|
||||
throw new Error("Sudo password required to install Root CA certificate");
|
||||
}
|
||||
await installCert(password, rootCACertPath);
|
||||
console.log("✅ Root CA installed successfully");
|
||||
log("🔐 Cert: ✅ trusted");
|
||||
} else {
|
||||
log("🔐 Cert: already trusted ✅");
|
||||
}
|
||||
|
||||
// Step 2: Spawn server (Root CA already installed in Step 1.5)
|
||||
log("🚀 Starting server...");
|
||||
if (IS_WIN) {
|
||||
const psSQ = (s) => s.replace(/'/g, "''");
|
||||
const nodePs = psSQ(process.execPath);
|
||||
@@ -436,17 +442,18 @@ async function startServer(apiKey, sudoPassword) {
|
||||
let startError = null;
|
||||
if (!IS_WIN) {
|
||||
serverProcess.stdout.on("data", (data) => {
|
||||
console.log(`[MITM Server] ${data.toString().trim()}`);
|
||||
// server.js already formats its own logs — print as-is
|
||||
process.stdout.write(data);
|
||||
});
|
||||
serverProcess.stderr.on("data", (data) => {
|
||||
const msg = data.toString().trim();
|
||||
if (msg && !msg.includes("Password:") && !msg.includes("password for")) {
|
||||
console.error(`[MITM Server Error] ${msg}`);
|
||||
err(msg);
|
||||
startError = msg;
|
||||
}
|
||||
});
|
||||
serverProcess.on("exit", (code) => {
|
||||
console.log(`MITM server exited with code ${code}`);
|
||||
log(`Server exited (code: ${code})`);
|
||||
serverProcess = null;
|
||||
serverPid = null;
|
||||
try { fs.unlinkSync(PID_FILE); } catch { /* ignore */ }
|
||||
@@ -470,6 +477,14 @@ async function startServer(apiKey, sudoPassword) {
|
||||
fs.writeFileSync(PID_FILE, String(serverPid));
|
||||
}
|
||||
|
||||
log(`✅ Server healthy (PID: ${serverPid || health.pid})`);
|
||||
|
||||
// Log DNS status per tool
|
||||
const dnsStatus = checkAllDNSStatus();
|
||||
for (const [tool, active] of Object.entries(dnsStatus)) {
|
||||
log(`🌐 DNS ${tool}: ${active ? "✅ active" : "❌ inactive"}`);
|
||||
}
|
||||
|
||||
await saveMitmSettings(true, sudoPassword);
|
||||
if (sudoPassword) setCachedPassword(sudoPassword);
|
||||
|
||||
@@ -483,7 +498,7 @@ async function stopServer(sudoPassword) {
|
||||
// Prevent auto-restart from triggering on intentional stop
|
||||
mitmIsRestarting = true;
|
||||
mitmRestartCount = 0;
|
||||
console.log("[MITM] Stopping server...");
|
||||
log("⏹ Stopping server...");
|
||||
|
||||
// Kill server process
|
||||
const proc = serverProcess;
|
||||
@@ -492,7 +507,7 @@ async function stopServer(sudoPassword) {
|
||||
: (() => { try { return parseInt(fs.readFileSync(PID_FILE, "utf-8").trim(), 10); } catch { return null; } })();
|
||||
|
||||
if (pidToKill && isProcessAlive(pidToKill)) {
|
||||
console.log(`Killing MITM server (PID: ${pidToKill})...`);
|
||||
log(`Killing server (PID: ${pidToKill})...`);
|
||||
killProcess(pidToKill, false, sudoPassword);
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
if (isProcessAlive(pidToKill)) killProcess(pidToKill, true, sudoPassword);
|
||||
@@ -562,6 +577,19 @@ async function disableToolDNS(tool, sudoPassword) {
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Install Root CA to system trust store (standalone, no server start)
|
||||
*/
|
||||
async function trustCert(sudoPassword) {
|
||||
const rootCACertPath = path.join(MITM_DIR, "rootCA.crt");
|
||||
if (!fs.existsSync(rootCACertPath)) throw new Error("Root CA not found. Start server first to generate it.");
|
||||
const { installCert } = require("./cert/install");
|
||||
const password = sudoPassword || getCachedPassword() || await loadEncryptedPassword();
|
||||
if (!password && !IS_WIN) throw new Error("Sudo password required to trust certificate");
|
||||
await installCert(password, rootCACertPath);
|
||||
if (password) setCachedPassword(password);
|
||||
}
|
||||
|
||||
// Legacy aliases for backward compatibility
|
||||
const startMitm = startServer;
|
||||
const stopMitm = stopServer;
|
||||
@@ -572,6 +600,7 @@ module.exports = {
|
||||
stopServer,
|
||||
enableToolDNS,
|
||||
disableToolDNS,
|
||||
trustCert,
|
||||
// Legacy
|
||||
startMitm,
|
||||
stopMitm,
|
||||
|
||||
Reference in New Issue
Block a user