第四章:具有tun设备的Client/Server模式

OpenVPN最常用的部署模型是具有多个远程客户端的单个服务器,能够路由IP流量。我们将此部署模型称为具有tun设备的clinet/server模式。

在本章中,我们从基本的客户端/服务器设置开始。我们将继续添加更多功能,本章末尾给出了一些关于如何在客户端/服务器tun模式下设置OpenVPN的高级示例。在下一章中,我们将解释如何将基于客户端/服务器tun的设置集成到现有的网络设置中,包括Windows文件共享和基于策略的路由等主题。

本章将涵盖以下主题:

理解 client/server 模式

客户端/服务器模式最初是在OpenVPN2.0中引入的。在这种模式下,服务器是一个单一的OpenVPN进程,多个客户端可以连接到该进程。每个经过身份验证和授权的客户端都会从OpenVPN服务器管理的IP地址池中分配一个IP地址。客户端不能直接互相通信。所有流量都通过服务器流动,这既是优点也是缺点。

优点如下:

缺点如下:

此模式最常见的部署场景是各种VPN客户端连接到的公司网站上的OpenVPN服务器。客户端可能包括分公司、流动工作者、在家工作的人,以及智能手机和平板电脑用户。

这种部署模型涵盖了VPN 95%的典型要求,并且比使用桥接等高级功能的更复杂的设置更可取。只有当路由非IP流量(例如,传统IPX流量)有特殊需求,或者需要形成一个单一的网络广播时,这种部署模型才是不够的。

建立公钥基础设施

在客户端/服务器模式下,OpenVPN使用带有X.509证书和私钥的公钥基础设施(Public Key Infrastructure——PKI)进行设置。在设置客户端/服务器VPN之前,我们需要先设置此PKI。PKI由CA、私钥和客户端和服务器的证书(公钥)组成。在第三章PKI和证书中,我们曾详细讨论了如何建立这样的PKI。本章以该章中生成的证书和密钥为基础。

首先,我们将证书和密钥复制到一个单独的位置。一般来说,将PKI文件保存在单独的位置时一种良好的安全做法,如果可能的话,甚至在单独的计算机上。应特别注意保护好ca.key文件,因为PKI的整个安全性都依赖于此文件。如果ca.key文件以任何方式被泄露,整个PKI将变得不安全,应该被放弃。在以下命令中,假设PKI文件是使用 ssladmin 生成的,并存储在目录 <PKI_DIR> 中,其中 <PKI_DIR> 表示系统上的真实目录。执行以下命令以复制服务器所需的PKI文件:

我们还需要生成VPN会话密钥所需的DH(Diffie-Hellman)参数文件。会话密钥是临时密钥,在首次建立客户端和服务器之间的连接时生成。为了确保最佳安全性,在会话期间以固定间隔重新生成临时密钥。OpenVPN的默认密钥间隔为一小时,但可以使用各种OpenVPN选项进行调整。本章稍后将在 Session key renegotiation (会话密钥重新协商)一节中对此进行解释。

要生成DH参数文件,请执行以下命令:

此例中,我们选择2048位的DH密钥大小,这是推荐的大小。DH过大会使每个OpenVPN客户端的初始连接变慢。我们现在已经准备好设置和启动OpenVPN服务器。

客户端/服务器模式的初始设置

为了设置基本的OpenVPN服务器,我们首先使用以下步骤创建服务器配置文件:

1、创建以下文件(各条目内容含义详见下一节):

2、将此文件保存为 movpn-04-01-server.conf 。稍后将给出每条配置线的详细说明。

3、启动OpenVPN服务:

4、该命令不会在命令行上产生任何输出,因为所有输出都被重定向到日志文件 /var/log/openvpn.log 。检查此文件以了解OpenVPN的启动消息详细信息:

5、注意,通常每个日志文件条目都以时间戳开头。为清楚起见,此时间戳已被删除。

6、接下来,创建客户端配置文件(各条目内容含义详见下一节):

将其保存为 movpn-04-01-client.conf

7、使用安全通道(例如scp命令)将PKI文件传输到客户端:

8、启动OpenVPN客户端:

9、时间戳再次丢失,但这次使用OpenVPN选项 suppress-timestamps 来抑制它们,如以上命令行上指定的。

10、连接启动后,检查以上信息中有以下一句:

11、你可以通过ping服务器的VPN地址来验证连接是否正常运行。

配置文件的详细说明

服务器配置文件包含以下行:

客户端配置文件包含以下内容:

client

指定OpenVPN进入客户端模式。

它指示OpenVPN连接到远程服务器,并在成功连接后从服务器中提取和处理配置参数。

客户端声明内部扩展如下:

proto udp

指定要使用的协议。虽然默认是tun,但强烈建议在配置文件中明确指出,以避免混淆。

remote openvpnserver.example.com

指定要连接的VPN服务器的名称。该名称可以是FQDN或IPv4地址。在本章后面,我们将介绍如何连接到基于IPv6的VPN服务器。

port 1194

指定OpenVPN客户端使用哪个端口连接服务器。默认值为1194,但可以使用任何有效的可用端口号(取决于服务器的设置)。

也是使用以下方式组合remoteport

dev tun

指定用于服务器的tun设备的名称。tun后面不添加数字,意味着OpenVPN连接时打开一个新的tun设备。这个新设备将被分配系统内核中的第一个可用编号。编号从0开始。

对于Windows服务器,建议保持此行不变。如果需要使用特定的Windows设备,则需要选项dev-node

nobind

指示OpenVPN客户端不要绑定(也不要监听)使用port指定的端口。

相反,OpenVPN客户端将使用匿名端口范围内的端口,通常是1024-65535。

ca <path to CA file>

指定CA文件的路径。此CA文件需要包含用于对服务器证书进行签名的CA证书(甚至证书集)。它不一定必须与用于签署客户端证书的CA相同,尽管我们在PKI设置中使用了相同的CA。

在linux/Unix上,建议为此文件(以及其他证书和私钥的路径)使用绝对路径。

cert <path to X.509 certificate file>

指定此客户端X.509公共证书的路径。可以将OpenVPN配置为使用用户名/密码身份验证而不是证书,但这样不安全。

在linux/Unix上,建议为此文件(以及其他证书和私钥的路径)使用绝对路径。

key <path to private key file>

指定客户端私钥文件路径。此文件需要仅由root(或管理员)用户读取,因为OpenVPN将在删除用户权限之前读取此文件。

在linux/Unix上,建议为此文件(以及其他证书和私钥的路径)使用绝对路径。

注意,我们没有为客户端配置指定 daemonlog-append ,因为在大多数情况下,包装器应用程序将启动 openvpn 进程。然后,此包装器应用程序将控制OpenVPN的日志记录。最常见的包装应用程序有:

操作系统包装应用程序
WindowsOpenVPN-GUI.exe(OpenVPN 安装包的一部分)
Mac OS XTunnelblick 或 Viscosity
LinuxNetworkManager(含OpenVPN插件)

拓扑subnet 对比 拓扑net30

OpenVPN在tun模式下支持多种拓扑结构:

拓扑net30是当前默认值。在此模式下,OpenVPN为每个客户端(以及服务器)设置一个点对点网络接口,并为每个客户端分配一个/30子网。这意味着服务器和客户端都被分配了一个由四个IP地址组成的块。在服务器配置文件种,指定了服务器10.200.0.0 255.255.255.0。对于拓扑net30,这会导致OpenVPN分配以下IP块:

如你所见,这不是一种非常有效的分配IP地址的方法——对于每个VPN客户端,分配四个IP地址。对于小型VPN设置,这种方法可以很好地工作,但这种方法不适用于连接了100多个客户端的服务器。

为了克服这个问题,引入了topology subnet(拓扑子网模)式。它允许OpenVPN为所有客户端分配一个IP地址,这使得管理大规模VPN变得更容易。服务器端路由存在一些问题(详细信息可参阅本章少受的路由和服务器端路由部分),这些问题阻止了此拓扑模式成为默认拓扑模式,但预计从2.4版本开始,这将是默认拓扑模式。

添加额外的安全性

初始配置文件集是客户端/服务器部署的良好起点。然而,对于生产级系统,我们希望增加更多的安全性。可以通过两种方式增强安全性:

使用 tls-auth 密钥

在C/S模式下,OpenVPN将尝试为每个尝试连接的客户端建立TLS控制通道。设置TLS控制通道会消耗资源,这使得OpenVPN容易受到拒绝服务攻击:攻击者可以启动大量配置错误的客户端,这些客户端都试图连接到OpenVPN服务器。对于每种情况,OpenVPN服务器都会尝试建立TLS连接,这将有效地导致配置良好的客户端拒绝服务。当OpenVPN使用proto udp(推荐的默认值)运行时尤其如此。UDP流量是无连接的,这意味着对于服务器接收到每个新UDP数据包,它都必须验证对方是否是有效的OpenVPN数据包。

为了解决这个可能的漏洞,OpenVPN使用 tls-auth 选项在TLS控制通道中引入了一个额外的身份验证层。此TSL身份验证必须使用预共享密钥完成,因为服务器尚不知道是否有有效的客户端正在尝试连接。用于此目的的预共享密钥与点对点模式中使用的密钥完全相同,可参阅第二章所述。

生成 tls-auth 密钥

与第二章一样,可以使用以下命令生成tls-auth密钥:

就像客户端的私钥文件一样,此文件需要使用安全通道复制到每个客户端,或者需要包含在安全客户端配置包中:

检查证书密钥使用属性

生成X.509证书时,可以将特殊的扩展密钥使用(Extended Key Usage——EKU)属性添加到证书中。这允许我们指定证书的用途,例如仅作为服务器证书或仅作为客户端证书。安全网站使用的证书使用相同的EKU属性。

在生成服务器证书或非服务器(客户端)证书时,easy-rsa 脚本和 ssladmin 工具默认设置EKU属性。要检查证书的EKU属性,请使用以下命令:

以上信息表明,server.crt 证书只能用于服务器身份验证。

旧证书可能没有设置这些EKU属性,而是使用(已弃用的) Netscape Cert Type 属性。easy-rsa 脚本和 ssladmin 工具也设置了此属性:

但是,此证书只能设置为服务器端证书。

通过检查这些属性可以提高OpenVPN的安全性。为此,我们使用选项 remote-cert-tls

remote-cert-tls client 选项指示OpenVPN服务器只允许来自具有X.509 EKU属性设置为 TLS Web Client Authentication 的证书的VPN客户端连接。

这可以防止黑客使用客户端证书设置流氓(rogue)OpenVPN服务器。

同样,对于客户端,remote-cert-tls server 选项指示OpenVPN客户端只允许连接到具有X.509 EKU属性设置为 TLS Web Server Authentication 的证书的VPN服务器。

这可以防止恶意客户端设置流氓OpenVPN服务器来吸引其他VPN用户的连接。

还可以检查 Netscape Cert Type 属性。由于这是服务器证书的属性,OpenVPN客户端在连接时需要检查此服务器。为此,可以使用 ns-cert-type server 选项。最好使用 remote-cert-tls 选项。

基本生产级配置文件

我们扩展了之前的客户端和服务器配置文件,以使用新创建的 tls-auth 密钥。我们通过在配置文件 movpn-04-01-server.conf 中添加一行以及第二个安全增强选项来实现这一点:

注意,此配置文件中语句的顺序是随机的。可以在文件中任意位置添加remote-cert-tlstls-auth 行。

此服务器配置文件是一个基本的服务器配置文件,我们将在本章和其他章节中重复使用。将其另存为 basic-udp-server.conf ,以便我们以后可以重用它。

我们在客户端配置文件 movpn-04-01-client.conf 中添加了两行类似的代码:

将以上文件保存为 basic-udp-client.conf

tls-auth 选项的第二个参数是所谓的密钥方向。OpenVPN支持使用方向密钥(directional keys),也就是说,传入和传出数据使用不同的密钥。这进一步增强了安全性。方向标志需要在一端为0,在另一端为1。在C/S模式下,这意味着服务器的方向参数为0,所有客户端的方向参数都设置为1。

当我们启动OpenVPN服务器时,我们可以看到TLS控制通道现在使用静态密钥进行保护:

同样的,当我们启动OpenVPN客户端,可以看到:

基于TCP的设置

OpenVPN使用的默认协议是UDP。根据之前创建的配置文件创建基于TCP的版本非常简单。在客户端和服务器配置文件中,将 proto udp 改为 proto tcp 。下面列出了整个基于TCP的服务器的配置文件:

将此文件保存为 basic-tcp-server.conf

同样的,修改客户端配置文件:

将其保存为 basic-tcp-client.conf

Windows下的配置文件

Windows平台的基本配置文件与Linux/Unix或Mac OS平台的配置文件略有不同。在Windows平台上,使用 Openvpn-GUI.exe 包装器,它要求所有配置文件都存储在目录 c:\Program Files\OpenVPN\config 或其子目录中。

其他语言的Windows版中 Program Files目录可能不同,在所有语言中,Windows的环境变量 %PRIGRAMFILES% 将指向正确的位置。

因此,基本的UDP和TCP配置文件实际上略短。创建UDP客户端配置文件:

将其另存为basic-udp-client.ovpn,以便我们可以在本书后面重复使用。

同样,创建客户端配置:

保存为 basic-tcp-client.ovpn

路由和服务器端路由

只有当VPN客户端可以访问服务器端资源时,VPN才真正有用。为了访问这些资源,在大多数情况下需要路由。OpenVPN有很多选项,可以在客户端连接或断开时自动设置和删除额外的路由。

应该指出的是,大多数OpenVPN故障排除问题都与路由有关。设置VPN连接是一回事,让网络流量正常流动是另外一回事。这通常与OpenVPN本身关系不大,但更多地与客户端和服务器的路由表和防火墙规则有关。

这里描述了访问服务器端网络上资源的最常见布局:

【有图,略】

服务器端的LAN是192.168.122.0/24。VPN客户端需要访问的资源位于此子网上。因此服务器需要指示VPN客户端需要设置额外的路由。这是使用 push 选项完成的,其中路由配置被推送到客户端。也可以通过将路由添加到客户端配置文件本身来实现,但这并不能很好地扩展。这是因为对于每个新的服务器端网络路由,都需要更新所有客户端配置文件。

我们从 basic-udp-server.conf 开始,添加一行:

将其保存为 movpn-04-03-server.conf 然后用这个配置文件启动OpenVPN服务器。此次,我们使用Windows7 64-bit专业版作为OpenVPN客户端,此客户端电脑安装了X86_64版的OpenVPN 2.3.4-I004。将以下文件复制到Windows电脑:

将它们放在 %PROGRAMFILES%\config 中。

启动OpenVPN GUI应用,选择设置 basic-udp-client 然后按 Connect

【有图。略】

成功建立连接后,OpenVPN GUI图标变为绿色,悬停在图标上时显示连接信息。

我们现在可以通过打开命令shell并ping服务器来验证到服务器的VPN连接是否正常工作。

在我们验证我们可以访问OpenVPN服务器后,我们需要确保OpenVPN服务器正在转发IP流量,我们需要在服务器端网关上添加一条额外的路由,以确保VPN流量通过VPN服务器正确路由回来。如果没有此路由,服务器端网络上的机器现在将知道IP地址为10.200.0.0/24的VPN流量来自哪里,并且很可能会错误地路由或丢弃数据包:

现在,我们检查客户端的路由表,并验证我们可以访问服务器端局域网上的机器。

【有图,略】

输出的第一部分显示,VPN子网10.200.0.0/24的多条路由已添加到路由表中,包括pushed网络192.168.122.0/24的路由。注意输出中的最后一列,它显示了路由度量。Windows计算一个度量(在这种情况下为286),但可以使用正确的route语句来推翻它。使用push route 192.168.122.0 255.255.255.0添加的路由具有较低的度量,因为指定了OpenVPN默认度量30。

路由选项的特殊参数

与第二章点对点模式中的解释类似,配置语句 push route <network> <netmaks> [vpn_gateway] [metric] 在此设置中至关重要。route 选项最多接受四个参数,其中两个是必需的,另外两个是可选的。这是在该设置中其重要作用的第三个参数。vpn_gateway 是一个特殊的OpenVPN关键字,它指定了VPN远程端点地址。通常,不必指定此关键字,除非还需要为此路由指定度量(metric)。

route 语句的完整语法是 route <network> <netmask> [gateway] [metirc] ,其中gateway可以显式设置为IPv4地址,也可以使用特殊关键字 vpn_gatewaynet_gateway 中的任何一个。如果没有指定网关和度量,则使用 vpn_gateway

关键字 net_gateway 可用于指定不应通过VPN明确路由的子网。对于 net_gateway,将替换建立VPN连接之前的默认网关。

该度量有一个默度量,可以使用 route-metric m ,然后应用于所有路由。如果你想推翻特定路由的度量(就像我们在这个例子中所做的那样),那么需要指定网关(在我们的例子中是 vpn_gateway ),然后指定该特定路由的metric。

伪装

有时,无法添加服务器端路由将所有VPN流量重定向回OpenVPN服务器。在这种情况下,一种快速而肮脏的方法是使用伪装(masquerading)。在Linux上,你可以使用iptables命令在服务器上设置伪装:

iptables 语句指示Linux内核重写来自VPN子网10.200.0.0/24并离开以太网接口eth0的所有流量。离开eth0接口的流量会重写其源地址,使其看起来像是来自OpenVPN服务器本身,而不是来自OpenVPN客户端。这是使路由正常工作的一个简单快捷方式,但缺点是不再可能区分此流量是来自OpenVPN服务器本身,还是来自连接的客户端之一。

重定向默认网关

VPN的一个非常常见的用途是通过安全隧道路由所有流量。这使得人们可以再恶劣的环境中(例如,保护不力的网吧)安全地访问网络,甚至互联网本身。

重定向默认网关是通过在服务器配置文件中添加 push "redirect-gateway [def1 local bypass-dhcp bypass-dns]"来实现的。

前面列出的 redirect-gateway 的参数是可选的,但它们可以发挥非常重要的作用:

除了选项 redirect-gateway 之外,我们还可以指定选项 push "redirect-private [def1 local bypass-dhcp bypass-dns]" 到服务器配置文件。此选项采用于 redirect-gateway 相同的参数,但它根本不会更改现有的默认网关。这对于推送私有子网非常有用。

现在,我们将 push "redirect-gateway def1" 添加到 basic-udp-server.conf 配置文件中。将其另存为 movpn-04-06-server.conf ,启动OpenVPN服务器,并使用默认配置文件重新连接客户端。

连接建立后,我们使用 traceroute 命令(在Windows上的命令是 tracert -d)验证所有流量现在都通过VPN流动。

traceroute 输出的第一跳(hop)是10.200.0.1,这是OpenVPN服务器的IP地址。这证明默认情况下流量是通过VPN流动的。

配置选项 redirect-gateway def1 告诉OpenVPN客户端向客户端操作系统添加三条路由:

第一条路由是通过LAN接口从客户端到OpenVPN服务器的显式路由。需要此路由,否则OpenVPN服务器本身的所有流量都将通过隧道。

另外两条路由是一个巧妙地技巧,可以推翻默认路由,使所有流量都通过隧道发送,而不是发送到默认地局域网网关。

这种方法地优点是原始默认网关保持不变。当VPN断开连接时,原始网关地址会自动再次接管。如果我们只是使用 redirect-gateway ,当VPN断开连接时,默认网关可能会丢失,从而导致网络连接完全丢失。

这种方法的缺点是Windows7及更高版本的客户端。Windows有时会拒绝信任没有默认路由的TAP-Win适配器,因此将其标记为公共适配器。在Windows7中,无法使用公共适配器进行文件或打印机共享。我们将在下一章了解如何解决这一特殊问题。

客户端特定配置 – CCD 文件

在单个服务器可以处理多个客户端的设置中,有时需要设置每个客户端的选项来推翻全局选项,或者为特定客户端添加额外的选项。client-config-dir 选项对此非常有用。它允许VPN管理员为客户端分配特定的IP地址,以便将DNS服务器等特定选项推送到特定客户端,或暂时完全禁用客户端。如果你想将子网从客户端路由到服务器端,此选项也很重要,我们稍后将看到。

client-config-dir 或CCD文件可以包含以下选项:

为了使用 CCD文件,我们在 basic-udp-server.conf 配置文件中添加一行:

将其保存为 movpn-04-04-server.conf 。接下来创建CCD目录并在其中创建CCD文件,令客户端使用证书 client1.crt

CCD文件的名称基于证书主体的通用名称("/CN="部分),如client1.crt文件中所示:

在这种情况下,文件名需要只是 client1 ,没有扩展名,即使在Windows上也是如此。如果公共名称中存在空格,则需要将其转换为下划线(_)。如果Windows资源管理器配置为隐藏常见文件类型的扩展名,则最简单的方法是打开命令shell(cmd.exe)窗口,并使用以下命令删除扩展名:

接下来,我们使用此配置文件启动OpenVPN服务器,并连接VPN客户端。连接日志显示,客户端被分配了地址10.200.0.99:

使用默认详细度(verbosity)设置时,服务器端日志不显示任何关于拾取CCD文件的消息。将详细度设置增加到5或更多,以查看是否处理了CCD文件:

如何判断CCD文件是否被正确处理

CCD文件是否正确处理的故障排除可能有点棘手。以下指南将有助于调试CCD文件问题:

CCD 文件和拓扑 net30

如果你使用的是(默认)拓扑设置(topology net30),那么 ifconfig-push 语句略有不同。由于现在为每个客户端分配了一个 /30 子网。以下规则适用:

例如,VPN客户端的有效IP地址为10.200.0.50:

CCD文件现在应包含以下内容:

客户端侧路由

有时候,需要服务器(或其他VPN客户端)访问客户端所在的网络。这被称为客户端侧(client-side)路由。OpenVPN中的客户端侧路由要求该客户端的CCD文件包含iroute 语句。

以下网络布局:

服务器端的LAN和服务器端子网192.168.122.0/24需要通过客户端侧LAN访问客户端子网192.168.4.0/24。通过以下方式实现此功能:

1、在 basic-udp-server.conf 配置文件中添加以下两行:

将文件保存为 movpn-04-05-server.conf

2、在目录 /etc/openvpn/movpn/clients 中创建 client1 CCD文件,包含以下内容:

3、在服务器和客户端分别确认IP流量转发已经启用(enabled)并被允许(allowed):

4、用以下配置文件启动OpenVPN服务器:

5、客户端使用以下配置文件连接:

6、连接建立后,我们验证两个子网是否可以使用ping互相连通:

深入解释 client-config-dir 配置

在以上例子的第一步,我们在服务器配置文件中添加了两行。这些行设置 client-config-dir ,它们指导OpenVPN为子网段192.168.4.0/24添加一个网络路由。由于OpenVPN中的一个小错误,我们需要在这里明确指定网关地址10.200.0.1。这个缺点预计在2.4版中得到解决,之后你可以再次指定 route 192.168.4.0 255.255.255.0

CCD文件的内容指示OpenVPN,当具有通用名称 client1 的客户端连接时,此客户端的IP地址应设置为 10.200.0.99 。此外,OpenVPN需要为此客户端设置一个内部路由( iroute ),以便OpenVPN本身知道子网192.168.4.0/24位于此特定客户端之后。

最后,push route 语句指示OpenVPN将此特定子网的路由推送到客户端 client1 。这样,OpenVPN服务器可以以透明的(transparent)方式将不同的路由推送到不同的客户端。

注意,有选择地将路由推送到特定客户端可能很方便,但它不能防止被篡改。单独向此子网添加路由的流氓VPN客户端也可以访问它。如果你需要控制对特定子网的访问,请使用防火墙解决方案,如 iptablesipfw

此示例显示了OpenVPN配置选项的灵活性。无需更改客户端配置文件中的任何一行,就可以分配不同的IP地址,将特定子网路由到客户端,或将特定子网络从客户端网络路由到服务器端局域网。

Client-to-client 流量

OpenVPN还允许你设置客户端到客户端的流量。默认情况下,不允许VPN客户端直接互相通信。这是一种很好的安全措施,但有时需要允许客户端之间的流量。请注意,所有VPN客户端到客户端的流量都将通过OpenVPN服务器流动:从client1到VPN服务器,然后再从VPN服务器到client2,反之亦然。这很容易导致性能问题。

在tun模式下,可以使用 iptables 或使用OpenVPN选项 client-to-client 来实现客户端到客户的连接。client-to-client 选项的优点是速度更快:从一个客户端到达服务器的流量会自动转发到第二个客户端,而无需通过系统路由表或防火墙规则。缺点是很难监控流量,也不可能应用访问控制。

如果没有 client-to-client 选项,来自一个客户端的流量将由OpenVPN服务器接收、转发到系统路由和防火墙表,并(如果配置正确)再次反弹回OpenVPN服务器。然后,服务器将其转发给第二个客户端。

如果其它VPN客户端需要访问前一个示例中指定的子网192.168.4.0/24,则服务器配置需要扩展一行:

这指示OpenVPN服务器向所有客户端推送一条路由,即子网192.168.4.0/24可以通过VPN隧道访问,但客户端 client1 除外。由于匹配的 iroute 条目,客户端 client1 本身被排除在外。

OpenVPN状态文件

OpenVPN提供了多种选项来监控连接到服务器的客户端。最常见的方法是使用状态文件。OpenVPN状态文件由OpenVPN进程不断更新,包含以下信息:

