赞
踩
以下根据strongswan代码中的testing/tests/route-based/net2net-xfrmi/中的测试环境,来看一下基于路由和XFRM接口的安全连接。在配置中sun网关使用特殊值%unique-dir自动为in/out两个方向创建不同ID值的xfrm虚拟设备;而moon网关仍然使用在swanctl.conf文件中手动指定xfrm接口ID值,并且手动创建XFRM接口的方法。sun网关的strongswan进程在生成xfrm接口ID之后,由updown插件调用updown脚本完成对应的设置。拓扑结构如下:
拓扑图中使用到两个IPSec网关设备:虚拟网关moon和sun。
sun的配置文件:/etc/swanctl/swanctl.conf,内容如下。注意其中的net-net子连接配置,if_id_in和if_id_out,都指定了特殊值%unique-dir。
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 if_id_in = %unique-dir if_id_out = %unique-dir updown = /etc/updown esp_proposals = aes128gcm128-x25519 } } version = 2 proposals = aes128-sha256-x25519 } }
sun的脚本文件:/etc/updown,内容如下。在子连接建立/删除时,执行此脚本。由于在以上swanctl.conf文件中为if_id_in/if_id_out指定了特殊值%unique-dir,在执行此脚本时,将创建xfrmi虚拟接口,添加路由和iptables规则的操作。
在销毁时,删除xfrmi接口,删除添加的iptables规则。此脚本由strongswan的updown插件执行。
#!/bin/bash IF_NAME="xfrm-" IF_NAME_IN="${IF_NAME}${PLUTO_IF_ID_IN}-in" IF_NAME_OUT="${IF_NAME}${PLUTO_IF_ID_OUT}-out" case "${PLUTO_VERB}" in up-client) /usr/local/libexec/ipsec/xfrmi -n "${IF_NAME_OUT}" -i "${PLUTO_IF_ID_OUT}" -d eth0 /usr/local/libexec/ipsec/xfrmi -n "${IF_NAME_IN}" -i "${PLUTO_IF_ID_IN}" -d eth0 ip link set "${IF_NAME_OUT}" up ip link set "${IF_NAME_IN}" up ip route add 10.1.0.0/16 dev "${IF_NAME_OUT}" iptables -A FORWARD -o "${IF_NAME_OUT}" -j ACCEPT iptables -A FORWARD -i "${IF_NAME_IN}" -j ACCEPT ;; down-client) iptables -D FORWARD -o "${IF_NAME_OUT}" -j ACCEPT iptables -D FORWARD -i "${IF_NAME_IN}" -j ACCEPT ip link del "${IF_NAME_OUT}" ip link del "${IF_NAME_IN}" ;; esac
xfrmi虚拟接口的名称为:IF_NAME_IN和IF_NAME_OUT,其由三部分组成:固定的xfrm-前缀,接口ID和方向标识。此处由于指定了%unique-dir特殊值,意味着两个方向将使用不同的ID值。在文件strongswan-5.8.1/src/libcharon/sa/child_sa.c文件中,函数child_sa_create创建安全关联,其中函数allocate_unique_if_ids将根据配置分配ID值。
child_sa_t *child_sa_create(host_t *me, host_t *other, child_cfg_t *config, child_sa_create_t *data) { static refcount_t unique_id = 0, unique_mark = 0; INIT(this, .public = { .get_unique_id = _get_unique_id, .get_if_id = _get_if_id, }, .if_id_in = config->get_if_id(config, TRUE) ?: data->if_id_in_def, .if_id_out = config->get_if_id(config, FALSE) ?: data->if_id_out_def, ); if (data->if_id_in) { this->if_id_in = data->if_id_in; } if (data->if_id_out) { this->if_id_out = data->if_id_out; } allocate_unique_if_ids(&this->if_id_in, &this->if_id_out);
对于设置了IF_ID_UNIQUE_DIR标志(即%unique-dir)的in/out方向的ID值,其使用一个静态变量unique_if_id来分配id值,首先分配给in方向;其次是out方向,下文将会看到,在两个方向上都开启自动分配的情况下,in方向的ID值为1;out方向为2。ref_get函数在每次调用之后,将静态变量unique_if_id值递增一。
另外,在swanctl.conf配置文件中,也可将if_id_in/if_id_out的值设置为特殊值%unique,此配置将为in/out两个方向分配相同的ID值。
void allocate_unique_if_ids(uint32_t *in, uint32_t *out) { static refcount_t unique_if_id = 0; if (IF_ID_IS_UNIQUE(*in) || IF_ID_IS_UNIQUE(*out)) { refcount_t if_id = 0; bool unique_dir = *in == IF_ID_UNIQUE_DIR || *out == IF_ID_UNIQUE_DIR; if (!unique_dir) { if_id = ref_get(&unique_if_id); } if (IF_ID_IS_UNIQUE(*in)) { *in = unique_dir ? ref_get(&unique_if_id) : if_id; } if (IF_ID_IS_UNIQUE(*out)) { *out = unique_dir ? ref_get(&unique_if_id) : if_id; }
在文件:strongswan-5.8.1/src/libcharon/plugins/updown/updown_listener.c文件中,函数child_updown在子SA创建和删除时调用,其子函数invoke_once如下,在调用/etc/updown脚本之前,设置环境变量PLUTO_IF_ID_IN和PLUTO_IF_ID_OUT,以便脚本中使用。
static void invoke_once(private_updown_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, ...)
{
if_id = child_sa->get_if_id(child_sa, TRUE);
if (if_id)
{
push_env(envp, countof(envp), "PLUTO_IF_ID_IN=%u", if_id);
}
if_id = child_sa->get_if_id(child_sa, FALSE);
if (if_id)
{
push_env(envp, countof(envp), "PLUTO_IF_ID_OUT=%u", if_id);
}
moon网关的配置文件:/etc/swanctl/swanctl.conf,内容如下。注意其中的net-net子连接配置,if_id_out指定为1337,if_id_in指定了不同的值42。与以上sun网关的特殊值(%unique-dir)配置不同。
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 if_id_out = 1337 if_id_in = 42 esp_proposals = aes128gcm128-x25519 } } version = 2 proposals = aes128-sha256-x25519 } }
操作流程如下,由于在moon网关上明确配置了if_id_in和if_id_out值,此处创建相应ID值的xfrm虚拟接口,见如下的xfrmi命令。对于sun主机由于指定的为特殊值(%unique-dir),交由strongswan进程去处理。
随后,在moon网关上配置到sun网关背后网络的路由,经由刚创建的xfrm-moon-out设备。
moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon-out -d eth0 -i 1337
moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon-in -d eth0 -i 42
moon::ip link set xfrm-moon-out up
moon::ip link set xfrm-moon-in up
moon::ip route add 10.2.0.0/16 dev xfrm-moon-out
moon::iptables -A FORWARD -o xfrm-moon-out -j ACCEPT
moon::iptables -A FORWARD -i xfrm-moon-in -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
以上的xfrmi命令将在moon网关上创建虚拟的XFRM接口:xfrm-moon-out和xfrm-moon-in,分别指定ID值(xfrm_id)为1337和42,其底层物理接口均为eth0。可使用xfrmi -list命令进行查看。
moon:~# /usr/local/libexec/ipsec/xfrmi -list
16: xfrm-moon-out dev eth0 if_id 0x00000539 [1337]
17: xfrm-moon-in dev eth0 if_id 0x0000002a [42]
No leaks detected, 2 suppressed by whitelist
moon:~#
使用ip route命令查看为xfrm-moon-out虚拟接口添加的路由信息,目的网段10.2.0.0/16(bob主机所在网段)的流量路由到xfrm-moon-out接口。
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 xfrm-moon-out scope link
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.1
moon:~#
以下配置的iptables规则,允许目的接口为xfrm-moon-out虚拟接口的所有流量,或者源接口为xfrm-moon-in虚拟接口的所有流量。
moon:~# iptables -L -n -v
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1 84 ACCEPT all -- * xfrm-moon-out 0.0.0.0/0 0.0.0.0/0
1 84 ACCEPT all -- xfrm-moon-in * 0.0.0.0/0 0.0.0.0/0
以下为moon网关发起net-net子连接时,sun网关上strongswan的与xfrm有关的日志信息。
sun charon-systemd: 15[IKE] CHILD_SA net-net{1} established with SPIs c0d94a84_i c9dc4b42_o and TS 0.0.0.0/0 === 0.0.0.0/0
sun charon-systemd: 15[CHD] updown: No leaks detected, 1 suppressed by whitelist
sun charon-systemd: 15[CHD] updown: No leaks detected, 1 suppressed by whitelist
sun charon-systemd: 16[KNL] interface xfrm-2-out activated
sun charon-systemd: 07[KNL] fe80::dda6:63cc:3554:b7b0 appeared on xfrm-2-out
sun charon-systemd: 10[KNL] interface xfrm-1-in activated
sun charon-systemd: 11[KNL] fe80::5f6b:9f2f:f29:3d4c appeared on xfrm-1-in
对于sun网关,由于其if_id_in/out指定为值%unique-dir,其xfrmi虚拟接口,相关路由和iptables规则,都是由以上的updown脚本所生成。
sun:~# /usr/local/libexec/ipsec/xfrmi -list
16: xfrm-2-out dev eth0 if_id 0x00000002 [2]
17: xfrm-1-in dev eth0 if_id 0x00000001 [1]
No leaks detected, 2 suppressed by whitelist
sun:~#
使用ip route命令查看为xfrm-2-out虚拟接口添加的路由信息,目的网段10.1.0.0/16(alice主机所在网段)的流量路由到xfrm-2-out接口。
sun:~# ip route
default via 192.168.0.254 dev eth0 onlink
10.1.0.0/16 dev xfrm-2-out scope link
10.2.0.0/16 dev eth1 proto kernel scope link src 10.2.0.1
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.2
sun:~#
以下配置的iptables规则,允许目的接口为xfrm-2-out虚拟接口的所有流量,或者源接口为xfrm-1-in虚拟接口的所有流量。
sun:~# iptables -L -n -v
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1 84 ACCEPT all -- * xfrm-2-out 0.0.0.0/0 0.0.0.0/0
1 84 ACCEPT all -- xfrm-1-in * 0.0.0.0/0 0.0.0.0/0
如果在alice主机上ping网关sun后面的主机bob,报文的源地址为alice的eth0接口地址10.1.0.10,目的地址为bob的eth0接口地址10.2.0.10。报文首先到达moon网关,根据moon网关上的路由配置,将其由接口xfrm-moon-out发出。执行其发送函数:xfrmi_xmit,将流结构的成员flowi_oif出接口,替换为XFRM虚拟接口所依据的底层物理接口的索引,例如以上的eth0接口的索引。
static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct xfrm_if *xi = netdev_priv(dev);
struct flowi fl;
memset(&fl, 0, sizeof(fl));
...
fl.flowi_oif = xi->phydev->ifindex;
ret = xfrmi_xmit2(skb, dev, &fl);
第二阶段的发送函数xfrmi_xmit2如下,其中xfrm_lookup_with_ifid函数,将根据流信息fl和if_id(此处为1337),查找匹配的xfrm策略,最终将生成xfrm_dst结构的路由信息结构,并绑定xfrm策略和状态state,最后由dst_output执行发送。
static int xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) { struct xfrm_if *xi = netdev_priv(dev); struct dst_entry *dst = skb_dst(skb); struct net_device *tdev; struct xfrm_state *x; dst_hold(dst); dst = xfrm_lookup_with_ifid(xi->net, dst, fl, NULL, 0, xi->p.if_id); x = dst->xfrm; if (x->if_id != xi->p.if_id) goto tx_err_link_failure; ... err = dst_output(xi->net, skb->sk, skb);
此处省略sun网关的处理过程,假设bob的回复报文到达moon网关。将由如下的xfrmi_rcv_cb函数处理,其中子函数xfrmi_lookup将xfrm状态结构中的的if_id(此处为42),与保存在网络命名空间中的xfrmi虚拟接口结构中的if_id做比较,查找对应的xfrm虚拟输入接口。
static int xfrmi_rcv_cb(struct sk_buff *skb, int err) { struct xfrm_state *x; struct xfrm_if *xi; x = xfrm_input_state(skb); xi = xfrmi_lookup(xs_net(x), x); if (!xi) return 1; dev = xi->dev; skb->dev = dev; static struct xfrm_if *xfrmi_lookup(struct net *net, struct xfrm_state *x) { struct xfrmi_net *xfrmn = net_generic(net, xfrmi_net_id); struct xfrm_if *xi; for_each_xfrmi_rcu(xfrmn->xfrmi[0], xi) { if (x->if_id == xi->p.if_id && (xi->dev->flags & IFF_UP)) return xi;
在moon网关上使用swanctl命令,可看到SA子连接信息在in/out两个方向上的接口ID值:0x0000002a(42)和0x00000539(1337),分别对应着moon的xfrmi虚拟接口xfrm-moon-in和xfrm-moon-out。
moon:~# swanctl --list-sas
gw-gw: #4, ESTABLISHED, IKEv2, 0a1b1b5c67a915ec_i ff721e588788eed3_r*
local 'moon.strongswan.org' @ 192.168.0.1[4500]
remote 'sun.strongswan.org' @ 192.168.0.2[4500]
AES_CBC-128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/CURVE_25519
established 9878s ago, rekeying in 4177s
net-net: #16, reqid 1, INSTALLED, TUNNEL, ESP:AES_GCM_16-128/CURVE_25519
installed 1232s ago, rekeying in 2220s, expires in 2728s
in c2413a11 (-|0x0000002a), 0 bytes, 0 packets
out c56daa73 (-|0x00000539), 0 bytes, 0 packets
local 0.0.0.0/0
remote 0.0.0.0/0
No leaks detected, 1442 suppressed by whitelist
moon:~#
在sun网关上使用swanctl命令的选项raw,可以更清晰的看到if-id-in和if-id-out的值,分别对应值updown脚本创建的xfrm虚拟设备:xfrm-1-in和xfrm-2-out。
sun:~# swanctl --list-sas --raw
list-sa event {gw-gw {uniqueid=4 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=yes initiator-spi=0a1b1b5c67a915ec responder-spi=ff721e588788eed3 encr-alg=AES_CBC encr-keysize=128 integ-alg=HMAC_SHA2_256_128 prf-alg=PRF_HMAC_SHA2_256 dh-group=CURVE_25519 established=10125 rekey-time=3701 child-sas {net-net-16 {name=net-net uniqueid=16 reqid=1 state=INSTALLED mode=TUNNEL protocol=ESP spi-in=c56daa73 spi-out=c2413a11
if-id-in=00000001 if-id-out=00000002 encr-alg=AES_GCM_16 encr-keysize=128 dh-group=CURVE_25519 bytes-in=0 packets-in=0 bytes-out=0 packets-out=0 rekey-time=1908 life-time=2481 install-time=1479 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:~#
strongswan版本: 5.8.1
内核版本: 5.0
END
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。