0%

OpenVPN-Reship

阅读更多

本文转载自笑叶林-OpenVPN

1 基本理论篇

1.1 VPN 简介

本小节转载自OpenVPN 简介

1.1.1 OpenVPN 简介

VPN直译就是虚拟专用通道,是提供给企业之间或者个人与公司之间安全数据传输的隧道,OpenVPN无疑是Linux下开源VPN的先锋,提供了良好的性能和友好的用户GUI

OpenVPN是一个基于OpenSSL库的应用层VPN实现。和传统VPN相比,它的优点是简单易用。

OpenVPN允许参与建立VPN的单点使用共享金钥,电子证书,或者用户名/密码来进行身份验证。它大量使用了OpenSSL加密库中的SSLv3/TLSv1协议函式库。OpenVPN能在SolarisLinuxOpenBSDFreeBSDNetBSDMac OS XWindows上运行,并包含了许多安全性的功能。它并不是一个基于WebVPN软件,也不与IPSec及其他VPN软件包兼容。

虚拟私有网络(VPN)隧道是通过Internet隧道技术将两个不同地理位置的网络安全的连接起来的技术。当两个网络是使用私有IP地址的私有局域网络时,它们之间是不能相互访问的,这时使用隧道技术就可以使得两个子网内的主机进行通讯。例如,VPN隧道技术经常被用于大型机构中不同办公区域子网的连接。有时,使用VPN隧道仅仅是因为它很安全。服务提供商与公司会使用这样一种方式架设网络,他们将重要的服务器(如,数据库,VoIP,银行服务器)放置到一个子网内,仅仅让有权限的用户通过VPN隧道进行访问。如果需要搭建一个安全的VPN隧道,通常会选用IPSec,因为IPSec VPN隧道被多重安全层所保护。

VPN(虚拟专用网)发展至今已经不在是一个单纯的经过加密的访问隧道了,它已经融合了访问控制、传输管理、加密、路由选择、可用性管理等多种功能,并在全球的信息安全体系中发挥着重要的作用。也在网络上,有关各种VPN协议优缺点的比较是仁者见仁,智者见智,很多技术人员由于出于使用目的考虑,包括访问控制、安全和用户简单易用,灵活扩展等各方面,权衡利弊,难以取舍;尤其在VOIP语音环境中,网络安全显得尤为重要,因此现在越来越多的网络电话和语音网关支持VPN协议。

1.1.2 VPN 分类

1.1.2.1 PPTP

1-1-2-1

点对点隧道协议(PPTP)是由包括微软和3Com等公司组成的PPTP论坛开发的一种点对点隧道协,基于拨号使用的PPP协议使用PAPCHAP之类的加密算法,或者使用Microsoft的点对点加密算法MPPE。其通过跨越基于TCP/IP的数据网络创建VPN实现了从远程客户端到专用企业服务器之间数据的安全传输。PPTP支持通过公共网络(例如Internet)建立按需的、多协议的、虚拟专用网络。PPTP允许加密IP通讯,然后在要跨越公司IP 络或公共IP网络(如Internet)发送的IP头中对其进行封装。

1.1.2.2 L2TP

1-1-2-2

第2层隧道协议(L2TP)IETF基于L2F(Cisco的第二层转发协议)开发的PPTP的后续版本。是一种工业标准Internet隧道协议,其可以为跨越面向数据包的媒体发送点到点协议(PPP)框架提供封装。PPTPL2TP都使用PPP协议对数据进行封装,然后添加附加包头用于数据在互联网络上的传输。PPTP只能在两端点间建立单一隧道。L2TP支持在两端点间使用多隧道,用户可以针对不同的服务质量创建不同的隧道。L2TP可以提供隧道验证,而PPTP则不支持隧道验证。但是当L2TPPPTPIPSEC共同使用时,可以由IPSEC提供隧道验证,不需要在第2层协议上验证隧道使用L2TPPPTP要求互联网络为IP网络。L2TP只要求隧道媒介提供面向数据包的点对点的连接,L2TP可以在IP(使用UDP),帧中继永久虚拟电路(PVCs),X.25虚拟电路(VCs)或ATM VCs网络上使用。

1.1.2.3 IPSec

1-1-2-3

IPSec的隧道是由封装、路由与解封装组成整个过程。隧道将原始数据包隐藏(或封装)在新的数据包内部。该新的数据包可能会有新的寻址与路由信息,从而使其能够通过网络传输。隧道与数据保密性结合使用时,在网络上窃听通讯的人将无法获取原始数据包数据(以及原始的源和目标)。封装的数据包到达目的地后,会删除封装,原始数据包头用于将数据包路由到最终目的地。

1.1.2.4 SSLVPN

1-1-2-4

SSL协议提供了数据私密性、端点验证、信息完整性等特性。SSL协议由许多子协议组成,其中两个主要的子协议是握手协议和记录协议。握手协议允许服务器和客户端在应用协议传输第一个数据字节以前,彼此确认,协商一种加密算法和密码钥匙。在数据传输期间,记录协议利用握手协议生成的密钥加密和解密后来交换的数据。

SSL独立于应用,因此任何一个应用程序都可以享受它的安全性而不必理会执行细节。SSL置身于网络结构体系的传输层和应用层之间。此外,SSL本身就被几乎所有的Web浏览器支持。这意味着客户端不需要为了支持SSL连接安装额外的软件。这两个特征就是SSL能应用于VPN的关键点。

1.1.2.5 什么是 VPN 使用的隧道技术与隧道协议

VPN隧道所使用的公共网络可以是任何类型的通信网络。可以是Internet,也可以是企业内部网。为创建隧道,VPN的客户机和服务器必须使用相同的隧道协议,常用的隧道协议包括点对点隧道协议PPT、第2层隧道协议L2TP和安全IP隧道模式IPSec

按照开放系统互联OSI参考模型划分,隧道技术可以分为以第2层隧道协议为基础的技术和以第3层隧道协议为基础的技术。第2层隧道协议对应OSI模型中的数据链路层,使用帧作为数据传输单位PPTPL2TP协议属于第2层隧道协议,都是将数据封装在点对点协议(PPP)的帧中通过Internet发送。第3层隧道协议对应OSI模型中的网络层,使用包作为数据传输单位。安全IP隧道模式IPSec属于第3层隧道协议,是将数据包封装在附加了IP包头的新数据包中通过IP网络传送。

点对点隧道协议(PPTP,Point-to-Point Tunneling Protocol)将点对点协议(PPP,Point-to-Point Protocol)的数据帧封装进IP数据包中,通过TCP/IP网络进行传输PPTP可以对IPIPXNetBEUI数据进行加密传递。PPTP通过PPTP控制连接来创建、维护和终止一条隧道,并使用通用路由封装(GRE,Generic Routing Encapsulation)对PPP数据帧进行封装。封装前,PPP数据帧的有效载荷(有效传输数据)首先必须经过加密、压缩或是两者的混合处理。

第2层隧道协议(L2TP,Layer Two Tunneling Protocol)是PPTP和第2层转发技术(L2F,Layer Two Forward)的结合。第2层转发是Cisco公司提出的隧道技术。为了避免PPTPL2F两种互不兼容的隧道技术在市场上彼此竞争给用户造成困惑和带来不便,Internet工程任务委员会IETF要求将两种技术结合在单一隧道协议中,并在该协议中综合PPTPL2F两者的优点,由此产生了L2TPL2TP协议将PPP数据帧封装后,可通过TCP/IPX.25、帧中继或ATM等网络进行传送。L2TP可以对IPIPXNetBEUI数据进行加密传递。目前,仅定义了基于TCP/IP网络的L2TPL2TP隧道协议既可用于Internet,也可用于企业内部网。

为了实现在专用或公共IP网络上的安全传输,安全IP隧道模式IPSec使用安全方式封装和加密整个IP包。它首先对IP数据包进行加密,然后将密文数据包再次封装在明文IP包内,通过网络发送到接收端的VPN服务器。VPN服务器对收到的数据包进行处理,在去除明文IP包头,对内容进行解密之后,获得原始的IP数据包,再将其路由到目标网络的接收计算机。

在这三种隧道协议中,点对点隧道协议PPTP和第2层隧道协议L2TP的优点是对用微软公司操作系统的用户来说很方便学习,因为微软公司已把它们作为路由软件的一部分;缺点是PPTPL2TP将不安全的IP数据包封装在安全的IP数据包内。PPTPL2TP适用于远程访问虚拟专用网。安全IP隧道模式IPSec的优点是它定义了一套用于认证、保护私密和数据完整性的标准协议,缺点是微软公司对IPSec的支持不够。IPSec适用于可信的局域网之间的虚拟专用网,即企业内部网VPN应用。

1.1.3 OpenVPN

典型的SSL VPN应用如OpenVPN,是一个比较好的开源软件。PPTP主要为那些经常外出移动或家庭办公的用户考虑;而OpenVPN主要是针对企业异地两地总分公司之间的VPN不间断按需连接,例如ERP在企业中的应用。

