Skip to content

[Bug]: fake-IP allowance unreachable for IPv6-mapped answers — classifyIpv6 hex regex misses the explicit zero group (::ffff:0:c612:1b) #2810

Description

@gaoran1209

Client or integration

Codex App

Area

Proxy and routing

Summary

On machines using Clash / Surge / Mihomo fake-IP DNS, provider model discovery still fails with blocked by destination policy: ... resolves to non-global address, even though #1748 added the fake-IP allowance.

The root cause is that the fake-IP opt-in in resolvePublicAddresses() is unreachable for IPv6-mapped answers. classifyIpv6() decodes hex IPv4-mapped IPv6 with:

const hexMapped = hostname.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);

That pattern assumes exactly two hex groups (::ffff:c612:1b). But the resolver here returns an explicit zero group:

cli-chat-proxy.grok.com has address 198.18.0.27
cli-chat-proxy.grok.com has IPv6 address ::ffff:0:c612:1b

::ffff:0:c612:1b does not match, so it falls through to the generic tail:

return { kind: "private", detail: "non-global address" };

It is therefore classified private with detail "non-global address"not "benchmark address". The allowance in resolvePublicAddresses() is gated on that exact detail string:

if (benchmarkAllowed && assessment?.kind === "private" && assessment.detail === "benchmark address") {

so the branch never runs, and the request is rejected regardless of HTTP(S)_PROXY being correctly configured. Node's ipaddress-style parsers agree the address is not a canonical ipv4_mapped value, which is why it reaches the hex path at all.

Security note: this same gap means loopback/private/link-local addresses in that zero-group form also skip IPv4 classification today. See the table below — fixing the regex tightens the policy rather than loosening it.

Reproduction

  1. Run Clash / Surge / Mihomo with fake-IP DNS enabled (198.18.0.0/15).
  2. Export a working proxy, e.g. export HTTPS_PROXY=http://127.0.0.1:1082.
  3. Configure any provider whose hostname resolves through fake-IP (reproduced with xai, but it affects every provider on this machine).
  4. ocx restart then ocx provider test xai.

Observed:

xai: failed
upstream /models blocked by destination policy: provider URL hostname cli-chat-proxy.grok.com resolves to non-global address (::ffff:0:c612:1b)

Expected: discovery succeeds by riding the configured proxy as an ordinary hostname CONNECT, per #1748.

Note the destination is reachable — the block is purely the classification:

curl -x http://127.0.0.1:1082 https://cli-chat-proxy.grok.com/v1/models  ->  401 (expected unauthenticated response)

Inference through the proxy also works fine; only discovery is blocked, so the failure is masked by the configured-model fallback.

Suggested fix

Make the zero group optional in src/lib/destination-policy.ts:

-  const hexMapped = hostname.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);
+  const hexMapped = hostname.match(/^::ffff:(?:0{1,4}:)?([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);

Verified locally against v2.33.0. Decoding behaviour before/after:

Input old new decoded intent
::ffff:0:c612:1b miss hit 198.18.0.27 fake-IP → allow via proxy
::ffff:c612:1b hit hit 198.18.0.27 unchanged
::ffff:0:7f00:1 miss hit 127.0.0.1 now correctly blocked
::ffff:0:c0a8:1 miss hit 192.168.0.1 now correctly blocked
::ffff:0:a9fe:a9fe miss hit 169.254.169.254 now correctly blocked
::ffff:0:0:c612:1b miss miss 4 groups still rejected

After applying it, all seven configured providers recovered live discovery, and the seven blocked by destination policy warnings disappeared from ocx sync:

Provider before after
xai blocked connected — 2 models
anthropic blocked connected — 10 models
kimi blocked connected — 4 models
deepseek blocked connected — 3 models
minimax-cn blocked connected — 8 models
zhipu-bigmodel-coding blocked connected — 10 models
google-antigravity blocked connected — 6 models

Happy to send this as a PR with a regression test over the address matrix above if useful.

Version

2.33.0

Operating system

macOS 26.5.2 (arm64)

Provider and model

xai / grok-4.6 (reproduces on all configured providers)

Logs or error output

$ ocx sync
[opencodex] Provider model discovery for "minimax-cn" was blocked by destination policy: provider URL hostname api.minimaxi.com resolves to non-global address (::ffff:0:c612:24) [urlClass=provider-models, fallback=configured].
[opencodex] Provider model discovery for "xai" was blocked by destination policy: provider URL hostname cli-chat-proxy.grok.com resolves to non-global address (::ffff:0:c612:1b) [urlClass=provider-models, fallback=configured].
[opencodex] Provider model discovery for "google-antigravity" was blocked by destination policy: provider URL hostname daily-cloudcode-pa.googleapis.com resolves to non-global address (::ffff:0:c612:29) [urlClass=provider-models, fallback=configured].
[opencodex] Provider model discovery for "anthropic" was blocked by destination policy: provider URL hostname api.anthropic.com resolves to non-global address (::ffff:0:c612:28) [urlClass=provider-models, fallback=configured].
[opencodex] Provider model discovery for "zhipu-bigmodel-coding" was blocked by destination policy: provider URL hostname open.bigmodel.cn resolves to non-global address (::ffff:0:c612:26) [urlClass=provider-models, fallback=configured].
[opencodex] Provider model discovery for "deepseek" was blocked by destination policy: provider URL hostname api.deepseek.com resolves to non-global address (::ffff:0:c612:25) [urlClass=provider-models, fallback=configured].
[opencodex] Provider model discovery for "kimi" was blocked by destination policy: provider URL hostname api.kimi.com resolves to non-global address (::ffff:0:c612:27) [urlClass=provider-models, fallback=configured].

$ ocx sync   # after the one-line fix
[opencodex] Provider outbound proxy mode preserves Bun proxy/NO_PROXY routing and validates the URL plus available local DNS results.
   + 18 models appended to Codex catalog

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingproxyHTTP proxy, routing, reverse-proxy / management auth

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions