Cisco AnyConnect是非常流行的SSL VPN客户端,并且跨平台,常见于iOS,Android,BlackBerry平台。由于我同时使用Linux,Mac,iPhone,黑莓,所以为了方便使用,采用通用的OpenConnect VPN Server - ocserv(兼容Cisco AnyConnect的开源解决方案)来部署VPN Server。
- 源代码下载
从 ocserv gitlab软件库 下载最新源代码
git clone https://gitlab.com/ocserv/ocserv.git
- 编译依赖
Debian和Fedora编译依赖软件库分别是 libgnutls28-dev
和 gnutls-devel
,此外,对应的一些可选功能依赖库如下
TCP wrappers: libwrap0-dev / tcp_wrappers-devel
PAM: libpam0g-dev / pam-devel
LZ4: liblz4-dev / lz4-devel
seccomp: libseccomp-dev / libseccomp-devel
occtl: libreadline-dev / readline-devel
libnl-route-3-dev / libnl3-devel
GSSAPI: libkrb5-dev / krb5-devel
开发依赖库如下
libprotobuf-c0-dev / protobuf-c-devel
libtalloc-dev / libtalloc-devel
libhttp-parser-dev / http-parser-devel
libpcl1-dev / pcllib-devel
libopts25-dev / autogen-libopts-devel
autogen / autogen
protobuf-c-compiler/ protobuf-c
gperf / gperf
Debian/Ubuntu按照以下命令准备依赖库安装 (参考 Setup OpenConnect VPN Server for Cisco AnyConnect on Ubuntu 14.04 x64)
apt-get install build-essential pkg-config libgnutls28-dev libwrap0-dev libpam0g-dev libseccomp-dev libreadline-dev libnl-route-3-dev
上述依赖包安装缺少
lbopts25-dev
,编译时候发现报错,所以补充安装了官方文档中说明的所有可选依赖开发库
- 编译 ocserv
如果是发行版本
./configure && make
如果是git版本
autoreconf -fvi
./configure && make
报错
make[3]: Entering directory '/root/ocserv/libopts'
CC libopts_a-libopts.o
In file included from libopts.c:24:0:
enum.c: In function ‘enum_err’:
enum.c:112:13: warning: embedded ‘\0’ in format [-Wformat-contains-nul]
fprintf(option_usage_fp, ENUM_ERR_LINE, *(paz_names++));
^
enum.c:135:9: warning: embedded ‘\0’ in format [-Wformat-contains-nul]
sprintf(zFmt, ENUM_ERR_WIDTH, (int)max_len);
^
尝试改成
./configure --enable-local-libopts
报错改成
make[2]: Entering directory '/root/ocserv/src'
: ocpasswd-args.def
: ocserv-args.def
protoc-c --c_out=. --proto_path=. ipc.proto
/bin/bash: protoc-c: command not found
Makefile:1779: recipe for target 'ipc.pb-c.c' failed
解决方法参考 OpenConnect on Ubuntu 并按照官方文档安装所有可选依赖开发库DTLS Dead Peer Detection detected dead peer!
apt-get install libprotobuf-c0-dev libtalloc-dev libhttp-parser-dev libpcl1-dev libopts25-dev autogen protobuf-c-compiler gperf
然后重新编译就可以通过
./configure
make
安装
make install
配置ocserv
首先需要创建自己的CA证书和服务器证书
cd ~
apt-get install gnutls-bin
mkdir certificates
cd certificates
创建CA模版文件 ca.tmpl
,这里cn
请设置成自己组织的cn
cn = "VPN CA"
organization = "Big Corp"
serial = 1
expiration_days = 3650
ca
signing_key
cert_signing_key
crl_signing_key
生成CA密钥和CA证书
certtool --generate-privkey --outfile ca-key.pem
certtool --generate-self-signed --load-privkey ca-key.pem --template ca.tmpl --outfile ca-cert.pem
然后使用以下内容创建本地服务器证书模版文件(server.tmpl
),注意cn
字段,必须符合你服务器的DNS名字或者IP地址
cn = "you domain name or ip"
organization = "MyCompany"
expiration_days = 3650
signing_key
encryption_key
tls_www_server
然后创建服务器密钥和证书
certtool --generate-privkey --outfile server-key.pem
certtool --generate-certificate --load-privkey server-key.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --template server.tmpl --outfile server-cert.pem
复制密钥、证书和配置文件到ocserv配置目录
mkdir /etc/ocserv
cp server-cert.pem server-key.pem /etc/ocserv
cd ~/ocserv/doc
cp sample.config /etc/ocserv/config
cd /etc/ocserv
编辑 /etc/ocserv/config
配置文件,类似如下
auth = "plain[/etc/ocserv/ocpasswd]"
try-mtu-discovery = true
server-cert = /etc/ocserv/server-cert.pem
server-key = /etc/ocserv/server-key.pem
tcp-port = 9000
udp-port = 9001
dns = 8.8.8.8
# comment out all route fields
#route = 10.10.10.0/255.255.255.0
#route = 192.168.0.0/255.255.0.0
#route = fef4:db8:1000:1001::/64
#no-route = 192.168.5.0/255.255.255.0
cisco-client-compat = true
no-route
配置可能需要根据自己的局域网配置调整。此外,对于国内网段,设置no-route可以避免国内流量通过vpn降低访问效率。默认端口是
443
,这里改成9000
另外,参考 安装配置AnyConnect服务端软件-ocserv做一些配置优化调整
#同一个用户最多同时登陆数
max-same-clients = 10
# Dead peer detection in seconds.
dpd = 900
# Dead peer detection for mobile clients. The needs to
# be much higher to prevent such clients being awaken too
# often by the DPD messages, and save battery.
# (clients that send the X-AnyConnect-Identifier-DeviceType)
mobile-dpd = 1800
output-buffer = 23000
try-mtu-discovery = true
# The time (in seconds) that a client is allowed to stay idle (no traffic)
# before being disconnected. Unset to disable.
idle-timeout = 3600
# The time (in seconds) that a mobile client is allowed to stay idle (no
# traffic) before being disconnected. Unset to disable.
mobile-idle-timeout = 3600
创建用户登录帐号
ocpasswd -c /etc/ocserv/ocpasswd username
激活NAT
iptables -t nat -A POSTROUTING -j MASQUERADE
激活IPv4 forwarding,编辑/etc/sysctl.conf
net.ipv4.ip_forward=1
并使之生效
sysctl -p /etc/sysctl.conf
启动ocserv
ocserv -c /etc/ocserv/config
注意:Cisco AnyConnect客户端配置要同时写上服务器IP地址和端口,类似
IP:PORT
Debug方法
ocserv -c /etc/ocserv/config -d 9 -f
-d
参数设置debug级别,从0-999
路由设置
参考 Ocserv 在 Debian 下的安装与配置指南,在 /etc/ocserv/config
中添加配置
no-route = 0.0.0.0/255.0.0.0
no-route = 1.0.0.0/255.128.0.0
no-route = 1.160.0.0/255.224.0.0
no-route = 1.192.0.0/255.224.0.0
no-route = 10.0.0.0/255.0.0.0
no-route = 14.0.0.0/255.224.0.0
no-route = 14.96.0.0/255.224.0.0
no-route = 14.128.0.0/255.224.0.0
no-route = 14.192.0.0/255.224.0.0
no-route = 27.0.0.0/255.192.0.0
no-route = 27.96.0.0/255.224.0.0
no-route = 27.128.0.0/255.128.0.0
no-route = 36.0.0.0/255.192.0.0
no-route = 36.96.0.0/255.224.0.0
no-route = 36.128.0.0/255.128.0.0
no-route = 39.0.0.0/255.224.0.0
no-route = 39.64.0.0/255.192.0.0
no-route = 39.128.0.0/255.192.0.0
no-route = 42.0.0.0/255.0.0.0
no-route = 43.224.0.0/255.224.0.0
no-route = 45.64.0.0/255.192.0.0
no-route = 47.64.0.0/255.192.0.0
no-route = 49.0.0.0/255.128.0.0
no-route = 49.128.0.0/255.224.0.0
no-route = 49.192.0.0/255.192.0.0
no-route = 54.192.0.0/255.224.0.0
no-route = 58.0.0.0/255.128.0.0
no-route = 58.128.0.0/255.224.0.0
no-route = 58.192.0.0/255.192.0.0
no-route = 59.32.0.0/255.224.0.0
no-route = 59.64.0.0/255.192.0.0
no-route = 59.128.0.0/255.128.0.0
no-route = 60.0.0.0/255.192.0.0
no-route = 60.160.0.0/255.224.0.0
no-route = 60.192.0.0/255.192.0.0
no-route = 61.0.0.0/255.192.0.0
no-route = 61.64.0.0/255.224.0.0
no-route = 61.128.0.0/255.192.0.0
no-route = 61.224.0.0/255.224.0.0
no-route = 100.64.0.0/255.192.0.0
no-route = 101.0.0.0/255.128.0.0
no-route = 101.128.0.0/255.224.0.0
no-route = 101.192.0.0/255.192.0.0
no-route = 103.0.0.0/255.192.0.0
no-route = 103.224.0.0/255.224.0.0
no-route = 106.0.0.0/255.128.0.0
no-route = 106.224.0.0/255.224.0.0
no-route = 110.0.0.0/254.0.0.0
no-route = 112.0.0.0/255.128.0.0
no-route = 112.128.0.0/255.224.0.0
no-route = 112.192.0.0/255.192.0.0
no-route = 113.0.0.0/255.128.0.0
no-route = 113.128.0.0/255.224.0.0
no-route = 113.192.0.0/255.192.0.0
no-route = 114.0.0.0/255.128.0.0
no-route = 114.128.0.0/255.224.0.0
no-route = 114.192.0.0/255.192.0.0
no-route = 115.0.0.0/255.0.0.0
no-route = 116.0.0.0/255.0.0.0
no-route = 117.0.0.0/255.128.0.0
no-route = 117.128.0.0/255.192.0.0
no-route = 118.0.0.0/255.224.0.0
no-route = 118.64.0.0/255.192.0.0
no-route = 118.128.0.0/255.128.0.0
no-route = 119.0.0.0/255.128.0.0
no-route = 119.128.0.0/255.192.0.0
no-route = 119.224.0.0/255.224.0.0
no-route = 120.0.0.0/255.192.0.0
no-route = 120.64.0.0/255.224.0.0
no-route = 120.128.0.0/255.224.0.0
no-route = 120.192.0.0/255.192.0.0
no-route = 121.0.0.0/255.128.0.0
no-route = 121.192.0.0/255.192.0.0
no-route = 122.0.0.0/254.0.0.0
no-route = 124.0.0.0/255.0.0.0
no-route = 125.0.0.0/255.128.0.0
no-route = 125.160.0.0/255.224.0.0
no-route = 125.192.0.0/255.192.0.0
no-route = 127.0.0.0/255.0.0.0
no-route = 139.0.0.0/255.224.0.0
no-route = 139.128.0.0/255.128.0.0
no-route = 140.64.0.0/255.224.0.0
no-route = 140.128.0.0/255.224.0.0
no-route = 140.192.0.0/255.192.0.0
no-route = 144.0.0.0/255.192.0.0
no-route = 144.96.0.0/255.224.0.0
no-route = 144.224.0.0/255.224.0.0
no-route = 150.0.0.0/255.224.0.0
no-route = 150.96.0.0/255.224.0.0
no-route = 150.128.0.0/255.224.0.0
no-route = 150.192.0.0/255.192.0.0
no-route = 152.96.0.0/255.224.0.0
no-route = 153.0.0.0/255.192.0.0
no-route = 153.96.0.0/255.224.0.0
no-route = 157.0.0.0/255.192.0.0
no-route = 157.96.0.0/255.224.0.0
no-route = 157.128.0.0/255.224.0.0
no-route = 157.224.0.0/255.224.0.0
no-route = 159.224.0.0/255.224.0.0
no-route = 161.192.0.0/255.224.0.0
no-route = 162.96.0.0/255.224.0.0
no-route = 163.0.0.0/255.192.0.0
no-route = 163.96.0.0/255.224.0.0
no-route = 163.128.0.0/255.192.0.0
no-route = 163.192.0.0/255.224.0.0
no-route = 166.96.0.0/255.224.0.0
no-route = 167.128.0.0/255.192.0.0
no-route = 168.160.0.0/255.224.0.0
no-route = 169.254.0.0/255.255.0.0
no-route = 171.0.0.0/255.128.0.0
no-route = 171.192.0.0/255.224.0.0
no-route = 172.16.0.0/255.240.0.0
no-route = 175.0.0.0/255.128.0.0
no-route = 175.128.0.0/255.192.0.0
no-route = 180.64.0.0/255.192.0.0
no-route = 180.128.0.0/255.128.0.0
no-route = 182.0.0.0/255.0.0.0
no-route = 183.0.0.0/255.192.0.0
no-route = 183.64.0.0/255.224.0.0
no-route = 183.128.0.0/255.128.0.0
no-route = 192.0.0.0/255.255.255.0
no-route = 192.0.2.0/255.255.255.0
no-route = 192.88.99.0/255.255.255.0
no-route = 192.96.0.0/255.224.0.0
no-route = 192.160.0.0/255.248.0.0
no-route = 192.168.0.0/255.255.0.0
no-route = 192.169.0.0/255.255.0.0
no-route = 192.170.0.0/255.254.0.0
no-route = 192.172.0.0/255.252.0.0
no-route = 192.176.0.0/255.240.0.0
no-route = 198.18.0.0/255.254.0.0
no-route = 198.51.100.0/255.255.255.0
no-route = 202.0.0.0/255.128.0.0
no-route = 202.128.0.0/255.192.0.0
no-route = 202.192.0.0/255.224.0.0
no-route = 203.0.0.0/255.128.0.0
no-route = 203.128.0.0/255.192.0.0
no-route = 203.192.0.0/255.224.0.0
no-route = 210.0.0.0/255.192.0.0
no-route = 210.64.0.0/255.224.0.0
no-route = 210.160.0.0/255.224.0.0
no-route = 210.192.0.0/255.224.0.0
no-route = 211.64.0.0/255.192.0.0
no-route = 211.128.0.0/255.192.0.0
no-route = 218.0.0.0/255.128.0.0
no-route = 218.160.0.0/255.224.0.0
no-route = 218.192.0.0/255.192.0.0
no-route = 219.64.0.0/255.224.0.0
no-route = 219.128.0.0/255.224.0.0
no-route = 219.192.0.0/255.192.0.0
no-route = 220.96.0.0/255.224.0.0
no-route = 220.128.0.0/255.128.0.0
no-route = 221.0.0.0/255.224.0.0
no-route = 221.96.0.0/255.224.0.0
no-route = 221.128.0.0/255.128.0.0
no-route = 222.0.0.0/255.0.0.0
no-route = 223.0.0.0/255.224.0.0
no-route = 223.64.0.0/255.192.0.0
no-route = 223.128.0.0/255.128.0.0
no-route = 224.0.0.0/224.0.0.0
不过,参考 OpenConnect server(ocserv) 一键脚本 for deibian 7 ,如果使用 openconnect 客户端,则所有版本都不支持 no-route ,可能需要使用cisco anyconnect客户端支持。所有如果使用 openconnect ,还是在客户端自己用脚本添加路由。
上述配置中,我更改了 192.168.0.0 ,因为我配置的ocserv使用了 192.168.101.0/255.255.255.0 作为 tun 网段,而我的局域网使用的是 192.168.1.0/24
192.168.0.0/255.255.255.0 ==> 192.168.1.0/255.255.255.0
此外,添加了一个VPN服务器的IP地址
Cisco AnyConnect for BlackBerry 不支持 no-route 指令,如果服务器端配置了no-route,会导致无法通讯(显示主机无法解析或者网络未连接),所以最后还是全部删除了no-route配置。不过Cisco AnyConnect for iOS没有问题,但不确定no-route是否真正生效。 反正手机主要是用于访问twiter,较少内网访问,所以暂时没有问题。Linux客户端采用罗有添加脚本。
有些IP段可能不是中国的,例如发现 m.voachinese.com 使用的akamai的CDN地址是日本的
m.voachinese.com. 1185 IN CNAME m.voanews.com.edgesuite.net.
m.voanews.com.edgesuite.net. 19185 IN CNAME a1250.b.akamai.net.
a1250.b.akamai.net. 30 IN A 124.40.42.57
a1250.b.akamai.net. 30 IN A 124.40.42.62
客户端添加路由脚本
默认的尚未连接VPN时候的路由表
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
default 10.33.33.250 0.0.0.0 UG 0 0 0 wlp3s0
10.33.32.0 0.0.0.0 255.255.254.0 U 0 0 0 wlp3s0
loopback 0.0.0.0 255.0.0.0 U 0 0 0 lo
连接VPN以后的路由表
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 0.0.0.0 0.0.0.0 U 0 0 0 tun0
0.0.0.0 10.33.33.250 0.0.0.0 UG 0 0 0 wlp3s0
10.33.32.0 0.0.0.0 255.255.254.0 U 0 0 0 wlp3s0
104.236.154.90 10.33.33.250 255.255.255.255 UGH 0 0 0 wlp3s0
127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo
192.168.101.0 0.0.0.0 255.255.255.0 U 0 0 0 tun0
参考上述ocserv服务器端设置 no-route ,在Linux主机上,采用脚本方式设置路由。思路是使用openconnect连接了VPN服务器之后,在本地终端执行脚本 vpn_route.sh start 设置路由(vpn_route.sh stop则去除路由)。注意,在 cn_route.cfg 中是需要路由的网段,类似格式如下
0.0.0.0/255.0.0.0
1.0.0.0/255.128.0.0
1.160.0.0/255.224.0.0
1.192.0.0/255.224.0.0
10.0.0.0/255.0.0.0
14.0.0.0/255.224.0.0
14.96.0.0/255.224.0.0
14.128.0.0/255.224.0.0
路由网段中去掉了
0.0.0.0/255.0.0.0
127.0.0.0/255.0.0.0
脚本 vpn_route.sh
#!/bin/bash
DEVICE=$(ip route list | grep "^default" | grep "metric 303" | awk '{print $5}')
GATEWAY=$(ip route list | grep "^default" | grep "metric 303" | awk '{print $3}')
ROUTELIST=cn_route.cfg
ROUTENUM=$(wc -l < $ROUTELIST)
addroute()
{
COUNT=0
while [ $COUNT -lt $ROUTENUM ]
do
let COUNT++
NET=`head -n $COUNT $ROUTELIST | tail -1`
ip route add $NET via $GATEWAY dev $DEVICE
done
}
delroute()
{
COUNT=0
while [ $COUNT -lt $ROUTENUM ]
do
let COUNT++
NET=`head -n $COUNT $ROUTELIST | tail -1`
ip route del $NET via $GATEWAY dev $DEVICE
done
}
case "$1" in
start)
addroute && exit 0
;;
stop)
delroute && exit 0
;;
*)
echo $"Usage: $0 {start|stop)"
RETVAL=2
esac
DNSMASQ
我设置了VPN服务器上的dnsmasq,想vpn连接以后,通过查询dns来解决内网和外网的dns解析(一些内网ip解析通过dnsmasq添加),但是发现,始终不能正常访问dns。在vpn服务器上是可以解析的,但是远程不行。我使用nc检查,端口是打开的
# nc -u -v -w 2 VPN_SERVER_IP 53
li421-128.members.linode.com [VPN_SERVER_IP] 53 (domain) open
但是查询超时
dig @VPN_SERVER_IP www.sina.com.cn
; <<>> DiG 9.10.2-P4 <<>> @VPN_SERVER_IP www.sina.com.cn
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached
但是在服务器上直接查询却完全正常
root@mynode:/etc# dig @VPN_SERVER_IP www.sina.com.cn
......
;; ANSWER SECTION:
www.sina.com.cn. 1728 IN CNAME jupiter.sina.com.cn.
jupiter.sina.com.cn. 2767 IN CNAME ara.sina.com.cn.
ara.sina.com.cn. 1 IN A 58.63.236.248
ara.sina.com.cn. 1 IN A 121.14.1.189
ara.sina.com.cn. 1 IN A 121.14.1.190
;; AUTHORITY SECTION:
sina.com.cn. 73563 IN NS ns4.sina.com.cn.
sina.com.cn. 73563 IN NS ns1.sina.com.cn.
sina.com.cn. 73563 IN NS ns3.sina.com.cn.
sina.com.cn. 73563 IN NS ns2.sina.com.cn.
......
开始我以为是vpn服务影响,所以特意关闭了VPN连接,并且从其他服务器上多次测试都没有成功。也验证了没有防火墙干扰。最后,偶然搜索到 dnsmasq: DNS request timed out for machines in local network ,原来必须显式地设置 listen-address 监听接口,DNSmasq才会对外部客户端请求响应,否则只有本机(估计DNSmasq代码中检查客户端IP来判断是否是本机IP进行过滤)才提供服务,虽然端口已经监听。
修改VPN服务器上 /etc/dnsmasq.conf 配置,添加
listen-address=192.168.101.1
listen-address=VPN_SERVER_IP
然后重启dnsmasq就可以正常解析。
为了安全起见,实际我是只监听tun接口提供服务,这样只有VPN客户端可以访问DNS。
参考
- Setup OpenConnect VPN Server for Cisco AnyConnect on Ubuntu 14.04 x64
- OpenConnect SERVER Setup Guide for Beginners - 在OpenWrt上部署OpenConnect服务
- ocserv安装文档
- 其他一些中文的设置参考文档