mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-05 10:50:22 +00:00
fix: sort IPv4 addresses before IPv6 in SSRF pinned DNS to fix Telegram media fetch on IPv6-broken hosts
On hosts where IPv6 is configured but not routed (common on cloud VMs), Telegram media downloads fail because the pinned DNS lookup may return IPv6 addresses first. Even though autoSelectFamily (Happy Eyeballs) is enabled, the round-robin pinned lookup serves individual IPv6 addresses that fail before IPv4 is attempted. Sort resolved addresses so IPv4 comes first, ensuring both Happy Eyeballs and single-address round-robin try the working address family first. Fixes #23975 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Peter Steinberger
parent
fb8edebc32
commit
dd9ba974d0
@@ -155,6 +155,23 @@ describe("ssrf pinning", () => {
|
||||
expect(lookup).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sorts IPv4 addresses before IPv6 in pinned results", async () => {
|
||||
const lookup = vi.fn(async () => [
|
||||
{ address: "2001:db8::1", family: 6 },
|
||||
{ address: "93.184.216.34", family: 4 },
|
||||
{ address: "2001:db8::2", family: 6 },
|
||||
{ address: "93.184.216.35", family: 4 },
|
||||
]) as unknown as LookupFn;
|
||||
|
||||
const pinned = await resolvePinnedHostname("example.com", lookup);
|
||||
expect(pinned.addresses).toEqual([
|
||||
"93.184.216.34",
|
||||
"93.184.216.35",
|
||||
"2001:db8::1",
|
||||
"2001:db8::2",
|
||||
]);
|
||||
});
|
||||
|
||||
it("allows ISATAP embedded private IPv4 when private network is explicitly enabled", async () => {
|
||||
const lookup = vi.fn(async () => [
|
||||
{ address: "2001:db8:1234::5efe:127.0.0.1", family: 6 },
|
||||
|
||||
@@ -290,7 +290,18 @@ export async function resolvePinnedHostnameWithPolicy(
|
||||
assertAllowedResolvedAddressesOrThrow(results, params.policy);
|
||||
}
|
||||
|
||||
const addresses = Array.from(new Set(results.map((entry) => entry.address)));
|
||||
// Sort IPv4 addresses before IPv6 so that Happy Eyeballs (autoSelectFamily) and
|
||||
// round-robin pinned lookups try IPv4 first. This avoids connection failures on
|
||||
// hosts where IPv6 is configured but not routed (common on cloud VMs and WSL2).
|
||||
// See: https://github.com/openclaw/openclaw/issues/23975
|
||||
const addresses = Array.from(new Set(results.map((entry) => entry.address))).toSorted((a, b) => {
|
||||
const aIsV6 = a.includes(":");
|
||||
const bIsV6 = b.includes(":");
|
||||
if (aIsV6 === bIsV6) {
|
||||
return 0;
|
||||
}
|
||||
return aIsV6 ? 1 : -1;
|
||||
});
|
||||
if (addresses.length === 0) {
|
||||
throw new Error(`Unable to resolve hostname: ${hostname}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user