日期:2014-05-16 浏览次数:20658 次
5. 安全策略(xfrm_policy)处理 本节所介绍的函数都在net/xfrm/xfrm_policy.c中定义。 5.1 策略分配 策略分配函数为xfrm_policy_alloc(), 该函数被pfkey_spdadd()函数调用 struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp) { struct xfrm_policy *policy; // 分配struct xfrm_policy结构空间并清零 policy = kzalloc(sizeof(struct xfrm_policy), gfp); if (policy) { // 初始化链接节点 INIT_HLIST_NODE(&policy->bydst); INIT_HLIST_NODE(&policy->byidx); // 初始化锁 rwlock_init(&policy->lock); // 策略引用计数初始化为1 atomic_set(&policy->refcnt, 1); // 初始化定时器 init_timer(&policy->timer); policy->timer.data = (unsigned long)policy; policy->timer.function = xfrm_policy_timer; } return policy; } EXPORT_SYMBOL(xfrm_policy_alloc); 定时器函数: static void xfrm_policy_timer(unsigned long data) { struct xfrm_policy *xp = (struct xfrm_policy*)data; unsigned long now = (unsigned long)xtime.tv_sec; long next = LONG_MAX; int warn = 0; int dir; // 加锁 read_lock(&xp->lock); // 如果策略已经是死的, 退出 if (xp->dead) goto out; // 根据策略索引号确定策略处理的数据的方向, 看索引号的后3位 dir = xfrm_policy_id2dir(xp->index); // 如果到期了还要强制要增加一些时间 if (xp->lft.hard_add_expires_seconds) { // 计算强制增加的超时时间 long tmo = xp->lft.hard_add_expires_seconds + xp->curlft.add_time - now; // 没法增加超时了, 到期 if (tmo <= 0) goto expired; if (tmo < next) next = tmo; } // 如果到期了还要强制要增加的使用时间 if (xp->lft.hard_use_expires_seconds) { // 计算强制增加的使用时间 long tmo = xp->lft.hard_use_expires_seconds + (xp->curlft.use_time ? : xp->curlft.add_time) - now; // 没法增加超时了, 到期 if (tmo <= 0) goto expired; if (tmo < next) next = tmo; } // 如果到期了还要软性要增加一些时间 if (xp->lft.soft_add_expires_seconds) { // 计算软性增加的时间 long tmo = xp->lft.soft_add_expires_seconds + xp->curlft.add_time - now; // 软性增加超时小于0, 设置报警标志, 并将超时设置为XFRM_KM_TIMEOUT, 这点和其他不同 if (tmo <= 0) { warn = 1; tmo = XFRM_KM_TIMEOUT; } if (tmo < next) next = tmo; } // 如果到期了还要软性要增加的使用时间 if (xp->lft.soft_use_expires_seconds) { // 计算软性增加的使用时间 long tmo = xp->lft.soft_use_expires_seconds + (xp->curlft.use_time ? : xp->curlft.add_time) - now; // 软性增加超时小于0, 设置报警标志, 并将超时设置为XFRM_KM_TIMEOUT, 这点和其他不同 if (tmo <= 0) { warn = 1; tmo = XFRM_KM_TIMEOUT; } if (tmo < next) next = tmo; } // 需要报警, 调用到期回调 if (warn) km_policy_expired(xp, dir, 0, 0); // 如果更新的超时值有效, 修改定时器超时, 增加策略使用计数 if (next != LONG_MAX && !mod_timer(&xp->timer, jiffies + make_jiffies(next))) xfrm_pol_hold(xp); out: read_unlock(&xp->lock); xfrm_pol_put(xp); return; expired: read_unlock(&xp->lock); // 如果确实到期, 删除策略 if (!xfrm_policy_delete(xp, dir)) // 1表示是硬性到期了 km_policy_expired(xp, dir, 1, 0); xfrm_pol_put(xp); } 5.2 策略插入 策略插入函数为xfrm_policy_insert(), 该函数被pfkey_spdadd()函数调用, 注意策略链表是按优先权大小进行排序的有序链表, 因此插入策略时要进行优先权比较后插入到合适的位置. int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) { struct xfrm_policy *pol; struct xfrm_policy *delpol; struct hlist_head *chain; struct hlist_node *entry, *newpos, *last; struct dst_entry *gc_list; write_lock_bh(&xfrm_policy_lock); // 找到具体的hash链表 chain = policy_hash_bysel(&policy->selector, policy->family, dir); delpol = NULL; newpos = NULL; last = NULL; // 遍历链表, 该链表是以策略的优先级值进行排序的链表, 因此需要根据新策略的优先级大小 // 将新策略插到合适的位置 hlist_for_each_entry(pol, entry, chain, bydst) { // delpol要为空 if (!delpol && // 策略类型比较 pol->type == policy->type && // 选择子比较 !selector_cmp(&pol->selector, &policy->selector) && // 安全上下文比较 xfrm_sec_ctx_match(pol->security, policy->security)) { // 新策略和已有的某策略匹配 if (excl) { // 如果是排他性添加操作, 要插入的策略在数据库中已经存在, 发生错误 write_unlock_bh(&xfrm_policy_lock); return -EEXIST; } // 保存好要删除的策略位置 delpol = pol; // 要更新的策略优先级值大于原有的优先级值, 重新循环找到合适