前言

这篇文章的目的,是以一种泛泛而谈、点到为止的方式介绍一些网络协议的 tunnel 技术,以及 tunnel 在 Kubernetes 网络模型中的应用。它基本不具备什么可操作性的东西,感兴趣的读者应当进一步地阅读 RFC 以获得更加清晰的知识,同时本篇文章因为缺少来源引用以及作者水平有限,可能存在一些错误在所难免。

什么是透明代理 (transparent proxy)? 透明代理指的是一个人工特意制造的软件运行环境,运行在此环境上的应用程序所收发的网络流量能够被环境自动拦截和处理,而不需要对应用程序本身进行额外的手动配置。

举例来说,进入 Firefox 浏览器的设置页面,将它的 proxy 设置为启用并且将 http proxy 设置为特定地址,这算不算是透明代理?不算,因为对应用程序做了额外配置,且不是无感的,firefox 肯定知道自己的 proxy 功能被启用了。在操作系统的全局代理设置页面进行设置,算不算是透明代理?不算,因为一些应用程序可能不尊重操作系统的全局代理设置。

然而假如用户启用了 VPN 并且通过 VPN 连接到企业内网,那么这时浏览器,以及操作系统上运行的其它应用程序的流量默认情况下就会走这条 VPN 线路,并且不需要经过额外设置,对于应用程序来说也是无感的,因此这算是一种透明代理。这说明,VPN 可以看做是透明代理的一个特例或者实例,虽然不能划上等号。

在本文中,我们参照 OSI 7 层模型,介绍适用于其中几个 layer 的透明代理运行原理,以及它们分别适用的协议。从某种程度上来说,tunnel 和透明代理具备相似的性质,因此在本文中,这两个术语可能会交叉着使用。

Layer 7 透明代理

Layer 7 透明代理作用于工作在应用层的,使用特定应用层协议进行通信的应用程序,同样地,按照本文开头的透明代理的定义,应当不需要对应用程序做手动配置(例如更改它的代码或者修改它的配置文件、命令行参数等),就能截获或者转发它的应用层协议流量。

在某些操作系统/环境上,可以在设置页面设置系统代理来实现,但这并不通用,例如,在 IOS 的 WiFi 设置页面,可以设置代理服务器的地址,这时手机上的所有 App 就会默认使用这个代理,所以这算是一种在 IOS 操作系统上的透明代理,但是在 macOS 上则不成立,因为这样的设置几乎只对一部分图形界面的应用程序生效,相反,命令行界面的应用程序,大概率不会尊重这个系统设置。

但是大部分工作在应用层的应用程序都需要调用操作系统提供的接口进行域名解析,以此将 DNS Label 转化为 32 位整型的 IPv4 地址或者 128 位整形的 IPv6 地址(也就是应用层地址到网络层地址的转换),因此我们可以通过劫持应用程序调用的 DNS 服务,来实现应用层特定网络协议的透明代理。

接下来我们描述、定以 4 个 docker container,各自扮演不同的角色,提供不同的功能和服务,分别是:

  1. web, 提供 http 服务;
  2. proxy, 提供 socks_proxy 服务;
  3. dns-server, 提供 dns 服务,将针对它自己的 DNS 请求解析为它自己的 IP 地址,将其余所有 DNS 请求地址解析为它自己的域名(CNAME);
  4. client, 模拟用户行为,测试 HTTP 连接是否最终由 proxy 转发。

我们将 client 的 DNS resolver 地址设置为 dns-server 的 IP 地址,这是可以做到的,因为 client 会在 1,2,3 之后才被创建,而到了那时 dns-server 的 IP 地址已知。

现在 client 发出一个普通的 HTTP 请求:curl <http://web>, 下列事件会依次发生:

  1. curl 会尝试解析 web 的 IP 地址,DNS 请求被发送至 dns-server;
  2. dns-server 返回一个 CNAME 指向它自己,这相当于表示: 「web 只不过是 dns-server 的别名,所以你 curl 还需要去请求 dns-server 的地址」;