日期:2014-05-16 浏览次数:20871 次
6. 通知回调处理
6.1 初始化
在pf_key的初始化函数中定义了通知回调结构pfkeyv2_mgr:
err = xfrm_register_km(&pfkeyv2_mgr);
该结构定义如下:
static struct xfrm_mgr pfkeyv2_mgr =
{
.id = "pfkeyv2",
.notify = pfkey_send_notify,
.acquire = pfkey_send_acquire,
.compile_policy = pfkey_compile_policy,
.new_mapping = pfkey_send_new_mapping,
.notify_policy = pfkey_send_policy_notify,
};
6.2 登记
/* net/xfrm/xfrm_state.c */
// 就是把xfrm_mgr结构挂接到xfrm_km_list链表
int xfrm_register_km(struct xfrm_mgr *km)
{
write_lock_bh(&xfrm_km_lock);
// 将结构挂接到xfrm_km_list链表
list_add_tail(&km->list, &xfrm_km_list);
write_unlock_bh(&xfrm_km_lock);
return 0;
}
EXPORT_SYMBOL(xfrm_register_km);
6.3 发送通知
在pf_key中调用以下两个函数来调用通知回调函数, 分别针对安全策略操作和SA操作:
// 安全策略通知回调
void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
{
struct xfrm_mgr *km;
read_lock(&xfrm_km_lock);
// 状态的通知回调函数为notify_policy
list_for_each_entry(km, &xfrm_km_list, list)
if (km->notify_policy)
km->notify_policy(xp, dir, c);
read_unlock(&xfrm_km_lock);
}
// SA状态通知回调
void km_state_notify(struct xfrm_state *x, struct km_event *c)
{
struct xfrm_mgr *km;
read_lock(&xfrm_km_lock);
// 状态的通知回调函数为notify
list_for_each_entry(km, &xfrm_km_list, list)
if (km->notify)
km->notify(x, c);
read_unlock(&xfrm_km_lock);
}
调用这些通知函数前要填写事件的相关参数, 如:
static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
unsigned proto;
struct km_event c;
proto = pfkey_satype2proto(hdr->sadb_msg_satype);
if (proto == 0)
return -EINVAL;
xfrm_state_flush(proto);
// 填写事件参数
// 协议
c.data.proto = proto;
// 序列号
c.seq = hdr->sadb_msg_seq;
// sock对方(用户空间进程)的pid
c.pid = hdr->sadb_msg_pid;
// 事件
c.event = XFRM_MSG_FLUSHSA;
km_state_notify(NULL, &c);
return 0;
}
6.4 pf_key通知回调函数
6.4.1 发送SA消息时的通知回调
// 状态通知回调, 在SA操作后调用
static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)
{
// 根据事件类型来发送相关通知
switch (c->event) {
case XFRM_MSG_EXPIRE:
// SA到期的通知, SA消息类型为SADB_EXPIRE,只是进行了登记的PF_KEY socket可以收到
return key_notify_sa_expire(x, c);
case XFRM_MSG_DELSA:
case XFRM_MSG_NEWSA:
case XFRM_MSG_UPDSA:
// SA的通知, SA消息类型为分别为SADB_DELETE, SADB_ADD和SADB_UPDATE,
// 所有PF_KEY socket都可以收到
return key_notify_sa(x, c);
case XFRM_MSG_FLUSHSA:
// 删除全部SA的通知, SA消息类型为分别为SADB_FLUSH, 所有PF_KEY socket都可以收到
return key_notify_sa_flush(c);
case XFRM_MSG_NEWAE: /* not yet supported */
break;
default:
printk("pfkey: Unknown SA event %d\n", c->event);
break;
}
return 0;
}
6.4.2 发送ACQUIRE
关于ACQUIRE的作用, 摘一段UNP vol.1, r3中的话:
chapter19.5:
"When the kernel needs to communicate with a peer and policy says that an SA is required but one is not available, the kernel sends an SADB_ACQUIRE message to key management sockets that have registered the SA type required, containing a proposal extension describing the kernel's proposed algorithms and key lengths. The proposal may be a combination of what is supported by the system and preconfigured policy that limits what is permitted for this communication. The proposal is a list of algorithms, key lengths, and lifetimes, in order of preference. When a key management daemon receives an SADB_ACQUIRE message, it performs the acts required to choose a key that fits one of the kernel's proposed combinations, and installs this key in the kernel. "
static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir)
{
struct sk_buff *skb;
struct sadb_msg *hdr;
struct sadb_address *addr;
struct sadb_x_policy *pol;
struct sockaddr_in *sin;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct sockaddr_in6 *sin6;
#endif
int sockaddr_size;
int size;
struct sadb_x_sec_ctx *sec_ctx;
struct xfrm_sec_ctx *xfrm_ctx;
int ctx_size = 0;