fix(cli): a capture DNS helper that dies silently says how it ended (#6570)

When the system lookup helper exited without printing anything, the failure carried only its command line. It now names the exit code or the signal.
This commit is contained in:
Miguel Ángel
2026-10-27 16:08:52 +00:00
committed by GitHub
parent 624c9becfd
commit d571d77cae
2 changed files with 26 additions and 2 deletions
@@ -91,6 +91,23 @@ describe("public address policy", () => {
"Capture DNS failed: ENOTFOUND",
);
});
it.each([
[{ code: 3221225794 }, "Capture DNS failed: the lookup helper exited with code 3221225794"],
[
{ code: null, signal: "SIGKILL" },
"Capture DNS failed: the lookup helper was ended by SIGKILL",
],
])(
"names how the system lookup helper ended when it says nothing (%j)",
async (ended, message) => {
mocks.resolve4.mockRejectedValue(new Error("queryA ENOTFOUND"));
mocks.execFile.mockImplementation((_file, _args, _options, callback) => {
callback(Object.assign(new Error("Command failed"), ended), "", "");
return liveChild();
});
await expect(resolvePublicAddress("helper-died.example.org")).rejects.toThrow(message);
},
);
it("checks a system answer like a DNS one, and asks the system once per host", async () => {
mocks.resolve4.mockRejectedValue(new Error("queryA ENOTFOUND"));
systemLookupPrints('["127.0.0.1"]');
+9 -2
View File
@@ -1,4 +1,4 @@
import { execFile, type ChildProcess } from "node:child_process";
import { execFile, type ChildProcess, type ExecFileException } from "node:child_process";
import { promises as dns } from "node:dns";
import { readFile } from "node:fs/promises";
import { isIP, type Socket } from "node:net";
@@ -138,6 +138,13 @@ const SYSTEM_LOOKUP = `require("node:dns").lookup(process.argv[1], { all: true,
const liveLookups = new Set<ChildProcess>();
function helperEnded(error: ExecFileException | null): string {
if (!error) return "the lookup helper printed no answer";
return error.signal
? `the lookup helper was ended by ${error.signal}`
: `the lookup helper exited with code ${error.code}`;
}
export function systemLookupInKillableChild(host: string, timeoutMs: number): Promise<string[]> {
if (!process.listeners("exit").includes(killLiveLookups)) process.on("exit", killLiveLookups);
const answers = new Promise<string[]>((resolve, reject) => {
@@ -152,7 +159,7 @@ export function systemLookupInKillableChild(host: string, timeoutMs: number): Pr
},
(error, stdout, stderr) => {
if (error?.killed) reject(new Error("Capture DNS timed out"));
else if (!stdout) reject(new Error(`Capture DNS failed: ${stderr || error?.message}`));
else if (!stdout) reject(new Error(`Capture DNS failed: ${stderr || helperEnded(error)}`));
else {
try {
resolve(JSON.parse(stdout) as string[]);