0x01 前言

因为我家里有台服务器,当外出工作或见客户时可能需要连接上家里的服务器存取文件。但同时外面的免费Wi-Fi大多都不安全,所以我通过VPN 的形式访问家里的服务器。

我试过使用PPTP 、L2TP 、IPSec 和IKEv1 ,这些都不如IKEv2 安全、便捷。最重要的是IKEv2 支持移动模式,也就是无论怎样切换网络,它都会保持VPN 连接,直至客户端发送断开指令或服务端在规定时间内没接收到数据包而强制断开。

0x02 编译安装

我写这篇文章的时候最新版还是5.4.0,请你在为你自己的服务器编译时通过以下地址检查最新版本:

strongSwan – Download

#我喜欢在/root 目录下新建一个文件夹存放用于编译的源代码
mkdir -p /root/codex/ipsec

#进入文件夹
cd /root/codex/ipsec

#下载strongSwan 源代码
wget https://download.strongswan.org/strongswan-5.4.0.tar.gz

#解压
tar zxvf strongswan-5.4.0.tar.gz

#进入文件夹
cd strongswan-5.4.0

#config ,请注意我将strongSwan 安装在/usr/local/ipsec 这个目录下。
#请根据需要调整安装目录
./configure --prefix=/usr/local/ipsec \
--libexecdir=/usr/local/ipsec/libexec \
--libdir=/usr/local/ipsec/lib \
--sysconfdir=/usr/local/ipsec/etc \
--enable-certexpire  --enable-dhcp \
--enable-eap-dynamic --enable-eap-identity \
--enable-eap-md5 --enable-eap-mschapv2 \
--enable-eap-peap  --enable-eap-radius \
--enable-eap-tls --enable-openssl \
--enable-unity --enable-xauth-eap \
--enable-xauth-pam --enable-eap-tnc \
--enable-eap-ttls --enable-addrblock \
--enable-radattr --disable-gmp

##注意!OpenVZ 架构的服务器需要添加以下编译项,KVM、XEN则不需要,这可能引发安全问题:
--enable-kernel-libipsec

#编译
make

#安装
make install

#创建软连接到/usr/sbin 
ln /usr/local/ipsec/sbin/ipsec /usr/sbin/
ln /usr/local/ipsec/sbin/swanctl /usr/sbin/

0x03 数字证书

IKEv2 需要一张有效的数字证书,这里有三种选择:

  1. 自己通过ipsec pki 生成自签名的数字证书。但有3个问题:
    1. 每台设备都需要安装一个p12 文件,里面包含证书和密钥;
    2. iOS 设备在安装p12 文件之后还需要安装自签名的CA 证书;
    3. OS X 需要在钥匙串中手动将证书和密钥设为“可信”。
  2. 购买商业数字证书
  3. 免费数字证书(StartSSL 或Let’s Encrypt )

其实上面的2和3的配置方式是一样的,下面我就介绍两种配置方法。而Let’s Encrypt 的相关文章我这几天写一篇介绍和自动配置方法。

0x03.1 自签数字证书

同样的,我也新建一个文件夹,以免文件太多造成混乱

#新建文件夹
mkdir /root/codex/ipsec/ipsec_crt

#进入文件夹
cd /root/codex/ipsec/ipsec_crt

下面开始通过ipsec pki 创建自签名的数字证书和私钥

#创建CA 私钥
ipsec pki --gen --outform pem > caKey.pem

#用上面创建的CA 私钥caKey.pem 创建CA 证书
ipsec pki --self --in caKey.pem --dn "C=HK, O=Proj, CN=Proj CA" --ca --outform pem > caCert.pem

#创建服务器私钥
ipsec pki --gen --outform pem > serverKey.pem

#创建服务器证书
##注意!! "C=HK, O=Proj, CN=foo.com" --san="foo.com"
## C=国家的两位字母缩写, CN=域名,不能用IP, --san=域名,必须与CN相同且不能使用IP
ipsec pki --pub --in serverKey.pem | ipsec pki --issue --cacert caCert.pem --cakey caKey.pem --dn "C=HK, O=Proj, CN=foo.com" --san="foo.com" --flag serverAuth --flag ikeIntermediate --outform pem > serverCert.pem

#创建用户私钥
ipsec pki --gen --outform pem > clientKey.pem

#创建用户证书
ipsec pki --pub --in clientKey.pem | ipsec pki --issue --cacert caCert.pem --cakey caKey.pem --dn "C=HK, O=Proj, CN=Proj VPN Client Crt" --outform pem > clientCert.pem

#将用户私钥和证书打包为p12文件,方便传播
openssl pkcs12 -export -inkey clientKey.pem -in clientCert.pem -name "Proj VPN Client" -certfile caCert.pem -caname "Proj VPN Client Crt" -out clientCert.p12

将文件放置到正确的目录,其中clientCert.pem 和clientKey.pem 并不要求放到服务器上,只是生成p12 文件所需要而已。但为了安全,推荐另外做备份或存放在服务器上。

cp -f caKey.pem /usr/local/ipsec/etc/ipsec.d/private/
cp -f caCert.pem /usr/local/ipsec/etc/ipsec.d/cacerts/
cp -f serverCert.pem /usr/local/ipsec/etc/ipsec.d/certs/
cp -f serverKey.pem /usr/local/ipsec/etc/ipsec.d/private/

#以下文件并不强制要求放置在相应目录中,但为了多做备份,我也放置到相应目录
cp -f clientCert.pem /usr/local/ipsec/etc/ipsec.d/certs/
cp -f clientKey.pem /usr/local/ipsec/etc/ipsec.d/private/

0x03.2 商业与免费数字证书

无论是商业还是免费的数字证书的证书链至少包含一个中级证书,例如我这网站的证书:

