上周六晚上闲来无事跟以前的同事聊天,问之最近有没有接触到什么比较好玩的技术,答曰tun2socks。这个正合我的胃口,我所谓的好玩的技术是那种简单,有用的技术点或者技术框架,能在10分钟内领略其原理和思想,能在20分钟内跑起来,能在半天内彻底剖析它的结构,能在此后很久的时间受益无穷。OpenVPN就是这样的“好玩”的东西,网卡点灯也算,tun2socks是另一个,当然还有一个更好玩的,那就是BadVPN,我要在另外的文章中单独介绍。本文先来介绍tun2socks,它其实是BadVPN的一个组成部分。
能玩tun2socks,要特别感谢这位目前貌似已经穿上皮鞋的刘经理,在我离职后抢了我最后面的经理工位,却放弃了我那把尊贵的防爆炸座椅(指不能旋转升降的座椅,因为旋转升降座椅会爆炸)。
总览
tun2socks实现一种机制,它可以让你无需改动任何应用程序而完全透明地将数据用socks协议封装,转发给一个socks代理,然后由该代理程序负责与真实服务器之间转发应用数据。使用代理有两种方式,一种是你自己显式配置代理,这样一来,数据离开你的主机时它的目标地址就是代理服务器,另一种是做透明代理,即在中途把原始数据重定向到一个应用程序,由该代理程序代理转发。tun2socks在第二种的基础上,完成了socks协议的封装,并且实现该机制时使用了强大的tun网卡而不必再去配置复杂的iptables规则。
什么是socks代理
本文以TCP为例,就不再提UDP了。所以说,简单点,把socks代理称为带有认证功能的TCP代理是合适的。
TCP代理非常容易理解,然而纯粹的TCP代理并不实用,必然要加入一些控制功能,比如谁可以被代理,谁不能被代理,如何认证,最多可以代理多少路的请求等等。有了这些控制手段,TCP代理才真正变得实用起来。
附:socks代理如何运作
socks的运作原理非常简单,就是在TCP数据外包一层socks协议头,到达socks代理服务器后,脱去socks头,然后通过socks服务器与真实服务器之间建立的连接将TCP裸数据传给真实服务器。如下图所示:
请注意,socks代理并不理解任何应用层协议,它只是负责转发应用层数据而已,这一点使socks成为了一个通用的代理协议,这一点和HTTP代理服务器是完全不同的。
什么是tun网卡
这个就不再多说。之所以有这个小节是为了文章的完整性。也是为了给初学者一个完整的提纲来更深入的学习。
什么是透明代理
我理解的透明代理就是“偷偷的给你做代理”,这一点与你在浏览器里显式设置socks代理服务器完全不同。透明代理就比如说下面这样子:
要实现这一点有很多方式,比如你可以用Linux的TProxy+Policy routing机制,关于这种方式请参见《socket的IP_TRANSPARENT选项实现代理》,然而,很多时候,这种方式行不通。
现实中的需求
如果给一个Linux的root账户,那么几乎可以随意显摆,而很多时候这并不可能。比如Android系统就不能随意root,这就意味着你无法在Android系统上随意地配置iptables规则,路由等。那么想在Android系统上免root实现一个透明代理,就需要别的办法。而tun2socks提供了一种这样的办法。
tun2socks能做什么
如果理解了上述所有的概念,那么tun2socks就不剩下什么了。先给出一个总览图:
通过上图,我们看到tun2socks可以被拆解出三个部分,即tun网卡部分,协议处理部分以及socks转换部分,这三部分在tun2socks的处理流程是串行的。我来一个一个说。
1.tun网卡部分
该部分解决了一个基本的问题,即“如何获取原始的数据包”。拿到了数据包,什么都好办了。
2.协议处理部分
如果你想做透明代理,那么你必须“想办法把数据流导入到本地”,完成这件事有好多种办法,以Linux为例,比如做一个DNAT即可完成,再比如如上所述,用tun网卡直接把原始数据包捕获到一个应用程序。显然tun2socks采用了后者。
两者有何不同呢?
很大的不同。如果使用DNAT的话,目标地址和端口将会是本地的一个代理程序,比如socks代理,那么操作系统的协议栈会自动将数据包交到该代理程序,除了这个DNAT之外不需要再做任何操作。而使用tun捕获数据包的话,由于只是捕获到了IP数据报文,这意味着你要自己处理IP层以上的逻辑,比如TCP按序交付,TCP状态处理,TCP拥塞控制,你要确保代理程序收到的数据包看起来是“经过协议栈处理过的数据包”,“就像是直接从socket的recv接口读到的一样”。
tun2socks使用现成的lwip来完成了协议处理。lwip是一个轻量级的用户态协议栈,非常适合完成这种协议适配工作。
附:Android系统使用TAP模式的tun网卡
说起lwip来处理tun捕获的原始IP数据报文与socks协议的适配工作,我想起了很早之前我也做过同样的事情。那就是在Android系统上使用TAP模式的tun网卡。
3.socks协议转换部分
经过第2部分,即协议处理之后,现在tun2socks拿到的已经是源主机试图发送到原始目标主机的裸数据了,接下来它可以做的事情可就多了,当然可以用socks协议封装裸数据,将其发送给一个socks代理程序。
tun2socks与OpenVPN
只要是使用了tun网卡获取原始数据,那么任何框架都会面临一个必须回答的问题,即拿到原始的IP数据报文或者以太帧之后,下一步如何处理这些数据。OpenVPN和tun2socks显然是给出了两种不同的回答,而这不同的回答即是OpenVPN和tun2socks之间唯一的不同。
后记
这篇文章的最初内容来自于刘经理,我只是做了补充。然而沿着这个tun2socks一路走下去,我发现了一个十分好玩的东西,那就是BadVPN,所以我准备写一篇关于BadVPN的文章了,请注意接收。