学习一种协议的最好的方式就是研究它的数据包,这样可以加深对协议的理解。对于研究过某种协议数据包的家伙来讲,他一定知道协议头的哪个位置对应哪个字段,虽然这对于理解协议为什么这么设计可能没有太大的帮助,然而对于排查问题和实际实施是很有帮助的。既然很多人都对 Richard Stevens 的《TCP/IP 详解》情有独钟,咱就剽窃他的风格,解析一下 OpenVPN 的握手是如何完成的。本文分析 70 余个数据包,当然,最终我会略去重复的内容,来看看 OpenVPN 的握手协商过程。

1. 分析前的解释

1.1. 数据包格式

本文以如下格式分析每一个握手数据包,具体 OpenVPN 数据包的格式,请参阅《OpenVPN 协议解析 - 网络结构之外》:

1.1.1. 本文为了节省篇幅,省去了 UDP 以下各层的数据,直接从 OpenVPN 的封装开始。

1.1.2. 以下为数据包格式,xx 为十六进制字节:

A->B:方向,分别为 Server->Client 和 Client->Server |xx|:操作码 +key id,1 字节,xx 右移 5 位就是操作码 |xx|xx|xx|xx|xx|xx|xx|xx|:session ID,这个 ID 是单方向的,8 字节 |xx|xx|xx|xx|xx|xx|xx|xx|1a|de|38|06|ab|5e|55|0f|8f|ed|ea|ca|:数据包消息 MAC,本文启用 tls-auth 选项,本文 MAC 长度 20 字节 (使用 SHA1) |xx|xx|xx|xx|xx|xx|xx|xx|: 包 id 和时间戳,包括 ack 包的 id 和时间戳,在该方向每法送一个包,包 id 都会递增。8 字节 |xx|[...|xx|...]:如果 ack buffer length 长度为 0,没有 ack 信息,如果不为 0,则后面包含确认的包序列号,然后追加一个对端的 session id,变长 |xx|xx|xx|xx|:包序列号,不包括 ack 包,也就是说,发送一个非 P_ACK 包,包序列号才会递增,实际上如果是 P_ACK 包,根本就没有这一行字段。4 字节

1.2. TLS/SSL 握手协议

关于 TLS/SSL 握手协议,最好的资料是 RFC,然后或许看 OpenSSL 的源码上手更快些。这里仅给出几个图示和几点解释,SSL 握手协议包格式如下:

不管是记录协议还是握手协议,都会有一个 record header,该 record 格式如下:

其中,如果是 SSL 握手协议的话,record header 的 type 字段为 0x16,我们使用的 TLS,因此其 major 和 minor 分别为 0x03 和 0x01。接下来,我们看一下握手头:

其中握手类型分别为:

Client hello:0x01
Server hello:0x02
Certificate:0x0b
Server key exchange:0x0c
Certificate request:0x0d
Server hello done:0x0e
Certificate verify:0x0f
Client key exchange:0x10
Finish:0x14
复制代码

1.3. SSL 握手协议和 OpenVPN 握手的关系

我们知道,OpenVPN 的连接建立使用了 SSL 握手协议,可是却抓不到 SSL 握手包,实际上 SSL 握手协议是作为一种载荷封装在了 OpenVPN 的协议包里面了,SSL 握手协议数据实际上是写入了一块内存,然后 OpenVPN 从该内存中读出这些数据包,然后封装后通过 reliable 层发出,数据到达对端后,解封装后写入一块内存,然后 SSL 从内存中读出 SSL 握手载荷,一切都是通过 BIO 实现的。(如不甚理解,请参阅《OpenVPN 协议解析 - 网络结构之外》)

可以看出,SSL 和 OpenVPN 属于不同的层次,SSL 握手协议在 OpenVPN 握手协议之上,然而当 SSL 握手结束后,OpenVPN 的密钥协议又在 SSL 记录协议协议之上,更清晰的图示如下所示:

因此,OpenVPN 握手协议可以将 SSL 握手载荷随意拆分和合并,它们通过 BIO 建立的内存区域建立唯一的联系。

2. OpenVPN 数据包详解

2.1. 第 1 个数据包

Client->Server
|38|
|5f|f2|07|b2|27|12|14|2d|
|5d|67|45|d5|59|1a|c5|b5|1a|de|38|06|ab|5e|55|0f|8f|ed|ea|ca|
|00|00|00|01|4d|da|14|7c|
|00|
|00|00|00|00|
复制代码

