赞
踩
以下根据strongswan代码中的testing/tests/route-based/net2net-vti/中的测试环境,来看一下基于路由和VTI接口实现的安全连接。拓扑结构如下:
拓扑图中使用到的设备包括:虚拟主机carol和dave,以及虚拟网关moon。
sun的配置文件:/etc/swanctl/swanctl.conf,内容如下。连接home中的字段vips设置为0.0.0.0,标识carol并不请求特定的虚拟IP地址。
connections { gw-gw { local_addrs = PH_IP_SUN remote_addrs = PH_IP_MOON local { auth = pubkey certs = sunCert.pem id = sun.strongswan.org } remote { auth = pubkey id = moon.strongswan.org } children { net-net { local_ts = 0.0.0.0/0 remote_ts = 0.0.0.0/0 mark_in = 1337 mark_out = 1337 esp_proposals = aes128gcm128-x25519 } } version = 2 proposals = aes128-sha256-x25519 } }
sun的配置文件:/etc/strongswan.conf,内容如下。其中install_routes指定为0,strongswan进程不依照IPSEC子连接向内核安装路由表项。
swanctl {
load = pem pkcs1 x509 revocation constraints pubkey openssl random
}
charon-systemd {
load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 curl revocation hmac vici kernel-netlink socket-default updown
}
charon {
install_routes = 0
}
charon进程使用的是kernel-netlink插件,与内核的接口在此插件内实现。在文件:src/libcharon/plugins/kernel_netlink/kernel_netlink_net.c中,如下函数通过配置文件中的值,初始化内部的install_routes变量。
kernel_netlink_net_t *kernel_netlink_net_create()
{
private_kernel_netlink_net_t *this;
INIT(this,
.install_routes = lib->settings->get_bool(lib->settings,
"%s.install_routes", TRUE, lib->ns),
路由的添加代码位于安全策略添加代码内部,位于文件:src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c中。函数add_policy_internal负责安全策略添加,完成之后,进行相应的路由安装。函数中的注释,解释了在什么情况下安装路由。1) outbound方向的安全策略; 2) strongswan.conf中没有禁止安装; 3) 选择器并不针对特定的协议或源/目的端口; 4) 没有配置XFRM虚拟接口ID值(if_id); 5) 模式为tunnel或者BEET之一,或者为bypass类型。使用函数install_route安全路由。
static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, policy_entry_t *policy, policy_sa_t *mapping, bool update) { /* install a route, if: * - this is an outbound policy (to just get one for each child) * - routing is not disabled via strongswan.conf * - the selector is not for a specific protocol/port * - no XFRM interface ID is configured * - we are in tunnel/BEET mode or install a bypass policy */ if (policy->direction == POLICY_OUT && this->install_routes && !policy->sel.proto && !policy->sel.dport && !policy->sel.sport && !policy->if_id) { if (mapping->type == POLICY_PASS || (mapping->type == POLICY_IPSEC && ipsec->cfg.mode != MODE_TRANSPORT)) { install_route(this, policy, mapping, ipsec); } }
以下为路由安装函数install_route,其安装到选择器中的目的网段的路由,经由下一跳网关,源地址和路由设备,其中网关通常为对端的IPSEC端点地址,源地址为本端的IPSEC端点地址,设备为IPSEC使用的出口设备。
static void install_route(private_kernel_netlink_ipsec_t *this, policy_entry_t *policy, policy_sa_t *mapping, ipsec_sa_t *ipsec)
{
policy_sa_out_t *out = (policy_sa_out_t*)mapping;
route_entry_t *route;
if (charon->kernel->get_address_by_ts(charon->kernel, out->src_ts, &route->src_ip, NULL) == SUCCESS)
{
DBG2(DBG_KNL, "installing route: %R via %H src %H dev %s", out->dst_ts,
route->gateway, route->src_ip, route->if_name);
switch (charon->kernel->add_route(charon->kernel, route->dst_net,
route->prefixlen, route->gateway,
route->src_ip, route->if_name))
在配置VTI接口和路由的请求下,不需要strongswan进行自动添加路由,需要在设置strongswan.conf文件中设置install_routes为0。对于XFRM虚拟接口,不必设置此选项,在swanctl.conf文件中设置if_id_out值之后,strongswan进程不会安装路由。
moon网关的配置文件:/etc/swanctl/swanctl.conf,内容如下。其中为远程用户定义了虚拟地址池rw_pool,地址为10.3.0.0/28网段。字段mark_in和mark_out等于42,其中mark_in指定在inbound方向的policies/SA所使用的Netfilter标记mark值;而mark_out指定在outbound方向上policies/SA设置的Netfilter标记mark值。此处未指定掩码值,即使用默认的0xffffffff。
connections { gw-gw { local_addrs = PH_IP_MOON remote_addrs = PH_IP_SUN local { auth = pubkey certs = moonCert.pem id = moon.strongswan.org } remote { auth = pubkey id = sun.strongswan.org } children { net-net { local_ts = 0.0.0.0/0 remote_ts = 0.0.0.0/0 mark_in = 42 mark_out = 42 esp_proposals = aes128gcm128-x25519 } } version = 2 proposals = aes128-sha256-x25519 } }
moon网关的配置文件:/etc/strongswan.conf,内容与以上sun网关的strongswan.conf文件相同。其中install_routes等于0,表明不为IPSec连接创建路由。
操作流程如下,在两个虚拟网关moon和sun上,分别创建名称为vti-moon和vti-sun的vti虚拟隧道接口,其中vit-moon隧道接口的本地地址为moon的eth0接口地址(192.168.0.1),远端地址为sun网关的eth0接口地址(192.168.0.2)。而vti-sun隧道接口正好相反,其本地地址为sun的eth0接口地址,远端地址为moon网关eth接口地址。
隧道接口vti-moon的key值指定为42,vti-sun接口的地址指定为1337。key值代表了in/out两个方向(ikey和okey)的值。
moon::ip tunnel add vti-moon local PH_IP_MOON remote PH_IP_SUN mode vti key 42
moon::sysctl -w net.ipv4.conf.vti-moon.disable_policy=1
moon::ip link set vti-moon up
moon::ip route add 10.2.0.0/16 dev vti-moon
moon::iptables -A FORWARD -i vti-moon -j ACCEPT
moon::iptables -A FORWARD -o vti-moon -j ACCEPT
sun::ip tunnel add vti-sun local PH_IP_SUN remote PH_IP_MOON mode vti key 1337
sun::sysctl -w net.ipv4.conf.vti-sun.disable_policy=1
sun::ip link set vti-sun up
sun::ip route add 10.1.0.0/16 dev vti-sun
sun::iptables -A FORWARD -i vti-sun -j ACCEPT
sun::iptables -A FORWARD -o vti-sun -j ACCEPT
最后在两个虚拟网关sun和moon上启动strongswan进程,以及在moon网关上启动名称为net-net的子连接。
moon::systemctl start strongswan
sun::systemctl start strongswan
moon::expect-connection gw-gw
sun::expect-connection gw-gw
moon::swanctl --initiate --child net-net
以下在moon网关上使用ip tunnel命令查看创建的vti-moon接口,由于在IPSec连接建立之后,alice到bob发送了一个ping报文,产生了统计信息:
moon:~# ip -s -d tunnel list
vti-moon: ip/ip remote 192.168.0.2 local 192.168.0.1 ttl inherit key 42
RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts
1 84 0 0 0 0
TX: Packets Bytes Errors DeadLoop NoRoute NoBufs
1 84 0 0 0 0
使用ip route命令查看添加的到目的网段10.2.0.0/16的路由,经由vti-moon虚拟隧道接口。
moon:~# ip route
default via 192.168.0.254 dev eth0 onlink
10.1.0.0/16 dev eth1 proto kernel scope link src 10.1.0.1
10.2.0.0/16 dev vti-moon scope link
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.1
moon:~#
以上vti-moon接口的disable_policy选项的使能,将导致此接口相关的路由缓存设置DST_NOPOLICY标志(dst_entry->flags)。在策略检查函数xfrm_policy_check的子函数__xfrm_policy_check2中,对于转发的报文(sk为空),如果报文的路由缓存项设置了DST_NOPOLICY标志,将跳过策略检查(不执行函数__xfrm_policy_check)。
static inline int __xfrm_policy_check2(struct sock *sk, int dir, struct sk_buff *skb, unsigned int family, int reverse)
{
struct net *net = dev_net(skb->dev);
int ndir = dir | (reverse ? XFRM_POLICY_MASK + 1 : 0);
if (sk && sk->sk_policy[XFRM_POLICY_IN])
return __xfrm_policy_check(sk, ndir, skb, family);
return (!net->xfrm.policy_count[dir] && !secpath_exists(skb)) ||
(skb_dst(skb)->flags & DST_NOPOLICY) || __xfrm_policy_check(sk, ndir, skb, family);
}
iptables命令在filter表的FORWARD链中添加了如下的两条规则,允许进出vti-moon虚拟隧道接口的所有流量。
moon:~# iptables -L -v
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1 84 ACCEPT all -- vti-moon any anywhere anywhere
1 84 ACCEPT all -- any vti-moon anywhere anywhere
moon:~#
以下在sun网关上使用ip tunnel命令查看创建的vti-sun接口,其key值为1337。由于在IPSec连接建立之后,alice到bob发送了一个ping报文,产生了统计信息:
sun:~# ip -s -d tunnel list
vti-sun: ip/ip remote 192.168.0.1 local 192.168.0.2 ttl inherit key 1337
RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts
1 84 0 0 0 0
TX: Packets Bytes Errors DeadLoop NoRoute NoBufs
1 84 0 0 0 0
sun:~#
内核数据层面的报文流程可参见。
在moon网关上使用swanctl命令,可看到net-net子连接在in/out两个方向上的标记mark值,都为:0x0000002a(42),对应moon网关的vti虚拟隧道接口vti-moon。
moon:~# swanctl --list-sas --raw
list-sa event {gw-gw {uniqueid=1 version=2 state=ESTABLISHED local-host=192.168.0.1 local-port=4500 local-id=moon.strongswan.org remote-host=192.168.0.2 remote-port=4500 remote-id=sun.strongswan.org initiator=yes initiator-spi=1bce564a8545c615 responder-spi=0768c456b84f5ea2 encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519 established=554 rekey-time=12612
child-sas {net-net-1 {name=net-net uniqueid=1 reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP spi-in=c953ea00 spi-out=c6405514
mark-in=0000002a mark-out=0000002a encr-alg=AES_GCM_16 encr-keysize=128 bytes-in=84 packets-in=1 use-in=553 bytes-out=84 packets-out=1 use-out=553 rekey-time=2759 life-time=3406 install-time=554 local-ts=[0.0.0.0/0] remote-ts=[0.0.0.0/0]}}}}
list-sas reply {}
No leaks detected, 1442 suppressed by whitelist
moon:~#
注意一下的两个方向的安全策略中的mark/掩码值: mark 0x2a/0xffffffff,正是vti-moon接口的key值,由于在安全策略中源和目的地址都指定为0.0.0.0,仅按照mark值区分流量。
moon:~# ip -s xfrm policy
src 0.0.0.0/0 dst 0.0.0.0/0 uid 0
dir out action allow index 545 priority 399999 ptype main share any flag (0x00000000)
mark 0x2a/0xffffffff
tmpl src 192.168.0.1 dst 192.168.0.2
proto esp spi 0xc6405514(3326104852) reqid 1(0x00000001) mode tunnel
level required share any
enc-mask ffffffff auth-mask ffffffff comp-mask ffffffff
src 0.0.0.0/0 dst 0.0.0.0/0 uid 0
dir in action allow index 528 priority 399999 ptype main share any flag (0x00000000)
mark 0x2a/0xffffffff
tmpl src 192.168.0.2 dst 192.168.0.1
proto esp spi 0x00000000(0) reqid 1(0x00000001) mode tunnel
level required share any
enc-mask ffffffff auth-mask ffffffff comp-mask ffffffff
在sun网关上使用swanctl命令,可看到net-net子连接在in/out两个方向上的标记mark值,都为:0x00000539(1337),对应sun网关的vti虚拟隧道接口vti-sun的key值。
sun:~# swanctl --list-sas --raw
list-sa event {gw-gw {uniqueid=1 version=2 state=ESTABLISHED local-host=192.168.0.2 local-port=4500 local-id=sun.strongswan.org remote-host=192.168.0.1 remote-port=4500 remote-id=moon.strongswan.org initiator-spi=1bce564a8545c615 responder-spi=0768c456b84f5ea2 encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519 established=1265 rekey-time=12343
child-sas {net-net-1 {name=net-net uniqueid=1 reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP spi-in=c6405514 spi-out=c953ea00
mark-in=00000539 mark-out=00000539 encr-alg=AES_GCM_16 encr-keysize=128 bytes-in=84 packets-in=1 use-in=1265 bytes-out=84 packets-out=1 use-out=1265 rekey-time=2089 life-time=2695 install-time=1265 local-ts=[0.0.0.0/0] remote-ts=[0.0.0.0/0]}}}}
list-sas reply {}
No leaks detected, 1442 suppressed by whitelist
sun:~#
注意以下的两个方向的安全策略中的mark/掩码值: mark 0x539/0xffffffff,正是vti-sun接口的key值,由于在安全策略中源和目的地址都指定为0.0.0.0,仅按照mark值区分IPSEC流量。
sun:~# ip -s xfrm policy
src 0.0.0.0/0 dst 0.0.0.0/0 uid 0
dir out action allow index 545 priority 399999 ptype main share any flag (0x00000000)
mark 0x539/0xffffffff
tmpl src 192.168.0.2 dst 192.168.0.1
proto esp spi 0xc953ea00(3377719808) reqid 1(0x00000001) mode tunnel
level required share any
enc-mask ffffffff auth-mask ffffffff comp-mask ffffffff
src 0.0.0.0/0 dst 0.0.0.0/0 uid 0
dir in action allow index 528 priority 399999 ptype main share any flag (0x00000000)
mark 0x539/0xffffffff
tmpl src 192.168.0.1 dst 192.168.0.2
proto esp spi 0x00000000(0) reqid 1(0x00000001) mode tunnel
level required share any
enc-mask ffffffff auth-mask ffffffff comp-mask ffffffff
以下为sun网关发送的IKE_AUTH Responder响应消息中携带的选择器字段,可见都为0.0.0.0。
strongswan测试版本: 5.8.1
内核版本 5.0
END
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。