博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux下使用netfilter进行IP包解析
阅读量:4139 次
发布时间:2019-05-25

本文共 2938 字,大约阅读时间需要 9 分钟。

一.netfilter

最近因为工作的原因,要用到netfilter进行IP包的解析和过滤,所以对netfilter进行了一些了解,目前网上比较容易搜索到的应该是这两篇文章http://alexanderlaw.blog.hexun.com/8960896_d.html,《Linux netfilter 源码解析》,

https://www.ibm.com/developerworks/cn/linux/l-ntflt/,《Linux Netfilter实现机制和扩展技术》

这两篇文章对于Linux netfilter进行了一个详细的介绍,第一篇还对其源码进行了剖析,至于其具体实现,网上也能够找到一些例子,但是问题在于,那些例子大部分都是基于老版本的linux kernel,而在2.6以上的linux内核中,关于netfilter的变动是巨大的,整个变化主要体现在skubuff.h这个头文件中,2.6以上的linux内核抛弃了以前的那种union的方式,老版本中的nh不再存在。至于更加详细的内容变化,可以直接去Google,我就不再赘述了。

另外一个需要注意的是,很多网上的例子程序给的接口是这样的

[html] 
  1. static unsigned int sample(  
  2. unsigned int hooknum,  
  3. struct sk_buff ** skb,  
  4. const struct net_device *in,  
  5. const struct net_device *out,  
  6. int (*okfn) (struct sk_buff *))  
  7. {  
  8.  return NF_ACCEPT;  
  9. }  
而实际上使用的接口应该是

[html] 
  1. static unsigned int sample(  
  2. unsigned int hooknum,  
  3. struct sk_buff * skb,  
  4. const struct net_device *in,  
  5. const struct net_device *out,  
  6. int (*okfn) (struct sk_buff *))  
  7. {  
  8.  return NF_ACCEPT;  
  9. }  
请注意,不是sk_buff **,而是sk_buf*,这个问题我没弄清楚是别人的代码贴的有问题,还是因为内核版本不同造成的,但是请大家注意一下。

二.示例源码

[html] 
  1. #include <linux/module.h>  
  2. #include <linux/kernel.h>  
  3. #include <linux/init.h>  
  4. #include <linux/types.h>  
  5. #include <linux/netdevice.h>  
  6. #include <linux/skbuff.h>  
  7. #include <linux/netfilter_ipv4.h>  
  8. #include <linux/inet.h>  
  9. #include <linux/in.h>  
  10. #include <linux/ip.h>  
  11.   
  12. MODULE_LICENSE("GPL");  
  13. #define NIPQUAD(addr) \  
  14.   ((unsigned char *)&addr)[0], \  
  15.   ((unsigned char *)&addr)[1], \  
  16.   ((unsigned char *)&addr)[2], \  
  17.   ((unsigned char *)&addr)[3]  
  18.   
  19. static unsigned int sample(  
  20. unsigned int hooknum,  
  21. struct sk_buff * skb,  
  22. const struct net_device *in,  
  23. const struct net_device *out,  
  24. int (*okfn) (struct sk_buff *))  
  25. {  
  26.     __be32 sip,dip;  
  27.  if(skb){  
  28.    struct sk_buff *sb = NULL;  
  29.    sb = skb;  
  30.    struct iphdr *iph;  
  31.    iph  = ip_hdr(sb);  
  32.    sip = iph->saddr;  
  33.    dip = iph->daddr;  
  34.    printk("Packet for source address: %d.%d.%d.%d\n destination address: %d.%d.%d.%d\n ", NIPQUAD(sip), NIPQUAD(dip));  
  35.     }  
  36.  return NF_ACCEPT;  
  37. }  
  38.   
  39.  struct nf_hook_ops sample_ops = {  
  40.    .list =  {NULL,NULL},  
  41.    .hook = sample,  
  42.    .pf = PF_INET,  
  43.    .hooknum = NF_INET_PRE_ROUTING,  
  44.    .priority = NF_IP_PRI_FILTER+2  
  45.  };  
  46.   
  47. static int __init sample_init(void) {  
  48.   nf_register_hook(&sample_ops);  
  49.   return 0;  
  50. }  
  51.   
  52.   
  53. static void __exit sample_exit(void) {  
  54.   nf_unregister_hook(&sample_ops);  
  55. }  
  56.   
  57.  module_init(sample_init);  
  58.  module_exit(sample_exit);   
  59.  MODULE_AUTHOR("chenkangrui");  
  60.  MODULE_DESCRIPTION("sample");  

