ipsec是一个安全协议,它得到多个网络安全厂家的支持,各个厂家之间的设备的对接也不在话下。相比之下,虽然ssl vpn[1]百花齐放,但是服务器和客户端就只能使用同一家的,兼容性和应用的广泛性就没有ipsec这么广。

随着freeswan开发的终结和openswan的日趋式微,strongswan大有一统天下之势,连freebsd都将strongswan作为默认的ipsec实现纳入官方源中。

安装和卸载

strongswan的开发很活跃,鉴于ubuntu/debian官方源中的strongswan软件包版本比较旧,所以建议通过编译的方式来安装最新的版本。

  • 准备

    $ cd /tmp && wget https://download.strongswan.org/strongswan-5.3.5.tar.gz
    $ tar -zxvf strongswan-5.3.5.tar.gz
    $ sudo apt-get install libpam0g-dev libgmp-dev libssl-dev make gcc pkg-config libsystemd-dev libsystemd-daemon-dev libsystemd-journal-dev
  • 生成编译配置文件

    $ ./configure --prefix=/opt/strongswan --enable-md4 --enable-eap-identity --enable-eap-md5 --enable-eap-mschapv2 --enable-eap-tls --enable-eap-ttls --enable-eap-peap --enable-eap-dynamic --enable-eap-radius --enable-xauth-eap --enable-xauth-pam  --enable-dhcp  --enable-openssl  --enable-addrblock --enable-unity --enable-certexpire --enable-radattr --enable-openssl --enable-lookip --enable-duplicheck --enable-coupling --enable-vici --enable-swanctl --enable-systemd (1)
    1 debian 8的init已经从sysV转向systemd,strongswan从5.2开始也针对systemd提供了更简洁的charon-systemd实现。需要打开--enable-systemd
  • 编译安装

    $ make && sudo make install

    configure默认的prefix为/usr/local,所以make install后,配置文件位于/usr/local/etc,可执行文件和lib则安装到/usr/local/{bin, sbin, lib}中。后续如果删除的话,手工删除相应的目录即可。如果想省事,可以将prefix更改为--prefix=/opt/strongwan。那么整个软件包的文件都放在该目录下。

  • 卸载

    因为编译的时候,选择了--prefix=/opt/strongswan,所以直接手工删除这个目录即可。当然也可以:

    $ cd ~/strongswan-5.3.5
    $ make uninstall

创建pki

strongswan支持多种认证方式,证书是最重要的一种。其它认证方式还有eap、xx等。

$ cd /usr/local/etc/ipsec.d

$ sudo ipsec pki --gen --type rsa --size 4096 --outform pem > private/qmcc.key.pem
chmod 600 private/qmcc.key.pem
$ sudo ipsec pki --self --ca --lifetime 3650 --in private/qmcc.key.pem --type rsa --dn "OU=jike, CN=qmcc CA" --outform pem > cacerts/qmcc.cacert.pem

$ sudo ipsec pki --gen --type rsa --size 4096 --outform pem > private/gw3.syharman.key.pem
$ sudo chmod 600 private/gw3.syharman.key.pem

$ sudo ipsec pki --pub --in private/gw4.syharman.key.pem --type rsa | ipsec pki --issue --lifetime 3650 --cacert cacerts/qmcc.cacert.pem --cakey private/qmcc.key.pem --dn "OU=syharman, CN=gateway4.syharman.qmcc" --san gateway4.syharman.qmcc --san @xx.xx.xx.124 --flag serverAuth --flag ikeIntermediate --outform pem > certs/gw4.syharman.cert.pem

$ sudo ipsec pki --gen --type rsa --size 2048 --outform pem > private/alice.key.pem
$ sudo chmod 600 private/alice.key.pem

$ sudo ipsec pki --pub --in private/alice.key.pem --type rsa | ipsec pki --issue --lifetime 3650 --cacert cacerts/qmcc.cacert.pem --cakey private/qmcc.key.pem --dn "OU=syharman, CN=alice@syharman.qmcc" --san "alice@syharman.qmcc" --outform pem > certs/alice.cert.pem

$ sudo openssl pkcs12 -export -inkey private/alice.key.pem -in certs/aliceCert.pem -name "alice@syharman.qmcc" -certfile cacerts/qmcc.cacert.pem -caname "qmcc CA" -out p12/alice.p12

关于证书的创建,有一些黑魔法,参考下文

p12证书可通过scp、ftp、邮件的方式发送给用户的电脑上。

配置

strongswan自5.2开始,引入了swanctl,未来将取代ipsec/stroke,所以配置方式分了两种,传统的ipsec.conf和未来的swanctl.conf

/usr/local/etc/ipsec.conf
config setup

conn win7-pubkey-template
    keyexchange=ikev2
    ike=aes256-sha1-modp1024!
    esp=aes256-sha1!
    rekey=no
    left=%defaultroute
    leftauth=pubkey
    leftfirewall=yes
    leftsubnet=0.0.0.0/0
    leftcert=gw3.syharman.cert.pem
    right=%any
    rightauth=pubkey
    auto=add

conn rw-pubkey-alice
    also=win7-pubkey-template
    rightsourceip=192.168.6.2
    rightid="OU=syharman, CN=alice@syharman.qmcc"

conn rw-pubkey-bob
    also=win7-pubkey-template
    rightsourceip=192.168.6.3
    rightid="OU=syharman, CN=bob@syharman.qmcc"

#--== win7 eap-mschapv2 ==--
conn win7-eap-mschapv2-template
    keyexchange=ikev2
    ike=aes256-sha1-modp1024!
    esp=aes256-sha1!
    dpdaction=clear
    dpddelay=300s
    rekey=no
    left=%defaultroute
    leftauth=pubkey
    leftsubnet=0.0.0.0/0
    leftcert=gw3.syharman.cert.pem
    right=%any
    rightauth=eap-mschapv2
    rightsendcert=never
    eap_identity=%any
    auto=add

conn rw-mschapv2-alice
    also=win7-eap-mschapv2-template
    rightsourceip=192.168.6.11
    rightid="alice"
/usr/local/etc/ipsec.secrets
: RSA gw3.syharman.key.pem
: PSK "xxxxxxxx"
alice : EAP "xxxx"
bob : EAP "xxxx"
/usr/local/etc/strongswan.conf
charon {
       duplicheck.enable = no
       dns1 = 192.168.5.11
       dns2 = 192.168.5.12
       # for Windows only
       nbns1 = 192.168.5.11
       nbns2 = 192.168.5.12
       filelog {
               /var/log/strongswan-charon.log {
                   time_format = %b %e %T
                   ike_name = yes
                   default = 1
                   append = no
                   flush_line = yes
               }
       }
}

