最新消息:

深入 OpenVPN 配置

openvpn admin 26295浏览 0评论

在实际使用中,可能还会遇到很多网络上的问题,今天就再举几个例子说明一下。

一、案例1

针对不同的客户端指定不同的等级和权限。通常的方法是:

1、每个客户端分配不同的IP地址;

2、利用防火墙对不同的IP地址进行控制;

例如:

引用 1、公司内部网段是10.66.4.0/24;

2、所有人允许访问Email服务器为10.66.4.4,但不能访问其他服务器;

3、特定的客户组允许访问Samba服务器为10.66.4.12,不能访问其他服务器;

4、管理员能访问所有公司内网服务器。

根据上述的要求,我们可以对OpenVPN服务端进行配置:(而不需要修改客户端配置文件)

引用 server.conf增加:

#10.8.0.0是给所有VPN客户端的IP段;

server 10.8.0.0 255.255.255.0

#10.8.1.0是给管理员分配的IP段;

server 10.8.1.0 255.255.255.0

#10.8.2.0就是给特定用户组分配的IP段;

10.8.2.0 255.255.255.0

#下面是定义读取特殊客户端配置文件的目录为ccd;

client-config-dir ccd

通过上面的配置,今后我们就可以对指定的客户进行特殊的定义了。配置文件应该放在ccd目录下:

引用 ccd/sysadmin1:

ifconfig-push 10.8.1.1 10.8.1.2

引用 ccd/contractor1:

ifconfig-push 10.8.2.1 10.8.2.2

引用 ccd/contractor2:

ifconfig-push 10.8.2.5 10.8.2.6

※注意:
1、文件名就是客户的Common Name,OpenVPN是根据该名称来获得指定客户端的;
2、客户端的IP地址不是任意指定的,由于Windows的TAP驱动必须采用/30网段的IP,为兼容该协议,应从特定的IP地址中选择,而且是成组出现的;(可参考第一份文章附录介绍)

那最后,剩下的就是用iptables防火墙做限制即可:(假设PLOICY为Deny)

iptables -A FORWARD -i tun0 -s 10.8.0.0/24 -d 10.66.4.4 -j ACCEPT

iptables -A FORWARD -i tun0 -s 10.8.1.0/24 -d 10.66.4.0/24 -j ACCEPT

iptables -A FORWARD -i tun0 -s 10.8.2.0/24 -d 10.66.4.12 -j ACCEPT

二、案例2

让客户端内部子网可与服务端内部网互通,其实也就是实现点对点互连了。

引用  要求如下:

1、客户端的子网网段必须唯一;

2、客户端的Common Name要唯一,而且不能在的配置文件中配置有duplicate-cn;

3、客户端打开IP Forward(路由转发)和允许TUN、TAP进入;

OK,那假设客户端子网为192.168.4.0,并且客户端网关和客户端OpenVPN是同一服务器,那可以这样配置:

引用 .conf增加:

#下面是定义服务器读取特殊客户端配置文件的目录为ccd;

client-config-dir ccd

#服务器增加到192.168.4.0/24的路由

route 192.168.4.0 255.255.255.0

#允许客户端子网互通

client-to-client

#让所有客户端都增加到192.168.4.0/24的

push “route 192.168.4.0 255.255.255.0”

然后,对指定的客户端建立配置文件。

mkdir /etc/vpn/ccd

在ccd目录下建立一个与客户端Common Name相同名字的文件名,并加入:

引用 #这是告诉,我(客户端)的子网网段是192.168.4.0/24;

iroute 192.168.4.0 255.255.255.0

※注意:
1、若OpenVPN Server不是服务端子网的网关,则必须在服务端子网网关加入指向192.168.4.0/24的路由;
2、若客户端的OpenVPN Client也不是客户端子网的网关,同样的,也必须加入对应的路由,如:

route add -net 192.168.4.0 netmask 255.255.255.0 gw 10.8.0.5 dev eth0

总而言之,就是必须让网关通过VPN服务器,可路由到所有的VPN子网,这无论是对于服务端还是客户端都是必须定义的。

三、案例3

OpenVPN内部提供了DHCP的服务,而不需要依赖外部的DHCP服务器。同样,也提供了DHCP服务的一些配置参数:

引用 .conf配置:

#定义客户端的DNS服务器地址

push “dhcp-options DNS 192.168.228.1”

#定义客户端的WINS服务器地址

push “dhcp-options WINS 192.168.228.1”

#让客户端发起的所有IP请求都通过OpenVPN服务器

push “redirect-gateway def1”

其中,最后一项配置会修改客户端的默认路由为OpenVPN服务器。这样,通常还必须加入NAT转换:

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

这样,所有客户端当和OpenVPN连接后,就可以把该服务器作为对外的服务器使用了。(类似Proxy)

四、案例4

前面案例提到的,都是由服务端先生成客户端证书,然后分发到客户端,让客户端通过证书连接到服务器上。但有时候,这样的分发是比较麻烦的(也不安全)。这样,我们可以考虑另外一种方式:
只在服务端制作客户端证书,而客户端只需要有ca.crt文件,而不需要拿到客户端证书,当登陆服务器的时候是通过用户名和密码即可登陆OpenVPN服务器。

◎服务端配置:(以Linux版为例)

OpenVPN可以通过插件(plugin)方式支持上述的用户名认证,在Linux下以PAM为例,必须先增加用户:

useradd -M test

passwd test

然后修改.conf增加:

引用 #使用PAM插件

plugin /usr/share/vpn/plugin/lib/openvpn-auth-pam.so login

#客户端可以不提供证书

client-cert-not-required

#用户登陆的用户名就是Common Name

username-as-common-name

※注意:
1、若不增加client-cert-not-required语句,默认PAM认证和证书验证是需要同时通过才能建立连接的;
2、OpenVPN是基于SSL连接,所以,上述设置只是让客户端不用提供证书,但却必须提供ca.crt;
3、而且OpenVPN服务器也必须用客户端使用的登陆名(如:test)建立相同Common Name的证书,否则客户端登陆的时候,服务器会提示找不到对应证书,而不能建立连接。

◎客户端配置:

client.conf增加:

引用 #激活登陆认证方式

auth-user-pass

#修改认证证书,保留ca.crt即可,客户端证书可以不要了

ca ./easy-rsa/keys/ca.crt

#cert ./easy-rsa/keys/client1.crt

#key ./easy-rsa/keys/client1.key

