TUN vs TAP
| 特性 | TUN | TAP |
|---|---|---|
| 模拟对象 | IP 网络接口 | 以太网卡 |
| 工作层 | 第三层(IP 层) | 第二层(数据链路层) |
| 处理单元 | IP 数据包 | 以太网帧 |
| 支持协议 | 仅 IP | IP、ARP、广播等 |
| 典型用途 | 全局路由代理 | 局域网桥接 |
| CPU 开销 | 较小 | 较大 |
TUN 适合”全部流量走 VPN”,TAP 适合”需要访问远程 LAN 内设备”的桥接场景。
TUN 模式的流量拦截
VPN 客户端启用 TUN 模式的流程:
- 创建虚拟网卡
tun0 - 修改系统路由表,将默认路由(
0.0.0.0/0)指向tun0 - 所有出站 IP 包经过
tun0→ VPN 客户端加密封装 → 通过真实网卡发送到 VPN 服务器
[本地应用]
| (IP 包)
v
[tun0 虚拟网卡]
| (加密封装)
v
[VPN 客户端程序]
|
v
[VPN 服务器 -> 目标网络]
TUN 全局模式会代理 localhost
开启全局代理时,若未排除环回地址,127.0.0.1 的流量也会被 tun0 拦截,导致本地服务访问失败。
排除 localhost(OpenVPN 配置)
route 127.0.0.1 255.0.0.0 net_gateway
或在客户端设置中勾选”分流模式”,只代理外网 IP。
TAP0901 驱动(Windows)
TAP-Windows Adapter V9(tap0901)是 OpenVPN 在 Windows 上使用的虚拟以太网卡驱动,安装后在网络适配器列表中以普通网卡形式出现。
驱动通过设备文件暴露接口:
\\.\Global\{TAP-Adapter-GUID}.tap
Java 通过 JNA 读写数据包
// 打开设备文件
HANDLE h = Kernel32.INSTANCE.CreateFile(
"\\\\.\\Global\\{GUID}.tap",
WinNT.GENERIC_READ | WinNT.GENERIC_WRITE,
0, null, WinNT.OPEN_EXISTING,
WinNT.FILE_ATTRIBUTE_NORMAL, null
);
// 读取以太网帧
byte[] buf = new byte[2048];
IntByReference bytesRead = new IntByReference();
Kernel32.INSTANCE.ReadFile(h, buf, buf.length, bytesRead, null);
// 写入以太网帧
Kernel32.INSTANCE.WriteFile(h, buf, bytesRead.getValue(), bytesRead, null);
操作虚拟网卡需要管理员权限。TAP0901 只在 Windows 上可用;Linux 和 macOS 使用系统内置的 TUN/TAP 接口。
实现 VPN 客户端的选型
| 目标 | 方案 | 难度 |
|---|---|---|
| 仅代理指定应用流量 | 纯 Socket / SOCKS5 代理 | 低 |
| 全局系统流量拦截 | TUN/TAP 驱动 + JNI/JNA | 高 |
Java 只能做用户空间的协议与加密逻辑;全局流量拦截必须借助内核级虚拟网卡驱动(TUN/TAP)。
