fix(dev): answer the proxy guard's DNS lookup in the shape the connector asked for - #1726
Conversation
…tor asked for The SSRF guard behind the dev server's `__geolibre_*_proxy` endpoints pins each connection to a pre-validated address through a custom undici `connect.lookup`. It queried DNS with `all: true` (correct: every candidate must be checked) but always replied with the three-argument `(err, address, family)` form. Node's `net.Socket` enables `autoSelectFamily` by default on Node 20+, so it asks for `all: true` and then reads `addresses[0].address` off the reply. Given a string it indexes into that string and throws `ERR_INVALID_IP_ADDRESS: undefined`, so every proxied fetch failed. In practice that meant a 502 on each `__geolibre_raster_proxy` range request and STAC / COG imagery that never rendered in `npm run dev`, with the real cause buried in the terminal. Reply in whichever shape the caller asked for, still validating every resolved address first, so the rebinding window stays closed either way. The lookup is now a named export with an injectable resolver so the reply-shape and private-address paths are covered offline.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe proxy guard now exposes a reusable ChangesGuarded DNS lookup
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed: dependency version conflict. Check your lock file or package.json. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🔍 Cloudflare PR preview
|
Code reviewI reviewed the DNS lookup shape fix in Bugs: None found. Security: No regressions. The SSRF guard's invariant — never hand the connector an address that wasn't validated — is preserved in both the array and single-address reply paths. Performance: No concerns; this is a low-frequency dev-server code path (per-connection DNS resolution), and the change doesn't add extra resolver calls versus the prior implementation. Quality: Minor, non-blocking observation: the extracted CLAUDE.md: No applicable guidelines are implicated by this change (it touches dev-server proxy internals, not any of the areas CLAUDE.md calls out for mirrored constants, i18n, or Tauri CSP). Overall this is a well-scoped, correctly-reasoned fix with tests that reproduce the original failure (array-reply case) and cover the private-address refusal in both reply shapes. |
What was broken
The SSRF guard behind the dev server's
__geolibre_*_proxyendpoints pins each connection to a pre-validated address through a custom undiciconnect.lookup. It queried DNS withall: true(correct: every candidate address must be checked before connecting) but always replied with the three-argument(err, address, family)form.Node's
net.SocketenablesautoSelectFamilyby default on Node 20+, so it asks forall: trueand then readsaddresses[0].addressoff the reply. Handed a string it indexes into that string and throwsERR_INVALID_IP_ADDRESS: undefined.The visible symptom in
npm run dev: every__geolibre_raster_proxyrange request returned 502, so STAC / COG imagery never rendered. The browser only reported a generic fetch failure, and the real cause was buried in the terminal as[vite-proxy-guard] upstream fetch blocked or failed.The fix
Reply in whichever shape the caller asked for. Every resolved address is still validated before either reply, so the check-then-connect rebinding window stays closed in both paths.
The lookup is now a named export (
guardedLookup) with an injectable resolver, matching howassertResolvedPublicHostis already made testable.Tests
Three cases in
tests/edge-proxy-redirect.test.ts: the array reply whenall: trueis requested (fails against the old code), the single-address reply when it is not, and a private-address refusal in both shapes.Verified against the live dev server: the raster proxy goes 502 -> 206 and Sentinel-2 COG tiles render again.
Summary by CodeRabbit
Bug Fixes
Tests