vpn翻墙app 安卓
经过2个月的开发,我的http代理可以说没有遗憾了,当然还有可以改进的地方,比如多用户认证啥的,但是没有必要啦。
为了在安卓上也能愉快地使用自己开发的代理,研究了一下安卓Vpnservice,在此记录一下当前的进度,并确定以后的开发思路。
1:vpn和各种自定义的vpn;它们是把iOS的ip数据包的内容通过一个tcp转发到vpn服务器,然后在服务器上创建一个tun虚拟网卡,再把接收到的ip数据包内容通过系统的函数发给网卡,然后网卡再把这个原始的ip数据包内容加上自己的ip地址等信息发送出去,对方接收到数据之后,解析出来,在ip之上的内容是没有改变的,所以tcp的连接之类的整个过程是不会影响的,只是在返回数据时,它识别到的源ip地址变成了服务器上虚拟网卡的地址;
2:http代理,现在主流的系统都支持设置http代理;它们的原理是客户端系统在发送http请求时,并不是把数据包发给真正的目的地址,而是与代理服务器创建一个tcp连接,把http包发送给代理服务器,这样代理服务器就可以接收到一个http请求,然后再从请求中得到真正的目的地址,把这个请求转发给目的ip,所以从服务器上来看,就是一个最基本的http服务器而已,只是它的目的从处理请求变成了转发请求;整个请求过程中,在http层上的内容不会改变,但是在tcp这一层会改变;对于客户端操作系统来说,在发送http之前,我们要先与目的地建立连接,但是操作系统并不知道我们是不是用来发送http的,所以它就不能让我们去连接代理服务器,由此可知,http代理的客户端处理不会是操作系统来提供,而是应该上层应用程序来提供;比如提供一个发送http的函数,那么在这个函数中,我们就可以知道它肯定是用来发http的,就可以去连接代理服务器而不是直接的目标服务器;这就解释了为什么有些http请求不走代理(比如libcurl创建的http请求,大部分的linux终端命令),因为这要库去支持,不过现在主流的浏览器都支持;
3:socks5代理,socks5代理中,客户端与代理服务器tcp连接上后,客户端会向代理服务器发送协商数据和真正的目标地址,代理服务器就与直接的目标地址连接,然后再把后续的请求转发到目标地址上;相对于http代理来说,socks5代理不区分上层协议,所以可以在系统库中去实现;
翻墙原理上是这几个基本的方法,vpn的ip数据转发,http代理的http数据转发,sock5代理的tcp,udp数据转发。
但是由于这几种方式都有它的明确的特征和易于识别,比如vpn,sock5代理特征明显,http代理数据明文可见,导致了用来翻墙不稳定(当然自定义vpn可以解决这个问题);
ShadowSocks的优点为sock5代理类似,由于不是在ip层面上,所以数据包相对来说要小(不用传ip数据包头与tcp数据包头,所有理论上它要快一些)
所以现在大家都在用ShadowSocks,在pc端它的实现比较简单,因为它只要在本地实现一个sockt5代理服务器就好了,这样在sock5代理服务器内部,就能得到tcp数据的内容,把内容通过自己的协议转发到远程服务器,让远程服务器转发tcp的内容;相当于本地和服务器上两边实现了类似的socket5代理;
但是对于iOS,android而言,sock5代理在非越狱和root的情况下不被支持,不过能得到ip数据包,所以要想办法把ip数据包转成tcp/udp的包,这样才能分析出tcp/udp中的内容进行转发;
这里引入一个开源的tcp/ip协议栈,它简单占用内存小,所以能运行在移动设备上,我们要的是让它接收系统的ip数据包,分析出tcp/udp数据内容。但是对于标准的tcp/ip协议栈,由于系统的ip数据包发送的目的地与这个协议栈运行的地址,所以正常情况下它是不会被解析出来的,不过由于这个协议栈相对来说简单,所以我们可以进行改造,让它不管是去哪里的ip数据包,都像本来就是发送给他的一样;这样它能accept 发给其它地址的tcp的连接,可以直接读取tcp连接之后的发送的内容;这也就是为什么叫tun2socks了(改造的过程其实很简单,只是把在tcp段组成tcp时的ip和port限制去掉就行了),并且由于它能让我们得到tcp发送的数据包,这样就不用另一个socks代理了。
我写的HttpProxy就是一个http代理(tcp代理),而安卓、iphone要求的是一个VPN(因为手机只给ip数据报)。socks则是不管应用层是tcp还是udp。所以从通用性上讲,VPNsockstcp代理。我的HttpProxy在这个时代可以说超级菜鸡了。
引用部分最后提到的开源tcp/ip协议栈是iwIP(我在别的博客看到的,可能我引用的部分是抄的别人的。。),引用还提到的tun2socks,则将在解决方案二中详细解释。
安卓example的ToyVpn;初步搭一个vpn应用的框架可以看这里,这个仅仅是搭建了框架,功能(ip数据包的收发)则没有实现
Vpnservice是安卓提供给开发者用于开发自己的VPN的服务。开发者继承这个Vpnservice,从而实现VPN。手机本身是有一块网卡,安卓虚拟出一个网卡,然后通过NAT,将真实网卡上的出站流量转发到虚拟网卡上,然后Vpnservice获取这个虚拟网卡上的“流量”,并转发给Vpn的服务端。其实还是挺好理解的。问题在于,上面说的流量,并不是传输层的tcp/udp流量,而是ip数据报。
tcp代理所操作的是tcp包,现在要处理ip数据报。而且java语言只提供了传输层(tcp/udp)的socket传输api。这意味着,开发Vpn必定有一部分需要使用其他语言(C/C++)。
看安卓example的ToyVpn中server的代码,发现他的代码就是直接open /dev下的网卡文件,然后读写来收取ip数据(一切皆文件真的骚。。)
一句话:将ip数据报通过Udp发送给代理服务器,代理服务器解包后得到原始的ip数据报,通过C/C++写进网卡文件。
通过Udp传输的原因是,Udp(用户数据报)是ip数据报的简单包裹,不像tcp数据包那样,增加了很复杂的东西,也不进行失败重传等操作。要清楚,我们这里传输的是较底层的ip数据报,在ip数据报的上层,可能是UDP,也可能是TCP,不管传输层是什么协议,消息的正确性,失败重传等等,都有人做过,我们只要传就好了,所以用UDP是最好的。
这样,这个数据包就是一个UDP数据包vpn翻墙app 安卓,里面装的是TCP数据包。系统可以将他想普通的UDP数据包一样发送;在接收端,额外的UDP头部被去掉后,原始的包含tcp消息的ip数据报经修改后(修改源ip地址)继续进入网络堆栈进行处理。
在安卓机上解析ip数据报,最终拿到tcp/udp的数据部分,最后传输。这意味着需要处理tcp协议栈中的握手等等,怎么看怎么不靠谱,主要是难度大。
tun2socks实现一种机制,它可以让你无需改动任何应用程序而完全透明地将数据用socks协议封装,转发给一个socks代理,然后由该代理程序负责与真实服务器之间转发应用数据。使用代理有两种方式,一种是你自己显式配置代理,这样一来,数据离开你的主机时它的目标地址就是代理服务器,另一种是做透明代理,即在中途把原始数据重定向到一个应用程序,由该代理程序代理转发。tun2socks在第二种的基础上,完成了socks协议的封装,并且实现该机制时使用了强大的tun网卡而不必再去配置复杂的iptables规则。
本文以TCP为例,就不再提UDP了。所以说,简单点,把socks代理称为带有认证功能的TCP代理是合适的。
TCP代理非常容易理解,然而纯粹的TCP代理并不实用,必然要加入一些控制功能,比如谁可以被代理,谁不能被代理,如何认证,最多可以代理多少路的请求等等。有了这些控制手段,TCP代理才真正变得实用起来。
socks的运作原理非常简单,就是在TCP数据外包一层socks协议头,到达socks代理服务器后,脱去socks头,然后通过socks服务器与真实服务器之间建立的连接将TCP裸数据传给真实服务器。如下图所示:
请注意,socks代理并不理解任何应用层协议,它只是负责转发应用层数据而已,这一点使socks成为了一个通用的代理协议,这一点和HTTP代理服务器是完全不同的。
这个就不再多说。之所以有这个小节是为了文章的完整性。也是为了给初学者一个完整的提纲来更深入的学习。
我理解的透明代理就是“偷偷的给你做代理”,这一点与你在浏览器里显式设置socks代理服务器完全不同。透明代理就比如说下面这样子:
要实现这一点有很多方式,比如你可以用Linux的TProxy+Policy routing机制,关于这种方式请参见《socket的IP_TRANSPARENT选项实现代理》,然而,很多时候,这种方式行不通。
如果给一个Linux的root账户,那么几乎可以随意显摆,而很多时候这并不可能。比如Android系统就不能随意root,这就意味着你无法在Android系统上随意地配置iptables规则,路由等。那么想在Android系统上免root实现一个透明代理,就需要别的办法。而tun2socks提供了一种这样的办法。
通过上图,我们看到tun2socks可以被拆解出三个部分,即tun网卡部分,协议处理部分以及socks转换部分,这三部分在tun2socks的处理流程是串行的。我来一个一个说。
如果你想做透明代理,那么你必须“想办法把数据流导入到本地”,完成这件事有好多种办法,以Linux为例,比如做一个DNAT即可完成,再比如如上所述,用tun网卡直接把原始数据包捕获到一个应用程序。显然tun2socks采用了后者。
很大的不同。如果使用DNAT的话,目标地址和端口将会是本地的一个代理程序,比如socks代理,那么操作系统的协议栈会自动将数据包交到该代理程序,除了这个DNAT之外不需要再做任何操作。而使用tun捕获数据包的话,由于只是捕获到了IP数据报文,这意味着你要自己处理IP层以上的逻辑,比如TCP按序交付,TCP状态处理,TCP拥塞控制,你要确保代理程序收到的数据包看起来是“经过协议栈处理过的数据包”,“就像是直接从socket的recv接口读到的一样”。
tun2socks使用现成的lwip来完成了协议处理。lwip是一个轻量级的用户态协议栈,非常适合完成这种协议适配工作。
经过第2部分,即协议处理之后,现在tun2socks拿到的已经是源主机试图发送到原始目标主机的裸数据了,接下来它可以做的事情可就多了,当然可以用socks协议封装裸数据,将其发送给一个socks代理程序。
只要是使用了tun网卡获取原始数据,那么任何框架都会面临一个必须回答的问题,即拿到原始的IP数据报文或者以太帧之后,下一步如何处理这些数据。OpenVPN和tun2socks显然是给出了两种不同的回答,而这不同的回答即是OpenVPN和tun2socks之间唯一的不同。
引用结束,作者说tun2socks和OpenVPN采用了两种完全不同的解答,其实也就是这里的tun2socks和OpenVpn了。
看到这里不禁感叹前人的智慧,存在即合理。看起来,我的http代理用于翻墙只是一种过时的选择了,的确是socks的时代,特别是有了tun2socks。


