新鲜出炉一份完整AnyConnect教程!

一周年零一个月更新:

因为StartCom全家爆炸所以删除了相关的证书内容。

经过测试以后更改了Let’s Encrypt签发证书的内容。

新增了未打开IPv4转发(表现:可以连上服务器但是不能打开网页)的解决方法。

给你们找了一个你们喜欢的一键脚本

GitHub有一个项目叫Streisand,要是搞不明白的可以尝试一下。自己没测试过。请注意如果直接编译按照步骤走的话这个程序似乎是会帮你开新服务器的,我建议参考README.md#running-streisand-on-other-providers来做。

说实话吧,其实我搞AnyConnect搞了好几天,一直碰到一个很鬼畜的Google不到的

getaddrinfo() failed: Name or service not known
Cannot listen to specified ports

这个报错…吓得我iptables rule重写了好几遍w

后面再提啦。先走主线。

1. AnyConnect概述

简而言之,AnyConnect是Cisco的新一代黑科技。鬼畜的协议可以让它在UDP/TCP之间切换,从而增强稳定性;(和其他VPN相比略微)复杂的部署让非企业用户使用AnyConnect的概率大大降低,基本上只剩下企业用户(这才是关键)。企业用户是什么,是GDP啊(笑)。

更何况今年某大新闻过后,坚挺许久的IPSec和他的小伙伴(PPTP和L2TP)一起见了马克思。

加上AnyConnect提供了独特的证书验证功能(这倒是次要的…反正自签名的证书都会报错根本防不了MITM),所以还是值得各位从各种IPSec啦PPTP啦L2TP啦跑过来的。

2.安装环境准备

一贯的,我用的是Debian Jessie,KVM架构。OpenVZ的话…应该也是可以的吧。

2.1 安装依赖包

AnyConnect要很多依赖包(喂别跑啊!还没到编译的部分呢)。这些东西可以在后面的README里面找到。Debian和Fedora有所不同,因为我用Debian,所以Fedora的各位就自己去readme里找咯…

apt-get install libgnutls28-dev libwrap0-dev libpam0g-dev liblz4-dev libseccomp-dev libreadline-dev libnl-route-3-dev libkrb5-dev build-essential pkg-config gnutls-bin -y

 

development package理论上是用不着的。

2.2 编译ocserv

ocserv就是我们需要的东西了。什么?OpenConnect和AnyConnect不一样?…别急啊。

但是由于官方没有最新版本的固定链接,所以我们得去他们的网站自己扒…看不懂没关系,第一个链接就是了。下载命令格式是:

curl -O 下载链接

下载下来以后解压,进入文件夹:

tar xvf ocserv*.tar.xz
./configure
make
make install

2.3 创建证书

AnyConnect需要一个证书来建立安全连接。理论上倒是可以用Let’s Encrypt来给服务器签发证书,但是!LE并不支持针对IP地址签发。如果你在域名中填了IP地址的话就会出现以下错误:

 

Requested name *.*.*.* is an IP address. The Let’s Encrypt certificate authority will not issue certificates for a bare IP address.

请求的域名*.*.*.*是一个IP地址。Let’s Encrypt证书签发机构将不会对IP地址签发证书。

 

所以要是你不想买域名的话,还是乖乖用自签名证书吧。反正只要后面把自签名的证书从服务器上导入到本地也是一样的效果。

2.3.1 创建证书模板

首先我们得新建一个文件夹,把东西到处乱丢可不是什么好习惯…

mkdir cert
cd cert
touch ca.tmpl
nano ca.tmpl

文本编辑器我用的是nano,各位要是不爽的话也可以用vi,这就不是重点了。总之复制上:

cn = "随便填,你开心就好"
organization = "同开心就好"
serial = 1
expiration_days = 365
ca
signing_key
cert_signing_key
crl_signing_key

保存退出。

生成密钥和证书。

certtool --generate-privkey --outfile ca-key.pem
certtool --generate-self-signed --load-privkey ca-key.pem --template ca.tmpl --outfile ca-cert.pem

警告:任何东西都不能丢!任何东西都不能丢!任何东西都不能丢!重要的话说三遍

2.3.2 创建服务器证书

cn = "这里必须填域名或IP"
organization = "同开心就好"
expiration_days = 365
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
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

