TUN & TAP

是什么?

tap 和 tun 都是虚拟网络内核接口,在创建网络连接方面起着至关重要的作用,在 Linux Kernel 2.4.x 版本后实现。

Tap(也称为以太网分流器)是在 OSI 模型的第 2 层运行的虚拟网络接口。它可用于将虚拟机、容器或其他网络设备连接到物理网络。Tap 接口通常用于桥接网络。

Tun 是 Tunnel 的缩写,是在 OSI 模型的第 3 层运行的虚拟网络接口。与 tap 接口不同,tun 用于点对点网络连接,通常用于 VPN(虚拟专用网络)实施。

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

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

当应用程序打开设备文件时,驱动程序就会创建并注册相应的虚拟设备接口,一般以 tunXtapX 命名。当应用程序关闭文件时,驱动也会自动删除 tunXtapX 设备,还会删除已经建立起来的路由等信息。

怎么用?

tap

1
2
3
4
5
6
# 创建
sudo ip tuntap add tap0 mode tap
# 查看
sudo ip link set tap0 up
# 分配 ip 地址
sudo ip addr add 192.168.0.1/24 dev tap0

tun

1
2
3
4
5
6
# 创建
sudo ip tuntap add tun0 mode tun
# 启动
sudo ip link set tun0 up
# 分配 ip 地址
sudo ip addr add 10.0.0.1/24 dev tun0

用 Golang 调用

注意,这里使用 github.com/songgao/water

通过文件字符设备读数据实验

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package main

import (
	"os"
	"os/signal"
	"syscall"

	"github.com/fatih/color"
	"github.com/songgao/water"
	flag "github.com/spf13/pflag"
)

var (
	tunName        = flag.String("dev", "", "local tun device name")
)

func main() {
	flag.Parse()

	// create tun/tap interface
	iface, err := water.New(water.Config{
		DeviceType: water.TUN,
	})
	if err != nil {
		color.Red("create tun device failed,error: %v", err)
		return
	}

	// 起一个协程去读取数据
	go IfaceRead(iface)

	sig := make(chan os.Signal, 3)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGABRT, syscall.SIGHUP)
	<-sig
}

/*
	IfaceRead 从 tun 设备读取数据
*/
func IfaceRead(iface *water.Interface) {
	packet := make([]byte, 2048)
	for {
		// 不断从 tun 设备读取数据
		n, err := iface.Read(packet)
		if err != nil {
			color.Red("READ: read from tun failed")
			break
		}
		// 在这里你可以对拿到的数据包做一些数据,比如加密。这里只对其进行简单的打印
		color.Cyan("get data from tun: %v", packet[:n])
	}
}

通过文件字符设备写数据实验

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func IfaceReadAndWrite(iface *water.Interface) {
	packet := make([]byte, 2048)
	for {
		// 不断从 tun 设备读取数据
		n, err := iface.Read(packet)
		if err != nil {
			color.Red("READ: read from tun failed")
			break
		}

		// 再把数据原封不动写入 tun 设备
		_,err= iface.Write(packet[:n])
		if err != nil {
			color.Red("WRITE: write to tun failed")
			break
		}
	}
}

Tap/Tun 的区别

tun、tap 作为虚拟网卡,除了不具备物理网卡的硬件功能外,它们和物理网卡的功能是一样的,此外tun、tap负责在内核网络协议栈和用户空间之间传输数据。

tuntap 都是虚拟网卡设备,但是:

  • tun 是三层设备,其封装的外层是 IP
  • tap 是二层设备,其封装的外层是以太网帧(frame)
  • tunPPP 点对点设备,没有 MAC 地址
  • tap 是以太网设备,有 MAC 地址
  • taptun 更接近于物理网卡,可以认为,tap设备等价于去掉了硬件功能的物理网卡

参考

Tap vs Tun: A Comprehensive Guide

Tun Tap and Veth for Fun

Linux虚拟网络设备之tun/tap

Licensed under CC BY-NC-SA 4.0
本文阅读量 次, 总访问量 ,总访客数
Built with Hugo .   Theme Stack designed by Jimmy