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

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

<div align="center"><font size="5">Linux内核中PF_KEY协议族的实现(4)</font></div>
<div><br>本文档的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>
<div>&nbsp;</div>
<div>6. 通知回调处理</div>
<div><br>6.1 初始化</div>
<div>在pf_key的初始化函数中定义了通知回调结构pfkeyv2_mgr:</div>
<div>&nbsp;err = xfrm_register_km(&amp;pfkeyv2_mgr);</div>
<div>该结构定义如下:</div>
<div>static struct xfrm_mgr pfkeyv2_mgr =<br>{<br>&nbsp;.id&nbsp;&nbsp;= "pfkeyv2",<br>&nbsp;.notify&nbsp;&nbsp;= pfkey_send_notify,<br>&nbsp;.acquire&nbsp;= pfkey_send_acquire,<br>&nbsp;.compile_policy&nbsp;= pfkey_compile_policy,<br>&nbsp;.new_mapping&nbsp;= pfkey_send_new_mapping,<br>&nbsp;.notify_policy&nbsp;= pfkey_send_policy_notify,<br>};</div>
<div><br>6.2 登记</div>
<div>/*&nbsp; net/xfrm/xfrm_state.c */<br>// 就是把xfrm_mgr结构挂接到xfrm_km_list链表<br>int xfrm_register_km(struct xfrm_mgr *km)<br>{<br>&nbsp;write_lock_bh(&amp;xfrm_km_lock);<br>// 将结构挂接到xfrm_km_list链表<br>&nbsp;list_add_tail(&amp;km-&gt;list, &amp;xfrm_km_list);<br>&nbsp;write_unlock_bh(&amp;xfrm_km_lock);<br>&nbsp;return 0;<br>}<br>EXPORT_SYMBOL(xfrm_register_km);</div>
<div><br>6.3 发送通知</div>
<div>在pf_key中调用以下两个函数来调用通知回调函数, 分别针对安全策略操作和SA操作:</div>
<div>// 安全策略通知回调<br>void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)<br>{<br>&nbsp;struct xfrm_mgr *km;</div>
<div>&nbsp;read_lock(&amp;xfrm_km_lock);<br>// 状态的通知回调函数为notify_policy<br>&nbsp;list_for_each_entry(km, &amp;xfrm_km_list, list)<br>&nbsp;&nbsp;if (km-&gt;notify_policy)<br>&nbsp;&nbsp;&nbsp;km-&gt;notify_policy(xp, dir, c);<br>&nbsp;read_unlock(&amp;xfrm_km_lock);<br>}</div>
<div>// SA状态通知回调<br>void km_state_notify(struct xfrm_state *x, struct km_event *c)<br>{<br>&nbsp;struct xfrm_mgr *km;<br>&nbsp;read_lock(&amp;xfrm_km_lock);<br>// 状态的通知回调函数为notify<br>&nbsp;list_for_each_entry(km, &amp;xfrm_km_list, list)<br>&nbsp;&nbsp;if (km-&gt;notify)<br>&nbsp;&nbsp;&nbsp;km-&gt;notify(x, c);<br>&nbsp;read_unlock(&amp;xfrm_km_lock);<br>}</div>
<div><br>调用这些通知函数前要填写事件的相关参数, 如:</div>
<div>static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)<br>{<br>&nbsp;unsigned proto;<br>&nbsp;struct km_event c;</div>
<div>&nbsp;proto = pfkey_satype2proto(hdr-&gt;sadb_msg_satype);<br>&nbsp;if (proto == 0)<br>&nbsp;&nbsp;return -EINVAL;</div>
<div>&nbsp;xfrm_state_flush(proto);<br>// 填写事件参数<br>// 协议<br>&nbsp;c.data.proto = proto;<br>// 序列号<br>&nbsp;c.seq = hdr-&gt;sadb_msg_seq;<br>// sock对方(用户空间进程)的pid<br>&nbsp;c.pid = hdr-&gt;sadb_msg_pid;<br>// 事件<br>&nbsp;c.event = XFRM_MSG_FLUSHSA;<br>&nbsp;km_state_notify(NULL, &amp;c);</div>
<div>&nbsp;return 0;<br>}</div>
<div><br>6.4 pf_key通知回调函数</div>
<div>6.4.1&nbsp; 发送SA消息时的通知回调</div>
<div>// 状态通知回调, 在SA操作后调用<br>static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)<br>{<br>// 根据事件类型来发送相关通知<br>&nbsp;switch (c-&gt;event) {<br>&nbsp;case XFRM_MSG_EXPIRE:<br>// SA到期的通知, SA消息类型为SADB_EXPIRE,只是进行了登记的PF_KEY socket可以收到<br>&nbsp;&nbsp;return key_notify_sa_expire(x, c);<br>&nbsp;case XFRM_MSG_DELSA:<br>&nbsp;case XFRM_MSG_NEWSA:<br>&nbsp;case XFRM_MSG_UPDSA:<br>// SA的通知, SA消息类型为分别为SADB_DELETE, SADB_ADD和SADB_UPDATE, <br>// 所有PF_KEY socket都可以收到<br>&nbsp;&nbsp;return key_notify_sa(x, c);<br>&nbsp;case XFRM_MSG_FLUSHSA:<br>// 删除全部SA的通知, SA消息类型为分别为SADB_FLUSH, 所有PF_KEY socket都可以收到<br>&nbsp;&nbsp;return key_notify_sa_flush(c);<br>&nbsp;case XFRM_MSG_NEWAE: /* not yet supported */<br>&nbsp;&nbsp;break;<br>&nbsp;default:<br>&nbsp;&nbsp;printk("pfkey: Unknown SA event %d\n", c-&gt;event);<br>&nbsp;&nbsp;break;<br>&nbsp;}</div>
<div>&nbsp;return 0;<br>}</div>
<div><br>6.4.2 发送ACQUIRE</div>
<div><br>关于ACQUIRE的作用, 摘一段UNP vol.1, r3中的话:</div>
<div>chapter19.5:</div>
<div>"When the kernel needs to communicate with a peer and policy says
that an SA is required but one is not available, the kernel sends an
SADB_ACQUIRE message to key management sockets that have registered the
SA type required, containing a proposal extension describing the
kernel's proposed algorithms and key lengths. The proposal may be a
combination of what is supported by the system and preconfigured policy
that limits what is permitted for this communication. The proposal is a
list of algorithms, key lengths, and lifetimes, in order of preference.
When a key management daemon receives an SADB_ACQUIRE message, it
performs the acts required to choose a key that fits one of the kernel's
proposed combinations, and installs this key in the kernel. "</div>
<div>&nbsp;</div>
<div>static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir)<br>{<br>&nbsp;struct sk_buff *skb;<br>&nbsp;struct sadb_msg *hdr;<br>&nbsp;struct sadb_address *addr;<br>&nbsp;struct sadb_x_policy *pol;<br>&nbsp;struct sockaddr_in *sin;<br>#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)<br>&nbsp;struct sockaddr_in6 *sin6;<br>#endif<br>&nbsp;int sockaddr_size;<br>&nbsp;int size;<br>&nbsp;struct sadb_x_sec_ctx *sec_ctx;<br>&nbsp;struct xfrm_sec_ctx *xfrm_ctx;<br>&nbsp;int ctx_size = 0;<br>&nbsp;<br>&nbsp;sockaddr_size = pfkey_sockaddr_size(x-&gt;props.family);<br>&nbsp;if (!sockaddr_size)<br>&nbsp;&nbsp;return -EINVAL;<br>// 消息长度包括SA基本头, 两个SA地址, 两个网络地址和策略<br>&nbsp;size = sizeof(struct sadb_msg) +<br>&nbsp;&nbsp;(sizeof(struct sadb_address) * 2) +<br>&nbsp;&nbsp;(sockaddr_size * 2) +<br>&nbsp;&nbsp;sizeof(struct sadb_x_policy);</div>
<div>// 还添加AH或ESP中所有算法描述的长度<br>&nbsp;if (x-&gt;id.proto == IPPROTO_AH)<br>&nbsp;&nbsp;size += count_ah_combs(t);<br>&nbsp;else if (x-&gt;id.proto == IPPROTO_ESP)<br>&nbsp;&nbsp;size += count_esp_combs(t);</div>
<div>&nbsp;if ((xfrm_ctx = x-&gt;security)) {<br>&nbsp;&nbsp;ctx_size = PFKEY_ALIGN8(xfrm_ctx-&gt;ctx_len);<br>&nbsp;&nbsp;size +=&nbsp; sizeof(struct sadb_x_sec_ctx) + ctx_size;<br>&nbsp;}</div>
<div>// 分配skb<br>&nbsp;skb =&nbsp; alloc_skb(size + 16, GFP_ATOMIC);<br>&nbsp;if (skb == NULL)<br>&nbsp;&nbsp;return -ENOMEM;<br>// 先填基本SA消息头信息&nbsp;<br>&nbsp;hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));<br>&nbsp;hdr-&gt;sadb_msg_version = PF_KEY_V2;<br>&nbsp;hdr-&gt;sadb_msg_type = SADB_ACQUIRE;<br>&nbsp;hdr-&gt;sadb_msg_satype = pfkey_proto2satype(x-&gt;id.proto);<br>&nbsp;hdr-&gt;sadb_msg_len = size / sizeof(uint64_t);<br>&nbsp;hdr-&gt;sadb_msg_errno = 0;<br>&nbsp;hdr-&gt;sadb_msg_reserved = 0;<br>&nbsp;hdr-&gt;sadb_msg_seq = x-&gt;km.seq = get_acqseq();<br>&nbsp;hdr-&gt;sadb_msg_pid = 0;</div>
<div>&nbsp;/* src address */<br>// 填充SA源地址信息<br>&nbsp;addr = (struct sadb_address*) skb_put(skb, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sizeof(struct sadb_address)+sockaddr_size);<br>&nbsp;addr-&gt;sadb_address_len = <br>&nbsp;&nbsp;(sizeof(struct sadb_address)+sockaddr_size)/<br>&nbsp;&nbsp;&nbsp;sizeof(uint64_t);<br>&nbsp;addr-&gt;sadb_address_exttype = SADB_EXT_ADDRESS_SRC;<br>&nbsp;addr-&gt;sadb_address_proto = 0;<br>&nbsp;addr-&gt;sadb_address_reserved = 0;<br>&nbsp;if (x-&gt;props.family == AF_INET) {<br>// IPV4地址<br>&nbsp;&nbsp;addr-&gt;sadb_address_prefixlen = 32;</div>
<div>&nbsp;&nbsp;sin = (struct sockaddr_in *) (addr + 1);<br>&nbsp;&nbsp;sin-&gt;sin_family = AF_INET;<br>&nbsp;&nbsp;sin-&gt;sin_addr.s_addr = x-&gt;props.saddr.a4;<br>&nbsp;&nbsp;sin-&gt;sin_port = 0;<br>&nbsp;&nbsp;memset(sin-&gt;sin_zero, 0, sizeof(sin-&gt;sin_zero));<br>&nbsp;}<br>#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)<br>&nbsp;else if (x-&gt;props.family == AF_INET6) {<br>// IPV6地址<br>&nbsp;&nbsp;addr-&gt;sadb_address_prefixlen = 128;</div>
<div>&nbsp;&nbsp;sin6 = (struct sockaddr_in6 *) (addr + 1);<br>&nbsp;&nbsp;sin6-&gt;sin6_family = AF_INET6;<br>&nbsp;&nbsp;sin6-&gt;sin6_port = 0;<br>&nbsp;&nbsp;sin6-&gt;sin6_flowinfo = 0;<br>&nbsp;&nbsp;memcpy(&amp;sin6-&gt;sin6_addr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x-&gt;props.saddr.a6, sizeof(struct in6_addr));<br>&nbsp;&nbsp;sin6-&gt;sin6_scope_id = 0;<br>&nbsp;}<br>#endif<br>&nbsp;else<br>&nbsp;&nbsp;BUG();<br>&nbsp;<br>&nbsp;/* dst address */<br>// 填充SA目的地址信息<br>&nbsp;addr = (struct sadb_address*) skb_put(skb, <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sizeof(struct sadb_address)+sockaddr_size);<br>&nbsp;addr-&gt;sadb_address_len =<br>&nbsp;&nbsp;(sizeof(struct sadb_address)+sockaddr_size)/<br>&nbsp;&nbsp;&nbsp;sizeof(uint64_t);<br>&nbsp;addr-&gt;sadb_address_exttype = SADB_EXT_ADDRESS_DST;<br>&nbsp;addr-&gt;sadb_address_proto = 0;<br>&nbsp;addr-&gt;sadb_address_reserved = 0;<br>&nbsp;if (x-&gt;props.family == AF_INET) {<br>&nbsp;&nbsp;addr-&gt;sadb_address_prefixlen = 32; </div>
<div>&nbsp;&nbsp;sin = (struct sockaddr_in *) (addr + 1);<br>&nbsp;&nbsp;sin-&gt;sin_family = AF_INET;<br>&nbsp;&nbsp;sin-&gt;sin_addr.s_addr = x-&gt;id.daddr.a4;<br>&nbsp;&nbsp;sin-&gt;sin_port = 0;<br>&nbsp;&nbsp;memset(sin-&gt;sin_zero, 0, sizeof(sin-&gt;sin_zero));<br>&nbsp;}<br>#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)<br>&nbsp;else if (x-&gt;props.family == AF_INET6) {<br>&nbsp;&nbsp;addr-&gt;sadb_address_prefixlen = 128; </div>
<div>&nbsp;&nbsp;sin6 = (struct sockaddr_in6 *) (addr + 1);<br>&nbsp;&nbsp;sin6-&gt;sin6_family = AF_INET6;<br>&nbsp;&nbsp;sin6-&gt;sin6_port = 0;<br>&nbsp;&nbsp;sin6-&gt;sin6_flowinfo = 0;<br>&nbsp;&nbsp;memcpy(&amp;sin6-&gt;sin6_addr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x-&gt;id.daddr.a6, sizeof(struct in6_addr));<br>&nbsp;&nbsp;sin6-&gt;sin6_scope_id = 0;<br>&nbsp;}<br>#endif<br>&nbsp;else<br>&nbsp;&nbsp;BUG();</div>
<div>// 填充策略信息<br>&nbsp;pol = (struct sadb_x_policy *)&nbsp; skb_put(skb, sizeof(struct sadb_x_policy));<br>&nbsp;pol-&gt;sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t);<br>&nbsp;pol-&gt;sadb_x_policy_exttype = SADB_X_EXT_POLICY;<br>&nbsp;pol-&gt;sadb_x_policy_type = IPSEC_POLICY_IPSEC;<br>&nbsp;pol-&gt;sadb_x_policy_dir = dir+1;<br>&nbsp;pol-&gt;sadb_x_policy_id = xp-&gt;index;</div>
<div>&nbsp;/* Set sadb_comb's. */<br>// 填充AH或ESP的可用算法信息<br>&nbsp;if (x-&gt;id.proto == IPPROTO_AH)<br>&nbsp;&nbsp;dump_ah_combs(skb, t);<br>&nbsp;else if (x-&gt;id.proto == IPPROTO_ESP)<br>&nbsp;&nbsp;dump_esp_combs(skb, t);</div>
<div>&nbsp;/* security context */<br>&nbsp;if (xfrm_ctx) {<br>// 填充安全上下文信息<br>&nbsp;&nbsp;sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb,<br>&nbsp;&nbsp;&nbsp;&nbsp;sizeof(struct sadb_x_sec_ctx) + ctx_size);<br>&nbsp;&nbsp;sec_ctx-&gt;sadb_x_sec_len =<br>&nbsp;&nbsp;&nbsp; (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t);<br>&nbsp;&nbsp;sec_ctx-&gt;sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX;<br>&nbsp;&nbsp;sec_ctx-&gt;sadb_x_ctx_doi = xfrm_ctx-&gt;ctx_doi;<br>&nbsp;&nbsp;sec_ctx-&gt;sadb_x_ctx_alg = xfrm_ctx-&gt;ctx_alg;<br>&nbsp;&nbsp;sec_ctx-&gt;sadb_x_ctx_len = xfrm_ctx-&gt;ctx_len;<br>&nbsp;&nbsp;memcpy(sec_ctx + 1, xfrm_ctx-&gt;ctx_str,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xfrm_ctx-&gt;ctx_len);<br>&nbsp;}<br>// 广播到进行了登记的PF_KEY套接口<br>&nbsp;return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);<br>}</div>
<div><br>6.4.3 编译策略</div>
<div>// 将sadb_x_policy(标准接口格式)编译为xfrm_policy(内核具体实现格式)<br>static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u8 *data, int len, int *dir)<br>{<br>&nbsp;struct xfrm_policy *xp;<br>&nbsp;struct sadb_x_policy *pol = (struct sadb_x_policy*)data;<br>&nbsp;struct sadb_x_sec_ctx *sec_ctx;</div>
<div>// 选项opt必须是IP_IPSEC_POLICY, 否则出错<br>&nbsp;switch (sk-&gt;sk_family) {<br>&nbsp;case AF_INET:<br>&nbsp;&nbsp;if (opt != IP_IPSEC_POLICY) {<br>&nbsp;&nbsp;&nbsp;*dir = -EOPNOTSUPP;<br>&nbsp;&nbsp;&nbsp;return NULL;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;break;<br>#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)<br>&nbsp;case AF_INET6:<br>&nbsp;&nbsp;if (opt != IPV6_IPSEC_POLICY) {<br>&nbsp;&nbsp;&nbsp;*dir = -EOPNOTSUPP;<br>&nbsp;&nbsp;&nbsp;return NULL;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;break;<br>#endif<br>&nbsp;default:<br>&nbsp;&nbsp;*dir = -EINVAL;<br>&nbsp;&nbsp;return NULL;<br>&nbsp;}</div>
<div>&nbsp;*dir = -EINVAL;</div>
<div>&nbsp;if (len &lt; sizeof(struct sadb_x_policy) ||<br>&nbsp;&nbsp;&nbsp;&nbsp; pol-&gt;sadb_x_policy_len*8 &gt; len ||<br>&nbsp;&nbsp;&nbsp;&nbsp; pol-&gt;sadb_x_policy_type &gt; IPSEC_POLICY_BYPASS ||<br>&nbsp;&nbsp;&nbsp;&nbsp; (!pol-&gt;sadb_x_policy_dir || pol-&gt;sadb_x_policy_dir &gt; IPSEC_DIR_OUTBOUND))<br>&nbsp;&nbsp;return NULL;<br>// 分配策略空间<br>&nbsp;xp = xfrm_policy_alloc(GFP_ATOMIC);<br>&nbsp;if (xp == NULL) {<br>&nbsp;&nbsp;*dir = -ENOBUFS;<br>&nbsp;&nbsp;return NULL;<br>&nbsp;}</div>
<div>// 填写策略动作<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);</div>
<div>// 填写策略有效期参数<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>&nbsp;xp-&gt;family = sk-&gt;sk_family;</div>
<div>&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; (*dir = parse_ipsecrequests(xp, pol)) &lt; 0)<br>&nbsp;&nbsp;goto out;</div>
<div>&nbsp;/* security context too */<br>&nbsp;if (len &gt;= (pol-&gt;sadb_x_policy_len*8 +<br>&nbsp;&nbsp;&nbsp;&nbsp; sizeof(struct sadb_x_sec_ctx))) {<br>// 转换安全上下文<br>&nbsp;&nbsp;char *p = (char *)pol;<br>&nbsp;&nbsp;struct xfrm_user_sec_ctx *uctx;</div>
<div>&nbsp;&nbsp;p += pol-&gt;sadb_x_policy_len*8;<br>&nbsp;&nbsp;sec_ctx = (struct sadb_x_sec_ctx *)p;<br>&nbsp;&nbsp;if (len &lt; pol-&gt;sadb_x_policy_len*8 +<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sec_ctx-&gt;sadb_x_sec_len) {<br>&nbsp;&nbsp;&nbsp;*dir = -EINVAL;<br>&nbsp;&nbsp;&nbsp;goto out;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;if ((*dir = verify_sec_ctx_len(p)))<br>&nbsp;&nbsp;&nbsp;goto out;<br>&nbsp;&nbsp;uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);<br>&nbsp;&nbsp;*dir = security_xfrm_policy_alloc(xp, uctx);<br>&nbsp;&nbsp;kfree(uctx);</div>
<div>&nbsp;&nbsp;if (*dir)<br>&nbsp;&nbsp;&nbsp;goto out;<br>&nbsp;}</div>
<div>&nbsp;*dir = pol-&gt;sadb_x_policy_dir-1;<br>&nbsp;return xp;</div>
<div>out:<br>&nbsp;security_xfrm_policy_free(xp);<br>&nbsp;kfree(xp);<br>&nbsp;return NULL;<br>}</div>
<div>6.4.4 NAT穿越映射</div>
<div>// 发送新映射(NAT穿越)SA消息, 包含SA头, SA, 转换前地址,端口, 转换后的地址端口<br>static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport)<br>{<br>&nbsp;struct sk_buff *skb;<br>&nbsp;struct sadb_msg *hdr;<br>&nbsp;struct sadb_sa *sa;<br>&nbsp;struct sadb_address *addr;<br>&nbsp;struct sadb_x_nat_t_port *n_port;<br>&nbsp;struct sockaddr_in *sin;<br>#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)<br>&nbsp;struct sockaddr_in6 *sin6;<br>#endif<br>&nbsp;int sockaddr_size;<br>&nbsp;int size;<br>&nbsp;__u8 satype = (x-&gt;id.proto == IPPROTO_ESP ? SADB_SATYPE_ESP : 0);<br>&nbsp;struct xfrm_encap_tmpl *natt = NULL;</div>
<div>// 协议的地址长度<br>&nbsp;sockaddr_size = pfkey_sockaddr_size(x-&gt;props.family);<br>&nbsp;if (!sockaddr_size)<br>&nbsp;&nbsp;return -EINVAL;</div>
<div>&nbsp;if (!satype)<br>&nbsp;&nbsp;return -EINVAL;</div>
<div>&nbsp;if (!x-&gt;encap)<br>&nbsp;&nbsp;return -EINVAL;</div>
<div>// NAT转换结构<br>&nbsp;natt = x-&gt;encap;</div>
<div>&nbsp;/* Build an SADB_X_NAT_T_NEW_MAPPING message:<br>&nbsp; *<br>&nbsp; * HDR | SA | ADDRESS_SRC (old addr) | NAT_T_SPORT (old port) |<br>&nbsp; * ADDRESS_DST (new addr) | NAT_T_DPORT (new port)<br>&nbsp; */<br>// 消息总长: SA消息头+SA+两个SA地址+两个协议地址+2个NAT端口&nbsp;<br>&nbsp;size = sizeof(struct sadb_msg) +<br>&nbsp;&nbsp;sizeof(struct sadb_sa) +<br>&nbsp;&nbsp;(sizeof(struct sadb_address) * 2) +<br>&nbsp;&nbsp;(sockaddr_size * 2) +<br>&nbsp;&nbsp;(sizeof(struct sadb_x_nat_t_port) * 2);<br>// 分配skb&nbsp;<br>&nbsp;skb =&nbsp; alloc_skb(size + 16, GFP_ATOMIC);<br>&nbsp;if (skb == NULL)<br>&nbsp;&nbsp;return -ENOMEM;</div>
<div>// 填写SA头&nbsp;<br>&nbsp;hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));<br>&nbsp;hdr-&gt;sadb_msg_version = PF_KEY_V2;<br>&nbsp;hdr-&gt;sadb_msg_type = SADB_X_NAT_T_NEW_MAPPING;<br>&nbsp;hdr-&gt;sadb_msg_satype = satype;<br>&nbsp;hdr-&gt;sadb_msg_len = size / sizeof(uint64_t);<br>&nbsp;hdr-&gt;sadb_msg_errno = 0;<br>&nbsp;hdr-&gt;sadb_msg_reserved = 0;<br>&nbsp;hdr-&gt;sadb_msg_seq = x-&gt;km.seq = get_acqseq();<br>&nbsp;hdr-&gt;sadb_msg_pid = 0;</div>
<div>&nbsp;/* SA */<br>// 填写SA结构<br>&nbsp;sa = (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa));<br>&nbsp;sa-&gt;sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t);<br>&nbsp;sa-&gt;sadb_sa_exttype = SADB_EXT_SA;<br>&nbsp;sa-&gt;sadb_sa_spi = x-&gt;id.spi;<br>&nbsp;sa-&gt;sadb_sa_replay = 0;<br>&nbsp;sa-&gt;sadb_sa_state = 0;<br>&nbsp;sa-&gt;sadb_sa_auth = 0;<br>&nbsp;sa-&gt;sadb_sa_encrypt = 0;<br>&nbsp;sa-&gt;sadb_sa_flags = 0;</div>
<div>&nbsp;/* ADDRESS_SRC (old addr) */<br>// 转换前SA地址参数<br>&nbsp;addr = (struct sadb_address*)<br>&nbsp;&nbsp;skb_put(skb, sizeof(struct sadb_address)+sockaddr_size);<br>&nbsp;addr-&gt;sadb_address_len = <br>&nbsp;&nbsp;(sizeof(struct sadb_address)+sockaddr_size)/<br>&nbsp;&nbsp;&nbsp;sizeof(uint64_t);<br>&nbsp;addr-&gt;sadb_address_exttype = SADB_EXT_ADDRESS_SRC;<br>&nbsp;addr-&gt;sadb_address_proto = 0;<br>&nbsp;addr-&gt;sadb_address_reserved = 0;<br>&nbsp;if (x-&gt;props.family == AF_INET) {<br>// 填写转换前IPV4协议地址具体参数<br>&nbsp;&nbsp;addr-&gt;sadb_address_prefixlen = 32;</div>
<div>&nbsp;&nbsp;sin = (struct sockaddr_in *) (addr + 1);<br>&nbsp;&nbsp;sin-&gt;sin_family = AF_INET;<br>&nbsp;&nbsp;sin-&gt;sin_addr.s_addr = x-&gt;props.saddr.a4;<br>&nbsp;&nbsp;sin-&gt;sin_port = 0;<br>&nbsp;&nbsp;memset(sin-&gt;sin_zero, 0, sizeof(sin-&gt;sin_zero));<br>&nbsp;}<br>#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)<br>&nbsp;else if (x-&gt;props.family == AF_INET6) {<br>// 填写转换前IPV6协议地址具体参数<br>&nbsp;&nbsp;addr-&gt;sadb_address_prefixlen = 128;</div>
<div>&nbsp;&nbsp;sin6 = (struct sockaddr_in6 *) (addr + 1);<br>&nbsp;&nbsp;sin6-&gt;sin6_family = AF_INET6;<br>&nbsp;&nbsp;sin6-&gt;sin6_port = 0;<br>&nbsp;&nbsp;sin6-&gt;sin6_flowinfo = 0;<br>&nbsp;&nbsp;memcpy(&amp;sin6-&gt;sin6_addr,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x-&gt;props.saddr.a6, sizeof(struct in6_addr));<br>&nbsp;&nbsp;sin6-&gt;sin6_scope_id = 0;<br>&nbsp;}<br>#endif<br>&nbsp;else<br>&nbsp;&nbsp;BUG();</div>
<div>&nbsp;/* NAT_T_SPORT (old port) */<br>// 填写转换前端口参数<br>&nbsp;n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));<br>&nbsp;n_port-&gt;sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);<br>&nbsp;n_port-&gt;sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;<br>&nbsp;n_port-&gt;sadb_x_nat_t_port_port = natt-&gt;encap_sport;<br>&nbsp;n_port-&gt;sadb_x_nat_t_port_reserved = 0;</div>
<div>&nbsp;/* ADDRESS_DST (new addr) */<br>// 填写转换后地址属性参数<br>&nbsp;addr = (struct sadb_address*)<br>&nbsp;&nbsp;skb_put(skb, sizeof(struct sadb_address)+sockaddr_size);<br>&nbsp;addr-&gt;sadb_address_len = <br>&nbsp;&nbsp;(sizeof(struct sadb_address)+sockaddr_size)/<br>&nbsp;&nbsp;&nbsp;sizeof(uint64_t);<br>&nbsp;addr-&gt;sadb_address_exttype = SADB_EXT_ADDRESS_DST;<br>&nbsp;addr-&gt;sadb_address_proto = 0;<br>&nbsp;addr-&gt;sadb_address_reserved = 0;<br>&nbsp;if (x-&gt;props.family == AF_INET) {<br>// 填写转换后IPV4协议地址具体参数<br>&nbsp;&nbsp;addr-&gt;sadb_address_prefixlen = 32;</div>
<div>&nbsp;&nbsp;sin = (struct sockaddr_in *) (addr + 1);<br>&nbsp;&nbsp;sin-&gt;sin_family = AF_INET;<br>&nbsp;&nbsp;sin-&gt;sin_addr.s_addr = ipaddr-&gt;a4;<br>&nbsp;&nbsp;sin-&gt;sin_port = 0;<br>&nbsp;&nbsp;memset(sin-&gt;sin_zero, 0, sizeof(sin-&gt;sin_zero));<br>&nbsp;}<br>#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)<br>&nbsp;else if (x-&gt;props.family == AF_INET6) {<br>// 填写转换后IPV6协议地址具体参数<br>&nbsp;&nbsp;addr-&gt;sadb_address_prefixlen = 128;</div>
<div>&nbsp;&nbsp;sin6 = (struct sockaddr_in6 *) (addr + 1);<br>&nbsp;&nbsp;sin6-&gt;sin6_family = AF_INET6;<br>&nbsp;&nbsp;sin6-&gt;sin6_port = 0;<br>&nbsp;&nbsp;sin6-&gt;sin6_flowinfo = 0;<br>&nbsp;&nbsp;memcpy(&amp;sin6-&gt;sin6_addr, &amp;ipaddr-&gt;a6, sizeof(struct in6_addr));<br>&nbsp;&nbsp;sin6-&gt;sin6_scope_id = 0;<br>&nbsp;}<br>#endif<br>&nbsp;else<br>&nbsp;&nbsp;BUG();</div>
<div>&nbsp;/* NAT_T_DPORT (new port) */<br>// 填写转换前端口参数<br>&nbsp;n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));<br>&nbsp;n_port-&gt;sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);<br>&nbsp;n_port-&gt;sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;<br>&nbsp;n_port-&gt;sadb_x_nat_t_port_port = sport;<br>&nbsp;n_port-&gt;sadb_x_nat_t_port_reserved = 0;<br>// 发送给进行登记了的PF_KEY套接口<br>&nbsp;return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);<br>}</div>
<div><br>6.4.5 发送策略的通知</div>
<div><br>// 策略通知回调, 在安全策略操作后调用<br>static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)<br>{<br>&nbsp;if (xp &amp;&amp; xp-&gt;type != XFRM_POLICY_TYPE_MAIN)<br>&nbsp;&nbsp;return 0;</div>
<div>&nbsp;switch (c-&gt;event) {<br>&nbsp;case XFRM_MSG_POLEXPIRE:<br>// 策略到期通知, 空函数<br>&nbsp;&nbsp;return key_notify_policy_expire(xp, c);<br>&nbsp;case XFRM_MSG_DELPOLICY:<br>&nbsp;case XFRM_MSG_NEWPOLICY:<br>&nbsp;case XFRM_MSG_UPDPOLICY:<br>// 策略的通知, SA消息类型为分别为SADB_X_SPDDELETE, SADB_X_SPDADD, SADB_X_SPDUPDATE等, <br>// 所有PF_KEY socket都可以收到<br>&nbsp;&nbsp;return key_notify_policy(xp, dir, c);<br>&nbsp;case XFRM_MSG_FLUSHPOLICY:<br>&nbsp;&nbsp;if (c-&gt;data.type != XFRM_POLICY_TYPE_MAIN)<br>&nbsp;&nbsp;&nbsp;break;<br>// 策略的通知, SA消息类型为分别为SADB_X_FLUSH, 所有PF_KEY socket都可以收到<br>&nbsp;&nbsp;return key_notify_policy_flush(c);<br>&nbsp;default:<br>&nbsp;&nbsp;printk("pfkey: Unknown policy event %d\n", c-&gt;event);<br>&nbsp;&nbsp;break;<br>&nbsp;}</div>
<div>&nbsp;return 0;<br>}</div>
<div><br>在pf_key.c中只用到了6.4.1和6.4.5的这两个函数.</div>
<div><br>...... 待续 ......</div>
页: [1]
查看完整版本: Linux内核中PF_KEY协议族的实现(4)