然后我们把证书放到一个你喜欢的文件夹,我们假设是/etc/ssl/selfsigned。存放路径可以自己改。

cp ca-cert.pem /etc/ssl/selfsigned/ca-cert.pem
cp server-cert.pem /etc/ssl/selfsigned/server-cert.pem
cp server-key.pem /etc/ssl/selfsigned/server-key.pem

 

3.配置ocserv

我们在ocserv-x.x.x下操作

把配置样本复制到/etc/ocserv中进行修改:

mkdir ocserv
cp doc/sample.config /etc/ocserv/ocserv.conf
nano /etc/ocserv/ocserv.conf

 

然后添加一个用户名和密码:

ocpasswd -c /etc/ocserv/ocpasswd 你喜欢的用户名

接着会让你添加密码,输两遍(一遍用来验证)就行了

找到以下几行(友情提示:nano使用Ctrl+w可以进行搜索)并按照#后面的提示改动(如果你不知道怎么改就不要动了)

# 选择喜欢的登录方式,如果想使用证书登录的话应该把auth="certificate"前的井号删掉并在下面这行的前面加上井号。第5点会提到
auth = "plain[/etc/ocserv/ocpasswd]"

# 允许同时连接的总客户端数量,比如下面的4就是最多只能4台设备同时使用
max-clients = 4

#不同用户用同一个用户名可以同时登录,下面限制的是多少同名用户可以同时使用。改成0就是不作限制
max-same-clients = 2

# ocserv监听的IP地址,千万别动动了就爆炸
#listen-host = [IP|HOSTNAME]

# 服务监听的TCP/UDP端口,如果没有搭网站的话就用TCP443/UDP80好了
tcp-port = 443
udp-port = 80

# 开启以后可以增强VPN性能
try-mtu-discovery = true

# 让服务器读取用户证书(后面会用到用户证书)
cert-user-oid = 2.5.4.3

# 服务器证书与密钥
server-cert = /etc/ssl/selfsigned/server-cert.pem
server-key = /etc/ssl/selfsigned/server-key.pem

# 服务器所使用的dns,我们使用Google提供的DNS
dns = 8.8.8.8
dns = 8.8.4.4

#把route = *全注释掉就是了
#route = 192.168.1.0/255.255.255.0

# 使ocserv兼容AnyConnect
cisco-client-compat = true

 

# 选择喜欢的登录方式,如果想使用证书登录的话应该把auth="certificate"前的井号删掉并在下面这行的前面加上井号。第5点会提到
auth = "plain[/etc/ocserv/ocpasswd]"

# 允许同时连接的总客户端数量,比如下面的4就是最多只能4台设备同时使用
max-clients = 4

#不同用户用同一个用户名可以同时登录,下面限制的是多少同名用户可以同时使用。改成0就是不作限制
max-same-clients = 2

# ocserv监听的IP地址,千万别动动了就爆炸
#listen-host = [IP|HOSTNAME]

# 服务监听的TCP/UDP端口,如果没有搭网站的话就用TCP443/UDP80好了
tcp-port = 443
udp-port = 80

# 开启以后可以增强VPN性能
try-mtu-discovery = true

# 让服务器读取用户证书(后面会用到用户证书)
cert-user-oid = 2.5.4.3

# 服务器证书与密钥
server-cert = /etc/ssl/selfsigned/server-cert.pem
server-key = /etc/ssl/selfsigned/server-key.pem

# 服务器所使用的dns,我们使用Google提供的DNS
dns = 8.8.8.8
dns = 8.8.4.4

#把route = *全注释掉就是了
#route = 192.168.1.0/255.255.255.0

# 使ocserv兼容AnyConnect
cisco-client-compat = true

Ctrl+x保存退出。

好了我们来聊聊开头提到的 getaddrinfo() failed。其实只要把listen-host那一行用#注释掉保存就可以了。然后ocserv就会自己进行扫描,多棒啊(

4.扫尾工作

4.1 防火墙设置

有些骚年的端口可能被iptables挡住了,现在我们就在iptables上开个洞:

iptables -A INPUT -p tcp -m state --state NEW --dport 443 -j ACCEPT
iptables -A INPUT -p udp -m state --state NEW --dport 80 -j ACCEPT

 