这样,当手动启动客户端的时候,即会提示用户名和密码。(用户名和密码为登陆服务器PAM认证,通过后,OpenVPN会提取用户名作为Common Name,并验证客户端证书,若也通过,则连接搭建成功)

※问题:若采用该方式,如何使用后台服务启动客户端?

答:可以先建立一个文件author-keys(用户名和密码各一行),然后修改配置文件

引用 auth-user-pass author-keys

另其从中读取该文件以通过验证。

但前提是必须在编译的时候增加–enable-password-save参数。

五、其他

1)若客户端不能访问OpenVPN使用的1194端口,可通过HTTP Proxy,但有要求:

1、OpenVPN连接要使用方式,而不能使用udp方式;

2、客户端配置加入:

引用 http-proxy ip port

2)OpenVPN负载均衡

要使用OpenVPN负载均衡,可以这样做:

1、可以建立多台,除server配置不同外,其余相同:

引用 server1

server 10.8.0.0 255.255.255.0

server2

server 10.8.1.0 255.255.255.0

server3

10.8.2.0 255.255.255.0

2、客户端可以用多点尝试进行配置:

引用 #默认从上往下尝试

remote server1 port

remote server2 port

#也可以改为随机连接

remote-random

#为防止DNS解析错误导致不进行后续的尝试,可以加入下面的语句

resolv-retry 60

3)撤回证书

前面已经提到,可以单方面的通过服务器撤回客户端证书,在easy-rsa目录下:

source ./vars

./revoke-full client2

会生成crl.pem文件。把文件拷入对应目录,如keys。然后修改server.conf:

引用 crl-verify ./easy-rsa/keys/crl.pem

即可。(CRL List对于新客户是马上生效的,而且不需要重启

六、加强OpenVPN的安全性

1、创建tls-auth

vpn –genkey –secret ta.key

.conf:

引用 tls-auth ta.key 0

client.conf:

引用 tls-auth ta.key 1

2、使用UDP协议

因为UDP一般不会有DoS攻击,而且能能防止端口被扫描,能保证更安全。

3、使用nobody用户和组运行服务

对于非Win的服务器,可以在配置中加入:

引用 user nobody

group nobody

4、使用chroot

请参考:
官方文档

5、使用Large RSA keys

可以通过修改./easy-rsa/vars中的KEY_SIZE,增加到2048。但要注意,该修改必须重建所有的keys、以及配置文件。

6、使用Large symmetric keys

可以在配置文件中加入:

引用 cipher AES-256-CBC

7、把ca.key单独存放

最后,也是最重要的一点。从前面的配置文件可以看到,无论是服务端,还是客户端都不需要使用ca.key文件的。但该文件却很重要,所以,我们应该把它另外保存好,而不是放在上哦!

8、还有一种安全问题,就是Man-in-the-Middle攻击。

也就是模拟server连接另一个client。可以参考
官方文档

※相信通过这些例子,今后对于OpenVPN的配置就不会再有任何问题了.

——————————————————————————

OpenVPN的参数详解

一般选项:

–config file    : 从file中读取配置选项.

–help                  : 显示选项.

–version            : 显示版权和版本信息.

隧道选项:

–local host      : 本地主机名或IP地址.

–remote host [port] : 远端主机名或IP地址.

–remote-random : 如果指定了多个–remote选项,从中随机选取一个.

–mode m              : 主模式, m = ‘p2p’ (默认, 点-到-点) 或者’server’.

–proto p            : 使用协议p和对端通信,

p = udp (默认), tcp-, 或tcp-client

–connect-retry n : 对–proto -client, 连接重试之前等待的秒数(默认值-5)

–http-proxy s p [up] [auth] : 通过在地址s和端口p的HTTP代理连接远端

如果代理要求认证,up是包含用户名/密码的文件,用户名和密码要在

两行上, 或者是’stdin’则从控制台输入。如果代理需要NTLM认证则

添加auth=’ntlm’.

–http-proxy-retry        : HTTP代理出错时总是重试。

–http-proxy-timeout n : 代理超时,秒,默认-5.

–http-proxy-option type [parm] : 设置HTTP代理的扩展选项.

重复使用设置多个选项.

VERSION 版本号(默认=1.0)

AGENT 用户代理

–socks-proxy s [p]: 通过在地址s端口p的Socks5代理连接远端主机(默认port=1080).

–socks-proxy-retry : Socks代理出错时总是重试。

–resolv-retry n: 如果–remote的名解析失败,重试n秒(默认是禁止的),

设置n=”infinite”则无限重试。

–float                : 允许远端改变它的IP 地址/端口.比如通过DHCP(如果没有使用

–remote, 则默认使用这一项).

–ipchange cmd  : 在远端IP地址初始设置或改变时执行shell命令cmd.

— cmd ip地址 端口号

–port port        : 本地和远端的TCP/UDP端口号

–lport port      : 本地TCP/UDP端口(默认值=1194).

–rport port      : 远端TCP/UDP端口(默认值=1194).

–nobind              : 不绑定到本地地址和端口.

–dev tunX|tapX : tun/tap设备(对于动态设备来说可以忽略X.

–dev-type dt    : 使用的设备类型(dt = tun 或 tap)

仅在用–dev使用tun/tap设备时没有使用”tun”或”tap”.

–dev-node node : 明确设置设备节点,而不是使用

/dev/net/tun, /dev/tun, /dev/tap, 等.

–tun-ipv6          : 使tun连接能够转发IPv6包。

–ifconfig l rn : TUN: 配置设备使用IP地址l作为本地端点rn作为远端端点.

l和rn在对端应当互换. l和rn应当是两端使用的子网之外的

地址

TAP: 配置设备使用IP地址l作为本地端点rn作为子网掩码。

–ifconfig-noexec : 并不执行ifconfig/netsh命令, 而是通过环境(变量?)将

–ifconfig的参数传递给脚本.

–ifconfig-nowarn : 如果这边的–ifconfig选项与另一边的不匹配并不告警.

–route network [netmask] [gateway] [metric] :

连接建立后将添加到路由表.可以指定多个路由.

默认子网掩码: 255.255.255.255

默认网关: 从–route-gateway 或 –ifconfig获得

通过保留空白或者设置为”nil”来使用默认值。

–route-gateway gw : 指定–route使用的默认网关.

–route-delay n [w] : 连接建立后等待n秒后添加路由(可以是0). 如果没有指定,

tun/tap打开后就立即添加路由. 在Windows下,为TUN/TAP适配器

连接等待w秒。

–route-up cmd  : 路由添加后执行shell命令cmd.

–route-noexec  : 不自动添加路由. 相反使用环境变量向–route-up脚本传递路由.

–redirect-gateway [flags]: (试验) 自动执行路由命令复位向所有出去的IP包为

通过VPN. 如果OpenVPN服务器通过同一个子网直接连接,添加

‘local’标志,比如WiFi. 添加’def1’标志设置默认使用

0.0.0.0/1和128.0.0.0/1而不是0.0.0.0/0.

–setenv name value : 设置传递给脚本的用户环境变量。

–shaper n          : 将向对端的输出限制为每秒n个字节。

–keepalive n m : 在模式下设置超时。每n秒发送一个ping包,

如果在m秒内没有收到ping包,则重启。

–inactive n      : 在tun/tap设备不活跃n秒后退出。

–ping-exit n    : 如果在n秒后没有收到远端的ping包则退出。

-restart n: 如果在n秒后没有收到远端的ping包则重启。

–ping-timer-rem: 仅在有远端地址时运行–ping-exit/–ping-restart定时器.

–ping n              : 每n秒通过TCP/UDP端口ping对端一次。

–fast-io            : (试验) 优化TUN/TAP/UDP写操作.

–remap-usr1 s  : 收到SIGUSR1信号后,将信号映射为(s=’SIGHUP’ 或 ‘SIGTERM’).

–persist-tun    : 在SIGUSR1或者–ping-restart时保持tun/tap设备打开。

–persist-remote-ip : 在SIGUSR1或者–ping-restart时保持远端IP地址。

–persist-local-ip  : 在SIGUSR1或者–ping-restart时保持本地IP地址。

–persist-key    : 在SIGUSR1或者–-restart时不重新读取key文件。

–tun-mtu n        : 将tun/tap设备的MTU设置为n, 并且从中获得(derive)

TCP/UDP MTU (默认值=1500).

–tun-mtu-extra n : 在读取tun/tap设备时返回的字节数最多比tun-mtu多n个字节,

(默认值 TUN=0 TAP=32).

–link-mtu n      : 将TCP/UDP设备的MTU设置为n,并且tun的MTU也从其中获得(derive).

–mtu-disc type : 在TCP/UDP通道上是否做Path MTU 发现?

‘no’      — 从来不发送DF (Don’t Fragment) 帧

‘maybe’ — 使用 per-route 提示

‘yes’    — 总是 DF (Don’t Fragment)

–mtu-test          : 根据经验衡量和报告MTU.

–fragment max  : 使能内部数据报分段,从而没有大于max字节的UDP包发送。

每个数据报加上4字节的的开销。

–mssfix [n]      : 设置TCP MSS的上部边界, 默认值 = tun-mtu

或 –fragment max, 两者中较小的一个.

–sndbuf size    : 设置TCP/UDP发送缓冲区的大小。

–rcvbuf size    : 设置TCP/UDP接收缓冲区的大小。

–txqueuelen n  : 将tun/tap 的发送队列长度设置为n (Linux).

–mlock                : 禁止分页–确保密钥和隧道数据不会写入磁盘。

–up cmd              : tun设备成功打开后将要执行的命令cmd.

执行为: cmd tun/tap-dev tun-mtu link-mtu \

ifconfig-local-ip ifconfig-remote-ip

(pre –user 或者 –group UID/GID change)

–up-delay          : 延迟 tun/tap 的打开并且可能还有–up 脚本的执行。

直到和对端的TCP/UDP连接建立。

–down cmd          : tun设备关闭后执行cmd命令。

(post –user/–group UID/GID change 和/或 –chroot)

(script parameters are same as –up option)

–down-pre          : TUN/TAP设备关闭之前调用–down cmd/script.

–up-restart      : 重启时执行up/down脚本, 包括那些由–-restart或

SIGUSR1引起的重启.

–user user        : 初始化后将UID设置为user.

–group group    : 初始化后将GID设置为group.

–chroot dir      : 初始化后将Chroot 到这个目录.

–cd dir              : 初始化前进到这一目录。

–daemon [name] : 初始化后成为一个Become.

可选的’name’参数作为程序名传递给系统日志(system logger).

–syslog [name] : 输出到系统日志(syslog), 但是不成为daemon.

‘name’参数和上面的–daemon意义相同。

–inetd [name] [‘wait’|’nowait’] : 运行为一个inetd或xinetd.

‘name’参数和上面的–daemon意义相同。

–log file          : 将日志输出到文件file, 文件file在打开时被创建/截尾.

–log-append file : 将日志追加到文件file, file如果不存在的话则创建它。

–suppress-timestamps : 不向stdout/stderr输出时间戳.

–writepid file : 将主进程ID写入文件file.

–nice n              : 改变进程的优先级(>0 = 低, <0 = 高).

–echo [parms …] : 将参数回显到日志。

–verb n              : 将输出冗余级别设置为 n (默认值=1):

(推荐使用级别3).

: 0 — 仅输出致命错误

: 1 — 启动信息 + 连接初始化信息 +

非致命的加密和网络错误

: 2,3 — 显示TLS协商和信息

: 4 — 显示参数

: 5 — 对每一个从TCP/UDP(caps)或tun/tap(lc)收到或发送的包在

在控制台上显示’RrWw’字符。

: 6 to 11 — 冗余信息递增的调试消息。

–mute n              : 最多记录n条相同类别的连续信息.

–status file n : 每n分钟向文件file写一次操作信息。

–status-version [n] : 选择状态文件模式版本号。

目前, n 可以是 1 或 2 (默认值=1).

–disable-occ    : 禁止两端选项一致性检查(options consistency check).

–gremlin mask  : 特别加强(Special stress)测试模式(仅仅为了测试).

–comp-lzo          : 使用快速LZO压缩– 对未压缩的每个数据包可能增加一个字节。

–comp-noadapt  : 使用–comp-lzo时,不使用自适应(adaptive)压缩。

–management ip port [pass] : 使ip:port上的一个TCP服务器处理远程管理.

pass是一个口令文件, 如果是’stdin’则从控制台输入口令。

–management-query-passwords : 私钥和auth-user-pass口令的查询管理信道。

–management-hold : 将OpenVPN启动为冬眠模式,直到一个管理接口客户端明确启动它。

–management-log-cache n : 为管理信道暂存n日志文件历史。

–plugin m [str]: 装载插件n将str作为参数传递给它的初始化函数。

多客户的服务端选项(使用–mode server时):

–server network netmask : 服务模式

-bridge IP netmask pool-start-IP pool-end-IP : 以太网桥服务模式。

–push “option” : 将一个配置文件选项发回对端执行,对端在配置文件须使用

–pull选项。

–push-reset      : 对某待定客户端不继承全局push列表。

–ifconfig-pool start-IP end-IP [netmask] : 为给客户端动态分配地址预留一个

地址池。

–ifconfig-pool-linear : 在tun模式时使用单一地址而不是/30子网。和Windows

客户端不兼容。

–ifconfig-pool-persist file [seconds] : Persist/unpersist ifconfig-pool

数据到file文件, 间隔seconds (默认值=600).

如果 seconds=0, 文件file被作为只读文件。

–ifconfig-push local remote-netmask : 给远端Push一个ifconfig选项,

覆盖 –ifconfig-pool 动态分配.

仅在 client-specific 配置文件中有效.

–iroute network [netmask] : Route subnet to client.

仅建立内部

仅在 client-specific 配置文件中有效.

–disable            : 禁止客户端.

仅在 client-specific 配置文件中有效.

–client-cert-not-required : 不需要客户端证书, 客户端使用用户名/密码认证。

–username-as-common-name  : 用于 auth-user-pass 认证, 使用授权的用户名作为

common name, 而不使用客户端证书中的common name.

–auth-user-pass-verify cmd method: 查询客户端的用户名/密码,运行脚本cmd

来验证,如果method=’via-env’通过环境变量传递用户名/密码,

如果method=’via-file’, 通过临时文件传递用户名/密码.

–client-to-client : 在内部 client-to-client 包.

–duplicate-cn  : 允许多个客户端使用相同的common name同时连接。

–client-connect cmd : 当客户连接时运行脚本cmd.

–client-disconnect cmd : 当客户连接断开时运行脚本cmd.

–client-config-dir dir : 用户(custom)客户端配置文件目录。

–ccd-exclusive : 拒绝连接直到找到用户(custom)客户端配置。

–tmp-dir dir    : 临时文件目录, 用于 –client-connect 返回文件.

–hash-size r v : 设置 real address hash 表的大小为r, 虚拟地址表大小为v.

–bcast-buffers n : 分配 n 个广播缓冲区.

-queue-limit n : 排队的TCP输出包的最大数目。

–learn-address cmd : 运行cmd脚本验证客户虚拟地址。

–connect-freq n s : 每s秒允许最多n个新连接.

–max-clients n : 最多允许n个同时连接的客户端。

–max-routes-per-client n : 每个客户端最多允许n个内部

客户端选项(连接多客户服务端时):

–client                : 客户端模式。

–auth-user-pass [up] : 服务端使用用户名/密码认证客户端.

up 是一个用户各/密码各占一行的文件。

如果没有指定up,则需从控制台输入用户名/密码。

–pull                    : 从对端接受配置文件选项就象它们是本地配置文件的一部分.

当连接到一个’–mode ’ 远端时必须使用这一选项.

–auth-retry t  : 怎样处理认证失败.  t的值可以是

none (默认), interact, 或 nointeract.

–explicit-exit-notify [n] : 退出/重启时,向服务端/远端发送exit信号。

n = 重试次数, 默认值=1.

数据通道加密选项(必须和对端兼容):

(这些选项对静态密钥和TLS模式都是有意义的)

–secret f [d]  : 使用静态密钥模式(非-TLS).

使用共享静态密钥文件 f, 使用–genkey参数生成.

可选的参数 d 控制密钥方向.

如果指定了 d , 每个方向使用一个密钥文件, 在连接的一端

设置d=0, 另一端设置d=1.

–auth alg          : HMAC认证包使用消息摘要算法alg(默认值=SHA1).

(通常使每个包添加了 16 或 20 个字节)

设置 alg=none 则禁止认证。

–cipher alg      : 使用alg算法加密包(默认值=BF-CBC).

设置 alg=none 则禁止加密。

–keysize n        : 密钥的位数(可选).

如果没有指定, 则默认为 cipher-specific 的默认值.

–engine [name] : 使能OpenSSL硬件加密引擎。

–no-replay        : 禁止 replay 保护.

–mute-replay-warnings : 不输出replay 警告.

–replay-window n [t]  : 使用大小为n的replay保护滑动窗口(replay protection

usliding window), t秒的时间窗口(time window).

默认值 n=64 t=15

–no-iv                : 禁止IV加密 — 仅允许CBC模式加密.

–replay-persist file : 使用文件file保持replay-protection状态 across sessions

–test-crypto    : 测试加密. 用于调试。 TLS 密钥协商选项:

(这些选项仅对TLS-模式有意义)

–tls-server      : 在TLS握手阶段使能TLS并使用规则。

–tls-client      : 在TLS握手阶段使能TLS并使用客户规则。

–key-method m  : 数据通道密钥交换方法.  m 是一个数字, 比如 1(默认值), 2, 等。

–ca file            : .pem格式的根证书文件。

–dh file            : .pem格式的Diffie Hellman参数文件(用于–tls-).

生成方法 “ssl dhparam -out dh1024.pem 1024″.

–cert file        : .pem 格式的本地证书文件 — 必须由–ca file中的认证机构签发。

–key file          : .pem 格式的本地私钥文件.

–pkcs12 file    : 包含本地私钥,本地证书和根证书的PKCS#12文件.

–cryptoapicert select-string : 从Windows证书系统库(Windows Certificate

System Store)装入证书和私钥.

–tls-cipher l  : 由:分隔的允许的TLS加密方法列表l: (可选).

: –show-tls 列出支持的TLS加密方法。

–tls-timeout n : TLS控制通道上包重传时间(default=2).

–reneg-bytes n : 发送和接收n个字节后重新协商data chan. key.

–reneg-pkts n  : 发送和接收n个包后重新协商data chan. key.

–reneg-sec n    : n秒后重新协商data chan. key (默认值=3600).

–hand-window n : 数据通道的密钥交换必须在n秒的握手阶段完成(默认=60).

–tran-window n : 发送窗口 — 新密钥协商开始后老密钥生存的时间(秒)

(默认=3600).

–single-session: 仅允许一个会话(重启时复位状态).

–tls-exit          : TLS 协商失败时退出.

–tls-auth f [d]: 在TLS控制通道上另加一个认证层来防止DoS攻击。

f (必需) 是一个 shared-secret passphrase 文件.

可选的 d 控制密钥方向。

更多信息查看–secret.

–askpass [file]: daemonize之前从tty获得PEM密码.

–auth-nocache  : 不暂存 –askpass 或 –auth-user-pass 口令.

–crl-verify crl: against a CRL检查对端证书.

–tls-verify cmd: 执行命令cmd验证已通过所有其他测试的TLS连接的X509名字。

cmd应该返回0使TLS 握手继续执行, 失败时则返回 1.

(cmd象这样执行’cmd certificate_depth X509_NAME_oneline’)

–tls-remote x509name: 仅接受X509名字为x509name的主机的连接。

远端必有已通过所有其它的验证测试。

–ns-cert-type t: 要求对端的证书必须是明确使用nsCertType

t = ‘client’ | ‘’签发的. SSL 库信息:

–show-ciphers  : 显示–cipher使用的加密算法..

–show-digests  : 显示–auth使用的消息摘要算法.

–show-engines  : 显示硬件加密加速引擎(如果可用的话).

–show-tls          : 显示所有的TLS密码 (TLS 仍用途控制通道). Windows 特有:

–ip-win32 method : 在Windows上使用–ifconfig时, 设置TAP-Win32

IP地址的方法 method = manual, netsh, ipapi, 或

dynamic (默认 = ipapi).

Dynamic 有两个可选参数:

offset: DHCP 地址偏移 (>-256 且 <256).

如果是0, 使用网络地址, 如果>0, take nth

address forward from 网络地址, 如果<0,

take nth address backward from 广播地址.

默认值 0.

lease-time: Lease time (秒).

默认值一年.

–route-method      : 在Windows下使用哪种方法添加

ipapi (默认) — 使用 IP helper API.

exe — 调用 route.exe .

–dhcp-option type [parm] : 设置 TAP-Win32 的扩展属性, 必须和

–ip-win32 dynamic一起使用.  如果允许多个地址,则必须

多次使用–dhcp-option .

DOMAIN name : 设置 DNS 后缀

DNS addr      : 设置动态域名服务器地址

NTP                : 设置NTP服务器地址

NBDD              : 设置NBDD地址

WINS addr    : 设置WINS服务器地址

NBT type      : 设置 NetBIOS over TCP/IP Node type

1: B, 2: P, 4: M, 8: H

NBS id          : 设置 NetBIOS scope ID

DISABLE-NBT : Disable Netbios-over-TCP/IP.

–dhcp-renew            : Windows启动时刷新TAP适配器。

–dhcp-pre-release : Windows启动时释放先前的TAP适配器线路。

–dhcp-release        : Windows 关闭时释放TAP适配器线路。

–tap-sleep n    : TAP适配器打开后设置属性之前休息n秒。

–pause-exit                : 从控制台窗口运行时,退出之前暂停。

–service ex [0|1]    : 作为服务运行。

ex 是一个事件对象的名字,当这一事件发生时将会使

OpenVPN退出. 第二个参数设置ex的初始状态。

–show-net-up    : 在TAP网卡连上(up)且路由添加后,显示OpenVPN的路由表和网卡

列表(net adapter list). Windows独立(Standalone)选项:

–show-adapters : 显示所有的TAP-Win32.

–show-net          : 显示 OpenVPN 的表和网络列表(net adapter list).

–show-valid-subnets : 显示–dev tun 模拟有效的子网. 生成一个随机密钥(非-TLS静态密钥加密模式):

–genkey

: 生成一个由–secret使用的随机密钥。

–secret file    : 将密钥写入文件file

————————————————

OpenVPN简易文档

1    OpenVPN简介

VPN替代昂贵的专线用以在开放的Internet上实现了一个虚拟的网络,该虚拟网络本身在不安全的真实网络上对数据提供安全保护。

OpenVPN实现了一个灵活的VPN,和通过修改协议栈而实现的基于IPSec的VPN相比,OpenVPN有以下的优点:

1.    OpenVPN无需对协议栈进行任何修改,无需专门的策略来解决VPN数据穿越NAT的问题,因此可在现有的网络进行规划;

2.    OpenVPN使用虚拟和路由进行虚拟网络的构建,配置十分方便;

3.    OpenVPN使用SSL协议对虚拟网络提供保护,从而实现“专用”,而SSL提供了丰富灵活的安全特性;

4.    OpenVPN的push模式可以最大限度简化客户端配置,和客户端可以不必花费太多的精力来使得两端一致。

OpenVPN实际上是虚拟网卡设备,TCP/IP网络技术,技术,SSL结合而成的一个应用,前三者构建了虚拟网络—隧道连接的网络,最后SSL保证了虚拟网络通信的安全—隧道通信的认证和加密,因此使用OpenVPN的过程基本就是对上述四方面进行配置的过程。

2    OpenVPN的参数集以及配置实例

2.1    参数详解

OpenVPN拥有很多的参数,但是很多参数涉及到很多的细节,首先如果不考虑过多的细节,那么这些参数大致可以分为五类,其中有一些参数是为了配置方便,组合其它的参数而成的:

2.1.1    虚拟网卡配置参数:

1)    –dev tunX|tapX:配置虚拟网络使用的设备,X是一个数字表示网卡的编号,在Unix/Linux系统中,它是一个字符设备,在Windows中, 它是一个设备命名空间中的一个节点,tun设备和tap设备的区别在于出入前者的第三层(IP)数据报,而出入后者的是第二层(以太网)数据帧。

注意:tap设备是二层设备,tun设备为三层设备,此二者各有优劣,简述如下:

tap特点:

a)    应用这种设备可以复用任意的三层数据报;

b)    构成一个两路层网络,比如以太网,因此广播数据可以自由跨隧道传输;

c)    无需路由即可进行节点通信;

d)    配置简单,但是缺乏灵活性,IP层的优良特性无法自由应用。

tun特点:

a)    可以应用IP层的所有特性,比如Routing,IP-Qos,IP-fragment/de等,但是只支持IP数据报;

b)    构成三层网络,节点间如不在一个子网要

c)    三层虚拟网络的每个子网下面没有链路层承载(ip数据报直接导出),因此链路层特性无法应用,比如以太网广播无法跨隧道传输,因此此虚拟网络是无法指定网关的。

2)    –dev-type dt:指示虚拟网卡设备的类型,仅仅在—dev参数无法识别设备类型的时候使用。

3)    –dev-node node:任意节点node被指示为虚拟网卡设备,node的路径以及名称可以任意,但是如果不是tunX/tapX的形式,那么必须配置—dev-type参数。

4)    –lladdr hw:为虚拟配置链路层地址。

2.1.2    网络配置参数:

1)    –local host:配置本地使用的IP地址,如果不是为了bind,那么可以不配置此参数,OpenVPN会自行处理。

2)    –remote host [port]:用于client端,配置client连接的server的IP或者名以及port,该参数可以配置多个用以实现一定的冗余,client则按照配置顺序依次连接server,直到连接成功为止。

3)    –proto p:配置隧道的类型,可以是udp或者tcp,其中tcp必须指明是还是client,而udp可以不区分server和client,因此p可以为udp,tcp-server,tcp-client。

注意:用tcp还是用udp构建隧道呢?默认是udp。任何有连接的协议在出现丢包时都会要求重发或者自动超时重发,为了避免因对网络带宽的未知或者网络 拥塞而丢包从而导致端点重发,tcp实现了慢启动,滑动窗口以及加增承减等机制,不幸的是,以上机制仅可用于分层模型中的一层,在不同层次都实现得如此复 杂就可能引起判断叠加从而使得上述机制无法做出最好的判断,比如用tcp建立的隧道,并且上面承载的又是tcp数据,那么一旦出现丢包,最终的端点以及隧 道都要重发数据,这就导致了网络流量突然增大,后面的行为很难在短时间给出预测并采取措施。事实上如果隧道本身并不是非用tcp不可,那么最好使用 udp,保证连接与否是最终终端的事,而不是隧道的事,如果说最终用户使用tcp,那么他自己就保证了连接,如果他使用udp,那么说明他不在乎是否有连 接,因此隧道使用udp,相反隧道使用tcp建立的话,如果最终用户使用已经保证了连接,隧道没必要再多此一举,如果最终用户使用udp,那么隧道 的tcp就降低了用户连接的效率,抵消了他使用udp的结果。

