Skip to content

fix: restore usable iOS routing and explicit UDP policy - #41

Merged
acking-you merged 1 commit into
devfrom
codex/ios-latency
Oct 22, 2026
Merged

acking-you merged 1 commit into
devfrom
codex/ios-latency

Conversation

@acking-you

@acking-you acking-you commented Oct 22, 2026 •

Copy link
Copy Markdown
Owner

Apple packet tunnels could leave Edge Google searches waiting on direct foreign QUIC, and node probes ran through the selected VPN node. Apply one UDP destination policy before opening a relay: mainland/local addresses are direct; foreign UDP is rejected immediately unless explicitly enabled, in which case it is proxied. Server UDP readiness is required before installing tunnel routes. TCP Auto/reverse settings do not alter this UDP policy, and DNS stays available.

Use the same bounded, TTL-aware address cache for TCP and UDP decisions instead of caching a transport-specific route. Keep optional UDP disabled in legacy imports/default client entry points. Connected Apple node probes now execute in the provider with four-worker concurrency and reconnect guards. Include the locally built 2.0.11+84 UI source revision; no generated binaries are committed.

Dependencies: acking-you/ipstack#3 (ICMP v4/v6 feedback), acking-you/tun2proxy#12 (destination policy), Proxy-UI/Proxy-UI-Flutter#29 (controls/provider probes). No remote proxy wire format or existing C ABI layout changes. Updated docs/ios-development.md and docs/client-usage.md distinguish Apple packet-tunnel rules from desktop TUN behavior.

Validation:

  • cargo test --workspace
  • cargo test -p proxy-client --features network-extension --test packet_tunnel
  • cargo test -p proxy-client --features network-extension --lib packet_routing
  • cargo clippy -p proxy-crypto -p proxy-core -p proxy-client -p proxy-server -p proxy-tui -p proxy-ffi --all-targets --all-features --no-deps -- -D warnings
  • cargo check -p proxy-client --no-default-features --locked
  • Rust formatting; ipstack/tun2proxy standalone tests and strict Clippy
  • fvm flutter analyze --no-fatal-infos; fvm flutter test (190 passed, 7 skipped), final focused Apple/UDP tests
  • python3 scripts/ios/build.py --team <development-team> --configuration Release, signatures and matching app/extension versions verified locally

Physical iPhone acceptance: real Edge Google search results; mainland TCP direct and foreign TCP proxy egress; mainland UDP by IP and domain succeeded in 51/104 ms; foreign UDP was rejected in 1/13 ms; 100 MB downloaded with no provider restart or dropped packets (peak footprint about 34 MB); terminating the containing app preserved forwarding. A real legacy node rejected UDP enablement before readiness, and restoring UDP-off successfully reconnected. Final Release 84 device checks additionally verified five provider-owned probes (146–443 ms), all ten HTTP/HTTPS acceptance requests, mainland UDP direct (57/97 ms), foreign UDP rejection (1/17 ms), and actual UDP proxy egress on a capable node. Three Edge Google searches, including restarting Edge, showed the reload icon and no progress bar by about 4.3 seconds; one cold search rendered results by 2.4 seconds. This checks load completion, not just visible results.

A further throughput comparison found a selected node slow on the phone network: 25 MB downloads exceeded their deadline both through TUN and through an explicit local SOCKS connection bypassing TUN. The invalid-SOCKS-port control failed immediately, confirming that the comparison actually used the explicit proxy. This is not reported as a passing stability test; final acceptance uses the independently verified working node. Timing evidence and captures remain local; no personal device data is published.

Final Release 84 on the working node completed all four 25 MB transfers (55.46 / 6.01 / 6.50 / 4.49 s; 100 MB total), with ten HTTP/HTTPS checks passing, distinct mainland/foreign egress, zero packet-queue drops, no provider restart, and a peak reported footprint of 25,166,696 bytes. Mainland UDP replies took 34–45 ms and foreign rejection 1–15 ms. The first bulk transfer was slower than subsequent transfers; these timings are retained rather than summarized as uniformly fast.

Final browsing boundary: the working-node Google “network latency” page reached 100% around 12.3 s (bar hidden by 14.3 s); subsequent “network protocol” and “network latency meaning” searches completed by about 4.3 s. In the packet trace, main Google-related TCP first responses were about 30–120 ms. The intermittent page-completion tail is not claimed to be eliminated or proven to originate in the VPN; result rendering alone is not the completion criterion.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-22T09:03:50.779813Z 6999f4c PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6999f4c01d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

.and_then(|v| parse_bool_env(&v))
})
.unwrap_or(true);
.unwrap_or(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the generated config to preserve UDP opt-in

When a first-time CLI user runs without arguments, main writes DEFAULT_CONFIG_TEMPLATE, but the embedded crates/proxy-client/config.template.toml still explicitly sets udp = true and says omission defaults to enabled. After the user fills in the server and restarts, that explicit value wins before this new fallback, so the normal first-run workflow still enables UDP without an opt-in; README.md likewise advertises the old default. Update the generated template, its configuration comment, and the README to match the new default.

AGENTS.md reference: AGENTS.md:L339-L350

Useful? React with 👍 / 👎.

Comment on lines +239 to +241
&& !ip.is_unspecified()
&& !ip.is_multicast()
&& !matches!(ip, IpAddr::V4(v4) if v4.is_broadcast())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep local multicast and broadcast UDP on the direct route

For captured local-discovery traffic such as mDNS (224.0.0.251/ff02::fb), this new filter discards the destination before is_local_network_host can classify it as local; limited IPv4 broadcasts are discarded similarly. The UDP router therefore returns Reject when UDP proxying is off or sends the packet to the remote proxy when it is enabled, breaking LAN discovery and contradicting the fixed policy that local-network UDP is direct. Preserve these local UDP destinations in the direct branch, potentially by separating UDP classification from the stricter TCP address filtering.

Useful? React with 👍 / 👎.

@acking-you
acking-you merged commit 72a1414 into dev Oct 22, 2026
3 checks passed
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