OpenVPN连接两个局域网(使用华硕RT-AC87U)

1 前言

本文所述VPN通道是使用带有OpenVPN的路由器(ASUS RT-AC87U)创建的,文中重点在OpenVPN服务端和客户端配置文件的内容,对这些配置项的理解,以及配置过程中遇到的问题。

主要硬件:ASUS RT-AC87U

需求:连接A、B两个子网,两子网内主机可互相自由访问。

网络拓扑图:VPN Router 1是服务端,VPN Router 2作为客户端。

connect-two-subnets-using-openvpn_01

2 说明

OpenVPN有两种工作模式:路由和桥接。路由模式工作在OSI第3层,广播包无法透过VPN,但其效率高,可扩展性(scalability)强。桥接模式工作在OSI第2层,允许广播包透过VPN,不需要设置路由,但效率和可扩展性较路由模式差。本文所述配置使用路由模式。

OpenVPN还可配置为通过VPN访问外部网络(客户端主机的默认路由指向VPN),但与本文目的不同,不涉及。

对于ASUS RT-AC87U这台路由器而言,下面的配置文件都是隐藏于路由器配置界面之后的,并且其内容无法随意更改。把配置文件放在这里的目的,一是为了方便理解ASUS RT-AC87U的OpenVPN功能;二是在PC主机或服务器上自行搭建OpenVPN时,可以作为参考。

3 配置

3.1 服务端

3.1.1 配置文件内容

daemon
server 10.8.0.0 255.255.255.0
proto udp
port 12345
dev tun21
float
cipher BF-CBC
comp-lzo adaptive
keepalive 15 60
verb 3
client-config-dir ccd
ccd-exclusive
route 192.168.1.0 255.255.255.0
tls-auth static.key 0
plugin /usr/lib/openvpn-plugin-auth-pam.so openvpn
ca ca.crt
dh dh.pem
cert server.crt
key server.key
status-version 2
status status
push "route 192.168.0.0 255.255.255.0"
push "route 172.16.0.0 255.255.0.0"

ccd目录中有一个名为client的文件(客户端证书的Common Name是client),其内容如下:

iroute 192.168.1.0 255.255.255.0

3.1.2 配置项说明

