Skip to content

[Withdrawn] fix(proxy): add opt-in local DNS for SOCKS5 targets - #4987

Closed
MarcusHO929 wants to merge 1 commit into
decolua:masterfrom
MarcusHO929:fix/opencode-socks-local-dns
Closed

MarcusHO929 wants to merge 1 commit into
decolua:masterfrom
MarcusHO929:fix/opencode-socks-local-dns

Conversation

@MarcusHO929

@MarcusHO929 MarcusHO929 commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Withdrawn — correction after follow-up measurements (2026-10-20)

I am withdrawing this proposal and the recommendation to use local DNS as an OpenCode 403 fix. Please do not merge this PR on the basis of my earlier diagnosis.

Later controlled checks in the same AdGuard SOCKS setup showed that local resolution / a numeric SOCKS target could lead multiple configured pools to the same service-visible US egress. With proxy-side DNS / a domain SOCKS target, the checked pools exposed their respective distinct VPN egresses. This was also reproduced by explicitly comparing socks5:// and socks5h:// with fresh trace URLs. No IP addresses, account details or credentials are included here.

We have removed the locally installed, hardcoded OpenCode DNS override and restored the byte-identical original 9router 0.5.104 transport. A local SOCKS/HTTPS regression check confirms domain addressing, original Host/SNI, and certificate verification. Follow-up checks with the restored installed transport showed the expected distinct pool egresses.

Important qualifications:

  • The hardcoded local override was our local modification, not upstream 9router's default behavior. This PR itself was opt-in and retained proxy-side DNS by default; it should not be confused with that local override.
  • Earlier successful responses were time- and path-specific observations, not evidence that local DNS repaired an upstream 9router defect or a general OpenCode access policy.
  • We have not established that the DNS change caused any IP-abuse flag. We have not established the gateway's trigger, thresholds or expiry time.
  • My earlier attribution to Cloudflare WAF, load-shedding or a guaranteed combination of DNS and fallback fixes was not demonstrated and is withdrawn.

I am closing my PR without merging. Other authors' fallback proposals are independent and are not being withdrawn by this correction. Sorry for the overstatement in the earlier diagnosis.

Superseded original proposal — retained as history, not a current recommendation

Summary

Add an opt-in local DNS mode for SOCKS5 proxy URLs:

socks5://127.0.0.1:1080?dns=local

Unparameterized URLs and ?dns=remote retain the existing remote/proxy-DNS behavior. This is a transport option, not a provider identity/header change or a hardcoded OpenCode exception.

Related: #4983, especially the controlled observations in #4983 (comment) .

Why

In an existing AdGuard SOCKS setup, the same OpenCode request returned 403 with the hostname sent as a SOCKS domain target, but 200 when the destination was resolved locally and its numeric address sent through the same SOCKS proxy. HTTP request data, Host/SNI and verified TLS identity were held constant. Numeric IPv4 and IPv6 both worked; the exact gateway-internal routing rule remains unknown.

The locally scoped workaround restored all 16 existing pools with strictProxy:true. This PR generalizes the DNS choice as an explicit per-proxy URL option rather than silently changing DNS for all users or special-casing OpenCode.

The actual PR source was also smoke-tested against the affected existing SOCKS proxy with identical synthetic request data: remote mode -> 403, local mode -> 200 / OK / completed stream. This does not claim to fix every OpenCode 403 or the separate GLM 429 Endpoint is unavailable.

Changes

  • Add a shared DNS-aware dispatcher factory for model transport and dashboard proxy tests.
  • For socks5: ... ?dns=local, resolve with the system resolver and pass the IPv4/IPv6 result to the existing SOCKS tunnel implementation; retain the original HTTP origin, TLS SNI and certificate hostname.
  • Keep remote DNS as the default. Separate DNS-mode URLs already have separate dispatcher cache keys.
  • Bound waiting for local DNS to five seconds; skip lookups for IP literals.
  • Reject invalid/duplicated/non-SOCKS DNS mode options as configuration errors instead of silently falling back to direct access.
  • Require Undici >= 7.30.1 for the exported SOCKS5 dispatcher used here. SOCKS5 remains experimental in Undici.
  • Document opt-in use, DNS privacy, existing Strict Proxy / STRICT_SSL behavior and cancellation limits.