这是 OpenVPN 连接的第一个数据包,当然也是握手的第一个数据包,在这里首先要提出的是,通过紧接着后面两个数据包,我们可以看出,虽然 OpenVPN 首推 UDP,且本文解析的数据包也是基于 UDP 的,然而对于 OpenVPN 握手,是必须要保持连接和保证传输的,因此实现了 reliable 层,OpenVPN 的握手完全基于 reliable 层,等完成了握手,协商好了密钥 (注意,这个密钥不是 SSL 握手协商出来的,而是在 SSL 记录协议上协商出来的),reliable 层就不需要了,OpenVPN 记录协议并不需要 reliable 层 (它只是一个运输协议,如 IP 协议)。

既然 reliable 层是一个有连接和保证传输的协议层,那么最简便的实现方式就是模仿已有的实现,那就是 TCP,虽然 reliable 层是一个高度简化的保证传输的版本,但是三次握手是少不了的,因此第一个数据包和下面两个数据包就是三次握手包。

除了和 TCP 一样,三次握手建立连接之外,OpenVPN 的握手协议的三次握手还协商了一个信息,那就是密钥交换算法,这个协商通过其操作码可以看出,第一个数据包的操作码是 0x38,右移 5 位就是 7,因此其表示第二类密钥协商算法。

其中第二行表示一个 session,这个 session 识别了一个连接,它是单方向的,每一个方向一个。然后第三行是一个 HMAC 值,在本文,它是 20 个字节 (特定于 MD5 和 SHA1),这个 HMAC 只有在开启 tls-auth 时才存在,其计算的密钥是静态配置的,两端必须配置一致。tls-auth 相当于 OpenVPN 协议在已经很安全的 SSL 协议外又加固了一层,者有效防止了拒绝服务攻击,毕竟,SSL 连接的安全性在于其建立安全通路的方式和建立后的安全性,其缺点就是消耗大量的资源。

再往下一行是一个 packet id 和一个时间戳,这两个字段一共占据 8 个字节,它有效的防止了重放攻击。再往后一行,为一个单字节 0x00,可见第一个数据包并不想确认任何数据,这也是正常的。最后是一个包序列号,占据 4 个字节,为 0,每个方向的非确认包 (P_ACK),都拥有一个序列号,这个序列号是用于保证传输的,并不是用于防止重放攻击的,注意,它和 packet id 的意义是不同的,确认包并不包含序列号。

2.2. 第 2 个数据包

Server->Client
|40| 
|7a|26|7c|45|a6|72|e1|a2|
|b0|72|21|0a|c1|3f|f1|4a|bc|79|46|14|30|51|f3|0c|64|63|54|de| 
|00|00|00|01|4d|da|14|7c| 
|01|00|00|00|00|5f|f2|07|b2|27|12|14|2d|
|00|00|00|00|
复制代码

第二个数据包是服务器发往客户端的,类似于 TCP 的 SYN/ACK,和第一个数据包一样,它的操作码也标识了密钥交换算法,这次是 8,表示服务器使用第二类密钥交换算法,这样就和客户端达成了一致。第二行是一个 session id,这是另一方向的 session id。后面的数据意义和第一个包是一样的。最后一行,也是一个 4 字节的 0,这表示在从服务器端到客户端这个方向上,这是第一个数据包。

值得注意的是,我们看第 5 行,第一个字节为 1,说明有一个数据包确认,紧接着 4 个字节为 0,说明它确认的是 Client 到 Server 方向的第一个数据包,再往后的 8 个字节是 Client 到 Server 方向的 session id。

2.3. 第 3 个数据包

Client->Server
|28|
|5f|f2|07|b2|27|12|14|2d|
|40|20|5a|f4|92|2c|a7|4e|8e|f5|1a|e8|45|06|e7|5a|ae|64|64|85|
|00|00|00|02|4d|da|14|7c|
|01|00|00|00|00|7a|26|7c|45|a6|72|e1|a2|
复制代码

这是一个确认包,从操作码可以看出来,0x28 右移 5 位就是 5,这就是 P_ACK_V1。说明这是一个确认。由于它是一个纯确认包,它没有最后的包序列号。