我们通过在服务器配置中添加一行来修改 client-side routing 服务器配置文件 movpn-04-05-server.conf

将其保存为 movpn-04-07-server.conf 。重新连接VPN后,在VPN客户端 client1 连接并传输了一些数据后,我们可以在状态文件中看到以下内容:

CLIENT LIST 显示了连接的客户端列表,包括有关接收到的字节数和发送的字节数的信息。

ROUTING TABLE 显示OpenVPN内部路由列表:

当客户端断开连接时,状态文件将在3秒后更新,连接的客户端将不再列出。

注:当客户端断开连接时,所有信息都将从状态文件中删除,所有统计信息都将重置。如果客户端稍后再次连接,则接收和发送的字节数将再次从零开始。当客户端断开连接时,客户端断开脚本会受到所有状态信息。

status 选项的第二个参数是状态文件更新(重写)的间隔。默认值为60秒。

UDP模式可靠连接跟踪

OpenVPN服务器在使用UDP协议时无法立即检测到客户端断开连接,无论是故意还是由于互联网连接不良。这允许客户端在连接不良的情况下重新连接到VPN服务器,而不会丢失所有隧道连接。缺点是OpenVPN服务器需要一些时间才能意识到客户端已经消失。

OpenVPN客户端可以使用 explicit-exit-notify 选项显式通知服务器它正在断开连接。此选项接受一个参数,该参数指定客户端尝试发送到服务器的显式消息的数量。默认值为1,如果底层网络连接本身不稳定,则无法正常工作。在这种情况下,建议将此值增加到3。

当使用 explicit-exit-notify 时,当客户端断开连接时,OpenVPN服务器会立即收到远程退出消息,如服务器日志文件所示:

注意,使用 proto tcp 时不会出现此问题,因为服务器会立即注意到TCP连接的终止。

OpenVPN管理界面

OpenVPN最强大但最不太知名的选项之一是管理界面。管理界面在服务器端和客户端都可用。在服务器端,它可用于收集统计数据、监视和控制连接的客户端,以及执行其他与管理相关的任务。在客户端,它可用于查询密码、输入与VPN服务器建立连接的代理信息、与PKCS#11设备交互以及收集客户端统计数据。

Linux NetworkManager的OpenVPN插件广泛使用管理界面来控制VPN连接的启动和关闭。

要使用管理界面,请在客户端或服务器配置文件中添加行 management 127.0.0.1 23000 stdin 。此选项指示OpenVPN在IP地址127.0.0.1、端口23000上设置管理接口,并使用stdin指定管理员密码。

如果我们将此添加到 basic-udp-server.conf 配置文件中并启动OpenVPN服务器,则OpenVPN将首先向我们查询要使用的管理密码。

我们可以使用 telnet 登录到管理界面(用户输入以黑体列出):

这个原始telnet接口可用于查看服务器的状态,提供与前一个示例中的选项状态相同的输出。它还可以使用以下命令立即终止客户端连接:

这将导致客户端 client1 断开连接。注意,在大多数情况下,客户端会自动尝试重新连接。现在,键入 exit 结束telnet会话。

管理界面可用于以多种不同的方式控制OpenVPN(详见OpenVPN手册页 https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage ):

会话密钥重新协商

为了确保每个OpenVPN连接的安全性,服务器会定期与每个客户端重新协商数据通道的密钥。这可以使用三个选项进行控制:

如果VPN客户端在连接到服务器时遇到周期性超时,则更改这些参数通常很有用。但是,如果以非常短的间隔设置 reneg-sec 参数,VPN的性能将严重下降。

reneg 选项可以在客户端或服务器端指定,也可以在两者上指定。在任何一侧运行最频繁的reneg 选项将重置两端的计数器。如果服务器指定了 reneg-sec 500 ,但客户端指定了 reneg-sec 60 ,则数据通道重新协商将大约每60秒发生一次。

我们通过在 basic-udp-server.conf 配置文件中添加三行来创建一个示例:

我们将配置保存为 movpn-04-09-server.conf ,并重新建立VPN连接。服务器日志现在将包含许多以 TLS: soft reset 开头的行:

设置了选项 reneg-sec 10 后,我们从服务器日志时间戳中看到,数据通道密钥每10秒重新协商一次。

在客户端侧,我们还可以看到密钥重新协商对VPN连接性能的影响。通过在连接建立后运行一个简单的ping命令,我们可以根据ping响应时间的峰值看到密钥重新协商何时发生:

当数据包或字节边界 (boundary)被跨越时,也会发生同样的事情,此时数据通道密钥也将被重新协商。

关于PKCS#11设备的说明

特别是在使用PKCS#11设备时,密钥重新协商可能很麻烦。一些PKCS#11设备对密钥重新协商施加了沉重的惩罚,导致重新协商过程需要几秒钟。在此期间,VPN没有响应。

reneg-sec 值设置为0将有效地禁用密钥重新协商,但这会使VPN本身容易受到中间人和定时攻击,从而使使用硬件安全设备的额外安全性变得毫无用处。

使用IPv6