OpenVPN允许参与建立VPN的单点使用预设的私钥,第三方证书,或者用户名/密码来进行身份验证。它大量使用了OpenSSL加密库,以及SSLv3/TLSv1协议。OpenVPN能在Linux、xBSDMac OS XWindows 2000/XP上运行。它并不是一个基于WebVPN软件,也不与IPsec及其他VPN软件包兼容。

1.1.3.1 隧道加密

OpenVPN使用OpenSSL库加密数据与控制信息:它使用了OpesSSL的加密以及验证功能,意味着,它能够使用任何OpenSSL支持的算法。它提供了可选的数据包HMAC功能以提高连接的安全性。此外,OpenSSL的硬件加速也能提高它的性能。

1.1.3.2 验证

OpenVPN提供了多种身份验证方式,用以确认参与连接双方的身份,包括:预享私钥,第三方证书以及用户名/密码组合。预享密钥最为简单,但同时它只能用于建立点对点的VPN;基于PKI的第三方证书提供了最完善的功能,但是需要额外的精力去维护一个PKI证书体系。OpenVPN2.0后引入了用户名/口令组合的身份验证方式,它可以省略客户端证书,但是仍有一份服务器证书需要被用作加密。

1.1.3.3 网络

OpenVPN所有的通信都基于一个单一的IP端口,默认且推荐使用UDP协议通讯,同时TCP也被支持OpenVPN连接能通过大多数的代理服务器,并且能够在NAT的环境中很好地工作。服务端具有向客户端“推送”某些网络配置信息的功能,这些信息包括:IP地址、路由设置等。OpenVPN提供了两种虚拟网络接口:通用Tun/Tap驱动,通过它们,可以建立三层IP隧道,或者虚拟二层以太网,后者可以传送任何类型的二层以太网络数据。传送的数据可通过LZO算法压缩。IANA(Internet Assigned Numbers Authority)指定给OpenVPN的官方端口为1194。OpenVPN 2.0以后版本每个进程可以同时管理数个并发的隧道。

OpenVPN使用通用网络协议(TCP与UDP)的特点使它成为IPsec等协议的理想替代,尤其是在ISP(Internet service provider)过滤某些特定VPN协议的情况下。在选择协议时候,需要注意2个加密隧道之间的网络状况,如有高延迟或者丢包较多的情况下,请选择TCP协议作为底层协议,UDP协议由于存在无连接和重传机制,导致要隧道上层的协议进行重传,效率非常低下。

1.1.3.4 安全

OpenVPN与生俱来便具备了许多安全特性:在用户空间运行,无须对内核及网络协议栈作修改;初始完毕后以chroot方式运行,放弃root权限;使用mlockall以防止敏感数据交换到磁盘。

OpenVPN通过PKCS#11支持硬件加密标识,如智能卡。

1.2 VPN 原理及实现之一般理论

本小节转载自VPN 原理及实现之一般理论

OpenVPN基于OpenSSL来实现安全,但是却不是传统意义上的SSLVPN,它只是一个普通的VPN,工作在IP层而不是传输层。

VPN的含义着重点有两层意思,一个是V,也就是虚拟,另一个是P,也就是专用。

虚拟就是说不用物理布线,仅仅在逻辑上实现一个网络,虚拟网络之所以能实现并建立起来,靠的是分层模型的优势,分层模型直接将网络按照逻辑意义纵向分成了7个层次(或者TCP/IP的5个层次),每一层都仅仅承载数据而不管数据的格式和内容,上下层次间仅仅通过接口和服务来通信,理论上任何层次的数据都可以被承载在其它的任何层次或者它当前的层次上,于是就出现了很多XXoverYY的网络模型,比较典型的比如ppp over ethernet等。

over模型按照数据层次可以分为三类,第一类是上层数据承载于下层,这实际上就是我们使用的普通的TCP/IP模型,第二类是同层承载,比如上面说的pppoe,这一类构建方式主要是为了在一个以传输占主导的层次上增加一个非传输意义的逻辑或者说实现一个隧道,比如pppoe中,ethernet主要用于局域网传输,而且性价比十分合理,但是却缺乏认证机制,但是ppp协议的认证功能虽然很好,但是却缺乏多点通信和寻址能力,作为传输协议意义不大,于是就使用ethernet进行传输,使用ppp进行认证,另外一个同层承载的例子是IPSec的隧道模式,它将一个IP数据报封装于另一个IP数据报中,这样实际上也就实现了一般意义上的“虚拟局域网络”(注意不是vlan),因为在数据报到达最终目的地之前,参与路由的始终是外层的IP头,内层的IP头连同真实数据都被外层IP当成了data,因此不参与路由,所以从隧道的出发路由器到结束路由器,不管中间经过的是局域网,广域网还是别的什么,内层的IP数据报一直“以为”自己在出发路由器的那个局域网内,因此就实现了一个虚拟网络,实现了VPN中的V,那么P呢,IPSecVP做到了一起,也就是说在实现ip over ip的过程中实现了安全,这就是熟知的ah协议和esp协议,实现了安全才能保证专用,否则别人都可以进入你的虚拟网络了,作为VPN来说,IPsec就到此为止,但是IPSec的用处不光如此,IPSec主要是保证IP数据报的安全(因为IP层不提供任何安全保护,ipv6就不一样了,完全不需要IPSec),VPN只是它的隧道模式的一个应用,除了隧道模式,IPSec还有传输模式,不建立隧道,只是将认证或者加密的功能置于IP数据报中,当然也就是不需要ip over ip了。

众所周知IPSec的隧道模式实现的VPN有一个缺陷,那就是很难穿越nat,因为nat要修改IP头,一旦IP头被修改了,那么最终的ah或者esp的认证加密的校验结果就会出错,因此就不能随意在nat的网络环境中使用IPSec实现的VPN,当然不涉及IP头认证的IPSec协议还是可以用的。

难道VPNIPSec这一根稻草了吗?认证和加密的逻辑十分复杂和多样,不适合在IP层做,IP层做好快速路由和连接不同子网就够了,如果将分层模型的每个层次仅仅当作一种交通工具来看待的话,问题就容易解决了,交通工具或者叫运输工具可以相互运输,大卡车可以运小卡车,也可以拆了被小卡车运,大卡车还可以运输别的大卡车,它们都可以被放入集装箱被轮船运输,分层模型就是这样的,我们可以让应用层或者表示层或者传输层来承载IP数据报,这也就是over模型的第三类,即上层承载下层,很多时候越往上层逻辑越复杂,实现越灵活,如果想要在低层次实现高度复杂的逻辑,不妨试试这种模型,这个意义上看,IPSec实现的VPN最后肯定不如ip over ssl好,因为扩充IPSec很难,毕竟它在协议栈中的位置不适合做大幅修改,但是ssl的扩展性却很好,它本身就在协议栈的顶端,即使影响也就影响应用层,比如迫使http转换到https

如果说底层就不该有复杂多样且多变的逻辑这种设计思想是对的,那么IPsec就不该出现,IPv6除了扩充地址空间外,新增的功能净加重了IP层的负担,IPv6的复杂设计净是商业公司为了推自己的接口或者设备而使出的伎俩,不过也说不准,留给历史评述吧。

VPN不一定要实现隧道,只要能互相访问并且保证互访者独占性的网络理论上都是VPN,然而隧道的方式更具有代表性,各种实现也更丰富和花哨。

1.3 VPN 原理及实现之隧道的一种实现

本小节转载自VPN 原理及实现之隧道的一种实现

理论上已经合理的ip over ssl还需要一些额外的技术支撑才能使用,必须想办法将一个ip数据报原封不动的让它被ssl重新封装一次,这个动作不可能在原始的标准协议栈中执行,标准协议栈不支持数据双向流动,那么解决方案之一就是修改协议栈,在ip层之下实现一个轻量的ssl协议层,但是如此一来就又回到了IPSec的老路上,因此此法不可取,正确的方法是不修改协议栈,让一切留在它应该在的地方,于是ssl必然得在应用层或者说是表示层实现,现在的问题是如何将下层的ip数据报重新引入上面的应用层,而且还不能修改标准协议栈,于是必然地要让ip数据报继续往下走,然后最终从一个网卡流出,于是就出了协议栈,接下来就可以自由发挥了,让数据流出网卡的原因是不能修改协议栈,但是还不能真的让它流出机器,如果它走了就不能指望用ssl封装它了,那么流到哪里呢?回环设备是一个不错的选择,从回环设备流出的数据实际上又流进了回环设备,用户空间只需要打开回环设备然后读取就可以了,注意不能通过一般套接字读取,毕竟那些数据不是发给我们的,要使用类似抓包的方式进行数据抓取,并且用防火墙禁止被抓取的数据继续被forward,这实际上是一种巧妙的拦截方式,被抓取得数据然后经过ssl封装后再发向一个真的ip地址,我们需要配置的就是将所有的vpn数据全部发往回环设备,其实就是添加一条路由,虚拟网络已经建立,事情到此为止看似要结束了。

