Skip to content

feat: multi-edge fronting_groups + rename google_only to direct#488

Merged
therealaleph merged 2 commits intotherealaleph:mainfrom
dazzling-no-more:feature/fronting-groups
Apr 29, 2026
Merged

feat: multi-edge fronting_groups + rename google_only to direct#488
therealaleph merged 2 commits intotherealaleph:mainfrom
dazzling-no-more:feature/fronting-groups

Conversation

@dazzling-no-more
Copy link
Copy Markdown
Contributor

Summary

  • New feature: fronting_groups config field — generalizes the Google-edge SNI-rewrite trick to any multi-tenant CDN edge (Vercel, Fastly, …). Each group is {name, ip, sni, domains}; matched hosts get MITM-decrypted at the local CA and re-encrypted upstream against ip with sni as the TLS SNI.
  • Rename: mode = "google_only"mode = "direct". The old name no longer described the mode now that it reaches more than Google. Both Rust and Android Kotlin keep "google_only" as a deprecated alias on parse — no existing config / saved settings break.
  • Recommend bumping to v1.9.0 rather than v1.8.6: a new top-level config field + a public mode-string rename are minor-bump territory, not a patch. Users on v1.8.x configs are unaffected (alias preserves them), but the feature surface justifies it.

What's new

  • fronting_groups: [{name, ip, sni, domains}] in config.json. Wins over the built-in Google SNI-rewrite suffix list; loses to passthrough_hosts and DoH bypass. Skipped in mode = full (which preserves end-to-end TLS and can't MITM).
  • Working example: config.fronting-groups.example.json.
  • Full doc at docs/fronting-groups.md — recipe for picking (ip, sni), routing precedence, and an explicit ⚠️ warning about the cross-tenant Host-header leak failure mode (don't list domains that aren't actually on the edge).

google_onlydirect rename

  • Rust: Mode::GoogleOnlyMode::Direct. Parser accepts both strings.
  • Android: Mode.GOOGLE_ONLYMode.DIRECT. Same parse-time alias.
  • Desktop UI dropdown: "Google-only (bootstrap)" → "Direct (no relay)". On load, the legacy string is normalized so the next Save migrates the on-disk file to the new name.
  • File rename: config.google-only.example.jsonconfig.direct.example.json.
  • Docs (README EN + FA, SF_README EN + FA, tunnel-node FA) carry a "was named google_only before v1.9 — old name still works" note for users following older guides / Telegram posts.

Review fixes folded in

  • Config::validate() parses ServerName::try_from(sni) so invalid SNIs fail at the load gate, not later at proxy startup.
  • RewriteCtx::fronting_groups: Vec<Arc<FrontingGroupResolved>> — per-CONNECT match is refcount-only, no Vec<String> clone of normalized domains.
  • New is_dot_anchored_match helper: byte-level slicing replaces per-match format!(".{}", entry) allocation.
  • Startup warnings: mode = full && !fronting_groups.is_empty() (groups never fire), and duplicate group names (log lines become ambiguous). Both follow the existing bypass_doh_hosts + tunnel_doh precedent.

Test plan

  • cargo build --release clean
  • cargo test --lib — 169 passed, 0 failed (+8 new: dispatch matching, config validation, alias back-compat)

Credit

Multi-edge fronting technique + the Vercel/Fastly example IPs are from @patterniha's MITM-DomainFronting. This PR ports the idea into mhrv-rs's existing MITM + dispatch infrastructure, validates SNIs through rustls, and exposes it as a first-class config field.

@github-actions github-actions Bot added the type: feature feat: PR — auto-applied by release-drafter label Apr 29, 2026
@dazzling-no-more dazzling-no-more mentioned this pull request Apr 29, 2026
@therealaleph therealaleph merged commit 79cca10 into therealaleph:main Apr 29, 2026
1 check passed
therealaleph added a commit that referenced this pull request Apr 29, 2026
…p + hotspot sharing

Three substantive PRs landed for this release plus an Iran-safe DoH default:

- #488 by @dazzling-no-more (with credit to @patterniha): fronting_groups
  config field generalizes the Google-edge SNI-rewrite trick to any
  multi-tenant CDN edge (Vercel, Fastly, etc.). Renames `mode = "google_only"`
  → `mode = "direct"` with a deprecated alias keeping existing configs working.
  This is the v1.9.0 headline — new top-level config field + public mode-string
  rename are minor-bump territory. xmux moves to v1.10.0.

- #494 by @dazzling-no-more: edge-cache DNS at Apps Script (CodeFull.gs)
  using CacheService. udp_open / port=53 ops served from cache or DoH
  fallback chain (Cloudflare → Google → Quad9). Cache hits drop typical
  first-hop DNS latency from 600-1200ms to 200-400ms. Default-on, opt-out
  via ENABLE_EDGE_DNS_CACHE; every failure mode falls through to existing
  tunnel-node forward path (zero regression).

- #483 by @yyoyoian-pixel: default listen_host from 127.0.0.1 to 0.0.0.0
  so an Android phone running the tunnel + an iPhone/laptop on the same
  hotspot can use it as proxy. Old configs with explicit 127.0.0.1 are
  honored (not overwritten).

Plus: default `tunnel_doh: true` (flipped from false in v1.8.x) per #468
— Iran ISPs filter direct connections to dns.google, chrome.cloudflare-dns.com,
and other pinned DoH hosts. The bypass-on default silently broke DNS for
the dominant Iranian userbase. The safe default keeps DoH inside the
tunnel; non-Iran users can opt back into the bypass for the latency win.
Backwards-compatible — any config with explicit tunnel_doh keeps its setting.

169 mhrv-rs lib tests + 33 tunnel-node tests + 11 edge-DNS JS tests all
passing. Clean release + UI builds.
@dazzling-no-more dazzling-no-more deleted the feature/fronting-groups branch April 29, 2026 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature feat: PR — auto-applied by release-drafter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants