fix: prefer ipv4 when resolving ssh host names (#1365)

This commit is contained in:
LukeGus committed 2026-09-30 11:56:14 -05:00
1 parent 4076eb66ab
commit e88df7827b
4 files changed
+72 -6

No files matched your search

+14 -3
View File
@@ -154,6 +154,17 @@ export function isRetriableDnsError(error: unknown): boolean {
);
}
type LookupResult = { address: string; family: number };
// Prefer IPv4: ssh2 gets one address and has no fallback, and a name that
// also has an AAAA record often points at a v6 address sshd is not bound to.
export function pickSshAddress(result: LookupResult | LookupResult[]): string {
const list = Array.isArray(result) ? result : [result];
if (list.length === 0)
throw Object.assign(new Error("No address found"), { code: "ENOTFOUND" });
return (list.find((entry) => entry.family === 4) ?? list[0]).address;
}
/** Resolves a hostname up front, retrying transient container DNS failures. */
export async function resolveHostForSshConnect(
host: string,
@@ -168,10 +179,10 @@ export async function resolveHostForSshConnect(
for (let attempt = 0; ; attempt += 1) {
try {
const result = await lookup(normalized);
const address = pickSshAddress(await lookup(normalized, { all: true }));
return {
host: result.address,
resolvedAddress: result.address,
host: address,
resolvedAddress: address,
attempts: attempt + 1,
};
} catch (error) {
@@ -0,0 +1,22 @@
import { describe, expect, it, vi } from "vitest";
import {
pickSshAddress,
resolveHostForSshConnect,
} from "../../src/backend/helpers.js";
describe("resolveHostForSshConnect", () => {
it("prefers IPv4 over IPv6", async () => {
const lookup = vi.fn().mockResolvedValue([
{ address: "fe80::1", family: 6 },
{ address: "192.168.1.20", family: 4 },
]);
const result = await resolveHostForSshConnect("nas", lookup);
expect(result.host).toBe("192.168.1.20");
});
it("keeps an IPv6-only answer", () => {
expect(pickSshAddress({ address: "2001:db8::5", family: 6 })).toBe(
"2001:db8::5",
);
});
});