但是且慢,问题来了,以后所有vpn数据都会经标准协议栈流出再流进loopback,然后作为裸数据进入应用层,接着整个原始vpn数据连同它的原始ip头封装作为应用数据接受ssl协议的封装,然后发往vpn的另一端,在另一端数据从真实网卡进入,然后由于这是隧道的终点,数据直接进入应用层,在应用层,vpn服务器等候在那里,得到原始的vpn裸数据还有它在发送端的ip头,服务端得到这个东西有什么用呢,接下来它要怎么做呢,它只是隧道的终点,并不是真的要接收数据的机器,因此它必须将数据重新发到真正需要它的机器,很显然它要作为一个应用层代理存在,剥去原始的ip头,得到原始的数据,然后将数据发给真实的目的地,且不说此法是否可能,有两点不合理之处足以否定它,由于vpn服务器实现了代理,那么数据必然要在该处集中并剥去ip头,并且在相反的方向要做同样的处理,那么它就要记住所有的ip头,否则数据就会有去无回,如此一来,vpn服务器的负载可堪忍受?性能呢?第二点,代理的方式消除了隧道的透明性,目的地受到数据后会不知道数据从何而来,统一认为是vpn服务器发来的,这样就无法根据数据源点进行策略化服务。

综上原因,loopback设备可用但不可行,因为它是本机闭合的,也就是说只有loopback出去的数据才能进入loopback,它又且仅有两个出口,一读一写都在应用层,你无法将数据作为物理层的流写入loopback,而只能作为应用层的数据通过协议栈逐级封装到达loopback,然后再逐级解封回来,vpn发送端面临同样的问题,因为仅仅是路由将数据出口指向了loopback,如果不用抓包的方式(pcap)的话是得不到数据的,而这种方式又十分影响性能,加之还要配置复杂的防火墙规则禁止进入loopback的数据被转发,性能又受影响,隧道两端由于是全双工通信,因此一端面临的问题在数据反向时在对端同样存在,抛开这些不谈,仅就loopback无法自由配置ip地址这一条,它就不能被选中来实现隧道,vpn网络需要被管理,有时管理本身就很复杂,虚拟网络不仅仅就一张,我们需要为每张虚拟网络准备一个子网,也就是每个虚拟网络要有不同的ip,所以必然需要灵活的ip配置,故而loopback不能实现优雅透明的隧道,既然如此我们回到原点,无非就是做到两点,第一,数据必须按照协议栈的标准逐级封装和解封装,不能修改协议栈,第二就是数据到了最下面物理层的时候不能真的走掉,而是回到用户空间,于是乎虚拟网卡就成了很好的选择。

1.4 VPN 原理及实现之虚拟网卡构建 VPN

本小节转载自VPN 原理及实现之虚拟网卡构建 VPN

虚拟网卡通过实现一个字符设备来支持物理层,这样应用层和物理层就通过这个字符设备联系起来了,从这个字符设备读出来的就是虚拟网卡发往物理层的字节流,写入字符设备的数据作为字节流被虚拟网卡接收,虚拟网卡下面不再是网线或者无线电波,而是一个字符设备,这样从字符设备读出的还是写入字符设备的都是物理层字节流了,用它来实现隧道再简单不过了,VPN程序读取字符设备,得到封装好的原始数据,然后用SSL再封装后发往VPN的对端,和loopback的最初尝试一样,实现配置一条路由,使得要通过隧道的数据从虚拟网卡流出,最终通过虚拟网卡的字符设备导入应用层的VPN进程。

有了虚拟网卡,VPN隧道可以如上述很简单的实现,那么还有什么额外的工作要做呢?由于虚拟网卡的物理层可以通过字符设备随意读写,那么一台机器也就被虚拟成了两台机器,VPN进程可以被设想为运行在另一台机器上,而这台机器有一个网卡连接真实的机器,该网卡就是虚拟网卡,于是问题就转化成了两台机器通信的问题,这个很好办,完全通过路由就能搞定,因此额外的工作基本没有,并且我们也避开了抓包,代理等降低性能又很难扩展的概念。虚拟网卡实现的隧道非常灵活,需要做的仅仅是安装一个虚拟网卡驱动,然后配置一下路由即可,一切尽在我们所熟悉的route命令中搞定。数据流向见下图:

1-4

其实IP网络本身就是一个虚拟的网络,任何不通过导线直接相连通信的网络都是虚拟网络,难道IP网不是构建在各种局域网,广域网,电信网,电视网等物理网络之上的虚拟网络吗?按照分层的观点,pstn都可以看成是虚拟网络,VPN作为虚拟网络的意义更特殊罢了,而且实现的也各式各样,甚为巧妙。

ip over ssl没有触动协议栈,也没有增加新的协议,利用SSL的灵活性将IP封装的更加安全了,SSLIPSec要灵活得多,应用层的SSL本身可配置性就比较好,不仅仅可以实现IPSecdh密钥协商,还可以使用很多pki的优秀特性。开源软件一向不会放弃任何优秀的东西,OpenVPN就是用上述思想完成的,实际上OpenVPN几乎没有做什么,就是一个整合,整合什么呢?通读代码发现就是配置虚拟网卡,配置路由,读写字符设备,用OpenSSL的库进行SSL协议封装,几乎全部都是现有的东西,然而经过OpenVPN的整合就成了一个稳定又高效的VPN软件。

1.5 VPN 原理及实现之TCP还是UDP

本小节转载自VPN 原理及实现之TCP还是UDP

有了ip over ssl的关键思想,OpenVPN就是一个必然结果了,于是就不多说了,OpenVPNOpenSSL并不在一个层次上,虽然都很openOpenVPN的配置非常复杂,主要就是为了建立更加合理的隧道,虽然IPSec实现的 VPN 不区分客户端和服务器,建立sa的时候全靠dh对称的协商加密密钥和算法,但是基于OpenSSLOpenVPN却区分二者,因为OpenVPN的安全是ssl实现的,而ssl区分客户端和服务器,虚拟网卡已经说的很多了,现在说说隧道的一些细节,OpenVPN可以建立tcp隧道和udp隧道,tcp隧道顾名思义就是用tcp来封装VPN数据流,udp亦然,但是虽然可以使用udp封装,在OpenVPN中你却不需要担心数据失序,因为udp之上还有ssl,而 ssl不允许数据失序,确切的说不应说是ssl,基于udpssl实际上是tlsssl数据由于并不是流式的,而是基于记录的,每次必然读取一条记录,因此ssl是存储接收和存储发送的,如果下面用udp传输,那么就可能出现丢包或者失序的情况,如此一来读取的记录就会不正确,在ssl解密特别是cbc方式解密时就会出错,所以ssl下面必然是可靠而按序的,即使用udp,那么在ssludp之间也必须实现可靠和按序。

那么到底tcp隧道和udp隧道如何选择呢?我们看一个组合,抛开tcp/udp之外的协议不谈,一共有四种隧道,分别是tcp in tcpudp in tcptcp in udpudp in udp,第一种和最后一种问题最大,先说第一种,由于 tcp是有连接的,如果出现丢包的话,那么不管是隧道还是真实收发方都要重传数据,双方重传的数据实际上是为了一个目的一份数据,VPN路由器仅仅提供封装服务,并不需要为丢包负责,因此收发方负责即可,然而tcp的语义却管不了这么复杂的策略,它只有让二者均重传数据包,如此一来网络一旦丢包,那么紧接着会出现大量的重传,udp in udp的情况正好相反,本来udp就会丢包而且丢后不管,udp式的隧道加重了这个问题,本来不用隧道的网络平均丢包x个,用了隧道就可能丢包n*x个,也不可取,那么就剩下余下的udp in tcptcp in udp了,其实需要考虑是不是in前面的协议,而是后面的,因为后面的更底层,我们必须要选出一个协议来创建隧道而不是强迫用户使用某一种协议,那么到底是tcp好还是udp好呢?

这似乎又是一个需要权衡的问题,个人认为udp要好些,如果用户使用tcp,那么用户自己就能处理重传和失序问题,不劳VPN代劳,如果用户使用udp,那么说明他不在乎丢包和失序,VPN更不需要多此一举用tcp保证不丢包和按序,画蛇添足反而抵消了用户选择udp的原因。如果用tcp建立隧道的话,用户使用tcp时会导致重传风暴,而用户使用udp时效率会明显降低。但是使用udp的话会有一个问题,那就是如果VPN两端之一断开了连接,由于udp在断开时不管是正常断开还是异常崩溃都不会向另一端发送通知,那么连接双方的连接感知必须通过一个心跳来完成,在OpenVPN中可以通过--ping--ping-restart来配置,如果心跳时间过短,虽然感知力增加了,但是心跳风暴不说,在端点物理间距很长时,有时的网络拥塞会被认为是断开了连接,造成误判。这又是一个值得权衡的事情

1.6 Linux 平台 VPN 技术概论

本小节转载自Linux 平台 VPN 技术概论Linux 平台 VPN 技术概论-续

1.6.1 VPN要解决的问题以及方案

1.6.1.1 问题及方案