4)    –connect-retry n:配置连接重试的次数,仅仅对于—proto参数为-client时有效。

5)    –connect-timeout n:连接重试的间隔。

6)    –auto-proxy:

7)    –bind:

8)    –nobind:

9)    –link-mtu n:配置四层链路的MTU,同时用同样的数值配置设备的MTU。

注意:这个配置可能会引起莫名其妙的问题,就其本质是由于OpenVPN不允许通过隧道的数据被任意分段,即使是IP分片也必须妥善处理,OpenVPN 用一种规则的方式来收发socket数据。IP层将数据到虚拟前如果发现数据报的长度大于虚拟网卡的MTU,那么就会将数据报分片,如果VPN两 端的虚拟网卡的MTU设置不一致,OpenVPN接收socket数据的时候就会产生问题,因为最一般的情况下OpenVPN调用 recv/recvfrom的时候,参数中的len总是设置成自己的link-mtu,假设两端H1和H2的link-mtu分别为L1 和L2(L1>L2),H1端发送数据给H2,则数据在H2则会接收不完整,因此势必会产生错误,即使解密收到的数据可能正确,由于数据长度不一 致,校验时也会出错,即使在没有校验的情形下,由OpenVPN发送给虚拟网卡的IP数据报也会不完整。因此最好不要配置link-mtu参数,让它默认 值好了,如果非要配置,保持两端一致。可以在linux上用strace,dump以及OpenVPN源代码确认以上问题,具体为何这样设计还不清 楚。如果在不考虑安全因素(程序输出的意思是防止active attack)可以更合理一些的话,我觉得recv数据时要按照对方的mtu来接收,毕竟recv和send只是一个中间阶段,数据从对端虚拟的字符 设备出来后就被send了,然后在本端被recv,之后被write进本端的虚拟网卡字符设备,如果仅仅按照本端的mtu来接收,势必会有问题,就好像在 物理层上将数据截断一样。(在隧道的一端另一端,如果mtu不一致并且ping包大于mtu的小者的话,一定不同,可是仅仅将两端作为中间隧道的 话就不一定了,数据从A,经由隧道的起始Ts,到达隧道终点Te,最终到达主机B,如果Ts和Te的mtu中小者都比A和B的mtu的大者大,在不考 虑复杂的分段情况下是可以通的)因此,一种“几乎总是正确”的配置方法就是将mtu配置成一个很大的值,要比已知的物理链路的mtu都大,这样一来不会出 错,二来可以不必担心两端不一致,三来可以最大限度的发送数据,而不会因为隧道太窄的缘故而降低数据发送速率,如果不理解以上这些或者为了保险起见,还是 将mtu留默认比较好。

10)    –tun-mtu:注意事项同上,但是要强调和link-mtu之不同,此二者配置一个即可且只能配置一个,此中之缘由在于其关联性,tun-mtu为 虚拟网卡之mtu,而link-mtu则为链路的mtu,其大小相差一个固定长度,二者区别等同于TCP的MSS和物理链路的MTU之区别。

11)    –shaper:该参数对隧道的带宽进行了限制,主要用于建立多个信道时在各个信道进行策略化带宽分配,如果只建立一个通道,也就是说仅仅运行一个 OpenVPN实例的话,这个参数就目前版本而言意义不大,因为本身单进程单线程的OpenVPN速度就很慢,再限速更没有意义了。

12)    –txqueuelen:该参数设定虚拟的最大排队包的数量,也就是队列长度,默认为100,对于OpenVPN这样很慢的VPN来说,100就够了,即使你设得再大,用户空间的OpenVPN进程处理不过来还是白搭。

2.1.3    路由参数:

1)    –route network [netmask] [gateway] [metric]:增加一条路由。

2)    –max-routes n:

3)    –route-gateway gw|’dhcp’:

4)    –route-metric m:配置路由的传输开销

