MIUI中VPN模块的设计原理与核心组件

系统架构 / 0人浏览

凌晨两点十七分,我盯着手机屏幕上那个旋转了快半分钟的加载圈,心里只有一个念头:如果再连不上新加坡那个节点,我挂的限价单就要在流动性最差的时段被吃掉了。

这不是什么电影桥段,是上周真实发生在我身上的事。当时BTC刚跌破六万,群里一片哀嚎,而我手里还捏着一笔准备在去中心化交易所抄底的USDT。问题出在手机上——我用的那台小米13,MIUI系统,VPN突然抽风,连不上。桌面上的VPN图标亮着,但流量就是出不去。我切换到备用机,iPhone上同样的节点秒连。那一刻我意识到,MIUI的VPN模块,远比我想象的要复杂。

一个深夜的VPN故障排查

先说说当时的情况。我用的是一家小众VPN服务商,协议是WireGuard,平时在MIUI上跑得好好的。但那天晚上,系统更新了一个安全补丁后,VPN就连不上了。表现很诡异:设置里的VPN状态显示“已连接”,但浏览器打不开任何网页,Telegram也转圈。我第一反应是节点挂了,但用iPhone测试后发现节点完全正常。

于是我开始折腾。关掉VPN重开,没用。重启手机,没用。清除VPN应用数据,重新导入配置,还是没用。最后我打开了MIUI的开发者选项,抓了一份logcat日志,才发现问题所在:MIUI的VPN模块在建立隧道后,没有正确地把DNS请求路由到VPN接口。系统仍然在用运营商的DNS解析域名,而运营商的DNS在特定时段会污染某些加密货币交易所的域名。

这让我对MIUI的VPN实现产生了浓厚的兴趣。后来我花了两周时间,翻了AOSP的源码、MIUI的部分开源组件,以及一些逆向工程的分析文章,才大致理清了它的设计原理和核心组件。这篇文章就是这些折腾的产物。

MIUI VPN模块的架构分层

要理解MIUI的VPN模块,得先明白Android本身的VPN框架。Android从4.0开始就内置了VpnService API,允许第三方应用创建虚拟网卡、配置路由表、拦截和转发流量。MIUI作为深度定制系统,在这个基础上做了不少自己的事情。

从VpnService到MIUI的封装层

标准的Android VPN应用是这样工作的:应用通过VpnService.Builder创建一个TUN设备,然后系统会把所有符合条件的流量路由到这个TUN设备上,应用再从TUN设备读取IP包,封装进VPN协议,通过物理网卡发出去。整个过程,VPN应用就像一个用户态的TCP/IP协议栈。

MIUI在这一层之上加了一个“VPN管理服务”,叫MiuiVpnManagerService。这个服务不是开源的,但从行为上看,它至少做了三件事:第一,统一管理所有VPN应用的连接状态;第二,在系统设置里提供一个集中的VPN开关和配置入口;第三,对VPN应用进行权限校验和生命周期管理。

这个设计的好处是,用户不需要每个VPN应用都去单独配置,系统层面就能切换。坏处也很明显:多了一层抽象,出问题的时候排查链路变长了。我那天晚上的故障,就出在这一层——MiuiVpnManagerService在系统更新后,对WireGuard应用的onRevoke回调处理有变化,导致VPN接口的DNS配置没有正确下发。

核心组件一:VpnService的MIUI实现

MIUI的VpnService实现和AOSP的基本一致,但在几个关键点上做了修改。最明显的是对Builder.addAddress()和Builder.addRoute()的调用时机做了限制。在AOSP里,你可以在onStartCommand里慢慢构建配置,但MIUI要求必须在onStartCommand返回之前完成所有Builder调用,否则系统会认为VPN应用无响应,直接杀掉。

这个改动对开发者来说是个坑。很多VPN应用在启动时会去拉取远程配置,比如从服务器获取最新的节点列表和路由规则。这个过程如果超过几秒钟,MIUI就会弹出一个“VPN应用无响应”的对话框,然后强制断开。我用的那家VPN服务商,后来专门为MIUI做了一个“快速启动”模式,把配置缓存到本地,就是为了绕过这个限制。

另一个改动是setBlocking()的默认行为。AOSP里,setBlocking(true)会让read()调用阻塞,直到有数据可读。MIUI在某些版本里,把这个调用改成了非阻塞模式,导致VPN应用需要自己处理EAGAIN错误。如果应用没做这个处理,就会出现“连接成功但没流量”的现象。我那天晚上的故障,有一部分原因就在这里。

核心组件二:路由与DNS处理

这是MIUI VPN模块里最复杂、也最容易出问题的部分。Android的VPN路由是基于策略路由的,系统会根据VPN应用配置的路由表,把流量分成“走VPN”和“不走VPN”两类。MIUI在这个基础上,加了一个“应用级分流”的功能,允许用户指定哪些应用走VPN,哪些不走。

这个功能对加密货币用户来说太重要了。比如,你可以让币安App走VPN,但让微信不走VPN。实现原理是,MIUI在netd里加了一套基于UID的路由规则。每个应用在安装时会被分配一个UID,MIUI的VPN服务会读取用户的分流配置,然后动态生成iptables规则,把不同UID的流量标记上不同的fwmark,再根据fwmark选择路由表。