基于主机的第三层VPN的要旨就是“透明/安全的接入”,其中透明的含义就是配置要简单,尽量让用户感觉不到VPN的存在,因此这种VPN的实现其实只要解决两个问题即可:

  1. 如何拿到第N层数据,然后放回第M层
  2. 加密/解密第三层ip数据报

针对第一个问题,实际上我们依赖的是这样一个事实,即OSI的分层网络模型,这样才可以使第M层将第N层的PDU(Protocol Data Unit)当成有效载荷,解析时只需要根据下层的协议号就可以定位上一层的协议类型。以封装第三层数据的VPN为例,上述第一个问题在linux上有三种方案:

方案一:使用netfilter

使用netfilter无疑是最直接的方式,对于接收的包,需要在prerouting上挂载一个钩子,对于本地发出的包,则需要在output上挂载一个钩子,这样就可以在钩子函数中进行加密/解密处理了,处理完毕之后再根据策略封装成一个新的ip数据报,重新路由并且发送出去或者接收

1-6-1-1-1

方案二:使用虚拟网卡

这是一种不直接但是很自然的方式,因为,我们知道从网卡出来的包包含一个IP数据报(暂不考虑其它三层协议,比如ipx)。实现一个虚拟网卡,在其xmit发送函数中处理加密,然后重新封装,重新路由。这里暂时先不考虑在哪里解密,因为网卡发送和接收的逻辑是不一样的,我们可以实现一个虚拟网卡,然而却不能修改ip协议栈,除非使用netfilter

1-6-1-1-2

方案三:将IP数据报导出到用户态,比如使用packet套接字以及替换send/recv

这是最灵活的方案,然而如果使用packet的话却不行。因为packet无法截获数据报。因此需要在socket层次替换send/recv函数,实现加密/封装以及解密/解封装。这里暂时不考虑send处理,因为对于一般的应用数据,是很难替换send的(Linux没有windows的LSP机制),这种方式,控制接收较方便,而控制发送则很难,和使用虚拟网卡的情形正好相反

1-6-1-1-3

我们发现,2和3是互补的,虚拟网卡很容易拿到发出的未封装的原始IP数据报-通过路由即可,但是拿不到接收的封装过的IP数据报,而替换socketsend/recv则很容易拿到接收的封装过的IP数据报但是拿不到发送的未封装的IP数据报。因此将2和3结合一下,就出现了第四种方式

接下来我们来讨论VPN整体的设计。在架设VPN的时候,首先要明白三件事:

  1. 确定不安全通路的两个端点。我们就在这两个端点之间建立VPN通路
  2. 要考虑到对forward数据包的支持,否则就没有必要使用三层VPN了,使用应用层 VPN即可
  3. 隧道的概念。隧道其实就是VPN链路两个端点之间的加密通路,其中封装着加密后的原始IP数据报

确定了VPN链路的端点以后,就可以根据上述的3种方式进行加密/封装,解密/解封装的操作了,也就是说,修建一条隧道。具体的方案如下:

方案1:采用netfilter的方式

这种方案部署起来比较简单,因为端点的两台设备是对称的,netfilter钩子会处理IPSec协议逻辑。成型的项目有Freeswan等,具体细节参见《FreeSWAN 结构框架》

方案2:虚拟网卡+udp

这种方案在端点两端的加密/封装,解密/解封装是不对称的,其中加密/封装这步操作在虚拟网卡完成,解密在recv逻辑中完成,解封装在send逻辑中完成。成型的项目如cipe等。数据通路实际上就是虚拟网卡的方式和导出到用户态方式的结合

1-6-1-1-4

设计要点:

  1. VPN隧道终点使用UDP端口区分了不同的IP安全通道,而不需要采用IPSec的方式;
  2. 为何不用TCP呢?因为会引起重传叠加导致网络不可用,详见CIPE的作者所做:《Why TCP Over TCP Is A Bad Idea》。同样的规则在后续的OpenVPN中依然如此,详见OpenVPNman手册中的--proto选项
  3. 加密在内核态,解密在用户态-使用UDP,之所以这样的不对称法是因为UDP端口是可以从客户端“连接(访问的含义)”的,不同的UDP端口就可以区分出来自不同地点的IP安全通道。这种方案依赖于,安全隧道总是由外部(位置不确定的互联网的任意一处)先发起建立请求。后面的OpenVPNC/S模型也有赖于这个事实

1.6.1.2 VPN类型

VPN按照网路通路区分划分为如下两种:

传输模式VPN

传输模式的VPN只加密数据,不构建隧道,也就是只实现数据安全。如下图所示

1-6-1-2-1

隧道模式VPN

隧道模式的VPN不仅加密数据,而且构建隧道,也就是说实现网络层次PDU的封装。如下图所示

1-6-1-2-2

VPN按照认证方式区分可以使用不同的协议承载方式:

PPPoE

严格来讲,这不是一种VPN,而只是一种接入方式,它只是实现了在以太网上承载ppp包。虽然它不属于VPN的范畴,然而却能表现隧道的思想,所谓隧道无非就是第m层的PDU用一种特定的隧道协议承载第n层的PDU,思想如下图

1-6-1-2-3

L2TP

L2TP是一个协议,使用这种协议的VPN用拨号来进行认证。如下图所示

1-6-1-2-4

SSL VPN

这种VPN使用证书,密码等SSL认可的可配置的方式进行认证。它不一定是第四层VPN,也不一定是第七层VPN,而只是强调它使用SSL协议实现认证以及密钥协商等安全策略。本文推崇的VPN也就是使用虚拟网卡实现的ssl vpn

1.6.2 进一步的讨论

1.6.2.1 问题

到此为止,VPN的两个首要工作都得到了解决,使用虚拟网卡,recv,或者netfilter抓住IP数据报,然后直接加密,也就是加密/封装和解封装/解密。但是加密的标准以及加密方式我们还没有涉及,理论上,任何加密算法都是可以对IP数据报进行加密的。

实现VPN有多种方式,标准的方式是使用IPSec协议(ESPAH等)来实现的,IPSec是一个封装第三层数据报的协议集,也可以理解成一个第四层协议集,和tcp/udp等是完全并列的tcpudp的协议号分别为6和17,而espah的协议号分别为50和51。总之IPSec协议集旨在第三层将数据直接进行加密/解密,要支持IPSec无疑需要对协议栈进行修改,在Linuxnetfilter可以完成此任务,Freeswan正是这样实现的IPSec

然而在内核态通过修改协议栈的实现方式很不灵活,配置起来也是比较复杂,如果能在用户态实现数据报的加密/解密就比较好,这是完全可行的,因为IPSec协议集和TCP/UDP一样也是第四层协议,完全可以用tcp或者udp来承载加密后的数据。既然使用虚拟网卡可以方便的拿到IP数据报,那么就可以想办法导出到用户态,然后加密/解密后再发出去

1.6.2.2 tap虚拟网卡

到此,我们明白IPSec只是加密/解密的支撑协议,和加密/解密没有关系,并且这种方式对于配置和实现来讲都不是很灵活,当然,这里先不考虑性能因素。既然IPSec只是支撑协议,那也就是说只要能实现加密/解密,并且能实现将封装后的数据报传输到VPN链路的对端就可以了。可是,又如何将虚拟网卡抓取的ip数据报导出到用户态呢?

前面提到,使用虚拟网卡抓取IP数据报和使用替换socketsend/recv函数抓取数据报是矛盾且互补的,因此它们的结合对于封装和解封装的实现是不对称的

tap网卡的出现带来了福音。tap网卡在实现一个虚拟网卡的同时也实现了一个字符设备,在虚拟网卡的xmit函数中直接将未加密未封装的原始IP数据报放到字符设备的输入缓冲区,然后用户态进程就可以从该字符设备读取到ip数据报,用户态进程只需要将之加密,然后通过socket发出即可,借助协议栈完成原始ip数据报的封装。数据到了对端,用户态进程从socket读取到的就是加过密的原始ip数据报,因为协议栈已经自动解封装了,然后将之解密后写入虚拟网卡字符设备即可,此时,虚拟网卡字符设备模拟中断CPU,从而虚拟网卡调用接收函数

因此,最终我们有了方案3:

1-6-2-2-1

采用这个模型的开源项目有很多,它们都基于一个很简单的demo程序:simpletun。在simpletun的基础上,衍生了VTunOpenVPNOpenssh's VPN等项目。

1.6.2.3 安全策略拓展

到此为止,VPN的通路问题解决了,其中最漂亮的方案就是使用tap网卡。可是加密/解密算法,认证算法等还没有涉及。和解决通路问题一样,处理安全策略也有很多的方案:

方案1:使用 IPSec 协议集以及 IKE 机制

这个方案其实就是IPSec的方案,无疑,这种方案对使用tap网卡是有限制的,因此很多情况下都是直接在内核实现。详情参见相关标准

方案2:编写用户态进程,实现可配置的安全策略

这个方案比较笼统,但是它却是最灵活的。最简单的方式,实现一个通过参数配置加密算法的程序,比如 VTun所作的那样,然而VTun对于身份认证和算法及密钥支持比较弱。最终人们想到了SSL协议。
SSL协议可以保证通信的保密性和可靠性,它使用公钥技术,支持安全且灵活的认证机制,常见的有使用X509证书的认证。SSL协议本身就包含密钥协商,因此相比IPSecIKE要简单的多。正是 tap虚拟网卡和SSL的结合,才带来了VPN技术的革命!tap网卡和SSL是缺一不可的,虽然 VTun使用了tap网卡,然而它没有使用SSL协议,这就直接阻碍了它的进一步拓展,而cipe则更是一个中间过程,它的安全运算全部在内核态完成,根本无法使用SSL协议。OpenVPN是这个革命的一个产儿

OpenVPN的基本要素有以下几点:

  1. 可配置的认证方式
  2. 可配置的加密算法,密钥协商
  3. 可插拔的插件机制
  4. 自动的策略推送机制-包括客户端的虚拟网卡的ip地址
  5. 集中的管理功能
  6. 灵活的外接程序
  7. 强大的日志输出功能

下面是OpenVPN的实现示意图

1-6-2-2-2

1.6.2.4 方案对比

对比IPsec虚拟网卡----通路方案选择

  1. IPSec的通路方案是在网络层直接修改IP数据报实现封装,然后直接交由路由模块重新路由。IPSec对原始IP数据报的封装是直接在网络层完成的(虽然逻辑上IPSec属于第四层)
  2. 虚拟网卡方案利用了这样的一个事实,即可以通过路由的方式将IP数据报导入虚拟网卡,另外从虚拟网卡接收的IP数据报也可以通过路由的方式导出到本机或者其它物理网卡。虚拟网卡对原始IP数据报的封装是利用标准的TCP/IP协议栈完成的(想使用标准协议栈封装数据报,则必须将原始IP数据报放回到协议栈的顶端,即socket层,然后随着数据在协议栈中往下流动,封装过程自然完成)。
    • 虚拟网卡的副作用:由于虚拟网卡也是一个起始于链路层的网卡,因此可以为之配置网络层地址,即IP地址,出入虚拟网卡的数据和出入物理网卡的数据一样受到所有TCP/IP协议栈语义的约束,因此也就可以通过虚拟网卡很简单地实现一个虚拟的局域网,虽然在物理上虚拟局域网内的设备可能相隔千里。正是这一点使后来的OpenVPN可以很简单的实现 client2client。
  3. 总结:无疑,虚拟网卡的方案没有IPSec的方案更直接,因此效率上也会大打折扣,在这一点上考虑,IPSec的方案要胜出。

对比IPSecSSL----安全策略方案选择

  1. IPSec定义了一整套内置的以及可外挂的安全策略协议,包括ESPAHIKE等,这些协议的操作全部在网络层完成
  2. SSL是一个安全套结字协议框架,通过Cipher Suit可以灵活配置认证以及加密,摘要算法,这些操作全部在表示层和会话层完成
  3. 总结:虽然IPSec是一种自然而然的方式,然而可供选择算法非常有限,并且配置很不灵活,因此 SSL相比IPSec的安全协议集无疑会胜出

综合对比IPSec虚拟网卡 + SSL

在数据通路和安全策略上,VPN更加关注的是安全策略,数据通路对于VPN来讲是完全透明的,而安全策略则需要是高度可定制的,除非在效率要求很高的需求下,虚拟网卡 + SSL 的方案要略胜一筹。以下只给出IPSec虚拟网卡 + SSL的数据封装框图:

IPSec的方式

1-6-2-4-1

虚拟网卡 + SSL

1-6-2-4-2

1.6.2.5 使用netfilter的引申

netfilter是一个很优秀的框架,它设计的5个HOOK点真的是恰到好处,因此我们可以围绕它做出几乎所有和协议栈相关的东西。包括虚拟网卡的功能也是可以通过netfilter完成的。也就是说,不再需要虚拟网卡了,这样既实现了用户态的安全策略,又不需要虚拟网卡,也就是下面这张图所显示的,仅以 forward出口包为例

1-6-2-5-1

作为对比,列出虚拟网卡的方式:

1-6-2-5-2

1.6.2.6 Linux 的其它可选方案-GRE + ESP/AH

将这节内容放到最后有点过分了,因为这节的内容对于linux上实现VPN而言实在太重要了

有很多成熟的方案可以实现VPN,特别是建立VPN隧道,其中最方便的VPN通路建立方式当属GRE隧道了,并且GRE也是一个相当成熟的隧道协议。因此使用GRE隧道技术可以方便的铺设隧道

其次,在Linux的2.6内核中,出现了一个新的框架,这就是xfrm

xfrm is an IP framework, which can transform format of the datagrams,i.e. encrypt the packets with some algorithm. xfrm policy and xfrm state are associated through templates TMPL_LIST.This framework is used as a part of IPsec protocol.

使用xfrm来实现IPSec要比使用netfilter来得更直接,因为xfrm是内嵌在协议栈内部的,而不是像netfilter一样外挂在外部的

xfrm通过注册一个struct net_protocol使得ESPAH在第四层协议中有了名分,毕竟 struct net_protocol就是一个协议栈第四层的操作例程集合,正如tcpudp拥有 tcp_protocol以及udp_protocol一样,espah也有esp4_protocolah4_protocol(暂不考虑IPv6)。如此xfrm以一种直接的方式在标准的协议栈中处理IPSec数据包,正如下图所示:

1-6-2-6-1

可见Linux使用xfrm框架(其中为esp/ah等实现了两个传输层的封装机制,且可以外挂其它机制,比如基于5元素的策略查找等)实现了逻辑上的IPSec安全策略,该框架包含两大部分:

  1. 将IPSec安全协议集注册在传输层
  2. 修改路由模块,加入策略检查逻辑,实现出口数据包的基于策略的捕获,然后将其导入传输层实现安全协议封装

然而VPN的另一大特性,也就是隧道的实现却另有其人,那就是GRE模块(体现为ip_gre)。本质上,GRE网卡和虚拟网卡的思想是一样的,只不过其使用一个标准协议,即GRE来封装网络层数据报。GRE的关键在于网络的互通,比如它能将ipx封装在IP中,从而实现跨协议通信

1.6.3 网络层 VPN 技术发展阶段

1.6.3.1 完全内核态的 IPSec 实现阶段

这是官方的VPN建议,其背后有着强大的协会和组织以及商业机构。代表作有cisco3com等厂商的核心安全设备,以及开源届的freeswan。Linux 2.6内核中内嵌了xfrm框架,该框架以一种直接的方式而不是netfilter这种间接过滤的方式可以方便的实现IPSec。然而使用者却没有因为这种实现的方便性而增多,关键还是在于其配置的不灵活以及协议的封闭

1.6.3.2 半虚拟网卡阶段

只实现了发送例程而没有实现接收例程的虚拟网卡,导致没有实现接收例程的原因是这个时候还没有虚拟网卡的字符设备,无从接收数据。cipe是这个阶段的代表作。在cipe的实现中,替换socketsend/recv例程并不是必要的,因为原始的协议栈对待从上到下的数据只是封装,对待自下而上的数据是解封装,如果不替换send/recv例程的话,数据到达用户态再发出去时就被封装成了本地出发的数据包了,而我们需要的是只解除隧道封装,而不再封装本地的信息,实际上,对recv的替换倒不是必须的,因为在recv中只处理了解密操作,而在用户态也可以做,不过既然加密是在内核做的,解密也在内核做比较好,其中效率是一大原因。之所以如此复杂,是因为这只是半虚拟网卡

1.6.3.3 全虚拟网卡阶段

虚拟网卡实现了一个字符设备,完全对称的实现了全虚拟网卡,不但具有发送例程,还有接收例程,这样就可以完美的在两台主机的两个虚拟网卡字符设备之间架设一条“虚拟物理线路”,分别处在两个主机上的两个进程中的一个只需要处理虚拟网卡字符设备和本地socket之间IO数据的处理/转发即可。这种方式将安全策略完全解放到了用户态,为OpenVPN的革命性进展开辟了道路。值得注意的是,此阶段的VPN还是将注意力集中在网络通路上,毕竟安全策略刚刚从内核解放出来。代表作品有VTun

1.6.3.4 SSL+全虚拟网卡阶段

虚拟网卡加上SSL协议给软件 VPN带来了一场革命,不仅仅是这种结合方式,而是这种结合方式之外的扩展功能才是亮点之所在。毕竟VTun也使用了虚拟网卡,其模式和OpenVPN并没有什么太大的不同,然而正是SSL协议给这种结合方式带来了新的活力,就像一剂猛药瞬间激活了最具扩展性的 OpenVPN。细解OpenVPN,发现它是如此的简单,实际上它在简单的背后映射了不简单的道理。如果我们细解牛顿三定律,也会发现它不过是伽利略理论的总结,正如OpenVPN不过是VTun加上一些标准化的安全拓展是一样的道理。实际上,所谓的革命本是不存在的,人们普遍将量变引起质变的点当成是革命,而事实上,只要有一个矮人站到巨人的肩上,那他也会比巨人更高大!

