netlink2

【OVS2.5.0源码分析】datapath之netlink ovs datapath是通过netlink与用户态进行通信的,实现dp、端口、流表、packet的操作。 netlink的注册是在datapath模块的初始化函数中实现的。 1、dp_init函数 static int __init dp_init(void) { int err; BUILD_BUG_ON(sizeof(struct ovs_skb_cb) > FIELD_SIZEO 阅读详情

Linux从2.2开始支持PF_NETLINK 域的通讯方式,这个方式主要的用途是在Linux的内核空间和用户空间进行通讯。目前在网络上面关于netlink编程的中文资料很少,为了促进对 netlink编程的理解我编写了这篇文章,由于我对netlink的了解不是很透彻,特别是对于内核部分不是很熟悉,所以文章中肯定有很多错误的地方还 请大家指正。文章分下面几个部分进行讲述

  1. netlink 基础知识
  2. nlmsghdr 结构介绍
  3. 解析nlmsghdr数据
  4. sockaddr_nl 结构介绍
  5. NETLINK_ROUTE 协议介绍
  6. NETLINK_SKIP 协议介绍
  7. NETLINK_USERSOCK协议介绍
  8. NETLINK_FIREWALL 协议介绍
  9. NETLINK_TCPDIAG 协议介绍
  10. NETLINK_NFLOG 协议介绍
  11. NETLINK_ARPD 协议介绍
  12. NETLINK_ROUTE6 协议介绍
  13. NETLINK_IP6_FW 协议介绍
  14. NETLINK_DNRTMSG 协议介绍
  15. NETLINK_TAPBASE 协议介绍
  16. 参考资料
  17. 版权说明
  18. 修改记录
  1.  
    1. 设置报文规则iptables -A INPUT -p icmp --icmp-type echo-request -j QUEUE
      这个规则表示所有的ping请求报文我们都进行排队记录,这样我们的程序中就可以获取到这个报文了.
    2. 执行监听程序./filter
    3. 进行测试使用ping命令发送请求报文ping -c 1 192.168.0.1
    4. 删除报文规则iptables -D INPUT -p icmp --icmp-type echo-request -j QUEUE 删除规则
    1. 设置报文规则iptables -A INPUT -p icmp --icmp-type echo-request -j ULOG --ulog-nlgroup 5
      这个规则表示所有的ping请求报文我们都进行记录,记录的组为5,这样我们的程序中就可以获取到这个报文了.
    2. 执行监听程序./ulog
    3. 进行测试使用ping命令发送请求报文ping -c 1 192.168.0.1
    4. 删除报文规则iptables -D INPUT -p icmp --icmp-type echo-request -j ULOG --ulog-nlgroup 5 删除规则
    1. Linux 系统内核空间与用户空间通信的实现与分析 这篇文章是陈鑫在IBM中国开发网站上的一篇文章,讨论了在LINUX下如何进行内核空间和用户空间通讯。
    2. Netlink Sockets Tour 这是一篇英文的介绍Linux内核中是如何实现netlink通讯的文章。
    3. Netlink Sockets - Overview 这是一篇介绍netlink编程入门的英文资料,介绍了一些基础性的东西。
    4. Understanding And Programming With Netlink Sockets 一篇介绍netlink程序的英文文章,介绍的非常详细。
    5. Linux Netlink as an IP Services Protocol 这个可能是最详细介绍netlink之间通讯协议报文的一篇RFC文档,详细的描述了每一个协议的通讯报文格式。
    6. NETLINK中文MAN手册 CMPP已经将netlink(7)的man手册翻译成中文了,不过现在找不到这个的html版,只找到了一个doc版。
    7. IPROUTE 路由工具 IPROUTE路由工具的源代码中有大量的关于netlink的ROUTE代码可以参考,同时也提供了一个libnetlink库用来进行操作。
    8. IPTABLES IPTABLES是一个Linux下强有力的防火墙工具。在IPTABLES的源代码中有大量的关于netlink编程的FIREWALL代码可以参考,同时也提供了一个libipq库来进行操作。
    9. ULOG 用户层日志 ULOG通过使用netlink的NFLOG功能,在用户层进行了通讯报文的日志记录功能,您可以参考ULOG的源代码来了解NFLOG的使用
    • NETLINK_ROUTE 用来获取,创建和修改设备的各种信息,详细参见 rtnetlink(7)
    • NETLINK_SKIP Enskip 的保留选项
    • NETLINK_USERSOCK 为今后用户程序空间协议用保留选项
    • NETLINK_FIREWALL 接收 IPv4 防火墙编码发送的数据包
    • NETLINK_TCPDIAG TCP套接字监控
    • NETLINK_NFLOG netfilter的用户空间日志
    • NETLINK_ARPD 用以维护用户地址空间里的 arp 表
    • NETLINK_ROUTE6 接收和发送 IPv6 路由表更新消息
    • NETLINK_IP6_FW 接收未通过 IPv6 防火墙检查的数据包(尚未实现)
    • NETLINK_TAPBASE 是 ethertap 设备实例
    • NLMSG_NOOP 这个消息类型表示消息内容为空,应用可以忽略该报文
    • NLMSG_ERROR 这个消息类型表示后面的消息是一个错误信息,错误信息的机构为nlmsgerr
                struct nlmsgerr
                {
                    int error;           /* 负数表示的出错号 errno 或为 0 要求确认 acks*/
                    struct nlmsghdr msg; /* 造成出错的消息报头*/
                };
      	
    • NLMSG_DONE 在我们接收或者发送消息给内核的时候,我们有可能一次发送多个报文,这个消息类型表示是报文的最后一个,类似于在链表中我们将最后一个成员的next指针设置为NULL。
    • NLM_F_REQUEST 表示这个消息是一个请求消息,这个消息可以同以下一个标志组合
      • NLM_F_ROOT 返回树的根
      • NLM_F_MATCH 返回所有匹配的
      • NLM_F_ATOMIC 返回对象表的单一快照
      • NLM_F_DUMP 被定义为NLM_F_ROOT|NLM_F_MATCH
      • NLM_F_REPLACE 表示替换现有的规则
      • NLM_F_EXCL 如果现有规则存在则不修改
      • NLM_F_CREAT 创建一个规则
      • NLM_F_APPEND 追加一个规则
    • NLM_F_MULTI 表示这个消息是多个报文中的一个,报文的结尾通过NLMSG_DONE来表示
    • NLM_F_ACK 表示这个消息是一个应答消息
    • NLM_F_ECHO 表示这个消息是一个要求返回请求信息的消息
    • RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK 创建,删除或者获取网络设备的信息
    • RTM_NEWADDR, RTM_DELADDR, RTM_GETADDR 创建,删除或者获取网络设备的IP信息
    • RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE 创建,删除或者获取网络设备的路由信息
    • RTM_NEWNEIGH, RTM_DELNEIGH, RTM_GETNEIGH 创建,删除或者获取网络设备的相邻信息
    • RTM_NEWRULE, RTM_DELRULE, RTM_GETRULE 创建,删除或者获取路由规则信息
    • RTM_NEWQDISC, RTM_DELQDISC, RTM_GETQDISC 创建,删除或者获取队列的原则
    • RTM_NEWTCLASS, RTM_DELTCLASS, RTM_GETTCLASS 创建,删除或者获取流量的类别
    • RTM_NEWTFILTER, RTM_DELTFILTER, RTM_GETTFILTER 创建,删除或者获取流量的过虑
    •  
      1. IPQM_MODE
      1. IPQM_VERDICT
      1. IPQM_PACKET
    • 设置内核模式 控制内核报文下一步骤 报文为从内核接收到
    • IPQ_COPY_NONE 取消从内核传送报文到用户
    • IPQ_COPY_META 只从内核拷贝基本数据到用户
    • IPQ_COPY_PACKET 除了拷贝基本数据外还拷贝报文数据,这个时候从内核出来的报文中payload指向数据的地址。
  2. 我们在使用socket(2)的man手册时候可以找到man手册中有下面一行说明

    PF_NETLINK          Kernel user interface device     netlink(7)

    在我们通过PF_NETLINK创建一个SOCKET以后表示我们期望同内核进行消息通讯。使用netlink(7)的手册可以看到关于PF_NETLINK的详细说明。

    	#include <asm/types.h>
    	#include <sys/socket.h>
    	#include <linux/netlink.h>
    
    	netlink_socket = socket(PF_NETLINK, socket_type, netlink_family);
    

    按照netlink的手册,socket_type可以取SOCK_RAW和SOCK_DGRAM,不过内核不区分这两个字段。netlink_family字段指定了我们期望的通讯协议,主要有:

    后面我们会对每一个协议进行解释和说明.

    每一个发送给内核或者从内核介绍的报文都有一个相同的报文头,这个报文头的结构如下定义:

                  struct nlmsghdr
                  {
    	              __u32 nlmsg_len;     /* 包括报头在内的消息长度*/
    	              __u16 nlmsg_type;    /* 消息正文 */
    	              __u16 nlmsg_flags;   /* 附加标志*/
    	              __u32 nlmsg_seq;     /* 序列号*/
    	              __u32 nlmsg_pid;     /* 发送进程号 PID */
                  };
    

    所有发送给内核或者内核的报文的第一部分都必须使用这个机构,后面跟随相应的内容。nlmsg_type为后面消息的内容个数,对于前面我们提到的不同通讯协议有着不同的消息类型。下面是三个通用的消息类型

    附加的标志用于控制或者表示消息的其它信息,一些比较通用的标志是

    为了获取netlink报文中数据的方便,netlink提供了下面几个宏进行数据的获取和解包操作

           #include <asm/types.h>
           #include <linux/netlink.h>
           int NLMSG_ALIGN(size_t len);
           int NLMSG_LENGTH(size_t len);
           int NLMSG_SPACE(size_t len);
           void *NLMSG_DATA(struct nlmsghdr *nlh);
           struct nlmsghdr *NLMSG_NEXT(struct nlmsghdr *nlh, int len);
           int NLMSG_OK(struct nlmsghdr *nlh, int len);
           int NLMSG_PAYLOAD(struct nlmsghdr *nlh, int len);
    
    NLMSG_ALIGN:进行数据长度的对齐操作
    NLMSG_DATA:获取通讯报文中的数据
    NLMSG_NEXT:获取下一个报文
    NLMSG_OK:判断是否数据可以继续获取
    NLMSG_PAYLOAD:获取数据的长度
    在我们后面的实例中会介绍如何使用这几个宏。

    在socket程序中,如果我们要求接收报文则要求调用bind,表示我们期望接收什么样的报文。对于netlink也一样,我们要求指定我们期望接收的地址信息,不过同传统的sockaddr不同,这个地方是一个sockaddr_nl的结构:

    	struct sockaddr_nl
    	{
    		sa_family_t nl_family; /* AF_NETLINK */
    		unsigned short nl_pad; /* 用来填充的字段,赋值为0 */
    		pid_t nl_pid; /* 进程标识号pid */
    		__u32 nl_groups; /* 多址广播组掩码*/
    	};
    

    每一个 netlink 数据类都有一个32位广播分组,当对套接字调用 bind(2) 时, sockaddr_nl 中的 nl_groups 字段设置成所要侦听的广播组的位掩码。其默认值为 0,表示不接收任何广播,我们会在后面中看到如何使用这个广播组的例子。

    netlink目前使用最广泛的是通过这个选项来获取网络设备或者网址的一些信息。在使用这个协议时候支持的类型有:

    由于NETLINK_ROUTE支持的类型实在太多了,我们这个地方只重点介绍一下RTM_GETLINK这个类型,然后通过一个例子介绍如何同内核进行通讯。关于其它类型的用法大家可以参考rtnetlink(7)的man手册。

    按照rtnetlink的说法,在获取设备信息的时候我们要求首先发送一个报文给内核表示我们的请求,这个报文的格式是1个nlmsghdr头部机构+1个ifinfomsg接口结构+多个rtattr属性机构。其中后面两个结构的定义是:

                  struct ifinfomsg
                  {
                      unsigned char  ifi_family;  /* AF_UNSPEC */
                      unsigned short ifi_type;    /* Device type */
                      int            ifi_index;   /* Interface index   */
                      unsigned int   ifi_flags;   /* Device flags  */
                      unsigned int   ifi_change;  /* change mask */
                  };
                  struct rtattr
                  {
                      unsigned short rta_len;     /* Length of option */
                      unsigned short rta_type;    /* Type of option */
                      /* Data follows */
                  };
    
    ifi_type:这个字段包含了硬件的类型,可以参考<linux/if_arp.h>比较常见的是
    	ARPHRD_ETHER 	10M以太网
    	ARPHRD_PPP      PPP拨号
    	ARPHRD_LOOPBACK 环路设备
    
    ifi_flags:这个字段包含了设备的一些标志,相应的值为:
                  IFF_UP             接口正在运行.
                  IFF_BROADCAST      有效的广播地址集.
                  IFF_DEBUG          内部调试标志.
                  IFF_LOOPBACK       这是自环接口.
                  IFF_POINTOPOINT    这是点到点的链路接口.
                  IFF_RUNNING        资源已分配.
                  IFF_NOARP          无arp协议, 没有设置第二层目的地址.
                  IFF_PROMISC        接口为杂凑(promiscuous)模式.
                  IFF_NOTRAILERS     避免使用trailer .
                  IFF_ALLMULTI       接收所有组播(multicast)报文.
                  IFF_MASTER         主负载平衡群(bundle).
                  IFF_SLAVE          从负载平衡群(bundle).
                  IFF_MULTICAST      支持组播(multicast).
                  IFF_PORTSEL        可以通过ifmap选择介质(media)类型.
                  IFF_AUTOMEDIA      自动选择介质.
                  IFF_DYNAMIC        接口关闭时丢弃地址.
    
    rta_type:这个字段指定属性的类型,相应的值为:
        IFLA_UNSPEC 后面的数据格式未指定
        IFLA_ADDRESS 后面的数据是一个硬件地址
        IFLA_BROADCAST 后面的数据是一个硬件广播地址
        IFLA_IFNAME 后面的数据是一个char型的设备名称
        IFLA_MTU unsigned int型的设备MTU值
        IFLA_LINK int型的链路类型
        IFLA_QDISC 字符串型的队列规则
        IFLA_STATS struct net_device_stats型的设备信息
    
    在我们接收和发送数据的时候为了我们获取属性的方便,rtnetlink提供了一个宏供我们取获取其中的结构,这些宏的定义为:
           #include <asm/types.h>
           #include <linux/netlink.h>
           #include <linux/rtnetlink.h>
           #include <sys/socket.h>
    
           int RTA_OK(struct rtattr *rta, int rtabuflen);
           void *RTA_DATA(struct rtattr *rta);
           unsigned int RTA_PAYLOAD(struct rtattr *rta);
           struct rtattr *RTA_NEXT(struct rtattr *rta, unsigned int rtabuflen);
           unsigned int RTA_LENGTH(unsigned int length);
           unsigned int RTA_SPACE(unsigned int length);
    
    下面是一个用来获取所有网卡信息的例子.
    #include 
    
    
    
    
    
    <stdio.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <string.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <errno.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <sys/socket.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <sys/types.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <unistd.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <asm/types.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netlink.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/rtnetlink.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netdevice.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <net/if_arp.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <netinet/if_ether.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <netinet/ether.h>
    
    
    
    
    
    
    
    int
    
    
    
    
    
     main()
    {
        int
    
    
    
    
    
     nSocket, nLen, nAttrLen;
        char
    
    
    
    
    
     szBuffer[4096
    
    
    
    
    
    ];
        struct
    
    
    
    
    
     {
            struct
    
    
    
    
    
     nlmsghdr nh;
            struct
    
    
    
    
    
     ifinfomsg ifi;
        }struReq;
        struct
    
    
    
    
    
     sockaddr_nl struAddr;
        struct
    
    
    
    
    
     nlmsghdr *pstruNL;
        struct
    
    
    
    
    
     ifinfomsg *pstruIF;
        struct
    
    
    
    
    
     rtattr *pstruAttr;
        struct
    
    
    
    
    
     net_device_stats *pstruInfo;
        struct
    
    
    
    
    
     ether_addr *pstruEther;
    
        /*
    
    
    
    
    
    
         * 创建一个PF_NETLINK的SOCKET,使用NETLINK_ROUTE协议
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        nSocket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
        if
    
    
    
    
    
    (nSocket < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "创建SOCKET错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        /*
    
    
    
    
    
    
         * 绑定地址
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        memset(&struAddr, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAddr));
        struAddr.nl_family = AF_NETLINK;
        struAddr.nl_pid = getpid();
        struAddr.nl_groups = 0
    
    
    
    
    
    ;
        if
    
    
    
    
    
    (bind(nSocket, (struct
    
    
    
    
    
     sockaddr *)&struAddr, sizeof
    
    
    
    
    
    (struAddr)) < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "绑定SOCKET错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        /*
    
    
    
    
    
    
         * 发送一个请求
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        memset(&struReq, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struReq));
        struReq.nh.nlmsg_len = NLMSG_LENGTH(sizeof
    
    
    
    
    
    (struReq));
        struReq.nh.nlmsg_type = RTM_GETLINK;
        struReq.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
        struReq.ifi.ifi_family = AF_UNSPEC;
        memset(&struAddr, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAddr));
        struAddr.nl_family = AF_NETLINK;
        struAddr.nl_pid = 0
    
    
    
    
    
    ;
        struAddr.nl_groups = 0
    
    
    
    
    
    ;
        if
    
    
    
    
    
    (sendto(nSocket, &struReq, struReq.nh.nlmsg_len, 0
    
    
    
    
    
    ,
            (struct
    
    
    
    
    
     sockaddr *)&struAddr, sizeof
    
    
    
    
    
    (struAddr)) < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "发送数据错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        /*
    
    
    
    
    
    
         * 循环接收数据,直到超时
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        alarm(30
    
    
    
    
    
    );
        memset(szBuffer, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (szBuffer));
        while
    
    
    
    
    
    ((nLen = recv(nSocket, szBuffer, sizeof
    
    
    
    
    
    (szBuffer), 0
    
    
    
    
    
    )))
        {
            alarm(0
    
    
    
    
    
    );
            pstruNL = (struct
    
    
    
    
    
     nlmsghdr *)szBuffer;
            /*
    
    
    
    
    
    
             * 判断是否继续有数据
    
    
    
    
    
    
             
    
    
    
    
    
    */
    
    
    
    
    
    
            while
    
    
    
    
    
    (NLMSG_OK(pstruNL, nLen))
            {
                /*
    
    
    
    
    
    
                 * 数据已经获取完成
    
    
    
    
    
    
                 
    
    
    
    
    
    */
    
    
    
    
    
    
                if
    
    
    
    
    
    (pstruNL -> nlmsg_type == NLMSG_DONE)
                    break
    
    
    
    
    
    ;
                if
    
    
    
    
    
    (pstruNL -> nlmsg_type == NLMSG_ERROR)
                {
                    /*
    
    
    
    
    
    
                     * 发生一个错误
    
    
    
    
    
    
                     
    
    
    
    
    
    */
    
    
    
    
    
    
                    struct
    
    
    
    
    
     nlmsgerr *pstruError;
    
                    pstruError = (struct
    
    
    
    
    
     nlmsgerr *)NLMSG_DATA(pstruNL);
                    fprintf(stderr
    
    
    
    
    
    , "发生错误[
    
    
    
    
    
    %s
    
    
    
    
    
    ]
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                        strerror(-pstruError -> error));
                    break
    
    
    
    
    
    ;
                }
    
                /*
    
    
    
    
    
    
                 * 下面通过宏获取数据
    
    
    
    
    
    
                 
    
    
    
    
    
    */
    
    
    
    
    
    
                pstruIF = NLMSG_DATA(pstruNL);
                fprintf(stderr
    
    
    
    
    
    , "获取到设备[
    
    
    
    
    
    %d
    
    
    
    
    
    ]信息
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , pstruIF -> ifi_index);
                fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    设备类型:"
    
    
    
    
    
    );
                switch
    
    
    
    
    
    (pstruIF -> ifi_type)
                {
                    case
    
    
    
    
    
     ARPHRD_ETHER:
                        fprintf(stderr
    
    
    
    
    
    , "以太网
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     ARPHRD_PPP:
                        fprintf(stderr
    
    
    
    
    
    , "PPP拨号
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     ARPHRD_LOOPBACK:
                        fprintf(stderr
    
    
    
    
    
    , "环路设备
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    default
    
    
    
    
    
    :
                        fprintf(stderr
    
    
    
    
    
    , "未知
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                }
                fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    设备状态:"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_UP )== IFF_UP)
                    fprintf(stderr
    
    
    
    
    
    , " UP"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_BROADCAST) == IFF_BROADCAST)
                    fprintf(stderr
    
    
    
    
    
    , " BROADCAST"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_DEBUG) == IFF_DEBUG)
                    fprintf(stderr
    
    
    
    
    
    , " DEBUG"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_LOOPBACK) == IFF_LOOPBACK)
                    fprintf(stderr
    
    
    
    
    
    , " LOOPBACK"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_POINTOPOINT) == IFF_POINTOPOINT)
                    fprintf(stderr
    
    
    
    
    
    , " POINTOPOINT"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_RUNNING) == IFF_RUNNING)
                    fprintf(stderr
    
    
    
    
    
    , " RUNNING"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_NOARP) == IFF_NOARP)
                    fprintf(stderr
    
    
    
    
    
    , " NOARP"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_PROMISC) == IFF_PROMISC)
                    fprintf(stderr
    
    
    
    
    
    , " PROMISC"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_NOTRAILERS) == IFF_NOTRAILERS)
                    fprintf(stderr
    
    
    
    
    
    , " NOTRAILERS"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_ALLMULTI) == IFF_ALLMULTI)
                    fprintf(stderr
    
    
    
    
    
    , " ALLMULTI"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_MASTER) == IFF_MASTER)
                    fprintf(stderr
    
    
    
    
    
    , " MASTER"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_SLAVE) == IFF_SLAVE)
                    fprintf(stderr
    
    
    
    
    
    , " SLAVE"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_MULTICAST) == IFF_MULTICAST)
                    fprintf(stderr
    
    
    
    
    
    , " MULTICAST"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_PORTSEL) == IFF_PORTSEL)
                    fprintf(stderr
    
    
    
    
    
    , " SLAVE"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_AUTOMEDIA) == IFF_AUTOMEDIA)
                    fprintf(stderr
    
    
    
    
    
    , " AUTOMEDIA"
    
    
    
    
    
    );
                if
    
    
    
    
    
    ((pstruIF -> ifi_flags & IFF_DYNAMIC) == IFF_DYNAMIC)
                    fprintf(stderr
    
    
    
    
    
    , " DYNAMIC"
    
    
    
    
    
    );
                fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
    
                /*
    
    
    
    
    
    
                 * 下面通过宏获取属性
    
    
    
    
    
    
                 
    
    
    
    
    
    */
    
    
    
    
    
    
                pstruAttr = IFLA_RTA(pstruIF);
                nAttrLen = NLMSG_PAYLOAD(pstruNL, sizeof
    
    
    
    
    
    (struct
    
    
    
    
    
     ifinfomsg));
                while
    
    
    
    
    
    (RTA_OK(pstruAttr, nAttrLen))
                {
                    switch
    
    
    
    
    
    (pstruAttr->rta_type)
                    {
                        case
    
    
    
    
    
     IFLA_IFNAME:
                            fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    设备名称:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                                (char
    
    
    
    
    
     *)RTA_DATA(pstruAttr));
                            break
    
    
    
    
    
    ;
                        case
    
    
    
    
    
     IFLA_MTU:
                            fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    设备MTU:
    
    
    
    
    
    %d
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                                *(unsigned
    
    
    
    
    
     int
    
    
    
    
    
     *)RTA_DATA(pstruAttr));
                            break
    
    
    
    
    
    ;
                        case
    
    
    
    
    
     IFLA_QDISC:
                            fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    设备队列:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                                (char
    
    
    
    
    
     *)RTA_DATA(pstruAttr));
                            break
    
    
    
    
    
    ;
                        case
    
    
    
    
    
     IFLA_ADDRESS:
                            if
    
    
    
    
    
    (pstruIF -> ifi_type == ARPHRD_ETHER)
                            {
                                pstruEther = (struct
    
    
    
    
    
     ether_addr *)
                                    RTA_DATA(pstruAttr);
                                fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    MAC地址:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                                    ether_ntoa(pstruEther));
                            }
                            break
    
    
    
    
    
    ;
                        case
    
    
    
    
    
     IFLA_BROADCAST:
                            if
    
    
    
    
    
    (pstruIF -> ifi_type == ARPHRD_ETHER)
                            {
                                pstruEther = (struct
    
    
    
    
    
     ether_addr *)
                                    RTA_DATA(pstruAttr);
                                fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    广播MAC地址:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                                    ether_ntoa(pstruEther));
                            }
                            break
    
    
    
    
    
    ;
                        case
    
    
    
    
    
     IFLA_STATS:
                            pstruInfo = (struct
    
    
    
    
    
     net_device_stats *)
                                RTA_DATA(pstruAttr);
                            fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    接收信息:
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
                            fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t/t
    
    
    
    
    
    接收报文:
    
    
    
    
    
    %lu
    
    
    
    
    
     字节:
    
    
    
    
    
    %lu
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                                pstruInfo -> rx_packets, pstruInfo -> rx_bytes);
                            fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t/t
    
    
    
    
    
    errors:
    
    
    
    
    
    %lu
    
    
    
    
    
     dropped:
    
    
    
    
    
    %lu
    
    
    
    
    
     "
    
    
    
    
    
    
                                    "multicast:
    
    
    
    
    
    %lu
    
    
    
    
    
     collisions:
    
    
    
    
    
    %lu
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                                pstruInfo -> rx_errors, pstruInfo -> rx_dropped,
                                pstruInfo -> multicast, pstruInfo -> collisions);
                            fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t/t
    
    
    
    
    
    length:
    
    
    
    
    
    %lu
    
    
    
    
    
     over:
    
    
    
    
    
    %lu
    
    
    
    
    
     crc:
    
    
    
    
    
    %lu
    
    
    
    
    
     "
    
    
    
    
    
    
                                    "frame:
    
    
    
    
    
    %lu
    
    
    
    
    
     fifo:
    
    
    
    
    
    %lu
    
    
    
    
    
     missed:
    
    
    
    
    
    %lu
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                                pstruInfo -> rx_length_errors,
                                pstruInfo -> rx_over_errors,
                                pstruInfo -> rx_crc_errors,
                                pstruInfo -> rx_frame_errors,
                                pstruInfo -> rx_fifo_errors,
                                pstruInfo -> rx_missed_errors);
                            fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    发送信息:
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
                            fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t/t
    
    
    
    
    
    发送报文:
    
    
    
    
    
    %lu
    
    
    
    
    
     字节:
    
    
    
    
    
    %lu
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                                pstruInfo -> tx_packets, pstruInfo -> tx_bytes);
                            fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t/t
    
    
    
    
    
    errors:
    
    
    
    
    
    %lu
    
    
    
    
    
     dropped:
    
    
    
    
    
    %lu
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                                pstruInfo -> tx_errors, pstruInfo -> tx_dropped);
                            fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t/t
    
    
    
    
    
    aborted:
    
    
    
    
    
    %lu
    
    
    
    
    
     carrier:
    
    
    
    
    
    %lu
    
    
    
    
    
     fifo:
    
    
    
    
    
    %lu
    
    
    
    
    
    "
    
    
    
    
    
    
                                    " heartbeat:
    
    
    
    
    
    %lu
    
    
    
    
    
     window:
    
    
    
    
    
    %lu
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                                pstruInfo -> tx_aborted_errors,
                                pstruInfo -> tx_carrier_errors,
                                pstruInfo -> tx_fifo_errors,
                                pstruInfo -> tx_heartbeat_errors,
                                pstruInfo -> tx_window_errors);
                            break
    
    
    
    
    
    ;
                        default
    
    
    
    
    
    :
                            break
    
    
    
    
    
    ;
    
                    }
                    /*
    
    
    
    
    
    
                     * 继续下一个属性
    
    
    
    
    
    
                     
    
    
    
    
    
    */
    
    
    
    
    
    
                    pstruAttr = RTA_NEXT(pstruAttr, nAttrLen);
                }
                /*
    
    
    
    
    
    
                 * 继续下一个数据
    
    
    
    
    
    
                 
    
    
    
    
    
    */
    
    
    
    
    
    
                pstruNL = NLMSG_NEXT(pstruNL, nLen);
            }
            memset(szBuffer, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (szBuffer));
            alarm(30
    
    
    
    
    
    );
        }
        return
    
    
    
    
    
     0
    
    
    
    
    
    ;
    }
    
    下面是我的机器的输出信息
    获取到设备[1]信息
    	设备类型:环路设备
    	设备状态: UP LOOPBACK RUNNING
    	设备名称:lo
    	设备MTU:16436
    	设备队列:noqueue
    	接收信息:
    		接收报文:73 字节:5105
    		errors:0 dropped:0 multicast:0 collisions:0
    		length:0 over:0 crc:0 frame:0 fifo:0 missed:0
    	发送信息:
    		发送报文:73 字节:5105
    		errors:0 dropped:0
    		aborted:0 carrier:0 fifo:0 heartbeat:0 window:0
    获取到设备[2]信息
    	设备类型:以太网
    	设备状态: UP BROADCAST RUNNING MULTICAST
    	设备名称:eth0
    	MAC地址:0:e0:4c:68:17:e2
    	广播MAC地址:ff:ff:ff:ff:ff:ff
    	设备MTU:1500
    	设备队列:pfifo_fast
    	接收信息:
    		接收报文:23942563 字节:2498812213
    		errors:0 dropped:0 multicast:0 collisions:0
    		length:0 over:0 crc:0 frame:0 fifo:0 missed:0
    	发送信息:
    		发送报文:26027259 字节:782054736
    		errors:0 dropped:0
    		aborted:0 carrier:0 fifo:0 heartbeat:0 window:0
    获取到设备[3]信息
    	设备类型:以太网
    	设备状态: UP BROADCAST RUNNING MULTICAST
    	设备名称:eth1
    	MAC地址:0:11:5b:16:ac:52
    	广播MAC地址:ff:ff:ff:ff:ff:ff
    	设备MTU:1500
    	设备队列:pfifo_fast
    	接收信息:
    		接收报文:28576652 字节:97399242
    		errors:0 dropped:0 multicast:0 collisions:0
    		length:0 over:0 crc:0 frame:0 fifo:0 missed:0
    	发送信息:
    		发送报文:22489921 字节:2255181112
    		errors:0 dropped:0
    		aborted:0 carrier:0 fifo:0 heartbeat:0 window:0
    获取到设备[4]信息
    	设备类型:PPP拨号
    	设备状态: UP POINTOPOINT RUNNING NOARP MULTICAST
    	设备名称:ppp0
    	设备MTU:1492
    	设备队列:pfifo_fast
    	接收信息:
    		接收报文:25021013 字节:3614587231
    		errors:0 dropped:0 multicast:0 collisions:0
    		length:0 over:0 crc:0 frame:0 fifo:0 missed:0
    	发送信息:
    		发送报文:22442439 字节:1757067695
    		errors:0 dropped:0
    		aborted:0 carrier:0 fifo:0 heartbeat:0 window:0
    

    TODO:还没有找到资料

    TODO:还没有找到资料

    FIREWALL协议一般主要是用于netfilter的包过虑机制中,我们通过使用iptables的-j QUEUE机制将报文进行队列排队,然后就从用户层来进行报文的接收或者拒绝操作。对于FIREWALL协议,支持的消息类型有三种分别是:

    当消息类型为IPQM_PACKET,表示报文是从内核到用户的。从内核到用户的报文格式为nlmsghdr头加上一个ipq_packet_msg数据报文。其中ipq_packet_msg的结构定义为:

     1
    
    
    
    
    
      /*
    
    
    
    
    
     
    
    
    
    
    
    
     2
    
    
    
    
    
       * 从内核发送到用户的消息格式
    
    
    
    
    
    
     3
    
    
    
    
    
       
    
    
    
    
    
    */
    
    
    
    
    
    
     4
    
    
    
    
    
      typedef
    
    
    
    
    
     struct
    
    
    
    
    
     ipq_packet_msg {
     5
    
    
    
    
    
          unsigned
    
    
    
    
    
     long
    
    
    
    
    
     packet_id;        /*
    
    
    
    
    
     报文ID号         
    
    
    
    
    
    */
    
    
    
    
    
    
     6
    
    
    
    
    
          unsigned
    
    
    
    
    
     long
    
    
    
    
    
     mark;             /*
    
    
    
    
    
     MARK标记         
    
    
    
    
    
    */
    
    
    
    
    
    
     7
    
    
    
    
    
          long
    
    
    
    
    
     timestamp_sec;             /*
    
    
    
    
    
     到达时间(秒)     
    
    
    
    
    
    */
    
    
    
    
    
    
     8
    
    
    
    
    
          long
    
    
    
    
    
     timestamp_usec;            /*
    
    
    
    
    
     到达时间(微秒)   
    
    
    
    
    
    */
    
    
    
    
    
    
     9
    
    
    
    
    
          unsigned
    
    
    
    
    
     int
    
    
    
    
    
     hook;              /*
    
    
    
    
    
     钩子位置         
    
    
    
    
    
    */
    
    
    
    
    
    
    10
    
    
    
    
    
          char
    
    
    
    
    
     indev_name[IFNAMSIZ];      /*
    
    
    
    
    
     进入接口         
    
    
    
    
    
    */
    
    
    
    
    
    
    11
    
    
    
    
    
          char
    
    
    
    
    
     outdev_name[IFNAMSIZ];     /*
    
    
    
    
    
     出去接口         
    
    
    
    
    
    */
    
    
    
    
    
    
    12
    
    
    
    
    
          unsigned
    
    
    
    
    
     short
    
    
    
    
    
     hw_protocol;     /*
    
    
    
    
    
     硬件协议         
    
    
    
    
    
    */
    
    
    
    
    
    
    13
    
    
    
    
    
          unsigned
    
    
    
    
    
     short
    
    
    
    
    
     hw_type;         /*
    
    
    
    
    
     硬件类型         
    
    
    
    
    
    */
    
    
    
    
    
    
    14
    
    
    
    
    
          unsigned
    
    
    
    
    
     char
    
    
    
    
    
     hw_addrlen;       /*
    
    
    
    
    
     硬件地址长度     
    
    
    
    
    
    */
    
    
    
    
    
    
    15
    
    
    
    
    
          unsigned
    
    
    
    
    
     char
    
    
    
    
    
     hw_addr[8
    
    
    
    
    
    ];       /*
    
    
    
    
    
     硬件地址         
    
    
    
    
    
    */
    
    
    
    
    
    
    16
    
    
    
    
    
          size_t
    
    
    
    
    
     data_len;                /*
    
    
    
    
    
     数据长度         
    
    
    
    
    
    */
    
    
    
    
    
    
    17
    
    
    
    
    
          unsigned
    
    
    
    
    
     char
    
    
    
    
    
     payload[0
    
    
    
    
    
    ];       /*
    
    
    
    
    
     数据起始位置     
    
    
    
    
    
    */
    
    
    
    
    
    
    18
    
    
    
    
    
      } ipq_packet_msg_t;
    

    当消息类型为IPQM_MODE,表示报文是从用户到内核,用户请求内核完成某项操作。请求报文的格式为nlmsghdr头加上一个ipq_mode_msg数据报文。其中ipq_mode_msg的结构定义为:

    21
    
    
    
    
    
       * 从用户到内核的消息
    
    
    
    
    
    
    22
    
    
    
    
    
       
    
    
    
    
    
    */
    
    
    
    
    
    
    23
    
    
    
    
    
      typedef
    
    
    
    
    
     struct
    
    
    
    
    
     ipq_mode_msg {
    24
    
    
    
    
    
          unsigned
    
    
    
    
    
     char
    
    
    
    
    
     value;            /*
    
    
    
    
    
     要求操作指令     
    
    
    
    
    
    */
    
    
    
    
    
    
    25
    
    
    
    
    
          size_t
    
    
    
    
    
     range;                   /*
    
    
    
    
    
     数据范围         
    
    
    
    
    
    */
    
    
    
    
    
    
    26
    
    
    
    
    
      } ipq_mode_msg_t;
    
    其中value的合法取值为: range在value为IPQ_COPY_PACKET时候指定我们希望从内核拷贝多少的数据出来。

    当消息类型为IPQM_VERDICT,表示报文是从用户到内核,用户指定内核完成某项操作。请求报文的格式为nlmsghdr头加上一个ipq_mode_verdict数据报文。其中ipq_mode_verdict的结构定义为:

    28
    
    
    
    
    
      /*
    
    
    
    
    
    
    29
    
    
    
    
    
       * 从用户到内核的消息
    
    
    
    
    
    
    30
    
    
    
    
    
       
    
    
    
    
    
    */
    
    
    
    
    
    
    31
    
    
    
    
    
      typedef
    
    
    
    
    
     struct
    
    
    
    
    
     ipq_verdict_msg {
    32
    
    
    
    
    
          unsigned
    
    
    
    
    
     int
    
    
    
    
    
     value;             /*
    
    
    
    
    
     控制操作模式     
    
    
    
    
    
    */
    
    
    
    
    
    
    33
    
    
    
    
    
          unsigned
    
    
    
    
    
     long
    
    
    
    
    
     id;               /*
    
    
    
    
    
     要求操作的报文ID 
    
    
    
    
    
    */
    
    
    
    
    
    
    34
    
    
    
    
    
          size_t
    
    
    
    
    
     data_len;                /*
    
    
    
    
    
     数据长度         
    
    
    
    
    
    */
    
    
    
    
    
    
    35
    
    
    
    
    
          unsigned
    
    
    
    
    
     char
    
    
    
    
    
     payload[0
    
    
    
    
    
    ];       /*
    
    
    
    
    
     数据的长度       
    
    
    
    
    
    */
    
    
    
    
    
    
    36
    
    
    
    
    
      } ipq_verdict_msg_t;
    

    其中value的取值为NF_ACCEPT表示要求内核接受这个报文,NF_DROP表示丢弃这个报文,其余我们不关心的取值有NF_STOLEN, NF_QUEUE, NF_REPEAT等。下面是一个实际的例子:

    #include 
    
    
    
    
    
    <unistd.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <stdlib.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <stdio.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <string.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <errno.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <time.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <asm/types.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <sys/types.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <sys/socket.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netlink.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netfilter.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netfilter_ipv4/ip_queue.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <netinet/ether.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netfilter_ipv4.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <signal.h>
    
    
    
    
    
    
    
    static
    
    
    
    
    
     volatile
    
    
    
    
    
     int
    
    
    
    
    
     gnContinue = 1
    
    
    
    
    
    ;
    static
    
    
    
    
    
     void
    
    
    
    
    
     in_catch_sig(int
    
    
    
    
    
     nSig)
    {
        gnContinue = 0
    
    
    
    
    
    ;
    }
    
    int
    
    
    
    
    
     main(int
    
    
    
    
    
     argc, char
    
    
    
    
    
     *argv[])
    {
        int
    
    
    
    
    
     nSocket, nLen;
        struct
    
    
    
    
    
     sockaddr_nl struAddr;
        struct
    
    
    
    
    
     nlmsghdr *pstruNL;
        struct
    
    
    
    
    
     ipq_packet_msg *pstruPacketMsg;
        char
    
    
    
    
    
     szBuffer[4096
    
    
    
    
    
    ];
        struct
    
    
    
    
    
     tm struTmNow;
        struct
    
    
    
    
    
     sigaction struAct;
    
        struct
    
    
    
    
    
     {
            struct
    
    
    
    
    
     nlmsghdr head;
            union
    
    
    
    
    
    {
                struct
    
    
    
    
    
     ipq_mode_msg mode;
                struct
    
    
    
    
    
     ipq_verdict_msg verdict;
            }body;
        } struReq;
    
        /*
    
    
    
    
    
    
         * 创建SOCKET
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        nSocket = socket(AF_NETLINK, SOCK_RAW, NETLINK_FIREWALL);
        if
    
    
    
    
    
     (nSocket < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "创建SOCKET错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        /*
    
    
    
    
    
    
         * 监听本地地址
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        memset(&struAddr, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAddr));
        struAddr.nl_family = AF_NETLINK;
        struAddr.nl_pid = getpid();
        struAddr.nl_groups = 0
    
    
    
    
    
    ;
        if
    
    
    
    
    
    (bind(nSocket, (struct
    
    
    
    
    
     sockaddr *)&struAddr, sizeof
    
    
    
    
    
    (struAddr)) < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "绑定SOCKET错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        memset(&struAct, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAct));
        struAct.sa_handler = in_catch_sig;
        sigfillset(&struAct.sa_mask);
        if
    
    
    
    
    
    (sigaction(SIGINT
    
    
    
    
    
    , &struAct, NULL
    
    
    
    
    
    ) < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "设置信号捕捉错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        /*
    
    
    
    
    
    
         * 设置报文内容
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        memset(&struReq, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struReq));
        struReq.head.nlmsg_len = NLMSG_LENGTH(sizeof
    
    
    
    
    
    (struReq));
        struReq.head.nlmsg_type = IPQM_MODE;
        struReq.head.nlmsg_flags =  NLM_F_REQUEST | NLM_F_DUMP;
        struReq.head.nlmsg_pid = getpid();
        struReq.body.mode.value = IPQ_COPY_META;
    
        /*
    
    
    
    
    
    
         * 发送报文到内核
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        memset(&struAddr, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAddr));
        struAddr.nl_family = AF_NETLINK;
        struAddr.nl_pid = 0
    
    
    
    
    
    ;
        struAddr.nl_groups = 0
    
    
    
    
    
    ;
        if
    
    
    
    
    
    (sendto(nSocket, &struReq, struReq.head.nlmsg_len, 0
    
    
    
    
    
    ,
            (struct
    
    
    
    
    
     sockaddr *)&struAddr, sizeof
    
    
    
    
    
    (struAddr)) < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "设置 IPQM_MODE 错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        memset(szBuffer, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (szBuffer));
        fprintf(stderr
    
    
    
    
    
    , "Press CTRL+C to quit
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
        while
    
    
    
    
    
    (gnContinue)
        {
            nLen = recv(nSocket, szBuffer, sizeof
    
    
    
    
    
    (szBuffer), 0
    
    
    
    
    
    );
            if
    
    
    
    
    
    (nLen < 0
    
    
    
    
    
    )
                break
    
    
    
    
    
    ;
            pstruNL =(struct
    
    
    
    
    
     nlmsghdr *)szBuffer;
    
            /*
    
    
    
    
    
    
             * 判断是否继续有数据
    
    
    
    
    
    
             
    
    
    
    
    
    */
    
    
    
    
    
    
            while
    
    
    
    
    
    (NLMSG_OK(pstruNL, nLen))
            {
                /*
    
    
    
    
    
    
                 * 数据已经获取完成
    
    
    
    
    
    
                 
    
    
    
    
    
    */
    
    
    
    
    
    
                if
    
    
    
    
    
    (pstruNL -> nlmsg_type == NLMSG_DONE)
                    break
    
    
    
    
    
    ;
                if
    
    
    
    
    
    (pstruNL -> nlmsg_type == NLMSG_ERROR)
                {
                    /*
    
    
    
    
    
    
                     * 发生一个错误
    
    
    
    
    
    
                     
    
    
    
    
    
    */
    
    
    
    
    
    
                    struct
    
    
    
    
    
     nlmsgerr *pstruError;
    
                    pstruError = (struct
    
    
    
    
    
     nlmsgerr *)NLMSG_DATA(pstruNL);
                    fprintf(stderr
    
    
    
    
    
    , "发生错误[
    
    
    
    
    
    %s
    
    
    
    
    
    ]
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                        strerror(-pstruError -> error));
                    break
    
    
    
    
    
    ;
                }
    
                /*
    
    
    
    
    
    
                 * 下面通过宏获取数据
    
    
    
    
    
    
                 
    
    
    
    
    
    */
    
    
    
    
    
    
                if
    
    
    
    
    
    (pstruNL -> nlmsg_type == IPQM_PACKET)
                {
                    pstruPacketMsg = NLMSG_DATA(pstruNL);
                    fprintf(stderr
    
    
    
    
    
    , "获取到一个报文:[MARK-
    
    
    
    
    
    %lu
    
    
    
    
    
    ]"
    
    
    
    
    
    ,
                        pstruPacketMsg -> mark);
                    switch
    
    
    
    
    
    (pstruPacketMsg -> hook)
                    {
                        case
    
    
    
    
    
     NF_IP_PRE_ROUTING:
                            fprintf(stderr
    
    
    
    
    
    , "[PREROUTING]"
    
    
    
    
    
    );
                            break
    
    
    
    
    
    ;
                        case
    
    
    
    
    
     NF_IP_LOCAL_IN:
                            fprintf(stderr
    
    
    
    
    
    , "[INPUT]"
    
    
    
    
    
    );
                            break
    
    
    
    
    
    ;
                        case
    
    
    
    
    
     NF_IP_FORWARD:
                            fprintf(stderr
    
    
    
    
    
    , "[FORWARD]"
    
    
    
    
    
    );
                            break
    
    
    
    
    
    ;
                        case
    
    
    
    
    
     NF_IP_LOCAL_OUT:
                            fprintf(stderr
    
    
    
    
    
    , "[OUTPUT]"
    
    
    
    
    
    );
                            break
    
    
    
    
    
    ;
                        case
    
    
    
    
    
     NF_IP_POST_ROUTING:
                            fprintf(stderr
    
    
    
    
    
    , "[POSTROUTING]"
    
    
    
    
    
    );
                            break
    
    
    
    
    
    ;
                        default
    
    
    
    
    
    :
                            fprintf(stderr
    
    
    
    
    
    , "[UNKNOWN]"
    
    
    
    
    
    );
                            break
    
    
    
    
    
    ;
                    }
                    fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
                    struTmNow = *localtime(&pstruPacketMsg -> timestamp_sec);
                    fprintf(stderr
    
    
    
    
    
    ,
                        "
    
    
    
    
    
    /t
    
    
    
    
    
    时间[
    
    
    
    
    
    %04d
    
    
    
    
    
    -
    
    
    
    
    
    %02d
    
    
    
    
    
    -
    
    
    
    
    
    %02d
    
    
    
    
    
     
    
    
    
    
    
    %02d
    
    
    
    
    
    :
    
    
    
    
    
    %02d
    
    
    
    
    
    :
    
    
    
    
    
    %02d
    
    
    
    
    
    ] ID:
    
    
    
    
    
    %lu
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                        struTmNow.tm_year + 1900
    
    
    
    
    
    , struTmNow.tm_mon + 1
    
    
    
    
    
    ,
                        struTmNow.tm_mday, struTmNow.tm_hour,
                        struTmNow.tm_min, struTmNow.tm_sec,
                        pstruPacketMsg -> packet_id);
                    fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    进入:
    
    
    
    
    
    %s
    
    
    
    
    
     出去:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                        pstruPacketMsg -> indev_name,
                        pstruPacketMsg -> outdev_name);
                    if
    
    
    
    
    
    (pstruPacketMsg -> hw_type == ARPHRD_ETHER)
                    {
                        fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    MAC地址:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                            ether_ntoa((struct
    
    
    
    
    
     ether_addr *)
                                pstruPacketMsg -> hw_addr));
                    }
    
                    /*
    
    
    
    
    
    
                     * 决定数据的下一步
    
    
    
    
    
    
                     
    
    
    
    
    
    */
    
    
    
    
    
    
                    memset(&struReq, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struReq));
                    struReq.head.nlmsg_len = NLMSG_LENGTH(sizeof
    
    
    
    
    
    (struReq));
                    struReq.head.nlmsg_type = IPQM_VERDICT;
                    struReq.head.nlmsg_flags =  NLM_F_REQUEST | NLM_F_DUMP;
                    struReq.head.nlmsg_pid = getpid();
                    struReq.body.verdict.value = NF_ACCEPT;
                    struReq.body.verdict.id = pstruPacketMsg -> packet_id;
    
                    /*
    
    
    
    
    
    
                     * 发送报文到内核
    
    
    
    
    
    
                     
    
    
    
    
    
    */
    
    
    
    
    
    
                    memset(&struAddr, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAddr));
                    struAddr.nl_family = AF_NETLINK;
                    struAddr.nl_pid = 0
    
    
    
    
    
    ;
                    struAddr.nl_groups = 0
    
    
    
    
    
    ;
                    if
    
    
    
    
    
    (sendto(nSocket, &struReq, struReq.head.nlmsg_len, 0
    
    
    
    
    
    ,
                        (struct
    
    
    
    
    
     sockaddr *)&struAddr, sizeof
    
    
    
    
    
    (struAddr)) < 0
    
    
    
    
    
    )
                    {
                        fprintf(stderr
    
    
    
    
    
    , "设置 IPQM_VERDICT 错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                            strerror(errno));
                        return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
                    }
    
                }
                /*
    
    
    
    
    
    
                 * 继续下一个数据
    
    
    
    
    
    
                 
    
    
    
    
    
    */
    
    
    
    
    
    
                pstruNL = NLMSG_NEXT(pstruNL, nLen);
            }
        }
    
        /*
    
    
    
    
    
    
         * 取消模式
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        memset(&struReq, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struReq));
        struReq.head.nlmsg_len = NLMSG_LENGTH(sizeof
    
    
    
    
    
    (struReq));
        struReq.head.nlmsg_type = IPQM_MODE;
        struReq.head.nlmsg_flags =  NLM_F_REQUEST | NLM_F_DUMP;
        struReq.head.nlmsg_pid = getpid();
        struReq.body.mode.value = IPQ_COPY_NONE;
    
        /*
    
    
    
    
    
    
         * 发送报文到内核
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        memset(&struAddr, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAddr));
        struAddr.nl_family = AF_NETLINK;
        struAddr.nl_pid = 0
    
    
    
    
    
    ;
        struAddr.nl_groups = 0
    
    
    
    
    
    ;
        if
    
    
    
    
    
    (sendto(nSocket, &struReq, struReq.head.nlmsg_len, 0
    
    
    
    
    
    ,
            (struct
    
    
    
    
    
     sockaddr *)&struAddr, sizeof
    
    
    
    
    
    (struAddr)) < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "设置 IPQM_MODE 错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
        return
    
    
    
    
    
     0
    
    
    
    
    
    ;
    }
    

    如果想上面的程序能够执行,我们必须以root身份执行下面几个命令(假设已经将上面的代码编译为了filter程序)

    下面是我的执行结果
    -- 这个是从本机ping过来的
    获取到一个报文:0  
    [INPUT]
            时间[2005-01-24 15:03:05] ID:3332502528
            进入:lo 出去:
    -- 这个是从另外一台ping过来的
    获取到一个报文:0
    [INPUT]
            时间[2005-01-24 15:03:34] ID:3332502784
            进入:eth0 出去:
            MAC地址:0:a:e4:24:24:86
    

    TCPDIAG用于TCP连接的诊断状态,由于网 络上面没有找到任何关于这个协议的说明,我就简单的分析了Linux的tcp_diag.c源代码,由于我对内核不熟悉,所以只分析了其中的一个 TCPDIAG_GETSOCK消息类型,TCPDIAG_REQ_BYTECODE这个消息类型还没有进行分析.使用TCPDIAG_GETSOCK时 候表示我们期望获取一个socket的状态,这个时候请求消息的格式为1个nlmsghdr机构加上一个tcpdiagreq结构,应答消息结构格式为1 个nlmsghdr结构加上一个tcpdiagmsg机构

    /*
    
    
    
    
    
     
    
    
    
    
    
    
     * SOCKET ID结构
    
    
    
    
    
    
     
    
    
    
    
    
    */
    
    
    
    
    
    
    struct
    
    
    
    
    
     tcpdiag_sockid
    {
        __u16   tcpdiag_sport;  /*
    
    
    
    
    
     源端口   
    
    
    
    
    
    */
    
    
    
    
    
    
        __u16   tcpdiag_dport;  /*
    
    
    
    
    
     目的端口 
    
    
    
    
    
    */
    
    
    
    
    
    
        __u32   tcpdiag_src[4
    
    
    
    
    
    ]; /*
    
    
    
    
    
     源地址   
    
    
    
    
    
    */
    
    
    
    
    
    
        __u32   tcpdiag_dst[4
    
    
    
    
    
    ]; /*
    
    
    
    
    
     目的地址 
    
    
    
    
    
    */
    
    
    
    
    
    
        __u32   tcpdiag_if;     /*
    
    
    
    
    
     接口设备 
    
    
    
    
    
    */
    
    
    
    
    
    
        __u32   tcpdiag_cookie[2
    
    
    
    
    
    ];
    #define TCPDIAG_NOCOOKIE (~
    
    
    
    
    
    0U
    
    
    
    
    
    )
    
    
    
    
    
    
    };
    
    /*
    
    
    
    
    
    
     * 请求结构
    
    
    
    
    
    
     
    
    
    
    
    
    */
    
    
    
    
    
    
    struct
    
    
    
    
    
     tcpdiagreq
    {
        __u8    tcpdiag_family;     /*
    
    
    
    
    
     Family of addresses. 
    
    
    
    
    
    */
    
    
    
    
    
    
        __u8    tcpdiag_src_len;
        __u8    tcpdiag_dst_len;
        __u8    tcpdiag_ext;        /*
    
    
    
    
    
     Query extended information 
    
    
    
    
    
    */
    
    
    
    
    
    
    
        struct
    
    
    
    
    
     tcpdiag_sockid id;
    
        __u32   tcpdiag_states;     /*
    
    
    
    
    
     States to dump 
    
    
    
    
    
    */
    
    
    
    
    
    
        __u32   tcpdiag_dbs;        /*
    
    
    
    
    
     Tables to dump (NI) 
    
    
    
    
    
    */
    
    
    
    
    
    
    };
    
    struct
    
    
    
    
    
     tcpdiagmsg
    {
        __u8    tcpdiag_family;
        __u8    tcpdiag_state;
        __u8    tcpdiag_timer;
        __u8    tcpdiag_retrans;
    
        struct
    
    
    
    
    
     tcpdiag_sockid id;
    
        __u32   tcpdiag_expires;
        __u32   tcpdiag_rqueue;
        __u32   tcpdiag_wqueue;
        __u32   tcpdiag_uid;
        __u32   tcpdiag_inode;
    };
    
    下面是一个简单的测试代码
    #include 
    
    
    
    
    
    <unistd.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <stdlib.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <stdio.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <string.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <errno.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <time.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <asm/types.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <sys/types.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <sys/socket.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netlink.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netfilter.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <netinet/ether.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netfilter_ipv4.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    "/usr/src/linux/include/linux/tcp_diag.h"
    
    
    
    
    
      /*
    
    
    
    
    
     这个地方是头文件位置 
    
    
    
    
    
    */
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <signal.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <sys/socket.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <netinet/tcp.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <netinet/in.h>
    
    
    
    
    
    
    
    static
    
    
    
    
    
     volatile
    
    
    
    
    
     int
    
    
    
    
    
     gnContinue = 1
    
    
    
    
    
    ;
    static
    
    
    
    
    
     void
    
    
    
    
    
     in_catch_sig(int
    
    
    
    
    
     nSig)
    {
        gnContinue = 0
    
    
    
    
    
    ;
    }
    
    int
    
    
    
    
    
     main(int
    
    
    
    
    
     argc, char
    
    
    
    
    
     *argv[])
    {
        int
    
    
    
    
    
     nSocket, nLen;
        struct
    
    
    
    
    
     sockaddr_nl struAddr;
        struct
    
    
    
    
    
     nlmsghdr *pstruNL;
        struct
    
    
    
    
    
     tcpdiagmsg *pstruPacketMsg;
        char
    
    
    
    
    
     szBuffer[4096
    
    
    
    
    
    ];
        struct
    
    
    
    
    
     tm struTmNow;
        struct
    
    
    
    
    
     sigaction struAct;
        char
    
    
    
    
    
     szTemp[256
    
    
    
    
    
    ];
    
        struct
    
    
    
    
    
     {
            struct
    
    
    
    
    
     nlmsghdr head;
            struct
    
    
    
    
    
     tcpdiagreq body;
        } struReq;
    
        /*
    
    
    
    
    
    
         * 创建SOCKET
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        nSocket = socket(AF_NETLINK, SOCK_RAW, NETLINK_TCPDIAG);
        if
    
    
    
    
    
     (nSocket < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "创建SOCKET错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        /*
    
    
    
    
    
    
         * 监听本地地址
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        memset(&struAddr, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAddr));
        struAddr.nl_family = AF_NETLINK;
        struAddr.nl_pid = getpid();
        struAddr.nl_groups = 0
    
    
    
    
    
    ;
        if
    
    
    
    
    
    (bind(nSocket, (struct
    
    
    
    
    
     sockaddr *)&struAddr, sizeof
    
    
    
    
    
    (struAddr)) < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "绑定SOCKET错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        memset(&struAct, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAct));
        struAct.sa_handler = in_catch_sig;
        sigfillset(&struAct.sa_mask);
        if
    
    
    
    
    
    (sigaction(SIGINT
    
    
    
    
    
    , &struAct, NULL
    
    
    
    
    
    ) < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "设置信号捕捉错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        /*
    
    
    
    
    
    
         * 设置报文内容
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        memset(&struReq, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struReq));
        struReq.head.nlmsg_len = NLMSG_LENGTH(sizeof
    
    
    
    
    
    (struReq));
        struReq.head.nlmsg_type = TCPDIAG_GETSOCK;
        struReq.head.nlmsg_flags =  NLM_F_REQUEST;
        struReq.head.nlmsg_pid = getpid();
    
        struReq.body.tcpdiag_family = AF_INET;
        struReq.body.id.tcpdiag_sport = htons(23
    
    
    
    
    
    );
        /*
    
    
    
    
    
    
         * 下面三个数据你的机器可能不一致
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        struReq.body.id.tcpdiag_dport = htons(3311
    
    
    
    
    
    );
        inet_pton(AF_INET, "192.168.0.1"
    
    
    
    
    
    , struReq.body.id.tcpdiag_src);
        inet_pton(AF_INET, "192.168.0.81"
    
    
    
    
    
    , struReq.body.id.tcpdiag_dst);
        struReq.body.id.tcpdiag_cookie[0
    
    
    
    
    
    ] = TCPDIAG_NOCOOKIE;
        struReq.body.id.tcpdiag_cookie[1
    
    
    
    
    
    ] = TCPDIAG_NOCOOKIE;
    
        /*
    
    
    
    
    
    
         * 发送报文到内核
    
    
    
    
    
    
         
    
    
    
    
    
    */
    
    
    
    
    
    
        memset(&struAddr, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAddr));
        struAddr.nl_family = AF_NETLINK;
        struAddr.nl_pid = 0
    
    
    
    
    
    ;
        struAddr.nl_groups = 0
    
    
    
    
    
    ;
        if
    
    
    
    
    
    (sendto(nSocket, &struReq, struReq.head.nlmsg_len, 0
    
    
    
    
    
    ,
            (struct
    
    
    
    
    
     sockaddr *)&struAddr, sizeof
    
    
    
    
    
    (struAddr)) < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "设置 IPQM_MODE 错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        memset(szBuffer, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (szBuffer));
        fprintf(stderr
    
    
    
    
    
    , "Press CTRL+C to quit
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
        while
    
    
    
    
    
    (gnContinue)
        {
            nLen = recv(nSocket, szBuffer, sizeof
    
    
    
    
    
    (szBuffer), 0
    
    
    
    
    
    );
            if
    
    
    
    
    
    (nLen < 0
    
    
    
    
    
    )
                break
    
    
    
    
    
    ;
            pstruNL =(struct
    
    
    
    
    
     nlmsghdr *)szBuffer;
    
            /*
    
    
    
    
    
    
             * 判断是否继续有数据
    
    
    
    
    
    
             
    
    
    
    
    
    */
    
    
    
    
    
    
            while
    
    
    
    
    
    (NLMSG_OK(pstruNL, nLen))
            {
                /*
    
    
    
    
    
    
                 * 数据已经获取完成
    
    
    
    
    
    
                 
    
    
    
    
    
    */
    
    
    
    
    
    
                if
    
    
    
    
    
    (pstruNL -> nlmsg_type == NLMSG_DONE)
                    break
    
    
    
    
    
    ;
                if
    
    
    
    
    
    (pstruNL -> nlmsg_type == NLMSG_ERROR)
                {
                    /*
    
    
    
    
    
    
                     * 发生一个错误
    
    
    
    
    
    
                     
    
    
    
    
    
    */
    
    
    
    
    
    
                    struct
    
    
    
    
    
     nlmsgerr *pstruError;
    
                    pstruError = (struct
    
    
    
    
    
     nlmsgerr *)NLMSG_DATA(pstruNL);
                    fprintf(stderr
    
    
    
    
    
    , "发生错误[
    
    
    
    
    
    %s
    
    
    
    
    
    ][
    
    
    
    
    
    %d
    
    
    
    
    
    ]
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                        strerror(-pstruError -> error),
                        -pstruError -> error);
                    break
    
    
    
    
    
    ;
                }
    
                /*
    
    
    
    
    
    
                 * 下面通过宏获取数据
    
    
    
    
    
    
                 
    
    
    
    
    
    */
    
    
    
    
    
    
                pstruPacketMsg = NLMSG_DATA(pstruNL);
                fprintf(stderr
    
    
    
    
    
    , "获取到一个报文
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
                fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    FAMILY: 
    
    
    
    
    
    %s
    
    
    
    
    
    "
    
    
    
    
    
    ,
                    pstruPacketMsg -> tcpdiag_family == AF_INET ?
                        "AF_INET"
    
    
    
    
    
     : "AF_INET6"
    
    
    
    
    
    );
                fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    STATE: "
    
    
    
    
    
    );
                switch
    
    
    
    
    
    (pstruPacketMsg -> tcpdiag_state)
                {
                    case
    
    
    
    
    
     TCP_ESTABLISHED:
                        fprintf(stderr
    
    
    
    
    
    , "ESTABLISHED"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     TCP_SYN_SENT:
                        fprintf(stderr
    
    
    
    
    
    , "SYN_SENT"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     TCP_SYN_RECV:
                        fprintf(stderr
    
    
    
    
    
    , "SYN_RECV"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     TCP_FIN_WAIT1:
                        fprintf(stderr
    
    
    
    
    
    , "FIN_WAIT1"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     TCP_FIN_WAIT2:
                        fprintf(stderr
    
    
    
    
    
    , "FIN_WAIT2"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     TCP_TIME_WAIT:
                        fprintf(stderr
    
    
    
    
    
    , "TIME_WAIT"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     TCP_CLOSE:
                        fprintf(stderr
    
    
    
    
    
    , "CLOSE"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     TCP_CLOSE_WAIT:
                        fprintf(stderr
    
    
    
    
    
    , "CLOSE_WAIT"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     TCP_LAST_ACK:
                        fprintf(stderr
    
    
    
    
    
    , "LAST_ACK"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     TCP_LISTEN:
                        fprintf(stderr
    
    
    
    
    
    , "LISTEN"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    case
    
    
    
    
    
     TCP_CLOSING:
                        fprintf(stderr
    
    
    
    
    
    , "CLOSING"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                    default
    
    
    
    
    
    :
                        fprintf(stderr
    
    
    
    
    
    , "UNKNOW"
    
    
    
    
    
    );
                        break
    
    
    
    
    
    ;
                }
                if_indextoname(pstruPacketMsg -> id.tcpdiag_if, szTemp);
                fprintf(stderr
    
    
    
    
    
    , " INTERFACE:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                    if_indextoname(pstruPacketMsg -> id.tcpdiag_if, szTemp));
                memset(szTemp, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (szTemp));
                inet_ntop(AF_INET, pstruPacketMsg -> id.tcpdiag_src,
                    szTemp, sizeof
    
    
    
    
    
    (szTemp));
                fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    FROM 
    
    
    
    
    
    %s
    
    
    
    
    
    :
    
    
    
    
    
    %d
    
    
    
    
    
     "
    
    
    
    
    
    ,
                    szTemp, ntohs(pstruPacketMsg ->id.tcpdiag_sport));
                memset(szTemp, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (szTemp));
                inet_ntop(AF_INET, pstruPacketMsg -> id.tcpdiag_dst,
                    szTemp, sizeof
    
    
    
    
    
    (szTemp));
                fprintf(stderr
    
    
    
    
    
    , "TO 
    
    
    
    
    
    %s
    
    
    
    
    
    :
    
    
    
    
    
    %d
    
    
    
    
    
     "
    
    
    
    
    
    ,
                    szTemp, ntohs(pstruPacketMsg ->id.tcpdiag_dport));
                fprintf(stderr
    
    
    
    
    
    , "RQ: 
    
    
    
    
    
    %lu
    
    
    
    
    
     SQ: 
    
    
    
    
    
    %lu
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                    pstruPacketMsg -> tcpdiag_rqueue,
                    pstruPacketMsg -> tcpdiag_wqueue);
    
                /*
    
    
    
    
    
    
                 * 继续下一个数据
    
    
    
    
    
    
                 
    
    
    
    
    
    */
    
    
    
    
    
    
                pstruNL = NLMSG_NEXT(pstruNL, nLen);
            }
        }
        return
    
    
    
    
    
     0
    
    
    
    
    
    ;
    }
    

    NETLINK_NFLOG和FIREWALL协 议其实非常类似,不过NFLOG只负责接收从内核发送过来的报文,对这些报文进行记录操作,不进行任何其它的操作。从内核过来的报文格式为 nlmsghdr+ulog_packet_msg结构。其中ulog_packet_msg的定义在<linux/netfilter_ipv4 /ipt_ULOG.h>文件

    31
    
    
    
    
    
       /*
    
    
    
    
    
     Format of the ULOG packets passed through netlink 
    
    
    
    
    
    */
    
    
    
    
    
    
    32
    
    
    
    
    
       typedef
    
    
    
    
    
     struct
    
    
    
    
    
     ulog_packet_msg {
    33
    
    
    
    
    
               unsigned
    
    
    
    
    
     long
    
    
    
    
    
     mark;
    34
    
    
    
    
    
               long
    
    
    
    
    
     timestamp_sec;
    35
    
    
    
    
    
               long
    
    
    
    
    
     timestamp_usec;
    36
    
    
    
    
    
               unsigned
    
    
    
    
    
     int
    
    
    
    
    
     hook;
    37
    
    
    
    
    
               char
    
    
    
    
    
     indev_name[IFNAMSIZ];
    38
    
    
    
    
    
               char
    
    
    
    
    
     outdev_name[IFNAMSIZ];
    39
    
    
    
    
    
               size_t
    
    
    
    
    
     data_len;
    40
    
    
    
    
    
               char
    
    
    
    
    
     prefix[ULOG_PREFIX_LEN];
    41
    
    
    
    
    
               unsigned
    
    
    
    
    
     char
    
    
    
    
    
     mac_len;
    42
    
    
    
    
    
               unsigned
    
    
    
    
    
     char
    
    
    
    
    
     mac[ULOG_MAC_LEN];
    43
    
    
    
    
    
               unsigned
    
    
    
    
    
     char
    
    
    
    
    
     payload[0
    
    
    
    
    
    ];
    44
    
    
    
    
    
      } ulog_packet_msg_t;
    

    大部分字段同我们前面介绍的FIREFOX协议中的字段含义相同,其中prefix是我们在使用iptables设定记录规则时候指定的--ulog-prefix参数。payload的数据指向一个ip包的起始地址。下面是一个实际的例子

    #include 
    
    
    
    
    
    <unistd.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <stdlib.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <stdio.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <string.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <errno.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <time.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <asm/types.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <sys/types.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <sys/socket.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netlink.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netfilter.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <netinet/ether.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netfilter_ipv4.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <net/if.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <linux/netfilter_ipv4/ipt_ULOG.h>
    
    
    
    
    
    
    #include 
    
    
    
    
    
    <signal.h>
    
    
    
    
    
    
    
    static
    
    
    
    
    
     volatile
    
    
    
    
    
     int
    
    
    
    
    
     gnContinue = 1
    
    
    
    
    
    ;
    static
    
    
    
    
    
     void
    
    
    
    
    
     in_catch_sig(int
    
    
    
    
    
     nSig)
    {
        gnContinue = 0
    
    
    
    
    
    ;
    }
    
    int
    
    
    
    
    
     main(int
    
    
    
    
    
     argc, char
    
    
    
    
    
     *argv[])
    {
       
        int
    
    
    
    
    
     nSocket, nLen;
       
        struct
    
    
    
    
    
     sockaddr_nl struAddr;
       
        struct
    
    
    
    
    
     nlmsghdr *pstruNL;
       
        struct
    
    
    
    
    
     ulog_packet_msg *pstruPacketMsg;
       
        char
    
    
    
    
    
     szBuffer[4096
    
    
    
    
    
    ];
       
        struct
    
    
    
    
    
     tm struTmNow;
       
        struct
    
    
    
    
    
     sigaction struAct;
       
        int
    
    
    
    
    
     i;
    
       
    
        /*
    
    
    
    
    
    
         * 创建SOCKET
    
    
    
    
    
    
             
    
    
    
    
    
    */
    
    
    
    
    
    
        nSocket = socket(AF_NETLINK, SOCK_RAW, NETLINK_NFLOG);
       
        if
    
    
    
    
    
     (nSocket < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "创建SOCKET错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
           
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
       
    
        /*
    
    
    
    
    
    
         * 监听本地地址
    
    
    
    
    
    
             
    
    
    
    
    
    */
    
    
    
    
    
    
        memset(&struAddr, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAddr));
        struAddr.nl_family = AF_NETLINK;
        struAddr.nl_pid = getpid();
        struAddr.nl_groups = 1
    
    
    
    
    
     << (5
    
    
    
    
    
     - 1
    
    
    
    
    
    ); /*
    
    
    
    
    
     这个地方是我们指定的组号   
    
    
    
    
    
    */
    
    
    
    
    
    
       
        if
    
    
    
    
    
    (bind(nSocket, (struct
    
    
    
    
    
     sockaddr *)&struAddr, sizeof
    
    
    
    
    
    (struAddr)) < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "绑定SOCKET错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
           
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        memset(&struAct, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (struAct));
        struAct.sa_handler = in_catch_sig;
        sigfillset(&struAct.sa_mask);
       
        if
    
    
    
    
    
    (sigaction(SIGINT
    
    
    
    
    
    , &struAct, NULL
    
    
    
    
    
    ) < 0
    
    
    
    
    
    )
        {
            fprintf(stderr
    
    
    
    
    
    , "设置信号捕捉错误:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    , strerror(errno));
           
            return
    
    
    
    
    
     -1
    
    
    
    
    
    ;
        }
    
        memset(szBuffer, 0
    
    
    
    
    
    , sizeof
    
    
    
    
    
    (szBuffer));
        fprintf(stderr
    
    
    
    
    
    , "Press CTRL+C to quit
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
       
        while
    
    
    
    
    
    (gnContinue)
        {
            nLen = recv(nSocket, szBuffer, sizeof
    
    
    
    
    
    (szBuffer), 0
    
    
    
    
    
    );
           
            if
    
    
    
    
    
    (nLen < 0
    
    
    
    
    
    )
               
                break
    
    
    
    
    
    ;
            pstruNL =(struct
    
    
    
    
    
     nlmsghdr *)szBuffer;
           
            /*
    
    
    
    
    
    
             * 判断是否继续有数据
    
    
    
    
    
    
                     
    
    
    
    
    
    */
    
    
    
    
    
    
           
            while
    
    
    
    
    
    (NLMSG_OK(pstruNL, nLen))
            {
               
                /*
    
    
    
    
    
    
                 * 数据已经获取完成
    
    
    
    
    
    
                             
    
    
    
    
    
    */
    
    
    
    
    
    
               
                if
    
    
    
    
    
    (pstruNL -> nlmsg_type == NLMSG_DONE)
                   
                    break
    
    
    
    
    
    ;
               
                if
    
    
    
    
    
    (pstruNL -> nlmsg_type == NLMSG_ERROR)
                {
                   
                    /*
    
    
    
    
    
    
                     * 发生一个错误
    
    
    
    
    
    
                                     
    
    
    
    
    
    */
    
    
    
    
    
    
                   
                    struct
    
    
    
    
    
     nlmsgerr *pstruError;
    
                    pstruError = (struct
    
    
    
    
    
     nlmsgerr *)NLMSG_DATA(pstruNL);
                    fprintf(stderr
    
    
    
    
    
    , "发生错误[
    
    
    
    
    
    %s
    
    
    
    
    
    ]
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                        strerror(-pstruError -> error));
                   
                    break
    
    
    
    
    
    ;
                }
    
               
    
                /*
    
    
    
    
    
    
                 * 下面通过宏获取数据
    
    
    
    
    
    
                             
    
    
    
    
    
    */
    
    
    
    
    
    
                pstruPacketMsg = NLMSG_DATA(pstruNL);
                struTmNow = *localtime(&pstruPacketMsg -> timestamp_sec);
                fprintf(stderr
    
    
    
    
    
    ,
                   
                    "
    
    
    
    
    
    /t
    
    
    
    
    
    时间[
    
    
    
    
    
    %04d
    
    
    
    
    
    -
    
    
    
    
    
    %02d
    
    
    
    
    
    -
    
    
    
    
    
    %02d
    
    
    
    
    
     
    
    
    
    
    
    %02d
    
    
    
    
    
    :
    
    
    
    
    
    %02d
    
    
    
    
    
    :
    
    
    
    
    
    %02d
    
    
    
    
    
    ]
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                    struTmNow.tm_year + 1900
    
    
    
    
    
    , struTmNow.tm_mon + 1
    
    
    
    
    
    ,
                    struTmNow.tm_mday, struTmNow.tm_hour,
                    struTmNow.tm_min, struTmNow.tm_sec);
                fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    进入:
    
    
    
    
    
    %s
    
    
    
    
    
     出去:
    
    
    
    
    
    %s
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    ,
                        pstruPacketMsg -> indev_name,
                        pstruPacketMsg -> outdev_name);
                fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /t
    
    
    
    
    
    MAC地址:"
    
    
    
    
    
    );
               
                for
    
    
    
    
    
    (i = 0
    
    
    
    
    
     ; i < pstruPacketMsg -> mac_len ; i ++)
                    fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    %02X
    
    
    
    
    
     "
    
    
    
    
    
    , pstruPacketMsg -> mac[i]);
                fprintf(stderr
    
    
    
    
    
    , "
    
    
    
    
    
    /n
    
    
    
    
    
    "
    
    
    
    
    
    );
    
               
    
                /*
    
    
    
    
    
    
                 * 继续下一个数据
    
    
    
    
    
    
                             
    
    
    
    
    
    */
    
    
    
    
    
    
                pstruNL = NLMSG_NEXT(pstruNL, nLen);
            }
        }
       
        return
    
    
    
    
    
     0
    
    
    
    
    
    ;
    }
    

    如果想上面的程序能够执行,我们必须以root身份执行下面几个命令(假设已经将上面的代码编译为了ulog程序)

    TODO:还没有找到资料

    TODO:还没有找到资料

    TODO:还没有找到资料

    TODO:还没有找到资料

    TODO:还没有找到资料

在2.6内核中,通过 netlink实现单播通讯(文件监控实例) 在2.6内核中, netlink相关的接口函数随着版本的变化很大,现在网上流传的多数代码是以较老的版本(2.6.24以下)作为依托。这里,我将一段基于2.6.18的简单的代码移植到了2.6.27中,希望可以帮助大家理解其中的变化。 阅读详情

相关推荐

Linux内核通信的Netlink机制与编程

Netlink机制提供了一种可靠的、高效的通信方式,用于实现内核与用户空间进程之间的数据交换。Netlink机制是Linux内核中用于进程间通信的一种机制,它提供了一种可靠的、高效的通信方式,用于内核与用户空间进程之间的数据交换。在本文中,我们将详细介绍Netlink机制的原理和编程方法,并给出相应的源代码示例。通过使用Netlink机制,我们可以实现内核与用户空间进程之间的高效通信。下面是一个简单的Netlink编程示例,演示了如何使用Netlink发送消息并接收回复。一、Netlink机制的原理。

SVIPCODE的博客 677

NETLINK

NETLINK(7)Linux程序员手册NETLINK(7) 名称 netlink-内核和用户空间之间的通信(AF_NETLINK) 概要 #include <asm / types.h> #include <sys / socket.h> #include <linux / netlink.h> netlink_socket = socket(AF_NETLINK, socket_type, netlink_family); 描述 Netlink用于在内核进程和

qq_42138566的博客 1269

Linux网络配置的演进:从ifconfig的ioctl到iproute2的Netlink

本文分析了Linux内核中RTNETLINK机制的实现。RTNETLINK是Linux网络配置的核心,通过netlink套接字实现用户空间与内核的通信。文章从数据结构、锁机制、消息处理流程等角度详细剖析了rtnetlink.c文件: 关键数据结构包括rtnl_link、rtnl_link_ops和rtnl_af_ops,分别用于注册消息处理器、定义链接类型操作和地址族特定操作。 采用模块化设计,通过rtnl_register注册不同类型的消息处理器,支持灵活扩展。 消息处理流程分为单个请求处理和批量转储请求

数字人生 568

linux添加libnet,Linux libnetlink 编程

netlink,rtnetlink,libnetlink 三者之间的关系是:netlink 是Linux内核和用户空间程序消息通信的一种方法。rtnetlink 是 netlink 的一个子集,用于访问内核中的路由表,网口,IP地址等信息。libnetlink 是为了方便使用rtnetlink服务而设计的API。image.png为了安装libnetlink.h,执行下面命令:$ dnf inst...

weixin_35486751的博客 653

libnl的通信机制详细解释

详细解释了libnetlink的通信机制,数据结构,从netlink的起源开始,一直到libnl,目前市面上没有相关的书籍。

libnetlink-examples:libnetlink用法示例,可将网络操作嵌入您自己的CC ++应用程序中

libnetlink示例 此仓库包含3个示例示例实用程序,这些实用程序使用libnetlink进行与iproute2'ip'命令相同的操作。 在将网络操作嵌入到自己的应用程序中时,通常需要执行此操作(例如,您的C应用程序需要创建macvlan),并且不想对ip命令使用ugly system()调用。 更不用说在多线程应用程序上调用system()正在寻找麻烦:) 您将需要安装rpm软件包iproute-devel或与您的发行版等效的软件包。 这是libnetlink.a附带的软件包,libnetlink.a是编译此仓库所需的库。 要编译,只需键入make 该仓库提供了3个示例应用程序: 阿德弗兰 用法:addvlan <设备> <名称> 这与ip link add link <device> <name> type macvlan rmif 用法:rmif <设备> 这与ip l

在2.6.24及以后版本的Linux内核中使用netlink

如何在2.6.24及以后版本的Linux内核中使用netlink<br />最近做Netlink 2.6.24 移植,网上相关的教程也不少,有些写得还十分系统,不过我拿来一测试,居然没一个能编译。后来仔细一看才发现,还是内核版本的问题。经过一番折腾,终于弄好了,下面简要介绍一下经验。 <br />我用的redhat 5 x64 自己升级的内核,内核更新至2.6.24,而从2.6.24开始,linux内部对netlink的实现机制和调用接口进行了很大的调整,特别是函数netlink_kernel_create

似水流年 -- 韩欣的博客 2650

晶圆测试(wafer sort)全流程解析:从探针卡到良率统计的实战指南

本文详细解析了晶圆测试(wafer sort)的全流程,从探针卡选型到良率统计的实战指南。涵盖了12英寸先进制程产线的关键技术,包括探针卡系统、测试程序开发、产线自动化集成及数据分析,特别聚焦多站点并行测试的时序优化和接触阻抗异常排查,帮助工程师提升测试效率与准确性。

weixin_29279153的博客 731

af_netlink_2、netlink简介

Netlink 是一种特殊的 socket,它是 Linux 所特有的,类似于 BSD 中的AF_ROUTE 但又远比它的功能强大,目前在最新的 Linux 内核(2.6.14)中使用netlink 进行应用与内核通信的应用很多,包括:路由 daemon(NETLINK_ROUTE),1-wire 子系统(NETLINK_W1),用户态 socket 协议(NETLINK_USERSOCK),防火...

weixin_39832448的博客 1950

Qt 6.5实战:用QMediaPlayer搞定RTSP监控流播放(附LAV Filters解码器避坑指南)

本文详细介绍了如何在Qt 6.5中使用QMediaPlayer实现低延迟RTSP监控流播放,并提供了LAV Filters解码器的配置避坑指南。通过优化缓冲策略和硬件加速设置,显著提升视频流的播放性能和稳定性,适用于工业视觉检测和安防监控等实时场景。

weixin_33712987的博客 401

告别误唤醒!S32K3xx低功耗设计避坑指南:Fast Standby模式与WISR寄存器操作详解

本文深入解析了NXP S32K3xx系列MCU在低功耗设计中常见的误唤醒问题,并提供了基于Fast Standby模式的解决方案。文章重点剖析了DCMRWF5寄存器的配置方法、WISR/WISR_64唤醒中断状态寄存器的标志位处理策略,以及如何利用32KB Standby SRAM保存唤醒状态,从而帮助开发者构建稳定可靠的汽车电子低功耗系统。

weixin_29163857的博客 364

2.6.24以上内核中netlink使用方法

2.6.24以上内核中netlink使用方法 测试环境:2.6.28 Netlink在2.6内核的不同版本中发生了很大变化,具体请参考(注意其中的版本号不一定确切): http://blog.youkuaiyun.com/sealyao/archive/2009/10/02/4628141.aspx   0. 综述 以下程序基本流程如下: 运行netlink内核模块; 运行用户态程序,向内核发

求索 676

Arm CCA架构:硬件级机密计算与安全隔离技术解析

机密计算(Confidential Computing)通过硬件级隔离技术构建可信执行环境(TEE),是当前云安全和数据隐私保护的核心方案。Armv9-A引入的CCA架构采用物理地址空间隔离和Granule保护表(GPT)机制,实现4KB颗粒度的内存访问控制。该技术通过标准化的RMI/RSI接口规范,为虚拟化环境和安全敏感应用提供硬件级保护,特别适用于金融交易、医疗数据处理等需要严格隔离的场景。相比传统TEE方案,Arm CCA在隔离等级和动态权限管理方面具有显著优势,其Realm World设计为机密计算

weixin_30905133的博客 566

netlink简单介绍 (linux-3.14.2)

看了几遍关于netlink的文章: http://www.linuxjournal.com/article/7356

ccskyer的专栏 5781

三相电机控制中的端电压、相电压与线电压波形解析

本文深入解析了三相电机控制中端电压、相电压与线电压的核心概念与波形差异。通过对比方波控制、SPWM和SVPWM三种主流控制策略下的实测波形特征,揭示了不同控制逻辑对电压波形(如梯形波、正弦波、马鞍波)的影响。文章重点阐述了SVPWM控制如何通过生成马鞍波形端电压来提高直流母线电压利用率,并提供了实用的波形测量与调试指南,帮助工程师深入理解电机控制原理并进行有效调试。

qsc901234567的博客 1400

用OpenNI2获取奥比中光Astra Pro及 Astra Pro SM输出的深度图(win,linux arm64 x64平台)

搞了一个奥比中光Astra Pro,想在windows平台,和linux rk3588 上获取深度信息,之前的驱动下载已经不好用了。

babytiger的专栏 1305

Netlink系列2Netlink socket地址结构

Netlink socket用到的结构体如下: Struct  sockaddr_nl  {   sa_family_t              nl_family;   //AF_NETLINK 或PF_NETLINK   unsigned short

cjchina的专栏 1217

单周期CPU设计【Verilog】

第一章 单周期CPU的设计原理 为实现单周期CPU,本文首先研究了单周期CPU的相关理论和工作原理。本章首先简要介绍单周期CPU的基本概念,然后对CPU的工作原理进行简要分析,以便为单周期CPU的设计和开发提供理论基础。 1.1 单周期CPU概述 中央处理器,即CPU,作为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元。在CPU内部,电平从低到高变化的瞬间称为时钟上升沿,两个相邻时钟上升沿之间的时间间隔称为一个时钟周期。单周期CPU指的是一条指令的执行在一个时钟周期内完成,然后开始下一

醉酒、冰城外 2万+

Netlink 内核实现分析 2

netlink 应用层如何创建socket 应用层通过socket()系统调用创建Netlink套接字,socket系统调用的第一个参数可以是AF_NETLINK或PF_NETLINK(在Linux系统中它俩实际为同一种宏),第二个参数可以是SOCK_RAW或SOCK_DGRAM(原始套接字或无连接的数据报套接字), 最后一个参为netlink.h中定义的协议类型,用户可以按需求自行创建...

weixin_30788619的博客 198

接入 AI 之后,为什么测试和排障还是没有真正变快?

如果你们准备做平台型 AI,不要先从聊天入口开始想。先把真实数据采上来;再把链路、版本、快照、报告这些核心对象建稳;再把历史沉淀、反馈、检索能力补齐;最后再让 AI 围绕这些对象去工作。这样做出来的 AI,才更容易从“看起来聪明”走向“真正省时间”。

专注 AI 精准测试平台实战落地,分享从代码 Diff 到回归决策的完整工程闭环。主张“先建数据链路,再上 AI 智能”,让测试从“靠经验”走向“基于风险”。 527

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

2、netlink简介

Netlink 是一种特殊的 socket,它是 Linux 所特有的,类似于 BSD 中的AF_ROUTE 但又远比它的功能强大,目前在最新的 Linux 内核(2.6.14)中使用netlink 进行应用与内核通信的应用很多,包括:路由 daemon(NETLINK_ROUTE),1-wire 子系统(NETLINK_W1),用户态 socket 协议(NETLINK_USERSOCK),防火...

weixin_30460489的博客 438

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

通用netlink的基本使用(2) NETLINK_GENERIC

根据family name 动态获得family id 内核代码 #include &lt;net/genetlink.h&gt; #include &lt;linux/module.h&gt; #include &lt;linux/kernel.h&gt; #include &lt;linux/init.h&gt; //接收消息后的回调函数 int test_ctl_function(s...

yldfree的博客 2578
上一篇: netlink 编程
下一篇: LINUX内核调试相关--oops信息的定位1
pulpdog
博客等级 码龄18年 1粉丝 1原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值