fix(ingest): pinnedDispatcher lookup must use undici array form
cb(null, address, family) was returning Invalid IP address: undefined
under undici v6. Returning the full records array (each {address, family})
gives undici what it expects and lets it pick the best family.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -62,15 +62,16 @@ async function resolveAndCheck(host) {
|
|||||||
throw new SafeFetchError(`${host} resolves to blocked address ${r.address}`, 'blocked_addr');
|
throw new SafeFetchError(`${host} resolves to blocked address ${r.address}`, 'blocked_addr');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return records[0];
|
return records; // pass all validated records to the dispatcher
|
||||||
}
|
}
|
||||||
|
|
||||||
function pinnedDispatcher(address, family) {
|
function pinnedDispatcher(records) {
|
||||||
return new Agent({
|
return new Agent({
|
||||||
connect: {
|
connect: {
|
||||||
// undici will call our lookup instead of OS DNS, so the chosen IP
|
// undici will call our lookup instead of OS DNS, so it only sees
|
||||||
// is the one we already validated. No TOCTOU re-resolution.
|
// IPs we've already validated. The array form `(err, results)` is
|
||||||
lookup: (_hostname, _options, cb) => cb(null, address, family)
|
// what undici v6+ expects (results[i] = {address, family}).
|
||||||
|
lookup: (_hostname, _options, cb) => cb(null, records)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -82,17 +83,14 @@ export async function safeFetch(url, options = {}, { maxHops = 5 } = {}) {
|
|||||||
if (u.protocol !== 'http:' && u.protocol !== 'https:') {
|
if (u.protocol !== 'http:' && u.protocol !== 'https:') {
|
||||||
throw new SafeFetchError(`unsupported scheme ${u.protocol}`, 'scheme');
|
throw new SafeFetchError(`unsupported scheme ${u.protocol}`, 'scheme');
|
||||||
}
|
}
|
||||||
let address, family;
|
let records;
|
||||||
if (net.isIP(u.hostname)) {
|
if (net.isIP(u.hostname)) {
|
||||||
if (isBlockedAddr(u.hostname)) throw new SafeFetchError(`blocked literal IP ${u.hostname}`, 'blocked_addr');
|
if (isBlockedAddr(u.hostname)) throw new SafeFetchError(`blocked literal IP ${u.hostname}`, 'blocked_addr');
|
||||||
address = u.hostname;
|
records = [{ address: u.hostname, family: net.isIPv4(u.hostname) ? 4 : 6 }];
|
||||||
family = net.isIPv4(u.hostname) ? 4 : 6;
|
|
||||||
} else {
|
} else {
|
||||||
const rec = await resolveAndCheck(u.hostname);
|
records = await resolveAndCheck(u.hostname);
|
||||||
address = rec.address;
|
|
||||||
family = rec.family;
|
|
||||||
}
|
}
|
||||||
const dispatcher = pinnedDispatcher(address, family);
|
const dispatcher = pinnedDispatcher(records);
|
||||||
const res = await fetch(current, { ...options, redirect: 'manual', dispatcher });
|
const res = await fetch(current, { ...options, redirect: 'manual', dispatcher });
|
||||||
if ([301,302,303,307,308].includes(res.status)) {
|
if ([301,302,303,307,308].includes(res.status)) {
|
||||||
const loc = res.headers.get('location');
|
const loc = res.headers.get('location');
|
||||||
|
|||||||
Reference in New Issue
Block a user