以下根据strongswan代码中的testing/tests/ikev2/nat-rw-mark/中的测试环境,在安全连接的两个节点之间存在NAT网关的情况,并且在安全网关上对外部连接的端点地址在访问内部网络之前,执行SNAT操作,适用于外部的分支使用与总部不同网段地址的情况。拓扑结构如下:

多个vlan共用一个网关_IP

拓扑图中使用到的设备包括:虚拟网关moon和sun。

sun网关配置

sun的配置文件:/etc/ipsec.conf,内容如下。注意其中的alice和venus子连接配置,前者指定了mark值10;后者venus的mark值为20,两者的掩码值都是0xffffffff。另外在sun连接中指定了leftupdown字段的执行脚本文件:/etc/mark_updown,随后将介绍到。alice和venus连接的also字段为sun连接,表示包含sun的配置。

conn alice
        rightid=alice@strongswan.org
        mark=10/0xffffffff
        also=sun
        auto=add

conn venus
        rightid=@venus.strongswan.org
        mark=20  #0xffffffff is used by default
        also=sun
        auto=add

conn sun
        left=PH_IP_SUN
        leftcert=sunCert.pem
        leftid=@sun.strongswan.org
        leftsubnet=10.2.0.0/16
        leftupdown=/etc/mark_updown
        right=%any
        rightsubnet=0.0.0.0/0

以下为脚本/etc/mark_updown的部分内容。首先,由于在以上配置文件ipsec.conf中指定了每个连接的mark字段值,需要关注在PREROUTING链上的mangle表规则,其通过匹配对短地址PLUTO_PEER以及可能的UDP源端口PLUTO_UDP_ENC,为报文增加mark标记值(PLUTO_MARK_IN)。主要用于在这些报文离开sun网关,进入其内网时,在POSTROUTING节点,依据mark标记值,进行SNAT转换,参见以下的介绍。

除此之外,为filter表的规则添加,主要是

IPSEC_POLICY="-m policy --pol ipsec --proto $PLUTO_PROTO --reqid $PLUTO_REQID"
IPSEC_POLICY_IN="$IPSEC_POLICY --dir in"
IPSEC_POLICY_OUT="$IPSEC_POLICY --dir out"

# is there an inbound mark to be set?
if [ -n "$PLUTO_MARK_IN" ]
then
        if [ -n "$PLUTO_UDP_ENC" ]
        then
                SET_MARK="-p udp --sport $PLUTO_UDP_ENC"
        else
                SET_MARK="-p $PLUTO_PROTO"
        fi
        SET_MARK="$SET_MARK -s $PLUTO_PEER -j MARK --set-mark $PLUTO_MARK_IN"
fi

# resolve octal escape sequences
PLUTO_MY_ID=`printf "$PLUTO_MY_ID"`
PLUTO_PEER_ID=`printf "$PLUTO_PEER_ID"`

case "$PLUTO_VERB:$1" in
up-client:)
        # connection to my client subnet coming up If you are doing a custom version, firewall commands go here.
        if [ -n "$PLUTO_MARK_IN" ]
        then
            iptables -t mangle -A PREROUTING $SET_MARK
        fi
        if [ "$PLUTO_PEER_CLIENT" != "$PLUTO_MY_SOURCEIP/32" ]
        then
          iptables -I FORWARD 1 -o $PLUTO_INTERFACE -p $PLUTO_PEER_PROTOCOL -s $PLUTO_MY_CLIENT $S_MY_PORT \
              -d $PLUTO_PEER_CLIENT $D_PEER_PORT $IPSEC_POLICY_OUT -j ACCEPT
          iptables -I FORWARD 1 -i $PLUTO_INTERFACE -p $PLUTO_MY_PROTOCOL -s $PLUTO_PEER_CLIENT $S_PEER_PORT \
              -d $PLUTO_MY_CLIENT $D_MY_PORT $IPSEC_POLICY_IN -j ACCEPT
        fi

对于alice和venus两个连接,sun网关的mark_updown脚本,实际上加入了以下的iptables规则:

