TUN 设备原理

TUN 设备原理

本文要阐述的就是 sslvpn 的运行机制。对其问题进行技术上的细化,就是要解决两个被公网环境独立开的私网,如何建立通道。核心细节就是tun设备。TUN设备还被用来在flannel中,作为跨宿主机容器间网络通信。

simpletun

首先玩一下简单的例子 https://github.com/gregnietsky/simpletun.git 然后有个直观的感受

我们找2台机器 分别使用make命令编译上述代码,生成 二进制 simpletun

A物理ip 11.238.116.73
B物理ip 11.238.116.75

在B机器上执行

sudo ./simpletun -i tun90 -s -d  &
sudo ifconfig tun90 6.6.6.2/24

在A机器上执行

sudo ./simpletun -i tun90 -c 11.238.116.75 -d &
sudo ifconfig tun90 6.6.6.1/24

simpletun 二进制会帮助生成一个叫做 tun90的虚拟网卡,然后我们使用ifconfig来进行ip地址的分配
其次,B机器上,通过-s告诉simpletun 监听 本机TCP 的 55555 端口,并且作为服务端;A机器上通过-c命令附加B的物理ip。

启动完成之后,在A机器上执行ping 6.6.6.2会出现如下日志,部分日志是ping的输出,表示ping成功,部分是simpletun打印的日志。

PING 6.6.6.2 (6.6.6.2) 56(84) bytes of data.
TAP2NET 4: Read 84 bytes from the tap interface
TAP2NET 4: Written 84 bytes to the network
NET2TAP 4: Read 84 bytes from the network
NET2TAP 4: Written 84 bytes to the tap interface
64 bytes from 6.6.6.2: icmp_seq=1 ttl=64 time=39.7 ms
TAP2NET 5: Read 84 bytes from the tap interface
TAP2NET 5: Written 84 bytes to the network
NET2TAP 5: Read 84 bytes from the network
NET2TAP 5: Written 84 bytes to the tap interface
64 bytes from 6.6.6.2: icmp_seq=2 ttl=64 time=39.9 ms

同样的,我们在B上面执行nc -l -k 9090监听 本机9090端口程序,然后再A上面执行nc 6.6.6.2 9090后敲入abc

A的输出
$nc 6.6.6.2 9090
TAP2NET 12: Read 60 bytes from the tap interface
TAP2NET 12: Written 60 bytes to the network
NET2TAP 11: Read 60 bytes from the network
NET2TAP 11: Written 60 bytes to the tap interface
TAP2NET 13: Read 52 bytes from the tap interface
TAP2NET 13: Written 52 bytes to the network
abc
TAP2NET 14: Read 56 bytes from the tap interface
TAP2NET 14: Written 56 bytes to the network
NET2TAP 12: Read 52 bytes from the network
NET2TAP 12: Written 52 bytes to the tap interface

B的输出
NET2TAP 12: Read 60 bytes from the network
NET2TAP 12: Written 60 bytes to the tap interface
TAP2NET 11: Read 60 bytes from the tap interface
TAP2NET 11: Written 60 bytes to the network
NET2TAP 13: Read 52 bytes from the network
NET2TAP 13: Written 52 bytes to the tap interface
NET2TAP 14: Read 56 bytes from the network
NET2TAP 14: Written 56 bytes to the tap interface
TAP2NET 12: Read 52 bytes from the tap interface
TAP2NET 12: Written 52 bytes to the network
abc

我们发现,A机器通过tcp 访问 6.6.6.2的9090端口,这个6.6.6.0/24相当于私网请求,而 A和B之间的网路根本没有6.6.6.0/24网段的路由,那么 B如何收到到A发送的私网请求呢,这当然是我们本文需要解释的疑惑。

TUN设备特性

对于 tun 设备的write操作(open tun,然后对fd进行write),tun在内核态获取到用户态数据后,调用netif_rx,通常情况下,netif_rx这个函数只有在机器收到报文是调用提交给协议栈,说明我们对tun设备的write操作,相当于让机器模拟收包。所以很关键的一点就是,tunwrite的数据必须要包含三次协议头(IP),否则linux协议栈无法将其路由。

对于 tun 设备的获取数据操作,首先tun设备在什么情况下,会获取到数据呢?即当我们在外部应用程序毫无感知tun设备存在的情况下,tun设备是如何获取到外部程序的数据的。

首先tun设备是有三层ip地址的,也就是意味着,tun设备可以被作为三层转发接口发送数据,我们只需要让 外部程序 发出的请求,被路由到tun设备即可。例如 我们访问200.100.1.1这个公网地址走tun设备,route add -net 200.100.1.1/32 dev tun90,这样请求就会走tun口出去。

然后 tun设备的 驱动程序 和 常规的类似eth不同,它不会真的将数据从自己接口发出去。

