基于路由和VTI隧道接口的net2net的IPSec实现

以下根据strongswan代码中的testing/tests/route-based/net2net-vti/中的测试环境,来看一下基于路由和VTI接口实现的安全连接。拓扑结构如下:

在这里插入图片描述

拓扑图中使用到的设备包括:虚拟主机carol和dave,以及虚拟网关moon。

sun网关配置

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网关配置

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值