Linux下Netfilter创建自己的Hook,让数据包可以发送到用户层,然后统计节点负载信息

Linux下Netfilter创建自己的Hook函数,让数据包可以发送到用户层,然后统计节点的负载信息

写在最前面,我的linux内核版本是4.4.0-31-generic,版本是Ubuntu 16.04.1 LTS

希望实现的功能如题目所示,该功能实际分为几个步骤

  • 在用户空间编写自己的Hook函数C文件,并将该文件编译成内核模块(后缀为.ko),然后加载到内核中,并测试Hook函数是否起作用
  • 在用户空间编写C文件,接收内核传过来的数据包,统计负载信息,然后回传给内核

一、在用户空间编写自己的Hook函数C文件,编译生成.ko模块,并动态加载到内核中

Makefile内容为:

obj-m := myhook.o
all:
    $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
    $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

linux头文件在下面这个目录中可以找到
/usr/src/linux-headers-4.4.0-31-generic(内核版本)/include/
然后如果是

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ip.h>
#include <asm/atomic.h>
#include <linux/version.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/moduleparam.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_bridge.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Wang");
MODULE_DESCRIPTION("Myhook");

static int pktcnt = 0;

//我们自己定义的hook回调函数
static unsigned int myhook_func(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
   const struct iphdr *iph = ip_hdr(skb);
   return NF_QUEUE;
} 
static struct nf_hook_ops nfho = 
{
.hook=myhook_func, //回调函数是myhook_func
.pf=PF_INET,       //协议类型
.hooknum=NF_BR_POST_ROUTING,//挂载点
.priority=NF_IP_PRI_FIRST,//优先级
};
static int __init myhook_init(void)
{
    return nf_register_hook(&nfho);
}
static void __exit myhook_fini(void)
{
    nf_unregister_hook(&nfho);
}
module_init(myhook_init);
module_exit(myhook_fini);

把makefile和myhook.c放在同一目录下,然后make即可,会生成myhook.ko文件。
动态加载内核模块命令为 sudo insmod myhook.ko
动态卸载内核模块命令为 sudo rmmod myhook.ko

在加载这个模块之后,你会发现自己机器无法上网了,这是因为所有的数据包都被排队到了用户空间中,需要在用户空间中进行处理,也就是我们的第二部分需要做的内容。

二、在用户空间编写C文件,接收内核传过来的数据包,统计负载信息,然后回传给内核

之前网络上很多教程说要用ip_queue模块,但实际上这个模块在新版本内核中已经没有了,所以很多程序的头文件
include <linux/netfilter_ipv4/ip_queue.h>
是已经不存在了的,没有办法使用。

所以在新版本内核中,需要用到三个库,下载地址为https://netfilter.org/projects/libnetfilter_queue/
1、libmnl
2、libnfnetlink
3、libnetfilter_queue
下载源代码后,先安装libmnl,然后安装libnfnetlink,再安装libnetfilter_queue,编译时configure, make ,make install (注意make install的时候需要sudo)

libnetfilter_queue的示例代码在libnetfilter_queue-1.0.3/examples/nf-queue和libnetfilter_queue-1.0.3/utils/nfqnl_test下都有

我们测试验证一下功能:
1、动态加载第一步中的内核模块;sudo insmod myhook.ko,把hook挂在post_routing上
2、终端执行ping www.baidu.com命令,命令没反应,发不出去数据包,因为数据包在post_routing处被hook送到用户空间了
3、运行sudo ./nf-queue 0,这里的0表示queue_num是0,目前我仅实现了hook挂在后把数据包传到第0个queue_num上,按道理应该是可以更改queue_num的,需要进一步研究。
4、此时终端会显示nf-queue收到了数据包,并且可以看到payload len,然后将数据包回传给内核,内核可以继续发送
5、关闭nf-queue,此时ping命令无法继续发送数据包

利用payload len我们就可以统计负载信息了

三、用iptables可以不用自己编hook函数挂载,但是挂载点似乎只能在input、output和forward,没有办法挂载在post_routing上

猜你喜欢

转载自blog.csdn.net/prowc/article/details/81352387