打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
通过netlink实现内核模块和应用层通信

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: hoi0714@163.com 
  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("hoi0714@163.com");  


内核模块Makefile

  1. module := netlink  
  2.   
  3. obj-m := $(module).o  
  4.   
  5. #$(module)-objs :=  $(module).o  
  6.   
  7. KDIR=/root/kernel_new  
  8. KHDR=/root/kernel_new/include  
  9. EXTRA_CFLAGS += $(FLAG) -I$(KHDR) -O2 -D__KERNEL__ -DMODULE $(INCLUDE) -DEXPORT_SYMTAB  
  10. CPPFLAGS += $(FLAG) -I$(KHDR)  
  11.   
  12. OUTDIR =  
  13. TARGET = netlink.ko  
  14. TARGETDIR = /lib/modules/  
  15.   
  16. all:  
  17.     make -C $(KDIR) M=$(PWD) modules  
  18.   
  19. clean:  
  20.     make -C $(KDIR) M=$(PWD) clean   
  21.   
  22.   
  23. install: all  
  24.     install --verbose --mode=0755 $(OUTDIR)$(TARGET) $(INSTALLROOT)$(TARGETDIR)  


应用层代码:

  1. /* 
  2.  * author: hoi0714@163.com 
  3.  * date  : 2011-10-29 
  4.  */  
  5. #include <sys/stat.h>     
  6. #include <unistd.h>     
  7. #include <stdio.h>     
  8. #include <stdlib.h>     
  9. #include <sys/socket.h>     
  10. #include <sys/types.h>     
  11. #include <string.h>     
  12. #include <asm/types.h>     
  13. #include <linux/netlink.h>     
  14. #include <linux/socket.h>     
  15. #include <stddef.h>  
  16. #include <errno.h>     
  17.   
  18. #define FREE_INIT(ptr) do{ \  
  19.     free(ptr); \  
  20.     ptr = NULL; \  
  21. }while(0)  
  22.   
  23. /* 消息最大值 */  
  24. #define MAX_MSG_LEN 1024  
  25. enum{  
  26.     NLMSG_TYPE_NONE = 0,  
  27.     NLMSG_TYPE_SETPID,  /* 设置PID */  
  28.     NLMSG_TYPE_KERNEL,  /* 消息来自内核 */  
  29.     NLMSG_TYPE_APP,     /* 消息来自应用层 */  
  30. };  
  31. struct nlmsg{  
  32.     int type;               /* 消息类型 */  
  33.     int len;                /* 消息长度,包括头部 */  
  34.     char msg[MAX_MSG_LEN];  /* 消息正文 */  
  35. };  
  36.   
  37. #define NETLINK_TEST 30     
  38.   
  39. /* 
  40.  * 打开netlink 
  41.  * return: 0, 成功; -1, 失败 
  42.  * */  
  43. int netlink_open(void)  
  44. {  
  45.     struct sockaddr_nl saddr;  
  46.     int sockfd = -1, ret = 0;  
  47.       
  48.     sockfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_TEST);    
  49.     if(sockfd < -1){    
  50.         perror("create socket!\n");  
  51.         return -1;    
  52.     }    
  53.       
  54.     memset(&saddr, 0, sizeof(saddr));    
  55.     saddr.nl_family = PF_NETLINK;     
  56.     saddr.nl_pid = getpid();    // self pid      
  57.     saddr.nl_groups = 0;        // multi cast   
  58.       
  59.     ret = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));    
  60.     if(ret < 0){    
  61.         perror("bind failed!\n");    
  62.         close(sockfd);    
  63.         return -1;    
  64.     }   
  65.   
  66.     return sockfd;  
  67. }  
  68. /* 
  69.  * 发送信息 
  70.  * param[in]: sockfd 
  71.  * param[in]: pmsg, 待发送信息 
  72.  *  
  73.  * return: 0, 发送成功; -1: 发送失败 
  74.  * */  
  75. int netlink_send(int sockfd, struct nlmsg *pmsg)  
  76. {    
  77.     struct msghdr msg;  
  78.     struct iovec iov;  
  79.     struct nlmsghdr *nlh = NULL;  
  80.       
  81.     int msglen = pmsg->len;  
  82.     int totlen = NLMSG_SPACE(pmsg->len);  
  83.     int ret = 0;  
  84.       
  85.     nlh = malloc(totlen);  
  86.     if(!nlh)  
  87.     {  
  88.         fprintf(stderr, "malloc failed!\n");  
  89.         return -1;  
  90.     }  
  91.     nlh->nlmsg_len = totlen;  
  92.     nlh->nlmsg_flags = 0;  
  93.     nlh->nlmsg_pid = getpid();  
  94.       
  95.     iov.iov_base = (void *)nlh;    
  96.     iov.iov_len = nlh->nlmsg_len;    
  97.     
  98.     memset(&msg, 0, sizeof(msg));    
  99.     msg.msg_iov = &iov;    
  100.     msg.msg_iovlen = 1;   
  101.       
  102.       
  103.     memcpy(NLMSG_DATA(nlh), pmsg, msglen);  
  104.     ret = sendmsg(sockfd, &msg, 0);  
  105.     if(ret < 0)  
  106.     {  
  107.         fprintf(stderr, "sendmsg failed!\n");  
  108.         FREE_INIT(nlh);  
  109.         return -1;  
  110.     }  
  111.     return 0;  
  112.       
  113. }  
  114. /* 
  115.  * 接收信息 
  116.  * param[in]: sockfd 
  117.  * param[out]: pmsg 
  118.  *  
  119.  * return 0, 成功; -1, 失败 
  120.  * */  
  121. int netlink_recv(int sockfd, struct nlmsg *pmsg)  
  122. {  
  123.     struct msghdr msg;  
  124.     struct iovec iov;  
  125.     struct nlmsghdr *nlh = NULL;  
  126.       
  127.     int msglen = sizeof(*pmsg);  
  128.     int totlen = NLMSG_SPACE(sizeof(*pmsg));  
  129.     int ret = 0;  
  130.       
  131.     nlh = malloc(totlen);  
  132.     if(!nlh)  
  133.     {  
  134.         fprintf(stderr, "malloc failed!\n");  
  135.         return -1;  
  136.     }  
  137.       
  138.     iov.iov_base = (void *)nlh;    
  139.     iov.iov_len = totlen;    
  140.     
  141.     memset(&msg, 0, sizeof(msg));    
  142.     msg.msg_iov = &iov;    
  143.     msg.msg_iovlen = 1;   
  144.       
  145.     memcpy(NLMSG_DATA(nlh), pmsg, msglen);  
  146.     ret = recvmsg(sockfd, &msg, 0);  
  147.     if(ret < 0)  
  148.     {  
  149.         fprintf(stderr, "recvmsg failed!\n");  
  150.         FREE_INIT(nlh);  
  151.         return -1;  
  152.     }  
  153.     memcpy(pmsg, NLMSG_DATA(nlh), msglen);  
  154.     return 0;  
  155. }  
  156. /*  
  157.  * 关闭netlink 
  158.  * param[in]: sockfd, netlink socket号 
  159.  * */  
  160. void netlink_close(int sockfd)  
  161. {  
  162.     if(sockfd > 0)  
  163.         close(sockfd);  
  164. }  
  165.   
  166. int main(int argc, char* argv[])    
  167. {    
  168.     int sockfd = -1;  
  169.     int ret = 0;  
  170.   
  171.     struct nlmsg msg;  
  172.   
  173.     char *psend = "msg from app!";  
  174.       
  175.     memset(&msg, 0, sizeof(msg));  
  176.     /* 创建netlink socket */  
  177.     sockfd = netlink_open();  
  178.     if(sockfd < 0)  
  179.     {  
  180.         fprintf(stderr, "netlink_open failed!\n");  
  181.         return -1;  
  182.     }  
  183.     /* 将进程号通知内核 */  
  184.     msg.type = NLMSG_TYPE_SETPID;  
  185.     msg.len = strlen(psend) + offsetof(struct nlmsg, msg) + 1;  
  186.     memcpy(msg.msg, psend, strlen(psend));  
  187.     ret = netlink_send(sockfd, &msg);  
  188.     if(ret < 0)  
  189.     {  
  190.         fprintf(stderr, "netlink_send failed!\n");  
  191.         return -1;  
  192.     }  
  193.     /* 接收消息 */  
  194.     while(1)  
  195.     {  
  196.         ret = netlink_recv(sockfd, &msg);  
  197.         if(ret < 0)  
  198.         {  
  199.             fprintf(stderr, "netlink_recv failed!\n");  
  200.             return -1;  
  201.         }  
  202.         printf("msg: %s\n", msg.msg);  
  203.     }  
  204.     /* 关闭netlink */  
  205.     netlink_close(sockfd);  
  206.     return 0;    
  207. }    
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
linux 内核和用户空间通信之netlink使用方法
基于netlink的内核态与用户态异步并发消息处理模型
Linux 内核态与用户态通信 netlink
linux netlink通信机制
用户空间和内核空间通讯之Netlink
netlink socket 编程之 why & how - 内核源码 - ChinaUn...
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服