iptables -t mangle -A PREROUTING -s 192.168.0.1/32 -p udp -m udp --sport 4510 -j MARK --set-xmark 0xa/0xffffffff
iptables -t mangle -A PREROUTING -s 192.168.0.1/32 -p udp -m udp --sport 4520 -j MARK --set-xmark 0x14/0xffffffff

iptables -t filter -A FORWARD -s 10.1.0.0/25 -d 10.2.0.0/16 -i eth0 -m policy --dir in --pol ipsec --reqid 2 --proto esp -j ACCEPT
iptables -t filter -A FORWARD -s 10.2.0.0/16 -d 10.1.0.0/25 -o eth0 -m policy --dir out --pol ipsec --reqid 2 --proto esp -j ACCEPT
iptables -t filter -A FORWARD -s 10.1.0.0/25 -d 10.2.0.0/16 -i eth0 -m policy --dir in --pol ipsec --reqid 1 --proto esp -j ACCEPT
iptables -t filter -A FORWARD -s 10.2.0.0/16 -d 10.1.0.0/25 -o eth0 -m policy --dir out --pol ipsec --reqid 1 --proto esp -j ACCEPT

主机配置

alice主机的配置文件:/etc/ipsec.conf ,内容如下。主机venus的配置与alice大致相同。

config setup

conn nat-t
        left=%defaultroute
        leftsubnet=10.1.0.0/25
        leftcert=aliceCert.pem
        leftid=alice@strongswan.org
        leftfirewall=yes
        lefthostaccess=yes
        right=PH_IP_SUN
        rightid=@sun.strongswan.org
        rightsubnet=10.2.0.0/16
        auto=add

连接建立

操作流程如下,在此拓扑中,在主机(alice和venus)与安全网关sun之间,需要经过NAT网关moon,以下为moon相关的SNAT配置命令。对于TCP协议的报文将其源地址变换为moon网关eth0接口的地址(192.168.0.1),源端口号由系统选择(此测试中被没有TCP报文)。但是,对于UDP报文,SNAT配置有所不同,源端口为500/4500的alice的报文,SNAT之后使用510/4510端口号;而源端口为500/4500的venus的报文,SNAT之后使用520/4520源端口号。之后将会看到,在安全网关sun上,由于alice和venus的报文经过了SNAT,只能以源端口号做区分,所以在此处将两者的流量指定为不同的固定源端口。

moon::iptables -t nat -A POSTROUTING -o eth0 -s 10.1.0.0/16 -p tcp -j SNAT --to PH_IP_MOON
moon::iptables -t nat -A POSTROUTING -o eth0 -s PH_IP_ALICE -p udp --sport 500  -j SNAT --to PH_IP_MOON:510
moon::iptables -t nat -A POSTROUTING -o eth0 -s PH_IP_VENUS -p udp --sport 500  -j SNAT --to PH_IP_MOON:520
moon::iptables -t nat -A POSTROUTING -o eth0 -s PH_IP_ALICE -p udp --sport 4500 -j SNAT --to PH_IP_MOON:4510
moon::iptables -t nat -A POSTROUTING -o eth0 -s PH_IP_VENUS -p udp --sport 4500 -j SNAT --to PH_IP_MOON:4520

以下sun网关的SNAT配置,目的是在alice或venus的流量进入sun网关的内网之前,将其源地址变换为地址PH_IP_CAROL10(10.3.0.10)和PH_IP_DAVE10(10.3.0.20)。这里匹配的是mark值10和20,在alice或venus的流量进入sun网关时,在PREROUTING链上,mangle表中的规则将依据源地址和源端口(主要是后者,因为源地址相同),为报文增加mark标记。才可在POSTROUTING中使用此标记。PREROUTING链的MARK标记规则由文件mark_updown添加。

最后两条mangle表的配置语句,目的在于,依据sun的内网回复报文的目的地址,为报文增加mark标记10或者20,以匹配之前的SNAT转换,执行反向变化,依据mark值将报文目的地址PH_IP_CAROL10(10.3.0.10)和PH_IP_DAVE10(10.3.0.20)分别还原为alice和venus的源地址和源端口。

sun::iptables -t nat -A POSTROUTING -o eth1 -m mark --mark 10 -j SNAT --to PH_IP_CAROL10
sun::iptables -t nat -A POSTROUTING -o eth1 -m mark --mark 20 -j SNAT --to PH_IP_DAVE10
sun::iptables -t mangle -A PREROUTING -d PH_IP_CAROL10 -j MARK --set-mark 10
sun::iptables -t mangle -A PREROUTING -d PH_IP_DAVE10 -j MARK --set-mark 20

最后在网关sun和主机alice/venus上启动strongswan进程,以及在alice和venus上启动名称为nat-t的连接。

sun::ipsec start
alice::ipsec start
venus::ipsec start
sun::expect-connection alice
sun::expect-connection venus
alice::expect-connection nat-t
alice::ipsec up nat-t
venus::expect-connection nat-t
venus::ipsec up nat-t

安全策略和关联

在sun网关上使用查看安全关联信息,可见不论是alice还是venus的安全策略,其基本内容都是相同的,唯一的区别是两者的mark值不同。以下前一个reqid为2的为venus的fwd方向安全策略,其mark值为20;后一个reqid为1的是alice的fwd方向连接策略,其mark值为10。

src 10.1.0.0/25 dst 10.2.0.0/16 uid 0
        dir fwd action allow index 98 priority 379007 ptype main share any flag  (0x00000000)
        mark 0x14/0xffffffff
        tmpl src 192.168.0.1 dst 192.168.0.2
                proto esp spi 0x00000000(0) reqid 2(0x00000002) mode tunnel
                level required share any
                enc-mask ffffffff auth-mask ffffffff comp-mask ffffffff

src 10.1.0.0/25 dst 10.2.0.0/16 uid 0
        dir fwd action allow index 74 priority 379007 ptype main share any flag  (0x00000000)
        mark 0xa/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网关上的安全关联,对于由sun网关到alice或者venus方向的安全关联(192.168.0.2->192.168.0.1),内容基本上是相同的,唯一的区别就是mark值的不同,对于不同的mark值,在进行UDP封装时,将选择不同的目的端口号。mark值为10(对应于alice),使用4510的目的端口;而对于mark值为20的关联,使用4520的目的端口号。

src 192.168.0.2 dst 192.168.0.1
        proto esp spi 0xc552aa8a(3310529162) reqid 2(0x00000002) mode tunnel
        replay-window 0 seq 0x00000000 flag af-unspec (0x00100000)
        mark 0x14/0xffffffff
        auth-trunc hmac(sha256) 0xf8d0ea121bbb28793200bf9c261dbe266de4a99a7c33aaf27c5f27f4b16ac412 (256 bits) 128
        enc cbc(aes) 0x302fedceacff7214b6037ee9a032021b (128 bits)
        encap type espinudp sport 4500 dport 4520 addr 0.0.0.0
src 192.168.0.1 dst 192.168.0.2
        proto esp spi 0xc3892214(3280544276) reqid 2(0x00000002) mode tunnel
        replay-window 32 seq 0x00000000 flag af-unspec (0x00100000)
        auth-trunc hmac(sha256) 0xb142cbbcd3d988725c06cd60ee484bc548458f2f8ad99243ed9650c5c481030f (256 bits) 128
        enc cbc(aes) 0x7ef7c4e1b8420a179f5ec354d9386714 (128 bits)
        encap type espinudp sport 4520 dport 4500 addr 0.0.0.0

src 192.168.0.2 dst 192.168.0.1
        proto esp spi 0xc26cdaec(3261913836) reqid 1(0x00000001) mode tunnel
        replay-window 0 seq 0x00000000 flag af-unspec (0x00100000)
        mark 0xa/0xffffffff
        auth-trunc hmac(sha256) 0xcbdd3d1117ded84ae1cd29a52e9b366c476c6f5de9fad74bae4958683540785f (256 bits) 128
        enc cbc(aes) 0x7ef9b749b5cfafbf495ec10be351496e (128 bits)
        encap type espinudp sport 4500 dport 4510 addr 0.0.0.0
src 192.168.0.1 dst 192.168.0.2
        proto esp spi 0xc8e3da92(3370375826) reqid 1(0x00000001) mode tunnel
        replay-window 32 seq 0x00000000 flag af-unspec (0x00100000)
        auth-trunc hmac(sha256) 0x46f470bc0cdb9e818caea156e713304c5a1114923d58bb70df9d7bb7ea0bb00e (256 bits) 128
        enc cbc(aes) 0x0fa39884fe5eaf614d41199dc81c1ce2 (128 bits)
        encap type espinudp sport 4510 dport 4500 addr 0.0.0.0

报文流程

假设有alice发送ping报文到bob主机,中间经过NAT网关moon和安全网关sun。ping报文在alice主机中经过加密处理,封装UDP报头之后发往moon网关,此时报文的源端口为4500,根据moon网关的以下SNAT规则,在发出报文时,将其源端口变换为4510,源地址变换为moon网关地址(192.168.0.1)。

moon::iptables -t nat -A POSTROUTING -o eth0 -s PH_IP_ALICE -p udp --sport 4500 -j SNAT --to PH_IP_MOON:4510

在到达安全网关sun之后,以下PREROUTING链表的规则,将为此报文增加mark值:0xa(10)。

iptables -t mangle -A PREROUTING -s 192.168.0.1/32 -p udp -m udp --sport 4510 -j MARK --set-xmark 0xa/0xffffffff

之后,根据以下的安全关联,对数据包进行解密和解封装处理。

src 192.168.0.1 dst 192.168.0.2
        proto esp spi 0xc8e3da92(3370375826) reqid 1(0x00000001) mode tunnel
        replay-window 32 seq 0x00000000 flag af-unspec (0x00100000)
        auth-trunc hmac(sha256) 0x46f470bc0cdb9e818caea156e713304c5a1114923d58bb70df9d7bb7ea0bb00e (256 bits) 128
        enc cbc(aes) 0x0fa39884fe5eaf614d41199dc81c1ce2 (128 bits)
        encap type espinudp sport 4510 dport 4500 addr 0.0.0.0

再由sun安全网关转发报文之前,在POSTROUTING链表根据报文的mark值,进行SNAT转换,将其源地址变更为PH_IP_CAROL10(10.3.0.10)。此后报文发送到bob主机。

sun::iptables -t nat -A POSTROUTING -o eth1 -m mark --mark 10 -j SNAT --to PH_IP_CAROL10

以上ping报文的请求处理完成,之后为bob返回ping回复。在回复报文返回到sun网关时,根据以下规则,为此报文重新打上mark值10。以及将报文的目的地址(PH_IP_CAROL10),转换回alice的主机地址10.1.0.10。

sun::iptables -t mangle -A PREROUTING -d PH_IP_CAROL10 -j MARK --set-mark 10

通过匹配以下策略及安全关联,对回复报文进行加密和封装,发送到NAT网关moon,由其经过DNAT变换,转发给alice主机。

src 10.2.0.0/16 dst 10.1.0.0/25 uid 0
        dir out action allow index 81 priority 379007 ptype main share any flag  (0x00000000)
        mark 0xa/0xffffffff
        tmpl src 192.168.0.2 dst 192.168.0.1
                proto esp spi 0xc26cdaec(3261913836) reqid 1(0x00000001) mode tunnel
                level required share any
                enc-mask ffffffff auth-mask ffffffff comp-mask ffffffff
				
src 192.168.0.2 dst 192.168.0.1
        proto esp spi 0xc26cdaec(3261913836) reqid 1(0x00000001) mode tunnel
        replay-window 0 seq 0x00000000 flag af-unspec (0x00100000)
        mark 0xa/0xffffffff
        auth-trunc hmac(sha256) 0xcbdd3d1117ded84ae1cd29a52e9b366c476c6f5de9fad74bae4958683540785f (256 bits) 128
        enc cbc(aes) 0x7ef9b749b5cfafbf495ec10be351496e (128 bits)
        encap type espinudp sport 4500 dport 4510 addr 0.0.0.0

以下为在sun网关上抓取的报文截图:

多个vlan共用一个网关_ipsec_02

venus主机与bob主机通信的流程基本相同,区别仅在于mark值的不同。

strongswan版本: 5.8.1
内核版本: 5.0

END