5)    –route-delay n [w]:配置添加的延迟,这是为了解决一IP地址自动配置的问题,有时候OpenVPN要添加路由了,可是OS还没有准备好,所以要给与一定的延迟。 具体来说就是,client和的连接建立以后,server需要往client端push一些信息,包括虚拟ip地址,子网掩码等必须的 信息以及路由等可选信息,client接收到以后需要在本机做相应的配置,比如配置虚拟网卡的ip/子网掩码,添加路由等,并且OpenVPN对虚拟网卡 的管理采取了一种懒惰的方式,也就是对于server只有在OpenVPN起来,对于client只有在和server的连接建立的时候才会建立虚拟网卡 对象并初始化,这个初始化过程就包括了设置ip地址/子网掩码,这个过程完成之前,添加路由是失败的,因此必须提供一些延迟保证虚拟网卡初始化完毕之后再 添加路由。这个选项主要针对某些虚拟网卡驱动设计不友好的系统,比如基于NDIS驱动的windows系统,虚拟网卡的ip地址“看起来”是通过DHCP 来分配,而DHCP分配是需要花费时间的,此间添加的请求必须等待。

2.1.4    SSL及安全参数:

1)    –genkey:生成一个对称密钥,该参数只能单独使用,该对称密钥的生成是为了使OpenVPN两端共享,从而不再使用SSL握手协议进行密钥协商。

2)    –secret file:使用共享的对称密钥。这实际上省去了SSL的握手,用于通信双方确信已拥有绝对保密绝对安全的对称密钥的情况,实际上SSL的握手也是为了这个 保证,二者殊途同归,因此问题的难度就在于一端用—genkey生成的密钥如何传输至另一端。这其实就是另一个大问题了,可以用数字信封传过去,甚至可以 冒险用明文直接发过去,这些都不是OpenVPN要考虑的。一般地在都是通过scp程序传递的,方便又安全。

3)    –reneg-XXX:这一族参数用来重新协商session key。OpenVPN基于SSL协议,然则其用法另有说法,SSL协议自带认证和加密功能,对于OpenVPN来说此二者是分开的,如果不考虑认证,密 钥协商的过程很容易受到中间人攻击,因此不管是基于IPSec这种修改或挂钩协议栈实现的VPN还是OpenVPN都提供了认证机制。OpenVPN使用 证书来进行认证,使用DH来进行密钥协商。使用DH而不是别的是由于建立的隧道安全参数要每隔一段时间进行一次重新协商,默认时间为1个小时,而DH的效 率很高,它不像RSA产生密钥那么耗时(由于美国出限制或者证书中没有可用于加密的公钥,在SSL握手时就需要临时生成一对RSA密钥),如此在 key exchange message消息中传输的就是DH参数了。

4)    –ca file:CA证书,用以验证对端的用户证书,这个参数可以包含多个证书,也就是一条证书链,在Unix/Linux中可以用cat命令将多个证书追加成一个文件。

5)    –cert file:自己的证书,用于传递给对端以表明自己的身份或者实现其它的准入性验证。

6)    –key file:对应—cert参数的key文件。

7)    –cryptoapicert select-string:用于从Windows的证书Store中获取证书,如此就不再需要—cert和—key参数了,select-string 是一个字符串,可以认为是一个查找“键值”,以”名称:值”的形式存在,比如使用颁发给名字是“老李”的个人的证书,那么select-string就 是:”SUBJ:老李”。这个参数多数用于key或者证书无法单独导出的环境下,比如一些设备。

2.1.5    事件参数:

1)    –route-up cmd:cmd是一个shell脚本,并且可以携带参数,该脚本在所有路由被添加之后被执行。

2)    –route-noexec:

3)    –route-nopull:用于client端,如果client端配置了—pull,那么该参数保证client不会pull过来server端push的

4)    –allow-pull-fqdn:

5)    –ping n:每n秒钟ping一次对端。

6)    –ping-restart n:如果n秒收不到对端的ping报文,那么就重启。

7)    –ping-exit n:如果n秒收不到对端的ping报文,那么就退出。

8)    –keepalive n m:该参数项为5)和6)的封装,展开后有下面的形式:

if mode :

ping n

ping-restart 2*m

push “ping n”

push “ping-restart m”

else

ping n

ping-restart m

注意:/ping-restart实现了一个心跳保活机制,这个机制在协议构建的隧道和udp协议构建的隧道中表现是不同的,使用tcp建 立的隧道本身就是有连接的,如果一端进程异常退出,那么OS必然会发送reset报文,这种情况其实keepalive的意义并不大,但是如果是诸如网线 被拔掉或者断电之类的问题,keepalive就有必要了,因为tcp没有机会在事前发送任何报文,此时tcp隧道的keepablive配置就和udp 一样了,如果ping-restart配置的过于大,对于tcp,将有更多的机会依靠tcp本身的超时重发机制使连接保持(前提是机器启动了或者网线又插 上了),而对于udp,只能依靠这个ping-restart,否则它永远不知道对端已经断开过了,如果对端在ping-restart配置的时间内重新 启动了,本端将不会知道对端已经断开过又重新启动了。反过来如果ping/ping-restart配置过小,将会有大量的包出现在网络,并且会 引起大量的重连,有时由于网络拥塞导致的ping接收超时这种根本就不需要重连的情况也会重连。到底配置成多少需要根据自己网络的规模,使用的协议等因素 来权衡。

9)    –persist-tun:在由于接收到SIGUSR1信号或者由于keepalive超时(–ping-restart)原因而重新建立连接的时 候,并不关闭并且重新打开虚拟设备。该参数会对网络行为造成影响,如下一例:client端由于某种原因休眠或者待机了,或者在任何可能的原因下重置 了网络而没有结束OpenVPN进程,VPN的路由随着网络的重置可能就被删除了,此时如果不重新打开虚拟网卡,待重新连上之 后,server端push过来的路由将不会被添加到client端路由表,最终之结果就是client端看到VPN网络仍然连通,然则由于没有 server端推送的路由而无法实际进行通信,VPN网络仍然连通全系一条协议栈自动发现的链路层路由,而该路由只要虚拟网卡up,就会自动添加,如果用 户不检查表或者非技术人员不懂的检查路由表,这种问题很难被排除。

10)    –persist-XXX族:以上描述了–persist-tun以及它可能造成的问题,但是参数存在的意义并不是为了引起问题的,相反是为了解决一 系列问题的,之所以存在persisit参数,顾名思义是为了“保持”一些东西,也就是说这些配置在由于接收到SIGUSR1信号或者由于– restart而重置连接时,这些配置不会改变,这才是这一族参数存在的意义,比如管理员由于某种原因想热重启一下VPN服务,或者由于网络拥塞而导致 keepalive超时,重新分配IP地址,重新配置等动作都是没有必要的。和该族参数有关联的一个参数就是—user参数。