OpenVPN2.3为IPv6提供了坚实的支持,包括在OpenVPN隧道内以及隧道本身的传输。OpenVPN一直到1.x都对IPv6有基本的支持,但IPv6在很大程度上被重写了。总体而言,在OpenVPN隧道内,管理员可以选择支持以太网(第2层)、IPv4(第3层)和IPv6(第3级)。

只需要使用一种传输方法,单个OpenVPN配置可以包含IPv4和IPv6 --remote 条目。所有交通,无论类型如何,都将在隧道内受到保护。拥有一个全IPv6隧道是完全可以接受的,将IPv6用于传输和受保护的流量。通过额外的路由和代理,甚至可以使用OpenVPN来帮助IPv6到IPv4的转换。

受保护的IPv6 流量

基于上一节的示例,我们可以像客户端提供IPv6地址,并保护隧道内的流量。为此,我们在服务器配置中添加了 --server-ipv6 选项。这与 --server 指令的操作类似,仅适用于IPv6而不是IPv4,并采用IPv6网络地址和网络掩码作为参数。与 --server 一样,--server-ipv6 是一个宏,用于单独传递其他选项:--ifconfig-ipv6--ifconfig-ipv6-pool--tun-ipv6-push tun-ipv6

与IPv4一样,IPv6路由可以从主服务器配置或 client-config 目录中的每个客户端配置文件中推送。然而,在这个例子中,我们将所有IPv6流量推送一个默认路由。

目前,IPv6的OpenVPN中没有 redirect-gateway 选项。添加路由类似于IPv6,关键字为 route-ipv6 ,而不是 route

现在,编辑 movpn-04-01-server.conf 文件,添加 --server-ipv6 指示:

文件保存后,需要重新启动OpenVPN服务器进程。如果使用新选项正确启动了该过程,你应该在日志文件中看到类似这样的内容:

此时,客户端能够在隧道内使用IPv6传递流量,服务器正在向客户端推送IPv6的默认路由。添加服务器配置选项不需要客户端配置中的其他相应选项。

连接的客户端将在 tunX 接口上显示IPv4和IPv6地址。

下面是一个FreeBSD例子:

使用IPv6作为传输

OpenVPN目前无法同时监听IPv4和IPv6地址,但大多数现代内核都可以通过IPv6映射地址为你处理。这所做的是获取一个版本4的IP,如192.168.200.4,并将其映射为IPv6地址 ::ffff:192:168.:200:.:4。此外,客户端和服务器上的协议将是udp6,而不是原型的udp

在更改了示例配置中的proto语句后,client2 被初始化,我们可以看到地址被分配了。OpenVPN服务器v4和v6地址都可以被ping到,我们可以通过tcpdump确认隧道上的传输是通过IPv6进行的。

下面是客户端tun接口:

下面是隧道 ping 中的IPv4:

下面是隧道 ping 中的IPv6:

下面是 tcpdump 输出(注意输出中的IPv6关键字):

高级设置选项

接下来的几节将说明一些高级配置选项。建议你在将其部署到生产环境中之前,充分了解其对网络的影响。这些选项很少使用,但在适当的情况下可能非常有益。

代理 ARP

通常希望VPN客户端看起来像是服务器端网络的一部分。这使得浏览文件夹、共享文件和打印机更容易。为了实现这一目的,许多设置都采用以太网桥接(见第六章 带tap设备的C/S模式),这有其自身的缺点。于非桥接设置相比,桥接配置的性能可能要低得多。

当OpenVPN服务器在Linux或Unix上运行时,有一种替代解决方案:大多数Unix内核都具有代理ARP功能,可用于在服务器局域网上为OpenVPN客户端分配IP地址,并使其看起来像是该局域网的一部分。请注意,这仅适用于IPv4网络,因为IPv6网络不使用ARP。

考虑以下网络布局:

客户端tun0地址为192.168.3.34

服务器端tun0地址为192.168.3.33,服务器端网段为192.168.3.0/24

此布局中,无法使用标准的VPN子网10.200.0.0/24,因为我们必须将VPN客户端集成到现有子网中,在本例中为192.168.3.0/24。此子网中的当前计算机在192.168.3.10-192.168.3.24范围内,因此我们将VPN地址放置在此范围之外。确保服务器端局域网上的DHCP服务器不应公布VPN地址,因为我们希望OpenVPN为VPN客户端分配地址。

对于这个例子,我们利用OpenVPN功能在客户端连接或断开连接时运行脚本。OpenVPN的脚本功能在第七章 脚本和插件 中有更详细的解释。

1、我们从以下服务器配置文件开始:

注意,我们添加了三条语句来设置脚本的安全级别,并在客户端连接或断开连接时运行自定义脚本。

2、将以上文件保存为 movpn-04-01-server.conf

3、接下来,创建每次VPN客户端连接时执行的 proxyarp-connect.sh 脚本:

4、将以上脚本保存为 /etc/openvpn/movpn/proxyarp-connect.sh 。脚本位置必须与 movpn-04-10-server.conf 文件中指定的绝对路径匹配。

5、然后,创建 proxyarp-disconnect.sh 脚本,该脚本在客户端断开连接时执行:

6、将以上脚本保存为 /etc/openvpn/movpn/proxyarp-disconnect.sh

