[Linux] 网络中的 `tun` 模式

引言

在网络编程和虚拟化技术中,tun 模式是一个非常重要的概念。

它通常用于实现虚拟网络设备,广泛应用于 VPN、容器网络、虚拟化环境等场景。

(VPN(虚拟专用网络)就像一条加密的"秘密通道",让你在公共网络上安全地访问私有网络资源,就像在家里的局域网一样安全)

本文将详细介绍 tun 模式的工作原理、应用场景以及它与 tap 模式的区别。

什么是 tun 模式?

tun(全称 Network TUNnel)是 Linux 内核提供的一种虚拟网络设备,工作在网络层(IP 层)。

它模拟了一个点对点的网络设备,可以用于传输 IP 数据包。与物理网卡不同,tun 设备并不直接处理链路层(如以太网帧),而是专注于 IP 数据包的传输。

特性

  1. 工作在 IP 层 :tun 设备只处理 IP 数据包,不涉及 MAC 地址或以太网帧。
  2. 点对点通信 :tun 设备通常用于两个端点之间的通信,类似于 VPN 中的隧道。
  3. 用户空间驱动 :tun 设备的数据包由用户空间的程序处理,而不是内核协议栈。

tun 模式的工作原理

tun 设备的核心功能是将内核生成的 IP 数据包传递给用户空间的程序,或者将用户空间的 IP 数据包注入内核协议栈。以下是其工作流程:

  1. 数据包从内核到用户空间:

    • 当内核需要发送一个 IP 数据包时,如果目标地址指向 tun 设备,数据包会被传递到用户空间的程序。
    • 用户空间的程序可以对这些数据包进行加密、封装或其他处理。
  2. 数据包从用户空间到内核:

    • 用户空间的程序可以将处理后的 IP 数据包写入 tun 设备。
    • 内核会将这些数据包视为从外部接收的 IP 数据包,并进行路由或转发。

示例

以下是一个简单的 tun 设备创建和使用的代码片段(C 语言):

c 复制代码
#include <fcntl.h>
#include <linux/if_tun.h>
#include <sys/ioctl.h>

int tun_alloc(char *dev) {
    struct ifreq ifr;
    int fd, err;

    if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
        perror("Opening /dev/net/tun");
        return fd;
    }

    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
    strncpy(ifr.ifr_name, dev, IFNAMSIZ);

    if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) {
        close(fd);
        perror("ioctl(TUNSETIFF)");
        return err;
    }

    return fd;
}

code:https://github.com/lvy010/linux-core

代码实现了一个名为tun_alloc的函数,用于在Linux系统中创建和配置TUN虚拟网络设备。

TUN设备属于操作系统内核中的虚拟网络接口,常用于实现VPN、隧道协议或网络层数据包处理。

解析

头文件引入

  • <fcntl.h>:提供文件控制相关函数(如open)和标志(如O_RDWR)。
  • <linux/if_tun.h>:定义TUN/TAP设备的常量(如IFF_TUN)和结构体(如ifreq)。
  • <sys/ioctl.h>:声明ioctl系统调用,用于设备配置。

函数参数

  • char *dev:指定要创建的TUN设备名称(如"tun0"),若为空则由内核自动分配。

核心流程

  1. 打开设备文件

    c 复制代码
    fd = open("/dev/net/tun", O_RDWR);

    以读写模式打开Linux的TUN设备控制文件,失败时返回负值并打印错误。

  2. 初始化结构体

    c 复制代码
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
    strncpy(ifr.ifr_name, dev, IFNAMSIZ);
    • ifreq结构体清零后设置标志位:
      • IFF_TUN:创建三层(IP层)设备(区别于二层的IFF_TAP)。
      • IFF_NO_PI:禁用数据包信息头(Packet Information)。
    • 将用户指定的设备名复制到结构体中(最多IFNAMSIZ字符)。
  3. 配置设备

    c 复制代码
    ioctl(fd, TUNSETIFF, &ifr);

    通过TUNSETIFF命令绑定设备:

    • 若dev名称已存在则关联现有设备。
    • 若名称为空或未使用则创建新设备,内核可能修改ifr.ifr_name为实际名称。
  4. 错误处理

    失败时关闭文件描述符并返回错误码,成功则返回可用于读写数据的文件描述符。

应用场景

  • 读取fd可获取其他主机发送到该TUN设备的IP数据包。
  • 写入fd可模拟从该TUN设备发出的IP数据包。
  • 需结合route或iptables配置路由才能使设备正常工作。

详见code: https://github.com/lvy010/linux-core/tree/main/tun_test

运行测试:

安全注意事项

  • 需要CAP_NET_ADMIN权限或root用户身份执行。
  • 设备名称长度不应超过IFNAMSIZ(通常为16字节),strncpy确保不会缓冲区溢出。

扩展说明

返回的文件描述符后续可通过read/write或poll/select进行数据操作,每个读操作返回一个完整的IP数据包(因设置了IFF_NO_PI,无额外头部信息)。

tun 模式的应用场景

1. VPN(虚拟专用网络)

VPN 是 tun 模式最典型的应用之一。例如,OpenVPN 默认使用 tun 模式来建立安全的点对点隧道。用户空间的 VPN 程序通过 tun 设备接收和发送加密的 IP 数据包。

2. 容器网络

在容器化技术(如 Docker、Kubernetes)中,tun 设备可以用于实现容器之间的网络隔离和通信。例如,Flannel 的 VXLAN 后端就使用了 tun 设备。

3. 网络测试和调试

tun 设备可以用于模拟网络环境,方便开发者测试网络协议或调试网络问题。

tun 与 tap 的区别

特性 tun 模式 tap 模式
工作层次 网络层(IP 数据包) 链路层(以太网帧)
典型应用 VPN、点对点隧道 虚拟机网络、桥接网络
数据包类型 IP 数据包 以太网帧
用户空间 处理 IP 数据包 处理以太网帧

总结

tun 模式是网络编程中一个强大而灵活的工具,特别适合需要处理 IP 层数据的场景。通过用户空间的程序,开发者可以轻松实现加密、隧道、网络隔离等功能。理解 tun 模式的工作原理和应用场景,有助于更好地设计和优化网络架构。