...
XFRM框架
IPsec基于XFRM(读作“transform”)框架实现,该框架源于USAGI项目,其目标是提供一种产品化的IPv6和IPsec协议栈。术语“transform”指的是在内核协议栈中根据一些IPsec规则转发入方向报文或者出方向报文。Linux内核2.5引入了XFRM框架,XFRM是一种协议族独立的基本框架,这意味着对于IPv4和IPv6而言存在一个通用的部分,这部分位于net/xfrm之中。IPv4和IPv6拥有各自的ESP、AH和IPCOMP实现,例如IPv4 ESP模块位于net/ipv4/esp4.c,IPv6 ESP模块在net/ipv6/esp6.c中。除此之外,IPv4和IPv6为支持XFRM基本框架还实现了一些与各自协议相关的一些模块,比如net/ipv4/xfrm4_policy.c或者net/ipv6/xfrm6_policy.c。
XFRM框架支持网络命名空间,这是一种轻量级的进程虚拟化,允许单个或者一组进程拥有自己的网络协议栈(在第14章会讨论网络命名空间)。每个网络命名空间(数据类型struct net的实例)都包含一个名为xfrm的成员,该成员是数据类型struct netns_xfrm的实例。这个对象包含很多你在本章会碰到的数据结构和变量,比如XFRM策略哈希表、XFRM状态哈希表、sysctl参数、XFRM状态垃圾回收器、计数器等等。
struct netns_xfrm {
struct hlist_head *state_bydst;
struct hlist_head *state_bysrc;
struct hlist_head *state_byspi;
. . .
unsigned int state_num;
. . .
struct work_struct state_gc_work;
. . .
u32 sysctl_aevent_etime;
u32 sysctl_aevent_rseqth;
int sysctl_larval_drop;
u32 sysctl_acq_expires;
};
(include/net/netns/xfrm.h)
XFRM初始化
在IPv4中,XFRM初始化工作在xfrm_init()函数完成,其调用栈为ip_rt_init()->xfrm4_init()->xfrm_init(),ip_rt_init()方法位于net/ipv4/route.c文件中。而在IPv6中,通过调用ipv6_route_init()方法中的xfrm6_init()方法实现了XFRM的初始化。通过创建NETLINK_XFRM类型netlink套接字(socket)并发送/接收netlink消息可以实现用户空间和内核之间的通信。
static int __net_init xfrm_user_net_init(struct net *net)
{
struct sock *nlsk;
struct netlink_kernel_cfg cfg = {
.groups = XFRMNLGRP_MAX,
.input = xfrm_netlink_rcv,
};
nlsk = netlink_kernel_create(net, NETLINK_XFRM, &cfg);
. . .
return 0;
}
从用户空间发出的消息(比如XFRM_MSG_NEWPOLICY创建新的安全策略或者XFRM_MSG_NEWSA创建新的安全联盟)会被xfrm_netlink_rcv()方法处理,该方法又会被xfrm_user_rcv_msg()方法调用(第二章曾讨论过netlink套接字)。
XFRM策略和XFRM状态是XFRM框架的基础数据结构,接下来我将陆续介绍什么是XFRM策略以及XFRM状态。
XFRM策略
安全策略是一种规则,告诉IPsec一条特定流量是否应该处理或者旁路,xfrm_policy结构用来描述IPsec策略。一个安全策略包含一个选择器(一个xfrm_selector对象)。当其选择器匹配一条流时会提供一种策略。XFRM选择器有一系列属性组成:比如source和destination address、source和destination port、protocol等等,用这些属性来识别一条流:struct xfrm_selector {
xfrm_address_t daddr;
xfrm_address_t saddr;
__be16 dport;
__be16 dport_mask;
__be16 sport;
__be16 sport_mask;
__u16 family;
__u8 prefixlen_d;
__u8 prefixlen_s;
__u8 proto;
int ifindex;
__kernel_uid32_t user;
};
(include/uapi/linux/xfrm.h)
xfrm_selector_match()方法使用XFRM selector、flow和family(IPv4对应AF_INET,IPv6对应AF_INET6)作为参数,当特定XFRM流量匹配中特定选择器时返回true。注意xfrm_selector结构同样用在XFRM状态中,在本节后续将看到。安全策略(Security Policy)使用xfrm_policy结构表示:
struct xfrm_policy {
. . .
struct hlist_node bydst;
struct hlist_node byidx;
/* This lock only affects elements except for entry. */
rwlock_t lock;
atomic_t refcnt;
struct timer_list timer;
struct flow_cache_object flo;
atomic_t genid;
u32 priority;
u32 index;
struct xfrm_mark mark;
struct xfrm_selector selector;
struct xfrm_lifetime_cfg lft;
struct xfrm_lifetime_cur curlft;
struct xfrm_policy_walk_entry walk;
struct xfrm_policy_queue polq;
u8 type;
u8 action;
u8 flags;
u8 xfrm_nr;
u16 family;
struct xfrm_sec_ctx *security;
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
};
(include/net/xfrm.h)
下面将重点介绍一些xfrm_policy结构中重要的成员:
- refcnt:XFRM引用计数,在xfrm_policy_alloc()方法中初始化为1,在xfrm_pol_hold()方法中增加计数,在xfrm_pol_put()方法中减少计数。
- timer:Per-policy定时器,定时器的回调函数在xfrm_policy_alloc()方法中的xfrm_policy_timer()里设置。xfrm_policy_timer()方法在策略到期时进行相关处理:某个策略到期后调用xfrm_policy_delete()方法时负责删除对应策略,向通过调用km_policy_expired()方法注册的Key Manager发送XFRM_MSG_POLEXPIRE事件。
- lft:XFRM策略有效期(xfrm_lifetime_cfg对象),每一个XFRM策略都有一个有效期(使用时间或者字节计数表示)。用户可以使用ip命令和限制的参数设置XFRM有效期,比如:ip xfrm policy add src 172.16.2.0/24 dst 172.16.1.0/24 limit byte-soft 6000...该命令设置XFRM策略有效期的软字节限制是6000,请参阅帮助8-ip xfrm。您可以执行ip -stat xfrm policy show命令查看有效期的配置项,显示XFRM策略的有效期(lft)。
- curlft:XFRM策略当前的有效期,反映某个策略当前有效期的情况,curlft是一个xfrm_lifetime_cur对象,由四个成员组成,每个成员都是unsigned类型的64bit属性
- bytes:IPsec子系统处理的字节数量,在Tx路径的xfrm_output_one()方法和Rx路径的xfrm_input()方法中增加。
- packets:IPsec子系统处理的报文数量,在Tx路径的xfrm_output_one()方法和Rx路径的xfrm_input()方法中增加。
- add_time:添加策略的时间戳,在xfrm_policy_insert()方法和xfrm_sk_policy_insert()方法中添加策略时初始化。
- use_time:最新一次访问策略的时间,在xfrm_lookup()方法或者_xfrm_policy_check()方法中更新use_time的时间戳,使用xfrm_policy_insert()方法和xfrm_sk_policy_insert()方法中添加策略时初始化为0。
- 注意:您可以执行ip -stat xfrm policy show命令查看有效期的配置项,显示某个XFRM策略的当前有效期(curlft)。
(未完待续)
原文源自网络,若有兴趣可直接阅读原文(http://apprize.info/linux/kernel/11.html)