当前位置:网站首页>TUN 设备原理

TUN 设备原理

2022-04-23 14:11:00 Mrpre

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就能获取到响应数据。

版权声明
本文为[Mrpre]所创,转载请带上原文链接,感谢
https://wonderful.blog.csdn.net/article/details/113105456