OpenVPN-ng,为移动续航的应用层隧道

来源:互联网 发布:淘宝网休闲小包包 编辑:程序博客网 时间:2024/06/07 17:47
VPN,让人觉得它总是做好事的,是逃离监管的途径,事实上VPN已经成了逃离监管的唯一代名词。你看,不管是什么技术,IPSec也好,WEB代理也罢,只要是加密了原始信息的技术,都可以叫做VPN,于是乎就有了所谓二层VPN技术,三层VPN技术,乃至七层VPN技术。VPN是草根的利器,同时也是排他性组织的利器,小到民营公司,大到跨国企业,都不希望自己企业的信息让别人看到,因此不管是对在外出差人员,还是针对处在各地的分支机构,都会使用各种VPN技术来提供远程接入,然而针对这种接入,监管则是必要的,因为VPN技术的使用者不是自觉使用的,而是被要求使用的。
       SoftEther曾经被日本信息处理事业协会勒令禁止使用,同样的还有我们这不便言说的情况。在本文中,我站在部属者和监管者的角度来谈一下VPN技术,最后给出一个我的设计。我可能是个叛教者。

1.OpenVPN怎么样

这是草根DIY的首选。然而不太适合大型企业的大流量。

1.1.OpenVPN的性能问题

1.2.OpenVPN的部署问题

2.完全星型拓扑的优势

它俨然是一个公司内部的局域网,大家都接在一个端口足够用的交换机上,这是一个BMA网络,想访问谁,简单地ARP一下即可。

3.OpenVPN的可利用的实现细节

那必须是memory BIO实现的TLS以及Realiable层了。

4.实现OpenVPN-ng

新的VPN称作OpenVPN-ng,主要有两个模块组成,分为Switch模块和处理模块,处理模块主要负责VPN数据的加密/解密以及VPN节点间的认证/密钥协商(TLS),而Switch只负责VPN流量的路由和转发,并不涉及加密/解密/认证等。

       所有的VPN节点均只和Switch进行UDP通信,流量分为两种,一种是节点间TLS过程的流量,封装在一个控制报文中,另一种是节点间的VPN数据流量,封装在一个数据报文中,两种报文仅仅在报文头部有所区分。报文头部以及通信模型如下图所示:





可以看到,VPN处理节点之间通过节点ID进行区分而不是通过常规的IP地址以及端口号进行区分,这样就形成了一个堆叠在IP地址和端口之上的和IP地址以及端口号无关的堆叠网络。

4.1.堆叠网络

这个堆叠网络的威力在于它和IP地址以及协议,端口号无关。VPN节点之间完全按照VPN节点ID来寻址。这部分任务由VPN Switch模块来完成。Switch模块中拥有一张{节点ID,IP/端口}的映射表。它的效力在于,只要保持VPN处理节点和VPN Switch的连通性,就可以保证节点间的互通。

4.2.VPN处理节点的数据结构

由于一个VPN节点和不止一个VPN节点通信,那么显然每一个VPN节点都会保存一个链表,每一个链表节点保存一个会话。安全参数包括:
对端节点ID:标示已经建立安全连接的对端VPN节点;
加密算法:比如3DES,AES,RC4之类的对称加密算法;
密钥长度:加密密钥的长度;
摘要算法:MD5,SHA-1等;
哈希长度:摘要计算结果的长度;
主密钥:计算工作密钥的材料;
预主密钥:计算主密钥的材料;
IV长度:...
这个类似于IPSec的SA,简直太像了,如果你懂SA,就知道怎么使用这个数据结构了,对端节点ID用来标示一个链表节点代表的一个数据结构,使用该数据结构的安全参数和对端进行通信。

4.3.VPN Switch的数据结构

VPN Switch上只要保存转发映射表,收到一个节点送来的数据包的时候,只要取出节点ID,查询其{节点ID,IP/端口}映射表,就知道数据该发往哪个VPN处理节点。

5.使用BIO而不是网络实现节点间TLS

要明白的是,SSL握手和网络元素是无关的,就像OpenVPN实现的那样,在两个memory buffer之间就可以通过BIO/Realiable层实现TLS协商。如此一来就可以在VPN处理节点之间进行隧道的建立,但是所有的外层IP数据报文统一均发往VPN Switch节点,然后通过这个Switch根据VPN数据包头上标示的内层目标IP地址进行路由查找后转发到正确的VPN处理节点。

6.只是堆叠的Ponitopoint模式的OpenVPN?