我们直接看第 5 行,它的意义和第二个数据包是一样的。到此为止,实际上我们已经没有必要在继续分析下去了,如果你已经理解了这前三个数据包的话,实际上对于 OpenVPN 的握手协议你基本已经理解了。然后我还要继续下去,因为接下来就要开始 SSL 握手了。可以通过接下来 OpenVPN 的握手协议对 SSL 握手协议的封装来解释为何抓取不到 OpenVPN 的 SSL 连接握手包。

2.4. 第 4 个数据包

Client->Server
|20|
|5f|f2|07|b2|27|12|14|2d|
|57|b8|8a|a1|3c|0f|84|2b|91|42|2a|92|c6|f4|55|c9|7c|82|48|65|
|00|00|00|03|4d|da|14|7c|
|00|
|00|00|00|01|
|16|03|01|00|5f|01|00|00|5b|03|01|4d|da|14|7c|77|15|6d|32|69|2a|3d|90|fc|8d|3d|a6|68|83|3f|11|e2|63|b7|1b|e5|d1|46|95|3b|99|a6|e5|00|00|34|00|39|00|38|00|35|00|16|00|13|00|0a|00|33|00|32|00|2f|00|66|00|05|00|04|00|63|00|62|00|61|00|15|00|12|00|09|00|65|00|64|00|60|00|14|00|11|00|08|00|06|00|03|01|00|
复制代码

通过前三个包的分析,我们看出,它们是没有包含数据的,这很类似于 TCP 的三次握手消息。这第四个数据包是第一个包含数据的 OpenVPN 握手包。

如果我们仔细观察一下 OpenVPN 的握手协议头,发现它里面实际上是没有长度信息的。这是因为我们讨论的是 UDP 上的 OpenVPN,UDP 数据报的长度是收发一致的,如果是 TCP 的话,它是流式的,收发不一致,当然是需要一个长度追加在操作码前面。另外,在深入数据载荷之前,我们看一下第六行,也就是一个 4 个字节的包序列号,这时是 0x01,说明这是 Client 到 Server 方向的第二个数据包,我们数一下,也真的是这样。

好了,我们看一下其数据载荷的前面几个字节,其前 5 个字节 0x16,0x03,0x01,0x00,0x5f,我们发现它是 SSL 记录头的格式,0x16 是其 type,实际上就是握手协议,后面的 0x03 和 0x01 是 major 和 minor 号,后面的两个字节表示 SSL 握手消息长度,那么它到底是什么 SSL 握手消息呢?我们根据 SSL 握手协议头的格式,其第一个字节是 0x01,也就是 Client hello,它的长度是后面的 3 个字节。最终,我们发现,这个 OpenVPN 协议封装的数据载荷就是 SSL 握手消息中的 Client hello 消息。

2.5. 第 5 个数据包

Server->Client
|20|
|7a|26|7c|45|a6|72|e1|a2|
|4c|b7|ae|78|e9|67|ca|bb|2b|71|0d|fc|48|51|08|9a|30|6c|dd|54|
|00|00|00|02|4d|da|14|7c|
|01|00|00|00|01|5f|f2|07|b2|27|12|14|2d|
|00|00|00|01|
|16|03|01|00|2a|02|00|00|26|03|01|4d|da|14|7c|5b|f3|9a|fa|b9|d3|b1|75|b7|ba|4f|9d|33|6e|4b|25|cc|f3|dd|6f|d6|73|b0|6e|f0|ac|aa|f4|00|00|39|00|16|03|01|04|8b|0b|00|04|87|00|04|84|00|02|41|30|82|02|3d|30|82|01|a6|02|09|00|fb|0e|c2|7f|49|2a|44|8b|30|0d|06|09|2a|86|48|86|f7|0d|01|01|05|05|00|30|61|31|0b|
复制代码

通过第四个数据包的分析,我们很简单的分析出这个 OpenVPN 协议封装的数据载荷是 Server hello 消息,因为 |16|03|01|00|2a|02| 中 02 表示 Server hello。

如果仔细往下看,我们最终又发现了一个 SSL 记录头序列:|16|03|01|04|8b|,紧接着的是 |0b|00|04|87|,这明显又是一个 SSL 握手消息,0x0b 是其消息类型,我们发现它是 Certificate,它的长度是 0x0487,这可够长的了...

SSL 握手消息之所有可以在 OpenVPN 协议封装的任意位置,是因为它只是数据载荷的一部分,再次重申,SSL 协议被 OpenVPN 协议封装了,SSL 是载荷,OpenVPN 提供封装和运输服务,不管怎样拆分,最终总是能保证数据能可靠到达对端,由对端的 SSL 协议负责进行组合。