tun设备的发送接口,做的操作是将 数据 保存下来放到自己的list上,然后通知监听tun设备的用户程序进行读取。

所以想要TUN拦截到数据,那么需要应用程序的目的地址,能从TUN设备口“出去”,配置一条路由就是常见的操作。

注意 tun设备获取到的数据,时携带三层头的数据。

TUN 实践

上解讲了TUN设备的特性,所有的特性均是TUN的字符驱动和设备驱动实现,我们结合这个特性,就能做出一个简单的私网穿越功能,也就是开头 simpletun 的功能

在这里插入图片描述

请求发送

1、应用程序发送数据,例如ping到 6.6.6.2,因为本机配置的路由等规则,数据被linux内核路由到 tun90进行发送。

2、tun90 获取到数据后,不会进行真的发送操作,,而是封装成三层报文,然后放到自己队列里面,等待用户程序进行读取,这就是tun设备的特性。
此时 tun client会获取到数据。数据是包含三层头的的数据,其中源ip是 tun设备的6.6.6.1 目的地址是应用程序访问的目的地址 6.6.6.2。

3、tun client 将 这个包含三层头的数据,通过公网发送,自然 这个公网上的五元组是本机物理地址以及目的物理地址,自然这个报文能够通过公网发送。

4、tun server 收到 数据,这个数据就是 上一步2中的数据,包含了6.6.6.1->6.6.6.2这个三层头的数据,tun server写到tun设备。

5、tun90 收到用户的write操作之后,会将数据扔到linux协议栈,linux协议栈就去解析 6.6.6.1->6.6.6.2这个三层头的数据怎么转发,自然 6.6.6.2 是自己本机地址,自然能处理。

注意 1 的发送,实际是 tun设备的xmit发送,4的write实际是tun设备的receive,是不一样的。

本例只是以PING为例子。如果 物理机A 的 应用程序 访问的是 一个 公网的地址,例如100.100.100.100,那么,物理机B如果在开启了ip_forward并且自己和100.100.100.100通,那么,这个请求就被转发到了100.100.100.100,开启nat的情况下,会向公网发出 11.238.116.75 -> 100.100.100.100 的请求,响应数据 100.100.100.100->11.238.116.75 回来后依靠nat还原成100.100.100.100->6.6.6.1。

数据响应
回包的也很有意思

6、假设 机器B要回复 6.6.6.1->6.6.6.2 PING对应的 响应包,那么机器B的回复响应的IP头是 6.6.6.2->6.6.6.1,这个包会被路由机器的tun90,这个过程相当于上述发送过程的1,tun90拦截到这个包之后,期待 tun server将其读取。

7、tun server探测到tun设备有数据,于是就读取数据,数据是包含6.6.6.2->6.6.6.1这个ip头的数据。

8、tun server 使用 tun client建立的通道,将数据通过公网传输至client。

9、tun client 将数据写入到 机器A的tun。

10、根据 tun 特性,tun 机会将 包含 6.6.6.2->6.6.6.1这个ip头的数据 的数据扔会协议栈,linux 就能 这样,外部执行的ping就能获取到响应数据。

Linux TUN/TAP设备是一种虚拟网络设备,它能够模拟一个网络接口。通过TUN/TAP设备,用户空间的程序可以像操作物理网络设备一样,发送和接收网络数据包。 TUN/TAP设备主要有两种模式:TUN模式和TAP模式。TUN模式主要用于IP层协议,TAP模式主要用于以太网层协议。两种模式的差异在于数据包的处理方式不同。 在Linux内核中,TUN/TAP设备的实现位于`drivers/net/tun.c`文件中。该文件中定义了一个名为`tun_net`的网络设备对象,并实现了`tun_chr_write_iter()`、`tun_chr_read_iter()`等函数,用于处理用户空间和内核空间之间的数据交互。 当用户空间的程序打开TUN/TAP设备时,会创建一个名为`tunX`的虚拟接口,其中`X`是一个数字,表示设备的编号。内核会将数据包发送到该虚拟接口,然后用户空间的程序可以通过读取该接口的文件描述符来接收数据包。同样地,用户空间的程序可以通过写入该接口的文件描述符来发送数据包。 TUN/TAP设备的实现使用了内核中的网络协议栈,因此它能够与其他网络设备无缝交互。用户空间的程序可以使用标准的套接字接口来与TUN/TAP设备进行通信,实现虚拟网络设备和物理网络设备之间的数据交换。 总之,TUN/TAP设备是一个非常有用的工具,它可以用于各种网络应用程序,如虚拟私有网络(VPN)和网络隧道。通过了解TUN/TAP设备的实现,我们可以更好地理解网络协议栈和Linux内核的工作原理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值