1、262以上内核中netlink使用方法2.6.24以上内核中netlink使用方法2010-02-04 14:565119人阅读评论(1)收藏举报structsocket数据结构null网络协议header2.6.24以上内核中netlink使用方法测试环境:2.6.28Netlink在2.6内核的不同版本中发生了很大变化,具体请参考(注意其中的版本号不一定确切):0. 综述以下程序基本流程如下:运行netlink内核模块;运行用户态程序,向内核发送连接消息,通知内核自身进程id;内核接收用户消息,记录其进程id;内核向用户进程id发送netlink消息;用户接收内核发送的netlink消息。
2、1. 内核部分1.1 相关的数据结构变量:cppview plaincopy1. 44/-Thesearefornetlink-/2. 45#defineNETLINK_REALNET263. 46structsock*g_nl_sk=NULL;4. 48structsockaddr_nlsrc_addr,dest_addr;5. 50structioveciov;6. 52intpid;7. 53structmsghdrmsg;8. 55/-/cppview plaincopy1. 45#defineNETLINK_REALNET26定义协议族。该变量在netlink_kernel_crea
3、te函数中使用。在2.6.28内核中netlink定义了20个协议,每个协议使用唯一整数标识。用户程序可以定义任意20个协议以外的协议,用唯一整数标识。cppview plaincopy1. 46structsock*g_nl_sk=NULL;sock数据结构,唯一标识netlink使用的sock,与普通socket编程中sock类似。cppview plaincopy1. 48structsockaddr_nlsrc_addr,dest_addr;标识netlink sock的源地址和目的地址。cppview plaincopy1. 50structioveciov;接收发送netlink数
4、据使用的数据结构。cppview plaincopy1. 53structmsghdrmsg;netlink消息头。1.2 调用过程1.2.1 创建netlink socketcppview plaincopy1. g_nl_sk=netlink_kernel_create(&init_net,NETLINK_REALNET,0,nl_data_ready,NULL,THIS_MODULE);1.2.2 实现回调函数nl_data_ready以下回调函数在netlink接收到完整的NETLINK_REALNET协议的数据包时由系统调用。该函数接收并判断netlink消息,如果第一个字符为H,则
5、保存该消息发出者的进程号,用以向该进程发送数据包;相同,如果为E,则清除与该进程的联系。cppview plaincopy1. 185voidnl_data_ready(structsk_buff*_skb)2. 1863. 187structsk_buff*skb;4. 188structnlmsghdr*nlh;5. 189charstr100;6. 1907. 191skb=skb_get(_skb);8. 1929. 193if(skb-len=NLMSG_SPACE(0)10. 19411. 195nlh=nlmsg_hdr(skb);12. 19613. 197memcpy(str
6、,NLMSG_DATA(nlh),sizeof(str);14. 198/DbgPrint(Messagereceived:%s/n,str);15. 19916. 200/HstandsforHellomessage.17. 201if(str0=H)18. 20219. 203pid=nlh-nlmsg_pid;20. 204u_connected=1;21. 205/sendnlmsg(Helloreply.);22. 20623. 207/EstandsforExitmessage24. 208elseif(str0=E)25. 20926. 210u_connected=0;27.
7、211pid=0;28. 21229. 213kfree_skb(skb);30. 21431. 215cppview plaincopy1. 191skb=skb_get(_skb);获取实际数据包。该函数的参数为netlink数据包的首地址,而sk_buff为网络协议栈使用的数据结构,两者存在细微差别。cppview plaincopy1. 195nlh=nlmsg_hdr(skb); 获取netlink数据包中netlink header的起始地址。cppview plaincopy1. 197memcpy(str,NLMSG_DATA(nlh),sizeof(str);将netlink
8、数据包的数据区拷贝到str中。NLMSG_DATA(nlh)返回数据区地址。相关宏定义参考:cppview plaincopy1. 213kfree_skb(skb);释放接收到的消息。1.2.3 向用户进程发送netlink消息 以下函数的参数为netfilter捕捉到的sk_buff结构的数据包,目的是将该包通过netlink发送到用户态进程。cppview plaincopy1. 247voidsend_to_user(structsk_buff*skb)2. 2483. 249structiphdr*iph;4. 250structethhdr*ehdr;5. 2516. 252str
9、uctnlmsghdr*nlh;7. 2538. 254structsk_buff*nl_skb;9. 25510. 256/DbgPrint(Sendpackagestouser/n);11. 25712. 258if(skb=NULL)13. 25914. 260return;15. 26116. 262if(!g_nl_sk)17. 26318. 264return;19. 26520. 266if(pid=0)21. 26722. 268return;23. 26924. 27025. 271nl_skb=alloc_skb(NLMSG_SPACE(1514),GFP_ATOMIC);
10、26. 272/nl_skb=alloc_skb(NLMSG_SPACE(0),GFP_ATOMIC);27. 273if(nl_skb=NULL)28. 27429. 275/allocatefailed.30. 276return;31. 27732. 27833. 279ehdr=eth_hdr(skb);34. 280iph=ip_hdr(skb);35. 28136. 282nlh=nlmsg_put(nl_skb,0,0,0,NLMSG_SPACE(1514)-sizeof(structnlmsghdr),0);37. 283NETLINK_CB(nl_skb).pid=0;38.
11、 28439. 285/DbgPrint(Datalength:%d,len=%d/n,htons(iph-tot_len)+ETH_HLEN,NLMSG_SPACE(1514);40. 28641. 287/Copydatatonlh42. 288memcpy(NLMSG_DATA(nlh),(char*)ehdr,htons(iph-tot_len)+ETH_HLEN);43. 28944. 290netlink_unicast(g_nl_sk,nl_skb,pid,MSG_DONTWAIT);45. 291cppview plaincopy1. 247voidsend_to_user(s
12、tructsk_buff*skb)参数skb为netfilter捕捉到的数据包,不是netlink数据包。这里作为netlink的数据传输。cppview plaincopy1. 271nl_skb=alloc_skb(NLMSG_SPACE(1514),GFP_ATOMIC);为发送数据包申请空间。空间数据区大小为1514,即最大ethernet数据包长度。NLMSG_SPACE(1514)返回数据区大小为1514的netlink数据包的大小。详细参考:cppview plaincopy1. 282nlh=nlmsg_put(nl_skb,0,0,0,NLMSG_SPACE(1514)-si
13、zeof(structnlmsghdr),0);填充netlink数据包头。cppview plaincopy1. 283NETLINK_CB(nl_skb).pid=0;确定发送数据包的进程号,0表示内核进程。该处宏定义同样参考:cppview plaincopy1. 290netlink_unicast(g_nl_sk,nl_skb,pid,MSG_DONTWAIT);通过非阻塞方式发送数据包。注意:在发送完数据包之后,nl_skb指向的数据空间将被清空,下一次发送数据包必须重新调用alloc_skb分配空间,否则将会造成内核崩溃,必须重新启动。1.2.4 释放netlink socket
14、使用完成netlink之后,必须要调用sock_release,否则cppview plaincopy1. 45#defineNETLINK_REALNET26指定的协议编号将不再可用。代码如下:cppview plaincopy1. 239voiddestory_netlink(void)2. 2403. 241if(g_nl_sk!=NULL)4. 2425. 243sock_release(g_nl_sk-sk_socket);6. 2447. 2452. 用户态程序2.1 相关数据结构cppview plaincopy1. 28/-ForNetlink-/2. 29structsock
15、addr_nlnl_src_addr,nl_dest_addr;3. 30structnlmsghdr*nlh=NULL;4. 31structioveciov;5. 32intnl_fd;6. 33structmsghdrnl_msg;7. 34/-/与内核态数据结构类似,不再赘述。2.2 运行过程2.2.1 初始化netlinkcppview plaincopy1. 114voidinit_nl()2. 1153. 116nl_fd=socket(PF_NETLINK,SOCK_RAW,NETLINK_REALNET);4. 117memset(&nl_msg,0,sizeof(nl_ms
16、g);5. 118memset(&nl_src_addr,0,sizeof(nl_src_addr);6. 119nl_src_addr.nl_family=AF_NETLINK;7. 120nl_src_addr.nl_pid=getpid();8. 121nl_src_addr.nl_groups=0;9. 12210. 123bind(nl_fd,(structsockaddr*)&nl_src_addr,sizeof(nl_src_addr);11. 124memset(&nl_dest_addr,0,sizeof(nl_dest_addr);12. 125nl_dest_addr.n
17、l_family=AF_NETLINK;13. 126nl_dest_addr.nl_pid=0;/*ForLinuxKernel*/14. 127nl_dest_addr.nl_groups=0;/*unicast*/15. 12816. 129sendnlmsg(H);17. 13018. 131memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD);19. 132cppview plaincopy1. 116nl_fd=socket(PF_NETLINK,SOCK_RAW,NETLINK_REALNET);创建用户netlink socket,与普通socket创建方
18、法相同,协议族为PF_NETLINK,协议类型为用户自定义的NETLINK_REALNET,与内核态定义相同。cppview plaincopy1. 117memset(&nl_msg,0,sizeof(nl_msg);清空netlink数据包。cppview plaincopy1. 118-127行与普通socket的初始化类似,如果不熟悉可以参考有关socket编程。需要注意的是nl_src_addr的数据结构与普通socket有些不同。cppview plaincopy1. 129sendnlmsg(H);向内核进程发送Hello消息,通知内核其进程id。2.2.2 向内核发送消息以下函
19、数创建并发送netlink消息到内核进程。cppview plaincopy1. 36voidsendnlmsg(constchar*message)2. 373. 38printf(Sending:%s/n,message);4. 39nlh=(structnlmsghdr*)malloc(NLMSG_SPACE(MAX_PAYLOAD);5. 40nlh-nlmsg_len=NLMSG_SPACE(MAX_PAYLOAD);6. 41nlh-nlmsg_pid=getpid();7. 42nlh-nlmsg_flags=0;8. 439. 44strcpy(char*)NLMSG_DATA
20、(nlh),message);10. 4511. 46iov.iov_base=(void*)nlh;12. 47iov.iov_len=nlh-nlmsg_len;13. 48nl_msg.msg_name=(void*)&nl_dest_addr;14. 49nl_msg.msg_namelen=sizeof(nl_dest_addr);15. 50nl_msg.msg_iov=&iov;16. 51nl_msg.msg_iovlen=1;17. 5218. 53printf(Starttosendmessage.);19. 54sendmsg(nl_fd,&nl_msg,0);20. 5
21、5printf(Sendingfinishes./n);21. 56cppview plaincopy1. 39nlh=(structnlmsghdr*)malloc(NLMSG_SPACE(MAX_PAYLOAD);为netlink header分配存储空间,MAX_PAYLOAD由用户定义,为发送(用户)数据的最大长度。cppview plaincopy1. 40-51行指定netlink相关的参数,准备发送消息。cppview plaincopy1. 54sendmsg(nl_fd,&nl_msg,0); 发送netlink数据包到内核进程,与普通socket中的sendmsg消息用法相同,最后一个参数0表示非阻塞模式。详细参考socket编程。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1