strongSwan,是一个完整的开源 IPsec VPN 解决方案,可以运行在 Linux、Windows 和 Mac OS X 上,此外,它还兼容基于 Android 和 iOS 的产品所支持的 IPsec 功能。

要注意的是,strongSwan 并不对 VPN 上的数据进行加密,而是由运行 strongSwan 的底层操作系统(比如 Linux)进行加密。strongSwan 负责使用网络密钥交换(internet key exchange, IKE)协议帮助同级协商用于对称加密的密钥。strongSwan 支持 IKEv1 和 IKEv2。IKE 允许对等体就加密所使用的加密参数达成一致,然后通过 Diffie-Hellman 密钥交换算法共同商定加密密钥。

IKEv1 于 1998 年发布,因为协议规格含糊不清,前后不一致,可能导致实施时容易受到各种安全攻击而最终受到批评。七年后,IKEv2 的规范发布,其中提出了一个有些简化和更可靠的协议版本。IKEv2 对 NAT 遍历、可扩展认证协议(extensible authentication protocol, EAP)、移动性和多宿主(mobility and multi-homing, MOBIKE)等功能也有更好的支持。

strongSwan 在一个叫 pluto 的服务中实现了 IKEv1,而 IKEv2 则由一个叫 charon 的服务提供。

1. Linux IPsec 支持

在 Linux 中有多个竞争性的 IPsec 协议栈,我们应该看看历史来了解它们之间的关系。1998年开始的 KAME 项目是第一个努力实现 IPv4 和 IPv6 的免费 IPsec 协议栈的项目。该项目的实施是为了 BSD UNIX 系统,但很快就作为 Linux 内核的补丁。大约在同一时间,John Gilmore(电子前沿基金会的创始人之一,因破解 DES 加密而闻名)启动了 FreeS/WAN 项目,旨在将 IPsec 引入 Linux。这也需要给 Linux 内核打补丁。FreeS/WAN 补丁被称为 Kernel IP Security(KLIPS)。

在这两种情况下(KAME 和 KLIPS),都需要打补丁来允许在用户空间运行的 IKE 服务与内核空间的对应服务进行通信,以安装加密密钥和配置各种加密参数。

IETF 在 RFC 2367 中定义了 PF_KEYv2,作为标准 API,允许用户空间进程在操作系统内核中配置 IPsec。KAME 和 KLIPS 都使用了 PF_KEYv2。为每个内核版本维护 KAME 和 KLIPS 的补丁是很有挑战性的,因此决定在 Linux 2.6 内核系列中把 KAME 作为默认的 IPsec 协议栈。2.6 内核下的 KAME 实现被称为 NETKEY。然而,2.6 内核的特点是修改了协议栈,其中一个新特性是一个叫做 NETLINK 的协议。与 PF_KEYv2 不同,NETLINK 是一个通用的协议,它允许用户空间实体与内核的各个部分交换消息。例如,RT_NETLINK 是一个 NETLINK 扩展,它可以让动态路由进程在内核中安装或删除路由。同样,XFRM_NETLINK 9 允许 IKE 或其他用户进程管理内核中维护的 IPsec 安全关联数据库(Security Association Database, SAD)和安全策略数据库(Security Policy Database, SPD)。

2. 策略路由

strongSwan 使用了一种叫做策略路由的网络功能。这与 SPD 和 IPsec 使用的安全策略不同。正常的 IP 路由是基于 IP 头中的目标 IP 地址字段。启用 IP 转发的主机将为所有前往特定目的地的数据包选择相同的路径。这种情况并不总是可取的。策略路由的一个早期案例是支持不同客户类别的不同 QoS 级别。金牌客户为获得高吞吐量和低延迟服务而付费,而青铜客户则为更便宜的尽力服务而解决。为这些客户选择路由时,除其他外,还需要将源 IP 地址和目的地址作为 IP 路由过程的一部分。

Linux 策略路由的实现需要多个路由表和一个路由策略数据库(RPDB)。你可以通过输入以下命令列出 RPDB 中的策略:

1ip rule show

输出应该显示这样的内容:

10:     from all lookup local
2220:   from all lookup 220
332766: from all lookup main
432767: from all lookup default

