使用 Strongswan 架设 Ipsec VPN
目录
什么是 IPsec?
IPsec 是 虚拟私密网络(VPN) 的一种,用于在服务器和客户端之间建立加密隧道并传输敏感数据之用。它由两个阶段组成,第一阶段(Phrase 1, ph1),交换金钥建立连接,使用互联网金钥交换(ike)协议; 第二阶段(Phrase 2, ph2),连接建立后对数据进行加密传输,使用封装安全载荷(esp)协议。参考:维基百科 IPsec 词条。
其中,第一阶段和第二阶段可以使用不同的加密方法(cipher suites)。甚至,第一阶段 ike 协议的第一版(ikev1)有两种模式,主力模式(main mode)和积极模式(aggressive mode),主力模式进行六次加密握手,而积极模式并不加密,以实现快速建立连接的目的。
第一阶段的 ike 协议有两个版本(ikev1/ikev2),不同的开源/闭源软件实现的版本均不同,不同的设备实现的版本也不同。再联系到第一阶段/第二阶段使用的各种不同加密方法,使得 IPsec 的配置有点黑魔法的性质,要么完全懂,通吃; 要么完全不懂,照抄。
设备/操作系统规格
这里主要介绍了设备/操作系统使用的 ike 版本及其特殊要求。
Linux
命令行客户端就是 strongswan 本身,因此完美兼容,支持 ikev1/ikev2 和所有加密方法的连接。因此如果用户只使用 Linux 命令行客户端,不使用各种移动设备也不使用 Windows,那么完全没有那么多事。
但 Linux 的图形界面客户端 NetworkManager-strongswan 目前只支持 ikev2 连接,必须使用证书或 EAP (各种加密方法都支持,包括微软的 MSCHAPv2)进行认证,不支持纯密码(PSK)认证。这并不是 strongswan 的错误,或者技术不行(开源总是走在技术最前沿的,毕竟命令行是支持的),而仅仅是体现一种选择:ikev1 被 strongswan 项目认为是该淘汰的协议,而 PSK 加密被认为是非常不安全的。参考 strongswan 维基 NetworkManager 词条。
Android
Android 和 Linux 不一样,只支持 ikev1。其它方面和 Linux 一样,甚至有好多种 IPsec VPN 配置模式可供选择。
iOS/Mac OS X
它们声明使用的 IPsec 客户端为 Cisco,实际为自己修改的 racoon。它只支持 ike 协议的第一版即 ikev1,可以使用证书或纯密码(PSK)认证,但必须辅之 xauth 用户名/密码认证。
该修改版的 racoon 会优先使用不加密的积极模式,而积极模式是 strongSwan 所不支持的。所以要使用主力模式。
iOS 6 还有一个「衔尾」故障:它在第一阶段握手时会把数据包拆分成小块(fragmentation),然后「加密」发送。然而这种加密仅仅是声明的,其实并未加密,这就导致 strongSwan 及其它标准服务器端/Cisco 设备无法解密。另外 ikev1 的 fragmentation 插件是闭源的。开源服务器端无法对这些小块进行重组。参考:Cisco VPN stop working after upgrading to IOS 6
所以产生了一种权宜之计,就是使用小证书(小于 1024,默认一般为 2048),来达到不拆包的目的。但是 Mac OS X 10.7 的更新却对这种方式进行了封杀,学习微软加入了证书验证,小证书直接拒绝。
所幸 strongswan 5.0.2 已经完成了 fragmentation 的开源实现和对 iOS 那个声明加密其实未加密故障的处理:IKE message fragmentation (cisco) + IOS 6.0 Hack for encrypted flaged ike fragmentation packets,该链接中也能找到 strongswan 4 的补丁。
Windows
微软的差劲只比 iOS 好一点。好处在于它支持了 ikev2,但是只在 Windows 7 以后支持,Vista 之前依然使用 ikev1。
坏处在于它的 ikev2 支持非常诡异,指定了 Diffie Hellman group(DH,迪菲-赫尔曼密钥交换组)必须是 modp1024。这是非常少见理论上不应该由系统管理员操心的加密选项:
在 strongswan 中,定义第一阶段(ike)和第二阶段(esp)加密方法的语法是:
ike/esp=encryption-integrity[-dhgroup][-esnmode] 第一阶段/第二阶段=加密方法-健壮性认证方法 (后面两项可选)[-DH 组] [-扩展序列号支持模式(RFC4304)]
Windows 定义了一个可选的选项,导致了我们必须去定义整个第一阶段的加密方法。这样被破解的可能性就提高了。
其次在于它的 rekey(重连)。IPsec 的认证是有时效的,超过时间会重新认证。这种 CHILD_SA 认证可由服务器发出,也可由客户端发出,一般是由服务器发出。但是 Windows 7 的 ikev2 的表现是,如果你在路由器(NAT)后,收到这种请求会把微软内部的通知代码发出去,代码为 12345, 经过 strongswan 项目侦错后发现这个代码的意思是 ERROR_IPSEC_IKE_INVALID_SITUATION。但是处理不了,它不是 IPsec 标准协议定义过的错误。
于是有两种权宜之计:
一种是让 Windows 7 来主动 rekey。Windows 7 rekey 的时间大约是 58 分 46 秒,所以要配置服务器 rekey 时间比它长。但是效果非常不好。因为 rekey 是由三个变量控制的,key 的生命周期,key 的边际时间(生命周期前多久进行 rekey),和边际时间误差(rekeyfuzz),误差是不可控的。参考:ExpiryRekey。
即使能控制 strongswan 这边,Windows 依然是「大约」; 即使两边都能控制,假设服务器延后一秒 rekey,理论上如果连接持续时间足够长,依然能够撞车:58x60+46 次 rekey 后即 146 天后撞车,连一年都没有,在 Linux 服务器对 Windows 服务器这种使用实例中就明显不符合要求。
所以目前只能使用后一种方法即完全禁用服务器端 rekey。
最后,它的 EAP 认证也非常糟糕。MSCHAPv2 的 eap 身份不是 ikev2 身份(ikev2 身份一般是 EAP 用户名),所以必须在服务器端显式定义 eap_identity 来使用 Windows 7 的 eap 身份。
安装 Srongswan
sudo zypper ar -f http://download.opensuse.org/repositories/network:/vpn/openSUSE_12.3/ network:vpn sudo zypper ref sudo zypper in --no-recommends strongswan-ipsec
这里 --no-recommends 是不带推荐软件包,因为推荐的软件包都是针对桌面环境的,服务器用不到。
生成证书(可选)
每一个完整的 ssl 证书都有一个公钥和一个私钥,它们可以在一起也可以分开放(当然如果你要在网络上传输,肯定只能用公钥)。公钥是在网络上传输的,而私钥是藏好用来和接收到的公钥配对的(因此私钥里也有整个公钥,用来配对)。
生成 CA 证书
生成一个私钥:
ipsec pki --gen --outform pem > ca.pem
没什么好解释的,--outform 一共有三个格式可选,但是另外两个是 der 和 pgp...
基于这个私钥自己签一个 CA 证书:
ipsec pki --self --in ca.pem --dn "C=CN, O=strongSwan, CN=strongSwan CA" --ca --outform pem > ca.cert.pem
这里 --self 表示自签证书,--in 是输入的私钥,--dn 是判别名,--ca 表示生成 CA,其它同上。这里需要解释下判别名:
- C 表示国家名,同样还有 ST 州/省名,L 地区名,STREET(全大写) 街道名。
- O 表示组织名。
- CN 为通用名。
具体见微软的文档:Distinguished Names
生成服务器证书
同样生成私钥:
ipsec pki --gen --outform pem > server.pem
用我们刚才自签的 CA 证书给自己发一个服务器证书:
ipsec pki --pub --in server.pem | ipsec pki --issue --cacert ca.cert.pem \ --cakey ca.pem --dn "C=CN, O=strongSwan, CN=forum.suse.org.cn" \ --san="forum.suse.org.cn" --flag serverAuth --flag ikeIntermediate \ --outform pem > server.cert.pem
这条命令的意思解释下:
ipsec pki --pub --in server.pem
是从我们刚生成的私钥里把公钥提取出来,然后用公钥去参与后面的服务器证书签发(这个是 VPN 连接时候要用的,你不想把私钥也给它吧?那样跟没签证书一样...)。
--issue, --cacert 和 --cakey 就是表明要用刚才自签的 CA 证书来签这个服务器证书。
--dn, --san,--flag 是一些客户端方面的特殊要求:
- iOS 客户端要求 CN 也就是通用名必须是你的服务器的 URL 或 IP 地址;
- Windows 7 不但要求了上面,还要求必须显式说明这个服务器证书的用途(用于与服务器进行认证),--flag serverAuth;
- 非 iOS 的 Mac OS X 要求了「IP 安全网络密钥互换居间(IP Security IKE Intermediate)」这种增强型密钥用法(EKU),--flag ikdeIntermediate;
- Android 和 iOS 都要求服务器别名(serverAltName)就是服务器的 URL 或 IP 地址,--san。
生成客户端证书
依然是生成私钥:
ipsec pki --gen --outform pem > client.pem
然后用刚才自签的 CA 证书来签客户端证书:
ipsec pki --pub --in client.pem | ipsec pki --issue --cacert caCert.pem \ --cakey caKey.pem --dn "C=CN, O=strongSwan, CN=client" \ --outform pem > client.cert.pem
这时命令行会提示你输入两遍密码,这个就是你的客户端证书密码。
看懂了服务器的,客户端的也就不难理解了。除了没有那一堆特殊要求别的都一样。
客户端证书可以每个客户端签一个,也可以让它们公用一个。是否多签看用途,一般用于区分设备(计费是不用这样的,是用账户来区分的)。
生成 pkcs12 证书(可选)
你可能还想生成一个可以直接导入的 pkcs12 证书(用于手机,诺基亚没这东西还不行):
openssl pkcs12 -export -inkey client.pem -in client.cert.pem -name "client" \ -certfile ca.cert.pem -caname "strongSwan CA" -out client.cert.p12
安装证书
cp -r ca.cert.pem /etc/ipsec.d/cacerts/ cp -r server.cert.pem /etc/ipsec.d/certs/ cp -r server.pem /etc/ipsec.d/private/ cp -r client.cert.pem /etc/ipsec.d/certs/ cp -r client.pem /etc/ipsec.d/private/
CA 证书、客户证书(两个)和 .p12 证书用 FTP 复制出来给客户端用。有几种 Android 配置还需要服务器证书(server.cert.pem)。
配置 Strongswan
ipsec.conf
config setup uniqueids=never conn iOS_cert keyexchange=ikev1 # strongswan version >= 5.0.2, compatible with iOS 6.0,6.0.1 fragmentation=yes left=%defaultroute leftauth=pubkey leftsubnet=0.0.0.0/0 leftcert=server.cert.pem right=%any rightauth=pubkey rightauth2=xauth rightsourceip=10.0.0.0/24 rightcert=client.cert.pem auto=add # also supports iOS PSK and Shrew on Windows conn android_xauth_psk keyexchange=ikev1 left=%defaultroute leftauth=psk leftsubnet=0.0.0.0/0 right=%any rightauth=psk rightauth2=xauth rightsourceip=10.0.0.0/24 auto=add # compatible with "strongSwan VPN Client" for Android 4.0+ # and Windows 7 cert mode. conn networkmanager-strongswan keyexchange=ikev2 left=%defaultroute leftauth=pubkey leftsubnet=0.0.0.0/0 leftcert=server.cert.pem right=%any rightauth=pubkey rightsourceip=10.0.0.0/24 rightcert=client.cert.pem auto=add conn windows7 keyexchange=ikev2 ike=aes256-sha1-modp1024! rekey=no left=%defaultroute leftauth=pubkey leftsubnet=0.0.0.0/0 leftcert=server.cert.pem right=%any rightauth=eap-mschapv2 rightsourceip=10.0.0.0/24 rightsendcert=never eap_identity=%any auto=add
其中 config setup 只能出现一次,而 conn <连接名称> 可以有很多个。这里的名称不是预定义的,可以随意写,只要你能识别就行,主要用来定义一种连接,就是为了让你在日志里好找。
新版 strongswan 里 config setup 的内容不如旧版的多,许多旧版必须有的选项都被作废了。比如:
- plutostart 新版所有的 ike 协议都由原来 ikev2 的 daemon:charon 接管。根本就没有 pluto 了。
- nat_traversal 新版所有的 ike 协议都是可以穿越路由器(NAT)的。
- virtual_private 定义服务器的局域网 IP 地址。现在被魔术字 0.0.0.0/0 取代了。
- pfs 完美向前保密,用于 rekey 时。意思是你现在的金钥互换过程如果被攻破了,会不会对已经互换过的金钥产生影响。以前一般设置成 no 来适用于 iOS 这种客户端会以积极模式发出非加密的 rekey 请求的情况。现在这个选项完全没作用了。第一阶段永远是完美向前保密的,第二阶段(esp)如果指定了 DH 组那么也是完美向前保密的,但是默认加密方法就已经指定了 DH 组。所以该选项永远为 yes。
而另外旧版和新版都有的选项也都定义了默认值,比如:
- strictpolicy 是否一定需要证书吊销列表(CRL)的 URL。默认就是 no。
- charonstart 是否启动 ikev2 的 daemon。这是旧版加入的,因为那个时候的主力是 pluto。现在默认就是 yes,你改成 no 那你连原先 pluto 的连接都无法连接,因为 ike 协议的实现全被 charon 接管了。
所以 config setup 基本上占位就行了。这里我们修改了 uniqueids 的值来实现多设备同时在线。
而 conn 最主要要理解左右的概念。其实左右是可以不分的,它们只是用来表示一个连接的两端。只是在如果你定义的不够全面时,左侧会默认被认为是本机(你的 VPS),右侧默认为他机(你的笔记本),即以左为尊。
- left/right 是左右 id。它们用来识别服务器/客户端,可以是证书的判别名(DN),比如 "C=CN, O=strongSwan, CN=strongSwan CA",也可以是 IP 地址,也可以是 EAP 的用户名,还可以是魔术字 %any,表示什么都行。只是在 5.0.0 之前,为本机这边定义 %any 的话,ikev1 连接即 keyexchange=ikev1 的连接是识别不了,所以要改成 %defaultroute 表示自己从 ifconfig 里取 IP。为了和 right 的 %any 区分开,我们使用这种方法。所以说到最后这两个选项似乎没有什么用。但它们是必须的。
- leftauth/rightauth 这是最重要的改动。新版主要是作废了之前的 authby 和 xauth=server/client 选项而都改用这种方法。因此使得 ikev1 也能够出现混血认证(左右两边认证的方法不同)了。参数主要有 pubkey 表示用证书,psk 表示用密码,eap 表示用扩展验证协议。
- leftauth2/rightauth2 是为了应对旧版很常见的 authby=xauthpsk/xauthrsasig 的。现在 xauth 只能写在这里。而 psk 对应 leftauth/rightauth 里的 PSK 方法,rsasig 则对应 pubkey 方法。
- leftsubnet 最重要的,引入了魔术字 0.0.0.0/0。如果你在右侧为客户端分配虚拟 IP 地址的话,那表示你之后要做 iptables 转发,那么左边就必须是用魔术字。
- leftcert/rightcert 就是指定证书名字。
- rightsourceip 为客户端分配的虚拟 IP 段。
- auto 定义 strongswan 启动时该连接的行为。start 是启动; route 是添加路由表,有数据通过就启动; add 是添加连接类型但不启动; ignore 是当它不存在。默认是 ignore。看起来似乎是 route 比较好,但问题是我们服务器端不能预分配虚拟 IP,所以服务器端一般用的都是 add。而客户端文本配置可以选择 start。
另外说下旧版的 xauth=server/client 的问题。它表示在服务器端还是在客户端执行 xauth 认证。而在新版中主要通过左右方向来体现。比如你在服务器端执行认证,那认证请求是由客户端发出的,所以要写 rightauth2=xauth。如果在客户端执行认证,那认证请求是服务器发出的,所以要写 leftauth2=xauth。
另外网上很常见的一个配置选项是 leftfirewall=yes。这是完全错误的。看上去它的唯一作用是定义你的服务器是不是在防火墙后面,但实际上它是作为 ipsec_updown 脚本的参数被开发出来,是表明你的本机 subnet 是不是用 iptables 转发/伪装出来的。如果是的话,就调用 left/rightupdown 定义的路径下的脚本,脚本的作用是对通过 ipsec 连接的数据包进行 iptables 豁免。
之所以说它是错到离谱的(虽然没有产生影响),因为这些人完全就不懂,有公网 IP 的服务器的 subnet 很少是伪装的。另外必须写了脚本该选项才有意义,没看过一个定义了这个选项的人写过脚本。还有,leftsubnet=0.0.0.0/0 通过魔术字把 subnet 定义为了 any,你根本没法写脚本啊。所以我们这里完全就不用。
至于某类型连接,主要是根据设备规格定义的,一些特殊选项的解释如下:
- fragmentation=yes 开启对 iOS 拆包的重组支持。
- ike=aes256-sha1-modp1024! Windows 指定的第一阶段加密方法。
- rekey=no 服务器对 Windows 发出 rekey 请求会断开连接。
- rightsendcert=never 因为这是一个混血连接。服务器对自己的身份进行认证时使用的是证书,而服务器对客户端的认证使用的只是 eap-mschapv2。如果不设置的话默认是 ifasked,意思是如果服务器向客户端请求证书,客户端就会给它,但客户端给不出,连接就会断。这里设置为客户端永远不给,实际上的意思其实是服务器不要向客户端请求证书。
- eap_identity=%any 使用 Windows 的 eap 身份。不然会出现”no eap key found for host <rightid>“错误。
ipsec.secrets
# # ipsec.secrets # # This file holds the RSA private keys or the PSK preshared secrets for # the IKE/IPsec authentication. See the ipsec.secrets(5) manual page. # : RSA server.pem : PSK "PSK password" marguerite : XAUTH "user password" marguerite : EAP "user password"
看上去比较好理解,实际不是。
有些人可能会误以为:
: PSK "PSK password" marguerite : XAUTH "user password"
是成对的,用于比如 android-xauth-psk 这样的连接,于是到了 iOS 的时候又写了一对:
: RSA server.pem marguerite : XAUTH "user password"
来支持 iOS 的 RSA + XAUTH 认证。
这样做是没有必要的,上面定义的是四种认证方法。它们之间是遵循「各找各妈」的原则的,可以任意混搭。即你写了一个 XAUTH 即可支持所有完全使用或部分使用 XAUTH 方法的连接。
实际上:
: PSK "PSK password"
相当于:
%any %any : PSK "PSK password"
遵循:
主机 对等点 : 方法 <本机证书/协议密码> <本机证书密码>
的格式。以 :为分界,分别从左到右填充,除了各类密码缺失以 null 补位,其它都用 %any 补位(密码怎么可能是 %any)。
于是
marguerite : EAP "user password"
相当于
marguerite %any : EAP "user password" // EAP 方法没有证书,也就没有证书密码
这里有些人可能迷惑了,前面不是说过以左为尊、本机(这里是 VPS)默认在左边吗,你刚才定义 eap-mschapv2 的时候可是定义给的 rightauth,这次怎么把 EAP 的用户名写在左边了?
请注意,ipsec.conf 使用的是本机/他机的逻辑,本机默认在左; 而 ipsec.secrets 使用的是主机/对等点的逻辑,主机永远在左。
ipsec.conf 里面定义的是连接,左侧的本机(对你来说,本机是你的笔记本,而对服务器来说,本机是它自己,你才是它的「他机」,这个配置是在服务器上的,不要混淆)用证书认证,右侧是你的 win7 用 mschapv2 认证; 而 ipsec.secrets 里定义的是认证,认证过程是你的 win7 用这个用户名和后面定义的密码去连接主机,认证是主机上发生的,所以要写在左边。
另外一部分人可能会混淆主机/对等点的含义,认为他们和 BT 是一样的,你开启了一个 strongswan 连接,于是你是主机,而其它人都是对等点,于是他们统一了本机/他机和主机/对等点这两种截然不同的逻辑。前面已经说了我们的例子是以 VPS/客户机这种典型案例为主,而你的客户机是图形界面自适配的,你没有改过客户机的配置文件(所以官方维基上提供的例子你要看的是 moon 的配置),这种尴尬的统一的影响几乎没有。
而这种案例下,你不能理解主机/对等点的含义的后果是致命的:
你有一台国外 VPS,一台国内 VPS,想让国内 VPS 也能科学上网。那你在国内 VPS 上就可能产生这样的配置:
<国外 VPS 的 IP> <国内 VPS 的 IP> : RSA <国内 VPS 的私人证书名称> <私人证书密码>
国外 VPS:
<国外 VPS 的 IP> <国内 VPS 的 IP> : RSA <国外 VPS 的服务器证书名称> // 服务器证书一般没有密码
这里国外服务器是主机,国内服务器是对等点。主机永远只有一台,而且是在一开始便确定并固定不变的。如果你把国内 VPS 配置成:
<国内 VPS 的 IP> <国外 VPS 的 IP> : RSA <国内 VPS 的私人证书名称> <私人证书密码>
是无法连接的。因为主机始终是国外的 VPS。你可以想象为 BT 中心种子服务器和你的计算机的关系。中心种子服务器是固定不变的。
另外也间接证明了 ipsec 连接的代理是单向的,只能是主机为对等点做代理。就是说即使两台都是服务器,它们的 ipsec 连接也不是双向的,比如你国内服务器可以科学上网,而国外服务器可以看优酷,这是不可能在一个连接里发生的。
strongswan.conf
# strongswan.conf - strongSwan configuration file charon { duplicheck.enable = no dns1 = 208.67.222.222 dns2 = 208.67.220.220 # for Windows only nbns1 = 208.67.222.222 nbns2 = 208.67.220.220 filelog { /var/log/strongswan.charon.log { time_format = %b %e %T default = 2 append = no flush_line = yes } } }
从 strongswan 5 起,无论是 ikev1 还是 ikev2 协议都使用 ikev2 的 daemon:charon 来实现。也就是说不必再在 /etc/strongswan.conf 里配置 pluto 了。
duplicheck.enable = no 是为了你能同时连接多个设备,所以要把冗余检查关闭。
dns 就不说了。nbns 是 Windows 的 NetBIOS 名称服务器实现, wins 服务会请求的。实际上 NBNS 协议是一个标准协议,但问题是 Linux 不强制而 Windows 强制请求,你不定义就无法连接。所以对于 ipsec VPN 来说,这个就是只供 Windows 使用的。
下面的 filelog 定义了一个文本日志。ipsec 协议的各种实现似乎都没有显式定义文本日志(比如 racoon,strongswan 都没有),而是写入系统日志 syslog。那样不利于调试,所以显式定义一下。
- default 是默认日志级别:-1,0,1,2,3,4。-1 是完全没有日志; 0 只告诉你连接建立、连接关闭; 1 只输出错误提示; 2 会输出错误、警告和调试信息; 3 会把连接传输的数据也打印; 4 则会把密钥内容这些敏感数据也打印。一般情况下,1 或 2 都可以。
- append 是当你重启 strongswan 后,是接上次日志写,还是新建一个日志(上次的会被删除)。因为 strongswan 的日志太多了,所以用 no。
- flush_line 是每产生一行日志,就写入到磁盘一次。防止突然断电,磁盘缓存数据丢失。
另外你还可以详细定义每个 strongswan 模块的日志级别,但是没什么必要,具体可见 LoggerConfiguration。
启动 Strongswan
sudo systemctl enable strongswan.service sudo systemctl start strongswan.service
注:如果是 openSUSE12.2 发行版,包中默认没有strongswan.service,需要用户到 /etc/init.d/ 目录下启动服务。
cd /etc/init.d/ sudo ipsec start
配置 Iptables 转发
使用 SuSEfirewall2
SuSEfirewall2 为系统默认防火墙,配置可以通过 YaST 修改,也可以通过直接编辑 /etc/sysconfig/SuSEfirewall2 来修改。
IPsec VPN 所需要的端口为 UDP 500 和 UDP 4500,在 /etc/sysconfig/SuSEfirewall2 里找到
FW_SERVICES_EXT_UDP=""
修改为
FW_SERVICES_EXT_UDP="500 4500"
需要启用路由功能,防火墙默认设置为未启用,将 /etc/sysconfig/SuSEfirewall2 中的
FW_ROUTE="no"
改为
FW_ROUTE="yes"
启用 NAT,将 /etc/sysconfig/SuSEfirewall2 中的
FW_MASQUERADE="no"
改为
FW_MASQUERADE="yes"
添加需要转发的网段 10.0.0.0/24 到配置中,在 /etc/sysconfig/SuSEfirewall2 里找到
FW_MASQ_NETS=""
修改为
FW_MASQ_NETS="10.0.0.0/24"
此外 IPsec VPN 可能还需要 启用 esp 或 ah,在 /etc/sysconfig/SuSEfirewall2 里找到
FW_SERVICES_EXT_IP=""
修改为
FW_SERVICES_EXT_IP="esp ah"
修改完成后重启防火墙
SuSEfirewall2 stop SuSEfirewall2 start
使用 iptables
如果禁用了 SuSEfirewall2,也可以使用 iptables 来设置。
sudo iptables -A INPUT -p udp --dport 500 -j ACCEPT sudo iptables -A INPUT -p udp --dport 4500 -j ACCEPT sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE sudo iptables -A FORWARD -s 10.0.0.0/24 -j ACCEPT sudo echo 1 > /proc/sys/net/ipv4/ip_forward
为了每次 VPS 启动不重新输入这些命令,我们做成了一个 Systemd 服务 strongswan-iptables.service。下载扔到 /etc/systemd/system,然后:
systemctl enable strongswan-iptables.service systemctl start strongswan-iptables.service
即可运行上述命令。以后系统启动时也将自动运行上述命令。
openSUSE 客户端配置
strongswan 项目同时开发了 NetworkManager-strongswan,最新版本是 1.3。
安装 NetworkManager-strongswan
sudo zypper in NetworkManager-strongswan
GNOME 要安装 NetworkManager-strongswan-gnome
sudo zypper in NetworkManager-strongswan-gnome
KDE 要安装 NetworkManager-strongswan-kde4
sudo zypper in NetworkManager-strongswan-kde4
如果你的 strongswan 是 5.0.0 以上的话,你还要安装 strongswan-nm
sudo zypper in strongswan-nm
然后编辑 /etc/NetworkManager/VPN/nm-strongswan-service.name,替换
program=/usr/lib/ipsec/charon
为:
program=/usr/lib/ipsec/charon-nm
并重载 systemd 的全部系统服务
sudo systemctl --system daemon-reload
不然会出现 “vpn service 'strongswan' start timed out” 即 “signal of type SIGTERM received. Shutting down” 错误。因为 5 版的 strongswan 引入了一个 strongswan-nm 来避免与系统的 strongswan 冲突,而 openSUSE 的 NetworkManager-strongswan 的 systemd 服务有 bug(待修复),并不会去使用 strongswan-nm。
之后一定要重启 NetworkManager.service 服务:
sudo systemctl restart NetworkManager.service
不然你设置好了会发现无法保存私钥(private key)的密码,也不会弹出窗口,错误信息为:
<error> [1370608229.893778] [nm-vpn-connection.c:1355] plugin_need_secrets_cb(): (f4f7fcdb-110b-4f80-8fc8-23934fc29a0c/strongswan) plugin NeedSecrets request #1 failed: dbus-glib-error-quark Rejected send message, 1 matched rules; type="method_call", sender=":1.3" (uid=0 pid=569 comm="/usr/sbin/NetworkManager --no-daemon ") interface="org.freedesktop.NetworkManager.VPN.Plugin" member="NeedSecrets" error name="(unset)" requested_reply="0" destination="org.freedesktop.NetworkManager.strongswan" (uid=0 pid=11246 comm="/usr/lib/ipsec/charon-nm ")
这是因为 NetworkManager 的 DBus 服务没有重载,不能识别 strongswan 的缘故。
配置要点如下:
- 勾选系统连接,不然启动不了 daemon
- 网关:你的服务器 URL 或 IP,必须和证书里面那个一样(证书里是 URL 这里就不能是 IP)
- 证书:你的 CA 证书
- 认证方式:证书/私钥
- 证书:你的客户证书
- 私钥:客户证书对应的私钥
- 私钥密码:生成客户证书时让你输入的那个密码,没有就选不需要,否则选储存或总是询问
- 勾选请求内部 IP 地址,不然你没有虚拟地址,tun 设备自然也没法为你中转流量
- 勾选强制 UDP 封装,这是因为 strongswan 5 以后即使 ikev1 也是通过 ikev2 的 charon 后端通讯的。而 charon 有一个新的特性叫 MOBIKE,也就是手机端上的自动重连(只适用于使用证书的情况),这个特性是默认开启的。而开启了这个特性所有的流量都会走 4500 端口也就是 UDP。你不勾根本连不上。
其它客户端配置
其它 Linux
Chakra Linux
方法和openSUSE的大同小异,不过关键问题在于Chakra默认所有源中是没有Strongswan,这个时候各位可以借助CCR来实现安装,CCR中有三个包,分别是strongswan, networkmanager-strongswan, networkmanager-dispatcher-strongswan-systemd(目前三者由我自己维护,从AUR照抄,修改了其中一个依赖而已)。其中,第一个是主要的,第二个大家都知道,第三个是systemd服务。推荐客户端用户只需要安装前两个。(我的源中默认启用了所有的源,包括core, platform, desktop, apps, games, lib32, extra以及测试源和不稳定源,个人认为主要要启动extra源,因为需要到一些gtk库)
- 编译安装两个主要包
ccr -S strongswan && ccr -S networkmanager-strongswan
(各位可以去喝喝茶,听听歌)
- 下载strongswan源代码编译安装strongswan-nm,下载地址,下载到一个你知道的地方,我放到/home/source/目录下,解压后,开始编译strongswan-nm插件
# build charon with OpenSSL/NM Plugin ./configure --sysconfdir=/etc --prefix=/usr --libexecdir=/usr/lib \ --disable-aes --disable-des --disable-md5 --disable-sha1 --disable-sha2 \ --disable-fips-prf --disable-gmp --enable-openssl --enable-nm --enable-agent \ --enable-eap-gtc --enable-eap-md5 --enable-eap-mschapv2 make make install
完成安装后,注意/usr/lib/ipsec/目录下多出了一个charon-nm,这个就是我么需要的东西。下面的设置基本遵循玛丽苏的方式。
- 编辑/etc/NetworkManager/VPN/nm-strongswan-service.name,替换
program=/usr/lib/strongswan/charon
为:
program=/usr/lib/ipsec/charon-nm
- 后面的步骤依照openSUSE中“并重载 systemd 的全部系统服务”
- NetworkManager 的配置要点同 openSUSE
- 补充:这个时候你的客户端应该能够连接了,如果不能,首先看看防火墙策略,如果还是不行,你可以试试先随便连接一个 VPN ,然后断开再连自己的 strongswan
其他 Linux 发行版参考 openSUSE 配置。
iOS
把 CA 证书和之前做好的 pkcs12(.p12)发邮件给自己。在 iOS 上收邮件,导入两者。然后新建 IPSec VPN:
- 服务器,和 openSUSE 的要求一样,都是 IP 或都是 URL
- 账户和密码写 ipsec.secrets 里 XAUTH 前后的那两个
- 如果要使用证书,证书选刚才的那个。否则可以不使用证书,输入 ipsec.secrets 里设置的 PSK 密码。
Android
IPSec Xauth PSK
我的 Jelly Bean 是有这个的,设置 VPN 之前 JB 要求你必须设置锁屏密码或者 PIN 码。
主要还是:
- 服务器,同上
- IPSec 预共享密钥:写 ipsec.secrets 里 PSK 后面的那个密码。
然后登入时还是用 XAUTH 前后的那两个做用户名密码。
"strongSwan VPN Client" for Android 4.0 (ICS)+
这是官方自己出的客户端,Google Play 里就有。
把之前做好的 pkcs12 发邮件给自己。实际上 pkcs12 里就包含了 CA 证书,iOS 是有 bug 才必须明确要求导入 CA 证书(鄙视之)。Android 不用。直接在 GMail 里点击就会提示你导入。
然后打开官方客户端,新建方案:
- Gateway 就是服务器,同上
- Type 选 IKEv2 Certificate
- User certificate 选你刚才导入的
- 取消自动选择 CA 证书,然后在用户证书里选你刚才从 pk12 导入的
Windows XP/Vista
使用 Shrew Soft VPN Client
下载:https://www.shrew.net/download/vpn
安装后打开,选「Add」:
- 「General」选项卡下,把「Host Name or IP address」添好
- 「Authorization」选项卡下:
- 「Authorization Method」选「Mutual PSK + XAuth」
- 「Local Identity」的「Identification Type」选「IP Address」
- 「Credentials」下面「Pre Shared Key」里输入 PSK 密码
- 「Phrase 1」,「Exchange Type」选「Main」
- 「Phrase 2」,「PFS Exchange」选「auto」
保存。连接时用户名密码是你的 XAUTH 用户名密码。
服务器端对应的配置是 android-xauth-psk 的连接类型。
Windows 7+
使用 Shrew Soft VPN Client 客户端:和上面 XP 的一样。
使用自带客户端(Agile):
导入证书:
- 开始菜单搜索「cmd」,打开后输入 mmc(Microsoft 管理控制台)。
- 「文件」-「添加/删除管理单元」,添加「证书」单元
- 证书单元的弹出窗口中一定要选「计算机账户」,之后选「本地计算机」,确定。
- 在左边的「控制台根节点」下选择「证书」-「个人」,然后选右边的「更多操作」-「所有任务」-「导入」打开证书导入窗口。
- 选择刚才生成的 client.cert.p12 文件。下一步输入私钥密码。下一步「证书存储」选「个人」。
- 导入成功后,把导入的 CA 证书剪切到「受信任的根证书颁发机构」的证书文件夹里面。
- 打开剩下的那个私人证书,看一下有没有显示「您有一个与该证书对应的私钥」,以及「证书路径」下面是不是显示「该证书没有问题」。
- 然后关闭 mmc,提示「将控制台设置存入控制台1吗」,选「否」即可。
至此,证书导入完成。
建立连接:
- 「控制面板」-「网络和共享中心」-「设置新的连接或网络」-「连接到工作区」-「使用我的 Internet 连接」
- Internet 地址写服务器地址,注意事项同 openSUSE 的,都是 IP 或都是 URL。
- 描述随便写。
- 用户名密码写之前配置的 EAP 的那个。
- 确定
- 点击右下角网络图标,在新建的 VPN 连接上右键属性然后切换到「安全」选项卡。
- VPN 类型选 IKEv2
- 数据加密是「需要加密」
- 身份认证这里需要说一下,如果想要使用 EAP-MSCHAPV2 的话就选择「使用可扩展的身份认证协议」-「Microsoft 安全密码」,想要使用私人证书认证的话就选择「使用计算机证书」。
调试
如果没有特殊需要,服务器端的日志就足够检测出绝大多数问题的来源。
我唯一需要在客户端上侦错的那次是 iOS 客户端。
日志阅读技巧
strongswan 的 charon daemon 启动后,会初始化并加载之前你定义好的 conn,这部分 log 是没有必要去读的。当然在你配置有问题时可能就有必要了,但当配置有问题的时候,systemctl start strongswan.service 会失败,systemctl status strongswan.service 就会指出你配置问题所在的行号(=。=)...
所以你只要去查找「added configuration 'windows7'」,这里 windows7 是你配置的最后一个 conn 的名称,然后从那里往下看就好了。
另外连接失败是会把连接状态从 CONNECTING 变为 DELETEING 的,DELETEING 又会刷一大堆日志,但那些日志都是没用的。
服务器端调试
/var/log/strongswan-charon.log 文件
Linux 调试
参照 strongswan 配置教学改 /etc/strongswan.conf,之后同服务器端调试。
iOS 调试
越狱安装 iFile。编辑 /etc/racoon/racoon.conf 文件,找到 #log debug; 字段,改成:
log debug; path logfile "/var/log/racoon.log";
保存。
Android 调试
- strongSwan 官方客户端提供了日志查看功能。
- android 自带的 VPN 调试方法如下:
打开「终端模拟器」,输入 su,会弹出超级用户,允许。
cd /storage/sdcard0 logcat -f ./log.txt
然后用 Airdroid 等工具把 SD 卡中的 log.txt 传到电脑上,打开搜索 VPN 即可。
Windows 调试
微软 technet:VPN Troubleshooting Tools。
扩展阅读
计费软件
- FreeRadius:账户认证和计费
- daloRadius:用户账单管理
参考:使用 StrongSwan 搭建 IKEv1 IKEv2 VPN服务器|莓玩没了。注:该文的 strongswan 配置仅供参考(有很多冗余配置)。
- MySQL:账户管理后台数据库
参考文献
配置选项:
- http://wiki.strongswan.org/projects/strongswan/wiki/IpsecConf
- http://wiki.strongswan.org/projects/strongswan/wiki/IpsecSecrets
- http://wiki.strongswan.org/projects/strongswan/wiki/NetworkManager
设备/操作系统特殊要求:
- http://wiki.strongswan.org/projects/strongswan/wiki/IOS_(Apple)
- http://wiki.strongswan.org/projects/strongswan/wiki/Win7Config
- http://wiki.strongswan.org/projects/strongswan/wiki/Win7Certs
- http://wiki.strongswan.org/projects/strongswan/wiki/Win7MultipleConfig
- http://wiki.strongswan.org/projects/strongswan/wiki/Win7EapMultipleConfig
作者
- MargueriteSu 2013年6月5日 (三) 23:03 (MDT)
- Houge_Langley 2013年6月12日 (三) 23:03 (MDT)