daemon
在初始化结束后成为一个后台程序。这一选项会让所有程序信息和错误输出都发往syslog文件(如/var/log/messages)。脚本和ifconfig命令的输出若没有重定向,默认发往/dev/null。
server network netmask
这一指令简化了OpenVPN服务端的配置。它会创建一个OpenVPN服务器,并根据给定的网络/掩码为客户端分配IP地址。服务器会把给定网络中的“.1”这个IP分配给自己的TUN/TAP接口。
proto p
使用协议“p”与另一端主机通信。p可以是“udp”,“tcp-client”或“tcp-server”,默认udp。若使用udp,服务端客户端都必须是proto udp;若使用tcp,一端必须是--proto tcp-server,另一端必须是--proto tcp-client。推荐使用udp。
port port
指定协议端口号。默认1194。
dev tunX | tapX | null
TUN/TAP虚拟网络设备(动态设备可忽略X)。tun设备封装(encapsulate)IPv4或IPv6(OSI第3层)tap设备封装Ethernet 802.3(OSI第2层)。
float
允许远端主机改变自己的IP地址和/或端口号。结合--remote参数,它允许OpenVPN回话一开始连接到一个已知的IP地址,如果之后的packet从一个新地址到达,但通过了所有鉴定测试,则新地址会接管这一回话。当远端主机的IP地址是动态的(客户端是DHCP或拨号连接),这一选项会很有用。从本质上来说,--float告诉OpenVPN从所有地址接受通过鉴定的packet,不只是--remote选项中指定的地址。
cipher alg
使用加密算法alg加密packet,客户端服务端这一选项必须保持一致。默认算法BF-CBC(全称Blowfish in Cipher Block Chaining mode)。可使用--show-ciphers选项查看其他支持的算法。OpenVPN支持CBC,、CFB和OFB密码(cipher)模式。推荐使用CBC,而把CFB和OFB看作进阶模式。
comp-lzo [mode]
使用快速LZO压缩。mode可以是“yes”,“no”或“adaptive(默认)”。
keepalive n m
时间参数。如果在n秒内没有发送packet,则通过TCP/UDP控制通道ping另一端的主机。时间n的用意有两个:一是与状态敏感的防火墙兼容,确保允许OpenVPN通过的防火墙规则不会因超时失效;二是为判断另一端主机是否在线提供一个手段。m是超时重连时间,在服务端,这一时间会被加倍。例如设置为60,在客户端超时重连时间是60秒,但在服务端,是120秒。这是为了确保在服务端丢弃连接前,客户端已经检测到连接超时。
verb n
配置输出信息的详细度。0,只输出严重错误;1-4,正常使用区间;5,为每一packet的读或写向控制台输出R或W字符,大写用于TCP/UDP packet,小写用于TUN/TAP packet;6-11,调试信息区间。
client-config-dir dir
指定目录dir存放客户端自定义配置文件。当一个已连接的客户端通过鉴定后,OpenVPN会在dir下寻找与此客户端证书的Common Name同名的文件,若找到,会打开并解析为特定客户端的配置选项;若未找到,会尝试打开并解析名为“DEFAULT”的配置文件(这一文件不是必需的)。在这一文件中合法的选项有--push,--push-reset,--iroute,--ifconfig-push,和--config。
ccd-exclusive
作为鉴定的条件之一,要求客户端必须有一个client-config-dir文件,否则拒绝建立连接。
route network/IP [netmask] [gateway] [metric]
iroute network [netmask]
--route选项用于连接建立后把这条路由添加进路由表。--iroute选项用于给某一客户端生成内部路由。在本配置文件中,--route告诉操作系统,子网192.168.1.0/24应路由到OpenVPN;--iroute告诉OpenVPN,子网192.168.1.0/24应路由到client。这两个选项相结合,服务端所在子网就能访问到客户端所在子网。
tls-auth file [direction]
在TLS控制通道上附加的HMAC鉴定层,用来抵御DoS攻击。简单来说,此选项在OpenVPN的TCP/UDP端口上启用了一种“HMAC防火墙”,HMAC签名(signature)错误的TLS控制packet会立即丢弃,并且不发送回应。file可以是一个使用--genkey参数生成的OpenVPN静态key文件,也可以是一个形式自由的密码文件。使用OpenVPN静态key文件时,必须指定direction。VPN通道两端的direction必须互补,比如一端设置为0,另一端设置为1。当OpenVPN被配置为监听任意IP地址的packet时(未指定--remote,或--remote与--float同时使用),建议使用--tls-auth。注意,这一选项只用于TLS初始化,并不用于加密或鉴定通道内数据。
plugin module-pathname [init-string]
从module-pathname文件加载插件模块,把init-string作为参数传递给模块,用来初始化模块功能。可为OpenVPN进程加载多个插件模块。在本配置文件中,这一选项的含义是使用PAM对客户端提供用户名和密码的连接鉴定。
ca file
dh file
cert file
key file
--ca,指定CA(Certificate authority)证书文件;--dh,指定包含Diffie Hellman参数的文件;--cert,指定服务端证书文件;--key,指定服务端证书文件的私钥。
status-version [n]
状态文件格式的版本号。可以是1、2或3,默认是1。
status file [n]
每过n秒钟把操作状态写入文件file。
push option
把配置选项推送给客户端,以便在客户端执行。option必须使用双引号("")括起来。在本配置文件中,这两条参数的目的是告诉客户端服务端有哪些子网。客户端会把这两条路由添加到操作系统中,目标地址在这两个子网中的packet会发送到VPN tunnel。

3.2 客户端

3.2.1 配置文件内容

daemon
client
proto udp
remote 1.1.1.1 12345
float
dev tun11
cipher BF-CBC
comp-lzo adaptive
keepalive 15 60
ns-cert-type server
resolv-retry infinite
nobind
persist-key
persist-tun
auth-user-pass up
verb 3
tls-auth static.key 1
ca ca.crt
cert client.crt
key client.key
status-version 2
status status

3.2.2 配置项说明

与服务端重复的配置项不再说明,因为其作用相同。

