阅读更多
本文转载自笑叶林-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
能在Solaris
、Linux
、OpenBSD
、FreeBSD
、NetBSD
、Mac OS X
与Windows
上运行,并包含了许多安全性的功能。它并不是一个基于Web
的VPN
软件,也不与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
点对点隧道协议(PPTP
)是由包括微软和3Com
等公司组成的PPTP
论坛开发的一种点对点隧道协,基于拨号使用的PPP
协议使用PAP
或CHAP
之类的加密算法,或者使用Microsoft
的点对点加密算法MPPE
。其通过跨越基于TCP/IP
的数据网络创建VPN
实现了从远程客户端到专用企业服务器之间数据的安全传输。PPTP
支持通过公共网络(例如Internet
)建立按需的、多协议的、虚拟专用网络。PPTP
允许加密IP
通讯,然后在要跨越公司IP
络或公共IP
网络(如Internet
)发送的IP
头中对其进行封装。
1.1.2.2 L2TP
第2层隧道协议(L2TP
)是IETF
基于L2F
(Cisco的第二层转发协议)开发的PPTP
的后续版本。是一种工业标准Internet
隧道协议,其可以为跨越面向数据包的媒体发送点到点协议(PPP
)框架提供封装。PPTP
和L2TP
都使用PPP
协议对数据进行封装,然后添加附加包头用于数据在互联网络上的传输。PPTP
只能在两端点间建立单一隧道。L2TP
支持在两端点间使用多隧道,用户可以针对不同的服务质量创建不同的隧道。L2TP
可以提供隧道验证,而PPTP
则不支持隧道验证。但是当L2TP
或PPTP
与IPSEC
共同使用时,可以由IPSEC
提供隧道验证,不需要在第2层协议上验证隧道使用L2TP
。PPTP
要求互联网络为IP
网络。L2TP
只要求隧道媒介提供面向数据包的点对点的连接,L2TP
可以在IP
(使用UDP),帧中继永久虚拟电路(PVCs
),X.25
虚拟电路(VCs)或ATM VCs
网络上使用。
1.1.2.3 IPSec
IPSec
的隧道是由封装、路由与解封装组成整个过程。隧道将原始数据包隐藏(或封装)在新的数据包内部。该新的数据包可能会有新的寻址与路由信息,从而使其能够通过网络传输。隧道与数据保密性结合使用时,在网络上窃听通讯的人将无法获取原始数据包数据(以及原始的源和目标)。封装的数据包到达目的地后,会删除封装,原始数据包头用于将数据包路由到最终目的地。
1.1.2.4 SSLVPN
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
模型中的数据链路层,使用帧作为数据传输单位。PPTP
和L2TP
协议属于第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
可以对IP
、IPX
或NetBEUI
数据进行加密传递。PPTP
通过PPTP
控制连接来创建、维护和终止一条隧道,并使用通用路由封装(GRE,Generic Routing Encapsulation
)对PPP
数据帧进行封装。封装前,PPP
数据帧的有效载荷(有效传输数据)首先必须经过加密、压缩或是两者的混合处理。
第2层隧道协议(L2TP,Layer Two Tunneling Protocol
)是PPTP
和第2层转发技术(L2F,Layer Two Forward
)的结合。第2层转发是Cisco
公司提出的隧道技术。为了避免PPTP
和L2F
两种互不兼容的隧道技术在市场上彼此竞争给用户造成困惑和带来不便,Internet
工程任务委员会IETF
要求将两种技术结合在单一隧道协议中,并在该协议中综合PPTP
和L2F
两者的优点,由此产生了L2TP
。L2TP
协议将PPP
数据帧封装后,可通过TCP/IP
、X.25
、帧中继或ATM
等网络进行传送。L2TP
可以对IP
、IPX
或NetBEUI
数据进行加密传递。目前,仅定义了基于TCP/IP
网络的L2TP
。L2TP
隧道协议既可用于Internet
,也可用于企业内部网。
为了实现在专用或公共IP
网络上的安全传输,安全IP
隧道模式IPSec
使用安全方式封装和加密整个IP
包。它首先对IP
数据包进行加密,然后将密文数据包再次封装在明文IP
包内,通过网络发送到接收端的VPN
服务器。VPN
服务器对收到的数据包进行处理,在去除明文IP
包头,对内容进行解密之后,获得原始的IP
数据包,再将其路由到目标网络的接收计算机。
在这三种隧道协议中,点对点隧道协议PPTP
和第2层隧道协议L2TP
的优点是对用微软公司操作系统的用户来说很方便学习,因为微软公司已把它们作为路由软件的一部分;缺点是PPTP
和L2TP
将不安全的IP
数据包封装在安全的IP
数据包内。PPTP
和L2TP
适用于远程访问虚拟专用网。安全IP
隧道模式IPSec
的优点是它定义了一套用于认证、保护私密和数据完整性的标准协议,缺点是微软公司对IPSec
的支持不够。IPSec
适用于可信的局域网之间的虚拟专用网,即企业内部网VPN
应用。
1.1.3 OpenVPN
典型的SSL VPN
应用如OpenVPN
,是一个比较好的开源软件。PPTP
主要为那些经常外出移动或家庭办公的用户考虑;而OpenVPN
主要是针对企业异地两地总分公司之间的VPN不间断按需连接,例如ERP
在企业中的应用。
OpenVPN
允许参与建立VPN
的单点使用预设的私钥,第三方证书,或者用户名/密码来进行身份验证。它大量使用了OpenSSL
加密库,以及SSLv3/TLSv1
协议。OpenVPN
能在Linux、xBSD
、Mac OS X
与Windows 2000/XP
上运行。它并不是一个基于Web
的VPN
软件,也不与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个层次),每一层都仅仅承载数据而不管数据的格式和内容,上下层次间仅仅通过接口和服务来通信,理论上任何层次的数据都可以被承载在其它的任何层次或者它当前的层次上,于是就出现了很多XX
overYY
的网络模型,比较典型的比如ppp over ethernet
等。
over
模型按照数据层次可以分为三类,第一类是上层数据承载于下层,这实际上就是我们使用的普通的TCP/IP
模型,第二类是同层承载,比如上面说的pppoe
,这一类构建方式主要是为了在一个以传输占主导的层次上增加一个非传输意义的逻辑或者说实现一个隧道,比如pppoe
中,ethernet
主要用于局域网传输,而且性价比十分合理,但是却缺乏认证机制,但是ppp
协议的认证功能虽然很好,但是却缺乏多点通信和寻址能力,作为传输协议意义不大,于是就使用ethernet
进行传输,使用ppp
进行认证,另外一个同层承载的例子是IPSec
的隧道模式,它将一个IP
数据报封装于另一个IP
数据报中,这样实际上也就实现了一般意义上的“虚拟局域网络”(注意不是vlan),因为在数据报到达最终目的地之前,参与路由的始终是外层的IP
头,内层的IP
头连同真实数据都被外层IP
当成了data
,因此不参与路由,所以从隧道的出发路由器到结束路由器,不管中间经过的是局域网,广域网还是别的什么,内层的IP
数据报一直“以为”自己在出发路由器的那个局域网内,因此就实现了一个虚拟网络,实现了VPN
中的V
,那么P
呢,IPSec
将V
和P
做到了一起,也就是说在实现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
协议还是可以用的。
难道VPN
就IPSec
这一根稻草了吗?认证和加密的逻辑十分复杂和多样,不适合在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
命令中搞定。数据流向见下图:
其实IP
网络本身就是一个虚拟的网络,任何不通过导线直接相连通信的网络都是虚拟网络,难道IP
网不是构建在各种局域网,广域网,电信网,电视网等物理网络之上的虚拟网络吗?按照分层的观点,pstn
都可以看成是虚拟网络,VPN
作为虚拟网络的意义更特殊罢了,而且实现的也各式各样,甚为巧妙。
ip over ssl
没有触动协议栈,也没有增加新的协议,利用SSL
的灵活性将IP
封装的更加安全了,SSL
比IPSec
要灵活得多,应用层的SSL
本身可配置性就比较好,不仅仅可以实现IPSec
中dh
密钥协商,还可以使用很多pki
的优秀特性。开源软件一向不会放弃任何优秀的东西,OpenVPN
就是用上述思想完成的,实际上OpenVPN
几乎没有做什么,就是一个整合,整合什么呢?通读代码发现就是配置虚拟网卡,配置路由,读写字符设备,用OpenSSL
的库进行SSL
协议封装,几乎全部都是现有的东西,然而经过OpenVPN
的整合就成了一个稳定又高效的VPN
软件。
1.5 VPN 原理及实现之TCP还是UDP
本小节转载自VPN 原理及实现之TCP还是UDP
有了ip over ssl
的关键思想,OpenVPN
就是一个必然结果了,于是就不多说了,OpenVPN
和OpenSSL
并不在一个层次上,虽然都很open
。OpenVPN
的配置非常复杂,主要就是为了建立更加合理的隧道,虽然IPSec
实现的 VPN
不区分客户端和服务器,建立sa
的时候全靠dh
对称的协商加密密钥和算法,但是基于OpenSSL
的OpenVPN
却区分二者,因为OpenVPN
的安全是ssl
实现的,而ssl
区分客户端和服务器,虚拟网卡已经说的很多了,现在说说隧道的一些细节,OpenVPN
可以建立tcp
隧道和udp
隧道,tcp
隧道顾名思义就是用tcp
来封装VPN
数据流,udp
亦然,但是虽然可以使用udp
封装,在OpenVPN
中你却不需要担心数据失序,因为udp
之上还有ssl
,而 ssl
不允许数据失序,确切的说不应说是ssl
,基于udp
的ssl
实际上是tls
,ssl
数据由于并不是流式的,而是基于记录的,每次必然读取一条记录,因此ssl
是存储接收和存储发送的,如果下面用udp
传输,那么就可能出现丢包或者失序的情况,如此一来读取的记录就会不正确,在ssl
解密特别是cbc
方式解密时就会出错,所以ssl
下面必然是可靠而按序的,即使用udp
,那么在ssl
和udp
之间也必须实现可靠和按序。
那么到底tcp
隧道和udp
隧道如何选择呢?我们看一个组合,抛开tcp/udp
之外的协议不谈,一共有四种隧道,分别是tcp in tcp
,udp in tcp
,tcp in udp
,udp in udp
,第一种和最后一种问题最大,先说第一种,由于 tcp
是有连接的,如果出现丢包的话,那么不管是隧道还是真实收发方都要重传数据,双方重传的数据实际上是为了一个目的一份数据,VPN
路由器仅仅提供封装服务,并不需要为丢包负责,因此收发方负责即可,然而tcp
的语义却管不了这么复杂的策略,它只有让二者均重传数据包,如此一来网络一旦丢包,那么紧接着会出现大量的重传,udp in udp
的情况正好相反,本来udp
就会丢包而且丢后不管,udp
式的隧道加重了这个问题,本来不用隧道的网络平均丢包x
个,用了隧道就可能丢包n*x
个,也不可取,那么就剩下余下的udp in tcp
,tcp 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
的实现其实只要解决两个问题即可:
- 如何拿到第N层数据,然后放回第M层
- 加密/解密第三层ip数据报
针对第一个问题,实际上我们依赖的是这样一个事实,即OSI
的分层网络模型,这样才可以使第M
层将第N
层的PDU(Protocol Data Unit)
当成有效载荷,解析时只需要根据下层的协议号就可以定位上一层的协议类型。以封装第三层数据的VPN
为例,上述第一个问题在linux上有三种方案:
方案一:使用netfilter
使用netfilter
无疑是最直接的方式,对于接收的包,需要在prerouting
上挂载一个钩子,对于本地发出的包,则需要在output
上挂载一个钩子,这样就可以在钩子函数中进行加密/解密处理了,处理完毕之后再根据策略封装成一个新的ip数据报,重新路由并且发送出去或者接收
方案二:使用虚拟网卡
这是一种不直接但是很自然的方式,因为,我们知道从网卡出来的包包含一个IP
数据报(暂不考虑其它三层协议,比如ipx)。实现一个虚拟网卡,在其xmit
发送函数中处理加密,然后重新封装,重新路由。这里暂时先不考虑在哪里解密,因为网卡发送和接收的逻辑是不一样的,我们可以实现一个虚拟网卡,然而却不能修改ip协议栈,除非使用netfilter
方案三:将IP
数据报导出到用户态,比如使用packet
套接字以及替换send/recv
这是最灵活的方案,然而如果使用packet
的话却不行。因为packet
无法截获数据报。因此需要在socket
层次替换send/recv
函数,实现加密/封装以及解密/解封装。这里暂时不考虑send
处理,因为对于一般的应用数据,是很难替换send
的(Linux没有windows的LSP
机制),这种方式,控制接收较方便,而控制发送则很难,和使用虚拟网卡的情形正好相反
我们发现,2和3是互补的,虚拟网卡很容易拿到发出的未封装的原始IP数据报-通过路由即可,但是拿不到接收的封装过的IP数据报,而替换socket
的send/recv
则很容易拿到接收的封装过的IP数据报但是拿不到发送的未封装的IP数据报。因此将2和3结合一下,就出现了第四种方式
接下来我们来讨论VPN
整体的设计。在架设VPN
的时候,首先要明白三件事:
- 确定不安全通路的两个端点。我们就在这两个端点之间建立
VPN
通路 - 要考虑到对
forward
数据包的支持,否则就没有必要使用三层VPN
了,使用应用层VPN
即可 - 隧道的概念。隧道其实就是
VPN
链路两个端点之间的加密通路,其中封装着加密后的原始IP数据报
确定了VPN
链路的端点以后,就可以根据上述的3种方式进行加密/封装,解密/解封装的操作了,也就是说,修建一条隧道。具体的方案如下:
方案1:采用netfilter的方式
这种方案部署起来比较简单,因为端点的两台设备是对称的,netfilter
钩子会处理IPSec
协议逻辑。成型的项目有Freeswan
等,具体细节参见《FreeSWAN 结构框架》
方案2:虚拟网卡+udp
这种方案在端点两端的加密/封装,解密/解封装是不对称的,其中加密/封装这步操作在虚拟网卡完成,解密在recv
逻辑中完成,解封装在send
逻辑中完成。成型的项目如cipe
等。数据通路实际上就是虚拟网卡的方式和导出到用户态方式的结合
设计要点:
VPN
隧道终点使用UDP
端口区分了不同的IP安全通道,而不需要采用IPSec
的方式;- 为何不用
TCP
呢?因为会引起重传叠加导致网络不可用,详见CIPE的作者所做:《Why TCP Over TCP Is A Bad Idea》。同样的规则在后续的OpenVPN
中依然如此,详见OpenVPN
的man
手册中的--proto
选项 - 加密在内核态,解密在用户态-使用
UDP
,之所以这样的不对称法是因为UDP
端口是可以从客户端“连接(访问的含义)”的,不同的UDP
端口就可以区分出来自不同地点的IP安全通道。这种方案依赖于,安全隧道总是由外部(位置不确定的互联网的任意一处)先发起建立请求。后面的OpenVPN
的C/S
模型也有赖于这个事实
1.6.1.2 VPN类型
VPN
按照网路通路区分划分为如下两种:
传输模式VPN
传输模式的VPN
只加密数据,不构建隧道,也就是只实现数据安全。如下图所示
隧道模式VPN
隧道模式的VPN
不仅加密数据,而且构建隧道,也就是说实现网络层次PDU
的封装。如下图所示
VPN
按照认证方式区分可以使用不同的协议承载方式:
PPPoE
严格来讲,这不是一种VPN
,而只是一种接入方式,它只是实现了在以太网上承载ppp
包。虽然它不属于VPN
的范畴,然而却能表现隧道的思想,所谓隧道无非就是第m层的PDU
用一种特定的隧道协议承载第n层的PDU
,思想如下图
L2TP
L2TP
是一个协议,使用这种协议的VPN
用拨号来进行认证。如下图所示
SSL VPN
这种VPN
使用证书,密码等SSL
认可的可配置的方式进行认证。它不一定是第四层VPN
,也不一定是第七层VPN
,而只是强调它使用SSL
协议实现认证以及密钥协商等安全策略。本文推崇的VPN
也就是使用虚拟网卡实现的ssl vpn
1.6.2 进一步的讨论
1.6.2.1 问题
到此为止,VPN
的两个首要工作都得到了解决,使用虚拟网卡,recv
,或者netfilter
抓住IP数据报,然后直接加密,也就是加密/封装和解封装/解密。但是加密的标准以及加密方式我们还没有涉及,理论上,任何加密算法都是可以对IP数据报进行加密的。
实现VPN
有多种方式,标准的方式是使用IPSec
协议(ESP
,AH
等)来实现的,IPSec
是一个封装第三层数据报的协议集,也可以理解成一个第四层协议集,和tcp/udp
等是完全并列的,tcp
,udp
的协议号分别为6和17,而esp
,ah
的协议号分别为50和51。总之IPSec
协议集旨在第三层将数据直接进行加密/解密,要支持IPSec
无疑需要对协议栈进行修改,在Linux
,netfilter
可以完成此任务,Freeswan
正是这样实现的IPSec
然而在内核态通过修改协议栈的实现方式很不灵活,配置起来也是比较复杂,如果能在用户态实现数据报的加密/解密就比较好,这是完全可行的,因为IPSec
协议集和TCP/UDP
一样也是第四层协议,完全可以用tcp
或者udp
来承载加密后的数据。既然使用虚拟网卡可以方便的拿到IP数据报,那么就可以想办法导出到用户态,然后加密/解密后再发出去
1.6.2.2 tap虚拟网卡
到此,我们明白IPSec
只是加密/解密的支撑协议,和加密/解密没有关系,并且这种方式对于配置和实现来讲都不是很灵活,当然,这里先不考虑性能因素。既然IPSec
只是支撑协议,那也就是说只要能实现加密/解密,并且能实现将封装后的数据报传输到VPN
链路的对端就可以了。可是,又如何将虚拟网卡抓取的ip数据报导出到用户态呢?
前面提到,使用虚拟网卡抓取IP数据报和使用替换socket
的send/recv
函数抓取数据报是矛盾且互补的,因此它们的结合对于封装和解封装的实现是不对称的
tap
网卡的出现带来了福音。tap
网卡在实现一个虚拟网卡的同时也实现了一个字符设备,在虚拟网卡的xmit
函数中直接将未加密未封装的原始IP数据报放到字符设备的输入缓冲区,然后用户态进程就可以从该字符设备读取到ip数据报,用户态进程只需要将之加密,然后通过socket
发出即可,借助协议栈完成原始ip数据报的封装。数据到了对端,用户态进程从socket
读取到的就是加过密的原始ip数据报,因为协议栈已经自动解封装了,然后将之解密后写入虚拟网卡字符设备即可,此时,虚拟网卡字符设备模拟中断CPU
,从而虚拟网卡调用接收函数
因此,最终我们有了方案3:
采用这个模型的开源项目有很多,它们都基于一个很简单的demo
程序:simpletun。在simpletun的基础上,衍生了VTun
,OpenVPN
,Openssh's VPN
等项目。
1.6.2.3 安全策略拓展
到此为止,VPN
的通路问题解决了,其中最漂亮的方案就是使用tap
网卡。可是加密/解密算法,认证算法等还没有涉及。和解决通路问题一样,处理安全策略也有很多的方案:
方案1:使用 IPSec 协议集以及 IKE 机制
这个方案其实就是IPSec
的方案,无疑,这种方案对使用tap
网卡是有限制的,因此很多情况下都是直接在内核实现。详情参见相关标准
方案2:编写用户态进程,实现可配置的安全策略
这个方案比较笼统,但是它却是最灵活的。最简单的方式,实现一个通过参数配置加密算法的程序,比如 VTun
所作的那样,然而VTun
对于身份认证和算法及密钥支持比较弱。最终人们想到了SSL
协议。
SSL
协议可以保证通信的保密性和可靠性,它使用公钥技术,支持安全且灵活的认证机制,常见的有使用X509
证书的认证。SSL
协议本身就包含密钥协商,因此相比IPSec
的IKE
要简单的多。正是 tap
虚拟网卡和SSL
的结合,才带来了VPN
技术的革命!tap
网卡和SSL
是缺一不可的,虽然 VTun
使用了tap
网卡,然而它没有使用SSL
协议,这就直接阻碍了它的进一步拓展,而cipe
则更是一个中间过程,它的安全运算全部在内核态完成,根本无法使用SSL
协议。OpenVPN
是这个革命的一个产儿
OpenVPN的基本要素有以下几点:
- 可配置的认证方式
- 可配置的加密算法,密钥协商
- 可插拔的插件机制
- 自动的策略推送机制-包括客户端的虚拟网卡的ip地址
- 集中的管理功能
- 灵活的外接程序
- 强大的日志输出功能
下面是OpenVPN的实现示意图
1.6.2.4 方案对比
对比IPsec
和虚拟网卡
----通路方案选择
IPSec
的通路方案是在网络层直接修改IP数据报实现封装,然后直接交由路由模块重新路由。IPSec
对原始IP数据报的封装是直接在网络层完成的(虽然逻辑上IPSec
属于第四层)- 虚拟网卡方案利用了这样的一个事实,即可以通过路由的方式将IP数据报导入虚拟网卡,另外从虚拟网卡接收的IP数据报也可以通过路由的方式导出到本机或者其它物理网卡。虚拟网卡对原始IP数据报的封装是利用标准的
TCP/IP
协议栈完成的(想使用标准协议栈封装数据报,则必须将原始IP数据报放回到协议栈的顶端,即socket层,然后随着数据在协议栈中往下流动,封装过程自然完成)。- 虚拟网卡的副作用:由于虚拟网卡也是一个起始于链路层的网卡,因此可以为之配置网络层地址,即IP地址,出入虚拟网卡的数据和出入物理网卡的数据一样受到所有
TCP/IP
协议栈语义的约束,因此也就可以通过虚拟网卡很简单地实现一个虚拟的局域网,虽然在物理上虚拟局域网内的设备可能相隔千里。正是这一点使后来的OpenVPN
可以很简单的实现 client2client。
- 虚拟网卡的副作用:由于虚拟网卡也是一个起始于链路层的网卡,因此可以为之配置网络层地址,即IP地址,出入虚拟网卡的数据和出入物理网卡的数据一样受到所有
- 总结:无疑,虚拟网卡的方案没有
IPSec
的方案更直接,因此效率上也会大打折扣,在这一点上考虑,IPSec
的方案要胜出。
对比IPSec
和SSL
----安全策略方案选择
IPSec
定义了一整套内置的以及可外挂的安全策略协议,包括ESP
,AH
,IKE
等,这些协议的操作全部在网络层完成SSL
是一个安全套结字协议框架,通过Cipher Suit
可以灵活配置认证以及加密,摘要算法,这些操作全部在表示层和会话层完成- 总结:虽然
IPSec
是一种自然而然的方式,然而可供选择算法非常有限,并且配置很不灵活,因此SSL
相比IPSec
的安全协议集无疑会胜出
综合对比IPSec
和虚拟网卡 + SSL
在数据通路和安全策略上,VPN
更加关注的是安全策略,数据通路对于VPN
来讲是完全透明的,而安全策略则需要是高度可定制的,除非在效率要求很高的需求下,虚拟网卡 + SSL
的方案要略胜一筹。以下只给出IPSec
和虚拟网卡 + SSL
的数据封装框图:
IPSec
的方式
虚拟网卡 + SSL
1.6.2.5 使用netfilter的引申
netfilter
是一个很优秀的框架,它设计的5个HOOK
点真的是恰到好处,因此我们可以围绕它做出几乎所有和协议栈相关的东西。包括虚拟网卡的功能也是可以通过netfilter
完成的。也就是说,不再需要虚拟网卡了,这样既实现了用户态的安全策略,又不需要虚拟网卡,也就是下面这张图所显示的,仅以 forward
出口包为例
作为对比,列出虚拟网卡的方式:
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
使得ESP
,AH
在第四层协议中有了名分,毕竟 struct net_protocol
就是一个协议栈第四层的操作例程集合,正如tcp
和udp
拥有 tcp_protocol
以及udp_protocol
一样,esp
和ah
也有esp4_protocol
和ah4_protocol
(暂不考虑IPv6)。如此xfrm
以一种直接的方式在标准的协议栈中处理IPSec
数据包,正如下图所示:
可见Linux
使用xfrm
框架(其中为esp/ah
等实现了两个传输层的封装机制,且可以外挂其它机制,比如基于5元素的策略查找等)实现了逻辑上的IPSec
安全策略,该框架包含两大部分:
- 将IPSec安全协议集注册在传输层
- 修改路由模块,加入策略检查逻辑,实现出口数据包的基于策略的捕获,然后将其导入传输层实现安全协议封装
然而VPN
的另一大特性,也就是隧道的实现却另有其人,那就是GRE
模块(体现为ip_gre)。本质上,GRE
网卡和虚拟网卡的思想是一样的,只不过其使用一个标准协议,即GRE
来封装网络层数据报。GRE
的关键在于网络的互通,比如它能将ipx
封装在IP中,从而实现跨协议通信
1.6.3 网络层 VPN 技术发展阶段
1.6.3.1 完全内核态的 IPSec 实现阶段
这是官方的VPN
建议,其背后有着强大的协会和组织以及商业机构。代表作有cisco
,3com
等厂商的核心安全设备,以及开源届的freeswan
。Linux 2.6内核中内嵌了xfrm
框架,该框架以一种直接的方式而不是netfilter
这种间接过滤的方式可以方便的实现IPSec
。然而使用者却没有因为这种实现的方便性而增多,关键还是在于其配置的不灵活以及协议的封闭
1.6.3.2 半虚拟网卡阶段
只实现了发送例程而没有实现接收例程的虚拟网卡,导致没有实现接收例程的原因是这个时候还没有虚拟网卡的字符设备,无从接收数据。cipe
是这个阶段的代表作。在cipe
的实现中,替换socket
的 send/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
的过渡。而基于IPSec
的VPN
受到各方面的限制也不予考虑,再者,VPDN
的应用场合也有限制,也不予考虑。最终我们只剩下了基于虚拟网卡的SSL VPN
,当然正如 OpenVPN
官方网站所说,OpenVPN
相比IPSec
所欠缺的就是各个操作系统的原生支持,虽然 OpenVPN
的设计非常优秀,但是在标准化方面还是比不过IPSec
,IPSec
的成功,和诸如 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
的优点就是公平性,然而UDP
和TCP
们共享统一网路通路,却没有对拥塞进行反应,这样导致了网路频宽分配的严重不公,大量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
的话,那将是致命的,本来N
个TCP
流量和UDP
是并列的,然而N
个TCP
流量被封装了,即使这样,单独的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 VPN
和IPSec 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
隧道以及其他隧道,此时你必须找到这家公司的网管去协商,而此时网管正好不在。然而http
,https
以及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服务器之间的翻译,或者它仅作为一个支持SSL
的TCP
代理,此时客户端还是可以使用原来的客户端,通过路由或重定向的方式和代理进行SSL连接,代理和应用服务器之间则进行明文通信。这种替代层网关目前很好买,也是以后发展的一个大方向。曾几何时,代理网关被淘汰了,而如今,作为SSL VPN
的一个重要组成部分,它又起来了
如果为了应付Cisco或华为的考试,那么你要记住,IPSec VPN
的NAT
不友好性,SSL VPN
不需要安装客户端等,但是你如果是一个实施人员,那么这些就都变成教条,关键是看具体的需求,相似相容,这是个亘古不变的道理,对称的互联就是用IPSec VPN
,C/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