共计 2661 个字符,预计需要花费 7 分钟才能阅读完成。
导读 | 在计算机网络中,TUN 与 TAP 是操作系统内核中的虚拟网络设备。不同于普通靠硬件网路板卡实现的设备,这些虚拟的网络设备全部用软件实现,并向运行于操作系统上的软件提供与硬件的网络设备完全相同的功能。 |
TAP 等同于一个以太网设备,它操作第二层数据包如以太网数据帧。TUN 模拟了网络层设备,操作第三层数据包比如 IP 数据封包。
操作系统通过 TUN/TAP 设备向绑定该设备的用户空间的程序发送数据,反之,用户空间的程序也可以像操作硬件网络设备那样,通过 TUN/TAP 设备发送数据。在后种情况下,TUN/TAP 设备向操作系统的网络栈投递(或“注入”)数据包,从而模拟从外部接受数据的过程。
Linux Tun/Tap 驱动程序为应用程序提供了两种交互方式:虚拟网络接口和字符设备 /dev/net/tun。写入字符设备 /dev/net/tun 的数据会发送到虚拟网络接口中;发送到虚拟网络接口中的数据也会出现在该字符设备上。
应用程序可以通过标准的 Socket API 向 Tun/Tap 接口发送 IP 数据包,就好像对一个真实的网卡进行操作一样。除了应用程序以外,操作系统也会根据 TCP/IP 协议栈的处理向 Tun/Tap 接口发送 IP 数据包或者以太网数据包,例如 ARP 或者 ICMP 数据包。Tun/Tap 驱动程序会将 Tun/Tap 接口收到的数据包原样写入到 /dev/net/tun 字符设备上,处理 Tun/Tap 数据的应用程序如 V ** 程序可以从该设备上读取到数据包,以进行相应处理。
应用程序也可以通过 /dev/net/tun 字符设备写入数据包,这种情况下该字符设备上写入的数据包会被发送到 Tun/Tap 虚拟接口上,进入操作系统的 TCP/IP 协议栈进行相应处理,就像从物理网卡进入操作系统的数据一样。
Tun 虚拟设备和物理网卡的区别是 Tun 虚拟设备是 IP 层设备,从 /dev/net/tun 字符设备上读取的是 IP 数据包,写入的也只能是 IP 数据包,因此不能进行二层操作,如发送 ARP 请求和以太网广播。与之相对的是,Tap 虚拟设备是以太网设备,处理的是二层以太网数据帧,从 /dev/net/tun 字符设备上读取的是以太网数据帧,写入的也只能是以太网数据帧。从这点来看,Tap 虚拟设备和真实的物理网卡的能力更接近。
下图描述了 Tap/Tun 的工作原理:
通过应用程序从 /dev/net/tun 字符设备中读取或者写入数据看上去并没有太大用处,但通过将 Tun/Tap 结合物理网络设备使用, 我们可以创建一个点对点的隧道。如下图所示,左边主机上应用程序发送到 Tun 虚拟设备上的 IP 数据包被 V ** 程序通过字符设备接收,然后再通过一个 TCP 或者 UDP 隧道发送到右端的 V ** 服务器上,V** 服务器将隧道负载中的原始 IP 数据包写入字符设备,这些 IP 包就会出现在右侧的 Tun 虚拟设备上,最后通过操作系统协议栈和 socket 接口发送到右侧的应用程序上。
上图中的隧道也可以采用 Tap 虚拟设备实现。使用 Tap 的话,隧道的负载将是以太数据帧而不是 IP 数据包,而且还会传递 ARP 等广播数据包。
结合路由规则和 IPTables 规则,可以将 V ** 服务器端的主机作为连接外部网络的网关,以绕过防火墙对客户端的一些外部网络访问限制。如下图所示,防火墙规则允许客户端访问主机 IP2,而禁止访问其他 Internet 上的节点。通过采用 Tun 隧道,从防火墙角度只能看到被封装后的数据包,因此防火墙认为客户端只是在访问 IP2,会对数据进行放行。而 V ** 服务端在解包得到真实的访问目的后,会通过路由规则和 IPTables 规则将请求转发到真正的访问目的地上,然后再将真实目的地的响应 IP 数据包封装进隧道后原路返回给客户端,从而达到绕过防火墙限制的目的。
如下图所示,可以使用 tap 建立二层隧道将两个远程站点桥接起来,组成一个局域网。对于两边站点中的主机来说,访问对方站点的主机和本地站点的主机的方式没有区别,都处于一个局域网 192.168.0.0/24 中。
V** 主机上有两个物理网卡,其中 Eth0 用于和对方站点的 V ** 主机进行通信,建立隧道。Eth1 在通过网线连接到以太网交换机的同时也被则加入了 Linux Bridge,这相当于用一条网线将 Linux Bridge 上的一个端口(Eth1)连接到了本地站点的以太网交换机上,Eth1 上收到的所有数据包都会被发送到 Linux Bridge 上,Linux Bridge 发给 Eth1 的数据包也会被发送到以太网交换机上。Linux Bridge 上还有一个 Tap 虚拟网卡,用于 V ** 程序接收从 Linux Bridge 上收到的数据包。
假设 192.168.0.5 发出了一个对 192.168.0.3 的 ARP 请求,该 ARP 请求在网络中经过的路径如下:
192.168.0.5 发出 ARP 请求,询问 192.168.0.3 的 MAC 地址。
该 ARP 请求将被发送到以太网交换机上。
以太网交换机对该请求进行泛洪,发送到其包括 Eth1 在内的所有端口上。
由于 Eth1 被加入了 V ** 主机上的 Linux Bridge,因此 Linux Bridge 收到该 ARP 请求。
Linux Bridge 对该 ARP 请求进行泛洪,发送到连到其上面的 Tap 虚拟网卡上。
V** 程序通过 /dev/net/tun 字符设备读取到该 ARP 请求,然后封装到 TCP/UDP 包中,发送到对端站点的 V ** 主机。
对端站点的 V ** 程序通过监听 TCP/UDP 端口接收到封装的 ARP 请求,将 ARP 请求通过 /dev/net/tun 字符设备写入到 Tap 设备中。
Linux Bridge 泛洪,将 ARP 请求发送往 Eth1,由于 Eth1 连接到了以太网交换机上,以太网交换机接收到了该 ARP 请求。
以太网交换机进行泛洪,将 ARP 请求发送给了包括 192.168.0.3 的所有主机。
192.168.0.3 收到了 APR 请求,判断 iP 地址和自己相同,对此请求进行响应。
同理,ARP 响应包也可以按照该路径返回到图左边包括 192.168.0.5 在内的站点中。
从站点主机的角度来看,上面图中两个 V ** 主机之间的远程连接可以看作一条虚拟的网线,这条网线将两个 Linux Bridge 连接起来。这两个 Linux Bridge 和两个以太网交换机一起将左右两个站点的主机连接在一起,形成了一个局域网。