免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5595 | 回复: 7
打印 上一主题 下一主题

[通信方式] 关于netlink中的NETLINK_NFLOG接口使用 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2015-05-27 12:07 |只看该作者 |倒序浏览
使用的是内核提供的NETLINK_NFLOG接口来抓取特定数据包。
但发现对数据的解析有错误,
源码如下:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/socket.h>
#include <errno.h>
#include <linux/netfilter_ipv4/ipt_ULOG.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/icmp.h>

#define MAX_PAYLOAD 1024 // maximum payload size
#define MOD_ID 2
#define ERROR 0

//for print the information string

#if 1
#define DEBUG_INFO(...) \
        do \
        { \
                printf(__VA_ARGS__); \
        }while (0)
#else
#define WIFI_DEBUG_INFO(...) ((void)0)
#endif


static int netlink_group_mask(int group)
{
    return group ? 1 << (group - 1) : 0;
}


static void print_info(struct iphdr *iph)
{
        if(NULL == iph)
                return;
        DEBUG_INFO("srcaddr:%d.%d.%d.%d\tdestaddr:%d.%d.%d.%d\n",
                (iph->saddr >>24)&0xff,
                (iph->saddr >>16)&0xff,
                (iph->saddr >> &0xff,
                iph->saddr&0xff,
                (iph->daddr >>24)&0xff,
                (iph->daddr >>16)&0xff,
                (iph->daddr >> &0xff,
                iph->daddr&0xff);
}

int main(int argc, char* argv[])
{
        socklen_t len = 0;
        int count = 0;
    int state;
    struct sockaddr_nl src_addr, dest_addr;
    struct nlmsghdr *nlh = NULL;
        struct ulog_packet_msg *umsg = NULL;
    int sock_fd, res;
        struct iphdr *iph = NULL;
        struct icmphdr *icp = NULL;
        char buffer[2048] = {0};

        len = sizeof(struct sockaddr_nl);
    sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NFLOG);
    if(sock_fd == -1){
        DEBUG_INFO("error getting socket: %s", strerror(errno));
        return -1;
    }

    // To prepare binding

    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid(); // self pid
    src_addr.nl_groups = netlink_group_mask(MOD_ID); // multi cast
  
    res = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
    if(res < 0){
        DEBUG_INFO("bind failed: %s", strerror(errno));
        close(sock_fd);
        return -1;
    }

    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
    if(!nlh){
        DEBUG_INFO("malloc nlmsghdr error!\n";
        close(sock_fd);
        return -1;
    }

    memset(&dest_addr,0,sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0;
    dest_addr.nl_groups = 0;
    memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));
    DEBUG_INFO("waiting received!\n";
    // Read message from kernel
        while(1)
        {
                ++count;

                state = recvfrom(sock_fd, buffer, sizeof(buffer), 0, (struct sockaddr *)&dest_addr, &len);
                if(state < 0)
                        DEBUG_INFO("recvfrom error !\n";

                nlh = (struct nlmsghdr *)buffer;
                if(!NLMSG_OK(nlh,state))
                {
                        DEBUG_INFO("nlmsg error !\n";
                        return ERROR;
                }
                                                       
                DEBUG_INFO("recved msg type: %d\t msg len: %d\n", nlh->nlmsg_type, nlh->nlmsg_len);       
               
                umsg =(struct ulog_packet_msg *)NLMSG_DATA(nlh);
                DEBUG_INFO("mark:%ld\tindev_name: %s\toutdev_name:%s\tprefix:%s\tmac:%s\n", umsg->mark, umsg->indev_name, umsg->outdev_name, umsg->prefix, umsg->mac);
                iph = (struct iphdr *)umsg->payload;


                switch(iph->protocol)
                {
                        case IPPROTO_ICMP:
                        {                               
                                DEBUG_INFO("this is icmp protocal !\n";
                                print_info(iph);
                                DEBUG_INFO("iph->ihl:%d\n", iph->ihl);
                                icp = (void *)iph + iph->ihl*4;
//                                icp = (void *)iph + 20;
                                DEBUG_INFO("icp->type:%d\t icp->code:%d\n", icp->type, icp->code);
                                if((icp->type == 0) && (icp->code == 0))
                                        DEBUG_INFO("this is echo reply message !\n";
                                if((icp->type == && (icp->code == 0))
                                        DEBUG_INFO("this is echo request message !\n";
                                break;
                        }
                        case IPPROTO_TCP:
                        {
                                DEBUG_INFO("this is TCP protocal !\n";
                                print_info(iph);
                                break;
                        }
                        case IPPROTO_UDP:
                        {
                                DEBUG_INFO("this is UDP protocal !\n";
                                print_info(iph);
                                break;
                        }
                        default:
                                DEBUG_INFO("this is default protocal !\n";
                                print_info(iph);
                                break;
                }
                DEBUG_INFO("count = %d\n", count);
  }

  close(sock_fd);

    return 0;
}

iph->ihl的长度应该是5,而这里是4?  这是什么原因呀?

论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
2 [报告]
发表于 2015-05-27 16:45 |只看该作者
字节序问题?确切的说是bitfield序的问题?
先看看((char *)iph)[0]是不是0x45。
顺便把iph->version也打印一下。

论坛徽章:
0
3 [报告]
发表于 2015-05-27 18:30 |只看该作者
回复 2# nswcfd



嗯 嗯 是这个问题!这个该如何改是好呀?我查看了一下ntohl和ntohs是对unsigned long 和 unsigned short进行转换,这难道要我自己重写?
这怎么会出现这种情况呀,我这仅仅是内核和用户通讯呀!?
那prefix和mac的值为空一直没想明白


   

论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
4 [报告]
发表于 2015-05-27 18:54 |只看该作者
本帖最后由 nswcfd 于 2015-05-27 18:57 编辑

struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
        __u8        ihl:4,
                version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
        __u8        version:4,
                  ihl:4;
#else
#error        "Please fix <asm/byteorder.h>"
#endif
}
ntohs和htons关注的是字节序,解决不了这个问题(bit序,应该跟编译器有关)。
应该是user space定义错了__LITTLE_ENDIAN_BITFIELD或者__BIG_ENDIAN_BITFIELD。

prefix是ULOG target的参数,默认没有。(当然也许你内核里直接调用了NFLOG的接口,而没有使用-j ULOG)

mac为空,跟在什么地方使用ULOG记录有关系,如果是OUTOUT路径,则mac还没有初始化,如果是INPUT路径,则应该有mac。
你的日志上显示,indev为空,outdev非空,则很有可能是OUTPUT路径。

论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
5 [报告]
发表于 2015-05-27 19:01 |只看该作者
用以下代码测试一下编译环境的bit endian
struct iph {
        char ver:4;
        char ihl:4;
};
int main()
{
        char test = 0x45;
        struct iph *p = (void *)&test;
        if (p->ver == 4)
                printf("__BIG_ENDIAN_BITFIELD\n");
        else if (p->ver == 5)
                printf("__LITTLE_ENDIAN_BITFIELD\n");
        else
                printf("sorry i don't know\n");
}

论坛徽章:
0
6 [报告]
发表于 2015-05-27 19:34 |只看该作者
回复 5# nswcfd

我这运行的结果是BIG_ENDIAN_BITFIELD!


   

论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
7 [报告]
发表于 2015-05-27 20:03 |只看该作者
实在不行暴力一点,在#include <linux/ip.h>之前,#undef __LITTLE_ENDIAN_BITFIELD和__BIG_ENDIAN_BITFIELD,再#define __BIG_ENDIAN_BITFIELD。

或者不引用#include <linux/ip.h>,自己在.c里定义好struct iphdr,注意iph和version的顺序。

实在想不清楚为什么你的代码会选择了__LITTLE_ENDIAN_BITFIELD?被之前的#include间接定义了?

论坛徽章:
0
8 [报告]
发表于 2015-05-27 21:17 |只看该作者
回复 7# nswcfd
这思路不错,我再好好检查下我的头文件包含的关系.
正是这个bit序的原因,导致了后面解析出来的icp->type 也出错。我自己以写死的方式:icp = (void *)iph +20; 那就正常了!不过这肯定是不行的!我再找找原因
关于mac和prefix为空的原因,正如你说的和在什么地方使用了ULOG有关系。我这里使用的是仅对OUTPUT链做了ULOG 处理(iptables -A OUTPUT -j ULOG --ulog-nlgroup 2)。所以才会出现为空的情况。
多谢你的回复呀! 学习了好多 {:qq11:}


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP