xfrm: configure xfrm state and policy with iproute2

测试环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ip netns exec ns1 ip l s veth1 down
ip l delete veth0
ip netns delete ns1

ip l add type veth
ip netns add ns1

ip l s dev veth1 netns ns1
ip l set veth0 up
ip netns exec ns1 ip l set veth1 up

ip a a dev veth0 192.168.100.1/24
ip netns exec ns1 ip a a dev veth1 192.168.100.2/24
ip netns exec ns1 ip r a default via 192.168.100.1

启用转发

1
echo 1 > /proc/sys/net/ipv4/ip_forward

配置xfrm SA and SP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SRC=172.17.0.2
DST=120.244.227.44
LOCAL=172.17.0.0/16
REMOTE=192.168.1.0/24
SRC_PORT=40001
DST_PORT=18181

ID=1234
KEY=0xabcdef01234567890abcd

ip xfrm state flush && ip xfrm policy flush

ip xfrm policy add src $LOCAL dst $REMOTE dir out tmpl src $SRC dst $DST proto esp spi $ID reqid $ID mode tunnel level required
ip xfrm policy add src $REMOTE dst $LOCAL dir fwd tmpl src $DST dst $SRC proto esp spi $ID reqid $ID mode tunnel level use
ip xfrm policy add src $REMOTE dst $LOCAL dir in tmpl src $DST dst $SRC proto esp spi $ID reqid $ID mode tunnel level use

ip xfrm state add src $SRC dst $DST proto esp spi $ID reqid $ID mode tunnel enc blowfish $KEY encap espinudp $SRC_PORT $DST_PORT 0.0.0.0
ip xfrm state add src $DST dst $SRC proto esp spi $ID reqid $ID mode tunnel enc blowfish $KEY encap espinudp $DST_PORT $SRC_PORT 0.0.0.0

udp server

创建一个udp socket,并设置UDP_ENCAP_ESPINUDP属性,这样内核收到报文后,剥离掉udp头后,将报文内容当做xfrm报文处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/udp.h>

#define SERV_PORT 40000

int main()
{
int len;
int val;
struct sockaddr_in addr_serv;

int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if(sock_fd < 0)
return -EINVAL;

memset(&addr_serv, 0, sizeof(struct sockaddr_in));
addr_serv.sin_family = AF_INET;
addr_serv.sin_port = htons(SERV_PORT);
len = sizeof(addr_serv);

if (bind(sock_fd, (struct sockaddr *)&addr_serv, sizeof(addr_serv)) < 0)
goto fin;

val = UDP_ENCAP_ESPINUDP;
if (setsockopt(sock_fd, SOL_UDP, UDP_ENCAP, &val, sizeof(val)) < 0) {
printf("Set val failed\n");
goto fin;
}

while (1)
sleep(10);

fin:
close(sock_fd);

return 0;
}

常用调试命令

  • xfrm proc 统计

    1
    cat  /proc/net/xfrm_stat
  • SA: ip -s x s

  • SP: ip -s x p