refactor: Fix MITM
This commit is contained in:
parent
877eea8ebe
commit
b98f4ce20e
5 changed files with 91 additions and 60 deletions
|
|
@ -33,13 +33,17 @@ import os from "os";
|
|||
// Multiple modules register SIGINT/SIGTERM handlers legitimately
|
||||
process.setMaxListeners(20);
|
||||
|
||||
let signalHandlersRegistered = false;
|
||||
let watchdogInterval = null;
|
||||
let networkMonitorInterval = null;
|
||||
let lastNetworkFingerprint = null;
|
||||
let lastWatchdogTick = Date.now();
|
||||
let lastTunnelRestartAt = 0;
|
||||
let tunnelRestartInProgress = false;
|
||||
// Use global to survive Next.js hot reload — prevents duplicate intervals
|
||||
const g = global.__appSingleton ??= {
|
||||
signalHandlersRegistered: false,
|
||||
watchdogInterval: null,
|
||||
networkMonitorInterval: null,
|
||||
lastNetworkFingerprint: null,
|
||||
lastWatchdogTick: Date.now(),
|
||||
lastTunnelRestartAt: 0,
|
||||
tunnelRestartInProgress: false,
|
||||
};
|
||||
|
||||
const WATCHDOG_INTERVAL_MS = 60000;
|
||||
const NETWORK_CHECK_INTERVAL_MS = 5000;
|
||||
const NETWORK_RESTART_COOLDOWN_MS = 30000;
|
||||
|
|
@ -68,14 +72,14 @@ export async function initializeApp() {
|
|||
}
|
||||
|
||||
// Kill cloudflared on process exit (register once only)
|
||||
if (!signalHandlersRegistered) {
|
||||
if (!g.signalHandlersRegistered) {
|
||||
const cleanup = () => {
|
||||
killCloudflared();
|
||||
process.exit();
|
||||
};
|
||||
process.on("SIGINT", cleanup);
|
||||
process.on("SIGTERM", cleanup);
|
||||
signalHandlersRegistered = true;
|
||||
g.signalHandlersRegistered = true;
|
||||
}
|
||||
|
||||
// Pre-download cloudflared binary in background
|
||||
|
|
@ -127,8 +131,8 @@ async function autoStartMitm() {
|
|||
|
||||
/** Periodically check tunnel process health and reconnect if crashed */
|
||||
function startWatchdog() {
|
||||
if (watchdogInterval) return;
|
||||
watchdogInterval = setInterval(async () => {
|
||||
if (g.watchdogInterval) return;
|
||||
g.watchdogInterval = setInterval(async () => {
|
||||
try {
|
||||
const settings = await getSettings();
|
||||
if (!settings.tunnelEnabled) return;
|
||||
|
|
@ -141,7 +145,7 @@ function startWatchdog() {
|
|||
}
|
||||
}, WATCHDOG_INTERVAL_MS);
|
||||
|
||||
if (watchdogInterval.unref) watchdogInterval.unref();
|
||||
if (g.watchdogInterval.unref) g.watchdogInterval.unref();
|
||||
}
|
||||
|
||||
/** Get network fingerprint from active interfaces (IPv4 only) */
|
||||
|
|
@ -161,53 +165,53 @@ function getNetworkFingerprint() {
|
|||
|
||||
/** Monitor network changes + sleep/wake → kill and reconnect tunnel */
|
||||
function startNetworkMonitor() {
|
||||
if (networkMonitorInterval) return;
|
||||
if (g.networkMonitorInterval) return;
|
||||
|
||||
lastNetworkFingerprint = getNetworkFingerprint();
|
||||
lastWatchdogTick = Date.now();
|
||||
g.lastNetworkFingerprint = getNetworkFingerprint();
|
||||
g.lastWatchdogTick = Date.now();
|
||||
|
||||
networkMonitorInterval = setInterval(async () => {
|
||||
g.networkMonitorInterval = setInterval(async () => {
|
||||
try {
|
||||
const settings = await getSettings();
|
||||
if (!settings.tunnelEnabled) return;
|
||||
|
||||
const now = Date.now();
|
||||
const elapsed = now - lastWatchdogTick;
|
||||
lastWatchdogTick = now;
|
||||
const elapsed = now - g.lastWatchdogTick;
|
||||
g.lastWatchdogTick = now;
|
||||
|
||||
const currentFingerprint = getNetworkFingerprint();
|
||||
const networkChanged = currentFingerprint !== lastNetworkFingerprint;
|
||||
const networkChanged = currentFingerprint !== g.lastNetworkFingerprint;
|
||||
const wasSleep = elapsed > NETWORK_CHECK_INTERVAL_MS * 3;
|
||||
|
||||
if (networkChanged) lastNetworkFingerprint = currentFingerprint;
|
||||
if (networkChanged) g.lastNetworkFingerprint = currentFingerprint;
|
||||
|
||||
if (!networkChanged && !wasSleep) return;
|
||||
|
||||
// Skip if restart already in progress or restarted recently
|
||||
if (tunnelRestartInProgress) return;
|
||||
if (now - lastTunnelRestartAt < NETWORK_RESTART_COOLDOWN_MS) return;
|
||||
if (g.tunnelRestartInProgress) return;
|
||||
if (now - g.lastTunnelRestartAt < NETWORK_RESTART_COOLDOWN_MS) return;
|
||||
|
||||
const reason = wasSleep && networkChanged ? "sleep/wake + network change"
|
||||
: wasSleep ? "sleep/wake" : "network change";
|
||||
console.log(`[NetworkMonitor] ${reason} detected, restarting tunnel...`);
|
||||
|
||||
tunnelRestartInProgress = true;
|
||||
lastTunnelRestartAt = now;
|
||||
g.tunnelRestartInProgress = true;
|
||||
g.lastTunnelRestartAt = now;
|
||||
try {
|
||||
killCloudflared();
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
await enableTunnel();
|
||||
console.log("[NetworkMonitor] Tunnel restarted");
|
||||
lastNetworkFingerprint = getNetworkFingerprint();
|
||||
g.lastNetworkFingerprint = getNetworkFingerprint();
|
||||
} finally {
|
||||
tunnelRestartInProgress = false;
|
||||
g.tunnelRestartInProgress = false;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("[NetworkMonitor] Tunnel restart failed:", err.message);
|
||||
}
|
||||
}, NETWORK_CHECK_INTERVAL_MS);
|
||||
|
||||
if (networkMonitorInterval.unref) networkMonitorInterval.unref();
|
||||
if (g.networkMonitorInterval.unref) g.networkMonitorInterval.unref();
|
||||
}
|
||||
|
||||
export default initializeApp;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue