服务器
Arch Linux可以安装aur/strongswan
,Debian可以安装unstable仓库的strongswan
和libcharon-extra-plugins
。Ubuntu等发行版,软件仓库中strongswan较旧,建议编译安装最新版本。
在服务器上执行:
123456789101112131415161718192021 | # CA key & certificateipsec pki --gen > caKey.deripsec pki --self --in caKey.der --dn 'C=JP, O=mynet, CN=CA' --ca > caCert.deropenssl x509 -inform der -in caCert.der -out caCert.pem# server key & certificateipsec pki --gen > serverKey.deripsec pki --pub --in serverKey.der | ipsec pki --issue --cacert caCert.der --cakey caKey.der --dn 'C=JP, O=mynet, CN=your.ip' --san 'your.domain' > serverCert.deropenssl x509 -inform der -in serverCert.der -out serverCert.pemopenssl rsa -inform der -in serverKey.der -out serverKey.pem# 本文未用到(iOS 9公钥认证未试验成功,Linux strongSwan客户端公钥认证产生1580字节packet超过MTU,分片未试验成功)。若需生成client key & certificate#ipsec pki --gen > clientKey.der#ipsec pki --pub --in clientKey.der | ipsec pki --issue --cacert caCert.der --cakey caKey.der --dn "C=JP, O=azurejp, CN=client" --san 'client@your.domain' > clientCert.der#openssl x509 -inform der -in clientCert.der -out clientCert.pem#openssl rsa -inform der -in clientKey.der -out clientKey.pemmkdir -p /etc/ipsec.d/{certs,cacerts,private}cp caCert.pem /etc/ipsec.d/cacerts/cp serverCert.pem /etc/ipsec.d/certs/cp serverKey.pem /etc/ipsec.d/private/ |
编辑/etc/ipsec.conf
:
1234567891011121314151617181920212223242526272829303132 | config setupuniqueids = neverconn ikev2ioskeyexchange = ikev2ike = aes256-sha256-modp1024,3des-sha1-modp1024,aes256-sha1-modp1024! # for iOS 9esp = aes256-sha256,3des-sha1,aes256-sha1! # for iOS 9left = %anyleftid = your.domain # iOS 9似乎要求此处为域名或IPleftsendcert = always # iOS 9会验证证书leftcert = serverCert.pemleftsubnet = 0.0.0.0/0 # 给iOS 9推送的路由right = %anyrightauth = eap-mschapv2rightsourceip = 10.99.1.0/24eap_identity = %anyauto = addfragmentation = yesconn ikev1androidkeyexchange = ikev1left = %anyleftid = your.ipleftsendcert = alwaysleftcert = serverCert.pemleftsubnet = 0.0.0.0/0right = %anyrightauth = xauthrightsourceip = 10.99.1.0/24auto = add |
注意修改your.ip
和your.domain
。
iOS 9内置的IKEv2 VPN客户端会验证服务端证书是否为本地某信任CA签署的,且“远程ID”匹配证书的CN(生成serverCert.der
时的--dn
选项中)或subject alternative name (生成serverCert.der
时的--san
选项)。CN、subject alternative name可以填域名或IP地址,域名可以乱写,不会检查域名是否和服务器IP对应。填写服务器的域名或IP地址可行,其他可能项如邮箱地址等不知是否可行。
编辑/etc/ipsec.secrets
:
123 | : RSA serverKey.pemclient : EAP "your.password" # iOS及Linux的EAP-MSCHAPv2client : XAUTH "your.password" # Android IPSec hybrid RSA |
注意修改用于EAP-MSCHAPv2的密码your.password
。
服务器需要允许外界访问500/udp和4500/udp。客户端连接后,可以把服务端作为路由的下一跳,服务端需要配置转发:
12 | sysctl -w net.ipv4.ip_forward=1iptables -t nat -A POSTROUTING -s 10.99.1.0/24 -j MASQUERADE |
某些使用环境可能会设定默认DROP、禁止FORWARD等,需要更复杂的配置,此处不赘述。
若要推送nameserver给客户端,可以编辑/etc/strongswan.conf
:
123456789101112 | charon {load_modular = yesduplicheck.enable = nocompress = yesdns1 = your.dns1dns2 = your.dns2plugins {include strongswan.d/charon/*.conf}} |
ipsec start
启动服务端守护进程,如果使用systemd的话,可能是systecmtl start strongswan
之类。
Linux strongSwan客户端
把caCert.pem
复制到本地,cp caCert.pem /etc/ipsec.d/cacerts/
。
编辑/etc/ipsec.conf
,设定名为myikev2
的连接:
123456789101112131415 | config setupniqueids = neverconn myikev2keyexchange = ikev2right = your.iprightca = caCert.pemrightid = your.domainrightsubnet = 0.0.0.0/0left = %anyleftsourceip = %configleftauth = eap-mschapv2eap_identity = clientauto = start |
注意修改your.domain
。
编辑/etc/ipsec.secrets
,需要服务端中指定的EAP密码:
1 | client : EAP "your.password" |
rightsubnet
会影响到myikev2
连接建立后的新建的路由。ip ru
可以看到多了一个ID为220的路由表,若把rightsubnet
改为8.0.0.0/8
,会看到ip r s t 220
输出:
12 | # 我本地无线网接口wlp3s0 IP 192.168.0.3,网关为192.168.0.1。wlp3s0上多出了一个10.99.1.1/32的由服务端推送的[virtual IP8.0.0.0/8 via 192.168.0.1 dev wlp3s0 table 220 proto static src 10.99.1.1 |
若要测试是否可以把服务端作为网关,可以用如下命令:
12345 | # 添加ip r a 180.149.132.47 dev enp4s0f2 src 10.99.1.1ping 180.149.132.47# 删除ip r d 180.149.132.47 dev enp4s0f2 src 10.99.1.1 |
Virtual IP。待补充。
iOS 9内置IKEv2客户端
在iOS 9中打开caCert.pem
,会提示导入“描述文件”,之后可以在“设置->通用->描述文件”看到该证书。
iOS 9中亦可导入用于客户端认证的私钥及证书,但必须是PKCS12格式,且有四位passphrase,可以用如下命令创建:
1 | openssl pkcs12 -export -inkey clientKey.pem -in clientCert.pem -name 'client' -certfile caCert.pem -caname 'CA' -passout 'pass:1234' -out client.p12 |
尚未弄明如何使用iOS 9内置客户端的公钥认证,但可以使用EAP-MSCHAPv2方式认证。“设置->通用->VPN->添加VPN配置”,填写如下字段:
类型:
IKEv2
服务器:
your.ip
远程ID:服务端
/etc/ipsec.conf
中指定的leftid
用户鉴定:
用户名
用户名:
client
(服务端/etc/ipsec.secrets
中配置了名为client
的EAP identity)密码:
your.password
iOS调试还是挺麻烦的,VPN连接失败什么错误消息都没有,只能看服务端的日志……对iOS认识太少。
Android
类型:IPSec Hybrid RSA
服务器地址:
your.ip
IPSec CA证书:
caCert.pem
IPSec服务器证书:
serverCert.pem
。“设置->安全->从存储设备安装”中可以安装。
测试时,“IPSec CA证书”、“IPSec服务器证书”可留空。长按新建的VPN条目可以修改配置。
较新的strongSwan似乎关闭Aggressive Mode PSK,默认无法使用IPSec Xauth PSK:
1 | Aggressive Mode PSK disabled for security reasons. |
调试
journal -fb _SYSTEM_UNIT=strongswan.service
看服务端日志,或者用ipsec start --nofork
在前台开启。客户端修改后ipsec restart
看日志,某些改动可以使用ipsec reload
、ipsec rereadsecrets
等。
常见错误
服务端找不到匹配的conn
配置:
12 | looking for peer configs matching 10.0.0.4[server]...1.2.3.4[client] # 未仔细研究,似乎对应配置文件中的:left[leftid]...right[rightid]no matching peer config found |
服务端strongswan不支持特定认证方式
journalctl -fb
后重启ipsec服务,看到如下字样:
12 | 14[IKE] EAP-Identity request configured, but not supported14[IKE] loading EAP_MSCHAPV2 method failed |
服务端未推送nameserver给客户端
Android、iOS难以看到IPSec客户端错误信息,可以尝试用IP访问网页。
Path MTU discovery
假设服务器上外网接口为eth0
,根据该接口的MTU与网站协商了一个MSS,但该MSS加上IP header很可能会大于IPSec客户端到服务器的MTU。服务器向网站发送ICMP Unreachable,但网站很可能屏蔽了该消息。
在服务器上使用命令tcpdump -ni eth0 'port 80 and tcp[13] & 2 == 2'
观察80/tcp带有SYN的TCP packets发现协商的MSS。tcpdump -ni eth0 'net 180.97.33.0/24'
发现网站发送的TCP packet与服务器发送的不被理会的ICMP Unreachable。
123456789101112 | 12:31:51.778576 IP (tos 0x0, ttl 44, id 42813, offset 0, flags [DF], proto TCP (6), length 1480)180.97.33.107.80 > 10.0.0.4.49016: Flags [.], cksum 0xba48 (correct), seq 1026:2466, ack 78, win 193, length 144012:31:51.778633 IP (tos 0xc0, ttl 64, id 59986, offset 0, flags [none], proto ICMP (1), length 576)10.0.0.4 > 180.97.33.107: ICMP 10.0.0.4 unreachable - need to frag (mtu 1438), length 556IP (tos 0x0, ttl 43, id 42813, offset 0, flags [DF], proto TCP (6), length 1480)180.97.33.107.80 > 10.0.0.4.49016: Flags [.], seq 1026:2466, ack 78, win 193, length 144012:31:52.194666 IP (tos 0x0, ttl 44, id 42814, offset 0, flags [DF], proto TCP (6), length 1480)180.97.33.107.80 > 10.0.0.4.49016: Flags [.], cksum 0xba48 (correct), seq 1026:2466, ack 78, win 193, length 144012:31:52.194740 IP (tos 0xc0, ttl 64, id 59995, offset 0, flags [none], proto ICMP (1), length 576)10.0.0.4 > 180.97.33.107: ICMP 10.0.0.4 unreachable - need to frag (mtu 1438), length 556IP (tos 0x0, ttl 43, id 42814, offset 0, flags [DF], proto TCP (6), length 1480)180.97.33.107.80 > 10.0.0.4.49016: Flags [.], seq 1026:2466, ack 78, win 193, length 1440 |
iOS客户端初始协商的MSS为1360,一般不会出问题。Linux strongswan客户端/Android客户端初始协商的MSS可能和MTU有关,对于MTU 1500,协商了MSS 1460,无法访问网页。解决办法是调低服务器向IPSec客户端通报的MSS:
1 | iptables -t mangle -A FORWARD -s 10.99.1.0/24 -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360 |