client
这一指令简化了客户端配置。让客户端执行服务端push过来的选项;同时在TLS握手期间承担客户端角色。
remote host [port] [proto]
远端主机的IP地址或主机名。OpenVPN客户端会尝试连接到host:port的服务器。proto是连接时使用的协议,可以是tcp或udp。由于udp是无连接的,连接失败由--ping和--ping-restart定义。若为提供remote参数,OpenVPN会监听所有IP地址的packet,但只有当它们通过鉴定测试后才会做出反应。
ns-cert-type client|server
要求对等主机证书使用明确的nsCertType命名,“client”或“server”。此选项可确保客户端连接的主机是指定的服务器。这一选项是一个重要的安全预防措施,可防御man-in-the-middle攻击(在这样的攻击中,授权的客户端会尝试连接到伪装成服务端的其它客户端)。
resolv-retry n
如果--remote的主机名解析失败,重新尝试解析n秒。默认--resolv-retry infinite,可把n设置为0以禁用。
nobind
不要绑定到本地IP和端口。IP协议栈会为返回的packet分配动态端口号。由于动态端口号无法预先被对等主机知晓,这一选项只适合使用--remote选项初始化连接的对等主机。
persist-key
在SIGUSR1或--ping-restart以后,不要重新读取key文件。
persist-tun
在SIGUSR1或--ping-restart以后,不要关闭重打开TUN/TAP设备或执行up/down脚本。--persist-tun及--persist-key选项的用意,详见man 8 openvpn。
SIGUSR1
一个信号,类似于SIGHUP信号。SIGHUP让OpenVPN关闭所有TUN/TAP和网络连接,容器,荣欣读取配置文件(如果有),重新打开TUN/TAP和网络连接。它与SIGHUP的区别,是不重新读取配置文件;同时,基于--persist-tun,--persist-key,--persist-local-ip,和--persist-remote-ip选项,可能也不关闭并重新打开TUN/TAP设备,不重新读取key文件,保留本地IP地址/端口,或保留最近鉴定过的远端IP地址/端口。这一信号也可被由--ping-restart控制的时间条件激发而从内部生成。
auth-user-pass [up]
使用用户名/密码与服务器进行鉴定。up是一个文件,用户名和密码分两行存储在这一文件中。

4 问题及解决

4.1 A中主机与B中主机相互无法ping通

VPN Router 1中没有到达B网络的路由,同时VPN Router 2中没有到达A网络的路由。解决方法是在服务端使用--route、--iroute、--push选项,让服务端和客户端互相了解对方的局域网,并自动在路由器中添加路由(详见服务端配置文件)。

4.2 配置都正确,但客户端连不上服务端,同时服务端日志出现“certificate is not yet valid”错误

这一错误只会在作为服务端的路由器重启后才会出现,问题的原因是时间。AC87U重启后初始时间是2011年1月1日上午8:00。如果证书是路由器自动生成的,证书的生效时间肯定晚于2011年1月1日上午8:00。当路由器时间超过证书生效时间后,即可正常连接。

解决方法有两个,一是把电脑的时间修改为2011年1月1日上午8:00以前,然后重新生成一套证书(CA、DH、Server、Client),让路由器使用这套证书;二是让路由器可访问互联网,从而能通过ntp自动配置正确的时间。

4.3 客户端无法连接服务端,同时服务端日志出现“--client-config-dir authentication failed for common name”错误

这一错误出现在这样一种情况下:A与B已通过本文所述方式建立了连接,但还希望单独的客户端(下文称作C)可通过VPN Router 1访问A网络。

由于使用了--ccd-exclusive选项(由于路由器限制,若想让A能访问B中主机,必须使用此选项),若C使用与VPN Router 2上相同的客户端证书,会造成A与B连接中断,因此必须给C专门生成了一个客户端证书及对应的私钥。当C使用自己的证书连接服务端时,就会出现这一错误。

由于路由器限制,在这一情况下可以尝试的解决方法,是随便添加一个--iroute路由及与之对应的--route路由。由于C是单独的主机,而且是从外部连接到VPN Router 1,不大可能具有固定IP,这一方案不是很合适。但由于路由器限制,这是唯一的解决方法。

5 参考文档

5.1 OpenVPN HOWTO

5.2 man 8 openvpn

5.3 OpenVPN documentation

点击量:2158

3个评论

    • 好久没摸过这个型号的路由器,都忘了。你先到/etc里面找找,不行的话,运行ps aux命令,看openvpn进程的参数,里面可能会有路径。

  1. Pingback: OpenVPN相关 – 汪小喵

发表评论

电子邮件地址不会被公开。 必填项已用*标注

18 − 3 =