摘要
本文提出了一种基于TUN虚拟网卡内重定向技术,在不依赖用户态TCP/IP协议栈的情况下,实现三层网络层1到四层传输层的代理功能。该技术通过修改TCP/IP包四元组信息,在TUN设备内部完成连接重定向,能有效解决TCP-in-TCP性能问题,同时保持了对UDP和ICMP等协议的原生支持。
1、引言
1.1、研究背景
随着虚拟专用网络(VPN)、TUN全局代理、等技术广泛应用,TUN虚拟网卡成为实现网络虚拟化的关键技术。
在虚拟专用网络(VPN)应用中,TCP-in-TCP成为一个关键的通信性能瓶颈,从而诞生TUN代理技术,TUN代理技术也广泛应用在全局代理应用中。然而现有的TUN代理方案仍然存在着一些不足。
1.2、现有解决方案及不足
1.2.1 现有方案
- 应用层协议栈方案:例如 tun->gVisor->socket,程序内从tun网卡读取到TCP/IP数据包,注入gVisor协议栈解析转化为四层代理
- 系统重定向方案:例如 iptables 配置重定向,将链接重定向至代理,
1.2.2、一些不足
- 不灵活:无法深度定制
- 完整应用层协议栈依赖:依赖应用层完整协议栈,对数据包处理转发存在着一定的性能损耗,且实现复杂
- 系统环境依赖:依赖注入iptables等工具实现重定向,无法任意跨平台移植
- 隧道依赖:对于代理TCP此类可靠性协议而言,无法使用UDP等不可靠协议进行数据传输
2、虚拟网卡内重定向方案
这是一个实验性新方案,针对现有代理方案的不足作出补充,简化系统复杂度,让系统更加健壮。
2.1、核心创新点
- 无应用层协议栈依赖:不依赖完整应用层协议栈,依靠TUN虚拟网卡自身协议栈重定向数据到代理服务
- 无额外系统依赖:不依赖如iptables等其它NAT服务依赖,在程序内修改数据包
- 轻量级状态跟踪:仅需简单四元组的轻量级连接映射,无连接状态管理
- 选择性代理:可自定义选择性代理,如当隧道为UDP时,无需代理,数据包直接转发。当TCP隧道时,为优化TCP-in-TCP可选择性代理TCP协议,UDP、ICMP等仍直接转发
2.2、技术背景
为了方便描述这一方案的具体实现流程,也为了方便理解,有一些用到的相关知识点需要说明。
- TUN设备:关于TUN设备,在windows下使用wintun.dll,在linux使用tuntap设备,在android使用VpnService,创建网卡设备后,程序可以从网卡读取TCP/IP数据包和写入TCP/IP数据包,也可以使用lwip、smoltcp、picotcp 等其它轻量级协议栈在嵌入式应用内使用
- 协议栈:对于Src IP 与 Dst IP 相同的数据包,会被视为环回数据包
- TCP三次握手:A 发送 SYN、B 回复 SYN+ACK、A 发送 ACK,完成一次握手
- 关于CIDR:假设网络为 10.18.18.0/24,则网络号 10.18.18.0,起始ip 10.18.18.1,结束ip 10.18.18.254,广播号 10.18.18.255,网络号无人使用,我们将使用网络号作为重定向中转ip
2.3、实现原理
2.3.1、环境设定
- TUN网段:10.18.18.0/24
- TUN设备IP:10.18.18.2
- 代理地址:0.0.0.0:33333,可以使用10.18.18.2:33333访问
- 目标服务:80,本地80,或者远程80
2.3.2、重定向过程
假设使用 10.18.18.3:80 访问对端服务,访问端为A端,代理服务为B端,实际服务为C端
- A.SYN:从TUN网卡读取到(访问产生的SYN)
- 包:10.18.18.2:11111->10.18.18.3:80
- 申请随机空闲端口,比如得到 22222,经过测试,在windows仍然可以使用11111
- 添加两条映射关系
- (10.18.18.2,11111) : (10.18.18.3,11111,80,22222)
- (10.18.18.2,22222) : (10.18.18.3,11111,80,22222)
- 修改包为 10.18.18.0:22222->10.18.18.2:33333
- 重新写入TUN网卡
- B.SYN+ACK:从TUN网卡读取到包(这是B端的回复)
- 包:10.18.18.2:33333->10.18.18.0:22222
- 根据(Src IP 10.18.18.2,Dst Port 22222)查询映射关系得到值
- 修改包为 10.18.18.3:80->10.18.18.2:11111
- 重新写入网卡
- A.ACK:从TUN网卡读取到包(这是A收到B的SYN+ACK后进行的ACK确认)
- 包:10.18.18.2:11111->10.18.18.3:80
- 根据 (Src IP 10.18.18.2,Src Port 11111) 查询映射关系得到值
- 修改包为 10.18.18.0:22222->10.18.18.2:33333
- 重新写入网卡
- B.代理:在代理端收到ACK后,socket.accept() 成功,得到socketB,再新建socketC去连接C端实际服务,后续 socketB 与 socketC 相互交换数据即可
- 已结束握手
- PSH+ACK/ACK:对于后续的 PSH+ACK、ACK 仍然同理,通过映射查询,修改包,再写入网卡
- FIN/RST:关于挥手,在网卡读取到FIN/RST数据包时,将映射标记为结束,在经过一定时间后,移除映射
- 完成一次完整代理过程
2.4、性能测试
2.4.1、测试环境
- 系统:windows11
- CPU:I9 9900KF
- 内存:3600 32GB
- 网卡:wintun 0.14.1
- 软件:iperf3
- 语言:C#(.NET8.0)
2.4.2、测试结果
直连为iperf3不经过任何代理直接连接服务,linker 为本文方案,tun2socks为现有开源方案
环回MTU非常大,TUN网卡无法设置那么大的MTU,所以选择使用 64K 包测试
本机环回连接服务,单位Gbits
宿主机TUN设备代理连接VMware虚拟机,单位Gbits
2.5、应用场景与优势
2.5.1、应用场景
- 隧道优化:能有效改善TCP-in-TCP问题
- TUN全局代理:快速有效的实现重定向,代理流量
2.5.2、优势
- 高性能:避免了用户态协议栈开销
- 灵活性:能在TCP/IP级别写的细粒度下控制流量
- 轻量级:核心代码少,逻辑简单
- 移植性:完全编程式,无外部依赖,可随意移植到任意环境
3、结论与未来
本文提出的TUN虚拟网卡内重定向技术为解决TCP代理中的性能问题提供了新的思路,对现有方案的一些不足之处作出补充,并兼顾性能与灵活性、可移植性,极大简化了重定向过程与逻辑。
4、末页
- 此文关于三层、四层的说法基于 网络七层模型:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。三层为网络层TCP/IP,四层为传输层UDP、TCP等的socket,http、https、socks5等代理为四层传输层socket。 ↩︎