最左边的一列显示了分配给同一行的策略路由规则的优先级。可用的规则从最高优先级(0)到最低优先级(32767)进行扫描,第一个匹配的规则会选择路由过程将使用的路由表来查找路由。一旦 RPDB 策略匹配,就会使用指定的表来查找下一跳。如果路由过程无法从规则所指示的路由表计算出数据包的下一跳,则继续处理到 RPDB 中的下一条规则。from 关键字表示对源 IP 地址的选择符,但由于也使用了 all ,所以表示所有数据包都会匹配。默认情况下,strongSwan 会插入一个优先级为 220 的策略规则。当 Ubuntu Linux 启动时,它会设置三个表:本地(id 255)、主(254)和默认(253)。本地路由表包含本地和广播地址的高优先级控制路由。这个表是供内核内部使用的,不应该从用户空间修改。主路由表是在没有指定表时使用的普通表。最后,默认表通常是空的,当没有其他表匹配时使用。

要在表中列出可用的路由(例如,local),使用以下命令之一:

1ip route list table local
2ip route list table 255

id 为 220 的表是由 strongSwan 创建的。它没有像上面三张表那样友好的名字。id 号的选择与 RPDB 中相应规则的优先级相匹配,便于识别策略规则与表之间的联系。所有由 strongSwan 创建的路由都会被插入到表 220 中。

3. 安装

1apt-get install strongswan

strongSwan 的主要配置文件是 /etc/ipsec.conf 和 /etc/ipsec.secrets 。

新版配置范例:https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2Examples

老版配置范例:https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2StrokeExamples

4. 实验环境

服务器 A 和客户机 A 各有一个只连接到 192.168.60.0/24 网络的主机接口。服务器 A 上的接口被分配的 IP 地址为 192.168.60.100 ,客户端 A 上的接口被分配的 IP 地址为 192.168.60.111 。为了使这个例子类似于现实中的例子,我们说服务器 A 和客户端 A 是站点 A 的一部分,站点 A “拥有” 网络192.168.60.0/24 。服务器 A 通过其 NAT 接口为网站 A 提供互联网访问。

相似的,服务器 B 上的网络接口被分配了 IP 地址 192.168.80.100 ,客户端 B 上的接口被分配了 IP 地址 192.168.80.111 。服务器 B 通过其 NAT 接口为 B 站点提供 Internet 访问。

服务器 A 和服务器 B 都有一个只连接到网络的二级主机接口 192.168.70.0/24 。服务器 A 的接口被分配的 IP 地址是 192.168.70.5 ,而服务器 B 的 IP 地址是 192.168.70.6 。您将配置服务器 A 和服务器 B 在 192.168.70.0/24 网络上建立 VPN 服务。

192.168.60.0/24 和 192.168.80.0/24 是私有网络,它们实际上将通过 “公共 “网络 192.168.70.0/24 连接。

5. 带 PSK 认证的 Host-to-Host Transport Mode 配置

Server A 的 ipsec.conf

 1# server A
 2# ipsec.conf - strongSwan IPsec configuration file
 3
 4# basic configuration
 5
 6config setup
 7      # strictcrlpolicy=yes
 8      # uniqueids = no
 9
10conn %default
11      ikelifetime=60m
12      keylife=20m
13      rekeymargin=3m
14      keyingtries=1
15      keyexchange=ikev2
16      mobike=no
17
18conn serverA-to-serverB
19      type=transport
20      authby=secret
21      left=192.168.70.5
22      leftsubnet=192.168.70.0/24
23      leftfirewall=yes
24      right=192.168.70.6
25      rightsubnet=192.168.70.0/24
26      auto=route

Server A 的 ipsec.secret

1# server A
2# This file holds shared secrets or RSA private keys for authentication.
3
4# RSA private key for this host, authenticating it to any other host
5# which knows the public part.
6
7192.168.70.5 192.168.70.6 : PSK "helloworld"

Server B 的 ipsec.conf

 1# server B
 2# ipsec.conf - strongSwan IPsec configuration file
 3
 4# basic configuration
 5
 6config setup
 7      # strictcrlpolicy=yes
 8      # uniqueids = no
 9
10conn %default
11      ikelifetime=60m
12      keylife=20m
13      rekeymargin=3m
14      keyingtries=1
15      keyexchange=ikev2
16      mobike=no
17
18conn serverB-to-serverA
19      type=transport
20      authby=secret
21      left=192.168.70.6
22      leftsubnet=192.168.70.0/24
23      leftfirewall=yes
24      right=192.168.70.5
25      rightsubnet=192.168.70.0/24
26      auto=route

