TUN/TAP虚拟网络设备为用户空间程序提供了网络数据包的发送和接收能力。他既可以当做点对点设备(TUN),也可以当做以太网设备(TAP)。
TUN/TAP虚拟网络设备的原理:
在Linux内核中添加了一个TUN/TAP虚拟网络设备的驱动程序和一个与之相关连的字符设备/dev/net/tun,字符设备tun作为用户空间和内核空间交换数据的接口。当内核将数据包发送到虚拟网络设备时,数据包被保存在设备相关的一个队列中,直到用户空间程序通过打开的字符设备tun的描述符读取时,它才会被拷贝到用户空间的缓冲区中,其效果就相当于,数据包直接发送到了用户空间。通过系统调用write发送数据包时其原理与此类似。
1、tun设备
TUN 设备是一种虚拟网络设备,通过此设备,程序可以方便地模拟网络行为。
TUN 模拟的是一个三层设备,也就是说,通过它可以处理来自网络层的数据,更通俗一点的说,通过它,我们可以处理 IP 数据包。
先来看看物理设备是如何工作的:
图中的 eth0 是主机已有的真实的网卡接口 (interface)。
网卡接口 eth0 所代表的真实网卡通过网线(wire)和外部网络相连,该物理网卡收到的数据包会经由接口 eth0 传递给内核的网络协议栈(Network Stack)。然后协议栈对这些数据包进行进一步的处理。
对于一些错误的数据包,协议栈可以选择丢弃;
对于不属于本机的数据包,协议栈可以选择转发;
而对于确实是传递给本机的数据包,而且该数据包确实被上层的应用所需要,协议栈会通过 Socket API 告知上层正在等待的应用程序。
下面看看 TUN 的工作方式:
我们知道,普通的网卡是通过网线来收发数据包的话,而 TUN 设备比较特殊,它通过一个设备文件(/dev/tunX)收发数据包。
如上图所示,tunX 和上面的 eth0 在逻辑上面是等价的, tunX 也代表了一个网络接口,虽然这个接口是系统通过软件所模拟出来的。
网卡接口 tunX 所代表的虚拟网卡通过文件 /dev/tunX 与我们的应用程序(App) 相连,应用程序每次使用 write 之类的系统调用将数据写入该文件,这些数据会以网络层数据包的形式,通过该虚拟网卡,经由网络接口 tunX 传递给网络协议栈。
同时该应用程序也可以通过 read 之类的系统调用,经由文件 /dev/tunX 读取到协议栈向 tunX 传递的所有数据包。
协议栈可以像操纵普通网卡一样来操纵 tunX 所代表的虚拟网卡:
比如,给 tunX 设定 IP 地址,设置路由,总之,在协议栈看来,tunX 所代表的网卡和其他普通的网卡区别不大,当然,硬要说区别,那还是有的,那就是 tunX 设备不存在 MAC 地址,这个很好理解,tunX 只模拟到了网络层,要 MAC地址没有任何意义。
如果是 tapX 的话,在协议栈的眼中,tapX 和真是网卡没有任何区别!!!!
示例:
Tun/Tap都是虚拟网卡,没有直接映射到物理网卡,是一种纯软件的实现。Tun是三层虚拟设备,能够处理三层即IP包,Tap是二层设备,能处理链路层网络包如以太网包。使用虚拟网络设备,可以实现隧道,如OpenVPN的实现。
上面的图中,左右两边分别为两台机器。一台有一块物理网卡配置了IP:172.16.1.11,这台机器的系统里有一个Tun(以Tun为例,不讲Tap了)设备,配置了IP:192.168.1.11; 另一台的一块物理网卡配置了IP:172.16.1.12,系统里有一个Tun设备并配置了IP:192.168.1.12。
左边Linux系统里有一个Application,绑定到端口地址为: 192.168.1.11:5000,右边Linux也有一个Application,绑定到端口地址为:192.168.1.12:5000,显然它们绑定的都是Tun设备的IP,接着它们就通过这两个地址通信了。
假设左边的Application要给右边的Application发送一个数据包,流程是这样的:
左边的Application并不知道什么虚拟网络设备,它只知道往"192.168.1.12:5000"这个地址发送,左边主机系统首先按正常的发包过程处理,比如判断目的主机是不是位于同一网段等等,然后数据包就在Linux的网络协议栈中穿行。Tun设备并不是真实的物理网卡,它不知道把数据包往哪里送,但是这些经过了Linux网络协议栈的数据可以从Tun设备的文件描述符中读取到,图中的“User Program”就是监听这个描述符等待读取数据的。这个“User Program”程序绑定的端口地址是:172.16.1.11:6000,每当它从Tun设备读到数据的时候,就把这些数据从物理网卡发送出去,目标地址是右边的:172.168.1.12:6000。
数据到达右边的系统,经过网络协议栈之后到达“User Program”应用进程,“User Program”将接收到的数据往Tun设备对应的文件描述符写入。对于Tun设备来说,“写入”就像是物理网卡接受到数据包一样,因此这些接收到的数据又进入了Linux的网络协议栈,最终到达右边的Application。
这里的Application是指各种各样的用户程序,如ping工具。“User Program”是用来辅助Tun设备来实现隧道功能的,可以想象成是OpenVPN进程,没有它隧道就废了!!!!
2、TAP设备
如图所示,当备一个 TAP 设被创建时,在 Linux 设备文件目录下将会生成一个对应 char 设备,用户程序可以像打开普通文件一样打开这个文件进行读写。
当执行write()操作时,数据进入 TAP 设备,此时对于 Linux 网络层来说,相当于 TAP 设备收到了一包数据,请求内核接受它,如同普通的物理网卡从外界收到一包数据一样,不同的是其实数据来自 Linux 上的一个用户程序。Linux 收到此数据后将根据网络配置进行后续处理,从而完成了用户程序向 Linux 内核网络层注入数据的功能。
当用户程序执行read()请求时,相当于向内核查询 TAP 设备上是否有需要被发送出去的数据,有的话取出到用户程序里,完成 TAP 设备的发送数据功能。
针对 TAP 设备的一个形象的比喻是:
使用 TAP 设备的应用程序相当于另外一台计算机,TAP 设备是本机的一个网卡,他们之间相互连接。应用程序通过 read()/write()操作,和本机网络核心进行通讯。
TAP 设备与 TUN 设备工作方式完全相同,区别在于:
1)TUN 设备是点对点的三层设备,处理IP分组,它只模拟到了 IP 层,即网络层 我们可以通过 /dev/tunX 文件收发 IP 层数据包,它无法与物理网卡做 bridge,但是可以通过三层交换(如 ip_forward)与物理网卡连通。可以使用ifconfig等命令给该设备设定 IP 地址。
2)TAP 设备是一个二层虚拟以太网设备,处理以太网帧,它比 TUN 更加深入,通过 /dev/tapX 文件可以收发 MAC 层数据包,即数据链路层,拥有 MAC 层功能,可以与物理网卡做 bridge,支持 MAC 层广播。同样的,我们也可以通过ifconfig等命令给该设备设定 IP 地址,还可以给它设定 MAC 地址。
3)
TAP:子网掩码是/24,255.255.255.0,对应以太网设备
TUN:子网掩码是/30,255.255.255.252,点对点设备。
4)设备节点号不同:
2.4的核:TUN 设备号是36 16+,文件节点:/dev/tun0
2.6的核:TUN 设备号是10 200,文件节点:/dev/net/tun
OSI模型中的七层:
第一层是物理层
第二层是数据链路层(tap设备)
第三层是网络层(tun设备)
第四层是传输层
第五层是会话层
第六层是表示层
第七层是应用层
3、VETH
VETH 设备出现较早,它的作用是反转通讯数据的方向,需要发送的数据会被转换成需要收到的数据,重新送入内核网络层进行处理,从而间接的完成数据的注入。
VETH 设备总是成对出现,送到一端请求发送的数据总是从另一端以请求接受的形式出现。
该设备不能被用户程序直接操作,但使用起来比较简单。创建并配置正确后,向其一端输入数据,VETH 会改变数据的方向并将其送入内核网络核心,完成数据的注入。在另一端能读到此数据