Skip to content

Commit e922970

Browse files
RichChen01claude
andcommitted
fix: isPortBusy preflight misses IPv4-only occupant (same address-family flaw as #94379)
Route isPortBusy through checkPortInUse (from src/infra/ports-inspect.ts), which probes all four endpoints (127.0.0.1, 0.0.0.0, ::1, ::) instead of a bare tryListenOnPort that binds the IPv6 wildcard (::) on dual-stack hosts. An occupant listening only on 127.0.0.1 (IPv4-only) does not conflict with that bind, so isPortBusy returns false (free) when the port is actually taken. This is the same address-family flaw fixed for the CDP preflight in #94379 / #94415, now fixed for the gateway --force flow. Closes #94426. Co-Authored-By: Claude <[email protected]>
1 parent c14793d commit e922970

2 files changed

Lines changed: 7 additions & 12 deletions

File tree

src/cli/ports.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { execFileSync } from "node:child_process";
33
import { createServer } from "node:net";
44
import { formatErrorMessage } from "../infra/errors.js";
55
import { resolveLsofCommandSync } from "../infra/ports-lsof.js";
6-
import { tryListenOnPort } from "../infra/ports-probe.js";
6+
import { checkPortInUse } from "../infra/ports-inspect.js";
77
import { resolvePositiveTimerTimeoutMs, resolveTimerTimeoutMs } from "../shared/number-coercion.js";
88
import { sleep } from "../utils.js";
99

@@ -130,16 +130,11 @@ function killPortWithFuser(port: number, signal: "SIGTERM" | "SIGKILL"): PortPro
130130
}
131131

132132
async function isPortBusy(port: number): Promise<boolean> {
133-
try {
134-
await tryListenOnPort({ port, exclusive: true });
135-
return false;
136-
} catch (err: unknown) {
137-
const code = (err as NodeJS.ErrnoException).code;
138-
if (code === "EADDRINUSE") {
139-
return true;
140-
}
141-
throw err instanceof Error ? err : new Error(String(err));
142-
}
133+
// Probes all four endpoints (127.0.0.1, 0.0.0.0, ::1, ::) instead of a bare
134+
// tryListenOnPort which binds the IPv6 wildcard (::) and misses IPv4-only
135+
// occupants. See #94379 / #94415 for the sibling fix.
136+
const status = await checkPortInUse(port);
137+
return status === "busy";
143138
}
144139

145140
export function parseLsofOutput(output: string): PortProcess[] {

src/infra/ports-inspect.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ async function tryListenOnHost(port: number, host: string): Promise<PortUsageSta
634634
}
635635
}
636636

637-
async function checkPortInUse(port: number): Promise<PortUsageStatus> {
637+
export async function checkPortInUse(port: number): Promise<PortUsageStatus> {
638638
const hosts = ["127.0.0.1", "0.0.0.0", "::1", "::"];
639639
let sawUnknown = false;
640640
for (const host of hosts) {

0 commit comments

Comments
 (0)