Chinaunix

标题: netfilter与用户空间通信二法 [打印本页]

作者: GoldenSoldier    时间: 2009-06-24 19:06
标题: netfilter与用户空间通信二法
最近在看netfilter的相关文章了,发现大家都是研究的很是深入。而我只是菜鸟一个,先从netfilter与用户空间通信方法入手吧。
法一:netlink
关于内核与用户空间的通信方法,在IBM的developer work上,有两篇很不错的文章。
http://www.ibm.com/developerworks/cn/linux/l-kerns-usrs/
http://www.ibm.com/developerworks/cn/linux/l-netlink/index.html
这两篇文章都提到了netlink,我也认为netfilter+netlink就可以在内核和用户空间实现零距离接触了。

自己也调试了上面的程序,还是蛮又感觉的。
不过还是有个问题,请教大侠们!
我的想法是这样的,一一分拆IP分组,(感觉和WireShark差不多),就是不仅得到skb的ip头和tcp/udp头,还可以同时得到里面的载荷,就是数据内容。但就是得不到数据内容,我先尝试用char类型的指针,不行;给它kmalloc分配空间,不行;使用char数组,也还是不行。但我分别实现就可以:比如说,我使用 netlink传输的结构体,要么只有IP地址、端口等纯数值类型的,或者要么只有传递字符串(就是内容),就可以。不知道是为什么。
法二:使用sockopt与内核交换数据
http://blog.chinaunix.net/u/12313/showart_245767.html
这篇文章写得不错。

这个方法是我在看一个开源项目的时候,看到的,主要还是使用的copy_from_user、copy_to_user。
最后:
法一使用的是大量的数据传输,比较常规,容易理解。
法二基本使用在控制方面的,少而精。
上面只是我粗浅的解释,希望能抛砖引玉,多谈谈这方面的自己应用的体会。
作者: Godbach    时间: 2009-06-24 19:16
还可以同时得到里面的载荷,就是数据内容。但就是得不到数据内容,我先尝试用char类型的指针,

应该可以得到完整的IP报文的,那就有数据内容啊。你的程序是怎么设置的。

之间记得分析IP Queue的时候,可以设定copy报文的模式,有只拷贝元数据,就是报文的一些摘要信息,也可以完全把整个报文拷贝出来的。
作者: Godbach    时间: 2009-06-24 19:17
这两篇文章确实写的很好,对于netlink和sockopt的学习有很大帮助。
作者: GoldenSoldier    时间: 2009-06-24 20:06
标题: 回复 #2 Godbach 的帖子
>应该可以得到完整的IP报文的,那就有数据内容啊。你的程序是怎么设置的
我先设置了一个结构体:
struct packet_info
{
  __u32 srcIP;
  __u32 destIP;
  __u16 destPort;
  __u32 seq;
  __u32 ack_seq;
  __u16 doff;
  __u8 fin;
  __u8 syn;
  __u8 ack;
  char *data;
};
其中data就是载荷数据,不包括包头的。
然后在钩子函数里处理skb,赋值给packet_info结构体。
info.data = (char *)((*pskb)->data+(iph->ihl*4)+(thead->doff*4));
然后,使用netlink_unicast发送,用户区程序接受,但收到的要么没有东西,要么是乱码
作者: GoldenSoldier    时间: 2009-06-24 20:09
补充一下:
pskb是指向skb的指针的指针,iph是ip头(struct iphdr *iph = (*pskb)->nh.iph;),thead是TCP头(thead = (struct tcphdr *)((*pskb)->data+(iph->ihl*4));)
作者: Godbach    时间: 2009-06-24 20:13
struct packet_info
{
  __u32 srcIP;
  __u32 destIP;
  __u16 destPort;
  __u32 seq;
  __u32 ack_seq;
  __u16 doff;
  __u8 fin;
  __u8 syn;
  __u8 ack;
  char *data;
};
其中data就是载荷数据,不包括包头的。
然后在钩子函数里处理skb,赋值给packet_info结构体。
info.data = (char *)((*pskb)->data+(iph->ihl*4)+(thead->doff*4));
然后,使用netlink_unicast发送,用户区程序接受,但收到的要么没有东西,要么是乱码


看一下你这个结构体,我觉得再传给用户态的时候,内存的处理上有问题,整个结构体是一块内存,而data指向的是另外一块内存,这两个应该不是连续的。

建议你这样测试一下,先让data是一个足够大的静态数组,然后报文的内容拷贝进去,然后再传给用户态测试一下数据是否正确。
作者: GoldenSoldier    时间: 2009-06-24 20:22
标题: 回复 #6 Godbach 的帖子
我也觉得是内存地址的指向问题,于是:
1给它kmalloc分配空间,不行;
2使用char数组,也还是不行,空间分的比较大2048,结果直接死机了
作者: Godbach    时间: 2009-06-24 20:23
原帖由 GoldenSoldier 于 2009-6-24 20:22 发表
我也觉得是内存地址的指向问题,于是:
1给它kmalloc分配空间,不行;
2使用char数组,也还是不行,空间分的比较大2048,结果直接死机了


你就简单的抓一个ping包上来,char data[256]应该就可以了。
作者: Godbach    时间: 2009-06-24 20:24
空间分的比较大2048,结果直接死机了

char data[2048]就有问题吗,你怎么操作的,怎么会导致死机呢。是不是出现oops了?
作者: GoldenSoldier    时间: 2009-06-24 21:29
标题: 回复 #9 Godbach 的帖子
在测试。。。。
初步结果出来了。我先用了ethereal做了比对,把data[1450],做出来的结果已经和ethereal一致了。
上面提到的死机,可能是我记错了,应该是|给它kmalloc分配空间|导致的。

多谢,多谢!!

技术牛人就是不一样!
作者: Godbach    时间: 2009-06-24 22:36
原帖由 GoldenSoldier 于 2009-6-24 21:29 发表
在测试。。。。
初步结果出来了。我先用了ethereal做了比对,把data[1450],做出来的结果已经和ethereal一致了。
上面提到的死机,可能是我记错了,应该是|给它kmalloc分配空间|导致的。

多谢,多谢!!
...


呵呵,一来要搞清楚你抓的包有多大。二来要搞清楚你是使用静态内存还是动态内存。
作者: emmoblin    时间: 2009-06-24 23:07
我觉得使用netlink是更常规而且更推荐的方法。
毕竟netlink效率更高。而且编程起来也方便。
作者: GoldenSoldier    时间: 2009-06-25 08:54
标题: 回复 #12 emmoblin 的帖子
的确,在我所看到的一些项目里,一般是使用nf_sock_opt来做控制选项的,而多使用netlink传输数据的。Linux 内核提供 copy_from_user()/copy_to_user() 函数来实现内核态与用户态数据的拷贝,但这两个函数会引发阻塞,所以不能用在硬、软中断中。这时,netlink就出场了。

唉,还是怪我学艺不精啊。这两种方法,各有侧重,各有所用。
我想表达的意思,陈鑫在Linux 系统内核空间与用户空间通信的实现与分析(http://www.ibm.com/developerworks/cn/linux/l-netlink/index.html)都说清楚了。

惭愧。。。。
作者: Godbach    时间: 2009-06-25 11:56
原帖由 GoldenSoldier 于 2009-6-25 08:54 发表
的确,在我所看到的一些项目里,一般是使用nf_sock_opt来做控制选项的,而多使用netlink传输数据的。Linux 内核提供 copy_from_user()/copy_to_user() 函数来实现内核态与用户态数据的拷贝,但这两个函数会引发 ...


两种不同的通信方式,根据实际情况选择使用。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2