Linux内核中的IPSEC实现(3)
短信预约 -IT技能 免费直播动态提醒
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
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);
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);
// 初始化链接节点
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;
{
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);
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);
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;
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);
}
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;
// 要更新的策略优先级值大于原有的优先级值, 重新循环找到合适的插入位置
// 因为这个链表是以优先级值进行排序的, 不能乱
// 现在delpol已经非空了, 前面的策略查找条件已经不可能满足了
if (policy->priority > pol->priority)
continue;
} else if (policy->priority >= pol->priority) {
// 如果新的优先级不低于当前的优先级, 保存当前节点, 继续查找合适插入位置
last = &pol->bydst;
continue;
}
// 这里是根据新策略的优先级确定的插入位置
if (!newpos)
newpos = &pol->bydst;
// 如果已经找到要删除的策略, 中断
if (delpol)
break;
last = &pol->bydst;
}
if (!newpos)
newpos = last;
// 插入策略到按目的地址HASH的链表的指定位置
if (newpos)
hlist_add_after(newpos, &policy->bydst);
else
hlist_add_head(&policy->bydst, chain);
// 增加策略引用计数
xfrm_pol_hold(policy);
// 该方向的策略数增1
xfrm_policy_count[dir]++;
atomic_inc(&flow_cache_genid);
// 如果有相同的老策略, 要从目的地址HASH和索引号HASH这两个表中删除
if (delpol) {
hlist_del(&delpol->bydst);
hlist_del(&delpol->byidx);
xfrm_policy_count[dir]--;
}
// 获取策略索引号, 插入索引HASH链表
policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir);
hlist_add_head(&policy->byidx, xfrm_policy_byidx+idx_hash(policy->index));
// 策略插入实际时间
policy->curlft.add_time = (unsigned long)xtime.tv_sec;
policy->curlft.use_time = 0;
if (!mod_timer(&policy->timer, jiffies + HZ))
xfrm_pol_hold(policy);
write_unlock_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;
// 要更新的策略优先级值大于原有的优先级值, 重新循环找到合适的插入位置
// 因为这个链表是以优先级值进行排序的, 不能乱
// 现在delpol已经非空了, 前面的策略查找条件已经不可能满足了
if (policy->priority > pol->priority)
continue;
} else if (policy->priority >= pol->priority) {
// 如果新的优先级不低于当前的优先级, 保存当前节点, 继续查找合适插入位置
last = &pol->bydst;
continue;
}
// 这里是根据新策略的优先级确定的插入位置
if (!newpos)
newpos = &pol->bydst;
// 如果已经找到要删除的策略, 中断
if (delpol)
break;
last = &pol->bydst;
}
if (!newpos)
newpos = last;
// 插入策略到按目的地址HASH的链表的指定位置
if (newpos)
hlist_add_after(newpos, &policy->bydst);
else
hlist_add_head(&policy->bydst, chain);
// 增加策略引用计数
xfrm_pol_hold(policy);
// 该方向的策略数增1
xfrm_policy_count[dir]++;
atomic_inc(&flow_cache_genid);
// 如果有相同的老策略, 要从目的地址HASH和索引号HASH这两个表中删除
if (delpol) {
hlist_del(&delpol->bydst);
hlist_del(&delpol->byidx);
xfrm_policy_count[dir]--;
}
// 获取策略索引号, 插入索引HASH链表
policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir);
hlist_add_head(&policy->byidx, xfrm_policy_byidx+idx_hash(policy->index));
// 策略插入实际时间
policy->curlft.add_time = (unsigned long)xtime.tv_sec;
policy->curlft.use_time = 0;
if (!mod_timer(&policy->timer, jiffies + HZ))
xfrm_pol_hold(policy);
write_unlock_bh(&xfrm_policy_lock);
// 释放老策略
if (delpol)
xfrm_policy_kill(delpol);
else if (xfrm_bydst_should_resize(dir, NULL))
schedule_work(&xfrm_hash_work);
if (delpol)
xfrm_policy_kill(delpol);
else if (xfrm_bydst_should_resize(dir, NULL))
schedule_work(&xfrm_hash_work);
// 下面释放所有策略当前的路由cache
read_lock_bh(&xfrm_policy_lock);
gc_list = NULL;
entry = &policy->bydst;
// 遍历链表, 搜集垃圾路由cache建立链表
hlist_for_each_entry_continue(policy, entry, bydst) {
struct dst_entry *dst;
read_lock_bh(&xfrm_policy_lock);
gc_list = NULL;
entry = &policy->bydst;
// 遍历链表, 搜集垃圾路由cache建立链表
hlist_for_each_entry_continue(policy, entry, bydst) {
struct dst_entry *dst;
write_lock(&policy->lock);
// 策略的路由链表头
dst = policy->bundles;
if (dst) {
// 直接将整个策略路由链表加到垃圾链表前面
struct dst_entry *tail = dst;
while (tail->next)
tail = tail->next;
tail->next = gc_list;
gc_list = dst;
// 当前策略的路由为空
policy->bundles = NULL;
}
write_unlock(&policy->lock);
}
read_unlock_bh(&xfrm_policy_lock);
// 释放垃圾路由cahce
while (gc_list) {
struct dst_entry *dst = gc_list;
// 策略的路由链表头
dst = policy->bundles;
if (dst) {
// 直接将整个策略路由链表加到垃圾链表前面
struct dst_entry *tail = dst;
while (tail->next)
tail = tail->next;
tail->next = gc_list;
gc_list = dst;
// 当前策略的路由为空
policy->bundles = NULL;
}
write_unlock(&policy->lock);
}
read_unlock_bh(&xfrm_policy_lock);
// 释放垃圾路由cahce
while (gc_list) {
struct dst_entry *dst = gc_list;
gc_list = dst->next;
dst_free(dst);
}
dst_free(dst);
}
return 0;
}
EXPORT_SYMBOL(xfrm_policy_insert);
}
EXPORT_SYMBOL(xfrm_policy_insert);
5.3 删除某类型的全部安全策略
该函数被pfkey_spdflush()等函数调用
void xfrm_policy_flush(u8 type)
{
int dir;
write_lock_bh(&xfrm_policy_lock);
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
struct xfrm_policy *pol;
struct hlist_node *entry;
int i, killed;
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
struct xfrm_policy *pol;
struct hlist_node *entry;
int i, killed;
killed = 0;
again1:
// 遍历inexact HASH链表
hlist_for_each_entry(pol, entry,
&xfrm_policy_inexact[dir], bydst) {
// 判断类型
if (pol->type != type)
continue;
// 将策略从bydst链表中断开
hlist_del(&pol->bydst);
// 将策略从byidt链表中断开
hlist_del(&pol->byidx);
write_unlock_bh(&xfrm_policy_lock);
// 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除
xfrm_policy_kill(pol);
killed++;
again1:
// 遍历inexact HASH链表
hlist_for_each_entry(pol, entry,
&xfrm_policy_inexact[dir], bydst) {
// 判断类型
if (pol->type != type)
continue;
// 将策略从bydst链表中断开
hlist_del(&pol->bydst);
// 将策略从byidt链表中断开
hlist_del(&pol->byidx);
write_unlock_bh(&xfrm_policy_lock);
// 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除
xfrm_policy_kill(pol);
killed++;
write_lock_bh(&xfrm_policy_lock);
goto again1;
}
// 遍历所有目的HASH链表
for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
again2:
// 遍历按目的地址HASH的链表
hlist_for_each_entry(pol, entry,
xfrm_policy_bydst[dir].table + i,
bydst) {
if (pol->type != type)
continue;
// 将节点从链表中断开
hlist_del(&pol->bydst);
hlist_del(&pol->byidx);
write_unlock_bh(&xfrm_policy_lock);
// 释放节点
xfrm_policy_kill(pol);
killed++;
goto again1;
}
// 遍历所有目的HASH链表
for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
again2:
// 遍历按目的地址HASH的链表
hlist_for_each_entry(pol, entry,
xfrm_policy_bydst[dir].table + i,
bydst) {
if (pol->type != type)
continue;
// 将节点从链表中断开
hlist_del(&pol->bydst);
hlist_del(&pol->byidx);
write_unlock_bh(&xfrm_policy_lock);
// 释放节点
xfrm_policy_kill(pol);
killed++;
write_lock_bh(&xfrm_policy_lock);
goto again2;
}
}
goto again2;
}
}
xfrm_policy_count[dir] -= killed;
}
atomic_inc(&flow_cache_genid);
write_unlock_bh(&xfrm_policy_lock);
}
EXPORT_SYMBOL(xfrm_policy_flush);
}
atomic_inc(&flow_cache_genid);
write_unlock_bh(&xfrm_policy_lock);
}
EXPORT_SYMBOL(xfrm_policy_flush);
// 策略释放到垃圾链表
static void xfrm_policy_kill(struct xfrm_policy *policy)
{
int dead;
write_lock_bh(&policy->lock);
// 保留老的DEAD标志
dead = policy->dead;
// 设置策略DEAD标志
policy->dead = 1;
write_unlock_bh(&policy->lock);
// 保留老的DEAD标志
dead = policy->dead;
// 设置策略DEAD标志
policy->dead = 1;
write_unlock_bh(&policy->lock);
// 为什么不在前面判断DEAD呢?
if (unlikely(dead)) {
WARN_ON(1);
return;
}
if (unlikely(dead)) {
WARN_ON(1);
return;
}
spin_lock(&xfrm_policy_gc_lock);
// 将该策略节点从当前链表断开, 插入策略垃圾链表
hlist_add_head(&policy->bydst, &xfrm_policy_gc_list);
spin_unlock(&xfrm_policy_gc_lock);
// 调度策略垃圾策略工作结构
schedule_work(&xfrm_policy_gc_work);
}
// 将该策略节点从当前链表断开, 插入策略垃圾链表
hlist_add_head(&policy->bydst, &xfrm_policy_gc_list);
spin_unlock(&xfrm_policy_gc_lock);
// 调度策略垃圾策略工作结构
schedule_work(&xfrm_policy_gc_work);
}
5.4 策略查找
5.4.1 策略查找并删除
根据选择子和安全上下文查找策略, 可查找策略并删除, 被pfkey_spddelete()函数调用
struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
struct xfrm_selector *sel,
struct xfrm_sec_ctx *ctx, int delete)
{
struct xfrm_policy *pol, *ret;
struct hlist_head *chain;
struct hlist_node *entry;
write_lock_bh(&xfrm_policy_lock);
// 定位HASH表
chain = policy_hash_bysel(sel, sel->family, dir);
ret = NULL;
// 遍历链表
hlist_for_each_entry(pol, entry, chain, bydst) {
// 根据类型, 选择子和上下文进行匹配
if (pol->type == type &&
!selector_cmp(sel, &pol->selector) &&
xfrm_sec_ctx_match(ctx, pol->security)) {
xfrm_pol_hold(pol);
if (delete) {
// 要的删除话将策略节点从目的地址HASH链表和索引HASH链表中断开
hlist_del(&pol->bydst);
hlist_del(&pol->byidx);
xfrm_policy_count[dir]--;
}
ret = pol;
break;
}
}
write_unlock_bh(&xfrm_policy_lock);
// 定位HASH表
chain = policy_hash_bysel(sel, sel->family, dir);
ret = NULL;
// 遍历链表
hlist_for_each_entry(pol, entry, chain, bydst) {
// 根据类型, 选择子和上下文进行匹配
if (pol->type == type &&
!selector_cmp(sel, &pol->selector) &&
xfrm_sec_ctx_match(ctx, pol->security)) {
xfrm_pol_hold(pol);
if (delete) {
// 要的删除话将策略节点从目的地址HASH链表和索引HASH链表中断开
hlist_del(&pol->bydst);
hlist_del(&pol->byidx);
xfrm_policy_count[dir]--;
}
ret = pol;
break;
}
}
write_unlock_bh(&xfrm_policy_lock);
if (ret && delete) {
// 增加genid
atomic_inc(&flow_cache_genid);
// 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除
xfrm_policy_kill(ret);
}
return ret;
}
EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
// 增加genid
atomic_inc(&flow_cache_genid);
// 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除
xfrm_policy_kill(ret);
}
return ret;
}
EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
5.4.2 按索引号查找并删除
struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete)
{
struct xfrm_policy *pol, *ret;
struct hlist_head *chain;
struct hlist_node *entry;
write_lock_bh(&xfrm_policy_lock);
// 根据索引号定位链表
chain = xfrm_policy_byidx + idx_hash(id);
ret = NULL;
// 遍历链表
hlist_for_each_entry(pol, entry, chain, byidx) {
// 策略的类型和索引号相同
if (pol->type == type && pol->index == id) {
xfrm_pol_hold(pol);
// 如果要删除, 将策略节点从链表中删除
if (delete) {
hlist_del(&pol->bydst);
hlist_del(&pol->byidx);
xfrm_policy_count[dir]--;
}
ret = pol;
break;
}
}
write_unlock_bh(&xfrm_policy_lock);
// 根据索引号定位链表
chain = xfrm_policy_byidx + idx_hash(id);
ret = NULL;
// 遍历链表
hlist_for_each_entry(pol, entry, chain, byidx) {
// 策略的类型和索引号相同
if (pol->type == type && pol->index == id) {
xfrm_pol_hold(pol);
// 如果要删除, 将策略节点从链表中删除
if (delete) {
hlist_del(&pol->bydst);
hlist_del(&pol->byidx);
xfrm_policy_count[dir]--;
}
ret = pol;
break;
}
}
write_unlock_bh(&xfrm_policy_lock);
if (ret && delete) {
// 增加genid
atomic_inc(&flow_cache_genid);
// 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除
xfrm_policy_kill(ret);
}
return ret;
}
EXPORT_SYMBOL(xfrm_policy_byid);
// 增加genid
atomic_inc(&flow_cache_genid);
// 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除
xfrm_policy_kill(ret);
}
return ret;
}
EXPORT_SYMBOL(xfrm_policy_byid);
5.4.3 根据路由查找策略
// 参数fl是路由相关的结构, 常用于路由查找中
// 注意返回值是整数, 0成功, 非0失败, 找到的策略通过参数objp进行传递
static int xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir,
void **objp, atomic_t **obj_refp)
{
struct xfrm_policy *pol;
int err = 0;
#ifdef CONFIG_XFRM_SUB_POLICY
// 子策略查找, 属于Linux自己的扩展功能, 非标准功能
pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir);
if (IS_ERR(pol)) {
err = PTR_ERR(pol);
pol = NULL;
}
if (pol || err)
goto end;
#endif
// 查找MAIN类型的策略
pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir);
if (IS_ERR(pol)) {
err = PTR_ERR(pol);
pol = NULL;
}
#ifdef CONFIG_XFRM_SUB_POLICY
end:
#endif
// 将找到的策略赋值给objp返回
if ((*objp = (void *) pol) != NULL)
*obj_refp = &pol->refcnt;
return err;
}
// 子策略查找, 属于Linux自己的扩展功能, 非标准功能
pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir);
if (IS_ERR(pol)) {
err = PTR_ERR(pol);
pol = NULL;
}
if (pol || err)
goto end;
#endif
// 查找MAIN类型的策略
pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir);
if (IS_ERR(pol)) {
err = PTR_ERR(pol);
pol = NULL;
}
#ifdef CONFIG_XFRM_SUB_POLICY
end:
#endif
// 将找到的策略赋值给objp返回
if ((*objp = (void *) pol) != NULL)
*obj_refp = &pol->refcnt;
return err;
}
// 按类型查找策略
static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl,
u16 family, u8 dir)
{
int err;
struct xfrm_policy *pol, *ret;
xfrm_address_t *daddr, *saddr;
struct hlist_node *entry;
struct hlist_head *chain;
u32 priority = ~0U;
// 由流结构的目的和源地址
daddr = xfrm_flowi_daddr(fl, family);
saddr = xfrm_flowi_saddr(fl, family);
if (unlikely(!daddr || !saddr))
return NULL;
daddr = xfrm_flowi_daddr(fl, family);
saddr = xfrm_flowi_saddr(fl, family);
if (unlikely(!daddr || !saddr))
return NULL;
read_lock_bh(&xfrm_policy_lock);
// 根据地址信息查找HASH链表
chain = policy_hash_direct(daddr, saddr, family, dir);
ret = NULL;
// 循环HASH链表
hlist_for_each_entry(pol, entry, chain, bydst) {
// 检查流结构,类型和协议族是否匹配策略, 返回0表示匹配
err = xfrm_policy_match(pol, fl, type, family, dir);
if (err) {
if (err == -Eclass="lazy" data-srcH)
continue;
else {
ret = ERR_PTR(err);
goto fail;
}
} else {
// 备份找到的策略和优先级
ret = pol;
priority = ret->priority;
break;
}
}
// 再在inexact链表中查找策略, 如果也找到策略, 而且优先级更小,
// 将新找到的策略替代前面找到的策略
chain = &xfrm_policy_inexact[dir];
// 循环HASH链表
hlist_for_each_entry(pol, entry, chain, bydst) {
// 检查流结构,类型和协议族是否匹配策略, 返回0表示匹配
err = xfrm_policy_match(pol, fl, type, family, dir);
if (err) {
if (err == -Eclass="lazy" data-srcH)
continue;
else {
ret = ERR_PTR(err);
goto fail;
}
} else if (pol->priority < priority) {
// 如果新找到的策略优先级更小, 将其取代原来找到的策略
ret = pol;
break;
}
}
if (ret)
xfrm_pol_hold(ret);
fail:
read_unlock_bh(&xfrm_policy_lock);
// 根据地址信息查找HASH链表
chain = policy_hash_direct(daddr, saddr, family, dir);
ret = NULL;
// 循环HASH链表
hlist_for_each_entry(pol, entry, chain, bydst) {
// 检查流结构,类型和协议族是否匹配策略, 返回0表示匹配
err = xfrm_policy_match(pol, fl, type, family, dir);
if (err) {
if (err == -Eclass="lazy" data-srcH)
continue;
else {
ret = ERR_PTR(err);
goto fail;
}
} else {
// 备份找到的策略和优先级
ret = pol;
priority = ret->priority;
break;
}
}
// 再在inexact链表中查找策略, 如果也找到策略, 而且优先级更小,
// 将新找到的策略替代前面找到的策略
chain = &xfrm_policy_inexact[dir];
// 循环HASH链表
hlist_for_each_entry(pol, entry, chain, bydst) {
// 检查流结构,类型和协议族是否匹配策略, 返回0表示匹配
err = xfrm_policy_match(pol, fl, type, family, dir);
if (err) {
if (err == -Eclass="lazy" data-srcH)
continue;
else {
ret = ERR_PTR(err);
goto fail;
}
} else if (pol->priority < priority) {
// 如果新找到的策略优先级更小, 将其取代原来找到的策略
ret = pol;
break;
}
}
if (ret)
xfrm_pol_hold(ret);
fail:
read_unlock_bh(&xfrm_policy_lock);
return ret;
}
}
// 检查xfrm策略是否和流参数匹配
// 返回0表示匹配成功
static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl,
u8 type, u16 family, int dir)
{
// 选择子
struct xfrm_selector *sel = &pol->selector;
int match, ret = -Eclass="lazy" data-srcH;
// 检查策略协议族和类型是否匹配
if (pol->family != family ||
pol->type != type)
return ret;
// 检查选择子是否匹配, 返回非0值表示匹配成功
match = xfrm_selector_match(sel, fl, family);
if (match)
// 这种security函数可以不用考虑, 当作返回0的函数即可
ret = security_xfrm_policy_lookup(pol, fl->secid, dir);
// 返回0表示匹配成功
static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl,
u8 type, u16 family, int dir)
{
// 选择子
struct xfrm_selector *sel = &pol->selector;
int match, ret = -Eclass="lazy" data-srcH;
// 检查策略协议族和类型是否匹配
if (pol->family != family ||
pol->type != type)
return ret;
// 检查选择子是否匹配, 返回非0值表示匹配成功
match = xfrm_selector_match(sel, fl, family);
if (match)
// 这种security函数可以不用考虑, 当作返回0的函数即可
ret = security_xfrm_policy_lookup(pol, fl->secid, dir);
return ret;
}
}
// 选择子匹配,分别对IPV4和IPV6协议族比较
static inline int
xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
unsigned short family)
{
switch (family) {
case AF_INET:
return __xfrm4_selector_match(sel, fl);
case AF_INET6:
return __xfrm6_selector_match(sel, fl);
}
return 0;
}
static inline int
xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
unsigned short family)
{
switch (family) {
case AF_INET:
return __xfrm4_selector_match(sel, fl);
case AF_INET6:
return __xfrm6_selector_match(sel, fl);
}
return 0;
}
//IPV4协议族选择子比较
static inline int
__xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl)
{
// 比较V4目的地址, V4源地址, 目的端口, 源端口, 协议, 网卡索引号
return addr_match(&fl->fl4_dst, &sel->daddr, sel->prefixlen_d) &&
addr_match(&fl->fl4_class="lazy" data-src, &sel->saddr, sel->prefixlen_s) &&
!((xfrm_flowi_dport(fl) ^ sel->dport) & sel->dport_mask) &&
!((xfrm_flowi_sport(fl) ^ sel->sport) & sel->sport_mask) &&
(fl->proto == sel->proto || !sel->proto) &&
(fl->oif == sel->ifindex || !sel->ifindex);
}
static inline int
__xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl)
{
// 比较V4目的地址, V4源地址, 目的端口, 源端口, 协议, 网卡索引号
return addr_match(&fl->fl4_dst, &sel->daddr, sel->prefixlen_d) &&
addr_match(&fl->fl4_class="lazy" data-src, &sel->saddr, sel->prefixlen_s) &&
!((xfrm_flowi_dport(fl) ^ sel->dport) & sel->dport_mask) &&
!((xfrm_flowi_sport(fl) ^ sel->sport) & sel->sport_mask) &&
(fl->proto == sel->proto || !sel->proto) &&
(fl->oif == sel->ifindex || !sel->ifindex);
}
//IPV6协议族选择子比较
static inline int
__xfrm6_selector_match(struct xfrm_selector *sel, struct flowi *fl)
{
// 比较V6目的地址, V6源地址, 目的端口, 源端口, 协议, 网卡索引号
return addr_match(&fl->fl6_dst, &sel->daddr, sel->prefixlen_d) &&
addr_match(&fl->fl6_class="lazy" data-src, &sel->saddr, sel->prefixlen_s) &&
!((xfrm_flowi_dport(fl) ^ sel->dport) & sel->dport_mask) &&
!((xfrm_flowi_sport(fl) ^ sel->sport) & sel->sport_mask) &&
(fl->proto == sel->proto || !sel->proto) &&
(fl->oif == sel->ifindex || !sel->ifindex);
}
static inline int
__xfrm6_selector_match(struct xfrm_selector *sel, struct flowi *fl)
{
// 比较V6目的地址, V6源地址, 目的端口, 源端口, 协议, 网卡索引号
return addr_match(&fl->fl6_dst, &sel->daddr, sel->prefixlen_d) &&
addr_match(&fl->fl6_class="lazy" data-src, &sel->saddr, sel->prefixlen_s) &&
!((xfrm_flowi_dport(fl) ^ sel->dport) & sel->dport_mask) &&
!((xfrm_flowi_sport(fl) ^ sel->sport) & sel->sport_mask) &&
(fl->proto == sel->proto || !sel->proto) &&
(fl->oif == sel->ifindex || !sel->ifindex);
}
5.4.4 查找和sock对应的策略
static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl)
{
struct xfrm_policy *pol;
{
struct xfrm_policy *pol;
read_lock_bh(&xfrm_policy_lock);
// sock结构中有sk_policy用来指向双向数据的安全策略
if ((pol = sk->sk_policy[dir]) != NULL) {
// 检查该策略的选择子是否和流结构匹配
int match = xfrm_selector_match(&pol->selector, fl,
sk->sk_family);
int err = 0;
// 如果匹配的话将策略作为结果返回
if (match) {
// 这个security函数可视为返回0的空函数
err = security_xfrm_policy_lookup(pol, fl->secid,
policy_to_flow_dir(dir));
if (!err)
xfrm_pol_hold(pol);
else if (err == -Eclass="lazy" data-srcH)
pol = NULL;
else
pol = ERR_PTR(err);
} else
pol = NULL;
}
read_unlock_bh(&xfrm_policy_lock);
return pol;
}
// sock结构中有sk_policy用来指向双向数据的安全策略
if ((pol = sk->sk_policy[dir]) != NULL) {
// 检查该策略的选择子是否和流结构匹配
int match = xfrm_selector_match(&pol->selector, fl,
sk->sk_family);
int err = 0;
// 如果匹配的话将策略作为结果返回
if (match) {
// 这个security函数可视为返回0的空函数
err = security_xfrm_policy_lookup(pol, fl->secid,
policy_to_flow_dir(dir));
if (!err)
xfrm_pol_hold(pol);
else if (err == -Eclass="lazy" data-srcH)
pol = NULL;
else
pol = ERR_PTR(err);
} else
pol = NULL;
}
read_unlock_bh(&xfrm_policy_lock);
return pol;
}
5.5 遍历安全策略
该函数被pfkey_spddump()等函数中调用
// func函数用来指定对遍历的策略进行的查找
// 实际遍历了两次所有策略
int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*),
void *data)
{
struct xfrm_policy *pol;
struct hlist_node *entry;
int dir, count, error;
read_lock_bh(&xfrm_policy_lock);
count = 0;
// 先统计符合类型的策略的总数量, 方向是双向的
for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
struct hlist_head *table = xfrm_policy_bydst[dir].table;
int i;
// inexact HASH表
hlist_for_each_entry(pol, entry,
&xfrm_policy_inexact[dir], bydst) {
if (pol->type == type)
count++;
}
// 遍历按地址HASH的链表
for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
// 遍历链表
hlist_for_each_entry(pol, entry, table + i, bydst) {
if (pol->type == type)
count++;
}
}
}
count = 0;
// 先统计符合类型的策略的总数量, 方向是双向的
for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
struct hlist_head *table = xfrm_policy_bydst[dir].table;
int i;
// inexact HASH表
hlist_for_each_entry(pol, entry,
&xfrm_policy_inexact[dir], bydst) {
if (pol->type == type)
count++;
}
// 遍历按地址HASH的链表
for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
// 遍历链表
hlist_for_each_entry(pol, entry, table + i, bydst) {
if (pol->type == type)
count++;
}
}
}
if (count == 0) {
error = -ENOENT;
goto out;
}
// 重新遍历HASH表, 当前的count值作为SA的序号, 因此用户空间收到的序号是递减的
for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
struct hlist_head *table = xfrm_policy_bydst[dir].table;
int i;
// 遍历inexact链表
hlist_for_each_entry(pol, entry,
&xfrm_policy_inexact[dir], bydst) {
if (pol->type != type)
continue;
// 对符合类型的策略调用func函数
error = func(pol, dir % XFRM_POLICY_MAX, --count, data);
if (error)
goto out;
}
// 遍历按地址HASH的链表
for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
hlist_for_each_entry(pol, entry, table + i, bydst) {
if (pol->type != type)
continue;
// 对符合类型的策略调用func函数, 当count递减到0时表示是最后一个策略了
error = func(pol, dir % XFRM_POLICY_MAX, --count, data);
if (error)
goto out;
}
}
}
error = 0;
out:
read_unlock_bh(&xfrm_policy_lock);
return error;
}
EXPORT_SYMBOL(xfrm_policy_walk);
error = -ENOENT;
goto out;
}
// 重新遍历HASH表, 当前的count值作为SA的序号, 因此用户空间收到的序号是递减的
for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
struct hlist_head *table = xfrm_policy_bydst[dir].table;
int i;
// 遍历inexact链表
hlist_for_each_entry(pol, entry,
&xfrm_policy_inexact[dir], bydst) {
if (pol->type != type)
continue;
// 对符合类型的策略调用func函数
error = func(pol, dir % XFRM_POLICY_MAX, --count, data);
if (error)
goto out;
}
// 遍历按地址HASH的链表
for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
hlist_for_each_entry(pol, entry, table + i, bydst) {
if (pol->type != type)
continue;
// 对符合类型的策略调用func函数, 当count递减到0时表示是最后一个策略了
error = func(pol, dir % XFRM_POLICY_MAX, --count, data);
if (error)
goto out;
}
}
}
error = 0;
out:
read_unlock_bh(&xfrm_policy_lock);
return error;
}
EXPORT_SYMBOL(xfrm_policy_walk);
5.5 策略检查
__xfrm_policy_check函数也是一个比较重要的函数, 被xfrm_policy_check()调用, 又被xfrm4_policy_check()和xfrm6_policy_check()调用, 而这两个函数在网络层的输入和转发处调用.
对普通包就返回合法, 对IPSEC包检查策略是否合法, 是否和路由方向匹配
// 返回1表示合法, 0表示不合法, 对于该函数返回0的数据包通常是被丢弃
int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
unsigned short family)
{
struct xfrm_policy *pol;
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
int npols = 0;
int xfrm_nr;
int pi;
struct flowi fl;
// 将策略方向转换为流方向, 其实值是一样的
u8 fl_dir = policy_to_flow_dir(dir);
int xerr_idx = -1;
// 调用协议族的decode_session()函数, 对IPV4来说就是_decode_session4
// 将skb中的地址端口等信息填入流结构fl中
if (xfrm_decode_session(skb, &fl, family) < 0)
return 0;
// 如果内核支持NETFILTER, 将调用ip_nat_decode_session函数填写NAT信息
// 否则的话就是个空函数
nf_nat_decode_session(skb, &fl, family);
// 将skb中的地址端口等信息填入流结构fl中
if (xfrm_decode_session(skb, &fl, family) < 0)
return 0;
// 如果内核支持NETFILTER, 将调用ip_nat_decode_session函数填写NAT信息
// 否则的话就是个空函数
nf_nat_decode_session(skb, &fl, family);
if (skb->sp) {
// 该包是进行了解密后的IPSEC包
int i;
for (i=skb->sp->len-1; i>=0; i--) {
// 获取该包相关的SA信息
struct xfrm_state *x = skb->sp->xvec[i];
// 检查SA选择子和流参数(路由)是否匹配, 结果为0表示不匹配, 不匹配的话返回
if (!xfrm_selector_match(&x->sel, &fl, family))
return 0;
}
}
// 获取该包相关的SA信息
struct xfrm_state *x = skb->sp->xvec[i];
// 检查SA选择子和流参数(路由)是否匹配, 结果为0表示不匹配, 不匹配的话返回
if (!xfrm_selector_match(&x->sel, &fl, family))
return 0;
}
}
pol = NULL;
// 如果sock结构中有策略
if (sk && sk->sk_policy[dir]) {
// 检查策略是否和流结构匹配, 匹配的话返回策略
pol = xfrm_sk_policy_lookup(sk, dir, &fl);
if (IS_ERR(pol))
return 0;
}
// 如果sock结构中有策略
if (sk && sk->sk_policy[dir]) {
// 检查策略是否和流结构匹配, 匹配的话返回策略
pol = xfrm_sk_policy_lookup(sk, dir, &fl);
if (IS_ERR(pol))
return 0;
}
// 查找路由信息, 如果没有就创建路由, xfrm_policy_lookup()函数作为参数传递给
// flow_cache_lookup()函数, 查找和该路由对应的安全策略
if (!pol)
pol = flow_cache_lookup(&fl, family, fl_dir,
xfrm_policy_lookup);
// 查找过程中出错,返回0
if (IS_ERR(pol))
return 0;
// flow_cache_lookup()函数, 查找和该路由对应的安全策略
if (!pol)
pol = flow_cache_lookup(&fl, family, fl_dir,
xfrm_policy_lookup);
// 查找过程中出错,返回0
if (IS_ERR(pol))
return 0;
// 策略不存在
if (!pol) {
// 如果该包是IPSEC包而且安全路径中的SA不是传输模式,
// 转发时, 对于已经封装的包没必要再次封装;
// 输入时, 是自身的IPSEC通信包封装基本也无意义
if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
// 拒绝该安全路径, 返回0失败
xfrm_secpath_reject(xerr_idx, skb, &fl);
return 0;
}
// 普通包处理, 安全策略不存在, 返回1
return 1;
}
if (!pol) {
// 如果该包是IPSEC包而且安全路径中的SA不是传输模式,
// 转发时, 对于已经封装的包没必要再次封装;
// 输入时, 是自身的IPSEC通信包封装基本也无意义
if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
// 拒绝该安全路径, 返回0失败
xfrm_secpath_reject(xerr_idx, skb, &fl);
return 0;
}
// 普通包处理, 安全策略不存在, 返回1
return 1;
}
// 找到安全策略, 对该包要根据策略进行IPSEC处理
// 更新策略当前使用时间
pol->curlft.use_time = (unsigned long)xtime.tv_sec;
// 更新策略当前使用时间
pol->curlft.use_time = (unsigned long)xtime.tv_sec;
pols[0] = pol;
npols ++;
#ifdef CONFIG_XFRM_SUB_POLICY
// 如果定义了子策略的话极限查找子策略, 这是标准IPSEC中没定义的, 可以不考虑
if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN,
&fl, family,
XFRM_POLICY_IN);
if (pols[1]) {
if (IS_ERR(pols[1]))
return 0;
pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec;
npols ++;
}
}
#endif
npols ++;
#ifdef CONFIG_XFRM_SUB_POLICY
// 如果定义了子策略的话极限查找子策略, 这是标准IPSEC中没定义的, 可以不考虑
if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN,
&fl, family,
XFRM_POLICY_IN);
if (pols[1]) {
if (IS_ERR(pols[1]))
return 0;
pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec;
npols ++;
}
}
#endif
// 策略动作是允许通过
if (pol->action == XFRM_POLICY_ALLOW) {
struct sec_path *sp;
// 先伪造个安全路径
static struct sec_path dummy;
struct xfrm_tmpl *tp[XFRM_MAX_DEPTH];
struct xfrm_tmpl *stp[XFRM_MAX_DEPTH];
struct xfrm_tmpl **tpp = tp;
int ti = 0;
int i, k;
if (pol->action == XFRM_POLICY_ALLOW) {
struct sec_path *sp;
// 先伪造个安全路径
static struct sec_path dummy;
struct xfrm_tmpl *tp[XFRM_MAX_DEPTH];
struct xfrm_tmpl *stp[XFRM_MAX_DEPTH];
struct xfrm_tmpl **tpp = tp;
int ti = 0;
int i, k;
// 如果数据包没有安全路径, 路径指针初始化为伪造的安全路径
if ((sp = skb->sp) == NULL)
sp = &dummy;
if ((sp = skb->sp) == NULL)
sp = &dummy;
// 遍历策略数组, 包括主策略和子策略(内核支持子策略的话),一般情况下就一个策略
for (pi = 0; pi < npols; pi++) {
// 如果有非允许通过的其他安全策略, 放弃
if (pols[pi] != pol &&
pols[pi]->action != XFRM_POLICY_ALLOW)
goto reject;
// 如果策略层次太多, 放弃
if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH)
goto reject_error;
// 备份策略中的xfrm向量模板, ti是数量
for (i = 0; i < pols[pi]->xfrm_nr; i++)
tpp[ti++] = &pols[pi]->xfrm_vec[i];
}
// 策略数量
xfrm_nr = ti;
if (npols > 1) {
// 如果超过一个策略,进行排序, 只是在内核支持子系统时才用, 否则只是返回错误
// 但该错误可以忽略
xfrm_tmpl_sort(stp, tpp, xfrm_nr, family);
tpp = stp;
}
for (pi = 0; pi < npols; pi++) {
// 如果有非允许通过的其他安全策略, 放弃
if (pols[pi] != pol &&
pols[pi]->action != XFRM_POLICY_ALLOW)
goto reject;
// 如果策略层次太多, 放弃
if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH)
goto reject_error;
// 备份策略中的xfrm向量模板, ti是数量
for (i = 0; i < pols[pi]->xfrm_nr; i++)
tpp[ti++] = &pols[pi]->xfrm_vec[i];
}
// 策略数量
xfrm_nr = ti;
if (npols > 1) {
// 如果超过一个策略,进行排序, 只是在内核支持子系统时才用, 否则只是返回错误
// 但该错误可以忽略
xfrm_tmpl_sort(stp, tpp, xfrm_nr, family);
tpp = stp;
}
// 遍历检查策略模板是否OK
for (i = xfrm_nr-1, k = 0; i >= 0; i--) {
// 注意k既是输入, 也是输出值, k初始化为0
// 返回值大于等于0表示策略合法可用
k = xfrm_policy_ok(tpp[i], sp, k, family);
if (k < 0) {
if (k < -1)
xerr_idx = -(2+k);
goto reject;
}
}
// 存在非传输模式的策略, 放弃
if (secpath_has_nontransport(sp, k, &xerr_idx))
goto reject;
xfrm_pols_put(pols, npols);
return 1;
}
// 放弃, 返回0表示检查不通过
reject:
xfrm_secpath_reject(xerr_idx, skb, &fl);
reject_error:
xfrm_pols_put(pols, npols);
return 0;
}
EXPORT_SYMBOL(__xfrm_policy_check);
return 1;
}
// 放弃, 返回0表示检查不通过
reject:
xfrm_secpath_reject(xerr_idx, skb, &fl);
reject_error:
xfrm_pols_put(pols, npols);
return 0;
}
EXPORT_SYMBOL(__xfrm_policy_check);
static inline int
xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start,
unsigned short family)
{
int idx = start;
if (tmpl->optional) {
// 如果是传输模式, 直接返回
if (tmpl->mode == XFRM_MODE_TRANSPORT)
return start;
} else
start = -1;
for (; idx < sp->len; idx++) {
// sp->xvec是xfrm状态
// 如果安全路径和模板匹配,返回索引位置
if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
return ++idx;
// 如果安全路径中的SA不是传输模式,返回错误
if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
if (start == -1)
start = -2-idx;
break;
}
}
return start;
}
// 如果是传输模式, 直接返回
if (tmpl->mode == XFRM_MODE_TRANSPORT)
return start;
} else
start = -1;
for (; idx < sp->len; idx++) {
// sp->xvec是xfrm状态
// 如果安全路径和模板匹配,返回索引位置
if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
return ++idx;
// 如果安全路径中的SA不是传输模式,返回错误
if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
if (start == -1)
start = -2-idx;
break;
}
}
return start;
}
5.6 安全策略路由查找
xfrm_lookup函数是个非常重要的函数, 用来根据安全策略构造数据包的路由项链表, 该路由项链表反映了对数据包进行IPSEC封装的多层次的处理, 每封装一次, 就增加一个路由项.
该函数被路由查找函数ip_route_output_flow()调用, 针对的是转发或发出的数据包.
该函数被路由查找函数ip_route_output_flow()调用, 针对的是转发或发出的数据包.
// 返回0表示超过, 负数表示失败
int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
struct sock *sk, int flags)
{
struct xfrm_policy *policy;
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
int npols;
int pol_dead;
int xfrm_nr;
int pi;
struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
struct dst_entry *dst, *dst_orig = *dst_p;
int nx = 0;
int err;
u32 genid;
u16 family;
u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
restart:
// 初始化清零操作
genid = atomic_read(&flow_cache_genid);
policy = NULL;
for (pi = 0; pi < ARRAY_SIZE(pols); pi++)
pols[pi] = NULL;
npols = 0;
pol_dead = 0;
xfrm_nr = 0;
// 初始化清零操作
genid = atomic_read(&flow_cache_genid);
policy = NULL;
for (pi = 0; pi < ARRAY_SIZE(pols); pi++)
pols[pi] = NULL;
npols = 0;
pol_dead = 0;
xfrm_nr = 0;
if (sk && sk->sk_policy[1]) {
// 如果在sock中定义了安全策略, 查找该sock相关的策略
// 一个socket的安全策略可通过setsockopt()设置, socket选项为
// IP_IPSEC_POLICY或IP_XFRM_POLICY(net/ipv4/ip_sockglue.c)
policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
if (IS_ERR(policy))
return PTR_ERR(policy);
}
// 如果在sock中定义了安全策略, 查找该sock相关的策略
// 一个socket的安全策略可通过setsockopt()设置, socket选项为
// IP_IPSEC_POLICY或IP_XFRM_POLICY(net/ipv4/ip_sockglue.c)
policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
if (IS_ERR(policy))
return PTR_ERR(policy);
}
if (!policy) {
// 没找到sock自身定义的安全策略
// 如果初始路由中设置了非IPSEC标志或没有发出方向的安全策略, 直接返回
if ((dst_orig->flags & DST_NOXFRM) ||
!xfrm_policy_count[XFRM_POLICY_OUT])
return 0;
// 没找到sock自身定义的安全策略
// 如果初始路由中设置了非IPSEC标志或没有发出方向的安全策略, 直接返回
if ((dst_orig->flags & DST_NOXFRM) ||
!xfrm_policy_count[XFRM_POLICY_OUT])
return 0;
// 查找路由信息, 如果没有就创建路由, xfrm_policy_lookup()函数作为参数传递给
// flow_cache_lookup()函数, 查找和该路由对应的安全策略
policy = flow_cache_lookup(fl, dst_orig->ops->family,
dir, xfrm_policy_lookup);
if (IS_ERR(policy))
return PTR_ERR(policy);
}
// 找不到策略的话返回, 就是普通包普通路由项
if (!policy)
return 0;
// flow_cache_lookup()函数, 查找和该路由对应的安全策略
policy = flow_cache_lookup(fl, dst_orig->ops->family,
dir, xfrm_policy_lookup);
if (IS_ERR(policy))
return PTR_ERR(policy);
}
// 找不到策略的话返回, 就是普通包普通路由项
if (!policy)
return 0;
// 以下是存在安全策略的情况, 要对该包建立安全路由链表
// 初始路由的协议族
family = dst_orig->ops->family;
// 安全策略最近使用时间
policy->curlft.use_time = (unsigned long)xtime.tv_sec;
// 将找到的策略作为策略数组的第一项
pols[0] = policy;
npols ++;
xfrm_nr += pols[0]->xfrm_nr;
// 初始路由的协议族
family = dst_orig->ops->family;
// 安全策略最近使用时间
policy->curlft.use_time = (unsigned long)xtime.tv_sec;
// 将找到的策略作为策略数组的第一项
pols[0] = policy;
npols ++;
xfrm_nr += pols[0]->xfrm_nr;
// 根据策略操作结果进行相关处理, 只有两种情况: 阻塞或通过
switch (policy->action) {
case XFRM_POLICY_BLOCK:
// 阻塞该数据包, 返回错误
err = -EPERM;
goto error;
switch (policy->action) {
case XFRM_POLICY_BLOCK:
// 阻塞该数据包, 返回错误
err = -EPERM;
goto error;
case XFRM_POLICY_ALLOW:
// 允许该包通过, 这样就要对该包进行IPSEC处理
#ifndef CONFIG_XFRM_SUB_POLICY
// 对子策略操作忽略
if (policy->xfrm_nr == 0) {
xfrm_pol_put(policy);
return 0;
}
#endif
// 允许该包通过, 这样就要对该包进行IPSEC处理
#ifndef CONFIG_XFRM_SUB_POLICY
// 对子策略操作忽略
if (policy->xfrm_nr == 0) {
xfrm_pol_put(policy);
return 0;
}
#endif
// 查找是否已经存在安全路由, bundle可以理解为描述安全处理的安全路由, 数据包走该路由
// 就是进行某种安全封装, 和普通路由项一样, 用过的安全路由也被缓存起来
dst = xfrm_find_bundle(fl, policy, family);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
goto error;
}
// 如果找到安全路由, 退出switch
if (dst)
break;
#ifdef CONFIG_XFRM_SUB_POLICY
// 对子策略操作, 由于是非标准IPSEC,忽略
if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN,
fl, family,
XFRM_POLICY_OUT);
if (pols[1]) {
if (IS_ERR(pols[1])) {
err = PTR_ERR(pols[1]);
goto error;
}
if (pols[1]->action == XFRM_POLICY_BLOCK) {
err = -EPERM;
goto error;
}
npols ++;
xfrm_nr += pols[1]->xfrm_nr;
}
}
// 对子策略操作, 由于是非标准IPSEC,忽略
if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN,
fl, family,
XFRM_POLICY_OUT);
if (pols[1]) {
if (IS_ERR(pols[1])) {
err = PTR_ERR(pols[1]);
goto error;
}
if (pols[1]->action == XFRM_POLICY_BLOCK) {
err = -EPERM;
goto error;
}
npols ++;
xfrm_nr += pols[1]->xfrm_nr;
}
}
if (xfrm_nr == 0) {
xfrm_pols_put(pols, npols);
return 0;
}
#endif
// 没找到安全路由, 准备构造新的路由项
// 利用策略, 流等参数构造相关SA(xfrm_state)保存在xfrm中, nx为SA数量
nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
// 没找到安全路由, 准备构造新的路由项
// 利用策略, 流等参数构造相关SA(xfrm_state)保存在xfrm中, nx为SA数量
nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
if (unlikely(nx<0)) {
// nx<0表示失败, 没找到SA
// 但如果是-EAGAIN表示已经通知用户空间的IKE进行协商新的SA了,
// 目前只生成了ACQUIRE类型的xfrm_state
err = nx;
if (err == -EAGAIN && flags) {
// 进程进入阻塞状态
DECLARE_WAITQUEUE(wait, current);
// nx<0表示失败, 没找到SA
// 但如果是-EAGAIN表示已经通知用户空间的IKE进行协商新的SA了,
// 目前只生成了ACQUIRE类型的xfrm_state
err = nx;
if (err == -EAGAIN && flags) {
// 进程进入阻塞状态
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&km_waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
schedule();
set_current_state(TASK_RUNNING);
remove_wait_queue(&km_waitq, &wait);
// 阻塞解除, 重新解析SA
nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
set_current_state(TASK_INTERRUPTIBLE);
schedule();
set_current_state(TASK_RUNNING);
remove_wait_queue(&km_waitq, &wait);
// 阻塞解除, 重新解析SA
nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
if (nx == -EAGAIN && signal_pending(current)) {
err = -ERESTART;
goto error;
}
if (nx == -EAGAIN ||
genid != atomic_read(&flow_cache_genid)) {
xfrm_pols_put(pols, npols);
goto restart;
}
err = nx;
}
if (err < 0)
goto error;
}
if (nx == 0) {
// nx==0表示数据是不需要进行IPSEC处理的, 返回
xfrm_pols_put(pols, npols);
return 0;
}
// 保存初始路由
dst = dst_orig;
// 创建新的安全路由, 返回0 表示成功, 失败返回负数
// dst在成功返回时保存安全路由项, 每个SA处理对应一个安全路由, 这些安全路由通过
// 路由项中的child链接为一个链表, 这样就可以对数据包进行连续变换, 如先压缩,
// 再ESP封装, 再AH封装等.
// 路由项链表的构造和协议族相关, 后续文章中介绍具体协议族中的实现时再详细描述
// 所构造出的路由项的具体结构情况
err = xfrm_bundle_create(policy, xfrm, nx, fl, &dst, family);
err = -ERESTART;
goto error;
}
if (nx == -EAGAIN ||
genid != atomic_read(&flow_cache_genid)) {
xfrm_pols_put(pols, npols);
goto restart;
}
err = nx;
}
if (err < 0)
goto error;
}
if (nx == 0) {
// nx==0表示数据是不需要进行IPSEC处理的, 返回
xfrm_pols_put(pols, npols);
return 0;
}
// 保存初始路由
dst = dst_orig;
// 创建新的安全路由, 返回0 表示成功, 失败返回负数
// dst在成功返回时保存安全路由项, 每个SA处理对应一个安全路由, 这些安全路由通过
// 路由项中的child链接为一个链表, 这样就可以对数据包进行连续变换, 如先压缩,
// 再ESP封装, 再AH封装等.
// 路由项链表的构造和协议族相关, 后续文章中介绍具体协议族中的实现时再详细描述
// 所构造出的路由项的具体结构情况
err = xfrm_bundle_create(policy, xfrm, nx, fl, &dst, family);
if (unlikely(err)) {
// 失败的话释放刚获取的SA
int i;
for (i=0; i<nx; i++)
xfrm_state_put(xfrm[i]);
goto error;
}
// 检查所有策略的dead状态
for (pi = 0; pi < npols; pi++) {
read_lock_bh(&pols[pi]->lock);
pol_dead |= pols[pi]->dead;
read_unlock_bh(&pols[pi]->lock);
}
// 失败的话释放刚获取的SA
int i;
for (i=0; i<nx; i++)
xfrm_state_put(xfrm[i]);
goto error;
}
// 检查所有策略的dead状态
for (pi = 0; pi < npols; pi++) {
read_lock_bh(&pols[pi]->lock);
pol_dead |= pols[pi]->dead;
read_unlock_bh(&pols[pi]->lock);
}
write_lock_bh(&policy->lock);
// 如果有策略是dead或获取的安全路由项有问题, 释放安全路由
if (unlikely(pol_dead || stale_bundle(dst))) {
write_unlock_bh(&policy->lock);
if (dst)
dst_free(dst);
// 如果有策略是dead或获取的安全路由项有问题, 释放安全路由
if (unlikely(pol_dead || stale_bundle(dst))) {
write_unlock_bh(&policy->lock);
if (dst)
dst_free(dst);
err = -EHOSTUNREACH;
goto error;
}
// 将安全路由加入到策略的路由项链表头, 该链表是以NULL结尾的单向链表
// 不过一般情况下应该只有一个元素
dst->next = policy->bundles;
policy->bundles = dst;
dst_hold(dst);
write_unlock_bh(&policy->lock);
}
// 将安全链表作为
*dst_p = dst;
dst_release(dst_orig);
xfrm_pols_put(pols, npols);
return 0;
goto error;
}
// 将安全路由加入到策略的路由项链表头, 该链表是以NULL结尾的单向链表
// 不过一般情况下应该只有一个元素
dst->next = policy->bundles;
policy->bundles = dst;
dst_hold(dst);
write_unlock_bh(&policy->lock);
}
// 将安全链表作为
*dst_p = dst;
dst_release(dst_orig);
xfrm_pols_put(pols, npols);
return 0;
error:
dst_release(dst_orig);
xfrm_pols_put(pols, npols);
*dst_p = NULL;
return err;
}
EXPORT_SYMBOL(xfrm_lookup);
dst_release(dst_orig);
xfrm_pols_put(pols, npols);
*dst_p = NULL;
return err;
}
EXPORT_SYMBOL(xfrm_lookup);
以下是在xfrm_lookup中用到的两个bundle的操作函数: 查找和创建, 由于使用了地址参数, 是和协议族相关的, 因此具体实现是在各协议族中实现的, 在后续文章中介绍协议族中的xfrm实现时再详细介绍.
static struct dst_entry *
xfrm_find_bundle(struct flowi *fl, struct xfrm_policy *policy, unsigned short family)
{
struct dst_entry *x;
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return ERR_PTR(-EINVAL);
x = afinfo->find_bundle(fl, policy);
xfrm_policy_put_afinfo(afinfo);
return x;
}
static struct dst_entry *
xfrm_find_bundle(struct flowi *fl, struct xfrm_policy *policy, unsigned short family)
{
struct dst_entry *x;
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return ERR_PTR(-EINVAL);
x = afinfo->find_bundle(fl, policy);
xfrm_policy_put_afinfo(afinfo);
return x;
}
static int
xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
struct flowi *fl, struct dst_entry **dst_p,
unsigned short family)
{
int err;
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return -EINVAL;
err = afinfo->bundle_create(policy, xfrm, nx, fl, dst_p);
xfrm_policy_put_afinfo(afinfo);
return err;
}
xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
struct flowi *fl, struct dst_entry **dst_p,
unsigned short family)
{
int err;
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return -EINVAL;
err = afinfo->bundle_create(policy, xfrm, nx, fl, dst_p);
xfrm_policy_put_afinfo(afinfo);
return err;
}
// 策略解析, 生成SA
static int
xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl,
struct xfrm_state **xfrm,
unsigned short family)
{
struct xfrm_state *tp[XFRM_MAX_DEPTH];
// npols > 1是定义了子策略的情况, 这时用tp数组保存找到的SA, 但没法返回原函数中了
// 不明白为什么这么作
struct xfrm_state **tpp = (npols > 1) ? tp : xfrm;
int cnx = 0;
int error;
int ret;
int i;
// 遍历策略, 一般情况下npols其实只是1
for (i = 0; i < npols; i++) {
// 检查保存SA的缓冲区是否还够大
if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) {
error = -ENOBUFS;
goto fail;
}
// 协议一个策略模板
ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family);
if (ret < 0) {
error = ret;
goto fail;
} else
cnx += ret;
}
for (i = 0; i < npols; i++) {
// 检查保存SA的缓冲区是否还够大
if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) {
error = -ENOBUFS;
goto fail;
}
// 协议一个策略模板
ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family);
if (ret < 0) {
error = ret;
goto fail;
} else
cnx += ret;
}
// 多个策略的话对找到的SA排序, 在没定义子策略的情况下是个空函数
if (npols > 1)
xfrm_state_sort(xfrm, tpp, cnx, family);
return cnx;
fail:
for (cnx--; cnx>=0; cnx--)
xfrm_state_put(tpp[cnx]);
return error;
for (cnx--; cnx>=0; cnx--)
xfrm_state_put(tpp[cnx]);
return error;
}
static int
xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
struct xfrm_state **xfrm,
unsigned short family)
{
int nx;
int i, error;
// 从流结构中获取地址信息
xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
xfrm_address_t tmp;
// 遍历策略中的所有SA
for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
struct xfrm_state *x;
xfrm_address_t *remote = daddr;
xfrm_address_t *local = saddr;
struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
struct xfrm_state **xfrm,
unsigned short family)
{
int nx;
int i, error;
// 从流结构中获取地址信息
xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);
xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
xfrm_address_t tmp;
// 遍历策略中的所有SA
for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
struct xfrm_state *x;
xfrm_address_t *remote = daddr;
xfrm_address_t *local = saddr;
struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
if (tmpl->mode == XFRM_MODE_TUNNEL) {
// 如果是通道模式, 会添加外部IP头, 内部IP头都封装在内部, 因此地址信息使用外部地址
// 即策略的SA模板中的地址信息
remote = &tmpl->id.daddr;
local = &tmpl->saddr;
// 如果local地址没定义, 选取个源地址作为本地地址, 选取过程是协议族相关的
if (xfrm_addr_any(local, family)) {
error = xfrm_get_saddr(&tmp, remote, family);
if (error)
goto fail;
local = &tmp;
}
}
// 根据地址,流,策略等新查找SA(xfrm_state),如果找不到现成的会通知IKE程序进行协商
// 生成新的SA, 但生成可用SA前先返回ACQUIRE类型的SA, 见前一篇文章
x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
// 如果是通道模式, 会添加外部IP头, 内部IP头都封装在内部, 因此地址信息使用外部地址
// 即策略的SA模板中的地址信息
remote = &tmpl->id.daddr;
local = &tmpl->saddr;
// 如果local地址没定义, 选取个源地址作为本地地址, 选取过程是协议族相关的
if (xfrm_addr_any(local, family)) {
error = xfrm_get_saddr(&tmp, remote, family);
if (error)
goto fail;
local = &tmp;
}
}
// 根据地址,流,策略等新查找SA(xfrm_state),如果找不到现成的会通知IKE程序进行协商
// 生成新的SA, 但生成可用SA前先返回ACQUIRE类型的SA, 见前一篇文章
x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
if (x && x->km.state == XFRM_STATE_VALID) {
// 如果SA是合法, 保存
xfrm[nx++] = x;
daddr = remote;
saddr = local;
continue;
}
if (x) {
// x存在但不是VALID的, 只要不出错, 应该是ACQUIRE类型的, 等IKE进程协商结果, 返回-EAGAIN
error = (x->km.state == XFRM_STATE_ERROR ?
-EINVAL : -EAGAIN);
xfrm_state_put(x);
}
// 如果SA是合法, 保存
xfrm[nx++] = x;
daddr = remote;
saddr = local;
continue;
}
if (x) {
// x存在但不是VALID的, 只要不出错, 应该是ACQUIRE类型的, 等IKE进程协商结果, 返回-EAGAIN
error = (x->km.state == XFRM_STATE_ERROR ?
-EINVAL : -EAGAIN);
xfrm_state_put(x);
}
if (!tmpl->optional)
goto fail;
}
return nx;
goto fail;
}
return nx;
fail:
for (nx--; nx>=0; nx--)
xfrm_state_put(xfrm[nx]);
return error;
}
for (nx--; nx>=0; nx--)
xfrm_state_put(xfrm[nx]);
return error;
}
关于路由处理过程在后面介绍IPSEC包的发出过程时会介绍路由处理过程, 从而了解安全路由的作用.
5.6 变更HASH表大小
改变策略状态表的是通过工作队列来实现的, 和xfrm_state类似
工作定义:
static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize, NULL);
// 更改HASH表大小
static void xfrm_hash_resize(void *__unused)
{
int dir, total;
mutex_lock(&hash_resize_mutex);
total = 0;
// 注意策略都是双向的
for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
// 按目的地址进行HASH的链表: 如果需要更改HASH表大小, 修改之
if (xfrm_bydst_should_resize(dir, &total))
xfrm_bydst_resize(dir);
}
// 按索引号进行HASH的链表更新
if (xfrm_byidx_should_resize(total))
xfrm_byidx_resize(total);
// 注意策略都是双向的
for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
// 按目的地址进行HASH的链表: 如果需要更改HASH表大小, 修改之
if (xfrm_bydst_should_resize(dir, &total))
xfrm_bydst_resize(dir);
}
// 按索引号进行HASH的链表更新
if (xfrm_byidx_should_resize(total))
xfrm_byidx_resize(total);
mutex_unlock(&hash_resize_mutex);
}
}
// 检查按目的地址HASH的HASH链表
static inline int xfrm_bydst_should_resize(int dir, int *total)
{
// 该方向是策略的数量
unsigned int cnt = xfrm_policy_count[dir];
// 该方向是策略的掩码
unsigned int hmask = xfrm_policy_bydst[dir].hmask;
static inline int xfrm_bydst_should_resize(int dir, int *total)
{
// 该方向是策略的数量
unsigned int cnt = xfrm_policy_count[dir];
// 该方向是策略的掩码
unsigned int hmask = xfrm_policy_bydst[dir].hmask;
// 累加策略数量
if (total)
*total += cnt;
if (total)
*total += cnt;
// 如果策略数量大于策略掩码量, 该增加了
if ((hmask + 1) < xfrm_policy_hashmax &&
cnt > hmask)
return 1;
// 否则不用
return 0;
}
if ((hmask + 1) < xfrm_policy_hashmax &&
cnt > hmask)
return 1;
// 否则不用
return 0;
}
// 检查按索引号HASH的HASH链表
static inline int xfrm_byidx_should_resize(int total)
{
unsigned int hmask = xfrm_idx_hmask;
// 策略总量超过当前的索引号掩码, 该扩大了
if ((hmask + 1) < xfrm_policy_hashmax &&
total > hmask)
return 1;
static inline int xfrm_byidx_should_resize(int total)
{
unsigned int hmask = xfrm_idx_hmask;
// 策略总量超过当前的索引号掩码, 该扩大了
if ((hmask + 1) < xfrm_policy_hashmax &&
total > hmask)
return 1;
return 0;
}
}
// 更改按目的地址HASH的HASH链表大小
static void xfrm_bydst_resize(int dir)
{
// 该方向的HASH表掩码(最大值, 一般是2^N-1)
unsigned int hmask = xfrm_policy_bydst[dir].hmask;
// 新HASH表掩码(2^(N+1)-1)
unsigned int nhashmask = xfrm_new_hash_mask(hmask);
// 新HASH表大小
unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
// 老HAHS表
struct hlist_head *odst = xfrm_policy_bydst[dir].table;
// 新HASH表
struct hlist_head *ndst = xfrm_hash_alloc(nsize);
int i;
// 新HASH表空间分配不出来, 返回
if (!ndst)
return;
if (!ndst)
return;
write_lock_bh(&xfrm_policy_lock);
// 将所有策略节点转到新HASH表
for (i = hmask; i >= 0; i--)
xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
for (i = hmask; i >= 0; i--)
xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
// 将全局变量值更新为新HASH表参数
xfrm_policy_bydst[dir].table = ndst;
xfrm_policy_bydst[dir].hmask = nhashmask;
xfrm_policy_bydst[dir].table = ndst;
xfrm_policy_bydst[dir].hmask = nhashmask;
write_unlock_bh(&xfrm_policy_lock);
// 释放老HASH表参数
xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
}
// 释放老HASH表参数
xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head));
}
// 更改按索引号HASH的HASH链表大小, 操作和上面类似
static void xfrm_byidx_resize(int total)
{
unsigned int hmask = xfrm_idx_hmask;
unsigned int nhashmask = xfrm_new_hash_mask(hmask);
unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head);
struct hlist_head *oidx = xfrm_policy_byidx;
struct hlist_head *nidx = xfrm_hash_alloc(nsize);
int i;
if (!nidx)
return;
return;
write_lock_bh(&xfrm_policy_lock);
for (i = hmask; i >= 0; i--)
xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask);
xfrm_policy_byidx = nidx;
xfrm_idx_hmask = nhashmask;
xfrm_idx_hmask = nhashmask;
write_unlock_bh(&xfrm_policy_lock);
xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head));
}
}
5.7 垃圾搜集
垃圾搜集的是不用的安全路由项, 是和协议族相关的
afinfo->garbage_collect = __xfrm_garbage_collect;
// 就是xfrm_prune_bundles()函数的包装函数,条件是unused_bundle()函数定义
static void __xfrm_garbage_collect(void)
{
xfrm_prune_bundles(unused_bundle);
}
// 删减安全路由
static void xfrm_prune_bundles(int (*func)(struct dst_entry *))
{
// 垃圾链表
struct dst_entry *gc_list = NULL;
int dir;
read_lock_bh(&xfrm_policy_lock);
// 循环所有方向
for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
struct xfrm_policy *pol;
struct hlist_node *entry;
struct hlist_head *table;
int i;
// 遍历inexact链表
hlist_for_each_entry(pol, entry,
&xfrm_policy_inexact[dir], bydst)
// 如果节点满足条件就删除挂接到垃圾链表
prune_one_bundle(pol, func, &gc_list);
// 循环所有方向
for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
struct xfrm_policy *pol;
struct hlist_node *entry;
struct hlist_head *table;
int i;
// 遍历inexact链表
hlist_for_each_entry(pol, entry,
&xfrm_policy_inexact[dir], bydst)
// 如果节点满足条件就删除挂接到垃圾链表
prune_one_bundle(pol, func, &gc_list);
// 遍历目的地址HASH的链表
table = xfrm_policy_bydst[dir].table;
for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
// 如果节点满足条件就删除挂接到垃圾链表
hlist_for_each_entry(pol, entry, table + i, bydst)
prune_one_bundle(pol, func, &gc_list);
}
}
read_unlock_bh(&xfrm_policy_lock);
// 如果搜集到的垃圾, 释放安全路由
while (gc_list) {
struct dst_entry *dst = gc_list;
gc_list = dst->next;
dst_free(dst);
}
}
// 没用的路由, 使用数为0
static int unused_bundle(struct dst_entry *dst)
{
return !atomic_read(&dst->__refcnt);
}
static int unused_bundle(struct dst_entry *dst)
{
return !atomic_read(&dst->__refcnt);
}
// 删除单个路由
static void prune_one_bundle(struct xfrm_policy *pol, int (*func)(struct dst_entry *), struct dst_entry **gc_list_p)
{
struct dst_entry *dst, **dstp;
// 策略写锁
write_lock(&pol->lock);
// 策略的路由项链表起点
dstp = &pol->bundles;
// 遍历链表
while ((dst=*dstp) != NULL) {
if (func(dst)) {
// 如果满足条件, 将节点从链表中删除, 添加到垃圾链表
*dstp = dst->next;
dst->next = *gc_list_p;
*gc_list_p = dst;
} else {
dstp = &dst->next;
}
}
write_unlock(&pol->lock);
}
static void prune_one_bundle(struct xfrm_policy *pol, int (*func)(struct dst_entry *), struct dst_entry **gc_list_p)
{
struct dst_entry *dst, **dstp;
// 策略写锁
write_lock(&pol->lock);
// 策略的路由项链表起点
dstp = &pol->bundles;
// 遍历链表
while ((dst=*dstp) != NULL) {
if (func(dst)) {
// 如果满足条件, 将节点从链表中删除, 添加到垃圾链表
*dstp = dst->next;
dst->next = *gc_list_p;
*gc_list_p = dst;
} else {
dstp = &dst->next;
}
}
write_unlock(&pol->lock);
}
5.8 杂项
这些杂项并不是策略的直接处理函数, 而是xfrm的一些相关处理, 只是也放在xfrm_policy.c中了.
5.8.1 协议处理类型处理
xfrm_type用来定义各种协议处理类型, 如AH,ESP, IPCOMP, IPIP等
// 登记协议处理类型, 返回0成功, 非0失败
int xfrm_register_type(struct xfrm_type *type, unsigned short family)
{
// 找到协议族相关的策略信息结构
struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
struct xfrm_type **typemap;
int err = 0;
int xfrm_register_type(struct xfrm_type *type, unsigned short family)
{
// 找到协议族相关的策略信息结构
struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
struct xfrm_type **typemap;
int err = 0;
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
// 策略信息结构中的类型数组
typemap = afinfo->type_map;
return -EAFNOSUPPORT;
// 策略信息结构中的类型数组
typemap = afinfo->type_map;
// 如果数组中相应协议对应元素非空, 则赋值, 否则发生错误
if (likely(typemap[type->proto] == NULL))
typemap[type->proto] = type;
else
err = -EEXIST;
xfrm_policy_unlock_afinfo(afinfo);
return err;
}
EXPORT_SYMBOL(xfrm_register_type);
if (likely(typemap[type->proto] == NULL))
typemap[type->proto] = type;
else
err = -EEXIST;
xfrm_policy_unlock_afinfo(afinfo);
return err;
}
EXPORT_SYMBOL(xfrm_register_type);
// 拆除协议处理类型, 返回0成功, 非0失败
int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
{
// 找到协议族相关的策略信息结构
struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
struct xfrm_type **typemap;
int err = 0;
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
// 策略信息结构中的类型数组
typemap = afinfo->type_map;
return -EAFNOSUPPORT;
// 策略信息结构中的类型数组
typemap = afinfo->type_map;
// 如果数组中相应协议对应元素等于要删除的结构, 元素清空, 否则发生错误
if (unlikely(typemap[type->proto] != type))
err = -ENOENT;
else
typemap[type->proto] = NULL;
xfrm_policy_unlock_afinfo(afinfo);
return err;
}
EXPORT_SYMBOL(xfrm_unregister_type);
if (unlikely(typemap[type->proto] != type))
err = -ENOENT;
else
typemap[type->proto] = NULL;
xfrm_policy_unlock_afinfo(afinfo);
return err;
}
EXPORT_SYMBOL(xfrm_unregister_type);
// 根据协议号和协议族查找类型
struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
{
struct xfrm_policy_afinfo *afinfo;
struct xfrm_type **typemap;
struct xfrm_type *type;
int modload_attempted = 0;
struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
{
struct xfrm_policy_afinfo *afinfo;
struct xfrm_type **typemap;
struct xfrm_type *type;
int modload_attempted = 0;
retry:
// 找到协议族相关的策略信息结构
afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return NULL;
// 策略信息结构中的类型数组
typemap = afinfo->type_map;
// 找到协议族相关的策略信息结构
afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return NULL;
// 策略信息结构中的类型数组
typemap = afinfo->type_map;
// 数组中对应指定协议的元素
type = typemap[proto];
// 增加type模块的使用计数
if (unlikely(type && !try_module_get(type->owner)))
type = NULL;
// 如果当前type为空, 则加载type的内核模块, 重新查找
if (!type && !modload_attempted) {
xfrm_policy_put_afinfo(afinfo);
request_module("xfrm-type-%d-%d",
(int) family, (int) proto);
modload_attempted = 1;
goto retry;
}
type = typemap[proto];
// 增加type模块的使用计数
if (unlikely(type && !try_module_get(type->owner)))
type = NULL;
// 如果当前type为空, 则加载type的内核模块, 重新查找
if (!type && !modload_attempted) {
xfrm_policy_put_afinfo(afinfo);
request_module("xfrm-type-%d-%d",
(int) family, (int) proto);
modload_attempted = 1;
goto retry;
}
xfrm_policy_put_afinfo(afinfo);
return type;
}
return type;
}
// 释放类型模块使用计数
void xfrm_put_type(struct xfrm_type *type)
{
module_put(type->owner);
}
void xfrm_put_type(struct xfrm_type *type)
{
module_put(type->owner);
}
5.8.2 协议模式处理
模式目前包括通道和传输两种.
// 登记模式, 返回0成功, 非0失败
int xfrm_register_mode(struct xfrm_mode *mode, int family)
{
struct xfrm_policy_afinfo *afinfo;
struct xfrm_mode **modemap;
int err;
if (unlikely(mode->encap >= XFRM_MODE_MAX))
return -EINVAL;
return -EINVAL;
// 找到协议族相关的策略信息结构
afinfo = xfrm_policy_lock_afinfo(family);
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
afinfo = xfrm_policy_lock_afinfo(family);
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
err = -EEXIST;
// 策略信息结构中的模式数组
modemap = afinfo->mode_map;
// 数组元素非空的话赋值, 返回成功
if (likely(modemap[mode->encap] == NULL)) {
modemap[mode->encap] = mode;
err = 0;
}
// 策略信息结构中的模式数组
modemap = afinfo->mode_map;
// 数组元素非空的话赋值, 返回成功
if (likely(modemap[mode->encap] == NULL)) {
modemap[mode->encap] = mode;
err = 0;
}
xfrm_policy_unlock_afinfo(afinfo);
return err;
}
EXPORT_SYMBOL(xfrm_register_mode);
return err;
}
EXPORT_SYMBOL(xfrm_register_mode);
// 拆除模式, 返回0成功, 非0失败
int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
{
struct xfrm_policy_afinfo *afinfo;
struct xfrm_mode **modemap;
int err;
int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
{
struct xfrm_policy_afinfo *afinfo;
struct xfrm_mode **modemap;
int err;
if (unlikely(mode->encap >= XFRM_MODE_MAX))
return -EINVAL;
return -EINVAL;
// 找到协议族相关的策略信息结构
afinfo = xfrm_policy_lock_afinfo(family);
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
afinfo = xfrm_policy_lock_afinfo(family);
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
err = -ENOENT;
// 策略信息结构中的模式数组
modemap = afinfo->mode_map;
// 数组元素等于要拆除的模式, 清空, 返回成功
if (likely(modemap[mode->encap] == mode)) {
modemap[mode->encap] = NULL;
err = 0;
}
// 策略信息结构中的模式数组
modemap = afinfo->mode_map;
// 数组元素等于要拆除的模式, 清空, 返回成功
if (likely(modemap[mode->encap] == mode)) {
modemap[mode->encap] = NULL;
err = 0;
}
xfrm_policy_unlock_afinfo(afinfo);
return err;
}
EXPORT_SYMBOL(xfrm_unregister_mode);
return err;
}
EXPORT_SYMBOL(xfrm_unregister_mode);
// 查找模式
struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
{
struct xfrm_policy_afinfo *afinfo;
struct xfrm_mode *mode;
int modload_attempted = 0;
if (unlikely(encap >= XFRM_MODE_MAX))
return NULL;
return NULL;
retry:
// 找到协议族相关的策略信息结构
afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return NULL;
// 找到协议族相关的策略信息结构
afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return NULL;
// 策略信息结构中的模式数组
mode = afinfo->mode_map[encap];
// 增加模式模块的使用计数
if (unlikely(mode && !try_module_get(mode->owner)))
mode = NULL;
// 如果当前模式为空, 则加载模式对应的内核模块, 重新查找
if (!mode && !modload_attempted) {
xfrm_policy_put_afinfo(afinfo);
request_module("xfrm-mode-%d-%d", family, encap);
modload_attempted = 1;
goto retry;
}
mode = afinfo->mode_map[encap];
// 增加模式模块的使用计数
if (unlikely(mode && !try_module_get(mode->owner)))
mode = NULL;
// 如果当前模式为空, 则加载模式对应的内核模块, 重新查找
if (!mode && !modload_attempted) {
xfrm_policy_put_afinfo(afinfo);
request_module("xfrm-mode-%d-%d", family, encap);
modload_attempted = 1;
goto retry;
}
xfrm_policy_put_afinfo(afinfo);
return mode;
}
return mode;
}
// 释放模式模块使用计数
void xfrm_put_mode(struct xfrm_mode *mode)
{
module_put(mode->owner);
}
5.8.3 协议信息处理
// 登记协议信息结构
int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
{
int err = 0;
if (unlikely(afinfo == NULL))
return -EINVAL;
if (unlikely(afinfo->family >= NPROTO))
return -EAFNOSUPPORT;
write_lock_bh(&xfrm_policy_afinfo_lock);
// 数组中的对应协议的协议信息结构元素应该为空
if (unlikely(xfrm_policy_afinfo[afinfo->family] != NULL))
err = -ENOBUFS;
else {
// 安全路由操作结构
struct dst_ops *dst_ops = afinfo->dst_ops;
// 安全路由操作结构的参数和操作函数赋值
if (likely(dst_ops->kmem_cachep == NULL))
dst_ops->kmem_cachep = xfrm_dst_cache;
if (likely(dst_ops->check == NULL))
dst_ops->check = xfrm_dst_check;
if (likely(dst_ops->negative_advice == NULL))
dst_ops->negative_advice = xfrm_negative_advice;
if (likely(dst_ops->link_failure == NULL))
dst_ops->link_failure = xfrm_link_failure;
if (likely(afinfo->garbage_collect == NULL))
afinfo->garbage_collect = __xfrm_garbage_collect;
// 数组中的对应协议的协议信息结构元素填为协议信息结构
xfrm_policy_afinfo[afinfo->family] = afinfo;
}
write_unlock_bh(&xfrm_policy_afinfo_lock);
return err;
}
EXPORT_SYMBOL(xfrm_policy_register_afinfo);
int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
{
int err = 0;
if (unlikely(afinfo == NULL))
return -EINVAL;
if (unlikely(afinfo->family >= NPROTO))
return -EAFNOSUPPORT;
write_lock_bh(&xfrm_policy_afinfo_lock);
// 数组中的对应协议的协议信息结构元素应该为空
if (unlikely(xfrm_policy_afinfo[afinfo->family] != NULL))
err = -ENOBUFS;
else {
// 安全路由操作结构
struct dst_ops *dst_ops = afinfo->dst_ops;
// 安全路由操作结构的参数和操作函数赋值
if (likely(dst_ops->kmem_cachep == NULL))
dst_ops->kmem_cachep = xfrm_dst_cache;
if (likely(dst_ops->check == NULL))
dst_ops->check = xfrm_dst_check;
if (likely(dst_ops->negative_advice == NULL))
dst_ops->negative_advice = xfrm_negative_advice;
if (likely(dst_ops->link_failure == NULL))
dst_ops->link_failure = xfrm_link_failure;
if (likely(afinfo->garbage_collect == NULL))
afinfo->garbage_collect = __xfrm_garbage_collect;
// 数组中的对应协议的协议信息结构元素填为协议信息结构
xfrm_policy_afinfo[afinfo->family] = afinfo;
}
write_unlock_bh(&xfrm_policy_afinfo_lock);
return err;
}
EXPORT_SYMBOL(xfrm_policy_register_afinfo);
// 拆除协议信息结构
int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
{
int err = 0;
if (unlikely(afinfo == NULL))
return -EINVAL;
if (unlikely(afinfo->family >= NPROTO))
return -EAFNOSUPPORT;
write_lock_bh(&xfrm_policy_afinfo_lock);
if (likely(xfrm_policy_afinfo[afinfo->family] != NULL)) {
// 数组中的协议信息结构等于指定的信息结构
if (unlikely(xfrm_policy_afinfo[afinfo->family] != afinfo))
err = -EINVAL;
else {
// 清空协议信息数组元素和路由操作结构参数
struct dst_ops *dst_ops = afinfo->dst_ops;
xfrm_policy_afinfo[afinfo->family] = NULL;
dst_ops->kmem_cachep = NULL;
dst_ops->check = NULL;
dst_ops->negative_advice = NULL;
dst_ops->link_failure = NULL;
afinfo->garbage_collect = NULL;
}
}
write_unlock_bh(&xfrm_policy_afinfo_lock);
return err;
}
EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
// 查找协议信息结构, 加读锁
static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
{
struct xfrm_policy_afinfo *afinfo;
if (unlikely(family >= NPROTO))
return NULL;
read_lock(&xfrm_policy_afinfo_lock);
// 获取指定协议位置处的协议信息结构
afinfo = xfrm_policy_afinfo[family];
// 如果该协议信息结构不存在, 解锁
if (unlikely(!afinfo))
read_unlock(&xfrm_policy_afinfo_lock);
return afinfo;
}
// 释放协议信息结构, 解读锁
static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
{
read_unlock(&xfrm_policy_afinfo_lock);
}
// 协议信息结构加写锁, 返回指定的协议信息结构, 错误时返回NULL
static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family)
{
struct xfrm_policy_afinfo *afinfo;
if (unlikely(family >= NPROTO))
return NULL;
write_lock_bh(&xfrm_policy_afinfo_lock);
// 获取指定协议位置处的协议信息结构
afinfo = xfrm_policy_afinfo[family];
// 如果该协议信息结构不存在, 解锁
if (unlikely(!afinfo))
write_unlock_bh(&xfrm_policy_afinfo_lock);
return afinfo;
}
// 协议信息结构解写锁
static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo)
{
write_unlock_bh(&xfrm_policy_afinfo_lock);
}
static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo)
{
write_unlock_bh(&xfrm_policy_afinfo_lock);
}
5.8.4 网卡回调
// 网卡通知结构
static struct notifier_block xfrm_dev_notifier = {
xfrm_dev_event,
NULL,
0
};
// 回调函数
static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
switch (event) {
// 就只响应网卡停事件, 删除和网卡相关的所有安全路由项
case NETDEV_DOWN:
xfrm_flush_bundles();
}
return NOTIFY_DONE;
}
static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
switch (event) {
// 就只响应网卡停事件, 删除和网卡相关的所有安全路由项
case NETDEV_DOWN:
xfrm_flush_bundles();
}
return NOTIFY_DONE;
}
static int xfrm_flush_bundles(void)
{
// 也是使用xfrm_prune_bundles()函数进行删除操作
// 条件函数是stale_bundle
xfrm_prune_bundles(stale_bundle);
return 0;
}
{
// 也是使用xfrm_prune_bundles()函数进行删除操作
// 条件函数是stale_bundle
xfrm_prune_bundles(stale_bundle);
return 0;
}
// 判断安全路由项是否可用
// 返回1表示不可用, 0表示可用
static int stale_bundle(struct dst_entry *dst)
{
return !xfrm_bundle_ok(NULL, (struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0);
}
// 返回1表示不可用, 0表示可用
static int stale_bundle(struct dst_entry *dst)
{
return !xfrm_bundle_ok(NULL, (struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0);
}
// 返回0表示不可用, 1表示可用
int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
struct flowi *fl, int family, int strict)
{
struct dst_entry *dst = &first->u.dst;
struct xfrm_dst *last;
u32 mtu;
int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
struct flowi *fl, int family, int strict)
{
struct dst_entry *dst = &first->u.dst;
struct xfrm_dst *last;
u32 mtu;
// 检查路由项
if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
// 检查网卡是否在运行
(dst->dev && !netif_running(dst->dev)))
return 0;
if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
// 检查网卡是否在运行
(dst->dev && !netif_running(dst->dev)))
return 0;
last = NULL;
do {
// 安全路由
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
// 安全路由
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
// 检查SA选择子是否匹配流结构
if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family))
return 0;
if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm, pol))
return 0;
// 检查SA状态是否合法
if (dst->xfrm->km.state != XFRM_STATE_VALID)
return 0;
if (xdst->genid != dst->xfrm->genid)
return 0;
if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family))
return 0;
if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm, pol))
return 0;
// 检查SA状态是否合法
if (dst->xfrm->km.state != XFRM_STATE_VALID)
return 0;
if (xdst->genid != dst->xfrm->genid)
return 0;
// 严格检查时, 检查非通道模式下的SA地址和流结构参数是否匹配
if (strict && fl && dst->xfrm->props.mode != XFRM_MODE_TUNNEL &&
!xfrm_state_addr_flow_check(dst->xfrm, fl, family))
return 0;
// 子路由项的MTU
mtu = dst_mtu(dst->child);
if (xdst->child_mtu_cached != mtu) {
last = xdst;
xdst->child_mtu_cached = mtu;
}
// 通用路由检查
if (!dst_check(xdst->route, xdst->route_cookie))
return 0;
if (strict && fl && dst->xfrm->props.mode != XFRM_MODE_TUNNEL &&
!xfrm_state_addr_flow_check(dst->xfrm, fl, family))
return 0;
// 子路由项的MTU
mtu = dst_mtu(dst->child);
if (xdst->child_mtu_cached != mtu) {
last = xdst;
xdst->child_mtu_cached = mtu;
}
// 通用路由检查
if (!dst_check(xdst->route, xdst->route_cookie))
return 0;
// 安全路由相关的普通路由的MTU
mtu = dst_mtu(xdst->route);
if (xdst->route_mtu_cached != mtu) {
last = xdst;
xdst->route_mtu_cached = mtu;
}
// 遍历安全路由链表
dst = dst->child;
} while (dst->xfrm);
mtu = dst_mtu(xdst->route);
if (xdst->route_mtu_cached != mtu) {
last = xdst;
xdst->route_mtu_cached = mtu;
}
// 遍历安全路由链表
dst = dst->child;
} while (dst->xfrm);
// last是最后一个和子路由和普通路由的MTU不同的安全路由, 一般都是相同的
if (likely(!last))
return 1;
if (likely(!last))
return 1;
// 调整各路由项中的MTU
mtu = last->child_mtu_cached;
for (;;) {
dst = &last->u.dst;
mtu = last->child_mtu_cached;
for (;;) {
dst = &last->u.dst;
mtu = xfrm_state_mtu(dst->xfrm, mtu);
if (mtu > last->route_mtu_cached)
mtu = last->route_mtu_cached;
dst->metrics[RTAX_MTU-1] = mtu;
if (mtu > last->route_mtu_cached)
mtu = last->route_mtu_cached;
dst->metrics[RTAX_MTU-1] = mtu;
if (last == first)
break;
break;
last = last->u.next;
last->child_mtu_cached = mtu;
}
last->child_mtu_cached = mtu;
}
return 1;
}
}
5.9 小结
xfrm_policy相关函数的调用被调用关系可如下简单表示:
ip_route_output_flow
->xfrm_lookup: find xfrm_dst for the skb, create dst_list
-> xfrm_sk_policy_lookup
-> flow_cache_lookup
-> xfrm_find_bundle
-> xfrm_policy_lookup_bytype
-> xfrm_tmpl_resolve
-> xfrm_tmpl_resolve_one
-> xfrm_get_saddr
-> afinfo->get_saddr == xfrm4_get_saddr
-> xfrm4_dst_lookup
-> xfrm_state_find
-> __xfrm_state_lookup
-> xfrm_state_alloc
-> km_query
-> km->acquire (pfkey_acquire, xfrm_send_acquire)
-> xfrm_state_sort
-> afinfo->state_sort == NULL
-> km_wait_queue
-> xfrm_bundle_create
->xfrm_lookup: find xfrm_dst for the skb, create dst_list
-> xfrm_sk_policy_lookup
-> flow_cache_lookup
-> xfrm_find_bundle
-> xfrm_policy_lookup_bytype
-> xfrm_tmpl_resolve
-> xfrm_tmpl_resolve_one
-> xfrm_get_saddr
-> afinfo->get_saddr == xfrm4_get_saddr
-> xfrm4_dst_lookup
-> xfrm_state_find
-> __xfrm_state_lookup
-> xfrm_state_alloc
-> km_query
-> km->acquire (pfkey_acquire, xfrm_send_acquire)
-> xfrm_state_sort
-> afinfo->state_sort == NULL
-> km_wait_queue
-> xfrm_bundle_create
do_ip_setsockopt
-> xfrm_user_policy
-> km->compile_policy
-> xfrm_sk_policy_insert
pfkey_compile_policy
-> xfrm_policy_alloc
timer.func=xfrm_policy_timer
-> xfrm_policy_alloc
timer.func=xfrm_policy_timer
pfkey_spdadd
-> xfrm_policy_alloc
-> xfrm_policy_insert
-> policy_hash_bysel
-> selector_cmp
-> xfrm_sel_ctx_match
pfkey_spddelete
-> xfrm_policy_bysel_ctx
-> policy_hash_bysel
-> xfrm_sel_ctx_match
-> xfrm_policy_bysel_ctx
-> policy_hash_bysel
-> xfrm_sel_ctx_match
pfkey_spdget
-> xfrm_policy_byid
-> xfrm_policy_byid
xfrm_flush_policy
pfkey_policy_flush
-> xfrm_policy_flush
-> xfrm_policy_kill
xfrm_dump_policy
-> xfrm_policy_walk
-> dump_one_policy
pfkey_spddump
-> xfrm_policy_walk
-> dump_sp
gen_reqid
-> xfrm_policy_walk
-> check_reqid
xfrm_add_pol_expire
xfrm_policy_timer
-> xfrm_policy_delete
-> __xfrm_policy_unlink
-> xfrm_policy_kill
xfrm_sk_policy_insert
-> xfrm_get_index
-> __xfrm_policy_link
-> __xfrm_policy_unlink
-> xfrm_policy_kill
xfrm_sk_clone_policy
-> __xfrm_sk_clone_policy
-> clone_policy
-> xfrm_policy_alloc
-> __xfrm_policy_link
xfrm_decode_session
-> xfrm4_decode_session
xfrm4_route_forward
-> xfrm_route_forward
-> __xfrm_route_forward
-> xfrm4_decode_session
-> xfrm_lookup
xfrm4_policy_check
-> xfrm_policy_check
-> __xfrm_policy_check
-> xfrm4_decode_session
-> __xfrm_sk_policy_lookup
-> xfrm_selector_match
-> __flow_cache_lookup
-> xfrm_policy_lookup
-> xfrm_policy_lookup_bytype
-> policy_hash_direct
-> xfrm_policy_match
-> xfrm_selector_match
-> xfrm_policy_lookup_bytype
-> xfrm_tmpl_sort
-> xfrm_policy_ok
-> xfrm_state_ok
xfrm_flush_bundles
-> xfrm_prune_bundles
-> prune_one_bundles
-> stale_bundle
-> xfrm_prune_bundles
-> prune_one_bundles
-> stale_bundle
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341