基于openswan klips的IPsec实现分析(八)内核SADB维护(2)

本文深入探讨了Linux内核如何处理基于openswan的IPsec协议安全联盟(SA)的增加和删除操作。通过pfkey_recvmsg和pfkey_sendmsg函数,阐述了内核接收和发送PF_KEY消息的过程,详细解析了pfkey_msg_interp函数中对SA、密钥、地址等信息的处理。同时,文章提到了satype2proto函数用于将应用层的协议类型转换为内核支持的协议号,以及内核如何将SA添加到哈希表中和从哈希表中删除的详细步骤。
摘要由CSDN通过智能技术生成

基于openswan klips的IPsec实现分析(七)内核SADB维护2

转载请注明出处:http://blog.csdn.net/rosetta

内核完整的消息处理过程,以隧道模式ESP协议增加SA情况为例

接收消息和发送消息的知识涉及到Linux内核了,所以不关注它是怎么收发,而是关注收到消息后对消息本身的处理过程。但为了保证代码的完整性,就把接收和发送的代码全部帖上来了(但省略部分比较长的调试信息)。

 

其接收发送函数调用关系如下:

pfkey_recvmsg()接收消息

pfkey_sendmsg()发送消息

 -> pfkey_msg_interp()解释消息后执行msg_parsers[]数组里相应函数(增加、删除SA等)。

         ->satype2proto()通过查表获取内核支持的协议号

         ->pfkey_msg_parse()解析并处理消息是否有错,判断相应的协议是否有算法支持等。

          ->ext_processors[]()处理消息中具体的数据结构,如SA,密钥,地址,周期等。

                   ->msg_parsers[]()调用最终的SA处理函数。

 

在msg_parsers[]处理函数数组中的每个函数,如果需要,都会在处理完后通过pfkey_upmsg()函数把消息发到PF_KEY密钥套接字传递给应用层。

从应用层接收到消息

pfkey_recvmsg()函数

/*

 *     Receive PF_KEY data up.

 */

DEBUG_NO_STATIC int

#ifdef NET_26

pfkey_recvmsg(struct kiocb *kiocb

               , struct socket *sock

               , struct msghdr *msg

               , size_t size

               , int flags)

#else

pfkey_recvmsg(struct socket *sock

               , struct msghdr *msg

               , int size, int flags

               , struct scm_cookie *scm)

#endif

{

         structsock *sk;

         intnoblock = flags & MSG_DONTWAIT;

         structsk_buff *skb;

         interror;

 

         if(sock== NULL) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_recvmsg: "

                                "Null socket passed in.\n");

                   return-EINVAL;

         }

 

         sk= sock->sk; 

 

         if(sk== NULL) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_recvmsg: "

                                "Null sock passed in forsock=0p%p.\n", sock);

                   return-EINVAL;

         }

 

         if(msg== NULL) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_recvmsg: "

                                "Null msghdr passed in for sock=0p%p,sk=0p%p.\n",

                                sock, sk);

                   return-EINVAL;

         }

 

         if(flags& ~MSG_PEEK) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "flags (%d) other than MSG_PEEK notsupported.\n",

                                flags);

                   return-EOPNOTSUPP;

         }

                  

         msg->msg_namelen= 0; /* sizeof(*ska); */

                  

         if(sk->sk_err){

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "sk->sk_err=%d.\n", sk->sk_err);

                   returnsock_error(sk);

         }

 

         if((skb= skb_recv_datagram(sk, flags, noblock, &error) )== NULL) {

                return error;

         }

 

         if(size> skb->len) {

                   size= skb->len;

         }

         elseif(size <skb->len) {

                   msg->msg_flags|= MSG_TRUNC;

         }

 

         skb_copy_datagram_iovec(skb,0, msg->msg_iov, size);

#ifdef HAVE_TSTAMP

         sk->sk_stamp.tv_sec  = skb->tstamp.off_sec;

         sk->sk_stamp.tv_usec= skb->tstamp.off_usec;

#else

       sk->sk_stamp=skb->stamp;

#endif

 

         skb_free_datagram(sk,skb);

         returnsize;

}

处理消息后发送给应用层

pfkey_sendmsg()函数

/*

 *     Send PF_KEY data down.

 */

DEBUG_NO_STATIC int

#ifdef NET_26

pfkey_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_tlen)

#else

pfkey_sendmsg(struct socket *sock, structmsghdr *msg, int len, struct scm_cookie *scm)

#endif

{

         structsock *sk;

         interror = 0;

         //pfkey_msg用于存放来至应用层的数据.

struct sadb_msg*pfkey_msg = NULL, *pfkey_reply = NULL;

        

        

         if(sock== NULL) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "Null socket passed in.\n");

                   SENDERR(EINVAL);

         }

        

         sk= sock->sk;

 

         if(sk== NULL) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "Null sock passed in.\n");

                   SENDERR(EINVAL);

         }

        

         if(msg== NULL) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "Null msghdr passed in.\n");

                   SENDERR(EINVAL);

         }

 

         KLIPS_PRINT(debug_pfkey,

                       "klips_debug:pfkey_sendmsg:.\n");

         if(sk->sk_err){

                   error= sock_error(sk);

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "sk->err is non-zero, returns%d.\n",

                                error);

                   SENDERR(-error);

         }

 

         if((current->uid!= 0)) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "must be root to send messages topfkey sockets.\n");

                   SENDERR(EACCES);

         }

 

         if(msg->msg_control)

         {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "can't set flags or setmsg_control.\n");

                   SENDERR(EINVAL);

         }

                  

         if(sk->sk_shutdown& SEND_SHUTDOWN) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "shutdown.\n");

                   send_sig(SIGPIPE,current, 0);

                   SENDERR(EPIPE);

         }

        

         if(len< sizeof(struct sadb_msg)) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "bogus msg len of %d, toosmall.\n", (int)len);

                   SENDERR(EMSGSIZE);

         }

 

         KLIPS_PRINT(debug_pfkey,

                       "klips_debug:pfkey_sendmsg: "

                       "allocating %d bytes for downwardmessage.\n",

                       (int)len);

         //为pfkey_msg分配空间

         if((pfkey_msg= (struct sadb_msg*)kmalloc(len, GFP_KERNEL)) == NULL) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "memory allocation error.\n");

                   SENDERR(ENOBUFS);

         }

        

//拷贝待处理消息至pfkey_msg指向的缓冲区中

memcpy_fromiovec((void*)pfkey_msg, msg->msg_iov, len);

        

         //一些字段的正确性判断,比如版本,长度,是否是发向自己的消息等。

         if(pfkey_msg->sadb_msg_version!= PF_KEY_V2) {

                   KLIPS_PRINT(1|| debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "not PF_KEY_V2 msg, found %d, shouldbe %d.\n",

                                pfkey_msg->sadb_msg_version,

                                PF_KEY_V2);

                   kfree((void*)pfkey_msg);

                   return-EINVAL;

         }

 

         if(len!= pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) {

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "bogus msg len of %d, not %d bytealigned.\n",

                                (int)len, (int)IPSEC_PFKEYv2_ALIGN);

                   SENDERR(EMSGSIZE);

         }

 

         if(pfkey_msg->sadb_msg_reserved){

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "reserved field must be zero, set to%d.\n",

                                pfkey_msg->sadb_msg_reserved);

                   SENDERR(EINVAL);

         }

        

         if((pfkey_msg->sadb_msg_type> SADB_MAX) || (!pfkey_msg->sadb_msg_type)){

                   KLIPS_PRINT(debug_pfkey,

                                "klips_debug:pfkey_sendmsg: "

                                "msg type too large orsmall:%d.\n",

                                pfkey_msg->sadb_msg_

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值