Linux tun 设备介绍
tun
是一种虚拟的 3 层虚拟网络设备,同时它也是一个字符设备,字符设备意味着可以把它当做一个文件,可以使用文件 API
操作这个设备,例如 open/read/write
,由于它同时也是一个网络设备,所以它也可以像一个网卡一样,从内核网络协议栈中收发报文。所以从它架构上来看,tun
设备的一端连接着应用程序,一端连接着网络协议栈,如下图所示:

从在系统中的表象来看,字符设备的文件类型是 c
,没有大小,但是有主次版本号:
1 | $ ls -alh /dev/net/tun |
tun
设备的创建是通过打开 /dev/net/tun
这个文件,然后使用 ioctl
系统调用对其进行 clone
。也可以使用 ip
命令来实现 tun
设备的创建:
ip tuntap add dev tun1 mod tun
新创建的 tun1
设备位于 /sys/class/net/
目录中:
1 | $ ll /sys/class/net/tun1 |
删除使用如下命令:
ip tuntap del dev tun1 mod tun
ICMP
示例
如前文所述,tun
设备的使用需要打开 /dev/net/tun
并对其 clone
之后才能进行使用,所以通用的创建 tun
设备有如下的步骤:
1 | int tun_alloc(char *dev, int flags) |
创建 tun
设备需要是 root
的用户,或者该应用程序需要具有 CAP_NET_ADMIN
权限,/dev/net/tun
必须以读写方式打开,它是创建任何 tun/tap
虚拟接口的起点,因此也被称为克隆设备 (clone device
)。操作 (open()
) 后会返回一个文件描述符,但此时还无法与接口通信。下一步会使用一个特殊的 ioctl()
系统调用,该函数的入参为上一步得到的文件描述符,以及一个 TUNSETIFF
常数和一个指向描述虚拟接口的结构体指针。
tun_alloc
函数的两个参数中:
dev
:指的是创建的tun
设备的名称,如果*dev
为'\0'
,则内核会尝试使用第一个对应类型的可用的接口,例如从tun0
开始,如果tun0
存在就为tun1
;flags
:用于指定虚拟设备的类型,通常为IFF_TUN
或者IFF_TAP
,分别代表tun
或者tap
设备。除此之外,还有一个IFF_NO_PI
标志,可以与IFF_TUN
或IFF_TAP
配合使用。IFF_NO_PI
会告诉内核不需要提供报文信息,即告诉内核仅需要提供 "纯"IP
报文,不需要其他字节。否则 (不设置IFF_NO_PI
),会在报文开始处添加4
个额外的字节 (2
字节的标识和2
字节的协议);
如果要完整的处理到达 tun
设备的 ICMP
请求,需要手动回响应:
1 | int main() |
完整的示例程序如下所示:
点击展开
1 | #include <stdio.h> |
将完整的源代码保存成文件 tun.c
,使用如下的命令进行编译:
gcc -o taptun tun.c
打开终端运行编译生成的可执行程序 taptun
可执行程序。然后打开另外一个终端,查询创建的 tun0
设备:
1 | $ ifconfig tun0 |
这个时候的 tun0
还未设置 IP
地址,可以使用如下的命令进行设置并启用:
ip a a 10.1.1.2/24 dev tun0
ip l s tun0 up
再次查看该设备,可以看到 IP
地址已经设置,并且处于启用状态:
1 | $ ifconfig tun0 |
创建设置并且设置 IP
以后,可以看到操作系统会自动添加一条路由,表示发往 10.1.1.0/24
这个网段的所有报文都会经 tun0
设备发出:
1 | $ route -n |
所以只要 ping
这个网段内的任一 IP
都会到达 tun0
设备,并且被我们的 taptun
应用程序收到并处理,例如:
1 | $ ping -c 1 10.1.1.10 |
应用程序将会有如下的输出:
1 | $ ./taptun |
参考链接
- IP packets
- IPv4 - Packet Structure
- ICMP Explained and Packet Format
- https://juejin.cn/post/7057833934947614750
- https://blog.51cto.com/u_11299290/5107265
- https://ctimbai.github.io/2019/03/01/tech/net/vnet/ 基于 taptun 写一个 ICMP 程序 /
- https://www.zhengwenfeng.com/pages/143447/# 应用程序通过 tun 设备获取 ping 数据包
- https://lxd.me/a-simple-vpn-tunnel-with-tun-device-demo-and-some-basic-concepts
- https://www.rectcircle.cn/posts/linux-net-virual-05-tunnel/#tun-tap - 虚拟设备
- https://www.zhaohuabing.com/post/2020-02-24-linux-taptun/
- https://www.luozhiyun.com/archives/684
- https://blog.avdancedu.com/52f625ca/
- https://www.xzcoder.com/posts/network/05-simple-vpn.html# 程序测试