quhr 发表于 2011-12-21 08:43

Linux内核中PF_KEY协议族的实现(3)

本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。<br>msn: <a href="mailto:yfydz_no1@hotmail.com" target="_blank">yfydz_no1@hotmail.com</a><br>来源:<a href="http://yfydz.cublog.cn/" target="_blank">http://yfydz.cublog.cn</a>
<div>&nbsp;</div>
<div>5.10 添加/更新SPD(安全策略)</div>
<div>// 添加安全策略到安全策略数据库SPDB<br>static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)<br>{<br>&nbsp;int err = 0;<br>&nbsp;struct sadb_lifetime *lifetime;<br>&nbsp;struct sadb_address *sa;<br>&nbsp;struct sadb_x_policy *pol;<br>&nbsp;struct xfrm_policy *xp;<br>&nbsp;struct km_event c;<br>&nbsp;struct sadb_x_sec_ctx *sec_ctx;</div>
<div>// 错误检查, 源目的地址类型要一致, 策略信息非空<br>&nbsp;if (!present_and_same_family(ext_hdrs,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ext_hdrs) ||<br>&nbsp;&nbsp;&nbsp;&nbsp; !ext_hdrs)<br>&nbsp;&nbsp;return -EINVAL;<br>// 策略指针<br>&nbsp;pol = ext_hdrs;<br>// 策略类型只能是DISCARD, NONE和IPSEC三者之一<br>&nbsp;if (pol-&gt;sadb_x_policy_type &gt; IPSEC_POLICY_IPSEC)<br>&nbsp;&nbsp;return -EINVAL;<br>// 必须明确该SP作用于哪个方向的的数据: IN, OUT和FORWARD, 最后那个不是RFC标准的<br>&nbsp;if (!pol-&gt;sadb_x_policy_dir || pol-&gt;sadb_x_policy_dir &gt;= IPSEC_DIR_MAX)<br>&nbsp;&nbsp;return -EINVAL;</div>
<div>// 分配xfrm策略<br>&nbsp;xp = xfrm_policy_alloc(GFP_KERNEL);<br>&nbsp;if (xp == NULL)<br>&nbsp;&nbsp;return -ENOBUFS;<br>// 策略的动作: 阻塞还是放行<br>&nbsp;xp-&gt;action = (pol-&gt;sadb_x_policy_type == IPSEC_POLICY_DISCARD ?<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW);<br>// 策略的优先级<br>&nbsp;xp-&gt;priority = pol-&gt;sadb_x_policy_priority;</div>
<div>// 获取策略源地址及地址类型(v4 or v6)<br>&nbsp;sa = ext_hdrs, <br>&nbsp;xp-&gt;family = pfkey_sadb_addr2xfrm_addr(sa, &amp;xp-&gt;selector.saddr);<br>&nbsp;if (!xp-&gt;family) {<br>&nbsp;&nbsp;err = -EINVAL;<br>&nbsp;&nbsp;goto out;<br>&nbsp;}<br>// 填充策略选择子结构参数, 选择子中包括用来辨别策略的相关参数, 用来查找匹配策略<br>// 协议族<br>&nbsp;xp-&gt;selector.family = xp-&gt;family;<br>// 地址长度<br>&nbsp;xp-&gt;selector.prefixlen_s = sa-&gt;sadb_address_prefixlen;<br>// 协议<br>&nbsp;xp-&gt;selector.proto = pfkey_proto_to_xfrm(sa-&gt;sadb_address_proto);<br>// 策略中可以有上层协议的源端口参数, 不过不是必须的<br>&nbsp;xp-&gt;selector.sport = ((struct sockaddr_in *)(sa+1))-&gt;sin_port;<br>&nbsp;if (xp-&gt;selector.sport)<br>&nbsp;&nbsp;xp-&gt;selector.sport_mask = htons(0xffff);</div>
<div>// 获取策略目的地址及地址类型(v4 or v6)<br>// 和源地址处理类似<br>&nbsp;sa = ext_hdrs, <br>&nbsp;pfkey_sadb_addr2xfrm_addr(sa, &amp;xp-&gt;selector.daddr);<br>&nbsp;xp-&gt;selector.prefixlen_d = sa-&gt;sadb_address_prefixlen;</div>
<div>&nbsp;/* Amusing, we set this twice.&nbsp; KAME apps appear to set same value<br>&nbsp; * in both addresses.<br>&nbsp; */<br>&nbsp;xp-&gt;selector.proto = pfkey_proto_to_xfrm(sa-&gt;sadb_address_proto);</div>
<div>&nbsp;xp-&gt;selector.dport = ((struct sockaddr_in *)(sa+1))-&gt;sin_port;<br>&nbsp;if (xp-&gt;selector.dport)<br>&nbsp;&nbsp;xp-&gt;selector.dport_mask = htons(0xffff);</div>
<div>// 用户定义的安全上下文<br>&nbsp;sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs;<br>&nbsp;if (sec_ctx != NULL) {<br>&nbsp;&nbsp;struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);</div>
<div>&nbsp;&nbsp;if (!uctx) {<br>&nbsp;&nbsp;&nbsp;err = -ENOBUFS;<br>&nbsp;&nbsp;&nbsp;goto out;<br>&nbsp;&nbsp;}</div>
<div>&nbsp;&nbsp;err = security_xfrm_policy_alloc(xp, uctx);<br>&nbsp;&nbsp;kfree(uctx);</div>
<div>&nbsp;&nbsp;if (err)<br>&nbsp;&nbsp;&nbsp;goto out;<br>&nbsp;}</div>
<div>// lft: xfrm_lifetime_config, 生存时间配置参数<br>// 关于字节数和包数的软硬限制初始化<br>&nbsp;xp-&gt;lft.soft_byte_limit = XFRM_INF;<br>&nbsp;xp-&gt;lft.hard_byte_limit = XFRM_INF;<br>&nbsp;xp-&gt;lft.soft_packet_limit = XFRM_INF;<br>&nbsp;xp-&gt;lft.hard_packet_limit = XFRM_INF;<br>// 如果在消息中定义了限制, 设置之<br>&nbsp;if ((lifetime = ext_hdrs) != NULL) {<br>&nbsp;&nbsp;xp-&gt;lft.hard_packet_limit = _KEY2X(lifetime-&gt;sadb_lifetime_allocations);<br>&nbsp;&nbsp;xp-&gt;lft.hard_byte_limit = _KEY2X(lifetime-&gt;sadb_lifetime_bytes);<br>&nbsp;&nbsp;xp-&gt;lft.hard_add_expires_seconds = lifetime-&gt;sadb_lifetime_addtime;<br>&nbsp;&nbsp;xp-&gt;lft.hard_use_expires_seconds = lifetime-&gt;sadb_lifetime_usetime;<br>&nbsp;}<br>&nbsp;if ((lifetime = ext_hdrs) != NULL) {<br>&nbsp;&nbsp;xp-&gt;lft.soft_packet_limit = _KEY2X(lifetime-&gt;sadb_lifetime_allocations);<br>&nbsp;&nbsp;xp-&gt;lft.soft_byte_limit = _KEY2X(lifetime-&gt;sadb_lifetime_bytes);<br>&nbsp;&nbsp;xp-&gt;lft.soft_add_expires_seconds = lifetime-&gt;sadb_lifetime_addtime;<br>&nbsp;&nbsp;xp-&gt;lft.soft_use_expires_seconds = lifetime-&gt;sadb_lifetime_usetime;<br>&nbsp;}<br>&nbsp;xp-&gt;xfrm_nr = 0;<br>// 如果是IPSEC策略, 解析相关请求<br>&nbsp;if (pol-&gt;sadb_x_policy_type == IPSEC_POLICY_IPSEC &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp; (err = parse_ipsecrequests(xp, pol)) &lt; 0)<br>&nbsp;&nbsp;goto out;</div>
<div>// 将策略xp插入内核SPDB<br>&nbsp;err = xfrm_policy_insert(pol-&gt;sadb_x_policy_dir-1, xp,<br>// 一般是添加, 也可以是更新<br>&nbsp;&nbsp;&nbsp;&nbsp; hdr-&gt;sadb_msg_type != SADB_X_SPDUPDATE);</div>
<div>&nbsp;if (err)<br>&nbsp;&nbsp;goto out;</div>
<div>&nbsp;if (hdr-&gt;sadb_msg_type == SADB_X_SPDUPDATE)<br>&nbsp;&nbsp;c.event = XFRM_MSG_UPDPOLICY;<br>&nbsp;else <br>&nbsp;&nbsp;c.event = XFRM_MSG_NEWPOLICY;</div>
<div>&nbsp;c.seq = hdr-&gt;sadb_msg_seq;<br>&nbsp;c.pid = hdr-&gt;sadb_msg_pid;<br>// 策略通知回调处理<br>&nbsp;km_policy_notify(xp, pol-&gt;sadb_x_policy_dir-1, &amp;c);<br>&nbsp;xfrm_pol_put(xp);<br>&nbsp;return 0;</div>
<div>out:<br>&nbsp;security_xfrm_policy_free(xp);<br>&nbsp;kfree(xp);<br>&nbsp;return err;<br>}</div>
<div>/* net/xfrm/xfrm_policy.c */<br>// 插入策略<br>int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)<br>{<br>&nbsp;struct xfrm_policy *pol;<br>&nbsp;struct xfrm_policy *delpol;<br>&nbsp;struct hlist_head *chain;<br>&nbsp;struct hlist_node *entry, *newpos, *last;<br>&nbsp;struct dst_entry *gc_list;</div>
<div>&nbsp;write_lock_bh(&amp;xfrm_policy_lock);<br>// 找到具体的hash链表, SPDB也是用HASH表实现的<br>&nbsp;chain = policy_hash_bysel(&amp;policy-&gt;selector, policy-&gt;family, dir);<br>&nbsp;delpol = NULL;<br>&nbsp;newpos = NULL;<br>&nbsp;last = NULL;<br>// 遍历链表, 该链表是以策略的优先级值进行排序的链表, 因此需要根据新策略的优先级大小<br>// 将新策略插到合适的位置<br>&nbsp;hlist_for_each_entry(pol, entry, chain, bydst) {<br>// delpol要为空<br>&nbsp;&nbsp;if (!delpol &amp;&amp;<br>// 策略类型比较<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pol-&gt;type == policy-&gt;type &amp;&amp;<br>// 选择子比较<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; !selector_cmp(&amp;pol-&gt;selector, &amp;policy-&gt;selector) &amp;&amp;<br>// 安全上下文比较<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xfrm_sec_ctx_match(pol-&gt;security, policy-&gt;security)) {<br>// 找到了<br>&nbsp;&nbsp;&nbsp;if (excl) {<br>// 如果是添加操作, 要插入的策略在数据库中已经存在, 发生错误<br>&nbsp;&nbsp;&nbsp;&nbsp;write_unlock_bh(&amp;xfrm_policy_lock);<br>&nbsp;&nbsp;&nbsp;&nbsp;return -EEXIST;<br>&nbsp;&nbsp;&nbsp;}<br>// 保存好要删除的策略位置<br>&nbsp;&nbsp;&nbsp;delpol = pol;<br>// 要更新的策略优先级值大于原有的优先级值, 重新循环找到合适的插入位置<br>// 因为这个链表是以优先级值进行排序的, 不能乱<br>// 现在delpol已经非空了,&nbsp; 前面的策略查找条件已经不可能满足了<br>&nbsp;&nbsp;&nbsp;if (policy-&gt;priority &gt; pol-&gt;priority)<br>&nbsp;&nbsp;&nbsp;&nbsp;continue;<br>&nbsp;&nbsp;} else if (policy-&gt;priority &gt;= pol-&gt;priority) {<br>// 如果新的优先级不低于当前的优先级, 保存当前节点, 继续查找合适插入位置<br>&nbsp;&nbsp;&nbsp;last = &amp;pol-&gt;bydst;<br>&nbsp;&nbsp;&nbsp;continue;<br>&nbsp;&nbsp;}<br>// 这里是根据新策略的优先级确定的插入位置<br>&nbsp;&nbsp;if (!newpos)<br>&nbsp;&nbsp;&nbsp;newpos = &amp;pol-&gt;bydst;<br>// 如果已经找到要删除的策略, 中断<br>&nbsp;&nbsp;if (delpol)<br>&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;last = &amp;pol-&gt;bydst;<br>&nbsp;}<br>&nbsp;if (!newpos)<br>&nbsp;&nbsp;newpos = last;<br>// 插入策略到按目的地址HASH的链表<br>&nbsp;if (newpos)<br>&nbsp;&nbsp;hlist_add_after(newpos, &amp;policy-&gt;bydst);<br>&nbsp;else<br>&nbsp;&nbsp;hlist_add_head(&amp;policy-&gt;bydst, chain);<br>&nbsp;xfrm_pol_hold(policy);<br>&nbsp;xfrm_policy_count++;<br>&nbsp;atomic_inc(&amp;flow_cache_genid);<br>// 如果有相同的老策略, 要从目的地址HASH和索引号HASH这两个表中删除<br>&nbsp;if (delpol) {<br>&nbsp;&nbsp;hlist_del(&amp;delpol-&gt;bydst);<br>&nbsp;&nbsp;hlist_del(&amp;delpol-&gt;byidx);<br>&nbsp;&nbsp;xfrm_policy_count--;<br>&nbsp;}<br>// 获取策略索引号, 插入索引HASH链表<br>&nbsp;policy-&gt;index = delpol ? delpol-&gt;index : xfrm_gen_index(policy-&gt;type, dir);<br>&nbsp;hlist_add_head(&amp;policy-&gt;byidx, xfrm_policy_byidx+idx_hash(policy-&gt;index));<br>// 策略插入实际时间<br>&nbsp;policy-&gt;curlft.add_time = (unsigned long)xtime.tv_sec;<br>&nbsp;policy-&gt;curlft.use_time = 0;<br>&nbsp;if (!mod_timer(&amp;policy-&gt;timer, jiffies + HZ))<br>&nbsp;&nbsp;xfrm_pol_hold(policy);<br>&nbsp;write_unlock_bh(&amp;xfrm_policy_lock);</div>
<div>// 释放老策略<br>&nbsp;if (delpol)<br>&nbsp;&nbsp;xfrm_policy_kill(delpol);<br>&nbsp;else if (xfrm_bydst_should_resize(dir, NULL))<br>&nbsp;&nbsp;schedule_work(&amp;xfrm_hash_work);</div>
<div>// 下面释放所有策略当前的路由cache<br>&nbsp;read_lock_bh(&amp;xfrm_policy_lock);<br>&nbsp;gc_list = NULL;<br>&nbsp;entry = &amp;policy-&gt;bydst;<br>// 遍历链表, 搜集垃圾路由cache建立链表<br>&nbsp;hlist_for_each_entry_continue(policy, entry, bydst) {<br>&nbsp;&nbsp;struct dst_entry *dst;</div>
<div>&nbsp;&nbsp;write_lock(&amp;policy-&gt;lock);<br>&nbsp;&nbsp;dst = policy-&gt;bundles;<br>&nbsp;&nbsp;if (dst) {<br>&nbsp;&nbsp;&nbsp;struct dst_entry *tail = dst;<br>&nbsp;&nbsp;&nbsp;while (tail-&gt;next)<br>&nbsp;&nbsp;&nbsp;&nbsp;tail = tail-&gt;next;<br>&nbsp;&nbsp;&nbsp;tail-&gt;next = gc_list;<br>&nbsp;&nbsp;&nbsp;gc_list = dst;</div>
<div>&nbsp;&nbsp;&nbsp;policy-&gt;bundles = NULL;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;write_unlock(&amp;policy-&gt;lock);<br>&nbsp;}<br>&nbsp;read_unlock_bh(&amp;xfrm_policy_lock);<br>// 释放垃圾路由cahce<br>&nbsp;while (gc_list) {<br>&nbsp;&nbsp;struct dst_entry *dst = gc_list;</div>
<div>&nbsp;&nbsp;gc_list = dst-&gt;next;<br>&nbsp;&nbsp;dst_free(dst);<br>&nbsp;}</div>
<div>&nbsp;return 0;<br>}<br>EXPORT_SYMBOL(xfrm_policy_insert);</div>
<div><br>5.11 删除SPD</div>
<div><br>static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)<br>{<br>&nbsp;int err;<br>&nbsp;struct sadb_address *sa;<br>&nbsp;struct sadb_x_policy *pol;<br>&nbsp;struct xfrm_policy *xp, tmp;<br>&nbsp;struct xfrm_selector sel;<br>&nbsp;struct km_event c;<br>&nbsp;struct sadb_x_sec_ctx *sec_ctx;</div>
<div>// 错误检查, 源目的地址类型要一致, 策略信息非空<br>&nbsp;if (!present_and_same_family(ext_hdrs,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ext_hdrs) ||<br>&nbsp;&nbsp;&nbsp;&nbsp; !ext_hdrs)<br>&nbsp;&nbsp;return -EINVAL;<br>// 消息中定义的策略<br>&nbsp;pol = ext_hdrs;<br>// 策略类型合法性检查<br>&nbsp;if (!pol-&gt;sadb_x_policy_dir || pol-&gt;sadb_x_policy_dir &gt;= IPSEC_DIR_MAX)<br>&nbsp;&nbsp;return -EINVAL;</div>
<div>&nbsp;memset(&amp;sel, 0, sizeof(sel));<br>// 解析消息中的源地址参数填充到选择子结构中<br>&nbsp;sa = ext_hdrs, <br>&nbsp;sel.family = pfkey_sadb_addr2xfrm_addr(sa, &amp;sel.saddr);<br>&nbsp;sel.prefixlen_s = sa-&gt;sadb_address_prefixlen;<br>&nbsp;sel.proto = pfkey_proto_to_xfrm(sa-&gt;sadb_address_proto);<br>&nbsp;sel.sport = ((struct sockaddr_in *)(sa+1))-&gt;sin_port;<br>&nbsp;if (sel.sport)<br>&nbsp;&nbsp;sel.sport_mask = htons(0xffff);</div>
<div>// 解析消息中的目的地址参数填充到选择子结构中<br>&nbsp;sa = ext_hdrs, <br>&nbsp;pfkey_sadb_addr2xfrm_addr(sa, &amp;sel.daddr);<br>&nbsp;sel.prefixlen_d = sa-&gt;sadb_address_prefixlen;<br>&nbsp;sel.proto = pfkey_proto_to_xfrm(sa-&gt;sadb_address_proto);<br>&nbsp;sel.dport = ((struct sockaddr_in *)(sa+1))-&gt;sin_port;<br>&nbsp;if (sel.dport)<br>&nbsp;&nbsp;sel.dport_mask = htons(0xffff);</div>
<div>&nbsp;sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs;<br>&nbsp;memset(&amp;tmp, 0, sizeof(struct xfrm_policy));<br>// 扩展的用户安全上下文信息处理<br>&nbsp;if (sec_ctx != NULL) {<br>&nbsp;&nbsp;struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);</div>
<div>&nbsp;&nbsp;if (!uctx)<br>&nbsp;&nbsp;&nbsp;return -ENOMEM;</div>
<div>&nbsp;&nbsp;err = security_xfrm_policy_alloc(&amp;tmp, uctx);<br>&nbsp;&nbsp;kfree(uctx);</div>
<div>&nbsp;&nbsp;if (err)<br>&nbsp;&nbsp;&nbsp;return err;<br>&nbsp;}<br>// 根据策略类型, 处理的数据方向, 选择子参数等信息查找策略<br>// 同时最后一个参数为1表示找到后将策略从系统的SPDB链表中断开后删除<br>&nbsp;xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol-&gt;sadb_x_policy_dir-1,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;sel, tmp.security, 1);<br>&nbsp;security_xfrm_policy_free(&amp;tmp);<br>// 没有该策略, 出错<br>&nbsp;if (xp == NULL)<br>&nbsp;&nbsp;return -ENOENT;</div>
<div>&nbsp;err = 0;</div>
<div>&nbsp;if ((err = security_xfrm_policy_delete(xp)))<br>&nbsp;&nbsp;goto out;<br>&nbsp;c.seq = hdr-&gt;sadb_msg_seq;<br>&nbsp;c.pid = hdr-&gt;sadb_msg_pid;<br>&nbsp;c.event = XFRM_MSG_DELPOLICY;<br>// 反方向的策略通知回调处理<br>&nbsp;km_policy_notify(xp, pol-&gt;sadb_x_policy_dir-1, &amp;c);</div>
<div>out:<br>// 释放策略<br>&nbsp;xfrm_pol_put(xp);<br>&nbsp;return err;<br>}</div>
<div>/* net/xfrm/xfrm_policy.c */<br>// 根据选择子和上下文查找策略<br>struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct xfrm_selector *sel,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct xfrm_sec_ctx *ctx, int delete)<br>{<br>&nbsp;struct xfrm_policy *pol, *ret;<br>&nbsp;struct hlist_head *chain;<br>&nbsp;struct hlist_node *entry;</div>
<div>&nbsp;write_lock_bh(&amp;xfrm_policy_lock);<br>// 定位HASH表<br>&nbsp;chain = policy_hash_bysel(sel, sel-&gt;family, dir);<br>&nbsp;ret = NULL;<br>// 遍历链表<br>&nbsp;hlist_for_each_entry(pol, entry, chain, bydst) {<br>// 根据类型, 选择子和上下文进行匹配<br>&nbsp;&nbsp;if (pol-&gt;type == type &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; !selector_cmp(sel, &amp;pol-&gt;selector) &amp;&amp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xfrm_sec_ctx_match(ctx, pol-&gt;security)) {<br>&nbsp;&nbsp;&nbsp;xfrm_pol_hold(pol);<br>&nbsp;&nbsp;&nbsp;if (delete) {<br>// 要的删除话将策略节点从目的地址HASH链表和索引HASH链表中断开<br>&nbsp;&nbsp;&nbsp;&nbsp;hlist_del(&amp;pol-&gt;bydst);<br>&nbsp;&nbsp;&nbsp;&nbsp;hlist_del(&amp;pol-&gt;byidx);<br>&nbsp;&nbsp;&nbsp;&nbsp;xfrm_policy_count--;<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;ret = pol;<br>&nbsp;&nbsp;&nbsp;break;<br>&nbsp;&nbsp;}<br>&nbsp;}<br>&nbsp;write_unlock_bh(&amp;xfrm_policy_lock);</div>
<div>&nbsp;if (ret &amp;&amp; delete) {<br>&nbsp;&nbsp;atomic_inc(&amp;flow_cache_genid);<br>// 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除<br>&nbsp;&nbsp;xfrm_policy_kill(ret);<br>&nbsp;}<br>&nbsp;return ret;<br>}<br>EXPORT_SYMBOL(xfrm_policy_bysel_ctx);</div>
<div><br>5.12 获取SPD</div>
<div><br>static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)<br>{<br>&nbsp;unsigned int dir;<br>&nbsp;int err;<br>&nbsp;struct sadb_x_policy *pol;<br>&nbsp;struct xfrm_policy *xp;<br>&nbsp;struct km_event c;</div>
<div>// 消息中的策略头<br>&nbsp;if ((pol = ext_hdrs) == NULL)<br>&nbsp;&nbsp;return -EINVAL;</div>
<div>// 根据策略id判断数据方向<br>&nbsp;dir = xfrm_policy_id2dir(pol-&gt;sadb_x_policy_id);<br>&nbsp;if (dir &gt;= XFRM_POLICY_MAX)<br>&nbsp;&nbsp;return -EINVAL;</div>
<div>// 根据方向/ID等参数来查找策略, 如果最后一个参数为真的同时删除策略<br>&nbsp;xp = xfrm_policy_byid(XFRM_POLICY_TYPE_MAIN, dir, pol-&gt;sadb_x_policy_id,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hdr-&gt;sadb_msg_type == SADB_X_SPDDELETE2);<br>&nbsp;if (xp == NULL)<br>&nbsp;&nbsp;return -ENOENT;</div>
<div>&nbsp;err = 0;</div>
<div>&nbsp;c.seq = hdr-&gt;sadb_msg_seq;<br>&nbsp;c.pid = hdr-&gt;sadb_msg_pid;<br>&nbsp;if (hdr-&gt;sadb_msg_type == SADB_X_SPDDELETE2) {<br>// 如果要删除策略, 进行通知回调<br>&nbsp;&nbsp;c.data.byid = 1;<br>&nbsp;&nbsp;c.event = XFRM_MSG_DELPOLICY;<br>&nbsp;&nbsp;km_policy_notify(xp, dir, &amp;c);<br>&nbsp;} else {<br>// 将结果填充一个skb返回给用户空间<br>&nbsp;&nbsp;err = key_pol_get_resp(sk, xp, hdr, dir);<br>&nbsp;}</div>
<div>&nbsp;xfrm_pol_put(xp);<br>&nbsp;return err;<br>}</div>
<div>&nbsp;</div>
<div>5.13 输出整个SPD</div>
<div>static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)<br>{<br>&nbsp;struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };<br>// 遍历策略链表输出策略, dump_sa是输出单一SP的函数<br>&nbsp;return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &amp;data);<br>}</div>
<div>// 输出单一SP<br>static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)<br>{<br>&nbsp;struct pfkey_dump_data *data = ptr;<br>&nbsp;struct sk_buff *out_skb;<br>&nbsp;struct sadb_msg *out_hdr;</div>
<div>// 将安全策略填充到skb前的准备操作<br>&nbsp;out_skb = pfkey_xfrm_policy2msg_prep(xp);<br>&nbsp;if (IS_ERR(out_skb))<br>&nbsp;&nbsp;return PTR_ERR(out_skb);</div>
<div>// 将安全策略填充到skb<br>&nbsp;pfkey_xfrm_policy2msg(out_skb, xp, dir);</div>
<div>// 填充基本SA消息头<br>&nbsp;out_hdr = (struct sadb_msg *) out_skb-&gt;data;<br>&nbsp;out_hdr-&gt;sadb_msg_version = data-&gt;hdr-&gt;sadb_msg_version;<br>&nbsp;out_hdr-&gt;sadb_msg_type = SADB_X_SPDDUMP;<br>&nbsp;out_hdr-&gt;sadb_msg_satype = SADB_SATYPE_UNSPEC;<br>&nbsp;out_hdr-&gt;sadb_msg_errno = 0;<br>// SA消息的序号<br>&nbsp;out_hdr-&gt;sadb_msg_seq = count;<br>&nbsp;out_hdr-&gt;sadb_msg_pid = data-&gt;hdr-&gt;sadb_msg_pid;<br>// 发送到指定的sock<br>&nbsp;pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data-&gt;sk);<br>&nbsp;return 0;<br>}</div>
<div><br>/* net/xfrm/xfrm_policy.c */<br>// 遍历安全策略<br>int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *data)<br>{<br>&nbsp;struct xfrm_policy *pol;<br>&nbsp;struct hlist_node *entry;<br>&nbsp;int dir, count, error;</div>
<div>&nbsp;read_lock_bh(&amp;xfrm_policy_lock);<br>&nbsp;count = 0;<br>// 先统计符合类型的策略的数量, 方向是双向的<br>&nbsp;for (dir = 0; dir &lt; 2*XFRM_POLICY_MAX; dir++) {<br>&nbsp;&nbsp;struct hlist_head *table = xfrm_policy_bydst.table;<br>&nbsp;&nbsp;int i;<br>// inexact HASH表<br>&nbsp;&nbsp;hlist_for_each_entry(pol, entry,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;xfrm_policy_inexact, bydst) {<br>&nbsp;&nbsp;&nbsp;if (pol-&gt;type == type)<br>&nbsp;&nbsp;&nbsp;&nbsp;count++;<br>&nbsp;&nbsp;}<br>// bydst HASH表<br>&nbsp;&nbsp;for (i = xfrm_policy_bydst.hmask; i &gt;= 0; i--) {<br>&nbsp;&nbsp;&nbsp;hlist_for_each_entry(pol, entry, table + i, bydst) {<br>&nbsp;&nbsp;&nbsp;&nbsp;if (pol-&gt;type == type)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count++;<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br>&nbsp;}</div>
<div>&nbsp;if (count == 0) {<br>&nbsp;&nbsp;error = -ENOENT;<br>&nbsp;&nbsp;goto out;<br>&nbsp;}<br>// 重新遍历HASH表, 当前的count值作为SA的序号, 因此用户空间收到的序号是递减的<br>&nbsp;for (dir = 0; dir &lt; 2*XFRM_POLICY_MAX; dir++) {<br>&nbsp;&nbsp;struct hlist_head *table = xfrm_policy_bydst.table;<br>&nbsp;&nbsp;int i;</div>
<div>&nbsp;&nbsp;hlist_for_each_entry(pol, entry,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;xfrm_policy_inexact, bydst) {<br>&nbsp;&nbsp;&nbsp;if (pol-&gt;type != type)<br>&nbsp;&nbsp;&nbsp;&nbsp;continue;<br>&nbsp;&nbsp;&nbsp;error = func(pol, dir % XFRM_POLICY_MAX, --count, data);<br>&nbsp;&nbsp;&nbsp;if (error)<br>&nbsp;&nbsp;&nbsp;&nbsp;goto out;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;for (i = xfrm_policy_bydst.hmask; i &gt;= 0; i--) {<br>&nbsp;&nbsp;&nbsp;hlist_for_each_entry(pol, entry, table + i, bydst) {<br>&nbsp;&nbsp;&nbsp;&nbsp;if (pol-&gt;type != type)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;<br>&nbsp;&nbsp;&nbsp;&nbsp;error = func(pol, dir % XFRM_POLICY_MAX, --count, data);<br>&nbsp;&nbsp;&nbsp;&nbsp;if (error)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto out;<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br>&nbsp;}<br>&nbsp;error = 0;<br>out:<br>&nbsp;read_unlock_bh(&amp;xfrm_policy_lock);<br>&nbsp;return error;<br>}<br>EXPORT_SYMBOL(xfrm_policy_walk);</div>
<div><br>5.14 删除全部SPD<br>&nbsp;&nbsp;= pfkey_spdflush,</div>
<div>// 删除全部SP<br>static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)<br>{<br>&nbsp;struct km_event c;<br>// 删除全部MAIN类型的SP<br>&nbsp;xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN);<br>&nbsp;c.data.type = XFRM_POLICY_TYPE_MAIN;<br>&nbsp;c.event = XFRM_MSG_FLUSHPOLICY;<br>&nbsp;c.pid = hdr-&gt;sadb_msg_pid;<br>&nbsp;c.seq = hdr-&gt;sadb_msg_seq;<br>// 通知回调处理<br>&nbsp;km_policy_notify(NULL, 0, &amp;c);</div>
<div>&nbsp;return 0;<br>}</div>
<div>// 删除SP回调<br>static int key_notify_policy_flush(struct km_event *c)<br>{<br>&nbsp;struct sk_buff *skb_out;<br>&nbsp;struct sadb_msg *hdr;</div>
<div>// 分配skb<br>&nbsp;skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);<br>&nbsp;if (!skb_out)<br>&nbsp;&nbsp;return -ENOBUFS;<br>&nbsp;hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));<br>// SA消息类型为删除所有SP<br>&nbsp;hdr-&gt;sadb_msg_type = SADB_X_SPDFLUSH;<br>&nbsp;hdr-&gt;sadb_msg_seq = c-&gt;seq;<br>&nbsp;hdr-&gt;sadb_msg_pid = c-&gt;pid;<br>&nbsp;hdr-&gt;sadb_msg_version = PF_KEY_V2;<br>&nbsp;hdr-&gt;sadb_msg_errno = (uint8_t) 0;<br>&nbsp;hdr-&gt;sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));<br>// 广播给所有打开PF_KEY类型套接口的用户进程<br>&nbsp;pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL);<br>&nbsp;return 0;</div>
<div>}</div>
<div>/* net/xfrm/xfrm_policy.c */<br>// 删除全部安全策略<br>void xfrm_policy_flush(u8 type)<br>{<br>&nbsp;int dir;</div>
<div>&nbsp;write_lock_bh(&amp;xfrm_policy_lock);<br>&nbsp;for (dir = 0; dir &lt; XFRM_POLICY_MAX; dir++) {<br>&nbsp;&nbsp;struct xfrm_policy *pol;<br>&nbsp;&nbsp;struct hlist_node *entry;<br>&nbsp;&nbsp;int i, killed;</div>
<div>&nbsp;&nbsp;killed = 0;<br>&nbsp;again1:<br>// 遍历inexact HASH链表<br>&nbsp;&nbsp;hlist_for_each_entry(pol, entry,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;xfrm_policy_inexact, bydst) {<br>// 判断类型<br>&nbsp;&nbsp;&nbsp;if (pol-&gt;type != type)<br>&nbsp;&nbsp;&nbsp;&nbsp;continue;<br>// 将策略从bydst链表中断开<br>&nbsp;&nbsp;&nbsp;hlist_del(&amp;pol-&gt;bydst);<br>// 将策略从byidt链表中断开<br>&nbsp;&nbsp;&nbsp;hlist_del(&amp;pol-&gt;byidx);<br>&nbsp;&nbsp;&nbsp;write_unlock_bh(&amp;xfrm_policy_lock);<br>// 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除<br>&nbsp;&nbsp;&nbsp;xfrm_policy_kill(pol);<br>&nbsp;&nbsp;&nbsp;killed++;</div>
<div>&nbsp;&nbsp;&nbsp;write_lock_bh(&amp;xfrm_policy_lock);<br>&nbsp;&nbsp;&nbsp;goto again1;<br>&nbsp;&nbsp;}<br>// 遍历bydst HASH链表<br>&nbsp;&nbsp;for (i = xfrm_policy_bydst.hmask; i &gt;= 0; i--) {<br>&nbsp;again2:<br>&nbsp;&nbsp;&nbsp;hlist_for_each_entry(pol, entry,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xfrm_policy_bydst.table + i,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bydst) {<br>&nbsp;&nbsp;&nbsp;&nbsp;if (pol-&gt;type != type)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;<br>// 将节点从链表中断开<br>&nbsp;&nbsp;&nbsp;&nbsp;hlist_del(&amp;pol-&gt;bydst);<br>&nbsp;&nbsp;&nbsp;&nbsp;hlist_del(&amp;pol-&gt;byidx);<br>&nbsp;&nbsp;&nbsp;&nbsp;write_unlock_bh(&amp;xfrm_policy_lock);<br>// 释放节点<br>&nbsp;&nbsp;&nbsp;&nbsp;xfrm_policy_kill(pol);<br>&nbsp;&nbsp;&nbsp;&nbsp;killed++;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;write_lock_bh(&amp;xfrm_policy_lock);<br>&nbsp;&nbsp;&nbsp;&nbsp;goto again2;<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}</div>
<div>&nbsp;&nbsp;xfrm_policy_count -= killed;<br>&nbsp;}<br>&nbsp;atomic_inc(&amp;flow_cache_genid);<br>&nbsp;write_unlock_bh(&amp;xfrm_policy_lock);<br>}<br>EXPORT_SYMBOL(xfrm_policy_flush);</div>
<div><br>...... 待续 ......</div>
页: [1]
查看完整版本: Linux内核中PF_KEY协议族的实现(3)