1.6.3.5 最终权衡

由于半虚拟网卡只是到达全虚拟网卡的过渡,因此这里不考虑半虚拟网卡,另外全虚拟网卡方案中的 VTun也只是到OpenVPN的过渡。而基于IPSecVPN受到各方面的限制也不予考虑,再者,VPDN的应用场合也有限制,也不予考虑。最终我们只剩下了基于虚拟网卡的SSL VPN,当然正如 OpenVPN官方网站所说,OpenVPN相比IPSec所欠缺的就是各个操作系统的原生支持,虽然 OpenVPN的设计非常优秀,但是在标准化方面还是比不过IPSecIPSec的成功,和诸如 Cisco 等公司的推波助澜是分不开的,我们知道,第一流的公司做标准,第二流的公司做品牌,第三流的公司做产品,因此标准化是很重要的。在Windows上,如想用VPDN,基本直接就能支持,然而想使用 OpenVPN,则必须安装客户端。另外效率问题也是OPenVPN的劣势,然而这不是根本的劣势,技术上的问题终究是可以得到解决的

1.6.4 Linux VPN 软件选型

IPSec的实现:freeswan

虽然IPSec的侧重点在性能和安全性,然而事实上在Linux中,Freeswan的效率并没有想象的那么高,因为它是netfilter实现的,而netfilter将会过往的每一个数据包进行判定,这会严重影响效率。Freeswan的优点在于其实现的标准性。Freeswan在2.6之前的Linux内核中使用的更加广泛一些,因为2.6内核有了更好的IPSec方案–Xfrm。另外,由于政治原因,Freeswan的推广受到了很大的限制

cipe

效率很高,然而配置不灵活,且只支持单通道

vtun

效率很高,支持多客户端,每个客户端一个进程处理。配置也很丰富,然而缺乏更高级的安全策略的支持,正如其文档中所说的那样

OpenVPN

具有革命性的VPN实现,支持多客户端,支持client2client。然而其效率却不是很高。OpenVPN的灵活性及安全性蕴藏着巨大的收益,并且其实现的对称性和简单性吸引了大量的开发者,最终开发出了各个平台的版本,这正体现了OpenVPN的强大。反观VTun,直到现在,它也不支持Windows版本,并且2007年就停止了开发

应用层VPN

这是应用级别的VPN,诸如代理软件,翻墙软件都属于这种范畴,它保护特定的主机,特定的应用,因此对于个人接入拥有很大的优势,它可以得到更多的应用层的用户信息,这是网络层的VPN所无能无力的。然而如果你希望使一个网络安全的接入另一个网络,那只能选择1到4的方案了

1.7 VPN 技术漫谈之 IPSec(附MPLS)

本小节转载自VPN技术漫谈之IPSec(附MPLS)

1.8 TCP 封装的隧道对于拥塞控制的意义

本小节转载自封裝的隧道對於擁塞控制的意義

1.8.1 一些词汇和短语的解释

正常传输队列:从应用层来一个数据包,该数据包就会被TCP封装,然后加入正常传输队列末尾

重传队列:在正常传输队列中每传送一个TCP分段,该分段就会加入重传队列末尾

正常传输TCP会视传送视窗的大小以及视窗的可用性从正常传输队列头取出一个TCP分段,然后传输

超时重传:从重传队列头取出一个TCP分段,重传之

快速重传:从重传队列头依次取出一个个可能丢失的TCP分段,重传之

避免不必要重传:在快速重传中,如果已经重传了可能丢失的TCP分段,理论上讲,按照标准,接下来会依次重传重传队列后面的所有TCP分段,然而如果是由于ACK丢失,这样的重传就是冗余的,由于正常传输队列和重传队列是分开的(重传队列和传送队列分离设计),此时传送正常传输队列中的当前可以传送(没有视窗限制和Nagel限制)的TCP分段可以有效地“带回一些ACK”这些ACK会清除重传队列里的TCP分段。因此根据这个策略,不必要的重传实际上是很少的。背景流量:如果一条IP层链路上封装了一个隧道,所有非隧道的流量都是背景流量

1.8.2 TCP隧道的问题

1.8.2.1 TCP拥塞控制的意义

注意,TCP本来是不包含拥塞控制的,但是因为它是端到端的协议,并没有执行于任何网路节点,因此裸TCP对于频宽是极其贪婪的,和UDP一样,当网路拥堵以后,TCP就加入了拥塞控制。然而端到端的协议并不仅仅就是TCP,虽然TCP加入了拥塞控制,可是UDP并没有,UDP本来就不关心丢包,网路拥塞了,丢包就是了。然而,UDP是情愿丢包也不进行拥塞控制,这确实是连累了TCP,结果就是TCP频繁的进入拥塞状态,不断的慢启动或者快速重传,导致TCP流量的颠簸,虽然诸多TCP流量都不断的徘徊在锯齿的峰谷之间,显得很公平,然而对于总体的频宽,在存在没有拥塞控制机制比如UDP流量的情况下,TCP的效能将急剧下降

因此整个频宽对各个端到端协议流量的分配是不公平的

1.8.2.2 TCP公平性

TCP的拥塞控制内在的实现了公平性,大家都会对拥塞快速反应。如果所有流量都是TCP,那再好不过了,频宽可以得到完全公平分配

1.8.2.3 并不是所有的流量承载于TCP

然而,还有很多协议是没有拥塞控制的,比如UDP,大量贪婪的流量瞬间挤满整个通路,虽然大多数贪婪流量被丢弃了,然而传送端并不在乎,仍然继续快速大量传送,结果导致对丢包很在乎的TCP进入拥塞状态,TCP的退出,导致UDP流量不再被丢弃,结果,整个通路长期保持拥堵状态,TCP流量很难有机会再获得公平频宽,直到UDP流量的退出

1.8.2.4 需要做的工作

现在怎么办?难道为UDP加入拥塞控制吗?这样不妥,那样对实时要求很高的UDP应用影响太大,因此需要一种更为温和的方式解决这个频宽在不同型别端到端协议之间的不公平分配问题

这种温和的解决方式就是TCP隧道,简而言之,就是在核心网路的容易拥堵的三层链路的两个路由器之间部署一条TCP隧道,封装所有的流量,包括UDP的流量,这样,起码在该段通路上,频宽分配公平了,特别是,如果仅仅部署一条TCP隧道(所有流量通过该隧道)的话,排除中间路由器排队/路由处理的影响,拥堵是不会发生的

1.8.2.5 TCP隧道导致的重传叠加

现在考虑一个问题,那就是TCP隧道之上的载荷也是TCP流量,这样的话,恰好TCP隧道上发生拥堵而丢包,这种情况下,载荷TCP超时也在预料之中,因此会发生重传叠加,事实上,我们知道,载荷的重传是不必要的,因为隧道是TCP的,所有的丢包都会得到重传。

我们可以把TCP隧道封装的一条网路通路想象成一个路由器,在该路由器中,只要得到排队的资料包都会安全可靠到达输出埠,在路由处理过程中不会丢包。这也许不太符合真实的路由器,因为真实的路由器中在路由处理的过程中很有可能发生错误的。既然是这样的话,我们就知道,一旦在这个虚拟的路由器中发生丢包,端TCP系统是不需要重传的,然而事实是,端到端的TCP协议永远都不知道是什么原因导致了丢包,并且更不知道丢包发生在哪里

部署TCP隧道的时候需要做什么?很简单,就是尽量避免隧道的丢包,可以理解为不要让隧道和其它流量竞争频宽,那么可选的方案只有一个,就是部署TCP隧道的通路最好不要再有其它的流量,也就是不要拥有背景流量!

TCP是一个端到端的有连线的可靠传输的协议,它作为尽力而为的IP协议的载荷而存在,如果它跑在TCP之上的话,就会造成重传叠加,这样的话很多重传将是不必要的,因此从设计的角度看来,分层模型之间的功能最好不要重合

1.8.2.6 TCP隧道导致的延迟增加

部署良好的TCP隧道虽然对于频宽的公平性有很好的促进作用,然而却会导致单个资料包延迟的增加,这个延迟的增加具体是什么原因导致的呢?其实很简单,那就是在TCP隧道的入口处,TCP分段要作为TCP载荷被封装,这个时间实际上完全是CPU完成的,这是延迟增加的原因。当然延迟虽然增加了,也不完全是坏事,后面我们会看到,通过TCP隧道的速率匹配,可能做到最大化吞吐量,毕竟,吞吐量和延迟总是满足反比律的

1.8.3 有效利用TCP隧道

事情并不是想象的那么坏到了极点。这是因为还有比TCP更坏的,几乎所有的端到端协议都比TCP更可恶,因为它们都比TCP更贪心,所有的端到端协议都以为整个频宽都是自己的,而TCP起码还做了拥塞控制使得整个网路使用者更加公平。既然如此,我们需要有效的利用TCP的这点优点

1.8.3.1 有效利用公平性