2.6. 第 6 个数据包

Server->Client
|20|
|7a|26|7c|45|a6|72|e1|a2|
|16|28|bc|a4|3a|34|01|45|26|2b|ab|59|ea|ee|d3|88|b4|dd|11|ee|
|00|00|00|03|4d|da|14|7c|
|00|
|00|00|00|02|
|30|09|06|03|55|04|06|13|02|61|61|31|0b|30|09|06|03|55|04|08|13|02|61|61|31|0b|30|09|06|03|55|04|07|13|02|61|61|31|0b|30|09|06|03|55|04|0a|13|02|61|61|31|0b|30|09|06|03|55|04|0b|13|02|61|61|31|0b|30|09|06|03|55|04|03|13|02|63|61|31|11|30|0f|06|09|2a|86|48|86|f7|0d|01|09|01|16|02|61|61|30|1e|17|0d|31|
复制代码

这个数据包比较奇怪,因为我们没有在数据载荷的开始处发现任何 SSL 协议的识别标识,另外,如果我们仔细分析上一个数据包,也就是第五个数据包中在中间封装的 Certificate 消息,它的长度是 0x0487,可是无论怎么看,第五个数据包整个也没有那么长,那么这么长的数据到底在哪里呢?答案就是在后续的数据包中,这就类似 IP 分片,非头 IP 分片的载荷中,是没有包含传输层协议头的,也可以通过 TCP 分段来理解...OpenVPN 的实现中,在 reliable 层中实现了根据虚拟网卡 MTU 或者当前网络状况任意拆分数据的功能,这样可达到高效利用网络的目的。这样,即使一个 1000 字节的 SSL 握手消息,reliable 层也可以将其拆成 10 个 100 多字节的 UDP 包,数据到达对端后,每一个 100 多字节的 UDP 包进入其 SSL BIO 的内存 BIO 中,由 SSL 协议的实现负责重组数据。

我们可以将 reliable 层当成一个在 UDP 上伪装的伪 TCP,该伪 TCP 直接和 SSL 的内存 BIO 接口。

在了解了上述原理之后,我们直接略过 Server 传输的 Certificate 消息,当然还是会分析一个 Client 的确认包,因为 reliable 层是需要确认的,这就是接下来马上就要分析的第九个数据包。

2.7. 第 9 个数据包

Client->Server
|28|
|5f|f2|07|b2|27|12|14|2d|
|60|e1|38|28|46|ef|63|5e|46|e6|31|9c|fd|7f|40|7d|df|bd|fd|df|
|00|00|00|04|4d|da|14|7c|
|01|00|00|00|01|7a|26|7c|45|a6|72|e1|a2|
复制代码

这是一个纯确认包,我们看到其操作码是 5,它确认的是 Server 发送的 Certificate 的 OpenVPN 协议封装的一部分,当然这样的包有好几个,这里仅仅揪出一个来分析。它确认的是 Server 发送的第两个数据包,也就是第五个数据包。

2.8. 第 27 个数据包

Server->Client
|20|
|7a|26|7c|45|a6|72|e1|a2|
|0a|1d|15|d6|1a|42|e6|57|29|18|71|b9|db|fd|d1|43|9d|6d|ef|8a|
|00|00|00|0e|4d|da|14|7c|
|00|
|00|00|00|0d|
|69|67|1e|99|7a|a1|8b|9d|b1|e7|9a|bb|8b|ca|49|16|03|01|01|8d|0c|00|01|89|00|80|bf|88|f7|46|21|4c|81|5c|20|77|d5|5a|52|1b|d4|e8|94|90|e4|84|ae|74|1a|82|f9|c1|0d|f2|ac|ea|10|2f|25|12|41|d8|d2|41|64|44|a2|a1|42|3f|73|1a|79|0c|e1|d4|64|8e|35|a1|1b|00|90|9f|29|8b|bd|ae|16|84|45|d9|44|f9|44|00|d1|03|fa|3e|
复制代码

在这个 OpenVPN 协议封装的中间,我们发现了 Server 的 Server key exchange 消息。这个道理请参照 2.6 节。

2.9. 第 34 个数据包