Server B 的 ipsec.secret

1# server B
2# This file holds shared secrets or RSA private keys for authentication.
3
4# RSA private key for this host, authenticating it to any other host
5# which knows the public part.
6
7192.168.70.5 192.168.70.6 : PSK "helloworld"

您也可以在服务器 A 或服务器 B 上输入以下命令,要求 strongSwan 报告建立的连接:

1sudo ipsec statusall

6. 带证书认证的 Host-to-Host Transport Mode 配置

此处省略创建证书的过程。

教程可以参考:https://wiki.strongswan.org/projects/strongswan/wiki/SimpleCA

注意:strongSwan 不知道如何处理单个 PEM 文件中包含的证书链。相反,你需要将根 CA 和中间 CA 的单个证书复制到 strongSwan 的 CA 证书目录中。

Server A 的 ipsec.conf

 1# server A
 2# ipsec.conf - strongSwan IPsec configuration file
 3
 4# basic configuration
 5
 6config setup
 7      # strictcrlpolicy=yes
 8      # uniqueids = no
 9
10conn %default
11      ikelifetime=60m
12      keylife=20m
13      rekeymargin=3m
14      keyingtries=1
15      keyexchange=ikev2
16      mobike=no
17
18conn serverA-to-serverB
19      type=transport
20      left=192.168.70.5
21      leftcert=192.168.70.5.cert.pem
22      leftid=%fromcert
23      leftfirewall=yes
24      right=192.168.70.6
25      rightid="C=CN, ST=Beijing, L=Chaoyang, O=the masses, CN=192.168.70.6"
26      auto=route

Server A 的 ipsec.secret

1# server A
2# This file holds shared secrets or RSA private keys for authentication.
3
4# RSA private key for this host, authenticating it to any other host
5# which knows the public part.
6
7 : RSA 192.168.70.5.key.pem

Server B 的 ipsec.conf

 1# server B
 2# ipsec.conf - strongSwan IPsec configuration file
 3
 4# basic configuration
 5
 6config setup
 7      # strictcrlpolicy=yes
 8      # uniqueids = no
 9
10conn %default
11      ikelifetime=60m
12      keylife=20m
13      rekeymargin=3m
14      keyingtries=1
15      keyexchange=ikev2
16      mobike=no
17
18conn serverB-to-serverA
19      type=transport
20      left=192.168.70.6
21      leftcert=192.168.70.6.cert.pem
22      leftid=%fromcert
23      leftfirewall=yes
24      right=192.168.70.5
25      rightid="C=CN, ST=Beijing, L=Chaoyang, O=the masses, CN=192.168.70.5"
26      auto=route

Server B 的 ipsec.secret

1# server B
2# This file holds shared secrets or RSA private keys for authentication.
3
4# RSA private key for this host, authenticating it to any other host
5# which knows the public part.
6
7 : RSA 192.168.70.6.key.pem

配置完后需要重启强制 strongSwan 读取 CA 证书。

要列出已存在的 CA 证书,请输入命令:

1sudo ipsec listcacerts

7. 带证书认证的 Site-to-Site Tunnel Mode 配置

Server A 的 ipsec.conf

 1# server A
 2# ipsec.conf - strongSwan IPsec configuration file
 3
 4# basic configuration
 5
 6config setup
 7      # strictcrlpolicy=yes
 8      # uniqueids = no
 9
10conn %default
11      ikelifetime=60m
12      keylife=20m
13      rekeymargin=3m
14      keyingtries=1
15      keyexchange=ikev2
16
17conn serverA-to-serverB
18      left=192.168.70.5
19      leftcert=192.168.70.5.cert.pem
20      leftid=%fromcert
21      leftfirewall=yes
22      right=192.168.70.6
23      rightid="C=CN, ST=Beijing, L=Chaoyang, O=the masses, CN=192.168.70.6"
24      auto=route

Server A 的 ipsec.secret

1# server A
2# This file holds shared secrets or RSA private keys for authentication.
3
4# RSA private key for this host, authenticating it to any other host
5# which knows the public part.
6
7 : RSA 192.168.70.5.key.pem