netfilter模块所linux系统的一部分,所以为netfilter添加hook,其实所linux内核编程,所以需要用到linux内核态的头文件。

根据sample_ops可以看到,我在NF_INET_PRE_ROUTING(老版本这个变量是NF_IP_PRE_ROUTING,哎,真是DT啊)这个位置添加了一个hook,处理函数是sample(sample的功能是将所有能够截获的IP包的源IP和目标IP给打印出来)。

另外就是,NIPQUAD这个宏在新版本中被取消了,需要自己手动定义下。

三.编译和加载

我是在ubuntu上进行编译的

[html] 
  1. obj-m :sample.o  
  2.     KERNELBUILD :=/lib/modules/$(shell uname -r)/build  
  3. default:  
  4.     make -C $(KERNELBUILD) M=$(shell pwd) modules  
  5. clean:  
  6.     rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions  

这是我使用的Makefile,需要注意的是,因为编译内核模块需要使用内核中的头文件,所以需要

sudo make

编译完成之后,将.ko文件加载到内核中就可以了

sudo insmod ./sample.ko

内核模块的输出printk不是直接打印到系统终端的,而是在系统日志中

你可以使用

dmesg

或者直接去/var/log/目录下查看syslog文件

转载地址:http://vnhvi.baihongyu.com/

你可能感兴趣的文章
为什么TCP服务端需要调用bind函数而客户端通常不需要呢?
查看>>
什么是socket的name? 怎样给socket取一个name? --- 以生宝宝并取名的过程再谈socket、name、bind和socket name
查看>>
如何偷窥到socket对应的内核缓冲区中有什么数据? 有多少数据?---利用recv的MSG_PEEK和ioctlsocket的FIONREAD
查看>>
《Windows Sockets 网络编程》. Bob Quinn & Dave Shuttle (非常实用的Windows编程书籍)
查看>>
为什么有时ping不通www.baidu.com但可以访问www.baidu.com网页?
查看>>
从telnet www.baidu.com 80 聊聊我经历过的tcp“三次握手”失败---顺便验证telnet是基于tcp协议的
查看>>
C++智能指针auto_ptr源码完全解析---以微软auto_ptr为例来探讨auto_ptr的用法
查看>>
我修改的问题单居然回归不通过?---趣闻二则
查看>>
模拟linux的shell---顺便复习一下fork,execlp和waitpid函数
查看>>
如何获取linux shell中ls进程的进程号?---有趣的问题!
查看>>
利用thread来简要模拟signal函数功能
查看>>
linux shell “永久环境变量”、“临时环境变量”和“普通变量“之完全解读
查看>>
配置文件的重要性------轻化操作
查看>>
cp后文件时间会变, mv后文件时间不会变化------定位一个低概率core问题时, 差点误导了自己
查看>>
又是缓存惹的祸!!!
查看>>
为什么要实现程序指令和程序数据的分离?
查看>>
我对C++ string和length方法的一个长期误解------从protobuf序列化说起(没处理好会引起数据丢失、反序列化失败哦!)
查看>>
一起来看看protobuf中容易引起bug的一个细节
查看>>
无protobuf协议情况下的反序列化------貌似无解, 其实有解!
查看>>
make -n(仅列出命令, 但不会执行)用于调试makefile
查看>>