strongswan(for android)服务器的搭建
前几天尝试了一下 VPS上基于Debian搭建和配置L2TP/IPsec VPN,但发现这个用openSwan + xl2tp实现的L2TP over IPsec对iOS自带VPN客户端的兼容性不好,为此改用strongSwan来配置pure
IPsec,同时发现该软件还支持win7自带的VPN客户端,以及Android第三方的strongSwan VPN client(ICS 4.0之后的系统才能用)。
strongSwan默认同时开启了pluto(支持IKEv1)和charon(IKEv2)的daemon,前者可兼容iOS的自带VPN客户端;而后者可兼容win7自带的VPN客户端,以及Android第三方的strongSwan VPN客户端,这样就可实现对多平台VPN客户端的支持。
仍旧用Xen,还是Debian 6.0 Squeeze的操作系统,先更新一下源,然后安装编译环境
apt-get update
apt-get install build-essential #编译环境
aptitude install libgmp3-dev libssl-dev pkg-config libpcsclite-dev libpam0g-dev #编译所需要的软件
本着求稳不求新的原则,下载strongSwan 4.x的最后一版v4.6.4并解压
cd /usr/src
wget http://download.strongswan.org/strongswan-4.6.4.tar.gz
tar zxvf strongswan-4.6.4.tar.gz
cd strongswan-4.6.4
接下来配置编译参数,按理应该不用指定那么多参数,但我为保险起见还是把和EAP相关的参数全部都指定了,有兴趣的可以试试哪些参数可以省去(详细的配置参数说明请见 官网)
./configure --prefix=/usr --sysconfdir=/etc --enable-cisco-quirks --enable-openssl --enable-nat-transport --disable-mysql --disable-ldap --disable-static --enable-shared --enable-md4 --enable-eap-mschapv2 --enable-eap-aka --enable-eap-aka-3gpp2 --enable-eap-gtc --enable-eap-identity --enable-eap-md5 --enable-eap-peap --enable-eap-radius --enable-eap-sim --enable-eap-sim-file --enable-eap-sim-pcsc --enable-eap-simaka-pseudonym --enable-eap-simaka-reauth --enable-eap-simaka-sql --enable-eap-tls --enable-eap-tnc --enable-eap-ttls
然后是编译和安装
make
make install
strongSwan安装完成后,需要对 /etc/ipsec.conf 进行修改,我的配置如下
config setup
charonstart=yes
plutostart=yes #其实pluto和charon默认yes,不过保险起见我还是再设置一下
nat_traversal=yes
uniqueids=yes
conn ios
keyexchange=ikev1
authby=xauthpsk
xauth=server
left=%defaultroute
leftsubnet=0.0.0.0/0
leftfirewall=yes
right=%any
rightsubnet=10.11.0.0/24
rightsourceip=10.11.0.0/24
pfs=no
auto=add
conn win7 #win7和android的配置一样
keyexchange=ikev2
ike=aes256-sha1-modp1024!
esp=aes256-sha1!
dpdaction=clear
dpddelay=300s
rekey=no
left=%defaultroute
leftsubnet=0.0.0.0/0
leftauth=pubkey
leftcert=serverCert.pem
leftid="C=CH, O=strongSwan, CN=VPS的公网ip"
right=%any
rightsourceip=10.11.1.0/24
rightauth=eap-mschapv2
rightsendcert=never
eap_identity=%any
auto=add
按照以往的经验,配置文件末尾需要多一个换行,否则启动ipsec时会提示
Starting strongSwan 4.6.4 IPsec [starter]…
(null):0: syntax error, unexpected $end, expecting EOL []
unable to start strongSwan — fatal errors in config
另外,配置文件中不能把某行简单地注释掉,比如注释 “aaaaaa#keyexchange=ikev2” 可以,但 “#aaaaaakeyexchange=ikev2”
或 “aaa#aaakeyexchange=ikev2” 的话,启动ipsec时就会提示出错
Starting strongSwan 4.6.4 IPsec [starter]…
/etc/ipsec.conf:8: syntax error, unexpected FIRST_SPACES [ ]
unable to start strongSwan — fatal errors in config
感觉strongSwan的这种小bug跟openswan一样,难道是它们都源自freeswan的关系?
还需要修改 /etc/strongswan.conf 文件,在charon项和pluto项里添加dns
# strongswan.conf - strongSwan configuration file
charon {
dns1 = 8.8.8.8
dns2 = 208.67.222.222
...
pluto {
dns1 = 8.8.8.8
dns2 = 208.67.222.222
...
修改 /etc/ipsec.secrets 文件,添加帐号,走IKEv1协议的设备用PSK认证方式,IKEv2用RSA方式
# this file is managed with debconf and will contain the automatically created private key
: PSK "自定义PSK密钥"
用户名1 : XAUTH "密码1"
: RSA serverKey.pem
用户名2 : EAP "密码2"
#include /var/lib/strongswan/ipsec.secrets.inc
注:对于走IKEv2的客户端如win7来说,我试了一下EAP或XAUTH格式的帐号都能用,而IKEv1的只能用XAUTH格式的,似乎是IKEv2向下兼容的缘故。
添加iptables命令,修改ip_forward以实现NAT,然后重启ipsec
iptables -A INPUT -p udp --dport 500 -j ACCEPT
iptables -A INPUT -p udp --dport 4500 -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.11.0.0/24 -o eth0 -j MASQUERADE
iptables -A FORWARD -s 10.11.0.0/24 -j ACCEPT
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s 10.11.1.0/24 -o eth0 -j MASQUERADE #win7和android vpn客户端用
iptables -A FORWARD -s 10.11.1.0/24 -j ACCEPT #win7和android vpn客户端用
ipsec restart
注:为避免VPS重启后NAT功能失效,可以把如上8行命令添加到 /etc/rc.local 文件中,添加在exit那一行之前即可。
现在iOS设备就可以在自带的VPN客户端中的cisco ipsec界面,填入VPS的公网ip,以及在/etc/ipsec.secrets 文件中预设的 用户名1、密码1和自定义PSK密钥 ,保存后连接,就可以连上VPN服务器了。
如有出错,请检查 /var/log/auth.log 文件看看有什么出错提示。
win7和Android等平台的VPN客户端走ikev2协议,需要制作相应的证书,先生成ca证书
ipsec pki --gen --outform pem > caKey.pem
ipsec pki --self --in caKey.pem --dn "C=CH, O=strongSwan, CN=strongSwan CA" --ca --outform pem > caCert.pem
然后是服务器端的证书
ipsec pki --gen --outform pem > serverKey.pem
ipsec pki --pub --in serverKey.pem | ipsec pki --issue --cacert caCert.pem --cakey caKey.pem --dn "C=CH, O=strongSwan, CN=VPS的公网ip或域名" --san="VPS的公网ip或域名" --flag serverAuth --flag ikeIntermediate --outform pem > serverCert.pem
注:对于IKEv2,如将来vpn客户端登录的是ip或域名,这里的CN项也必须对应ip或域名,IKEv1则不受此限制。使用域名比较方便,但有的移动运营商劫持了DNS可能导致vpn客户端无法访问域名,这样的话就只能是ip地址了。
客户端的证书
ipsec pki --gen --outform pem > clientKey.pem
ipsec pki --pub --in clientKey.pem | ipsec pki --issue --cacert caCert.pem --cakey caKey.pem --dn "C=CH, O=strongSwan, CN=client" --outform pem > clientCert.pem
生成的客户端证书 clientCert.pem 不能直接导入到win7或Anroid设备中,需先转换为.p12格式。执行后会提示要设置证书使用密码,可以设置一下密码也可以直接回车(密码为空)。
openssl pkcs12 -export -inkey clientKey.pem -in clientCert.pem -name "client" -certfile caCert.pem -caname "strongSwan CA" -out clientCert.p12
如有更多的vpn客户端需要证书,则建议制作不同的客户端证书
ipsec pki --gen --outform pem > client2Key.pem
ipsec pki --pub --in client2Key.pem | ipsec pki --issue --cacert caCert.pem --cakey caKey.pem --dn "C=CH, O=strongSwan, CN=client" --outform pem > client2Cert.pem
openssl pkcs12 -export -inkey client2Key.pem -in client2Cert.pem -name "client" -certfile caCert.pem -caname "strongSwan CA" -out client2Cert.p12
这样,万一某个客户端的证书泄漏,只需在服务器端注销对应该客户端的证书即可,不影响其他vpn客户端的使用。
把证书复制到对应的目录中去
cp caCert.pem /etc/ipsec.d/cacerts/
cp serverCert.pem /etc/ipsec.d/certs/
cp serverKey.pem /etc/ipsec.d/private/
接下来进行在vpn客户端导入证书文件 clientCert.p12 的步骤,Android的导入比较简单,先把证书文件放到sdcard根目录,然后在 设置 > 安全 > 从存储设备安装证书 即可,按提示输入前面设置的证书使用密码。设备重启后证书生效,然后到google play里下载安装strongswan vpn client这个软件,在其中设置 用户名2、密码2,以及ikeav2的协议,就可以登录vpn服务器了。
而在win7端导入则稍麻烦些,可以按照网上的教程导入(无需重启,证书导入后即可生效),然后在win7自带的vpn客户端中设置一下,比如下面的链接。
http://www.vpncup.com/config/windows7-ikev2
至此多平台的vpn客户端基本就实现了,据说还支持黑莓自带的vpn客户端,手上没有黑莓手机所以就没测试。
补充1:
按如上的ipsec.conf配置后,启动ipsec时会在/var/log/auth.log文件里生成如下记录
Dec 12 02:29:00 (none) pluto[4565]: “/etc/ipsec.secrets” line 18: unrecognized key format: EAP
Dec 12 02:29:00 (none) pluto[4565]: added connection description “ios”
但却不影响使用,不知道到底是bug还是配置有问题。
补充2:
为方便VPN客户端的证书制作,可自制一个脚本,比如取名 /root/cc.sh ,内容如下,供参考
#!/bin/bash
read -p "Please input username:" user
if [ "$user" = "" ]; then
echo "Error! - you must input an username"
echo "Exit!"
exit 1
fi
echo "==========================="
echo "Making ${user}Key.pem ..."
ipsec pki --gen --outform pem > ${user}Key.pem
echo "Making ${user}Cert.pem ..."
ipsec pki --pub --in ${user}Key.pem | ipsec pki --issue --cacert caCert.pem --cakey caKey.pem --dn "C=CH, O=strongSwan, CN=client" --outform pem > ${user}Cert.pem
echo "Making ${user}Cert.p12 ..."
openssl pkcs12 -export -inkey ${user}Key.pem -in ${user}Cert.pem -name "client" -certfile caCert.pem -caname "strongSwan CA" -out ${user}Cert.p12
echo "========== done =========="
修改脚本权限并执行
cd /root
chmod 755 cc.sh #修改权限
./cc.sh #执行并按提示操作
补充3:
经过一段时间的使用,发现这类IPsec VPN软件的稳定性比OpenVPN这样的SSL VPN要稍差些,主要表现在有时客户端断开后(尤其是进入sleep状态时)VPN服务器端未能收到断开信号,以致该客户端短时间内再次连接VPN服务器时可能就会被拒绝,这时要么重启VPN服务器,或者等上一段时间再访问(一般情形下VPN服务器端过一段时间,比如最多2分钟,就会自动恢复正常)。
为尽可能确保VPN服务器端处于正常状态,我还是做了一个定时任务,比如每天临晨4:00让VPN服务器端重启一下。
crontab -e #进入定时任务编辑状态
在其中添加如下的一条定时任务,并保存退出。
00 20 * * * /usr/sbin/ipsec restart
注:Debian的定时任务似乎默认按UTC时间来执行的(尽管系统的时区我已设置UTC+8),所以这里是20:00以确保实际在临晨4:00执行。
修改完成后,需要重启一下定时任务的程序。
/etc/init.d/cron restart
2013.01.14 更新:
整理了一份 各平台VPN客户端的使用教程
其中提到的WinXP平台Cisco VPN Client客户端,相关的设置请见 这里
另外,建议把所有的证书文件,包括ca证书、服务器端和客户端的证书,通过Winscp备份到本地电脑硬盘上,这样万一将来VPS因故障需要重装系统时,无需重新制作各个客户端证书并一一通知对方更新了。
2013.02.23 更新
刚发现手上的Nexus 4手机(4.2.2)其自带的VPN客户端已支持pure IPsec,选择IPSec Xauth PSK方式,填写服务器地址和PSK密码后保存,登录时填入用户名、密码即可(仅第一次登陆时需要),无需证书。
上网搜了一下,似乎从4.1 (Jelly Bean) 开始android自带的vpn客户端就已支持pure IPsec了,不过之前没留意过。顺便提一下,第一次配置VPN帐号时Android系统会提示设置一个新的锁屏安全密码,按提示设置即可。
另外,跟iOS自带的vpn客户端一样都属于IKEv1方式(顺便提一下,strongSwan仅支持IKEv1的main mode,但不支持aggressive mode,所以不兼容客户端vpnc),跟IKEv2相比,前者无需证书使用方便但安全性稍差,且在断网恢复或更换网络后无法像后者那样能自动再连上,感觉还是IKEv2更适合手机等移动终端设备。