基于openswan klips的IPsec实现分析(七)内核SADB维护2
转载请注明出处:http://blog.youkuaiyun.com/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_