Server->Client
|20|
|7a|26|7c|45|a6|72|e1|a2|
|8c|6e|d5|13|e0|f8|14|13|c3|c6|d7|e3|b0|7f|7b|10|92|0c|85|b5|
|00|00|00|12|4d|da|14|7c|
|00|
|00|00|00|11|
|b5|e4|de|cb|85|b9|10|0c|1f|d6|7a|21|56|2c|7e|ca|15|16|03|01|00|74|0d|00|00|6c|04|03|04|01|02|00|65|00|63|30|61|31|0b|30|09|06|03|55|04|06|13|02|61|61|31|0b|30|09|06|03|55|04|08|13|02|61|61|31|0b|30|09|06|03|55|04|07|13|02|61|61|31|0b|30|09|06|03|55|04|0a|13|02|61|61|31|0b|30|09|06|03|55|04|0b|13|02|
复制代码

在这个 OpenVPN 协议封装的中间,我们发现了 Server 的 Certificate request 消息。这个道理请参照 2.6 节。

2.10. 第 36 个数据包

Server->Client
|20|
|7a|26|7c|45|a6|72|e1|a2|
|a4|af|b5|cd|45|2e|33|ea|ff|6b|0b|58|b2|fc|1b|41|bd|e4|ef|99|
|00|00|00|13|4d|da|14|7c|
|00|
|00|00|00|12|
|61|61|31|0b|30|09|06|03|55|04|03|13|02|63|61|31|11|30|0f|06|09|2a|86|48|86|f7|0d|01|09|01|16|02|61|61|0e|00|00|00|
复制代码

最终,在数据载荷的最后,我们发现了 |0e|00|00|00| 序列,这是什么呢?我们知道,Server hello done 的握手 type 是 0x0e,其后三个字节为消息长度,为全 0,这个消息只是想告诉 Client,Server 发送的消息结束了,Client 可以发送数据了。注意,和往常不一样,Server hello down 消息并没有 SSL 记录头序列,而是直接贴在消息后面的。

我们只是想分析 OpenVPN 协议,而不是 SSL 协议,因此不会过分叙述 SSL 握手的细节。接下来的 OpenVPN 协议封装的载荷包含了 Client 发送给 Server 的 Certificate,Verify, Client key exchange 消息等,我们略过这部分重复且枯燥的叙述。

2.11. 第 65 个数据包

Client->Server
|20|
|5f|f2|07|b2|27|12|14|2d|
|56|ae|02|5f|0c|22|95|78|b7|7e|fb|24|8e|f9|34|56|69|09|87|e7|
|00|00|00|23|4d|da|14|7c|
|00|
|00|00|00|10|
|0f|17|d5|75|85|7b|ba|84|e9|b2|a0|9b|22|cc|ad|cc|cf|aa|38|6d|1c|ef|2b|23|69|8f|06|ac|81|79|50|7c|00|cb|21|0d|26|7d|26|81|14|28|bd|45|36|02|14|03|01|00|01|01|16|03|01|00|30|fc|bf|67|e0|a3|95|5d|ee|e1|59|fb|16|2d|c0|7a|55|82|de|73|34|02|1c|a2|88|15|4a|92|c6|6e|41|87|e4|a1|94|e8|f8|e5|31|e1|e0|ae|2f|7d|
复制代码

注意,我们发现了 |14|03|01|00|01|01| 序列,这个序列特殊吗?是的,很特殊,因为这并不属于 SSL 握手协议,而是一个单独的 SSL 协议,那就是 CHANGE_CIPHER_SPEC 协议,这个协议说明,SSL 通道上的安全密钥 (加密对称密钥,摘要密钥等) 已经建立,接下来的消息将会被这些密钥作用,因此接下来的消息我们将无法再看到了,它们是加密的。CHANGE_CIPHER_SPEC 协议规定,其数据载荷就是一个 0x01,因此其长度也就是 1,故而出现了 |14|03|01|00|01|01| 序列。

我本来想把这个数据包作为一个终结,结束讨论,因为以后的数据包都是通过 SSL 握手协商出来的安全通道加密的,也就无法理解其中的内容了,这样分析还有什么意义呢?我们知道,SSL 握手的最后一步是 Finish 消息,这个消息是协议规定的,可是我们再也看不到了。

2.12. 第 71 个数据包

