🚀 What's new in 1.2.1
Added
- Public GPLv3 source release on GitHub, with a full bilingual README, CONTRIBUTING guide, and Git LFS for native binaries/geo data.
- Server-less domain fronting — new "Domain Fronting (server-less)" folder on the Connection tab. Reaches YouTube, Instagram, WhatsApp, Facebook, Reddit and other Fastly-hosted sites with no server or Cloudflare worker anywhere in the path — nothing to deploy, nothing to pay for, no shared bandwidth to saturate. TLS is terminated locally against an RSA-2048 root certificate the app generates on-device (raw X.509/DER, no BouncyCastle dependency) and re-established to the real host under a different, unblocked SNI. A guided setup card walks through certificate creation, installation (handled by Android's own installer on 10 and below; a save-to-Downloads + step-by-step Settings walkthrough on Android 11+, since the platform stopped letting apps install CAs directly), and live trust detection — no app restart needed. Browser-only by design — the YouTube/Instagram apps don't trust user-installed CAs on Android 7+; this is a platform rule with no workaround. A full tutorial (install and removal paths for Samsung, Xiaomi, Pixel, Huawei/Honor, Oppo/Realme/OnePlus, Vivo) plus 11 new FAQ entries were added to the in-app Help Center.
- Two new default Iran configs — "کانفیگ ایران ۷/۸ (جدید)", shipped byte-for-byte from upstream Serverless-for-Iran v48 (@patterniha). A strategy change over the existing six v44-derived configs: sanctioned services (GitHub, Microsoft, OpenAI, Anthropic, xAI, Go/Python/Rust package hosts) now route direct through the system resolver so they still see an Iranian IP; the DoH resolver is domain-fronted through
challenges.cloudflare.com; TLS gets a dedicated two-stage fragment outbound; QUIC and UDP/443 are blocked outright instead of noised; Iran's filter-page IP ranges are blackholed; IPv6 is raced against IPv4. A warning now shows inside the Iran-configs folder when the Local Port isn't10808, which these configs require. - Connection tab: new "Get free configs" button. A multi-step wizard aggregates configs from public GitHub-hosted subscription sources, tests each one with a real Xray-proxied connection (not just a ping), and keeps only what actually connects.
- Connection tab: real per-config country flags, queried once through the live tunnel during the "Real Delay" test and cached — no full connection needed just to see a config's real exit country.
- App updates: automatic GitHub release check on launch (and again on connect, in case GitHub was blocked at launch), with an in-app download-and-install flow when a newer version exists.
- Connection: a config's server domain is now resolved and IP-pinned before the core starts, with the outbound racing the resolved addresses concurrently (
happyEyeballs). Matters most for Cloudflare-panel configs (BPB/EDG/Nahan), whose*.workers.devdomain resolves to a large rotating pool of edge IPs — some throttled or dead at any given moment from Iranian networks. Lowers connect latency and raises connect success rate; does not change post-connect throughput. - Connection: three wasteful behaviours removed from the generated Xray config, all found via a live logcat capture rather than by inspection —
- every DNS lookup cost two round trips (an always-empty AAAA query before the real A query); now follows the device's own address-family preference
- QUIC traffic was being tunneled into a worker that carries no UDP at all, stalling every attempt before it fell back to TCP anyway; QUIC and UDP/443 are now refused immediately
- traffic to Iran's block-page IP ranges was paying full proxy latency to fetch a censorship notice; those ranges are now blackholed
- Real delay test: the per-config test config is now trimmed to just what a one-URL measurement needs (no DNS servers, fake-DNS pool, or routing table), and each concurrent test gets its own local port instead of colliding on one. Applied to the scanner's health test and the Cloudflare IP scanner's delay test too.
- Connection: the core's log level reverted from
infoback towarning— it had been raised for diagnostics and never reverted, costing constant CPU/storage for log lines nothing reads in a release build. - Proxy mode: the Local Port now accepts both SOCKS and HTTP (a
mixedinbound) instead of SOCKS only. - Connection: the app now recovers automatically from a real network drop while connected — previously the tunnel had no way to notice the underlying network was gone, so the UI stayed stuck on "connected" until a manual reconnect.
Changed
- Game tab: removed the two hardcoded legacy UAE WireGuard servers (one a dead 1-hour-trial endpoint, one already-retired dead code). Full-tunnel game boosting now goes entirely through the Aether engine, which self-selects a healthy endpoint across multiple protocols instead of one fixed server.
- Cloud panel: bundled BPB Worker Panel upgraded 4.2.2 → 5.1.1 (new per-account config embedding model, JSON login, updated settings schema).
- Cloud panel: bundled EDG worker (cmliu/edgetunnel) updated to the latest upstream build (packet coalescing, concurrent-dial racing, DoH caching).
- Cloud panel: bundled Nahan (نهان) worker upgraded 2.9.4 → 3.0.0 (VLESS proxy chaining, v2rayN JSON subscription format, redesigned user form).
- Aether: the MASQUE gateway-scan step now shows real progress (elapsed time, current attempt) instead of a static "in progress" message during a step that can legitimately take minutes.
Removed
- Deno Panel: removed entirely (drawer entry, tab, FAQ, and the underlying
engines/denocode).api.deno.comhas been blocked in Iran for a while, and Deno's duration-based billing made free servers unsuitable for VPN use anyway — the Cloudflare panels (BPB/EDG/Nahan) cover the same need without either problem.
Fixed
- Battery: substantially reduced drain while connected, from four separate always-on costs — an unbounded partial wake lock blocking deep sleep for the entire session, a leftover 5-second diagnostic loop, a traffic meter writing to disk every 2 seconds regardless of change, and an auto-switch watcher polling every 10 seconds even when the feature is off.
- Scanner: real delay/speed test numbers could read far worse than the network actually was — hundreds of configs were tested with up to 8 real concurrent connections against the same servers, which Cloudflare/DPI throttles as suspicious traffic. Concurrency is now capped at 3.
- Status bar: icons could render dark-on-dark and become invisible on phones set to system light mode.
- Cloud panel: adding an account could get permanently stuck behind a "verify your email" overlay even when email verification wasn't the actual problem.
- Cloud panel: a Global API Key with no email showed a vague "Invalid API Token" error; now explains the requirement directly.
- Cloud panel: MLM worker deploys failed intermittently around midnight–3:30am Iran time, from
compatibility_datebeing computed off the device's local clock instead of a fixed date. - Cloud panel: MLM/Nahan deploys could get permanently stuck on "Failed to create D1 Database" after a few retries, with the only fix being manual cleanup in the Cloudflare dashboard; the error now lists every existing database name.
- Cloud panel: the MLM "User Management" screen could get stuck on "Error fetching users" right after a fresh deploy (a transient Cloudflare edge 404 before the new route was live); now retries automatically.
- Cloud panel: BPB uploads failed with Cloudflare error 10021 ("No such module node:crypto") — v5.1.1 requires the
nodejs_compatflag, which wasn't being sent. - Cloud panel: BPB-generated configs connected to nothing because the worker's
mainDomainwas left blank, falling back to BPB's own placeholder domain. - Personal anti-sanction DNS: sanctioned sites still 403'd with the feature on — domain routing relied on sniffing the TLS ClientHello's SNI, which silently fails under Encrypted Client Hello (Chrome's increasing default). Now resolves through a dedicated fake-IP pool instead.
- Personal anti-sanction DNS: the DNS resolver was hardcoded to plain UDP
1.1.1.1:53with no fallback, so turning the feature on could break unrelated sites (e.g. Gmail) on networks that block plain DNS; now uses DoH like the main config. - Personal anti-sanction DNS: the "check" button's message read as if it enabled routing on its own; it only classifies, and now says to press "add" explicitly.
- Subscription links: background auto-sync re-uploaded configs to Cloudflare on every node-list change, even metadata-only ones (a ping result, a flag) that don't touch the actual config list.
- Subscription links: a link's configs could silently go empty before the user ever pressed "Update".
- Node connection: "Proxy mode" could show "connected" while the local proxy passed zero traffic, with every site timing out silently.
- Navigation: the bottom nav bar's icons looked lopsided when optional tabs (Game/WireGuard) put a different icon count on each side of the center button.
- Navigation: the hamburger drawer could get cut off on short screens, making the Emergency tiers unreachable; drawer content now scrolls fully.
- Connection tab: the country flag above the Connect button used Cloudflare's own (occasionally wrong) geoIP field; now uses the same source as per-config flags, so both agree with each other and with third-party checkers.
فارسی: تاریخچه کامل و دوزبانه در CHANGELOG.md موجود است.
Full diff: https://github.com/mlmvpn/mlmvpn_android/commits/v1.2.1