WeChat_1466284429

证书链中的根证书(DST Root CA X3)和所有中级证书(Let’s Encrypt Authority X3)都视为CA 证书,缺一不可。而最后一项写有自己服务器域名的证书(我这里是proj.org.cn)视为服务器证书(serverCert.pem),还有服务器证书所对应的密钥(Key)。说得有点复杂,其实需要准备一下这些:

  1. Root 证书
  2. 所有中级证书
  3. 由可信机构为你域名签发的数字证书
  4. 可信机构为你域名签发的数字证书所对应的密钥

我家里服务器用的是StartCom 的免费数字证书StartSSL Free 。其实我更喜欢用Let’s Encrypt 的数字证书,过几天我再换过来。

而StartCom 签发后下载的文件里有这几个压缩包:

  1. ApacheServer.zip (有Root 证书和对应域名的证书,没有中级证书)
  2. IISServer.zip (有中级证书和对应域名的证书,没有Root 证书)
  3. NginxServer.zip (中级证书和对应域名的证书在同一个文件了,没有Root 证书)
  4. OtherServer.zip (Root 证书、中级证书和对应域名的证书都有且存放于单独文件中)

这里只需要解压第4项的OtherServer.zip 压缩包即可,将其中的文件重命名为:

  1. 1_Intermediate.crt >> caCert_Intermediate.crt
  2. root.crt >> caCert.crt
  3. your_domain.crt >> serverCert.crt

同时将域名证书对应的key 命名为:serverKey.key

分别将上面4个文件分别存放于:

cp caCert.crt /usr/local/ipsec/etc/ipsec.d/cacerts/
cp caCert_Intermediate.crt /usr/local/ipsec/etc/ipsec.d/cacerts/
cp serverCert.crt /usr/local/ipsec/etc/ipsec.d/certs/
cp serverKey.key /usr/local/ipsec/etc/ipsec.d/private/

0x04 strongswan.conf

strongswan.conf 是主要的配置文件,这个文件在:

/usr/local/ipsec/etc/strongswan.conf

配置信息如下:

charon {
  #指定DNS,这是我家里的BIND服务器地址,请根据需要作出修改
  dns1=10.1.1.2
  ikesa_table_size = 2048
  ikesa_table_segments = 16
  reuse_ikesa = no
  load_modular = yes

  #线程数
  threads = 32

  filelog {
    /var/log/strongswan/charon.log {

      #log等级,有-1,0,1,2,3,4这几个等级,等级越大,产生日志文件就越大,同时日志也就越详细。
      ##有趣的是,我尝试将log等级设为4,不到半小时就产生了1GB的日志。
      default = 0
      append = no
      flush_line = yes
      ike_name = yes
      time_format = %b %e %T
    }
  }

  syslog {
    identifier = strongswan_syslog
    daemon {
      default = 0
    }
    auth {
      default = 0
    }
  }

  plugins {
    include /usr/local/ipsec/etc/strongswan.d/charon/*.conf

    sql {
      loglevel = -1
    }
  }
 }
include /usr/local/ipsec/etc/strongswan.d/charon/*.conf

0x05 ipsec.conf

这个文件配置用户环境所需要使用的规则或方法,文件在:

/usr/local/ipsec/etc/ipsec.conf

配置信息如下:

config setup
     #唯一ID,默认为yes 。账户不能同时登录多台设备,B 上线会把已经在线上的A 强制断开!
     #这里设置为从不进行唯一性检查,如果你想要更高的安全性,请将下面这句移除
     uniqueids = never

conn %default
     auto = start
     closeaction = clear

     #每10秒向客户发送数据包以检测用户是否在线,不在线则断开!
     dpddelay = 10s

     #60秒内没收到用户发回的数据包则强制断开!
     dpdtimeout = 60s

     #30分钟内用户与服务器没有数据交互则强制断开!
     inactivity = 30m

     #每次连接的最长有效期,超过有效期则自动重新连接
     ikelifetime = 2h

     #连接最大尝试数
     keyingtries = 3
     lifetime=1h

     #ikelifetime 超时前5分钟重新协商连接,以免被强制断开!
     margintime = 5m

     #清除不响应用户的所有缓存、安全信息,Dead Peer Detection
     dpdaction = clear

     #服务器端防火墙
     leftfirewall = yes
     leftsubnet = 0.0.0.0/0
     right = %any

     #给客户端分配的IP 地址段
     rightsourceip = 10.10.1.0/24

conn IKEv2_EAP_Crt
     keyexchange = ikev2
     eap_identity = %any
     leftcert = serverCert.crt
     leftauth = pubkey
     leftid = @your-domain.com
     #rightauth = eap-radius
     rightauth = eap-mschapv2
     rightsendcert = always
     leftsendcert = always

conn IKEv1_Crt
     keyexchange = ikev2
     fragmentation = yes
     leftcert = serverCert.crt
     leftauth = pubkey
     leftca = caCert.crt
     rightauth = pubkey
     rightauth2 = xauth

0x06 ipsec.secrets

这个文件在:

/usr/local/ipsec/etc/ipsec.secrets

因为我使用的是IKEv2 ,所有这个文件里有一行记录着服务器私钥的信息,另外还有用户名和密码:

: RSA serverKey.key
username %any : EAP "password"

0x07 启动与除错

通过以下命令启动、重启和停止:

#启动
ipsec start

#重启
ipsec restart

#停止
ipsec stop

因为我的配置文件里将log的等级设为0,所以通过命令ipsec start –nofork 所获取的有用信息不多。但可以启动ipsec 后通过以下命令实时监视ipsec 的使用情况:

swanctl --log

0x08 结语

现在可以尝试连接了。