歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

通過netlink實現內核模塊和應用層通信

skb常用操作函數,比較容易弄混

skb_put : skb->tail += len, skb->len += len
skb_pull: skb->data += len, skb->len -= len
skb_push: skb->data -= len, skb->len += len


內核版本Linux2.6.38,編譯環境gcc 4.4.4,CentOS6.0

內核模塊代碼:

  1. /* 
  2.  * author: [email protected] 
  3.  * date  : 2011-10-29 
  4.  */  
  5. #include <linux/module.h>   
  6. #include <linux/netlink.h>   
  7. #include <linux/sched.h>   
  8. #include <net/sock.h>   
  9. #include <linux/proc_fs.h>   
  10. #include <linux/netfilter.h>   
  11. #include <linux/netfilter_ipv4.h>   
  12. #include <linux/ip.h>   
  13. #include <linux/tcp.h>   
  14. #include <linux/icmp.h>   
  15. #include <linux/udp.h>   
  16.   
  17. #define NETLINK_TEST 30   
  18.   
  19. /* 調試信息 */  
  20. #define LOGMSG(fmt, arg...) \   
  21. do{ \  
  22.     printk("[func:%s,line:%d]: "fmt, __FUNCTION__, __LINE__, ##arg); \  
  23. }while(0)  
  24. /* 錯誤信息 */  
  25. #define LOGERR(fmt, arg...) \   
  26. do{ \  
  27.     printk("[func:%s,line:%d]: "fmt, __FUNCTION__, __LINE__, ##arg); \  
  28. }while(0)  
  29. /* 斷言 */  
  30. #define ASSERT(expr) \   
  31. if (unlikely(!(expr))) { \  
  32.     printk("Assertion failed! %s,%s,%s,line=%d\n", \  
  33.     #expr, __FILE__, __func__, __LINE__); \   
  34. }  
  35. /* 消息最大值 */  
  36. #define MAX_MSG_LEN 1024   
  37. enum{  
  38.     NLMSG_TYPE_NONE = 0,  
  39.     NLMSG_TYPE_SETPID,  /* 設置PID */  
  40.     NLMSG_TYPE_KERNEL,  /* 消息來自內核 */  
  41.     NLMSG_TYPE_APP,     /* 消息來自應用層 */  
  42. };  
  43. struct nlmsg{  
  44.     int type;               /* 消息類型 */  
  45.     int len;                /* 消息長度,包括頭部 */  
  46.     char msg[MAX_MSG_LEN];  /* 消息正文 */  
  47. };  
  48. /* netlink socket */  
  49. static struct sock *g_nl_sk = NULL;  
  50. static int g_nlpid = -1;    /* 應用層接收程序PID */  
  51.   
  52. /* 
  53.  * 發送整個從ip頭開始的skb數據到應用層 
  54.  *  
  55.  * param[in]: sk, skb發送目的socket 
  56.  * param[in]: skb, 待發送的skb 
  57.  * return -1, 失敗; 0, 成功 
  58.  * */  
  59. int nl_sendskb(struct sock *sk, struct sk_buff *skb)  
  60. {  
  61.     struct iphdr *iph = NULL;  
  62.     struct nlmsghdr *nlh = NULL;  
  63.     struct sk_buff *nl_skb = NULL;  
  64.   
  65.     int skb_len = 0;  
  66.   
  67.     ASSERT(skb != NULL);  
  68.     ASSERT(sk != NULL);  
  69.     if(g_nlpid < 0)  
  70.         return 0;  
  71.   
  72.     iph = ip_hdr(skb);  
  73.     skb_len = iph->tot_len;  
  74.     /* NLMSG_SPACE: sizeof(struct nlmsghdr) + len按4字節對齊 */  
  75.     nl_skb = alloc_skb(NLMSG_SPACE(skb_len), GFP_ATOMIC);  
  76.     if(!nl_skb)  
  77.     {  
  78.         LOGERR("nl_skb == NULL, failed!\n");  
  79.         return -1;  
  80.     }  
  81.     /* 
  82.      * static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, 
  83.      *               int type, int payload, int flags); 
  84.      * 設置skb->tail指針指向skb->data + sizeof(struct nlmsghdr) + payload 
  85.      * skb->len = sizeof(struct nlmsghdr) + payload  
  86.      */  
  87.     nlh = nlmsg_put(nl_skb, 0, 0, 0, NLMSG_SPACE(skb_len) - sizeof(struct nlmsghdr), 0);   
  88.     NETLINK_CB(nl_skb).pid = 0; /* 0代表數據來自內核 */  
  89.     memcpy(NLMSG_DATA(nlh), (char *)iph, htons(iph->tot_len));  
  90.     /* 將數據發送給進程號22345的進程 */  
  91.     return netlink_unicast(sk, nl_skb, g_nlpid , MSG_DONTWAIT);  
  92. }  
  93. /* 
  94.  * 發送字符串到應用層 
  95.  * 
  96.  * param[in]: sk, 數據發往的socket 
  97.  * param[in]: pmsg, 待發送字符串 
  98.  * param[in]: msglen, 待發送字符串長度 
  99.  *  
  100.  * return: -1, 失敗; 0, 成功 
  101.  * */  
  102. int nl_sendmsg(struct sock *sk, struct nlmsg *pmsg)  
  103. {  
  104.     struct nlmsghdr *nlh = NULL;  
  105.     struct sk_buff *nl_skb = NULL;  
  106.     int msglen = pmsg->len;  
  107.   
  108.     ASSERT(pmsg != NULL);  
  109.     ASSERT(sk != NULL);  
  110.   
  111.     if(g_nlpid < 0)  
  112.         return 0;  
  113.     nl_skb = alloc_skb(NLMSG_SPACE(msglen), GFP_ATOMIC);  
  114.     if(!nl_skb)  
  115.     {  
  116.         LOGERR("nl_skb == NULL, msglen = %d, failed!\n", msglen);  
  117.         return -1;  
  118.     }  
  119.   
  120.     nlh = nlmsg_put(nl_skb, 0, 0, 0,   
  121.                     NLMSG_SPACE(msglen) - NLMSG_HDRLEN, 0);   
  122.     NETLINK_CB(nl_skb).pid = 0;  
  123.     memcpy(NLMSG_DATA(nlh), pmsg, msglen);  
  124.   
  125.     return netlink_unicast(sk, nl_skb, g_nlpid , MSG_DONTWAIT);  
  126. }  
  127. /*  
  128.  * 從應用層接收數據, netlink_kernel_create注冊的回調 
  129.  * param[in]: skb, 包含netlink數據的skb 
  130.  * 
  131.  * skb常用操作函數 
  132.  * skb_put : skb->tail += len, skb->len += len 
  133.  * skb_pull: skb->data += len, skb->len -= len 
  134.  * skb_push: skb->data -= len, skb->len += len 
  135.  */  
  136. static void nl_recvmsg(struct sk_buff *skb)  
  137. {  
  138.     struct nlmsg *pmsg = NULL;  
  139.     struct nlmsghdr *nlh = NULL;  
  140.     uint32_t rlen = 0;  
  141.       
  142.     while(skb->len >= NLMSG_SPACE(0))  
  143.     {  
  144.         nlh = nlmsg_hdr(skb);  
  145.         if(nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)  
  146.             return;  
  147.         rlen = NLMSG_ALIGN(nlh->nlmsg_len);  
  148.         if(rlen > skb->len)  
  149.             rlen = skb->len;  
  150.         pmsg = (struct nlmsg*)NLMSG_DATA(nlh);  
  151.         switch(pmsg->type)  
  152.         {  
  153.         case NLMSG_TYPE_SETPID:  
  154.             g_nlpid = nlh->nlmsg_pid;  
  155.             LOGMSG("pid: %d\n", g_nlpid);  
  156.             LOGMSG("msg: %s\n", pmsg->msg);  
  157.             break;  
  158.         case NLMSG_TYPE_KERNEL:  
  159.             break;  
  160.         case NLMSG_TYPE_APP:  
  161.             break;  
  162.         }  
  163.         /* 獲取下一條netlink消息 */  
  164.         skb_pull(skb, rlen);  
  165.     }  
  166. }  
  167.   
  168. /*  
  169.  * netfilter PRE_ROUTING鉤子 
  170.  * */  
  171. unsigned int pre_routing_hook(unsigned int hooknum,   
  172.                            struct sk_buff *skb,   
  173.                            const struct net_device *in,  
  174.                            const struct net_device *out,  
  175.                            int (*okfn)(struct sk_buff *))  
  176. {  
  177.     char *psend = "msg for kernel";  
  178.     struct nlmsg msg;  
  179.     int ret = 0;  
  180.   
  181.     msg.type = NLMSG_TYPE_KERNEL;  
  182.     msg.len = strlen(psend) + offsetof(struct nlmsg, msg) + 1;  
  183.     memcpy(msg.msg, psend, msg.len);  
  184.     //ret = nl_sendskb(g_nl_sk, skb);   
  185.     ret = nl_sendmsg(g_nl_sk, &msg);  
  186.     //LOGMSG("ok\n");   
  187.     return NF_ACCEPT;  
  188. }  
  189.   
  190. static struct nf_hook_ops local_in_ops __read_mostly = {  
  191.     .hook = pre_routing_hook,  
  192.     .owner = THIS_MODULE,  
  193.     .pf = PF_INET,  
  194.     .hooknum = NF_INET_PRE_ROUTING,  
  195.     .priority = NF_IP_PRI_FIRST  
  196. };  
  197.   
  198. static int __init nl_init(void)  
  199. {  
  200.     int ret = 0;  
  201.     /*  
  202.      * struct sock *netlink_kernel_create(struct net *net, int unit, unsigned int groups, 
  203.      *                                    void (*input)(struct sk_buff *skb), 
  204.      *                                    struct mutex *cb_mutex, struct module *module) 
  205.      */  
  206.     g_nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 0, nl_recvmsg, NULL, THIS_MODULE);  
  207.     if (!g_nl_sk) {  
  208.         LOGERR("Fail to create netlink socket.\n");  
  209.         return -1;  
  210.     }  
  211.   
  212.     ret = nf_register_hook(&local_in_ops);  
  213.     if(ret < 0)  
  214.     {  
  215.         LOGMSG("nf_register_hook failed!\n");  
  216.         goto sock_release;  
  217.     }  
  218.     LOGMSG("ok!\n");  
  219.     return 0;  
  220.   
  221. sock_release:  
  222.     if(g_nl_sk)  
  223.         sock_release(g_nl_sk->sk_socket);  
  224.     return -1;  
  225. }  
  226.   
  227. static void __exit nl_exit(void)  
  228. {  
  229.     synchronize_sched();  
  230.     if(g_nl_sk)  
  231.         sock_release(g_nl_sk->sk_socket);  
  232.     nf_unregister_hook(&local_in_ops);  
  233.     LOGMSG("ok!\n");  
  234. }  
  235.   
  236. module_init(nl_init);  
  237. module_exit(nl_exit);  
  238. MODULE_LICENSE("GPL");  
  239. MODULE_AUTHOR("[email protected]");  
Copyright © Linux教程網 All Rights Reserved