跨平台代理客户端开发实战指南
从系统代理、TUN/VPN、DNS、路由回环,到 Rust Platform Adapter 与移动端嵌入全流程架构指南。
客户端: Flutter / Rust / Electron / 原生 GUI
平台: Windows、Linux、macOS、Android、iOS
目标: 从系统代理、TUN/VPN、DNS、路由回环,到 Rust Platform Adapter 与移动端嵌入,建立一套可以真正落地开发的跨平台代理客户端架构。
0. 先明确:我们到底在开发什么
一个代理客户端并不是“把订阅链接导入,然后启动一个代理内核”这么简单。
真正的客户端至少需要解决三个问题:
- Core:流量应该怎么处理?
- Platform:操作系统的流量怎么进入 Core?
- GUI / Backend:用户怎么控制 Core 与 Platform?
因此可以把整个系统拆成:
┌──────────────────────────────────────────────┐
│ GUI │
│ Flutter / Tauri / Native / Electron │
└──────────────────────┬───────────────────────┘
│
│ IPC / FFI / API
▼
┌──────────────────────────────────────────────┐
│ Client Backend │
│ │
│ 配置 / 订阅 / 节点 / 状态机 / 生命周期 / 日志 │
└───────────────┬───────────────────┬──────────┘
│ │
▼ ▼
┌────────────────┐ ┌──────────────────┐
│ Proxy Core │ │ Platform Adapter │
│ │ │ │
│ Mihomo │ │ Windows │
│ sing-box │ │ Linux │
│ │ │ macOS │
│ DNS │ │ Android │
│ Routing │ │ iOS │
│ Proxy │ │ │
│ TUN/tun2socks │ │ System / TUN/VPN │
└────────┬───────┘ └────────┬─────────┘
│ │
└──────────┬─────────┘
▼
Operating System
核心原则:
这也是后续所有设计的基础。
1. 代理客户端的两种基本工作模式
绝大多数客户端首先可以抽象为两种模式:
System Proxy
TUN / VPN
它们不是两个不同的“代理协议”,而是两种把流量交给 Proxy Core 的方式。
2. System Proxy:让应用主动连接 Core
System Proxy 的逻辑非常简单。
假设 Core 监听:
HTTP 127.0.0.1:7890
SOCKS 127.0.0.1:7891
客户端修改操作系统代理:
HTTP → 127.0.0.1:7890
HTTPS → 127.0.0.1:7890
SOCKS → 127.0.0.1:7891
数据流:
Application
│
│ HTTP / HTTPS / SOCKS
▼
OS Proxy Configuration
│
▼
127.0.0.1:7890
│
▼
Proxy Core
│
├── DIRECT
│
└── PROXY
这里最重要的概念是:
因此:
浏览器
↓
读取系统代理
↓
127.0.0.1:7890
↓
Core
可能正常。
但是:
某些游戏
某些后台服务
某些 CLI
某些 UDP 应用
某些自己实现网络栈的程序
可能完全不读取系统代理。
所以 System Proxy 的特点是:
| 特性 | System Proxy |
|---|---|
| 实现难度 | 低 |
| 权限需求 | 低 |
| CPU 开销 | 低 |
| 全局接管 | 否 |
| UDP | 取决于应用 |
| 游戏 | 不保证 |
| 后台程序 | 不保证 |
| DNS | 不一定经过 Core |
3. TUN:直接接管 IP 流量
TUN 的思路完全不同。
System Proxy:
应用 → 主动连接代理
TUN:
应用 → 操作系统网络栈 → TUN → Core
典型数据流:
Application
│
▼
Operating System Network Stack
│
▼
TUN Interface
│
│ IPv4 / IPv6 Packet
▼
Tun2socks / User-space Network Stack
│
│ TCP / UDP
▼
Proxy Core
│
├── DNS
├── Routing
├── DIRECT
└── PROXY
│
▼
Physical Network
│
▼
Internet
所以:
System Proxy
= 应用主动使用代理
TUN
= 系统把 IP 流量送到虚拟网络接口
4. 为什么 TUN 不能直接交给 SOCKS?
这是理解 TUN 的关键。
TUN 读到的是:
IPv4 / IPv6 Packet
例如一个 TCP 数据包:
┌────────────────────────────────┐
│ IPv4 Header │
├────────────────────────────────┤
│ TCP Header │
├────────────────────────────────┤
│ Application Payload │
└────────────────────────────────┘
而 SOCKS5、Shadowsocks、VLESS、Trojan 等代理协议通常需要的是:
TCP Stream
或者:
UDP Datagram
因此需要一个转换层:
L3 IP Packet
│
▼
┌──────────────────┐
│ tun2socks │
│ / user-space stack│
└────────┬─────────┘
│
▼
TCP / UDP
│
▼
Proxy Protocol
常见实现思路包括:
gVisor Netstack
lwIP
系统网络栈
Core 自带用户态协议栈
这里不要把 tun2socks 理解成“另一个代理”。
它解决的是:
5. TUN 最危险的问题:Routing Loop
这是开发 TUN 客户端必须首先解决的问题。
假设:
代理服务器:
1.2.3.4:443
正常情况下:
Core
↓
1.2.3.4:443
↓
Internet
但是你设置了:
0.0.0.0/0 → TUN
于是 Core 发出的连接也可能被送进:
TUN
↓
Core
↓
TUN
↓
Core
↓
...
形成:
Routing Loop
结果可能是:
- CPU 飙升
- 网络带宽异常
- Core 不断建立自身连接
- 整机断网
- DNS 失效
- TUN 无法关闭
因此 TUN 客户端有一个非常重要的原则:
不同平台实现方式不同。
6. Windows 防回环
Windows 常见思路:
TUN 全局接管
│
├── 普通应用 → TUN
│
└── Proxy Core → Physical NIC
可以使用:
IP_UNICAST_IF
WFP
进程 / PID 过滤
物理网卡 IfIndex 绑定
核心思想不是“让 Core 不联网”,而是:
例如:
Application
↓
Wintun
↓
Core
│
├── 普通代理流量
│
└── Core → Proxy Server
↓
Physical NIC
而不是:
Core → Wintun → Core
7. Linux 防回环:Policy Routing
Linux 的一个典型方案是:
普通流量
↓
TUN
Core 流量
↓
fwmark
↓
独立路由表
↓
Physical NIC
概念上:
┌──────────────────────────┐
│ Main Routing Table │
│ default → tun0 │
└──────────────────────────┘
┌──────────────────────────┐
│ Table 100 │
│ default → Physical NIC │
└──────────────────────────┘
Core 的 socket:
SO_MARK = 0x1
然后:
ip rule
把:
fwmark 0x1
导向:
table 100
这样:
Core
↓
mark 0x1
↓
table 100
↓
eth0 / wlan0
↓
Internet
而普通应用:
Application
↓
main routing
↓
tun0
↓
Core
8. Android 防回环:protect()
Android 是这个问题最典型的平台。
Android 提供:
VpnService
当 VPN 接管:
0.0.0.0/0
以后,Core 自己创建的 socket 也可能被 VPN 捕获。
因此 Core 创建:
socket()
connect(proxy_server)
之前,需要:
VpnService.protect(socket)
逻辑:
Application
↓
VPN
↓
Core
│
│ protect(socket)
▼
Physical Wi-Fi / Cellular
↓
Proxy Server
没有 protect():
Core
↓
VPN
↓
Core
↓
VPN
↓
...
因此在 Android 平台,protect() 不是可选优化,而是 VPN Core 集成中的关键机制。
9. DNS 为什么是代理客户端的核心问题
TUN 不仅仅要处理 TCP / UDP。
DNS 同样需要考虑。
如果:
Application
↓
公网 DNS
↓
真实 IP
那么可能出现:
DNS Leak
DNS 污染
域名分流失效
例如规则:
DOMAIN-SUFFIX,google.com,PROXY
如果应用首先把:
google.com
解析成:
142.x.x.x
Core 后面只看到:
142.x.x.x:443
那么基于域名的路由信息可能已经丢失。
10. Fake-IP
因此许多代理 Core 会采用 Fake-IP。
例如:
Application
│
│ DNS: google.com
▼
Proxy Core DNS
│
▼
198.18.0.23
Core 保存:
198.18.0.23
↕
google.com
之后:
Application
↓
198.18.0.23:443
↓
TUN
↓
Core
Core 查询映射:
198.18.0.23
↓
google.com
然后:
google.com
↓
Routing Rules
↓
PROXY
↓
Proxy Node
这样 Core 即使收到的是 Fake-IP,也能够恢复原始域名。
11. Fake-IP 的数据结构
逻辑上可以理解成:
struct FakeIpEntry {
ip: IpAddr,
domain: String,
expires_at: Instant,
}
映射:
198.18.0.23 → google.com
198.18.0.24 → github.com
198.18.0.25 → example.com
实际 Core 的实现可能更加复杂,但客户端架构需要理解的核心就是:
DNS Query
↓
Fake-IP allocation
↓
Mapping table
↓
TUN packet
↓
Restore domain
↓
Routing
12. Windows:System Proxy
Windows 系统代理通常可以通过:
HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings
配置。
典型字段:
ProxyEnable
ProxyServer
ProxyOverride
例如:
ProxyEnable = 1
ProxyServer =
127.0.0.1:7890
ProxyOverride =
<local>;localhost;127.*;10.*;192.168.*
修改后还需要通知系统刷新设置:
InternetSetOptionW(
NULL,
INTERNET_OPTION_SETTINGS_CHANGED,
NULL,
0
);
InternetSetOptionW(
NULL,
INTERNET_OPTION_REFRESH,
NULL,
0
);
13. Windows 客户端不能直接“关闭代理”
这是很多客户端容易犯的错误。
假设用户原本:
ProxyEnable = 1
ProxyServer = 192.168.1.10:8080
PAC = ...
启动你的客户端:
保存原配置
↓
设置 127.0.0.1:7890
退出时必须:
恢复原配置
而不是:
ProxyEnable = 0
否则你的客户端会破坏用户原来的网络环境。
因此 Backend 应该维护:
struct PreviousProxyState {
enabled: bool,
server: Option<String>,
bypass: Option<String>,
pac_url: Option<String>,
}
14. Windows:TUN
Windows 没有像 Linux /dev/net/tun 那样直接给用户态使用的标准 TUN 文件接口。
代理客户端通常使用:
Wintun
典型结构:
Applications
↓
Windows TCP/IP Stack
↓
Wintun
↓
Proxy Core
↓
Routing / DNS / Proxy
↓
Physical NIC
Platform Adapter 需要负责:
创建 Wintun
配置 IP
配置路由
启动 / 停止接口
清理路由
恢复系统状态
15. Windows 权限模型
不要让整个 GUI:
Administrator
运行。
推荐:
┌──────────────────────┐
│ GUI │
│ 普通用户 │
└──────────┬───────────┘
│
│ Named Pipe / IPC
▼
┌──────────────────────┐
│ Privileged Service │
│ Windows Service │
│ │
│ Wintun │
│ Route │
│ Firewall / WFP │
└──────────────────────┘
这样:
GUI
只负责 UI。
而:
Service
负责需要管理员权限的操作。
16. Linux:System Proxy
Linux 没有一个统一覆盖所有程序的“系统代理 API”。
常见来源包括:
GNOME
KDE
Environment Variables
Application-specific settings
环境变量:
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
export ALL_PROXY=socks5://127.0.0.1:7891
export NO_PROXY=localhost,127.0.0.1
GNOME 可以使用:
gsettings
KDE 则存在对应桌面配置机制。
因此 Linux System Proxy 的重要结论:
17. Linux:TUN
Linux 提供:
/dev/net/tun
创建 TUN 后:
Application
↓
Linux Network Stack
↓
tun0
↓
Proxy Core
需要处理:
TUN
IP address
Routing
Policy Routing
DNS
Firewall
Permissions
典型检查:
ip addr
ip route
ip rule
18. Linux 权限分离
推荐:
GUI
↓
Unix Socket / D-Bus
↓
Privileged Helper
↓
TUN / Route / Firewall
而不是:
Flutter GUI
↓
sudo
↓
各种 shell 命令
对于需要的能力,可以考虑:
CAP_NET_ADMIN
CAP_NET_BIND_SERVICE
Polkit
systemd service
例如原始文档中的一种方案:
sudo setcap cap_net_admin,cap_net_bind_service=+ep /path/to/proxy-core
但实际产品中仍需要根据发行版、安全模型和安装方式决定最终权限方案。
19. macOS:System Proxy
macOS 的系统代理可以通过:
SystemConfiguration
networksetup
处理。
例如:
networksetup -setwebproxy "Wi-Fi" 127.0.0.1 7890
networksetup -setsecurewebproxy "Wi-Fi" 127.0.0.1 7890
networksetup -setsocksfirewallproxy "Wi-Fi" 127.0.0.1 7891
关闭:
networksetup -setwebproxystate "Wi-Fi" off
networksetup -setsecurewebproxystate "Wi-Fi" off
networksetup -setsocksfirewallproxystate "Wi-Fi" off
产品级实现应优先使用系统 API,而不是简单依赖 shell。
20. macOS:Network Extension
macOS 网络接管可以围绕:
Network Extension
设计。
核心组件:
NEPacketTunnelProvider
逻辑:
Main App
│
▼
VPN Configuration
│
▼
System Extension
│
▼
NEPacketTunnelProvider
│
▼
Proxy Core
主 App 和 Extension 是不同运行环境。
因此需要设计:
配置同步
状态同步
启动 / 停止
错误传递
IPC
21. Android:VpnService
Android 与桌面最大的不同是:
基本代码结构:
class LocalVpnService : VpnService() {
private var vpnInterface: ParcelFileDescriptor? = null
fun startVpn() {
val builder = Builder()
.setSession("ProxyClient")
.setMtu(1500)
.addAddress("172.19.0.1", 30)
.addRoute("0.0.0.0", 0)
.addRoute("::", 0)
.addDnsServer("198.18.0.1")
vpnInterface = builder.establish()
}
}
关键 API:
Builder.establish()
addAddress()
addRoute()
addDnsServer()
addAllowedApplication()
addDisallowedApplication()
protect()
22. Android VPN 到底是不是“远程 VPN”?
不是。
这里必须区分两个概念。
Android:
VpnService
只是建立:
本地虚拟网络接口
它并不意味着:
Android → 某个 VPN 服务器
真正的链路可能是:
Android
↓
VpnService
↓
Proxy Core
↓
Shadowsocks / VLESS / Trojan / ...
↓
Remote Proxy Server
↓
Internet
因此:
VpnService = 系统流量接管机制
代理节点 = Core 的远程出站
二者不是一回事。
23. Android:按 App 分流
Android 可以利用:
addAllowedApplication()
addDisallowedApplication()
实现:
白名单
黑名单
Split Tunnel
例如:
Chrome → VPN
Steam → VPN
微信 → DIRECT
最终由:
VpnService Builder
决定哪些应用进入 VPN。
24. Android:Core 如何运行
桌面可以:
启动 mihomo.exe
Android 不应该简单照搬这种模式。
推荐:
Flutter / Native
│
▼
Kotlin VpnService
│
│ tunFd
▼
Native Core
Core 可以根据实现选择:
.so
JNI
C ABI
AAR
Rust library
例如:
Kotlin
│
├── establish()
│
├── tunFd
│
└── protect()
│
▼
Rust Core
25. Android:tunFd 的生命周期
这里是移动端开发最容易出问题的地方之一。
流程应该是:
用户点击启动
↓
请求 VPN 权限
↓
VpnService 启动
↓
Builder.establish()
↓
获得 ParcelFileDescriptor
↓
获得 tunFd
↓
把 fd 交给 Native Core
↓
Core 开始读取 Packet
停止:
用户点击停止
↓
停止 Core
↓
停止所有出站连接
↓
关闭 TUN
↓
关闭 ParcelFileDescriptor
↓
VpnService stop
不能让 Core 在 fd 已经关闭以后继续读写。
26. Android:protect() 的调用链
建议把它抽象成:
Rust Core
│
│ connect(proxy_server)
▼
Native socket
│
│ JNI / callback
▼
Kotlin VpnService.protect(fd)
│
▼
Android Network
│
▼
Physical Interface
因此 Platform Adapter 可以提供:
trait SocketProtector {
fn protect(&self, fd: RawFd) -> Result<(), PlatformError>;
}
Android:
protect(fd)
Linux:
fwmark
Windows:
interface binding / WFP
这样 Core 不需要知道:
Android
Windows
Linux
只需要调用抽象接口。
27. iOS:Network Extension
iOS 的系统级网络接管主要围绕:
Network Extension
NEPacketTunnelProvider
Main App:
Flutter / SwiftUI
Extension:
NEPacketTunnelProvider
二者不能简单理解为一个普通进程。
结构:
┌────────────────────────┐
│ Main App │
│ Flutter / SwiftUI │
└───────────┬────────────┘
│
│ VPN configuration
▼
┌────────────────────────┐
│ Network Extension │
│ │
│ NEPacketTunnelProvider │
│ │ │
│ ▼ │
│ Proxy Core │
└───────────┬────────────┘
│
▼
iOS Network Stack
28. iOS:packetFlow
iOS 不让开发者直接照搬桌面:
/dev/net/tun
而是提供:
packetFlow
读取:
packetFlow.readPackets { packets, protocols in
// process packets
}
写回:
packetFlow.writePackets(
packets,
withProtocols: protocols
)
因此:
iOS kernel
↓
packetFlow
↓
Proxy Core
↓
packetFlow
↓
iOS kernel
29. iOS:主 App 与 Extension
主 App:
订阅
节点
配置
UI
状态
Extension:
VPN
Packet
Core
Routing
DNS
共享配置通常需要:
App Group
逻辑:
Main App
│
│ shared container
▼
App Group
▲
│
Network Extension
因此不要设计成:
Flutter UI 直接控制 packetFlow
而应该:
Flutter
↓
Native iOS layer
↓
VPN Manager
↓
Network Extension
↓
Core
30. 五个平台真正的差异
| 平台 | System Proxy | TUN / VPN | 核心入口 | 防回环 |
|---|---|---|---|---|
| Windows | WinINet / 系统配置 | Wintun | Wintun + 路由 | 接口绑定 / WFP |
| Linux | GNOME / KDE / 环境变量 | /dev/net/tun |
TUN + ip rule | fwmark / policy routing |
| macOS | SystemConfiguration | Network Extension / utun 路线 | NEPacketTunnelProvider | 路由 / Extension 机制 |
| Android | 有限系统代理能力 | VpnService | ParcelFileDescriptor | protect() |
| iOS | 能力受限 | Network Extension | NEPacketTunnelProvider |
平台网络扩展机制 |
真正应该抽象的不是:
Windows = TUN
Linux = TUN
Android = TUN
而是:
Platform Adapter
│
├── Create Traffic Capture
├── Configure Routing
├── Configure DNS
├── Protect Core Egress
├── Configure System Proxy
└── Restore System State
31. PlatformAdapter
Rust 可以把平台差异收敛到一个接口。
pub trait PlatformAdapter: Send + Sync {
fn enable_system_proxy(
&self,
settings: &SystemProxySettings,
) -> Result<(), AdapterError>;
fn disable_system_proxy(
&self,
) -> Result<(), AdapterError>;
fn enable_tun(
&self,
settings: &TunSettings,
) -> Result<(), AdapterError>;
fn disable_tun(
&self,
) -> Result<(), AdapterError>;
fn protect_socket(
&self,
fd: RawFd,
) -> Result<(), AdapterError>;
fn status(
&self,
) -> PlatformStatus;
fn emergency_restore(
&self,
) -> Result<(), AdapterError>;
}
但要注意:
例如:
WindowsAdapter
├── WinINet
├── Wintun
└── WFP
LinuxAdapter
├── gsettings
├── /dev/net/tun
├── ip rule
└── nftables
AndroidAdapter
├── VpnService
├── tunFd
└── protect()
IOSAdapter
├── NETunnelProviderManager
└── NEPacketTunnelProvider
32. Core 与 Platform 的边界
这是整个项目最重要的架构边界之一。
Proxy Core 负责
代理协议
DNS
Fake-IP
Routing
TCP
UDP
TLS
节点
出站
tun2socks
连接管理
Platform Layer 负责
TUN 创建
VPN 创建
路由
系统代理
DNS 系统配置
权限
Socket 防回环
网络状态恢复
Client Backend 负责
订阅
配置
节点管理
状态机
Core 生命周期
Platform 生命周期
日志
错误处理
GUI 负责
界面
交互
节点选择
模式切换
实时状态
流量显示
33. 推荐项目目录
如果使用:
Flutter + Rust
可以采用:
proxy-client/
├── apps/
│ ├── desktop/
│ ├── android/
│ └── ios/
│
├── crates/
│ ├── core/
│ ├── config/
│ ├── subscription/
│ ├── routing/
│ ├── platform/
│ │ ├── windows/
│ │ ├── linux/
│ │ ├── macos/
│ │ ├── android/
│ │ └── ios/
│ │
│ ├── ipc/
│ └── ffi/
│
├── native/
│ ├── windows/
│ ├── android/
│ └── ios/
│
└── flutter/
├── lib/
└── assets/
如果 Core 使用 Mihomo / sing-box,而不是自己实现代理协议,则可以进一步:
proxy-client/
├── frontend/
│
├── backend/
│ ├── config
│ ├── controller
│ ├── process
│ └── state
│
├── core/
│ └── mihomo / sing-box
│
├── platform/
│ ├── windows
│ ├── linux
│ ├── macos
│ ├── android
│ └── ios
│
└── native/
34. Core 生命周期
不要让 GUI 自己到处执行:
start core
kill core
restart core
set proxy
set tun
应该由 Backend 管理状态机。
例如:
enum ClientState {
Stopped,
Starting,
Running,
Stopping,
Error,
}
代理模式:
enum TrafficMode {
SystemProxy,
Tun,
}
完整状态:
Stopped
↓
Starting
↓
CoreReady
↓
PlatformReady
↓
Running
停止:
Running
↓
Stopping
↓
RestorePlatform
↓
StopCore
↓
Stopped
35. 启动顺序
推荐:
1. 读取配置
2. 验证配置
3. 启动 Core
4. 等待 Core Ready
5. 创建 / 配置 Platform
6. 配置 DNS / Route
7. 启用 System Proxy 或 TUN
8. 状态切换 Running
而不是:
先改系统路由
再启动 Core
否则 Core 启动失败时:
系统已经被接管
但没有处理流量的 Core
用户就会直接断网。
36. 停止顺序
推荐反过来:
1. 停止接收新的系统流量
2. 关闭 TUN / System Proxy
3. 恢复 DNS / Route
4. 停止 Core
5. 清理临时资源
6. 状态 = Stopped
如果 Core 先死:
Core
↓
Crash
↓
TUN 仍然存在
↓
系统流量继续进入 TUN
↓
用户断网
所以平台层必须有:
emergency_restore()
37. Fail-Safe
生产环境必须考虑:
客户端崩溃
Core 崩溃
系统重启
强制关机
网络切换
用户拔网线
Wi-Fi → Ethernet
Wi-Fi → Cellular
Windows 尤其需要防:
ProxyEnable = 1
ProxyServer = 127.0.0.1:7890
但是 Core 已经不存在。
因此:
启动
↓
检查残留状态
↓
验证 Core
↓
清理孤儿配置
必要时增加:
Watchdog
38. IPv6
如果只配置:
0.0.0.0/0
而没有:
::/0
系统可能通过 IPv6:
Physical NIC
↓
Internet
从而绕过 IPv4 TUN。
因此 IPv6 策略必须明确:
支持 IPv6
或者:
明确阻断 IPv6
而不是:
什么都不配置
39. MTU
TUN 不应该默认认为:
MTU = 1500
在不同环境中可能需要不同值。
例如:
Ethernet
Wi-Fi
Cellular
VPN
Proxy Protocol
都会影响有效 MTU。
如果代理协议产生额外开销:
Original Packet
+
Proxy Header
+
Encryption Overhead
可能超过路径 MTU。
因此需要考虑:
MTU
MSS
Fragmentation
TCP MSS Clamping
40. 完整 Windows TUN 数据流
┌─────────────────────┐
│ Application │
│ Chrome / Steam etc. │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ Windows TCP/IP │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ Wintun │
└─────────┬───────────┘
│ L3 Packet
▼
┌─────────────────────┐
│ Proxy Core │
│ │
│ tun2socks │
│ DNS │
│ Fake-IP │
│ Routing │
└─────────┬───────────┘
│
│ Proxy Socket
│
│ interface binding
▼
┌─────────────────────┐
│ Physical NIC │
└─────────┬───────────┘
│
▼
Proxy Server
│
▼
Internet
41. 完整 Android VPN 数据流
┌────────────────────┐
│ Android App │
└─────────┬──────────┘
│
▼
┌────────────────────┐
│ Android Network │
└─────────┬──────────┘
│
▼
┌────────────────────┐
│ VpnService │
│ Builder.establish │
└─────────┬──────────┘
│
│ tunFd
▼
┌────────────────────┐
│ Rust / Native Core │
│ │
│ Packet → TCP/UDP │
│ DNS │
│ Routing │
└─────────┬──────────┘
│
│ protect(fd)
▼
┌────────────────────┐
│ Wi-Fi / Cellular │
└─────────┬──────────┘
│
▼
Proxy Server
42. 完整 iOS 数据流
┌─────────────────────┐
│ Main App │
│ Flutter / Swift │
└──────────┬──────────┘
│
▼
NETunnelProviderManager
│
▼
┌─────────────────────┐
│ NEPacketTunnelProvider│
└──────────┬──────────┘
│
▼
packetFlow
│
▼
┌─────────────────────┐
│ Embedded Core │
│ DNS / Routing / Proxy│
└──────────┬──────────┘
│
▼
iOS Network
│
▼
Internet
43. Flutter 与 Rust
如果 GUI 使用 Flutter,而 Backend 使用 Rust,建议:
Flutter
│
│ FFI / plugin
▼
Rust Client Backend
│
├── Config
├── Subscription
├── State
├── Core Controller
└── Platform Adapter
但 Android / iOS 的系统能力仍然需要原生层。
例如 Android:
Flutter
↓
Dart
↓
Platform Channel / FFI
↓
Kotlin VpnService
↓
Rust Core
iOS:
Flutter
↓
Swift
↓
NETunnelProviderManager
↓
Network Extension
↓
Rust Core
Windows:
Flutter
↓
Rust
↓
Windows Service
↓
Wintun / WFP
因此:
真正应该统一的是:
业务模型
Core API
配置模型
状态模型
PlatformAdapter 抽象
而不是强迫所有系统 API 都使用 Rust 重新包装。
44. Core API 应该是什么样
Client Backend 不应该依赖 GUI。
例如:
pub trait ProxyController {
fn start(
&self,
config: CoreConfig,
) -> Result<(), CoreError>;
fn stop(
&self,
) -> Result<(), CoreError>;
fn reload(
&self,
config: CoreConfig,
) -> Result<(), CoreError>;
fn status(
&self,
) -> CoreStatus;
fn connections(
&self,
) -> Vec<ConnectionInfo>;
}
GUI 只需要:
start()
stop()
reload()
status()
connections()
而不需要知道:
Wintun
VpnService
NEPacketTunnelProvider
ip rule
fwmark
45. 一个完整的启动流程
以 TUN 模式为例:
用户点击“启动”
│
▼
GUI
│
▼
Client Backend
│
├── 读取配置
├── 检查配置
└── 启动 Core
│
▼
Core Ready
│
▼
Platform Adapter
│
┌───────┴────────┐
│ │
▼ ▼
TUN/VPN DNS/Route
│ │
└───────┬────────┘
▼
Platform Ready
│
▼
Running
46. 一个完整的关闭流程
用户点击“停止”
│
▼
Client Backend
│
▼
停止新的流量接管
│
▼
Disable TUN / VPN
│
▼
恢复 Route / DNS
│
▼
恢复 System Proxy
│
▼
Stop Core
│
▼
Cleanup
│
▼
Stopped
47. 开发顺序
不要同时开发五个平台。
推荐:
第一阶段:Windows
先完成:
Core Controller
System Proxy
配置备份
配置恢复
Wintun
TUN
Routing
DNS
防回环
Crash Recovery
目标:
Windows 上可以稳定运行
第二阶段:Linux
加入:
/dev/net/tun
ip rule
ip route
fwmark
systemd-resolved
nftables
CAP_NET_ADMIN
然后验证:
Linux TUN
第三阶段:macOS
先实现:
System Proxy
再实现:
Network Extension
不要一开始就把:
utun
root helper
Network Extension
全部混在一起。
第四阶段:Android
核心目标:
VpnService
tunFd
Rust / Native Core
protect()
DNS
App Routing
重点测试:
Wi-Fi
5G
切网
锁屏
后台
VPN 重启
Core 崩溃
第五阶段:iOS
最后再处理:
Network Extension
NEPacketTunnelProvider
App Group
Extension 生命周期
Core 嵌入
内存
签名
Entitlement
iOS 应该最后做,因为它对进程、权限和 Extension 生命周期的限制最明显。
48. 最终架构
最后整个项目应该收敛成:
┌───────────────────┐
│ GUI │
│ Flutter / Native │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ Client Backend │
│ │
│ Config │
│ Subscription │
│ State Machine │
│ Core Controller │
└─────────┬─────────┘
│
┌──────────────┴──────────────┐
│ │
▼ ▼
┌──────────────────┐ ┌────────────────────┐
│ Proxy Core │ │ Platform Adapter │
│ │ │ │
│ DNS │ │ Windows │
│ Routing │ │ Linux │
│ Proxy │ │ macOS │
│ TUN │ │ Android │
│ tun2socks │ │ iOS │
└─────────┬────────┘ └─────────┬──────────┘
│ │
└──────────────┬─────────────┘
▼
Operating System
│
▼
Internet
最终职责非常明确:
GUI
↓
用户怎么控制
Client Backend
↓
整个客户端怎么运行
Proxy Core
↓
流量怎么代理
Platform Adapter
↓
系统流量怎么进入 Core
Operating System
↓
真正的网络设备与系统能力
49. 开发者应该记住的四句话
第一
第二
第三
第四
50. 最终设计原则
如果把整份指南压缩成一个架构原则,就是:
GUI
│
▼
Client Backend
│
┌────────┴────────┐
▼ ▼
Proxy Core Platform Adapter
│ │
│ │
│ ┌──────┼──────┐
│ ▼ ▼ ▼
│ Windows Linux Android ...
│
▼
Proxy Network
Proxy Core 决定“怎么代理”。
Platform Adapter 决定“怎么接管系统流量”。
Client Backend 决定“怎么把 Core 与 Platform 组织起来”。
GUI 决定“用户怎么操作”。
这四层分开以后,Windows、Linux、macOS、Android、iOS 才真正能够共享一套客户端架构。
附:实现前的验证清单
Core
- ☐ 配置加载
- ☐ 配置校验
- ☐ DNS
- ☐ Fake-IP
- ☐ Routing
- ☐ TCP
- ☐ UDP
- ☐ TUN / tun2socks
- ☐ Proxy Outbound
- ☐ Core 状态
Platform
- ☐ System Proxy
- ☐ TUN / VPN
- ☐ Route
- ☐ DNS
- ☐ Socket 防回环
- ☐ 权限
- ☐ 状态恢复
- ☐ 网络切换
- ☐ Crash Recovery
Client Backend
- ☐ Core 生命周期
- ☐ Platform 生命周期
- ☐ 状态机
- ☐ 配置管理
- ☐ 订阅管理
- ☐ 日志
- ☐ 错误处理
GUI
- ☐ 节点列表
- ☐ 模式选择
- ☐ 启动 / 停止
- ☐ 当前状态
- ☐ 流量统计
- ☐ 连接列表
- ☐ 日志
- ☐ 设置
Android
- ☐ VpnService
- ☐ VPN 授权
- ☐ tunFd
- ☐ protect()
- ☐ App 分流
- ☐ Wi-Fi / Cellular
- ☐ 后台生命周期
iOS
- ☐ Network Extension
- ☐ NEPacketTunnelProvider
- ☐ packetFlow
- ☐ VPN 配置
- ☐ App Group
- ☐ Extension 生命周期
- ☐ Core 嵌入
- ☐ Entitlement / Signing