然后再开个NAT:

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

顺便说一下有人问“能够正常连接但是上不了网”是什么情况,原因很可能是因为没有开启IPv4转发。IPv4转发的相关参数在/etc/sysctl.conf中,进入后找到net.ipv4.ip_forward=1并把前面的注释(“#”)删掉并保存(保存文件并且sysctl -p)即可。或者也可以使用echo来在文件尾添加上这一参数:

echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p

 

哦对了。看到analytics说有一个“anyconnet不能改端口”的搜索跳转,这里就补充一下:其实把tcp-port和udp-port改掉就好了…

4.2 测试

洋洋洒洒写了这么多终于写到了测试,真是泪流满面…

ocserv -f -d 1

要是没有报错退出的话,那就可以用了。然而,只是可以用而已。

5.可选操作——添加守护进程(Debian)或使用证书认证

5.1 添加守护进程

添加守护进程这个是Debian多出来的一步。在CentOS下直接yum install ocserv然后就可以用service ocserv start或者service ocserv stop了。所以其实我新开了一台CentOS服务器,下面的内容是我从其他地方复制的

cd /etc/init.d

sudo ln -s /lib/init/upstart-job ocserv

cd /etc/init

sudo nano ocserv.conf

 

在新文件中加入以下几行:

#!upstart
description "OpenConnect Server"

start on runlevel [2345]
stop on runlevel [06]

respawn
respawn limit 20 5

script
exec start-stop-daemon --start --pidfile /var/run/ocserv.pid --exec /usr/local/sbin/ocserv -- -f >> /dev/null 2>&1
end script

 

然后Debian党也可以使用service ocserv start/stop了。

 

补充:CentOS上systemctl start ocserv.service后可能会返回

Job for ocserv.service failed because the control process exited with error code. See “systemctl status ocserv.service” and “journalctl -xe” for details.

这时候敲systemctl status ocserv.service查看上一次的运行过程中发生了什么。一般来说这个日志中会显示配置错误(Syntax error,配置文件中的参数错误,一般会显示执行到第几行)或者是地址已经被使用[bind() failed: Address already in use]。对于第一种情况请检查相关配置文件,对于第二种情况可以lsof -i:ocserv使用的端口 查看端口调用情况。如果看到ocserv-ma则表示已经有一个ocserv服务在运行中,如果没有的话就需要调整到空端口或者手动杀掉占用此端口的进程然后重新启动ocserv。

 

5.2 客户端使用证书登录

既然服务器需要提供证书来验证身份,那么客户端也可以提供身份证书进行登录。那么,我们开始咯我开始感到不耐烦了你们看出来了吗

现在证书推荐使用let’s encrypt生成,具体的方法各位可以参照这一篇文章用户使用自签名证书作为身份验证凭据的话会因为issuer unknown被拒绝(使用ocserv -f -d 1可以看到debug信息),所以自签名的用户证书是没有用的各位不要再折腾了。

首先我们要回到之前我们创建证书的地方(参见2.3.1),因为路径是阁下选的这里就给不出命令了明明就是偷懒

touch user-cert.tmpl
nano user-cert.tmpl

 

cn = "随便填"
unit = "也是随便填"
expiration_days = 365
signing_key
tls_www_client

 

生成密钥

certtool --generate-privkey --outfile user-key.pem

 

生成证书

certtool --generate-certificate --load-privkey user-key.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --template user-cert.tmpl --outfile user-cert.pem

 

这里多一步格式转换:

certtool --to-p12 --load-privkey user-key.pem --pkcs-cipher 3des-pkcs12 --load-certificate user-cert.pem --outfile user.p12 --outder

然后各位可以把证书弄到自己设备上。怎么弄呢?可以用SFTP/FTP(如:filezilla),也可以直接用Apache/Nginx,本来文章就够长了就不增加各位心理负担了(笑

最后回去编辑/etc/ocserv/ocserv.conf,把auth = “plain[/etc/ocserv/ocpasswd]”用 # 注释掉,把auth = “certificate” 的注释删除,注释掉 listen-clear-file = /var/run/ocserv-conn.socket,把ca-cert = 改成下面的 ca-cert = /etc/ssl/selfsigned/ca-cert.pem ,重启服务,大功告成!