有了 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
来配置,如果心跳时间过短,虽然感知力增加了,但是心跳风暴不说,在端点物理间距很长时,有时的网络拥塞会被认为是断开了连接,造成误判。这又是一个值得权衡的事情。