Linux Tap/Tun 介绍

半兽人 发表于: 2023-02-24   最后更新时间: 2024-03-30 00:30:01  
{{totalSubscript}} 订阅, 1,555 游览

虚拟二层网卡Tap,虚拟三层隧道网卡Tun

Tap/Tun 是 Linux 内核 2.4.x 版本之后加入的虚拟网络设备,不同于物理网卡靠硬件网路板卡的实现方式,Tap/Tun 虚拟网卡完全由内核软件来实现的,是一种让用户态程序向内核协议栈注入数据的设备。Tap工作在二层(数据链路层)而 Tun 工作在三层(网络层)。功能和硬件实现完全没有差别,它们都属于网络设备,都可以配置IP,都归 Linux 网络设备管理模块统一管理。

Tap 工作在数据链路层:只能处理二层的以太网数据帧,与其中的以太网(Ethernet)协议对应,所以 tap 有时也称为 “虚拟以太网设备” 。

Tun 工作在网络层:是一个点对点(Peer To Peer)的网络层设备,只能处理 IP 数据包,通常用于建立 IP 层隧道(Tunnel)。

作为网络设备,tap/tun 也需要配套相应的驱动程序才能工作。tap/tun 驱动程序包括两个部分:

  1. 字符设备驱动:负责数据包在内核空间和用户空间的传送。
  2. 网卡驱动:负责数据包在内核网络协议栈上的传输和处理。

Tap/Tun 作为用户空间与内核空间的数据传输通道

在 Linux 中,用户空间和内核空间的数据传输有多种方式,字符设备就是其中的一种。tap/tun 通过驱动程序和一个与之关联的字符设备文件,来实现用户空间和内核空间的通信接口。

在 Linux 内核 2.6.x 之后的版本中,tap/tun 对应的字符设备文件分别为:

  • tap:/dev/tap0
  • tun:/dev/net/tun

字符设备文件即充当了用户空间和内核空间通信的接口。当应用程序打开设备文件时,驱动程序就会创建并注册相应的虚拟设备接口,一般以 tunX 或 tapX 命名。当应用程序关闭文件时,驱动也会自动删除 tunX 和 tapX 设备,还会删除已经建立起来的路由等信息。

tap/tun 设备文件就像一个管道,一端连接着用户空间,一端连接着内核空间。当用户程序向文件 /dev/net/tun 或 /dev/tap0 写数据时,内核就可以从对应的 tunX 或 tapX 接口读到数据,反之,内核可以通过相反的方式向用户程序发送数据。

tap/tun 与内核网络协议栈的数据传输

tap/tun 通过实现相应的网卡驱动程序来和 TCP/IP 网络协议栈通信。一般的流程和物理网卡和协议栈的交互流程是一样的,不同的是物理网卡一端是连接物理网络,而 tap/tun 虚拟网卡一般连接到用户空间。

首先看看物理网卡是如何工作的,物理网卡时收到数据包之后就会交给内核网络协议栈处理,然后通过 Socket API 通知给用户程序。

screenshot

下面看看 tun 的工作方式,物理网卡通过网线收发数据包,但是 tun 设备通过一个字符设备文件收发数据包。

tun的工作方式

如果使用 tun 设备搭建一个基于 UDP VPN,那么整个处理过程就是这样:数据包会通过内核网络协议栈两次,在经过 VPN App 的处理后,数据包可能已经加密,并且原有的 IP Header 被封装在 UDP 内部,所以网络包在第二次通过内核网络栈时看到的是截然不同的网络包。

screenshot

再举一个例子,我们有两个应用程序 A、B,物理网卡 eth0 和虚拟网卡 tun0 分别配置 IP:10.1.1.11192.168.1.11,程序 A 希望构造数据包发往 192.168.1.0/24 网段的主机 192.168.1.1。

+----------------------------------------------------------------+
|                                                                |
|  +--------------------+      +--------------------+            |
|  | User Application A |      | User Application B |<-----+     |
|  +--------------------+      +--------------------+      |     |
|               | 1                    | 5                 |     |
|...............|......................|...................|.....|
|               ↓                      ↓                   |     |
|         +----------+           +----------+              |     |
|         | socket A |           | socket B |              |     |
|         +----------+           +----------+              |     |
|                 | 2               | 6                    |     |
|.................|.................|......................|.....|
|                 ↓                 ↓                      |     |
|             +------------------------+                 4 |     |
|             | Newwork Protocol Stack |                   |     |
|             +------------------------+                   |     |
|                | 7                 | 3                   |     |
|................|...................|.....................|.....|
|                ↓                   ↓                     |     |
|        +----------------+    +----------------+          |     |
|        |      eth0      |    |      tun0      |          |     |
|        +----------------+    +----------------+          |     |
|    10.1.1.11   |                   |   192.168.1.11      |     |
|                | 8                 +---------------------+     |
|                |                                               |
+----------------|-----------------------------------------------+Physical Network
  1. 应用程序 A 构造数据包,目的 IP 是 192.168.1.1,通过 socket A 将这个数据包发给协议栈。
  2. 协议栈根据数据包的目的 IP 地址,匹配路由规则,发现要从 tun0 出去。
  3. tun0 发现自己的另一端已经被应用程序 B 打开,于是将数据发给程序 B。
  4. 程序 B 收到数据后,做一些跟业务相关的操作,然后构造一个新的数据包,源 IP 是 eth0 的 IP,目的 IP 是 10.1.1.0/24 的网关 10.1.1.1,封装原来的数据的数据包,重新发给协议栈。
  5. 协议栈再根据本地路由,将这个数据包从 eth0 发出。

后续步骤,当 10.1.1.1 收到数据包后,会进行解封装,读取里面的原始数据包,继而转发给本地的主机 192.168.1.1。当接收回包时,也遵循同样的流程。在这个流程中,应用程序 B 的作用其实是利用 tun0 对数据包做了一层隧道封装。

tap 设备与 tun 设备工作方式完全相同,区别在于:tun 设备的 /dev/tunX 文件收发的是 IP 层数据包,只能工作在 IP 层,无法与物理网卡做 bridge,但是可以通过三层交换(e.g. ip_forward)与物理网卡连通;而 tap 设备的 /dev/tapX 文件收发的是 MAC 层数据包,拥有 MAC 层功能,可以与物理网卡做 bridge,支持二层广播。

更新于 2024-03-30
在线,10分钟前登录

查看Linux更多相关的文章或提一个关于Linux的问题,也可以与我们一起分享文章