11)    –client-connect cmd:只要有client连接,就会执行cmd。

2.1.6    OpenVPN本身的配置参数:

1)    –nice n:设置VPN进程的nice值,此参数将影响VPN进程的优先级,数值越小优先级越高。

2)    –user user:切换OpenVPN运行的UID。User是一个UID。这个参数的目的在于安全性,一旦有攻击者获取了OpenVPN进程的控制权,他所能做 的也很有限。但是注意这种主动放弃root权限的行为是不可逆转的,否则攻击者也可以逆转,该参数也就失去了存在的意义。所以要注意的是,如果使用了— user参数,那么要确保一系列persist参数被设置从而在软重启OpenVPN的时候避免进行需要root权限的操作,这是因为很多操作是需要 root权限的,比如ifconfig。

3)    –mlock:该参数的行为和操作系统紧密关联。配置该参数的结果就是将key等敏感信息锁在内存而永不被换入磁盘,如果不过度专注于其对效率的提升, 则仅从安全性考虑它的意义也是不容忽视的。如果key被换入了磁盘,那么key就有可能被窃取,攻击者只需要简单的从交换分区读取即可,这里的key并不 是指key文件,而是动态生成的用语协商密钥的数据,key文件一般以映像方式进入内存编址空间而不会被换入交换空间,如是可以说,key文件本身也是不 安全的,攻击者掌握了你的机器,读取你的磁盘易如反掌,因此key文件的保护应依赖于你的主机安全,对于锁在内存的数据的保护,更进一步,应依赖于比主机 安全更进一步的内存管理的安全,即使这样也还是可以攻破的,比如如果你有root权限,在很多linux上你都可以读取/dev/mem来dump当前的 内存,这和读取磁盘有何区别呢?dump内存真的比dump交换分区更难吗?实际上一旦你有了root权限加上你有扎实的功底,整台机器的任何对象都尽在 你的掌握之中。(最好的办法就是永远不将敏感数据导出到“公共”空间,我说磁盘和内存都是可以复用的公共空间,公共空间的不安全性在于大家都可以访问,充 其量出示一些证明就能被准入,而这证明之真伪连带验证之逻辑本身又是一个极其复杂的体系,因此最好在私密空间完成所有的涉密操作,比如PKCS#11中所 描述的,私密空间导入导出的仅仅是操作之结果以及操作之把手—句柄,正如开动汽车只需钥匙,按钮,方向盘而无需了解轮轴,气缸,变速器一致。)

4)    –mode m:配置VPN的mode,有p2p和server两类,p2p顾名思义就是点对点,也就是说整个虚拟网络只有两台,这两台主机一台是另一台是 客户端;server的含义和p2p不同,它可以实现一个一对多的虚拟网络,同时可以有多个客户端连接入一个服务器。

5)    –topology t:2.1版本新增参数,指定网络拓扑,可选参数为net30,p2p以及subnet。net30拓扑结构主要用于p2p网络,该种网络假设 server和client均存在于一个p2p链路之上,因此各需要配置一个p2p网关,每对连接要用去4个IP地址,这也正是30的含义,client 和server均占有一个30位的子网掩码的网络,每端余下4个IP地址,然则一个子网中全0号IP表示子网本身,全1号IP表示广播地址,于是仅留下两 个IP地址可用,net30虽然用于p2p链路,在以太网这种广播网络中也是可以使用的,该模式十分浪费IP地址;p2p拓扑用在一种半p2p的网络 中,将分配且只分配一个IP地址给client端,如此一来client端就可以和server端直接建立联系,而不必再通过一个p2p网关 了,而server端仍然保留p2p网关,类似net30模式;subnet拓扑则是完全实现了虚拟网络从p2p模式向广播型网络的过渡,server端 和client端均使用且只使用一个IP地址,如此一来server和所有的client构成一个可以基于广播链路的虚拟局域网(注意不是VLAN),大 量节省了IP地址并且降低了配置的难度。

注意:net30->p2p->subnet的演进过程有两层含义,第一层含义代表了OpenVPN本身的版本升级,在2.0之前 OpenVPN是不支持multi-clients的,也就是说所有的p2p模式以及c/s模式均是一对一的连接,因此虚拟的配置很简单,直接配置上 对端的ip地址即可,但是到了2.0及之后,OpenVPN的一个可以对应多个客户端了,按照前面的思路,只需要将client虚拟网卡的地 址p2p地配置成server的虚拟网卡地址即可,可是对于Windows这样却不行,于是就引出了第二层含义,为了兼容Tap-WIN32驱 动,Tap-WIN32驱动不支持在“点对多点/多点对多点”的链路上创建p2p连接,于是不得不用net30的方式来“模拟”出一条p2p的链路,比如 对于client来讲,tun的地址配置是:

10.8.0.6<–>10.8.0.5

server的配置是:

10.8.0.1<–>10.8.0.2

在这里,.5和.2地址都是为了模拟p2p的,对于client来讲,.5就是server,而对于server来讲,.2就是client,所以这些模 拟的地址仅仅是在OpenVPN内部使用,对于外界是不可见的。这样在不支持真实p2p配置的Tap-WIN32上就可以配置出一条虚拟的p2p链路了, 而模拟的地址仅仅作为路由将数据导向真正的server。

6)    –push “option”:推送一个配置到对端,如果对端期望接收并应用该配置,那么它必须配置—pull参数。

7)    –client-to-client:使能客户端之间的通信,仅在—mode配置成的时候有意义,此时server被众client连接,server就是这些client之间通信的“器”。

8)

察看OpenVPN的man手册或者直接执行—help,你会得到另外一种参数分类的方式,基本上—help显示出的结果是基于OpenVPN的设施进行分类的,而本文档则是基于OpenVPN的行为进行分类的。

2.2    OpenVPN的配置实例

OpenVPN的使用非常简单,它有两种使用方式,这个和*nix的传统相一致,一般提供众多命令行参数的程序都会提供一个配置文件,因此如果环境过于复杂,那么用配置文件要比直接使用命令行更方便。

官网:  http://openvpn.net/index.php/open-source/documentation/manuals/65-openvpn-20x-manpage.html,这里有很多参数讲解。

http://vpn.net/index.php/open-source/documentation/howto.html

转载请注明:爱开源 » 深入 OpenVPN 配置

您必须 登录 才能发表评论!