Skip to content
This repository has been archived by the owner on Nov 1, 2023. It is now read-only.

Latest commit

 

History

History
240 lines (181 loc) · 5.71 KB

StrongSwan.org

File metadata and controls

240 lines (181 loc) · 5.71 KB

StrongSwan

用作实验室内部环境的VPN。

我很喜欢IKEv2的 Traffic Selector Narrowing,这样服务器和客户机可以分别制定策略, 决定到底哪些流量通过IPSec传输。 我不喜欢了……本来路由和 NAT 规则就已经很乱了, 半路杀出来 IPSec,光制定能通的策略就已经非常繁琐……万一出了问题完全不会调试。

看看它能支持多少路由表吧。

注意

在CentOS 7中,原本的ipsec命令似乎改名为strongswan。

安装

zh_CN en_US: Installation

CentOS 7

sudo yum install -y epel-release
sudo yum install -y strongswan

ArchLinux

之所以在自己电脑上装,主要是为了管理PKI。

sudo pacman -S strongswan

PKI

见一个非常简单的strongswan pki脚本

配置

名字里*不要*带点!(’.’)会和swanctl本身的配置解析冲突!

strongswan真的是……选项超多。

  • 可以选传统ipsec.conf风格的配置,也可以选最新的stronswan.conf风格,这里选择后者
  • 可以选择IKEv1,或者v2,这里选择v2
  • 各种认证方式,这里选择和OpenVPN最类似的公钥体系
  • 还有很多看不懂的选项……

关于路由的选择

traffic selector: 用于匹配包的 目标 地址。

Initiator(客户端)和Responder(服务器端)各自可以有 local_ts/remote_ts (Traffic Selector,流选择),而IKEv2规定,最终的IPSec策略是在两者的ts之间取交集 (narrowing),因此可以相对灵活地由客户或者服务器端 配合决定 哪些流量通过IPSec传输。

关于IPv6的ND

官方文档说得挺清楚。就是万一ND等本地组播的地址也被Tunnel了,本地端口的 link local 协商会被影响,估计拿不到 fe80**的地址了。解决办法是在 ND 被影响的端加入一 个本地的 connection,盖住 ND 使它不走IPSec

connections {
  ...
  ndp {
    children {
      ns {
        local_ts = ::/0[ipv6-icmp/135]
        remote_ts = ::/0[ipv6-icmp/135]
        mode = pass
        start_action = trap
      }
      na {
        local_ts = ::/0[ipv6-icmp/136]
        remote_ts = ::/0[ipv6-icmp/136]
        mode = pass
        start_action = trap
      }
    }
  }
}

RoadWarrior(Host-To-Site)

通过IPSec连接访问某些内网,客户访问其它站点不受影响:服务器端不做NAT。但是还是有可能要做端口转发。

Responsder(服务器端)

connections {
   roadwarriors {
      version = 2
      local_addrs = ip,ip6

      pools = v4pool,v6pool
      local {
         auth = pubkey
         certs = server-cert.pem
         id = vm0.lab.ivi2.org
      }
      remote {
         auth = pubkey
         cacerts = ca-cert.pem
     }
      children {
         net {
            local_ts = 172.16.21.0/24
         }
      }
   }
}
pools {
   v4pool {
      addrs = 172.16.254.0/24
   }
   v6pool {
      addrs = fddc:ffff::0/64
   }
}

Initiator(客户端)

connections {
   lab {
      version = 2
      vips = 0.0.0.0, ::
      remote_addrs = ip,ip6

      local {
         auth = pubkey
         certs = user-cert.pem
         id = user
      }
      remote {
         auth = pubkey
         cacerts = ca-cert.pem
         id = vm0.lab.ivi2.org
     }
      children {
         lab {
            remote_ts = 0.0.0.0/0,::/0
            start_action = trap
         }
      }
   }
}

启动

Responsder

首先配置防火墙!

sudo firewall-cmd --zone=public --add-service="ipsec" --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

注意在 children 配置里没有 start_action,默认为 none 。Responsder 是这样配的。

sudo systemctl enable strongswan-swanctl
sudo systemctl start strongswan-swanctl
# sudo swanctl --load-all

Initiator

不同的 start_action 行为:

  • none: 只加载,等着用 swanctl -i -c children
  • trap: 有匹配 children 的流量出现时建立连接(准确说是协商 SA)
  • start: 立即建立连接

调试

抓包的方法需要 IPtables 配合。从另一个角度讲,也可以帮助 Debug IPtables 规则。

校园网

校园网用的公网IP所以看不出NAT。但是即便使用

connections.<conn>.encap = yes

也没用。忧郁。

SELinux

默认的 SELinux profile 会导致 strongswan-swanctl 的 systemd service 中,swanctl 执行权限不够。

cat <<EOF >swanctl-local.te
module swanctl-local 1.0;

require {
	type ipsec_conf_file_t;
	type ipsec_mgmt_t;
	class dir { open read search };
}

#============= ipsec_mgmt_t ==============

allow ipsec_mgmt_t ipsec_conf_file_t:dir { open read search };
EOF
checkmodule -M -m -o swanctl-local.mod swanctl-local.te
semodule_package -o swanctl-local.pp -m swanctl-local.mod
semodule -i swanctl-local.pp

调试记录

# 重启

sudo setenforce 0
sudo systemctl restart strongswan-swanctl
sudo ausearch  -m AVC | grep swan
sudo grep ipsec_mgmt_t /var/log/audit/audit.log | sudo audit2allow -m swanctl-local > swanctl-local.te

Masquerade

如果客户通过 IPSec 默认路由到服务器上,本地不可以再做 MASQUERADE 等 SNAT,否则源地址是错的。

iptables -t nat -I POSTROUTING -m policy --pol ipsec --dir out -j ACCEPT

遗憾的是,nftables 暂时还没有这个功能。需要通过标记等方式实现类似的东西。