载入拥塞控制机制的TCP的优点就是公平性,然而UDPTCP们共享统一网路通路,却没有对拥塞进行反应,这样导致了网路频宽分配的严重不公,大量UDP流量会瞬间吃掉所有频宽。因此一个好的解决方案就是将UDP(以及其它所有的没有拥塞控制的端到端协议资料)封装在TCP隧道中。TCP隧道在中间路由器上增加了容量适配功能我们知道,在单一连线的链路上,延迟和频宽的乘积表示了该链路的容量,如果能始终保持链路的满载,那无疑是对网路频宽的最有效的利用,可惜的是,端到端的TCP并不能做到这一点,因为端到端之间要经过无数的二层链路,经过无数的路由器,往往中间的核心网路频宽是很大的,然而端系统的TCP却不可能认识到这一点,最有效的措施是在核心网最容易拥堵的链路上部署一个TCP隧道,以及在核心网容量差别最大的两条相邻链路之中的大容量链路上部署一条TCP隧道,这样该TCP隧道就会起到容量匹配的作用

然而事情并不是这么简单,这个TCP隧道的构建是有要求的,事实证明,它的出入口快取的容量达到该链路的延迟和频宽乘积,那将是最高效的

1.8.3.2 TCP隧道减少了拥塞控制起作用的频率

TCP隧道显式的减少了流的数量,在构建了两条TCP隧道且没有背景流量的情况下,原来N个流量的频宽竞争现在成了两个TCP的竞争。更可贵的是,原来的N个流量中可能还有UDP流量,它会吃掉几乎整个频宽的哦!现在公平了,只有两个TCP,完全履行拥塞公平的原则。可见TCP隧道缩小了竞争者的数量,并且消除了贪婪者,是一个化干戈为玉帛的利器

我们知道,TCP隧道本身封装了N个流量,它们之间的频宽分配是不加权的,要想实现N个被封装流量频宽的加权分配,最好的办法是按照协议型别对TCP隧道进行一些配置,比如UDP流量封装在一个TCP隧道中,TCP流量封装在另一个TCP隧道中,然后对排队规则进行配置,比如实时优先顺序高的UDP优先排队,或者同一TCP隧道中的统一端到端协议的不同流量按照路由器的配置进行加权排队等等

1.8.3.3 强制措施

虽然TCP隧道可以解决网路频宽分配不公的问题,然而并不是所有人都能部署TCP隧道的,作为一种实验,在实验室可以随意配置,然而作为一种实施,你就必须依赖政府和运营商。ISP或者政府需要对整个核心网路规划十分了解,这样它们便知道在哪里部署TCP隧道了,更为重要的是,只有它们可以触动核心网路的配置,只有它们有权力这么做

1.8.3.4 部署TCP隧道

我们知道,只有一个TCP连线的链路(也没有中间路由器)是没有拥塞的,因此总是能期望其资料传输最终使网路满载

因此需要在流量很杂,UDP特别多的拥堵链路上部署TCP隧道,这样所有的流量就进入了一个隧道,为了避免UDP撑满整个隧道,有时需要部署两条TCP隧道,一条专门用于UDP,另一条用于别的,这样,UDP流量也要接受拥塞控制了。如果实现了解不用很惯着UDP,那么就可以只部署一条TCP隧道,这样的话,可以消除大部分的堵塞事件

1.8.4 效能

1.8.4.1 Selected ACK的意义

选择重传实现了一种机制,可以只重传丢失的TCP分段,并且只要不是连续丢包就不用等待超时,只要接收端都到乱序分段就会在ack中附带sack资讯,这样即使TCP隧道的丢包也会得到快速的选择重传,这种重传仅仅是TCP隧道两端的,远远比端到端的链路距离要短很多,这样端系统感知到的拥塞将会大大减小,减少了端系统TCP重传的次数,同时也提升了传送速率,因为进入慢启动的机会少了

1.8.4.2 TCP隧道的缓冲区大小的意义

频宽,延迟的乘积表示了一个网路链路的容量,如果希望能获得很大的吞吐量和较小的延迟,保持整个链路容量满载是最有效的,然而要想避免拥塞,使TCP的拥塞控制不起作用,那么只能保持仅有一个TCP连线的状态,这样TCP的端到端的流控机制最终会使链路满载的。虽然由于可恶UDP流量的存在,不可能只部署一个TCP隧道,也就是说,最终TCP的拥塞控制还是会起作用,其时间-视窗图可能还是会出现经典的锯齿状,然而实验表明,保持TCP隧道入口缓冲区大小等于频宽、延迟的乘积的话,还是会得到最大的吞吐量

可以想象,在这个场景下,TCP隧道起到了容量适配的作用。否则,仅凭各个TCP端使用者疯狂在网路上争抢频宽,大量频宽将浪费在大量TCP使用者拥塞控制导致的锯齿下尖角的位置

1.8.4.3 TCP隧道对IP分片的影响

一旦由于MTU的影响,IP资料包分了片,一旦分片丢失,如果其上的载荷是TCP,那么将会导致端系统的TCP重传,在一条长长的且MTU变化很大并且还有点拥堵的三层链路上,IP分片很容易丢失,只要丢失一个分片,IP将不能重组,TCP分段也会玩完,在这种链路上,这很可能发生,如果只有1个资料包那么其丢失造成TCP分段不能接收的可能为10%,如果该IP资料包分了10个片,那么只要有一个分片丢失,那将造成同样的结局,毕竟IP是尽力而为的,这个资讯最终会反馈到端TCP系统,如果在这种链路上的MTU突变造成分片的链路上部署一条TCP隧道,那么将把到达稳定链路的跳数减少为1跳,有效遮蔽了MTU突变造成的IP分片且丢失的影响

记住,TCP隧道两端的路由器和中间的链路组成了一个虚拟路由器,该路由器只要资料排队就不会丢包,是一种名副其实的工业级路由器!TCP隧道的存在使N跳变成了1跳,好事!

1.8.5 影响TCP隧道效能因素

1.8.5.1 TCP隧道的实现

这是一个很重要的因素,因为TCP隧道的实现有很多的方案,诸如OpenVPN的方式是一种很低效的实现,因为它是基于socket的,而socket是一个使用者介面,它作用于端到端的系统,对于核心网行为的理解是很片面的,因此OpenVPN只能面对TCP隧道的问题而抛弃它(但是在udp被封堵的时候仍然支援它),OpenVPN始终没有认识到TCP隧道的优势,根据设计需求,它没有必要认识到

更高效的实现方式是在核心协议栈中直接实现,像IPsec一样,对于Linux而言,这是很高效的,因为可在软中断中完成一切TCP隧道载荷的封装和解封装,避免了端系统程式排程系统带来的悲哀

1.8.5.2 有没有背景流量

存在背景流量将是可悲的,如果背景流量是UDP的话,那将是致命的,本来NTCP流量和UDP是并列的,然而NTCP流量被封装了,即使这样,单独的UDP流量也可能吃掉频宽,因此部署TCP隧道的时候,一定不要UDP背景流量的存在,将它们封装在一个单独的加权值比较低的TCP隧道中是一个好方法。只要没有背景流量,tunnel是可靠的,一旦有背景流量,在TCP隧道中丢包,就会出现重复的重传叠加

1.8.5.3 原始链路的性质

如果原始链路本来就不拥堵,那么TCP隧道是没有意义的,只有在原始链路很拥堵或者背景流量很大的情况下,才要部署TCP隧道

1.9 VPN 的概念及要点

本小节转载自

1.10 SSL VPN 和 IPSec VPN 的区别以及部署

本小节转载自SSL VPN和IPSec VPN的区别以及部署

SSL VPNIPSec VPN的区别是什么,如果你希望找到答案,随便用一个搜索引擎,当你输入SSL VPN后按一个空格,智能联想就会帮你填充IPSec,可见很多人都在找两者的区别。找这两者的区别的目的是进行一个选择,到底用SSL VPN呢还是用IPSec

话说SSL VPN越来越多,背后的一大原因是web应用越来越多,如果能使用http,那就不再开发自己的协议,如果能使用浏览器,那就不再开发自己的客户端,应用研发人员集中力量实现应用的原始逻辑,而不必再考虑开发通信协议以及开发客户端之类的事情,现在基于web的B/S应用中,这些都减小了。SSLVPN什么?实际上它就是一层B/S应用的防弹衣,保护壳,它加密了明文http流,它认证了浏览器端的操作者和应用服务器双方,它使用一个称为SSL协议的东西实现了认证和加密,保证了B/S应用的安全,这就是SSL VPN的本质

你要知道,这个世界上,服务器永远比客户端多,考虑到安全部署的守恒定律,否则你把安全设施部署在服务器上,或者部署在客户端,而实际上,大多数情况下都要部署,问题是如何使部署成本最低,有了结果以后,到底是使用SSL VPN还是使用IPSec VPN就有了答案