Security / compatibility notes

  • Opt-in local DNS exposes destination lookups to the local/system resolver rather than the proxy resolver. It can change split-DNS/routing results. Use a dedicated pool entry if only one provider needs this behavior.
  • No new proxy addresses, credentials, provider headers/fingerprints, destination IP constants or disabled TLS checks.
  • Existing non-strict direct fallback and TLS fallback policies are unchanged. Enable Strict Proxy if failed proxy requests must not be retried directly.
  • The lookup deadline bounds the dispatcher's wait, not the underlying OS DNS operation. Cancellation prevents target HTTP delivery, but an already pending lookup may still complete and initiate a SOCKS handshake.
  • No migration, default behavior change or production installation modification is required by this PR.

Tests

  • Red -> green regression for local numeric SOCKS targets versus remote domain targets.
  • 26/26 targeted tests pass:
    cd tests
    npm test -- unit/socks-proxy-dns.test.js unit/strict-proxy-enforcement.test.js unit/qoder-proxy-replay.test.js
  • Real local SOCKS + HTTPS fixtures exercise TLS trust/hostname, original Host/SNI, IPv4/IPv6, IP literals, percent-encoded proxy credentials, DNS failure/timeout, caller cancellation, cache-mode separation, model transport and dashboard proxy tests. No external service is needed for these tests.
  • ESLint on changed JavaScript files: pass.
  • npm run build: pass (optional better-sqlite3 binding unavailable with lifecycle scripts disabled; supported node:sqlite fallback used).
  • Full suite run in isolated HOME/DATA_DIR without inherited credentials: 3599 passed / 90 failed / 93 pending. Unmodified master at 87a74e1, using the same installed dependencies and conditions: 3589 passed / 90 failed / 93 pending. Exact failed-case and failed-file sets match; no new failures. That full current run preceded the last two IPv6/IP-literal additions; the final 26-test targeted run includes them.
  • Independent read-only review: no remaining concrete blockers after addressing alias consistency, tracked documentation and precise DNS/cancellation wording.

The full suite is not green on the unmodified baseline either; I am not presenting this as a clean full-suite pass.

yorihaput added a commit to yorihaput/9router that referenced this pull request Oct 17, 2026
andyvandaric added a commit to andyvandaric/9router that referenced this pull request Oct 17, 2026
… strategy in full

Problem: the fork ran an older fingerprint contract than upstream frontier on the keyed lane and lacked both proxy escape hatches from issue decolua#4983. opencode-zen still sent the v1 UA plus a stub bash/glob/grep/read quartet with empty schemas and the v1-only x-opencode-request header, the fingerprint helper could not satisfy the gate when a caller tool reuses read/shell with platform-specific wording, and proxyAwareFetch had no way out of an egress the gate had flagged.

Changes: port upstream PR decolua#4972 (in-place fingerprint normalization with alias fallback), decolua#4883 (UA opencode/latest/2.0.29/cli across both executors, registry and dashboard test; strict v2 channel matcher kept), decolua#4860 fingerprint/strategy for opencode-zen (verbatim read/shell via applyFingerprintTools, cli client, four session mirrors, drop x-opencode-request and x-api-key for free tier; /zen/v1 to /inference/v1 switch NOT taken), decolua#4987 (open-sse/utils/proxyDispatcher.js with opt-in socks5 dns=local, shared by proxyFetch and the dashboard proxy test, fail-closed ERR_PROXY_DNS_MODE) and decolua#4988 (replay a proxied 403 FreeTierError once on the direct egress, strictProxy contract preserved). undici ^7.19.2 to ^7.30.1. Version 0.5.108.

Verification: full suite re-derived on this machine from a git stash -u baseline - failure sets byte-identical (95 = 95, 0 new), passes 3592 to 3617. Targeted opencode/proxy/session groups 214 pass. undici 7.30.1 exposes Socks5ProxyAgent and createSocks5Connection; the local-DNS dispatcher is exercised end to end against a local SOCKS5 plus TLS fixture (11 cases). Root cause of the free-tier 403 is egress-IP load-shedding (decolua#4983), so these ports restore request truth and add escape hatches but cannot make a flagged egress succeed.
mulqizamzam added a commit to mulqizamzam/9router that referenced this pull request Oct 18, 2026
@MarcusHO929 MarcusHO929 changed the title fix(proxy): add opt-in local DNS for SOCKS5 targets [Withdrawn] fix(proxy): add opt-in local DNS for SOCKS5 targets Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant