`
xitong
  • 浏览: 6193245 次
文章分类
社区版块
存档分类
最新评论

netlink使用方法

 
阅读更多

测试环境:2.6.28

Netlink在2.6内核的不同版本中发生了很大变化,具体请参考(注意其中的版本号不一定确切):

http://blog.csdn.net/sealyao/archive/2009/10/02/4628141.aspx

0. 综述

以下程序基本流程如下:

运行netlink内核模块;

运行用户态程序,向内核发送连接消息,通知内核自身进程id;

内核接收用户消息,记录其进程id;

内核向用户进程id发送netlink消息;

用户接收内核发送的netlink消息。

1. 内核部分

1.1 相关的数据结构变量:

  1. 44//---------Thesearefornetlink---------//
  2. 45#defineNETLINK_REALNET26
  3. 46structsock*g_nl_sk=NULL;
  4. 48structsockaddr_nlsrc_addr,dest_addr;
  5. 50structioveciov;
  6. 52intpid;
  7. 53structmsghdrmsg;
  8. 55//-----------------------------------------//

  1. 45#defineNETLINK_REALNET26

定义协议族。该变量在netlink_kernel_create函数中使用。

在2.6.28内核中netlink定义了20个协议,每个协议使用唯一整数标识。用户程序可以定义任意20个协议以外的协议,用唯一整数标识。

  1. 46structsock*g_nl_sk=NULL;

sock数据结构,唯一标识netlink使用的sock,与普通socket编程中sock类似。

  1. 48structsockaddr_nlsrc_addr,dest_addr;

标识netlink sock的源地址和目的地址。

  1. 50structioveciov;

接收发送netlink数据使用的数据结构。

  1. 53structmsghdrmsg;

netlink消息头。

1.2 调用过程

1.2.1 创建netlink socket

  1. 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,则保存该消息发出者的进程号,用以向该进程发送数据包;相同,如果为E,则清除与该进程的联系。

  1. 185voidnl_data_ready(structsk_buff*__skb)
  2. 186{
  3. 187structsk_buff*skb;
  4. 188structnlmsghdr*nlh;
  5. 189charstr[100];
  6. 190
  7. 191skb=skb_get(__skb);
  8. 192
  9. 193if(skb->len>=NLMSG_SPACE(0))
  10. 194{
  11. 195nlh=nlmsg_hdr(skb);
  12. 196
  13. 197memcpy(str,NLMSG_DATA(nlh),sizeof(str));
  14. 198//DbgPrint("Messagereceived:%s/n",str);
  15. 199
  16. 200//HstandsforHellomessage.
  17. 201if(str[0]=='H')
  18. 202{
  19. 203pid=nlh->nlmsg_pid;
  20. 204u_connected=1;
  21. 205//sendnlmsg("Helloreply.");
  22. 206}
  23. 207//EstandsforExitmessage
  24. 208elseif(str[0]=='E')
  25. 209{
  26. 210u_connected=0;
  27. 211pid=0;
  28. 212}
  29. 213kfree_skb(skb);
  30. 214}
  31. 215}

  1. 191skb=skb_get(__skb);

获取实际数据包。

该函数的参数为netlink数据包的首地址,而sk_buff为网络协议栈使用的数据结构,两者存在细微差别。

  1. 195nlh=nlmsg_hdr(skb);

获取netlink数据包中netlink header的起始地址。

  1. 197memcpy(str,NLMSG_DATA(nlh),sizeof(str));

将netlink数据包的数据区拷贝到str中。NLMSG_DATA(nlh)返回数据区地址。相关宏定义参考:

http://blog.csdn.net/wangjingfei/archive/2010/02/04/5288263.aspx

  1. 213kfree_skb(skb);

释放接收到的消息。

1.2.3 向用户进程发送netlink消息

以下函数的参数为netfilter捕捉到的sk_buff结构的数据包,目的是将该包通过netlink发送到用户态进程。

  1. 247voidsend_to_user(structsk_buff*skb)
  2. 248{
  3. 249structiphdr*iph;
  4. 250structethhdr*ehdr;
  5. 251
  6. 252structnlmsghdr*nlh;
  7. 253
  8. 254structsk_buff*nl_skb;
  9. 255
  10. 256//DbgPrint("Sendpackagestouser/n");
  11. 257
  12. 258if(skb==NULL)
  13. 259{
  14. 260return;
  15. 261}
  16. 262if(!g_nl_sk)
  17. 263{
  18. 264return;
  19. 265}
  20. 266if(pid==0)
  21. 267{
  22. 268return;
  23. 269}
  24. 270
  25. 271nl_skb=alloc_skb(NLMSG_SPACE(1514),GFP_ATOMIC);
  26. 272//nl_skb=alloc_skb(NLMSG_SPACE(0),GFP_ATOMIC);
  27. 273if(nl_skb==NULL)
  28. 274{
  29. 275//allocatefailed.
  30. 276return;
  31. 277}
  32. 278
  33. 279ehdr=eth_hdr(skb);
  34. 280iph=ip_hdr(skb);
  35. 281
  36. 282nlh=nlmsg_put(nl_skb,0,0,0,NLMSG_SPACE(1514)-sizeof(structnlmsghdr),0);
  37. 283NETLINK_CB(nl_skb).pid=0;
  38. 284
  39. 285//DbgPrint("Datalength:%d,len=%d/n",htons(iph->tot_len)+ETH_HLEN,NLMSG_SPACE(1514));
  40. 286
  41. 287//Copydatatonlh
  42. 288memcpy(NLMSG_DATA(nlh),(char*)ehdr,htons(iph->tot_len)+ETH_HLEN);
  43. 289
  44. 290netlink_unicast(g_nl_sk,nl_skb,pid,MSG_DONTWAIT);
  45. 291}

  1. 247voidsend_to_user(structsk_buff*skb)

参数skb为netfilter捕捉到的数据包,不是netlink数据包。这里作为netlink的数据传输。

  1. 271nl_skb=alloc_skb(NLMSG_SPACE(1514),GFP_ATOMIC);

为发送数据包申请空间。空间数据区大小为1514,即最大ethernet数据包长度。NLMSG_SPACE(1514)返回数据区大小为1514的netlink数据包的大小。详细参考:

http://blog.csdn.net/wangjingfei/archive/2010/02/04/5288263.aspx

  1. 282nlh=nlmsg_put(nl_skb,0,0,0,NLMSG_SPACE(1514)-sizeof(structnlmsghdr),0);

填充netlink数据包头。

  1. 283NETLINK_CB(nl_skb).pid=0;

确定发送数据包的进程号,0表示内核进程。该处宏定义同样参考:

http://blog.csdn.net/wangjingfei/archive/2010/02/04/5288263.aspx

  1. 290netlink_unicast(g_nl_sk,nl_skb,pid,MSG_DONTWAIT);

通过非阻塞方式发送数据包。注意:在发送完数据包之后,nl_skb指向的数据空间将被清空,下一次发送数据包必须重新调用alloc_skb分配空间,否则将会造成内核崩溃,必须重新启动。

1.2.4 释放netlink socket

使用完成netlink之后,必须要调用sock_release,否则

  1. 45#defineNETLINK_REALNET26

指定的协议编号将不再可用。代码如下:

  1. 239voiddestory_netlink(void)
  2. 240{
  3. 241if(g_nl_sk!=NULL)
  4. 242{
  5. 243sock_release(g_nl_sk->sk_socket);
  6. 244}
  7. 245}

2. 用户态程序

2.1 相关数据结构

  1. 28//----------------ForNetlink--------------//
  2. 29structsockaddr_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 初始化netlink

  1. 114voidinit_nl()
  2. 115{
  3. 116nl_fd=socket(PF_NETLINK,SOCK_RAW,NETLINK_REALNET);
  4. 117memset(&nl_msg,0,sizeof(nl_msg));
  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. 122
  10. 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.nl_family=AF_NETLINK;
  13. 126nl_dest_addr.nl_pid=0;/*ForLinuxKernel*/
  14. 127nl_dest_addr.nl_groups=0;/*unicast*/
  15. 128
  16. 129sendnlmsg("H");
  17. 130
  18. 131memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));
  19. 132}

  1. 116nl_fd=socket(PF_NETLINK,SOCK_RAW,NETLINK_REALNET);

创建用户netlink socket,与普通socket创建方法相同,协议族为PF_NETLINK,协议类型为用户自定义的NETLINK_REALNET,与内核态定义相同。

  1. 117memset(&nl_msg,0,sizeof(nl_msg));

清空netlink数据包。

  1. 118-127行

与普通socket的初始化类似,如果不熟悉可以参考有关socket编程。需要注意的是nl_src_addr的数据结构与普通socket有些不同。

  1. 129sendnlmsg("H");

向内核进程发送Hello消息,通知内核其进程id。

2.2.2 向内核发送消息

以下函数创建并发送netlink消息到内核进程。

  1. 36voidsendnlmsg(constchar*message)
  2. 37{
  3. 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. 43
  9. 44strcpy((char*)NLMSG_DATA(nlh),message);
  10. 45
  11. 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. 52
  18. 53printf("Starttosendmessage.");
  19. 54sendmsg(nl_fd,&nl_msg,0);
  20. 55printf("Sendingfinishes./n");
  21. 56}

  1. 39nlh=(structnlmsghdr*)malloc(NLMSG_SPACE(MAX_PAYLOAD));

为netlink header分配存储空间,MAX_PAYLOAD由用户定义,为发送(用户)数据的最大长度。

  1. 40-51行

指定netlink相关的参数,准备发送消息。

  1. 54sendmsg(nl_fd,&nl_msg,0);

发送netlink数据包到内核进程,与普通socket中的sendmsg消息用法相同,最后一个参数0表示非阻塞模式。详细参考socket编程。

分享到:
评论

相关推荐

    Linux 用户态与内核态的交互――netlink 篇

    例如iprote2网络管理工具,它与内核的交互就全部使用了netlink,著名的内核包过滤框架Netfilter在与用户空间的通读,也在最新版本中改变为netlink,无疑,它将是Linux用户态与内核态交流的主要方法之一。它的通信...

    linux下使用netlink获取gateway的IP地址

    要在linux下的程序中获取gateway的IP地址,使用netlink是一种直接、可靠的方法,不需要依赖其它命令,直接从linux内核获取信息,netlink编程的中文资料很少,本文试图用尽可能简单的方式讨论使用netlink获取gataway...

    论文研究-基于Linux Netlink快速写入路由方法的设计与实现 .pdf

    基于Linux Netlink快速写入路由方法的设计与实现,刘鹏展,李昕,本文介绍了linux中一种用户程序与内核通信的一种方式:netlink,对比了netlink与其他内核通信方式的优点;给出了一种基于netlink通信方式来

    netlink.rar

    从netlink和普通的内核用户通信的对比,和对netlink创建方法的步骤详解,有框图描述,有内核模块和用户模块的实例,以及makefile。

    NEC SV8100功能编程手册

    NEC 交换机功能编程手册 netlink功能手册 30B+D组网方法

    C语言获取ipv6地址的三种方法

    使用通常获取ipv4的IP地址的方法是无法获取ipv6地址的,本文介绍了使用C语言获取ipv6地址的三种方法:从proc文件从系统获取ipv6地址、使用getifaddrs()函数获取ipv6地址和使用netlink获取ipv6地址,每种方法均给出了...

    使用ioctl扫描wifi信号获取AP的essid、mac地址等属性

    仅使用 ioctl 扫描附近的 wifi 信号,并获取这些 AP 的 ESSID、MAC 地址、占用信道和工作频率,本文将给出完整的源程序,今后还会写一些文章讨论如果编程获取 wifi 信号的其它属性(比如:信号强度、加密方式等)的...

    rtnetlink:软件包rtnetlink提供了对Linux rtnetlink API的低级访问。 麻省理工学院许可

    另一种(可能甚至更灵活)的方法是使用nlmon和wireshark 。 nlmod是一个特殊的内核模块,它允许您捕获内核内部的所有netlink(而不仅仅是rtnetlink)流量。 请注意,这可能在具有大量netlink流

    基于Linux LQL流量控制系统的研究与实现

    该方法摒弃了传统方法中所运用的TC命令解析,netlink传输,内核空间执行的3层结构,而直接在Linux内核的框架下,采用LQL库直接对内核进行操控,并改进了相关U32过滤器以对IP段的流量控制,从而实现对系统的智能流量控制。...

    Tenus:Go中Linux网络

    Golang中Linux网络 tenus是一个软件包,它允许您以编程方式配置和管理Linux网络设备。 它通过与Linux内核通信,以促进...开始吧回购中有一个Vagrantfile ,因此使用是最简单的入门方法: milosgajdos@bimbonet ~ $ git

    nf-hipac-0.9.2

    明显的,这个方法缺乏效率。 nf-HiPAC ,提供一个新颖包分类的架构。当查找每一个包的时候使用一个高级算法来减少内存占用。在一个有特别多的规则和高带宽的网络中nf-HiPAC表现十分完美。 功能: 充分优化以实现适度...

    Android 获取蓝牙Mac地址的正确方法

    以下方法能正确的获取android自带蓝牙的Mac地址: 1.添加net.vidageek:mirror:1.6.1 2.实现过程 本人也尝试过其他方法获取,比如从cat /sys/class/net/wlan0/address 或者/sys/class/net/eth0/address路径获取,该...

    Linux系统内核空间与用户空间通信的实现与分析

    多数的 Linux 内核态程序都需要和用户空间的进程交换数据,但 Linux 内核态无法对传统的 Linux 进 程间同步和通信的方法提供足够的支持。...推荐使用 netlink 套接字实现中断环境与用户态进程通信。 1

    matlab的egde源代码-Realtime-processing-for-csitool:Linux802.11n通道状态信息(CSI)测

    matlab的egde源代码csitool的实时处理 实时数据处理和可视化插件。 用法 要使用此代码,您将需要中的所有文件。 在Matlab中: ...限制Wi-Fi覆盖范围:使用物理层信息的众包方法。 IEEE SECON,2016年。

    wpa_cli_wrapper.zip

    如果遇到提示类似“致命错误:netlink/genl/genl.h:没有那个文件或目录 ”的错误,请安装libnl库重试。 # 如何使用 设置 /etc/wpa_supplicant/wpa_supplicant.conf 的内容为 ctrl_interface=/var/run/wpa_...

    端口连通测试

    测试端口连通,具体方法: 运行netlink [port] telnet [ip] [port] 测试端口的开放

    入门学习Linux常用必会60个命令实例详解doc/txt

    umount 命令是mount命令的逆操作,它的参数和使用方法和mount命令是一样的。Linux挂装CD-ROM后,会锁定CD—ROM,这样就不能用CD- ROM面板上的Eject按钮弹出它。但是,当不再需要光盘时,如果已将/cdrom作为符号链接...

    论文研究-Linux下内核态-用户态高效易用的数据交互方法研究 .pdf

    Linux下内核态-用户态高效易用的数据交互方法研究,徐明昆, 胡勇刚,Linux操作系统是一款单内核操作系统,它将各子系统包含在内核中,并为所有进程提供服务。为了保护子系统的安全,Linux将进程空间划分为��

    go-audit:go-audit是许多发行版附带的auditd守护程序的替代方法

    go-audit是许多发行版附带的auditd守护程序的替代方法。 创建了插件以将审核日志转换为json之后,我开始对替换现有守护程序感兴趣。 目标 安全:以安全且高效的现代语言编写 快速:如果我们能避免的话,永远不会阻塞...

    Linux用户磁盘配额设置方法

    CONFIG_QUOTA_NETLINK_INTERFACE=y # CONFIG_QUOTA_DEBUG is not set CONFIG_QUOTA_TREE=y CONFIG_QUOTACTL=y CONFIG_QUOTACTL_COMPAT=y 如果有上列输出,则表示当前内核已经支持quota。 二:修改/etc/fstab加入...

Global site tag (gtag.js) - Google Analytics