能少安装一个客户端,能少进行一次文件复制操作,能少一次安全系统初始化时的网络通信,能少一次为了解决客户端问题而安排的出差,成本就相应降了下来,SSL VPN将客户端问题转嫁给了网络浏览器,而网络浏览器为何旅途这趟浑水呢,正是因为标准化导致的,如果微软的IE支持了SSL,那么火狐为了生存就必须支持SSL,反过来也一样,因为大家都想用SSL,60%的用户可以左右市场的发展,促进协议的标准化,浏览器必须支持SSL,如果浏览器厂商拒绝这样做,马上就会有一家小公司甚至车库公司,咖啡厅公司瞬间跳出来,然后一年后,它就成了巨大的公司,微软,苹果,包括沃尔玛不都是这么起来的么?

SSL VPN就这样将成本转换嫁给了浏览器和应用服务器,一旦出了问题,重新安装证书,换个浏览器,甚至重新安装一次系统,或者找自己证书的提交者说事,用户最大化的去IT

对于应用服务器端也一样,其只需要部署一次就够了,除了会出现单点故障之外,这种集中的部署方案成本降低到最低,服务器端一般都会养着几个IT管理员,系统管理员和网络管理员可以最短时间解决各种问题。对于单点故障问题,也可以通过高可用性或者分布式积累来解决之门

如果对于OA这样的系统,SSL VPN再合适不过了,它可以让休假在家,出差在外的人员访问OA,在任何地方都无所谓,火车站,咖啡厅都可以,哪怕随便借一个电脑,哪怕在网吧,你只需要随身携带你的数字证书,随时随地访问,而这是IPSec处理不到的,如果你在一家公司的内网,需要访问自己公司的OA,你所在的这家公司防火墙可能封堵了GRE隧道以及其他隧道,此时你必须找到这家公司的网管去协商,而此时网管正好不在。然而httphttps以及mail几乎是不封堵的,因为它们是互联网的窗口

在部署上,SSL VPN是不对称的,服务器端的部署成本稍微有些,但是集中的管理会倾斜掉这种部署成本。相反,IPSec VPN在部署上是对称的,这并没有什么值得奇怪的,本来SSL VPN就工作在应用层,对于应用层的应用,大多数是分为客户端和服务器端的,对于服务器和客户端,它们本来就不对称,而对于IPSec,它工作在IP层,IP层提供了数据报分组交换服务,它完全不区分客户端和服务器,它转发每一个数据报,完全没有状态记录,因此IPSec VPN本质上需要在外网端点和接入网两端花费同样的部署成本,这样做有时候很麻烦,但是有时候是必要的。

考虑到一个公司两个分部之间的网络互连,IPSec VPN就是首选的。因为需求是网络的互连,而不是具体应用的安全访问。网络互连的核心在IP协议,而IPSec VPN正是提供了IP层的安全。如果互连双方是对称的分区,那么部署IPSec是值得的,但是如果双方不对称,则需要大量散客连入公司内网的特定应用时,这是部署IPSec VPN是很不明智的,姑且不说需要在这些散客电脑上安装客户端,仅由于他们完全连入了内网,因此需要内部网另外部署复杂的权限系统来限制这些散客对未授权应用的访问,此时如果他们使用SSL VPN,全网的权限系统就不是很必要了,只需要PKI体系就能搞定。另外散客分布在各处,对这些散客的客户端的管理和排错也是一件令人惊奇头疼的事

对于IPSec VPN,如果仅仅需要部署一台硬件网关加密分区的所有可视化流到远端内网,那就部署吧,千万要避免安全IPSec VPN客户端,实际上那台IPSec硬件网关也算是一个客户端,然则该客户端和较长的IPSec VPN服务器是一对一的,对于IPSec VPN,要避免多对一的部署,如果是一对一的部署,IPSec的效率更高。

对于SSL VPN,如何对非web应用进行兼容呢?要知道,目前很多的应用还都不是基于web的,而是tcp任意端口的,诸如qq,诸如RTX,等等很多的财务管理系统。这就需要做一个适应层,该适应层本质上是一个第七层的网关,它作为一个支持https的web服务器负责的web客户端和非web服务器之间的翻译,或者它仅作为一个支持SSLTCP代理,此时客户端还是可以使用原来的客户端,通过路由或重定向的方式和代理进行SSL连接,代理和应用服务器之间则进行明文通信。这种替代层网关目前很好买,也是以后发展的一个大方向。曾几何时,代理网关被淘汰了,而如今,作为SSL VPN的一个重要组成部分,它又起来了

如果为了应付Cisco或华为的考试,那么你要记住,IPSec VPNNAT不友好性,SSL VPN不需要安装客户端等,但是你如果是一个实施人员,那么这些就都变成教条,关键是看具体的需求,相似相容,这是个亘古不变的道理,对称的互联就是用IPSec VPNC/S的互联就是用SSL VPN,这条原则在大多数场合适用,当然,它也不能被当成教条

2 基本编译配置篇

2.1 OpenVPN 简易文档

本小节转载自OpenVPN 简易文档

2.2 OpenVPN - 2.1.1在windows上的编译

本小节转载自OpenVPN - 2.1.1在windows上的编译

2.3 Mac OS X上安装 OpenVPN

本小节转载自Mac OS X上安装 OpenVPN

2.4 OpenVPN 碰到 Windows-一些问题的解决

本小节转载自OpenVPN 碰到 Windows-一些问题的解决

2.5 OpenVPN 遇到的 Secondary 地址问题

本小节转载自OpenVPN 遇到的 Secondary 地址问题

3 源码分析篇

3.1 OpenVPN 的广播问题以及 tun 和 tap 设备的深层次挖掘

本小节转载自OpenVPN 的广播问题以及 tun 和 tap 设备的深层次挖掘

3.2 OpenVPN 中虚拟ip地址的自定义分配

本小节转载自OpenVPN中虚拟ip地址的自定义分配

3.3 OpenVPN 中虚拟ip地址的分配

本小节转载自OpenVPN 中虚拟ip地址的分配

3.4 OpenVPN 中虚拟ip地址的自定义分配–总结

本小节转载自OpenVPN 中虚拟ip地址的自定义分配–总结

3.5 OpenVPN 的日志记录头

本小节转载自OpenVPN 的日志记录头

3.6 使用 OpenVPN 时的问题–用源代码进行分析

本小节转载自使用 OpenVPN 时的问题–用源代码进行分析

3.7 OpenVPN 关于 push-peer-info 的实现

本小节转载自OpenVPN 关于 push-peer-info 的实现

4 协议篇

4.1 OpenVPN 协议解析-网络结构之外

本小节转载自OpenVPN协议解析-网络结构之外

4.2 OpenVPN 协议解析-握手数据包分析

本小节转载自OpenVPN 协议解析-握手数据包分析

4.3 OpenVPN 协议解析-通道/状态机/Reliability层

本小节转载自OpenVPN 协议解析-通道/状态机/Reliability层

5 高级路由篇

5.1 使用 OpenVPN 的桥接模式扩展内部局域网

本小节转载自使用 OpenVPN 的桥接模式扩展内部局域网

5.2 OpenVPN 的高级路由技术-内部路由

本小节转载自OpenVPN 的高级路由技术-内部路由

5.3 OpenVPN 高级路由技术-扩展成巨大的网络

本小节转载自OpenVPN 高级路由技术-扩展成巨大的网络

5.4 OpenVPN 高级路由技术-反向推送信息

本小节转载自OpenVPN 高级路由技术-反向推送信息

5.5 OpenVPN 的包过滤机制

本小节转载自OpenVPN 的包过滤机制

5.6 OpenVPN 高级路由技术-虚拟交换机和内部路由缓存

本小节转载自OpenVPN 高级路由技术-虚拟交换机和内部路由缓存

5.7 OpenVPN 高级路由技术-全面的互通性配置

本小节转载自OpenVPN 高级路由技术-全面的互通性配置

6 性能相关

6.1 OpenVPN 的效率问题

本小节转载自OpenVPN 的效率问题

6.2 OpenVPN 性能-数据采集

本小节转载自OpenVPN性能-数据采集

6.3 OpenVPN 性能-OpenVPN 的第一个瓶颈在tun驱动

本小节转载自OpenVPN性能-OpenVPN的第一个瓶颈在tun驱动

6.4 OpenVPN 性能-OpenVPN 的第二个瓶颈在ssl加解密

本小节转载自OpenVPN 性能-OpenVPN 的第二个瓶颈在ssl加解密

6.5 OpenVPN 性能-当tap遇到bonding

本小节转载自OpenVPN 性能-当tap遇到bonding

6.6 OpenVPN 性能-多 OpenVPN 共享一个虚拟网卡

本小节转载自OpenVPN性能-多OpenVPN共享一个虚拟网卡

7 功能实现

7.1 OpenVPN 的新钩子设计

本小节转载自OpenVPN的新钩子设计

7.2 让 OpenVPN 实现IKE似的两阶段密钥协商

本小节转载自让OpenVPN实现IKE似的两阶段密钥协商

7.3 返璞归真实现 OpenVPN 第二阶段协商

本小节转载自返璞归真实现 OpenVPN 第二阶段协商

7.4 完全在用户态实现 IPSec VPN

本小节转载自完全在用户态实现IPSec VPN

8 参考