注意,设备名称 eth0tun0 被硬编码到脚本中。这是必要的,因为OpenVPN不知道需要发布额外ARP地址的设备。通过在两个脚本中复制 /sbin/arp 行,也可以在多个接口(eth0、eth1、wlan0等)上发布额外的ARP地址。

使这两个脚本都可执行,并使用以下命令启动OpenVPN服务器:

7、与往常一样,使用 basic-udp-client.conf (或者 basic-udp-client.ovpn)配置文件连接到服务器。VPN客户端成功连接后,我们会验证局域网上的其他设备是否可以看到该客户端。

【原文有安卓收集界面的图,略】

安卓设备上没有添加额外的网络路由。VPN客户端真正集成到现有子网中。

8、我们还可以验证OpenVPN服务器现在是否在其ARP表中发布了额外的IP地址:

代理ARP如何工作?

代理ARP是大多数Unix和Linux内核支持的功能。它最常用于将拨入客户端连接到局域网,现在也被ADSL和有线互联网提供商使用。

当客户端连接时,OpenVPN服务器从其本地局域网范围借用IP地址。然后将此IP地址分配给此OpenVPN客户端。服务器还在系统的ARP表中创建了一个特殊条目,告诉站点B的局域网的其余部分,OpenVPN服务器充当IP 192.168.3.34的代理。这意味着,当服务器端局域网上的另一台机器想知道在哪里找到IP为192.168.3.34的主机时,OpenVPN服务器将使用其自己的代理ARP地址发布的接口的MAC地址进行响应。

服务器配置文件包含一些需要解释的语句:

前面的行导致OpenVPN服务器将地址192.168.3.33分配给服务器VPN IP地址,网络掩码为255.255.255.224(或/27)。第一个VPN客户端被分配了地址192.168.3.34/27。但是,这意味着VPN客户端本身无法访问此范围之外的任何IP地址。需要推送路由声明来告诉OpenVPN客户端可以通过VPN访问整个子网192.168.3.0/24。

到目前为止,服务器配置文件通常包括以下行:

在此配置文件中,它们不存在,因为 client-connectclient-disconnect 脚本需要以 root 用户身份运行。另一种方法是设置 sudo 权限,以便允许 user nobody 以root权限执行/sbin/arp命令。

最后,以下行:

设置OpenVPN的脚本功能。第一行将脚本的安全级别设置为2,这意味着某些环境变量对脚本可用。 client-connectclient-disconnect 行都指定了要执行的脚本的绝对路径。

为客户端分配公共IP地址

作为代理ARP示例的后续,我们现在将研究如何将公共IPv4地址分发给OpenVPN客户端。让我们假设以下一组(仅作为示例)公共IPv4地址对我们可用:

我们的公网IPv4网络是192.0.2.160/28,这给了我们16个地址,这些地址的使用方式如下:

IP地址用处
192.0.2.160子网的网络地址
192.0.2.161服务器的VPN IP地址
192.0.2.162未使用
192.0.2.163未使用
192.0.2.163-192.0.2.170用于VPN客户端
192.0.2.171OpenVPN服务器本身的局域网地址
192.0.2.172未使用
192.0.2.173未使用
192.0.2.174远程局域网上的路由器
192.0.2.175网络广播地址

我们现在想设置一个OpenVPN服务器,能够分发地址192.0.2.164到192.0.2.170,OpenVPN服务器本身位于地址192.0.2.161:

1、创建服务器配置文件:

2、将此文件另存为 movpn-04-11-server.conf 。我们将重用前面示例中的 proxyarp-connect.shproxyarp-disconnect.sh 脚本。创建每次VPN客户端连接时执行的 proxyarp-connect.sh

3、将以上内容保存为 /etc/openvpn/movpn/proxyarp-connect.sh

4、然后,创建 proxyarp-disconnect.sh 脚本,该脚本在客户端断开连接时执行:

5、将以上内容保存为 /etc/openvpn/movpn/proxyarp-disconnect.sh 。使这两个脚本都可执行并启动OpenVPN服务器:

6、使用基本配置文件将OpenVPN客户端连接到服务器。第一个客户端将被分配地址192.0.2.164。

服务器配置文件类似于文件movpn-04-10-server.conf,除了以下块:

本章前面解释了宏 server 10.200.0.0 255.255.255.0的扩展如下:

在分发公共IP地址时,我们通常不会浪费IPv4地址。OpenVPN 2.1中引入的选项 topology subnet在这里非常有用。 在检查了我们的公共IPv4空间后,我们放弃了server语句,并包含了我们自己版本的ifconfigifconfig-pool选项:

总结

本章介绍了具有tun设备的客户端/服务器模式的各种功能和选项。我们为OpenVPN服务器和客户端、作为传输手段的UDP和TCP协议以及Windows和Linux/Unix客户端建立了一组基本的配置文件。这组基本配置文件将在本书的其余部分中使用。

我们讨论了如何设置一个同时提供IPv4地址和IPv6地址的OpenVPN服务器。我们介绍了服务器端和客户端路由,包括通过VPN隧道重定向所有流量。我们还看到了如何使用OpenVPN分发公共IPv4地址。

在下一章中,我们将探讨OpenVPN提供的高级功能。此外,在第6章“带抽头设备的客户端/服务器模式”中,将解释几个对tun模式也有用的选项和示例。