通常,使用OpenVPN设置VPN非常容易。与其他VPN解决方案相比,这是OpenVPN最具吸引力的功能之一。然而,有时有必要对不工作的设置进行故障排除或调整现有设置以获得性能。
OpenVPN的故障排除和调优经常被忽视。客户端和服务器端的OpenVPN日志文件提供了大量信息,但你必须知道如何读取它们。在设置客户端和服务器配置文件时,也会犯很多常见错误。在本章中,您将学习如何解释OpenVPN日志文件,以及如何检测和修复其中一些常见错误。
最后,工作设置和工作良好的设置之间存在很大差异。您的OpenVPN设置可能运行正常,但用户仍可能抱怨性能不佳。从OpenVPN设置中获得最大性能似乎是一种魔法。在本章中,你将学习一些这种黑魔法。
本章将涵盖以下主题:
ping
和 iperf
优化性能tcpdump
分析OpenVPN流量测试一个不工作的设置起初似乎是一项艰巨的任务。你该从哪里开始?
幸运的是,OpenVPN提供了出色的日志记录和调试功能。然而,随着日志记录的冗长程度增加,读取这些日志文件也变得越来越困难。
OpenVPN的默认日志级别为 1
,但建议将详细程度设置为 3
。这通常会为管理员提供足够的信息来检测设置问题,同时将性能损失降至最低。
建议仅在出于测试的目的时,将详细程度设置为 5
或更高,因为这会严重影响性能。
到目前为止,这本书中的每个例子都包含了设置 verb 3
。首先,我们将仔细检查客户端和服务器日志文件,以获得这种冗长的工作设置。了解甚至可能存储工作连接的日志非常重要。当试图在非工作设置中查找错误时,将非工作案例的日志文件与工作设置的日志文件进行比较非常有用。
使用默认配置文件 basic-udp-server.conf
启动服务器:
xxxxxxxxxx
[root@server]# openvpn --config basic-udp-server.conf
先不要连接客户端。服务器日志文件现在将包含以下内容:
xxxxxxxxxx
1 14:53:27 OpenVPN 2.3.6 x86_64-redhat-linux-gnu
[SSL (OpenSSL)] [LZO] [EPOLL] [PKCS11] [MH] [IPv6]
built on Dec 2 2014
2 14:53:27 library versions: OpenSSL 1.0.1e-fips 11 Feb 2013,
LZO2.03
3 14:53:27 Diffie-Hellman initialized with 2048 bit key
4 14:53:31 WARNING: this configuration may cache passwords in
memory -- use the auth-nocache option to prevent this
5 14:53:31 Control Channel Authentication: using
'/etc/openvpn/movpn/ta.key' as a OpenVPN static key
file
6 14:53:31 Outgoing Control Channel Authentication: Using 160
bit message hash 'SHA1' for HMAC authentication
7 14:53:31 Incoming Control Channel Authentication: Using 160
bit message hash 'SHA1' for HMAC authentication
8 14:53:31 Socket Buffers: R=[16777216->131072]
S=[16777216->131072]
9 14:53:31 TUN/TAP device tun0 opened
10 14:53:31 TUN/TAP TX queue length set to 100
11 14:53:31 do_ifconfig, tt->ipv6=0, tt-did_ifconfig_ipv6_setup=0
12 14:53:31 /sbin/ip link set dev tun0 up mtu 1500
13 14:53:31 /sbin/ip addr add dev tun0 10.200.0.1/24
broadcast 10.200.0.255
14 14:53:31 GID set to nobody
15 14:53:31 UID set to nobody
16 14:53:31 UDPv4 link local (bound): [undef]
17 14:53:31 UDPv4 link remote: [undef]
18 14:53:31 MULTI: multi_init called, r=256 v=256
19 14:53:31 IFCONFIG POOL: base=10.200.0.2 size=252, ipv6=0
20 14:53:31 Initialization Sequence Completed
为了清楚起见,每行前面的时间戳都被缩写了。
让我们逐行浏览这个日志文件:
dh /etc/openvpn/movpn/dh2048.pem
中指定的文件用于此目的。tls-auth
配置选项进行保护,并且OpenVPN能够成功读取指定的文件。SHA1
密钥是从 tls-auth
文件中派生出来的,现在用于对传出流量进行签名(哈希)和检查传入流量。Receive (R)
和 Send (S)
缓冲区的大小。这些参数仅在调整工作设置时有用,我们将在本章稍后看到。tun
设备,并能够将该设备的数据包队列深度设置为 100
。server 10.200.0.0 255.255.255.0
的翻译。group nobody 和
user nobody` 的结果。proto udp
和 bind
的结果。256
。server 10.200.0.0 255.255.255.0
翻译的一部分。接下来,我们启动客户端并查看服务器端日志文件:
xxxxxxxxxx
[root@client]# openvpn --config basic-udp-client.conf
之后,我们还将浏览客户端日志文件:
xxxxxxxxxx
21 15:30:37 <CLIENT-IP>:39086 TLS: Initial packet from
[AF_INET]<CLIENT-IP>:39086, sid=071ba589 7e9ff2a0
22 15:30:37 <CLIENT-IP>:39086 VERIFY OK: depth=1, C=ZA,
ST=Enlightenment, L=Overall, O=Mastering OpenVPN,
CN=Mastering OpenVPN, emailAddress=root@example.org
23 15:30:37 <CLIENT-IP>:39086 VERIFY OK: depth=0, C=ZA,
ST=Enlightenment, O=Mastering OpenVPN, CN=client3,
emailAddress=root@example.org
24 15:30:37 <CLIENT-IP>:39086 Data Channel Encrypt: Cipher
'BF-CBC' initialized with 128 bit key
25 15:30:37 <CLIENT-IP>:39086 Data Channel Encrypt: Using 160 bit
message hash 'SHA1' for HMAC authentication
26 15:30:37 <CLIENT-IP>:39086 Data Channel Decrypt: Cipher
'BF-CBC' initialized with 128 bit key
27 15:30:37 <CLIENT-IP>:39086 Data Channel Decrypt: Using 160 bit
message hash 'SHA1' for HMAC authentication
28 15:30:37 <CLIENT-IP>:39086 Control Channel: TLSv1, cipher
TLSv1/SSLv3 DHE-RSA-AES256-SHA, 2048 bit RSA
29 15:30:37 <CLIENT-IP>:39086 [client3] Peer Connection Initiated
with [AF_INET]<CLIENT-IP>:39086
30 15:30:37 client3/<CLIENT-IP>:39086 MULTI_sva: pool returned
IPv4=10.200.0.2, IPv6=(Not enabled)
31 15:30:37 client3/<CLIENT-IP>:39086 MULTI: Learn: 10.200.0.2 →
client3/<CLIENT-IP>:39086
32 15:30:37 client3/<CLIENT-IP>:39086 MULTI: primary virtual IP
for client3/<CLIENT-IP>:39086: 10.200.0.2
33 15:30:39 client3/<CLIENT-IP>:39086 PUSH: Received control
message: 'PUSH_REQUEST'
34 15:30:39 client3/<CLIENT-IP>:39086 send_push_reply():
safe_cap=940
35 15:30:39 client3/<CLIENT-IP>:39086 SENT CONTROL [client3]:
'PUSH_REPLY,route-gateway 10.200.0.1,topology subnet,
ping 10,ping-restart 60,
ifconfig 10.200.0.2 255.255.255.0' (status=1)
让我们浏览一下新的日志条目:
<CLIENT-IP>
的客户端接收到初始数据包。通常,这里会列出完整的IPv4地址。VERIFY-OK
。SHA1
哈希BF-CBC(Blowfish Cipher Block Chaining)是OpenVPN的当前默认密码。<CLIENT-IP>
的客户端 client3
成功通过了身份验证过程。PUSH REQUEST
),以及服务器的回复,即它将发送 push_reply
。push_reply
消息的内容,其中包含此客户端的所有配置信息。这一行在调试OpenVPN设置时非常有用,因为它显示了OpenVPN服务器为特定客户端提供的大部分信息,而不管使用的配置文件如何。同样,这是客户端日志文件(注意时间戳,并将其与服务器日志文件中的时间戳进行匹配):
xxxxxxxxxx
1 15:30:37 OpenVPN 2.3.6 x86_64-redhat-linux-gnu
[SSL (OpenSSL)] [LZO] [EPOLL] [PKCS11] [MH] [IPv6]
built on Dec 2 2014
2 15:30:37 library versions: OpenSSL 1.0.1e-fips 11 Feb 2013,
LZO 2.03
3 15:30:37 Control Channel Authentication: using
'/etc/openvpn/movpn/ta.key' as a OpenVPN static key
file
4 15:30:37 UDPv4 link local: [undef]
5 15:30:37 UDPv4 link remote: [AF_INET]<SERVER-IP>:1194
6 15:30:37 [Mastering OpenVPN Server] Peer Connection Initiated
with [AF_INET]<SERVER-IP>:1194
7 15:30:39 TUN/TAP device tun0 opened
8 15:30:39 do_ifconfig, tt->ipv6=0, tt-did_ifconfig_ipv6_setup=0
9 15:30:39 /sbin/ip link set dev tun0 up mtu 1500
10 15:30:39 /sbin/ip addr add dev tun0 10.200.0.2/24
broadcast 10.200.0.255
11 15:30:39 Initialization Sequence Completed
让我们浏览一下新的日志条目:
tls-auth
配置选项进行保护,并且OpenVPN能够成功读取指定的文件。<SERVER-IP>
和端口 1194
处与服务器建立了UDP连接。Mastering OpenVPN Server
的OpenVPN服务器的连接已成功建立。服务器的名称从服务器端证书的 common name 中检索。tun0
。/sbin/ip
命令设置的。OpenVPN设置可能会因多种原因失败。在下一节中,我们将介绍一系列常见故障。首先,让我们看看连接尝试失败时日志文件中显示的内容。失败可能发生在连接尝试的早期,甚至在 Initialization Sequence Completed
行之后。
如果我们使用了错误的 tls-auth
文件,连接将很早失败。这正是使用 tls-auth
的原因,因为当流氓客户端尝试访问时,它将最大限度地减少OpenVPN服务器的负载。尝试连接而不指定 tls-auth
文件的客户端将在服务器日志中显示如下:
xxxxxxxxxx
16:40:31 Authenticate/Decrypt packet error:
packet HMAC authentication failed
16:40:31 TLS Error: incoming packet authentication failed from
[AF_INET]<CLIENT-IP>:49956
16:40:33 Authenticate/Decrypt packet error:
packet HMAC authentication failed
16:40:33 TLS Error: incoming packet authentication failed from
[AF_INET]<CLIENT-IP>:49956
16:40:37 Authenticate/Decrypt packet error:
packet HMAC authentication failed
16:40:37 TLS Error: incoming packet authentication failed from
[AF_INET]<CLIENT-IP>:49956
16:40:45 Authenticate/Decrypt packet error:
packet HMAC authentication failed
16:40:45 TLS Error: incoming packet authentication failed from
[AF_INET]<CLIENT-IP>:49956
16:41:01 Authenticate/Decrypt packet error:
packet HMAC authentication failed
16:41:01 TLS Error: incoming packet authentication failed from
[AF_INET]<CLIENT-IP>:49956
由于OpenVPN服务器立即拒绝连接尝试,因此没有关于此客户端的其他报告。从日志文件中的时间戳可以看出,客户端在每次连接失败时都会增加连接尝试之间的延迟时间。如果60秒内无法建立连接,则客户端将中止:
xxxxxxxxxx
TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity)
TLS Error: TLS handshake failed
只有在连接似乎已成功初始化后,第二次连接失败才会变得明显。为此,我们指定在一侧使用不同的加密密码,但忘记在另一侧使用。客户端日志文件现在将显示以下内容:
xxxxxxxxxx
16:56:20 /sbin/ip link set dev tun0 up mtu 1500
16:56:20 /sbin/ip addr add dev tun0 10.200.0.2/24 broadcast 10.200.0.255
16:56:20 Initialization Sequence Completed
16:56:30 Authenticate/Decrypt packet error: cipher final failed
16:56:40 Authenticate/Decrypt packet error: cipher final failed
因此,起初连接似乎已经成功建立(第1至3行),但10秒后,数据信道加密和解密失败。
注:如果在这种情况下使用了Windows GUI,GUI图标将变为绿色,但VPN本身将无法运行!
在初始化过程中,大多数配置问题将在服务器端或客户端报告。路由问题更为常见,OpenVPN通常不会报告。因此,需要不同的故障排除技术。
在设置OpenVPN配置时,有一些常见的错误很容易犯。这些配置错误大致可分为四类:
tun
与 tap
、密码短语和压缩在本节中,我们将介绍其中的前三个类别。本章稍后将讨论路由错误。
客户端配置文件几乎总是包含如下三行:
xxxxxxxxxx
ca ca.crt
cert client.crt
key client.key
这些证书和私钥文件在第3章“PKI和证书”中创建,并在后续章节中广泛使用。
但是,CA文件不需要指定用于对客户端证书文件进行签名的证书颁发机构。它必须是用于签署服务器证书的证书颁发机构的公共证书。如果服务器证书由其他CA签名,则客户端将拒绝连接到服务器。这可以在客户端日志文件中看到:
xxxxxxxxxx
UDPv4 link remote: [AF_INET]<SERVER-IP>:1194
VERIFY ERROR: depth=1, error=self signed certificate in certificate chain: C=ZA, ST=Enlightenment, L=Overall, O=Mastering OpenVPN, CN=Mastering OpenVPN, emailAddress=root@example.org
TLS_ERROR: BIO read tls_read_plaintext error: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
TLS Error: TLS object -> incoming plaintext read error
TLS Error: TLS handshake failed
在这种情况下,服务器端不会记录任何错误,因为服务器认为客户端证书是有效的。
服务器上唯一记录的内容如下:
xxxxxxxxxx
<CLIENT-IP>:42472 TLS: Initial packet from
[AF_INET]<CLIENT-IP>:42472, sid=9a1e4a84 cdbb6926
<CLIENT-IP>:51441 TLS: Initial packet from
[AF_INET]<CLIENT-IP>:51441, sid=17d3c89b 6999ae97
<CLIENT-IP>:43513 TLS: Initial packet from
[AF_INET]<CLIENT-IP>:43513, sid=4609202f 4c91c23d
这显示了OpenVPN客户端连续进行的连接尝试。
确保在客户端配置文件中指定了正确的CA文件。
如果服务器无法识别客户端证书,服务器将拒绝访问它。如果使用了错误的(或恶意的)客户端证书,或者客户端的证书被吊销,并且在服务器配置文件中指定了 crl-verify
选项,则可能会发生这种情况。
如果未知客户端尝试连接到OpenVPN服务器,以下条目将显示在服务器的日志文件中:
xxxxxxxxxx
<CLIENT-IP>:57072 TLS: Initial packet from
[AF_INET]<CLIENT-IP>:57072, sid=a175f1be 6faed111
<CLIENT-IP>:57072 VERIFY ERROR: depth=0, error=unable to get
local issuer certificate: C=NL, O=Cookbook, CN=client1,
name=Cookbook Client, emailAddress=janjust@nikhef.nl
<CLIENT-IP>:57072 TLS_ERROR: BIO read tls_read_plaintext error:
error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:
no certificate returned
<CLIENT-IP>:57072 TLS Error: TLS object -> incoming plaintext
read error
<CLIENT-IP>:57072 TLS Error: TLS handshake failed
服务器无法验证客户端的证书,因为它无法识别用于签名的CA证书。因此,它拒绝允许此客户端连接。
在客户端,60秒内日志文件中不会打印任何消息,之后初始握手超时并进行新的连接尝试:
xxxxxxxxxx
13:24:23 UDPv4 link local: [undef]
13:24:23 UDPv4 link remote: [AF_INET]<SERVER-IP>:1194
13:25:23 TLS Error:
TLS key negotiation failed to occur within
60 seconds (check your network connectivity)
13:25:23 TLS Error: TLS handshake failed
13:25:23 SIGUSR1[soft,tls-error] received, process restarting
13:25:25 Control Channel Authentication: using
'/etc/openvpn/movpn/ta.key' as a OpenVPN static key file
13:25:25 UDPv4 link local: [undef]
13:25:25 UDPv4 link remote: [AF_INET]<SERVER-IP>:1194
确保服务器能够识别客户端的证书。这可以通过在服务器配置文件中指定正确的CA证书来实现,也可以通过将CA证书添加到服务器配置文件的堆叠CA证书文件中来实现:
xxxxxxxxxx
# cat CA1.crt CA2.crt > /etc/openvpn/movpn/ca-stack.pem
接下来,在服务器配置中使用以下内容:
xxxxxxxxxx
ca /etc/openvpn/movpn/ca-stack.pem.
这样,服务器将接受由 CA1.crt
或 CA2.crt
签名的客户端证书。
当然,如果这是一个试图连接的流氓客户端,那么更合适的解决方案可能是将客户端连接的IP地址列入黑名单。
如果客户端上的证书和私钥不匹配,那么OpenVPN甚至不会尝试连接到服务器。以下错误将打印在日志文件中:
xxxxxxxxxx
Cannot load private key file /etc/openvpn/movpn/client1.key: error:0B080074:x509 certificate routines:
X509_check_private_key:key values mismatch
Error: private key password verification failed
Exiting due to fatal error
当证书和私钥更新时,尤其会出现此问题;将旧私钥与新证书一起使用是一个常见的错误。
确保客户端的证书和私钥匹配。令人惊讶的是,没有易于使用的工具。为了确定证书和私钥是否属于一起,我们可以使用以下命令并查找模数部分:
x$ openssl x509 -text -noout -in client1.crt
[…]
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:b2:17:bd:31:6d:56:d9:eb:c9:09:98:e2:c1:48:
c9:6a:e4:4a:6b:54:52:ea:1e:60:94:6b:cb:5e:d5:
a1:ef:83:05:f8:cf:a4:06:df:06:ee:d6:c8:75:65:
de:a7:96:68:a1:41:d1:9d:f0:2c:84:3f:ca:b9:d2:
e8:07:af:37:48:24:69:57:4e:09:70:66:47:6c:47:
36:4d:c9:29:13:eb:ed:c1:aa:cd:36:84:3c:55:18:
bc:ce:01:34:b5:89:04:dc:09:c5:ea:f2:57:9f:c2:
f5:c1:05:dd:66:4d:11:13:05:47:46:26:1a:55:18:
51:bd:89:65:ba:0d:89:bd:ea:03:58:5e:d3:d9:96:
a5:5e:2f:5f:b9:c8:88:fc:48:95:cb:4a:b2:12:3b:
b5:ed:4c:40:4c:50:8d:1d:eb:a5:c9:c0:e6:2c:ec:
01:0a:56:ac:db:9e:e7:56:f0:06:f7:ba:b6:ac:de:
41:d4:fb:b3:d6:f5:fe:13:b4:03:81:d9:f7:7c:2e:
60:2f:9c:5a:81:eb:2e:3a:e1:c4:8b:f8:b6:8d:2d:
f7:ec:7a:f6:2c:ff:af:1c:d2:7b:58:ca:9e:d1:f4:
ed:8a:7a:35:00:97:a3:35:dd:79:02:b4:79:9a:66:
3c:5e:c8:4d:87:eb:68:5d:45:29:73:70:7f:61:28:
67:b1
$ openssl rsa -text -noout -in client1.key
Private-Key: (2048 bit)
modulus:
00:b2:17:bd:31:6d:56:d9:eb:c9:09:98:e2:c1:48:
c9:6a:e4:4a:6b:54:52:ea:1e:60:94:6b:cb:5e:d5:
a1:ef:83:05:f8:cf:a4:06:df:06:ee:d6:c8:75:65:
de:a7:96:68:a1:41:d1:9d:f0:2c:84:3f:ca:b9:d2:
e8:07:af:37:48:24:69:57:4e:09:70:66:47:6c:47:
36:4d:c9:29:13:eb:ed:c1:aa:cd:36:84:3c:55:18:
bc:ce:01:34:b5:89:04:dc:09:c5:ea:f2:57:9f:c2:
f5:c1:05:dd:66:4d:11:13:05:47:46:26:1a:55:18:
51:bd:89:65:ba:0d:89:bd:ea:03:58:5e:d3:d9:96:
a5:5e:2f:5f:b9:c8:88:fc:48:95:cb:4a:b2:12:3b:
b5:ed:4c:40:4c:50:8d:1d:eb:a5:c9:c0:e6:2c:ec:
01:0a:56:ac:db:9e:e7:56:f0:06:f7:ba:b6:ac:de:
41:d4:fb:b3:d6:f5:fe:13:b4:03:81:d9:f7:7c:2e:
60:2f:9c:5a:81:eb:2e:3a:e1:c4:8b:f8:b6:8d:2d:
f7:ec:7a:f6:2c:ff:af:1c:d2:7b:58:ca:9e:d1:f4:
ed:8a:7a:35:00:97:a3:35:dd:79:02:b4:79:9a:66:
3c:5e:c8:4d:87:eb:68:5d:45:29:73:70:7f:61:28:
67:b1
[…]
如果我们仔细查看公钥(证书)和私钥的模数,我们可以看到它们是相等的。因此,此证书和私钥属于一起。
贴士:在比较模数时,比较前几个字节和后几个字节通常就足够了。
auth
和 tls-auth
选项用于使用HMAC签名算法对控制通道和数据通道数据包进行身份验证。auth
HMAC算法的默认值是 SHA1
,它使用160位密钥。tls-auth
选项没有默认值,因为它不是必需的。但是,建议使用此选项,因为它提供了额外的DDoS攻击防护层。
如果客户端和服务器配置中指定的 auth
算法不匹配,则服务器将不允许客户端开始TLS安全握手。同样,如果客户端和服务器上的 tls-auth
文件不匹配,或者如果任何一方给出了错误的 direction
参数,那么服务器也将不允许客户端开始TLS安全握手。
通常,在服务器配置文件中指定以下选项:
xxxxxxxxxx
tls-auth /etc/openvpn/movpn/ta.key 0
相应地,在客户端上,我们有以下选项:
xxxxxxxxxx
tls-auth /etc/openvpn/movpn/ta.key 1
这里,第二个参数定义了所使用的 tls-auth
密钥的 direction
。此参数不是必需的,但它允许OpenVPN对传入和传出流量使用不同的哈希(或HMAC)密钥。客户端上用于对传出流量进行签名的密钥必须与服务器上用于验证传入流量的密钥匹配,反之亦然。
如果使用了错误的 tls-auth
密钥文件,或者省略了方向或未正确指定方向,则服务器日志文件中将显示以下条目:
xxxxxxxxxx
Authenticate/Decrypt packet error: packet HMAC
authentication failed
TLS Error: incoming packet authentication failed from
[AF_INET]<CLIENT-IP>:54377
与此同时,客户端将在超时发生之前尝试连接60秒。
确保在客户端和服务器配置文件中使用相同的 tls-auth
文件。此外,请确保在两端正确指定了方向参数(如果使用的话)。
如果您仍然不确定哪些HMAC密钥用于传入和传出连接,可以增加日志文件的详细程度,以查看客户端和服务器都使用的实际密钥。让我们将以下内容添加到客户端和服务器配置文件中:
xxxxxxxxxx
verb 7
现在,双方将在启动时打印出大量日志信息。日志文件中要查找的行位于服务器端:
xxxxxxxxxx
Outgoing Control Channel Authentication:
Using 160 bit message hash 'SHA1' for HMAC authentication
Outgoing Control Channel Authentication:
HMAC KEY: 4660a714 7f4d33f9 d2f7c61a 9f1d5743 4bf9411e
Outgoing Control Channel Authentication:
HMAC size=20 block_size=20
Incoming Control Channel Authentication:
Using 160 bit message hash 'SHA1' for HMAC authentication
Incoming Control Channel Authentication:
HMAC KEY: cd1f6d9c 88db5ec7 d7977322 e01d14f1 26ee4e22
Incoming Control Channel Authentication:
HMAC size=20 block_size=20
HMAC size=20
行对应于使用 SHA1
的160位消息哈希的事实,因为160位与20字节相同。
如果在客户端使用了正确的 tls-auth
文件和方向(direction)参数,我们将发现以下内容:
xxxxxxxxxx
Outgoing Control Channel Authentication:
Using 160 bit message hash 'SHA1' for HMAC authentication
Outgoing Control Channel Authentication:
HMAC KEY: cd1f6d9c 88db5ec7 d7977322 e01d14f1 26ee4e22
Outgoing Control Channel Authentication:
HMAC size=20 block_size=20
Incoming Control Channel Authentication:
Using 160 bit message hash 'SHA1' for HMAC authentication
Incoming Control Channel Authentication:
HMAC KEY: 4660a714 7f4d33f9 d2f7c61a 9f1d5743 4bf9411e
Incoming Control Channel Authentication:
HMAC size=20 block_size=20
传入和传出的控制通道身份验证密钥在客户端和服务器上镜像,以确保正确的TLS身份验证。
OpenVPN使用两种最大传输单元(Maximum Transfer Unit——MTU)大小:
tun-mtu
:指定tun适配器的 tun
设置,并指定VPN隧道内每个数据包的最大大小。link mtu
:指定隧道外每个数据包的最大大小。这包括所有填充、加密和身份验证位,但它不是在网络上传输的实际数据包大小。实际的数据包大小无法预先确定,因为每个数据包的大小可能因压缩和加密算法而异。tun-mtu
参数的默认值是1500字节,这也是以太网适配器的默认mtu大小。在正常情况下,我们可以使用以下公式从 tun-mtu
大小计算link-mtu
大小:
xxxxxxxxxx
link-mtu = tun-mtu + constant
在这里,constant
取决于所使用的配置选项。在影响此常数的配置选项中,我们有以下选项:
comp-lzo
和 comp-noadapt
cipher
选项的加密参数的初始化向量(initialization vector——IV)大小fragment
选项no-replay
选项如果我们看到 link-mtu
警告不匹配,这通常表明客户端和服务器配置文件中的其他地方配置错误。正如您将在后续示例中看到的,客户端和服务器之间的 link-mtu
不匹配可能会经常发生。通常,如果 link-mtu
不匹配,VPN连接将无法正常运行。
小贴士:通过明确设置来抵制修复 link-mtu
警告本身的诱惑。首先,修复可能导致 link-mtu
警报出现的其他警告。
在调整VPN连接时,link-mtu
参数也很有价值。为了从VPN连接中获得最大的性能,我们需要确保数据包不会被操作系统碎片化,因为这将对性能产生巨大影响。特别是在基于卫星的链路上,这可能会使性能几乎停滞不前。
如果在服务器端指定的MTU大小与客户端不同,则日志文件中将显示以下警告:
xxxxxxxxxx
WARNING: 'link-mtu' is used inconsistently,
local='link-mtu 1441', remote='link-mtu 1541'
WARNING: 'tun-mtu' is used inconsistently,
local='tun-mtu 1400', remote='tun-mtu 1500'
这表明,对于一个相当 default
的配置,link-mtu
开销实际上是41个字节。在这里,我们在客户端配置文件中添加了:
xxxxxxxxxx
tun-mtu 1400
此时,VPN连接将正常工作。然而,由于数据包需要分段和重新组装,性能将受到限制。通过发送设置了 do not fragment
标志的大型ICMP数据包,可能会触发此设置的错误。在Linux/FreeBSD上,可以使用以下命令完成此操作:
xxxxxxxxxx
$ ping -M do -s 1450 10.200.0.2
在Windows上,我们使用以下内容:
xxxxxxxxxx
C:\> ping -f -l 1450 10.200.0.2
这将导致 ping
命令100%的数据包丢失,它也会显示在日志文件中:
xxxxxxxxxx
Authenticate/Decrypt packet error:
packet HMAC authentication failed
这个错误消息起初可能看起来很混乱,但它是由发送方构造并签名了一个大于1400字节的数据包这一事实引起的。客户端仅接收此数据包的前1400个字节并检查签名,但失败。然后,它拒绝该数据包并打印出错误。
如果要使用 tun-mtu
选项,请确保在客户端和服务器配置文件中都指定了该选项。
用于OpenVPN数据通道的加密密码可以通过使用以下选项指定,默认设置为 BF-CBC
:
xxxxxxxxxx
cipher aes-256-cbc
如果客户端配置文件中指定的密码与服务器配置文件中的密码不同,则双方的日志文件都会打印出警告消息,但VPN连接会出现。然而,一旦任何流量通过它,它将无法解密。我们可以在客户端日志文件的以下摘录中看到这一点:
xxxxxxxxxx
WARNING: 'link-mtu' is used inconsistently,
local='link-mtu 1557', remote='link-mtu 1541'
WARNING: 'cipher' is used inconsistently,
local='cipher AES-256-CBC', remote='cipher BF-CBC'
WARNING: 'keysize' is used inconsistently,
local='keysize 256', remote='keysize 128'
[Mastering OpenVPN Server] Peer Connection Initiated
with [AF_INET]<SERVER-IP>:1194
TUN/TAP device tun0 opened
do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
/sbin/ip link set dev tun0 up mtu 1500
/sbin/ip addr add dev tun0 10.200.0.2/24 broadcast 10.200.0.255
Initialization Sequence Completed
Authenticate/Decrypt packet error: cipher final failed
最初打印的三个警告显示了所使用密码的不同类型和不同 size
。默认的Blowfish密码使用128位强度,而AES-256密码使用256位强度,导致加密数据包稍大(Blowfish的 link-mtu
为1541字节,AES-256的 link-mtu
为1557字节)。
确保在客户端和服务器配置文件中指定了相同的密码。由于客户端和服务器日志文件都会打印出预期的密码,因此这是一个相对容易修复的错误。
注:目前无法将密码从服务器 push
到客户端。这是OpenVPN开发人员的愿望清单,但它对代码有重大影响。在版本2.4甚至2.5之前,它不会被添加到OpenVPN中。
OpenVPN能够压缩所有正在运行的VPN流量。对于某些类型的流量,如普通网络流量,这可以提高VPN的性能,但确实会给VPN协议增加额外的开销。对于不可压缩的流量,此选项实际上会略微降低性能。
当前用于指定压缩的选项如下:
xxxxxxxxxx
comp-lzo [no|yes|adaptive]
请注意,我们不需要指定第二个参数。如果使用压缩,默认值是 adaptive
。
正如我们将在第10章“未来方向”中了解到的那样,这个选项将被一个更通用的 compression
选项所取代,允许不同的压缩机制。
可以将 compression
选项从服务器推送到客户端,但前提是在客户端配置文件本身中指定了压缩选项。如果客户端配置文件不包含此选项,则VPN连接将失败。客户端日志文件将显示以下内容:
xxxxxxxxxx
UDPv4 link remote: [AF_INET]<SERVER-IP>:1194
WARNING: 'link-mtu' is used inconsistently,
local='link-mtu 1541', remote='link-mtu 1542'
WARNING: 'comp-lzo' is present in remote config but
missing in local config, remote='comp-lzo'
[Mastering OpenVPN Server] Peer Connection Initiated with
[AF_INET]<SERVER-IP>:1194
TUN/TAP device tun0 opened
do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
/sbin/ip link set dev tun0 up mtu 1500
/sbin/ip addr add dev tun0 10.200.0.2/24 broadcast 10.200.0.255
Initialization Sequence Completed
write to TUN/TAP : Invalid argument (code=22)
服务器日志文件将列出相同的 WARNING
消息,还将显示解压缩警告:
xxxxxxxxxx
client3/<CLIENT-IP>:45113 Bad LZO decompression header byte: 42
注:奇怪但真实的是:如果我们等待足够长的时间,客户端将由于压缩错误而重新启动,并尝试重新连接。然而,这一次连接将成功,因为 comp-lzo
选项仍位于内存中。
如果要使用压缩,请确保在客户端和服务器配置文件中都指定了 comp-lzo
选项。通过客户端配置文件中的 comp-lzo
选项,我们现在可以使用 push
选项控制服务器端使用的压缩类型。使用以下内容:
xxxxxxxxxx
comp-lzo no
push "comp-lzo no"
这将关闭压缩,但不幸的是,这与根本不指定任何压缩方法不同。希望在未来的版本中解决这个问题。
最常用的调优参数之一是 fragment
选项。您将在本章稍后的“如何使用ping和iperf优化性能”一节中了解有关此选项的更多信息。
与 comp-lzo
选项一样,fragment
选项不需要在任何一侧指定。然而,我们不能只从一个方面来具体说明;必须在两者上都进行配置。如果仅在一侧指定,则必须在另一侧指定。从技术上讲,甚至没有必要为两侧的 fragment
选项使用相同的值,但建议使用。
如果客户端未指定 fragment
选项,但服务器端使用了该选项,则VPN连接将无法正常运行,如客户端日志所示:
xxxxxxxxxx
WARNING: 'link-mtu' is used inconsistently,
local='link-mtu 1541', remote='link-mtu 1545'
WARNING: 'mtu-dynamic' is present in remote config but
missing in local config, remote='mtu-dynamic'
[Mastering OpenVPN Server] Peer Connection Initiated with
[AF_INET]194.171.96.101:1194
TUN/TAP device tun0 opened
do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
/sbin/ip link set dev tun0 up mtu 1500
/sbin/ip addr add dev tun0 10.200.0.2/24 broadcast 10.200.0.255
Initialization Sequence Completed
write to TUN/TAP : Invalid argument (code=22)
同样,它看起来好像VPN已经启动(Initialization sequence completed
初始化序列完成),但日志文件将充满 code=22
错误消息。
请注意,警告实际上列出了 mtu-dynamic
,这是此功能的弃用名称。
如果要使用 fragment
选项,请确保在客户端和服务器配置文件中都指定了它。
请注意,与 comp-lzo
选项不同,此功能不能从服务器推送到客户端。
使用 tap
式网络最常见的用例是桥接设置,正如我们在第6章“tap设备的客户端/服务器模式”中所了解到的那样。然而,并非所有设备都支持轻触式网络。最值得注意的是,所有Android和iOS设备都缺乏这种功能。因此,如果我们将这样的设备连接到 tap
式OpenVPN服务器,服务器日志文件将列出来自这些客户端的警告:
xxxxxxxxxx
<CLIENT-IP>:39959 WARNING: 'dev-type' is used inconsistently,
local='dev-type tap', remote='dev-type tun'
<CLIENT-IP>:39959 WARNING: 'link-mtu' is used inconsistently,
local='link-mtu 1573', remote='link-mtu 1541'
<CLIENT-IP>:39959 WARNING: 'tun-mtu' is used inconsistently,
local='tun-mtu 1532', remote='tun-mtu 1500'
除了这些警告之外,服务器将不会检测到有关连接客户端的任何信息。在客户端上,类似的警告将与此警告一起列出:
xxxxxxxxxx
WARNING: Since you are using --dev tun with a point-to-point topology, the second argument to --ifconfig must be an IP address. You are using something (255.255.255.0) that looks more like a netmask. (silence this warning with --ifconfig-nowarn)
由于我们无法在分接式设置中推送子网拓扑,客户端将回退到默认的Net30式网络。这种类型的网络本质上与分接式网络不兼容,但除此之外,客户端不会列出任何警告或错误。
即使我们(错误地)添加拓扑子网来抑制客户端上的此警告,VPN仍然无法正常运行。
确保两侧使用相同类型的网络(tun或tap)。如果你必须使用Android或iOS设备,那么你必须设置一个tun风格的服务器配置,因为这些操作系统不支持tap风格的网络。
在第4章“使用tun设备的客户端/服务器模式”中,我们在“客户端特定配置-CCD文件”一节中了解了CCD文件及其用途。CCD文件通常用于通过 iroute
语句将客户端局域网连接到服务器网络。
OpenVPN邮件列表和论坛上的经验表明,客户端配置目录选项容易出错和配置错误。造成这种情况的三个主要原因如下:
nobody
)后,OpenVPN无法读取CCD文件或其所在的目录。client-config-dir
选项没有绝对路径。/CN=
字段中的名称相同,没有 /CN= part
,也没有任何扩展名!在 normal
的日志级别下,如果OpenVPN无法找到或读取CCD文件,它不会抱怨。它只是将传入连接视为标准连接,因此永远不会达到所需的 iroute
语句。
调试此问题的最简单方法是在服务器配置中临时添加一个额外选项:
xxxxxxxxxx
ccd-exclusive
重新启动服务器,让客户端尝试重新连接。如果服务器无法读取连接客户端的相应CCD文件,它将拒绝访问。如果发生这种情况,我们知道CCD文件尚未被读取。如果客户端可以连接,那么就存在另一个问题——很可能是路由问题。
查看OpenVPN服务器如何处理CCD文件的另一种方法是将日志级别增加到 4
,并重新连接列出CCD文件的客户端。证书 /CN=client1
的客户端的CCD文件内容如下:
xxxxxxxxxx
ifconfig-push 10.200.0.99 255.255.255.0
iroute 192.168.4.0 255.255.255.0
这指示OpenVPN服务器将VPN IP地址 10.200.0.99
分配给此客户端,并通过此客户端路由子网 192.168.4.0./24
。服务器日志文件现在列出了以下内容:
xxxxxxxxxx
<CLIENT-IP>:38876 [client1] Peer Connection Initiated with [AF_INET]<CLIENT-IP>:38876
client1/<CLIENT-IP>:38876 OPTIONS IMPORT: reading client specific options from: /etc/openvpn/movpn/clients/client1
client1/<CLIENT-IP>:38876 MULTI: Learn: 10.200.0.99 -> client1/<CLIENT-IP>:38876
client1/<CLIENT-IP>:38876 MULTI: primary virtual IP for client1/<CLIENT-IP>:38876: 10.200.0.99
client1/<CLIENT-IP>:38876 MULTI: internal route 192.168.4.0/24 -> client1/<CLIENT-IP>:38876
client1/<CLIENT-IP>:38876 MULTI: Learn: 192.168.4.0/24 -> client1/<CLIENT-IP>:38876
如果突出显示的行不存在,则不会读取CCD文件。此外,以 MULTI:
开头的下一行显示了OpenVPN服务器如何解释CCD文件中的行。这对于进一步调试任何 iroute
问题非常重要。
如果服务器进程无法读取CCD文件,请检查文件完整路径的权限,包括指向该文件的所有子目录。确保使用 user
选项指定的用户有权读取所有目录和CCD文件本身。
确保 client-config-dir
选项列出的是绝对路径,而不是相对路径。此外,如果我们使用 chroot
选项(有关详细信息,请参阅手册页),请确 client-config-dir
在 chroot-jail
中可见。
使用 ccd-exclusive
选项快速确定OpenVPN是否可以读取ccd文件。如果可以,那么增加服务器端的日志级别,看看OpenVPN如何解释CCD文件中的语句。
如果OpenVPN启动时权限不足,或者OpenVPN设置为放弃root权限并切换到另一个 userid
(例如,nobody
),那么对 tun
设备的访问可能会丢失。如果OpenVPN用于虚拟化环境,如OpenVZ或虚拟专用服务器(Virtual Private Server ——VPS),也可能发生这种情况。
如果OpenVPN启动时权限不足,则VPN连接根本不会出现:
xxxxxxxxxx
UDPv4 link local: [undef]
UDPv4 link remote: [AF_INET]<SERVER-IP>:1194
[Mastering OpenVPN Server] Peer Connection Initiated with
[AF_INET]<SERVER-IP>:1194
ERROR: Cannot ioctl TUNSETIFF tun: Operation not permitted
(errno=1)
Exiting due to fatal error
在启动OpenVPN之前,请检查 userid
或使用 sudo
切换到特权用户。
当权限不足时,更常见的情况是在VPN连接自动重启后。考虑以下客户端配置文件:
xxxxxxxxxx
client
proto udp
remote openvpnserver.example.com
port 1194
dev tun
nobind
remote-cert-tls server
tls-auth /etc/openvpn/movpn/ta.key 1
ca /etc/openvpn/movpn/movpn-ca.crt
cert /etc/openvpn/movpn/client3.crt
key /etc/openvpn/movpn/client3.key
user nobody
group nobody
这是在底部添加了两行的基本配置文件。当我们使用此配置文件启动VPN连接时,连接正常,但会打印一条警告:
xxxxxxxxxx
WARNING: you are using user/group/chroot/setcon without persist-tun -- this may cause restarts to fail
事实上,在需要重新启动VPN连接后(例如,由于网络连接不良),重新启动将失败:
xxxxxxxxxx
[Mastering OpenVPN Server] Inactivity timeout (--ping-restart),
restarting
Mon Jun 1 16:51:50 2015 /sbin/ip addr del dev tun0 10.200.0.2/24
RTNETLINK answers: Operation not permitted
Linux ip addr del failed: external program exited with error
status: 2
SIGUSR1[soft,ping-restart] received, process restarting
WARNING: you are using user/group/chroot/setcon without
persist-key -- this may cause restarts to fail
Error: private key password verification failed
Exiting due to fatal error
在这里,我们看到OpenVPN无法重新启动,因为用户 nobody
被允许读取用于此连接的私钥。如果我们指定了一个具有正确权限的用户,我们会看到一个不同的错误:
xxxxxxxxxx
ERROR: Cannot ioctl TUNSETIFF tun: Operation not permitted
(errno=1)
Exiting due to fatal error
请注意,在重新启动期间,OpenVPN无法关闭现有的 tun
设备或删除任何系统路由。如果使用 persist-tun
,也会出现这种情况,但在这种情况下,它是无害的。
如果您也使用 user
和/或 group
选项,请将以下选项添加到客户端配置文件中:
xxxxxxxxxx
persist-tun
persist-key
确保您以足够的权限启动OpenVPN。
此外,请确保OpenVPN具有正确的SELinux安全上下文,或者尝试在SELinux设置为允许或禁用模式的情况下运行OpenVPN:
xxxxxxxxxx
# setenforcing permissive
对于某些旧版本的Windows版OpenVPN安装程序,没有为OpenVPN GUI应用程序设置正确的权限。
对于这个特定的例子,从OpenVPN服务器向所有客户端推送了一条路由:
xxxxxxxxxx
push "route 192.168.122.0 255.255.255.0"
在Windows Vista及更高版本上,OpenVPN需要提升权限才能添加或删除系统路由。如果这些权限不存在,VPN通常会正确初始化,GUI图标将变为绿色。
我们甚至可以ping OpenVPN服务器的VPN服务器IP地址。但是,OpenVPN GUI中的日志文件将显示一些错误。
第一行实际上很棘手:
xxxxxxxxxx
Warning: cannot open -log file: .....: Access is denied
棘手的部分是,一旦我们点击 Disconnect 按钮,日志就会消失,因为它无法写入磁盘!这是由于默认日志目录 C:\Program Files\OpenVPN \log
只能由具有提升权限的用户访问。
日志文件中的最后几行告诉我们,OpenVPN无法添加服务器推送的路由。同样,这是由于OpenVPN程序在运行时权限不足造成的。
使用提升的权限(启用以管理员身份运行)重新启动OpenVPN GUI后,路由被正确添加。这可以从路由表中看出:推送的路由 192.168.122.0/24
现在存在于路由表中,使用服务器的VPN IP地址 10.200.0.1
作为网关。
OpenVPN电子邮件列表和用户论坛上提出的大多数问题实际上都是路由问题。设置VPN连接是一回事,但将其集成到现有网络中则是另一回事。对于新手来说,困难的部分是看OpenVPN在哪里停止,路由从哪里开始。本节旨在作为一个逐步指导,以解决相当基本的OpenVPN设置中的路由问题。
考虑以下网络计划:
为此,在主办公室设置了一个OpenVPN服务器,员工作为常规VPN客户端连接,而辅助办公室作为特殊客户端连接,公开了自己的网络。
在为OpenVPN创建配置文件之前,请绘制网络布局的详细图片,包括所有子网、IP地址、网关IP地址、接口名称等。
使用的公共IP地址未在此图片中列出,但建议这样做。此外,来自在家工作的人的连接也不包括在内,但他们将连接到上图中 gateway1
的公共IP位址。
在 gateway1
上,添加了一个端口转发规则,因此端口 1194
上的传入和传出UDP流量被转发到 172.31.1.2:1194
的OpenVPN服务器。
由于我们需要在二级办公室披露网络,我们还需要使用带有适当 iroute
语句的 client-config-dir
文件。
此设置的服务器和客户端配置文件已在第4章“带tun设备的客户端/服务器模式”中列出,但有一些细微的IP地址更改。新的配置文件集如下:
xxxxxxxxxx
proto udp
port 1194
dev tun
server 10.200.0.0 255.255.255.0
tls-auth /etc/openvpn/movpn/ta.key 0
dh /etc/openvpn/movpn/dh2048.pem
ca /etc/openvpn/movpn/movpn-ca.crt
cert /etc/openvpn/movpn/server.crt
key /etc/openvpn/movpn/server.key
persist-key
persist-tun
keepalive 10 60
topology subnet
user nobody
group nobody
verb 3
daemon
log-append /var/log/openvpn.log
push "route 172.31.1.0 255.255.255.0"
client-config-dir /etc/openvpn/movpn/clients
route 192.168.3.0 255.255.255.0 10.200.0.1
此文件保存为 movpn-09-01-server.conf
。对于辅助办公室中的OpenVPN客户端,会创建一个名为 /CN=SecondaryOffice
的特殊证书。因此,相应的CCD文件名为 /etc/openvpn/movpn/clients/SecondaryOffice
。其内容如下:
xxxxxxxxxx
ifconfig-push 10.200.0.200 255.255.255.0
iroute 192.168.3.0 255.255.255.0
对于所有客户端,可以使用 basic-udp-client.conf
或 basic-upp-client.ovpn
配置文件。顺便说一句,这显示了OpenVPN配置文件的灵活性。在大多数情况下,即使修改了服务器端的网络布局,或者将辅助网络引入VPN,也不需要更改客户端配置文件。
接下来,我们启动OpenVPN服务器和辅助办公室客户端,并确保CCD文件已被拾取。辅助办公室的VPN客户端可以在其VPN IP地址上 ping
OpenVPN服务器,家里的测试用户也可以。
注:此时,VPN正在工作,但路由不起作用。
解决此设置问题的最有效方法是将VPN链接视为中间,然后逐步向外工作,直到网络的所有部分都连接起来。首先,在二级办公室的OpenVPN客户端上要执行一些测试。对于几乎所有的测试,一个简单的 ping
命令就足够了。
请注意,如果第一个测试失败,则继续进行第二个测试是没有意义的,同样,如果第二个检测尚未工作,则继续第三个测试也是没有意义的:
客户端可以访问服务器的VPN IP地址吗?
这应该起作用;否则,我们的VPN有问题。这可能是服务器上非常严格的防火墙/iptables设置。VPN服务器IP应该是私有的(通常为RFC1918),因此不能在普通互联网上路由。
客户端可以访问服务器的局域网IP地址吗?
如果这不起作用,那么很可能是防火墙或iptables规则阻止了访问。检查入站规则或尝试禁用防火墙规则进行调试。
客户端可以访问服务器端网关IP地址吗?
如果没有,请检查以下问题的答案:
gateway1
上IP为 172.31.1.2
的OpenVPN服务器。请注意,通常情况并非如此。将此类路由添加到网关的实际语法取决于所用路由器的型号和固件。客户端能否连接到服务器端局域网上的另一台服务器?
如果没有,请检查以下问题的答案:
在确保客户端可以访问服务器端局域网上的所有机器之后,是时候确保反过来也是正确的了。确保OpenVPN服务器可以访问辅助客户端后面局域网上的所有机器。要进行的测试非常相似:
服务器可以访问客户端的VPN IP地址吗? 这应该起作用;否则,我们的VPN有问题。这可能是客户端上非常严格的防火墙/iptables设置。然而,在这一点上,这不太可能成为问题。不过,安全总比后悔好,所以让我们来测试一下。
服务器能否访问客户端的局域网IP地址? 如果这不起作用,那么很可能是防火墙/iptables规则阻止了访问。检查入站规则。
服务器可以访问客户端网关IP地址吗? 如果没有,请检查以下问题的答案:
10.200.0.1
的流量。10.200.0.1
的数据包应转发到路由器 gateway2
上IP 192.168.3.17
的OpenVPN客户端。请注意,通常情况并非如此。将此类路由添加到网关的实际语法取决于所用路由器的型号和固件。此外,请注意,我们只允许来自OpenVPN服务器本身的数据包通过,因为所有其他客户端都不需要访问此网络。OpenVPN服务器可以连接到客户端局域网上的另一台机器吗? 如果没有,请检查以下问题的答案:
此时,二级办公室的OpenVPN客户端应该能够访问服务器端局域网中的所有机器,而主办公室的OpenVPP服务器应该能够访问客户端局域网中的全部机器。只有一个步骤:确保服务器端局域网上的服务器可以连接到客户端局域网上的服务,反之亦然。同样,有四个测试要执行,从服务器端局域网上的机器开始:
【略】
通过有条不紊地完成所有这些步骤,我们可以解决几乎所有的路由问题。在某些情况下,可能需要更高级的调试技术。这可能需要我们暂时禁用防火墙规则,因此在尝试之前应该特别小心。
OpenVPN邮件列表中有太多人无法使用路由的情况,事实证明这是一个过于严格的防火墙或iptables规则。无需禁用所有防火墙规则,但如果您在前面列出的十二个步骤中遇到困难,请尝试禁用与您无法访问或正在发送流量的设备相关的防火墙。
注:如果您需要使用NATted设置,请确保您没有禁用NATting规则。
低级网络工具 tcpdump
是测试连接性的好工具。为了调试路由问题,我们可以使用 tcpdump
查看是否有任何流量到达或离开特定的网络接口,我们可以检查此流量的源地址和目标地址。在Windows客户端或服务器上,运行Wireshark可能更容易(http://www.wireshark.org),其提供类似的功能,包括GUI。
在前面列出的十二个步骤中,以下 tcpdump
语句可以提供帮助:
1、在服务器上运行 tcpdump -nnel -i tun0
,查看是否有任何流量通过VPN进入。
2、在服务器上运行 tcpdump-nnel-i eth0
(其中 eth0
是正在使用的服务器的LAN接口),查看LAN接口上是否有任何流量。如果没有,那么很可能防火墙规则正在丢弃隧道接口上的入站流量。
3、在服务器上运行 tcpdump-nnel-i eth0
,查看是否有任何流量通过以下方式离开LAN接口:
xxxxxxxxxx
source address = 10.200.0.200
destination address = 172.31.1.254
此外,检查我们是否可以看到源地址和目标地址颠倒的服务器端网关的返回流量。
4、再次,在服务器上运行 tcpdump -nnel -i eth0
,查看是否有任何流量使用以下数据包头离开LAN接口:
xxxxxxxxxx
source address = 10.200.0.200
destination address = 172.31.1.XXX
这里,172.31.1.XXX
是我们试图在服务器端局域网上访问的机器的IP地址。看到回程车辆了吗?
接下来的步骤,以此类推!
从OpenVPN设置中获得最大性能可能很难实现。在干净的以太网网络上,OpenVPN的默认设置相当不错。然而,在千兆速度的网络上需要进行一些调整。
当使用ADSL或电缆调制解调器连接时,性能通常也很好。然而,在某些情况下,我们的OpenVPN隧道的性能可能远远落后于正常网络的性能。这些情况几乎总是依赖于ISP,但无论如何,探索如何提高性能是值得的。
优化性能的关键是首先要有良好的工具来衡量性能。测量网络性能的两个基本但非常宝贵的工具是 ping
和 iperf
。iperf
工具在Linux、FreeBSD和Mac OS上很容易获得。有适用于Windows甚至Android的端口。
使用 ping
,我们可以确定网络的最佳MTU大小。大多数网络运营商现在为客户提供1500字节的以太网式MTU。这导致1472字节的有效数据包有效载荷。剩下的28个字节是源地址和目标地址等TCP/IP开销。
但是,如果客户端和服务器之间的网络具有较低的MTU,那么它可以大大提高性能,将OpenVPN数据包的大小减小到略低于该大小。要了解我们网络的最大传输大小,我们使用以下方法:
xxxxxxxxxx
$ ping -M do -s 1472 www.example.org
在Windows上,我们使用以下内容:
xxxxxxxxxx
C:\> ping -f -l 1472 www.example.org
这将向我们选择的远程服务器发送ICMP数据包,并设置 do not fragment
标志,指示网络路由器不要将此数据包分解为更小的比特。如果客户端和服务器之间存在MTU较小的网络,则 ping
命令将失败:
xxxxxxxxxx
$ ping -M do -s 1472 www.example.org
PING www.example.org (IP) 1472(1500) bytes of data.
ping: local error: Message too long, mtu=1480
这告诉我们,如果我们使用1480的 fragment
大小或1480字节的MTU大小而不是默认值 1500
,那么性能很可能会提高。请注意,这并不能保证——只有通过测量实际的VPN性能,我们才能知道实际的影响是什么。
通过使用 iperf
,我们可以测量VPN隧道内外的网络性能。这将让我们深入了解使用VPN隧道浪费了多少带宽。
在测量VPN隧道本身的性能之前,请务必尝试测量正常网络的性能。很难使VPN的性能优于底层网络。
首先,使用以下命令在服务器上启动 iperf
:
xxxxxxxxxx
$ iperf -s
接下来,使用以下命令在客户端上启动 iperf
:
xxxxxxxxxx
$ iperf -c openvpn.example.org
在用于测试的电缆网络上,结果如下:
【略】
这实际上是所用电缆连接的上传速度。我们现在可以在同一网络上测试VPN隧道的性能:
xxxxxxxxxx
[ 3] 0.0-10.8 sec 5.25 MBytes 4.09 Mbits/sec
重复测量得到的数字非常相似,因此可以公平地说,VPN隧道的性能比底层网络低几个百分点。这实际上是有道理的,因为使用VPN确实会为原始数据的封装、加密和身份验证(签名)带来一些开销。很难进一步优化这个网络。
同样,对于所使用的电缆连接的下载速度,我们发现VPN隧道的性能要低几个百分点:
底层网络的性能如下:
xxxxxxxxxx
[ 4] 0.0-10.6 sec 51.6 MBytes 40.7 Mbits/sec
现在,将其与VPN隧道进行比较:
xxxxxxxxxx
[ 4] 0.0-10.7 sec 49.5 MBytes 39.0 Mbits/sec
我们再次看到性能下降了4.5%。
我们现在可以使用fragment和mssfix参数来查看是否可以提高性能。为了找到特定设置的最佳点,将进行一些试错工作。目前尚不清楚确切的最佳点是什么,但找到它的方法总是一样的。现在,将选项添加到客户端和服务器配置文件中:
xxxxxxxxxx
fragment X
mssfix
通过这样做并改变 x
,我们得到以下结果:
X (bytes) | Download (Mbps) | Upload (Mbps) |
---|---|---|
1200 | 37.9 | 3.94 |
1300 | 38.1 | 4.01 |
1400 | 38.4 | 4.04 |
1472 | 38.8 | 4.06 |
1500 | 37.6 | 3.98 |
<none> | 39.0 | 4.09 |
我们可以得出结论,OpenVPN的默认设置实际上是这个网络的最佳选择。我们可以通过改变 tun-mtu
参数来重复这个练习,但我们会发现相同的结果。然而,建议首先使用 fragment
参数来调整性能,因为该参数对数据包的转发影响较小。
我们现在将在未使用的千兆以太网上执行相同的过程。底层网络的 iperf
性能上下为950 Mbps。
当我们使用 basic-udp-server.conf
配置启动OpenVPN服务器,并使用 basic.udp-client.conf
配置文件将客户端连接到该服务器时,我们实现了以下 iperf
性能:
xxxxxxxxxx
[ ID] Interval Transfer Bandwidth
[ 5] 0.0-10.0 sec 193 MBytes 161 Mbits/sec
[ 4] 0.0-10.0 sec 242 MBytes 203 Mbits/sec
现在表现明显下降。不幸的是,降低 fragment
参数在这里对我们没有帮助。使用 fragment 1200
,我们分别实现了149 Mbps和115 Mbps。
在高速网络上,尝试加密密码也是有意义的。由于CPU上存在AES-NI扩展(分别为2 GHz Xeon E5 2620和3.5 GHz(turbo)Xeon E5 2643),本例中使用的服务器都能够执行快速AES指令。让我们添加以下内容:
xxxxxxxxxx
cipher aes-256-cbc
我们现在得到以下结果:
xxxxxxxxxx
[ 5] 0.0-10.0 sec 316 MBytes 265 Mbits/sec
[ 4] 0.0-10.0 sec 266 MBytes 223 Mbits/sec
在功能强大的CPU上,密码对性能有很大的影响。由于OpenVPN是一个单片程序,大量的内核根本没有帮助。CPU的时钟速度是一个主要因素。通过将3.8 GHz(涡轮增压)Core i7笔记本电脑连接到3.5 GHz Xeon E5-2643服务器,我们使用完全相同的配置实现了更高的吞吐量:
xxxxxxxxxx
[ 5] 0.0-10.0 sec 707 MBytes 593 Mbits/sec
[ 4] 0.0-10.0 sec 529 MBytes 443 Mbits/sec
因此,如果你想在高速网络上设置OpenVPN隧道,那么最好的建议是使用支持AES-NI指令集的高时钟速度CPU。通过这样的设置,可以在两个方向上实现超过500 Mbps的网络速度。
低级网络工具 tcpdump
或其GUI等效工具Wireshark是解决网络问题和网络性能的最后手段。在本节中,我们将介绍捕获和分析OpenVPN产生的加密网络流量的过程。
首先,我们使用 basic-udp
配置文件设置我们的标准OpenVPN网络。在客户端上,还有一个web服务器正在运行。我们将在服务器端使用 wget
命令从web服务器检索文件,以便查看由此产生的网络流量。
我们在以太网接口上运行 tcpdump
,并在隧道外执行 wget
时捕获网络流量:
xxxxxxxxxx
wget -O /dev/null https://CLIENT-IP/test1
tcpdump
输出结果如下(为清楚起见进行了修改):
【略】
正如我们所看到的,传输一个5KB的文本文件需要13个数据包。这些数据包中的大多数用于建立和断开连接,但有四个大数据包用于实际传输数据。四个数据包中的前三个数据包的大小为1514字节,这是以太网数据包的最大大小。
接下来,我们在隧道内运行相同的 wget
命令。我们现在观察以太网适配器上的加密流量:
【略】
在这里,我们看到22个数据包被捕获。前两个和后两个数据包是OpenVPN heartbeat
数据包,可以忽略。其余18个数据包是第一个 tcpdump
输出中所示数据包的加密等效数据包。正如我们在这里看到的,数据包的长度稍小,尤其是每个数据包的 payload
要小得多:最大的UDP payload
数据包是1445字节。这1445个字节包含来自 wget
命令的加密和签名数据。在我们的设置中,我们没有指定 fragment
参数,这意味着OpenVPN 2.3将默认为1450字节的内部片段。
每个数据包的总大小永远不会超过1487字节,这相当接近最佳值:通常,数据包不应超过MTU大小,即1500字节。
这个 tcpdump
屏幕转储还显示,除了OpenVPN之外,没有发生碎片。这很好,因为我们希望避免操作系统或网络造成的数据包碎片,以获得最佳性能。如果我们在这里看到了数据包碎片,那么这将是一个很好的迹象,表明我们需要在OpenVPN配置中添加额外的碎片。
让我们来看看如果我们将 fragment 1400
添加到我们的设置中会发生什么。我们重新启动服务器和客户端,然后重新运行 wget
命令。
在我们的设置中添加了 fragment 1400
后,我们可以在 tcpdump
输出中看到,数据包的有效载荷现在是1397字节,非常接近1400的限制。我们还可以看到,现在需要更多的数据包才能通过隧道传输5KB的文本文件,这意味着性能下降。从这个屏幕截图中,我们可以得出结论,我们应该再次删除该参数。
从前面的屏幕截图和前面的截图中,我们还可以推断出每个OpenVPN数据包都会产生42字节的开销。这种开销在一定程度上导致了使用任何VPN解决方案所产生的开销。它确实包含了整个开销,因为所有网络数据包都需要包含有关源地址、目的地址、数据包类型、校验和、标志等的开销信息。
最后,让我们来看看实际加密的OpenVPN数据包的内容。为此,使用Wireshark工具很方便(http://www.wireshark.org). Wireshark基本上在低级 tcpdump
工具之上提供了一个GUI。它可以解码大多数类型的网络流量的内容。
输出结果告诉我们以下内容:
payload
是OpenVPN数据包(格式版本1),有效载荷大小为1487字节。请注意,tcpdump之
前报告了1488个字节,但Wireshark可以解码有效载荷,并看到第一个字节是OpenVPN操作码。此数据包将由OpenVPN接收,检查身份验证,解密和解压缩(如果我们指定的话)。然后将得到的未加密数据包转发到操作系统的路由表,路由表决定将数据包路由到哪里。在我们的例子中,数据包将保留在服务器上,并将被提供给 wget
进程。
在本章中,您学习了一些排除和调整OpenVPN的基本技术。您还了解了如何读取客户端和服务器日志文件。你学会了如何发现和修复一些最常犯的错误。OpenVPN电子邮件列表中的大多数问题都是关于路由问题的,因此我们讨论了检测和修复路由问题。最后,工作设置和良好工作设置之间存在很大差异,因此我们查看了如何检测和解决性能问题的示例。
当然,OpenVPN并不完美,因此您的非工作设置也可能是由OpenVPN本身的错误引起的。有几种报告错误的渠道,包括电子邮件列表(openvpn-users@lists.sourceforge.net),一个IRC频道(freenode.net IRC上的 #openvpn
)和一个论坛网站(https://forums.openvpn.net). 您还可以向这些频道报告功能请求或愿望列表,其中一些可能会成为OpenVPN的未来版本。
在下一章中,您将了解即将发布的OpenVPN版本中的新功能。您还将了解OpenVPN代码库目前已知的问题,以及解决这些问题的计划。