include strongswan.d/*.conf

操控

ipsec

  • 启动

    $ sudo ipsec start
  • 重启

  • 查看连接

swanctl

场景

strongswan官网中提到四种场景,分别是:

  • site-to-site

  • host-to-site

  • host-to-host

  • road warrior

其中,应用最广泛的是site-to-site和road warrior两种。

road warrior

在该场景下,ipsec server为gateway4.syharman.qmcc,客户端可以是linux、windows7或windows10

ipsec server(gateway4.syharman.qmcc)

ipsec.conf
config setup

#############################################
# ikev2 road warrios pubkey template
#############################################
conn ikev2-rw-pub-template
    keyexchange=ikev2
    left=%defaultroute
    leftauth=pubkey
    leftfirewall=yes
    leftsubnet=0.0.0.0/0
    leftcert=gw5.syharman.cert.pem
    leftid=gateway5.syharman.qmcc
    right=%any
    rightauth=pubkey
    auto=add

# ikev2 road warrios pubkey linux client
conn ikev2-rw-pub-linux-ssTester
    also=ikev2-rw-pub-template
    rightdns=192.168.5.12
    rightsourceip=192.168.7.10
    rightid="OU=jike, CN=ssTester@jklab.qmcc"

# ikev2 road warrios pubkey windows7+ client
conn ikev2-rw-pub-win7-alice
    also=ikev2-rw-pub-template
    ike=aes256-sha1-modp1024!
    rekey=no
    rightsourceip=192.168.7.2
    rightid="OU=syharman, CN=alice@syharman.qmcc"

ipsec client

  • linux client

    本文所使用的linux client是ubuntu 14.04/strongswan 5.3.5

    ipsec.conf
    config setup
    
    conn %default
            ikelifetime=60m
            keylife=20m
            rekeymargin=3m
            keyingtries=1
            keyexchange=ikev2
    
    conn home
            #left=192.168.111.246
            leftsourceip=%config
            leftcert=ssTester.cert.pem
            #leftid=ssTester@jklab.qmcc
            leftfirewall=yes
            right=xx.xx.xx.124
            rightsubnet=0.0.0.0/0
            rightid=gateway5.syharman.qmcc
            auto=add
  • windows 7 client:

    使用windows7自带的agile客户端即可,安装和配置详见windows7的ipsec设置

  • windows 10 client

    Windows 10的ikev2客户端似乎无法接受来自strongswan server的push route,通过以下方法可以手工添加路由:

    powershell
    set-vpnconnection syxy-ikev2 -splittunneling $True
    
    Add-VpnConnectionRoute -ConnectionName "syxy-ikev2" -DestinationPrefix 10.10.0.0/24 -PassThru
    Add-VpnConnectionRoute -ConnectionName "syxy-ikev2" -DestinationPrefix 192.168.111.0/24 -PassThru

    syxy-ikev2是vpn连接的名称,10.10.0.0/24和192.168.111.0/24是远端网段,这两条powershell指令比route add更灵活,仅当vpn连接后,这两条预设的路由才起作用,当vpn断开时,路由自动消失。通过route print可以确认。

site-to-site

下面举例说明“节点A: gateway1.jklab.qmcc”跟“节点B: gateway-3.sy-harman.qmcc”之间构建ipsec tunnle。

  • 节点A: gateway1.jklab.qmcc

    /opt/strongswan/etc/ipsec.conf
    conn jklab-syharman
        ikelifetime=60m
        keylife=20m
        rekeymargin=3m
        keyingtries=1
        keyexchange=ikev2
        mobike=no
        left=%defaultroute
        leftcert=gw1.jklab.cert.pem
        leftid=gateway1.jklab.qmcc
        leftsubnet=192.168.33.0/24,192.168.66.0/24
        leftfirewall=yes
        right=xx.xx.xx.123
        rightid=gateway3.syharman.qmcc
        rightsubnet=192.168.5.0/24,172.16.28.0/24
        auto=start
  • gateway-3.syharman.qmcc

    /opt/strongswan/etc/ipsec.conf
    conn syharman-jklab
        ikelifetime=60m
        keylife=20m
        rekeymargin=3m
        keyingtries=1
        keyexchange=ikev2
        mobike=no
        left=%defaultroute
        leftcert=gw3.syharman.cert.pem
        leftid=gateway3.syharman.qmcc
        leftsubnet=192.168.5.0/24,172.16.28.0/24
        leftfirewall=yes
        right=xx.xx.xx.189
        rightid=gateway1.jklab.qmcc
        rightsubnet=192.168.33.0/24,192.168.66.0/24
        auto=start

    下面是节点B启动后的日志:

    $ sudo ipsec start
    18866 Jan 18 16:39:29 05[NET] <syharman-jklab|93> received packet: from xx.xx.xx.189[4500] to 192.168.5.3[4500] (76 bytes)
    18867 Jan 18 16:39:29 05[ENC] <syharman-jklab|93> parsed INFORMATIONAL request 6 [ D ]
    18868 Jan 18 16:39:29 05[IKE] <syharman-jklab|93> received DELETE for IKE_SA syharman-jklab[93]
    18869 Jan 18 16:39:29 05[IKE] <syharman-jklab|93> deleting IKE_SA syharman-jklab[93] between 192.168.5.3[gateway3.syharman.qmcc]...xx.xx.xx.189[gateway1.jklab.qm      cc]
    18870 Jan 18 16:39:29 05[IKE] <syharman-jklab|93> IKE_SA deleted
    18871 Jan 18 16:39:29 05[ENC] <syharman-jklab|93> generating INFORMATIONAL response 6 [ ]
    18872 Jan 18 16:39:29 05[NET] <syharman-jklab|93> sending packet: from 192.168.5.3[4500] to xx.xx.xx.189[4500] (76 bytes)
    18873 Jan 18 16:39:29 16[NET] <94> received packet: from xx.xx.xx.189[62619] to 192.168.5.3[500] (1148 bytes)
    18874 Jan 18 16:39:29 16[ENC] <94> parsed IKE_SA_INIT request 0 [ SA KE No N(NATD_S_IP) N(NATD_D_IP) N(HASH_ALG) ]
    18875 Jan 18 16:39:29 16[IKE] <94> xx.xx.xx.189 is initiating an IKE_SA
    18876 Jan 18 16:39:29 16[IKE] <94> local host is behind NAT, sending keep alives
    18877 Jan 18 16:39:29 16[IKE] <94> remote host is behind NAT
    18878 Jan 18 16:39:29 16[IKE] <94> sending cert request for "OU=jike, CN=qmcc CA"
    18879 Jan 18 16:39:29 16[ENC] <94> generating IKE_SA_INIT response 0 [ SA KE No N(NATD_S_IP) N(NATD_D_IP) CERTREQ N(HASH_ALG) N(MULT_AUTH) ]
    18880 Jan 18 16:39:29 16[NET] <94> sending packet: from 192.168.5.3[500] to xx.xx.xx.189[62619] (481 bytes)
    18881 Jan 18 16:39:29 06[NET] <94> received packet: from xx.xx.xx.189[4500] to 192.168.5.3[4500] (2332 bytes)
    18882 Jan 18 16:39:29 06[ENC] <94> parsed IKE_AUTH request 1 [ IDi CERT N(INIT_CONTACT) CERTREQ IDr AUTH SA TSi TSr N(MULT_AUTH) N(EAP_ONLY) ]
    18883 Jan 18 16:39:29 06[IKE] <94> received cert request for "OU=jike, CN=qmcc CA"
    18884 Jan 18 16:39:29 06[IKE] <94> received end entity cert "OU=jklab, CN=gateway1.jklab.qmcc"
    18885 Jan 18 16:39:29 06[CFG] <94> looking for peer configs matching 192.168.5.3[gateway3.syharman.qmcc]...xx.xx.xx.189[gateway1.jklab.qmcc]
    18886 Jan 18 16:39:29 06[CFG] <syharman-jklab|94> selected peer config 'syharman-jklab'
    18887 Jan 18 16:39:29 06[CFG] <syharman-jklab|94>   using certificate "OU=jklab, CN=gateway1.jklab.qmcc"
    18888 Jan 18 16:39:29 06[CFG] <syharman-jklab|94>   using trusted ca certificate "OU=jike, CN=qmcc CA"
    18889 Jan 18 16:39:29 06[CFG] <syharman-jklab|94> checking certificate status of "OU=jklab, CN=gateway1.jklab.qmcc"
    18890 Jan 18 16:39:29 06[CFG] <syharman-jklab|94> certificate status is not available
    18891 Jan 18 16:39:29 06[CFG] <syharman-jklab|94>   reached self-signed root ca with a path length of 0
    18892 Jan 18 16:39:29 06[IKE] <syharman-jklab|94> authentication of 'gateway1.jklab.qmcc' with RSA_EMSA_PKCS1_SHA384 successful
    18893 Jan 18 16:39:29 06[IKE] <syharman-jklab|94> authentication of 'gateway3.syharman.qmcc' (myself) with RSA_EMSA_PKCS1_SHA384 successful
    18894 Jan 18 16:39:29 06[IKE] <syharman-jklab|94> IKE_SA syharman-jklab[94] established between 192.168.5.3[gateway3.syharman.qmcc]...xx.xx.xx.189[gateway1.jklab      .qmcc]
    18895 Jan 18 16:39:29 06[IKE] <syharman-jklab|94> scheduling reauthentication in 3353s
    18896 Jan 18 16:39:29 06[IKE] <syharman-jklab|94> maximum IKE_SA lifetime 3533s
    18897 Jan 18 16:39:29 06[IKE] <syharman-jklab|94> sending end entity cert "OU=syharman, CN=gateway3.syharman.qmcc"
    18898 Jan 18 16:39:29 06[IKE] <syharman-jklab|94> CHILD_SA syharman-jklab{362} established with SPIs c3b64fa9_i cccdb4cf_o and TS 172.16.28.0/24 192.168.5.0/24 ===       192.168.33.0/24 192.168.66.0/24
    18899 Jan 18 16:39:29 06[ENC] <syharman-jklab|94> generating IKE_AUTH response 1 [ IDr CERT AUTH SA TSi TSr N(AUTH_LFT) ]
    18900 Jan 18 16:39:29 06[NET] <syharman-jklab|94> sending packet: from 192.168.5.3[4500] to xx.xx.xx.189[4500] (2140 bytes)
    ipsec status
    $ sudo ipsec status
    Security Associations (1 up, 0 connecting):
    syharman-jklab[94]: ESTABLISHED 46 minutes ago, 192.168.5.3[gateway3.syharman.qmcc]...xx.xx.xx.189[gateway1.jklab.qmcc]
    syharman-jklab{365}:  INSTALLED, TUNNEL, reqid 92, ESP in UDP SPIs: c1df037d_i c24623f7_o
    syharman-jklab{365}:   172.16.28.0/24 192.168.5.0/24 === 192.168.33.0/24 192.168.66.0/24
    rp_filter配置
    $ sudo sysctl -a | grep rp_filter
    net.ipv4.conf.all.arp_filter = 0
    net.ipv4.conf.all.rp_filter = 0
    net.ipv4.conf.default.arp_filter = 0
    net.ipv4.conf.default.rp_filter = 0
    net.ipv4.conf.eth0.arp_filter = 0
    net.ipv4.conf.eth0.rp_filter = 0
    net.ipv4.conf.eth1.arp_filter = 0
    net.ipv4.conf.eth1.rp_filter = 0
    net.ipv4.conf.lo.arp_filter = 0
    net.ipv4.conf.lo.rp_filter = 0

因为netfilter会检查源ip地址,假如跟网卡的ip地址处于同一个网段,它就会根据路由表发送redirect给

自启动

开源界很疯狂,动不动就新造个轮子,systemd无疑是近期最轰动的,rhel7、debian8、ubuntu 15.04都已用systemd取代了sysV,虽然canoncial在ubuntu 9.10时欲以upstart取代sysV,谁知道螳螂捕蝉黄雀在后,最终也被systemd给干掉了。

下面提供两种自启动方式的配置

upstart

/etc/init/strongswan.conf
# Upstart job for strongSwan.

description     "strongSwan IPsec services"
author          "Jonathan Davies <jonathan.davies@canonical.com>"

start on (runlevel [2345] and net-device-up IFACE!=lo)
stop on runlevel [!2345]

expect fork
respawn

pre-start script
    # Create lock directory.
    mkdir -p /var/lock/subsys/
end script

post-stop script
    rm -f /var/run/charon.pid /var/run/starter.charon.pid
end script

env PIDFILE=/var/run/charon.pid

pre-start exec /usr/local/sbin/ipsec start
post-stop exec /usr/local/sbin/ipsec stop

systemd

这玩意挺复杂,待续。

troubleshooting

可以通过tcpdump来跟踪ipsec的数据包,但是ipsec都tcpdump的版本有一定的要求:libpcap4.7+,目前只有debian8的tcpdump版本能够完整支持监听nflog和打印到屏幕,debian7虽然可以监听nflog,但是不支持打印,ubuntu14.04甚至都无法监听nflog端口。

在某台strongswan(debian8)中应用以下iptables rules:

iptables -t filter -I INPUT -p esp -j NFLOG --nflog-group 5
iptables -t filter -I INPUT -p ah -j NFLOG --nflog-group 5
iptables -t filter -I INPUT -p udp -m multiport --dports 500,4500 -j NFLOG --nflog-group 5
iptables -t filter -I OUTPUT -p esp -j NFLOG --nflog-group 5
iptables -t filter -I OUTPUT -p ah -j NFLOG --nflog-group 5
iptables -t filter -I OUTPUT -p udp -m multiport --dports 500,4500 -j NFLOG --nflog-group 5
iptables -t mangle -I PREROUTING -m policy --pol ipsec --dir in -j NFLOG --nflog-group 5
iptables -t mangle -I POSTROUTING -m policy --pol ipsec --dir out -j NFLOG --nflog-group 5
iptables -t filter -I INPUT -m addrtype --dst-type LOCAL -m policy --pol ipsec --dir in -j NFLOG --nflog-group 5
iptables -t filter -I INPUT -m addrtype ! --dst-type LOCAL -m policy --pol ipsec --dir in -j NFLOG --nflog-group 5
iptables -t filter -I OUTPUT -m policy --pol ipsec --dir out -j NFLOG --nflog-group 5

然后使用下列命令可以看到加密之前的数据包:

$ sudo tcpdump -i nflog
在iptables中使用nflog target不需要安装ulogd2,但是如果希望将iptables的日志记录到文件中就只能使用ulogd2。

ubuntu14.04的tcpdump不支持nflog,使用

$ sudo tcpdump -i eth0 -n -s 0 \(port 500 or port 4500 or proto 50\)

可以看到部分ipsec的数据包,但是看不到加密之前数据包。

ipsec on openbsd

在l2tp/ipsec的年代,openbsd的isakmpd(ipsec)碾压linux openswan[2]毫无压力,因为openbsd的isakmpd配置起来非常方便,真正做到开箱即用。然而到了ikev2的年代,虽然openbsd有openiked项目,但是优先级别并不高,到目前为止网上都没有一份像样的配置示例。strongswan逐渐一统江湖。


1. openvpn是ssl vpn的一个实现
2. linux中早期的ipsec实现