听起来很优雅,但实际用起来经常出问题。最常见的是DNS泄漏。Android的DNS解析默认走netd的resolv服务,这个服务在VPN连接后,应该把DNS请求也路由到VPN接口。但MIUI在某些版本里,resolv服务的配置更新有延迟,导致VPN刚连上的几秒钟内,DNS请求仍然走物理网卡。对于加密货币用户来说,这几秒钟足够让交易所的域名被污染,然后你就会被重定向到一个钓鱼网站。

我后来养成了一个习惯:每次连上VPN后,先访问一个DNS泄漏检测网站,确认DNS也走了VPN,再去操作交易所。这个习惯救了我好几次。

核心组件三:Always-on VPN与Kill Switch

MIUI的“始终开启的VPN”功能,底层用的是Android的AlwaysOnVpn机制。这个机制的原理是,系统会记住一个VPN应用,在开机后自动连接,并且在VPN断开时阻止所有流量。对于加密货币用户来说,这个功能是刚需——你肯定不希望手机在后台偷偷用物理网卡发交易请求。

但MIUI的实现有个小毛病:它会在VPN断开时,弹出一个不可忽略的系统通知,而且这个通知会一直响,直到你手动关掉。更麻烦的是,在某些MIUI版本里,这个通知会触发系统的省电策略,把VPN应用杀掉,然后进入一个“断开-重连-再断开”的死循环。我有一台备用机就遇到过这个问题,最后只能把“始终开启的VPN”关掉,改用Tasker脚本手动管理。

Kill Switch的实现倒是比较标准,用的是iptables的DROP规则。当VPN断开时,系统会插入一条规则,把所有非VPN接口的流量丢弃。但这条规则有个漏洞:它不阻止DNS请求。所以如果你的VPN断了,DNS请求还是会发出去,只是响应回不来。对于普通用户来说,这没什么,但对于加密货币用户来说,DNS请求本身就包含了你要访问的域名,这已经泄露了你的意图。

虚拟币热点下的MIUI VPN实践

说回虚拟币。为什么我要在手机上折腾VPN?因为现在的加密货币操作,早就不是坐在电脑前看K线那么简单了。空投交互、链上挖矿、NFT抢购、DEX套利,这些操作都需要在手机上完成,而且往往需要在几分钟内完成。一旦VPN出问题,机会就没了。

我认识一个专门做链上套利的朋友,他用的是小米手机,MIUI系统,装了五个不同的VPN应用。他的策略是:平时用A应用,A挂了立刻切B,B挂了切C。他还在开发者选项里打开了“不保留活动”,确保每个VPN应用在切换时都是冷启动,避免状态残留。他告诉我,MIUI的VPN模块虽然问题多,但有一个好处:它允许同时安装多个VPN应用,并且可以在系统设置里快速切换。这个功能在AOSP里是没有的,原生Android只能同时激活一个VPN。

另一个有意思的实践是,有人把MIUI的VPN模块和加密货币钱包的“隐私模式”结合起来。比如,某些钱包应用支持通过VPN接口发送交易,这样交易的广播就不会暴露你的真实IP。但MIUI的VPN模块在切换网络时(比如从WiFi切到5G),会重新建立隧道,这个过程中如果钱包应用正在广播交易,交易可能会失败。所以有人写了一个Xposed模块, hook了MIUI的VPN状态回调,在隧道重建时暂停钱包应用的网络请求,等隧道稳定后再恢复。

一些不那么技术但很重要的细节

MIUI的VPN模块在省电策略上非常激进。默认情况下,当屏幕关闭后,系统会限制VPN应用的后台网络活动。对于加密货币用户来说,这意味着如果你在挂单,然后锁屏,VPN可能会断,然后你的挂单可能因为IP变化而被交易所风控。解决办法是在“电池与性能”里把VPN应用设为“无限制”,并且在“省电策略”里关掉“锁屏后断开数据”。

另一个细节是,MIUI的VPN模块对IPv6的支持一直不太稳定。很多VPN服务商默认只分配IPv4地址,但MIUI在某些版本里会优先尝试IPv6连接,导致连接失败。解决办法是在VPN配置里强制指定IPv4,或者在开发者选项里关掉IPv6。

还有,MIUI的VPN模块在系统更新后,经常会重置一些配置。比如你设置的应用级分流规则,更新后可能会丢失。所以每次系统更新后,最好重新检查一遍VPN配置。我现在的做法是,把VPN配置导出成文件,更新后直接导入。

写在最后

那天晚上,我最终通过关闭“始终开启的VPN”、手动设置DNS、然后重新导入WireGuard配置,恢复了连接。但等我连上的时候,那笔限价单已经被别人吃掉了。我损失了一个大概15%的套利机会,换算成USDT,大概够买一台新的小米手机。

这件事让我明白,在加密货币的世界里,VPN不是可有可无的工具,而是基础设施。而MIUI的VPN模块,虽然功能丰富,但在稳定性和可预测性上,还有很长的路要走。如果你也在用MIUI手机做加密货币操作,我的建议是:永远准备一个备用方案,永远在操作前测试VPN,永远不要完全信任系统的VPN状态显示。

版权声明:

作者: 最新小米VPN免费节点分享

链接: https://xiaomivpn.com/system-arch/miui-vpn-module-design-principles.htm

来源: xiaomivpn.com

文章版权归作者所有,未经允许请勿转载。

最新文章

归档

标签