非也!这并不是多个P2P模式的OpenVPN的简单叠加。注意,OpenVPN-ng中,我显式分离了Switch转发和处理(OpenVPN本身就分离了TLS通道和网络的关系)!因此Switch不再关注包的具体内容,它只是一个简单的转发代理,每一个到来的数据包的目的地都是它,它只需要将此数据包buffer始发转发到对应的目的地VPN节点即可。
       隧道是在VPN处理节点之间建立的,但是这个隧道却既不是IP隧道,也不是四层隧道,而是一个应用层隧道,是一个纯粹的buffer隧道,一个buffer到达VPN Switch,作为socker的buffer被读出,这个buffer就是一个加了OpenVPN-ng头部的加密的IP数据报或者一个以太帧,然后根据头部信息进行路由之后,将这个buffer作为一个socket的buffer发送到目标VPN处理节点。

7.信任问题

VPN处理节点信任VPN Switch吗?
VPN处理节点能把所有的密钥托管到VPN Switch吗?
如果可以的话,VPN处理节点就可以分别和VPN Switch建立SSL连接(为了支持移动性,此SSL依然使用堆在Reliable层上的BIO在远程内存进行,和IP地址无关),然后将VPN节点间协商出来的对称密钥用数字信封传输给VPN Switch,于是VPN Switch就建立了一个n*n的映射,保存每一对VPN处理节点间的对称密钥。
       现在想想VPN Switch能做什么?它可以解密每一个数据包并处理后再重新加密。进而可以实现安全审计以及协议转换之类的事情。但是这关乎信任问题,不可小觑。到底我们该不该信任第三方,到底有没有权威,这是一个莫大的问题。

8.密钥托管到VPN Swtich

见上一小节。

9.密钥共享到集群

这又是一个扩展。协商出来的对称密钥仅仅在两个节点间共享还是在两个集群之间共享。如果是在两个集群之间共享,那就涉及到密钥如何共享给集群的问题。这个问题很多解决方案,数字信封?TLS通道...

10.不动点-终极意义的

这是一个终极意义的不动点,它可以解决移动终端在移动时更换IP的问题。之前我已经用一个自定义的会话层取消掉了IP地址变化的限制,那么看看我现在的OpenVPN-ng实现,VPN节点之间不再直接建立网络连接,这就意味着,只要VPN节点始终保持和VPN Switch的联通性,VPN节点间的通信就是可以进行的。此时不变的那个点就是VPN Switch!当然了,我需要设计一个状态机,在VPN节点更换IP地址的时候主动上报给VPN Switch一个消息,以便使VPN Switch可以更新其{节点ID,IP/端口}映射表。之前我实现的以SID替代IP地址/端口作为multi_instance链表的查找键值,那只是解决了客户端的IP地址变化问题,但是现在,OpenVPN-ng,不再区分服务端和客户端,留下的只有VPN处理节点了,它们只和不动点VPN Switch保持连通性,如此一来,哪个VPN处理节点都是随意移动的!
       我们来看一下整个网络全部都是移动终端的情况,比如都是手机。
       我们来找另外一个不动点,那就是虚拟IP地址。虚拟网卡的IP地址是不变的,虽然移动终端的IP地址在不断变化,但是由于VPN节点和VPN Switch之间一直保持连通性,因此其虚拟网卡的IP地址不会变化,因此在这些虚拟网卡的IP地址之间建立的TCP连接将会保持,不会因移动终端本身的IP地址变化而中断。是不是有点像LISP(注意,不是Lisp语言,而是位置标识分离协议)的思想呢?

11.为移动续航

这篇文章我已经写了好几周了,过去的8月份,实在太忙,先是上旬几乎都是在出差,不过那算是好的,因为短短的几天竟然学会了很多东西,接下来的中旬和下旬就是悲哀了,重复性的技术支持让我竟然好几次想摔了我的iPhone5,断断续续一直在思考如何让移动终端在移动时支持完全的平滑过渡,但是仅仅是想象一下而已,因为我知道这个OpenVPN-ng是不会被采纳的...再后来,由于要为小小上幼儿园作准备,家长会,家访,...又是短短的时间,让我明白了很多的世态炎凉,抽了几个夜晚,我把OpenVPN-ng实现了出来。
       OpenVPN不仅仅可以加密数据,还有一个特性,它有自己的协议,而且是应用层协议,用该协议封装了一个IP数据报或者以太帧,这就使应用层隧道成为可能,然后它使用虚拟网卡以路由的方式捕获数据包到应用层,这就可以将IP数据报或者以太帧在应用层完成协议封装,一切通信全都围绕虚拟网卡的IP地址进行的话,移动便不再是问题了。然而要寻找一个Switch作为不动点,它就像航空母舰一样,只是它在为移动性续航!这种中心化的移动性策略非常简洁,起码我是这么认为的,非常适用于一个单一的移动环境。

4 1
原创粉丝点击