Server B 的 ipsec.conf

 1# server B
 2# ipsec.conf - strongSwan IPsec configuration file
 3
 4# basic configuration
 5
 6config setup
 7      # strictcrlpolicy=yes
 8      # uniqueids = no
 9
10conn %default
11      ikelifetime=60m
12      keylife=20m
13      rekeymargin=3m
14      keyingtries=1
15      keyexchange=ikev2
16
17conn serverB-to-serverA
18      left=192.168.70.6
19      leftcert=192.168.70.6.cert.pem
20      leftid=%fromcert
21      leftfirewall=yes
22      right=192.168.70.5
23      rightid="C=CN, ST=Beijing, L=Chaoyang, O=the masses, CN=192.168.70.5"
24      auto=route

Server B 的 ipsec.secret

1# server B
2# This file holds shared secrets or RSA private keys for authentication.
3
4# RSA private key for this host, authenticating it to any other host
5# which knows the public part.
6
7 : RSA 192.168.70.6.key.pem

8. 带 IP 转发的 Site-to-Site Tunnel Mode 配置

在 Client A 上编辑 /etc/network/interfaces 并添加 gateway 192.168.60.100 。编辑 /etc/resolv.conf 并验证 nameserver 10.0.98.3 是 DNS 服务器。

在 Server A 上输入:

1sudo sysctl -w net.ipv4.ip_forward=1
2sudo sysctl -p
3sudo iptables -t nat -A POSTROUTING -j SNAT -o <interface> --to 10.0.98.100

在 Client B 上编辑 /etc/network/interfaces 并添加 gateway 192.168.80.100 。编辑 /etc/resolv.conf 并验证 nameserver 10.0.99.3 是 DNS 服务器。

在 Server B 上输入:

1sudo sysctl -w net.ipv4.ip_forward=1
2sudo sysctl -p
3sudo iptables -t nat -A POSTROUTING -j SNAT -o <interface> --to 10.0.99.100

Server A 的 ipsec.conf

 1# server A
 2# ipsec.conf - strongSwan IPsec configuration file
 3
 4# basic configuration
 5
 6config setup
 7      # strictcrlpolicy=yes
 8      # uniqueids = no
 9
10conn %default
11      ikelifetime=60m
12      keylife=20m
13      rekeymargin=3m
14      keyingtries=1
15      keyexchange=ikev2
16      mobike=no
17
18conn serverA-to-serverB
19      left=192.168.70.5
20      leftcert=192.168.70.5.cert.pem
21      leftsubnet=192.168.60.0/24
22      leftid=%fromcert
23      leftfirewall=yes
24      right=192.168.70.6
25      rightsubnet=192.168.80.0/24
26      rightid="C=CN, ST=Beijing, L=Chaoyang, O=the masses, CN=192.168.70.6"
27      auto=route

Server A 的 ipsec.secret

1# server A
2# This file holds shared secrets or RSA private keys for authentication.
3
4# RSA private key for this host, authenticating it to any other host
5# which knows the public part.
6
7 : RSA 192.168.70.5.key.pem

Server B 的 ipsec.conf

 1# server B
 2# ipsec.conf - strongSwan IPsec configuration file
 3
 4# basic configuration
 5
 6config setup
 7      # strictcrlpolicy=yes
 8      # uniqueids = no
 9
10conn %default
11      ikelifetime=60m
12      keylife=20m
13      rekeymargin=3m
14      keyingtries=1
15      keyexchange=ikev2
16      mobike=no
17
18conn serverB-to-serverA
19      left=192.168.70.6
20      leftcert=192.168.70.6.cert.pem
21      leftsubnet=192.168.80.0/24
22      leftid=%fromcert
23      leftfirewall=yes
24      right=192.168.70.5
25      rightsubnet=192.168.60.0/24
26      rightid="C=CN, ST=Beijing, L=Chaoyang, O=the masses, CN=192.168.70.5"
27      auto=route

9. iptables 中关于 IPSec 的设置

在默认为 DROP 的规则中,添加:

1# IKE negotiations
2iptables -A INPUT -p udp --sport 500 --dport 500 -j ACCEPT
3iptables -A OUTPUT -p udp --sport 500 --dport 500 -j ACCEPT
4# ESP encrypton and authentication
5iptables -A INPUT -p 50 -j ACCEPT
6iptables -A OUTPUT -p 50 -j ACCEPT

10. 参考