RUST Network - Tun
一直想了解加速器的工作原理,看到很多都会提到普通的代理只能提供Tcp的代理,而游戏是走UDP的,一般用Tap设备虚拟网卡和修改路由表的方式来转发游戏的数据到加速服务器
网络协议
开发时经常提到:
- 二层协议指数据链路层,主要是以太协议,物理链路算是第一层
- 三层协议就是指网络层,主要是IP协议
- 四层协议是指传输层,主要是TCP和UDP协议
- 应用层协议就是一般的应用程序基于TCP或UDP实现的特殊应用功能的协议
层次 | 作用和协议 | |
---|---|---|
Layer 5 | 应用层application layer | 例如HTTP、FTP、DNS(如BGP和RIP这样的路由协议,尽管由于各种各样的原因它们分别运行在TCP和UDP上,仍然可以将它们看作网络层的一部分) |
Layer 4 | 传输层transport layer | 例如TCP、UDP、RTP、SCTP(如OSPF这样的路由协议,尽管运行在IP上也可以看作是网络层的一部分) |
Layer 3 | 网络互连层internet layer | 对于TCP/IP来说这是因特网协议(IP)(如ICMP和IGMP这样的必须协议尽管运行在IP上,也仍然可以看作是网络互连层的一部分;ARP不运行在IP上) |
Layer 2 | 网络链路层Network Access(link) layer | 例如以太网、Wi-Fi、MPLS等。 |
低层协议头包在高层协议外层,例如收到到数据为
1 | [链路层以太协议包头][IP包头][TCP包头][应用协议包头][应用数据] |
TCP
RFC793 定义了TCP的详细内容
TCP协议头
1 | TCP Header Format( Note that one tick mark represents one bit position) |
UDP
RFC768定义了UDP协议,很短一份文档
UDP包头
1 |
|
IP
IP协议分为IPv4 RFC791 和IPv6 RFC8200
IPv4包头为20字节
1 | 0 1 2 3 |
ICMP
RFC 792定义了ICMP
ping命令的协议格式如下
1 | Echo or Echo Reply Message |
Raw Packet编程
Socket
网络应用程序通信时会使用socket来建立主机间的点对点连接,RFC3493 对它有一些扩展描述。一般可以认为socket是在传输层和应用层之间的会话层,因为它建立了两个设备之间会话连接。普通的应用程序使用socket编程时,会设置socket的类型为SOCK_STREAM
表示TCP数据传输或SOCK_DGRAM
表示UDP数据传输。当然对于抓包应用程序,还可以设置类型为SOCK_RAW
,这样获取到数据不会被内核的TCP/IP协议栈处理掉对应的TCP或IP的包头。socket编程学习可以参考https://w3.cs.jmu.edu/kirkpams/OpenCSF/Books/csf/html/Sockets.html
一般应用程序不会使用raw类型的socket,因为原始包中的TCP或IP包头没有被处理,就需要应用程序来处理这些包头,这些不是应用程序关心的协议,所以很少会用SOCK_RAW
类型。
如果是为了学习网络协议,特别是底层协议,就需要获取到网卡传给内核的原始数据包。由于应用程序在用户空间无法获取到内核空间的数据,应用程序拿到的网络数据一般(除了SOCK_RAW
)都是经过内核的协议栈处理过的TCP或UDP协议上的数据,这些数据的TCP或UDP的包头已经被内核处理掉了,应用直接拿到的就是数据而不包括协议头。
虚拟网络设备
linux类的系统中提供了Tap/Tun虚拟网卡设备,它可以在用户空间接收和传输原始数据包,可以看作是一个简单的从物理介质上收发数据的点对点或以太设备。
使用虚拟网卡的基本步骤:
- 创建虚拟网卡设备,一般网卡名称为Tap0或Tun0
- 给虚拟网卡配置ip地址,掩码,网关信息,可能还需要路由信息,让指定ip的访问都通过这个网卡传输
- 网络应用程序中打开这个虚拟网卡,得到对应的设备描述符,通过描述符读写数据
- 例如主机A的浏览器需要从服务器B下载文件,但是主机A不能直接访问到服务器B,通过配置路由表,让对服务器B的访问都通过虚拟网卡Tun0传输,此时浏览器像B地址的请求,内核会发送给虚拟网卡Tun0
- 网络应用程序收到内核给Tun0发来的IP数据包,并将IP数据包数据包加密压缩处理后发送给代理服务器P
- 代理服务器P收到数据包,解压解密后,向服务器B发送请求,并得到B的应答
- 代理服务器P将服务器B的应答压缩加密后,发送回网络应用程序
- 网络应用程序通过Tun0网卡把解压和解密后数据发送给浏览器
整个过程中内核会把tun0当作真实的物理网卡
Tap和Tun区别
Tap工作在2层网络,它的数据包从以太帧开始
Tun工作在3层网络,它的数据包从IP包开始
因此,如果想要自己实现TCP或UDP协议,使用tun就足够了,如果想实现ARP协议,需要Tap设备,参看编写网络协议栈之Ethernet & ARP Protocol
wintun
linux内核默认支持了tun/tap虚拟网卡,windows可以通过wintun来创建tun网卡。
wintun是WireGuard软件中使用的为windows内核实现的tun虚拟网卡设备,使用方法和linux的tun相同。
rust使用wintun
crate wintun 是对wintun动态库的rust封装,项目中有使用这个crate的例子程序
1 | [dependencies] |
ICMP by Rust
ICMP虽然和IP在同一层,但是它也是由IP包头里面打包的。ping命令就是ICMP的一个重要功能。
[IP Header][ICMP Header][ICMP Data]
通过使用socket的SOCK_RAW
类型也可以实现ping命令,参看Linux下实现ping程序。
为了学习tun和rust参考Implementing ICMP in Rust和study-udp 来实现ICMP的ping命令应答。
下图为ping -4 www.baidu.com
执行后的数据包,可以看到IP包包头20字节,ICMP的 Echo包共40字节
工程依赖使用wintun和etherparse,后者用来解析ip包
1 | [dependencies] |
下载wintun的压缩包,解压后wintun目录放在项目的根目录中。程序运行后,执行ping 172.250.68.100
就可以看到收到的数据包和应答。如果ping
虚拟网卡自己的ip则不会收到包。
1 | use std::sync::{atomic::{AtomicBool, Ordering}, Arc}; |