Server->Client
|20|
|7a|26|7c|45|a6|72|e1|a2|
|c8|eb|b1|85|e7|b2|bb|34|f1|96|0e|00|1f|56|df|21|30|34|a3|0e|
|00|00|00|23|4d|da|14|7c|
|01|00|00|00|11|5f|f2|07|b2|27|12|14|2d|
|00|00|00|13|
|14|03|01|00|01|01|16|03|01|00|30|8f|57|7d|42|ae|a3|89|2d|34|5a|a7|d1|f7|08|ef|a1|bd|8b|52|1c|32|56|da|5d|33|0b|f2|95|82|d2|f3|c8|60|69|e6|0b|c2|0d|88|65|cf|fc|af|b4|93|6e|0c|31|
复制代码

无疑,这个数据包的载荷中也包含了 |14|03|01|00|01|01| 序列,这是 Server 发送的 CHANGE_CIPHER_SPEC 消息,表示接下来就是加密数据了。接着上节的话题,本来该结束了,但是为何还没有结束呢?因为 OpenVPN 的握手协议之后,紧跟着的就是 OpenVPN 的密钥协议,这两个协议同在 OpenVPN 的控制通道中进行,也就是说都用到了 reliability 层,然而 OpenVPN 密钥协议却不是用于封装 SSL 载荷的,而是在 SSL 记录协议之下,作为 SSL 记录协议的载荷存在的。

2.13. 第 72 个数据包

Client->Server
|20|
|5f|f2|07|b2|27|12|14|2d|
|95|6f|3c|de|d3|4c|45|71|89|7f|86|5c|c0|58|01|47|7d|72|1a|61|
|00|00|00|25|4d|da|14|7c|
|01|00|00|00|13|7a|26|7c|45|a6|72|e1|a2|
|00|00|00|12|
|17|03|01|00|20|42|32|5b|54|35|72|45|07|f7|41|dd|5d|d8|ba|42|46|d9|bf|a7|44|2d|38|38|f3|11|cf|bc|81|df|e4|33|37|17|03|01|01|20|a6|81|5e|5a|cf|5a|dd|9a|4d|b0|1d|8a|87|91|0c|e6|3f|ad|94|16|cf|f9|6c|9f|fb|08|5f|d1|52|35|32|47|3e|93|76|31|27|db|0b|7d|77|cb|4c|c6|b5|6d|da|e1|3d|67|a1|23|24|c4|4f|81|a2|54|
复制代码

在这个 OpenVPN 数据包中,包含了 |17|03|01|00|20| 序列,这无疑也是 SSL 记录头,其中 0x17 是 type,这是什么呢?是 SSL 记录协议。也就是说,从这里开始,OpenVPN 使用了 SSL 记录协议。但是前面不是说 OpenVPN 使用自己的“尽力而为”协议传输数据的吗?而 SSL 是基于可靠连接的啊!事实上,这里使用的 SSL 记录协议并不是实际的数据传输,而是 OpenVPN 使用的真正的密钥的协商,我们前面提到过,这个协商是作为 SSL 记录协议的载荷存在的。

再仔细观察这个数据包,我们发现其中有两个 |17|03|01|00|20| 序列,在相反的方向上又有两个这样的序列,当然后两个字节是不同的,这实际就是 OpenVPN 密钥协议的载荷,这里的握手明显使用的是第二类方式 (因为最开始的三次握手中的操作码已经决定了)。由于这里的密钥协议数据已经使用 SSL 记录协议在 SSL 加密通道中了,因此其协议包我们不得而知 (这个实验中,我使用的 cipher 是 none,然而 digest 却不是 none)!

3. 总结

通过 OpenVPN 握手数据包的抓取和分析,我们了解到了 OpenVPN 协议的更多的细节,它分为两个部分,控制协议和记录协议,两个协议通过 OpenVPN 协议头复用到了 UDP,其中控制协议又分为了握手协议和密钥协议,它们都跑在一个可靠的伪 TCP 虚拟连接上,它实际上很复杂同时又很简单。

通过分析数据包的方式学习网络协议是一个不错的方式却不是一个不错的开始,对于 OpenVPN,首先我们必须首先明白它的设计,它的框架,它的用途以及必须可以熟练使用它。其中的前提是使用。如果只是认识到 OpenVPN 是虚拟网卡加 SSL 协议的结合,那未免太肤浅了,一个革命性的开源 VPN 肯定不可能如此肤浅的,它拥有自己的协议。


reference

  • 安全

    互联网安全是一门涉及计算机科学、网络技术、通信技术、密码技术等多种学科的综合性学科。

    64 引用
感谢    赞同    分享    收藏    关注    反对    举报    ...