# TCP/IP、《关于TUN虚拟网卡内重定向实现TCP/IP三层转四层代理的技术原理研究》

摘要

本文提出了一种基于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 现有方案
  1. 应用层协议栈方案:例如 tun->gVisor->socket,程序内从tun网卡读取到TCP/IP数据包,注入gVisor协议栈解析转化为四层代理
  2. 系统重定向方案:例如 iptables 配置重定向,将链接重定向至代理,
1.2.2、一些不足
  1. 不灵活:无法深度定制
  2. 完整应用层协议栈依赖:依赖应用层完整协议栈,对数据包处理转发存在着一定的性能损耗,且实现复杂
  3. 系统环境依赖:依赖注入iptables等工具实现重定向,无法任意跨平台移植
  4. 隧道依赖:对于代理TCP此类可靠性协议而言,无法使用UDP等不可靠协议进行数据传输

2、虚拟网卡内重定向方案

这是一个实验性新方案,针对现有代理方案的不足作出补充,简化系统复杂度,让系统更加健壮。

2.1、核心创新点

  1. 无应用层协议栈依赖:不依赖完整应用层协议栈,依靠TUN虚拟网卡自身协议栈重定向数据到代理服务
  2. 无额外系统依赖:不依赖如iptables等其它NAT服务依赖,在程序内修改数据包
  3. 轻量级状态跟踪:仅需简单四元组的轻量级连接映射,无连接状态管理
  4. 选择性代理:可自定义选择性代理,如当隧道为UDP时,无需代理,数据包直接转发。当TCP隧道时,为优化TCP-in-TCP可选择性代理TCP协议,UDP、ICMP等仍直接转发

2.2、技术背景

为了方便描述这一方案的具体实现流程,也为了方便理解,有一些用到的相关知识点需要说明。

  1. TUN设备:关于TUN设备,在windows下使用wintun.dll,在linux使用tuntap设备,在android使用VpnService,创建网卡设备后,程序可以从网卡读取TCP/IP数据包和写入TCP/IP数据包,也可以使用lwip、smoltcp、picotcp 等其它轻量级协议栈在嵌入式应用内使用
  2. 协议栈:对于Src IP 与 Dst IP 相同的数据包,会被视为环回数据包
  3. TCP三次握手:A 发送 SYN、B 回复 SYN+ACK、A 发送 ACK,完成一次握手
  4. 关于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、环境设定
  1. TUN网段:10.18.18.0/24
  2. TUN设备IP:10.18.18.2
  3. 代理地址:0.0.0.0:33333,可以使用10.18.18.2:33333访问
  4. 目标服务:80,本地80,或者远程80
2.3.2、重定向过程

假设使用 10.18.18.3:80 访问对端服务,访问端为A端代理服务为B端实际服务为C端

  1. A.SYN:从TUN网卡读取到(访问产生的SYN)
    1. 包:10.18.18.2:11111->10.18.18.3:80
    2. 申请随机空闲端口,比如得到 22222,经过测试,在windows仍然可以使用11111
    3. 添加两条映射关系
      • (10.18.18.2,11111) : (10.18.18.3,11111,80,22222)
      • (10.18.18.2,22222) : (10.18.18.3,11111,80,22222)
    4. 修改包为 10.18.18.0:22222->10.18.18.2:33333
    5. 重新写入TUN网卡
  2. B.SYN+ACK:从TUN网卡读取到包(这是B端的回复)
    1. 包:10.18.18.2:33333->10.18.18.0:22222
    2. 根据(Src IP 10.18.18.2,Dst Port 22222)查询映射关系得到值
    3. 修改包为 10.18.18.3:80->10.18.18.2:11111
    4. 重新写入网卡
  3. A.ACK:从TUN网卡读取到包(这是A收到B的SYN+ACK后进行的ACK确认)
    1. 包:10.18.18.2:11111->10.18.18.3:80
    2. 根据 (Src IP 10.18.18.2,Src Port 11111) 查询映射关系得到值
    3. 修改包为 10.18.18.0:22222->10.18.18.2:33333
    4. 重新写入网卡
  4. B.代理:在代理端收到ACK后,socket.accept() 成功,得到socketB,再新建socketC去连接C端实际服务,后续 socketB 与 socketC 相互交换数据即可
  5. 已结束握手
  6. PSH+ACK/ACK:对于后续的 PSH+ACK、ACK 仍然同理,通过映射查询,修改包,再写入网卡
  7. FIN/RST:关于挥手,在网卡读取到FIN/RST数据包时,将映射标记为结束,在经过一定时间后,移除映射
  8. 完成一次完整代理过程

2.4、性能测试

2.4.1、测试环境
  1. 系统:windows11
  2. CPU:I9 9900KF
  3. 内存:3600 32GB
  4. 网卡:wintun 0.14.1
  5. 软件:iperf3
  6. 语言:C#(.NET8.0)
2.4.2、测试结果

直连为iperf3不经过任何代理直接连接服务,linker 为本文方案,tun2socks为现有开源方案

环回MTU非常大,TUN网卡无法设置那么大的MTU,所以选择使用 64K 包测试

本机环回连接服务,单位Gbits
宿主机TUN设备代理连接VMware虚拟机,单位Gbits

2.5、应用场景与优势

2.5.1、应用场景
  1. 隧道优化:能有效改善TCP-in-TCP问题
  2. TUN全局代理:快速有效的实现重定向,代理流量
2.5.2、优势
  1. 高性能:避免了用户态协议栈开销
  2. 灵活性:能在TCP/IP级别写的细粒度下控制流量
  3. 轻量级:核心代码少,逻辑简单
  4. 移植性:完全编程式,无外部依赖,可随意移植到任意环境

3、结论与未来

本文提出的TUN虚拟网卡内重定向技术为解决TCP代理中的性能问题提供了新的思路,对现有方案的一些不足之处作出补充,并兼顾性能与灵活性、可移植性,极大简化了重定向过程与逻辑。


4、末页

  1. 此文关于三层、四层的说法基于 网络七层模型:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。三层为网络层TCP/IP,四层为传输层UDP、TCP等的socket,http、https、socks5等代理为四层传输层socket。 ↩︎