继前面介绍了 netfilter hook,这里我们开始进行简单的实例讲解,主要是Netfilter hook的注册与注销:
wqlkp.c:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
MODULE_LICENSE("Dual BSD/GPL");
static struct nf_hook_ops nfho;
unsigned int hook_func(const struct nf_hook_ops *ops,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return NF_DROP;
}
static int __init hook_init(void)
{
nfho.hook = hook_func;
nfho.hooknum = NF_INET_PRE_ROUTING;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho);
return 0;
}
static void __exit hook_exit(void)
{
nf_unregister_hook(&nfho);
}
module_init(hook_init);
module_exit(hook_exit);
上面涉及到的数据结构及函数接口,请见上一篇博文。
Makefile:
ifneq ($(KERNELRELEASE),)
obj-m := wqlkp.o
else
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
endif
clean:
rm -f *.o *.ko *.mod.c .wqlkp*
加载模块后的结果就是,你访问不了网络了,要解除的话,卸载这个模块就行了。
为啥会出现上面的结果?主要看这两个
nfho.hook = hook_func;
nfho.hooknum = NF_INET_PRE_ROUTING;
ok,老规矩,知其然还要知其所以然,我们去窥探下内核源码(Linux kernel 3.14):
注册函数:int nf_register_hook(struct nf_hook_ops *reg)
int nf_register_hook(struct nf_hook_ops *reg)
{
struct nf_hook_ops *elem;
int err;
err = mutex_lock_interruptible(&nf_hook_mutex);
if (err < 0)
return err;
list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) {
if (reg->priority < elem->priority)
break;
}
list_add_rcu(®->list, elem->list.prev);
mutex_unlock(&nf_hook_mutex);
#if defined(CONFIG_JUMP_LABEL)
static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]);
#endif
return 0;
}
从上面的代码就可以看出,所有的 struct nf_hook_ops 都以指针的形式记录在一个列表中,其保存的顺序就是按照优先级的顺序。这个表是一个二维数组,用来存储不同协议过滤点的回调处理函数。通过协议族类型和hook类型定位。如下图所示:
extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
注销函数:void nf_unregister_hook(struct nf_hook_ops *reg)
void nf_unregister_hook(struct nf_hook_ops *reg)
{
mutex_lock(&nf_hook_mutex);
list_del_rcu(®->list);
mutex_unlock(&nf_hook_mutex);
#if defined(CONFIG_JUMP_LABEL)
static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]);
#endif
/**
* synchronize_net - Synchronize with packet receive processing
*
* Wait for packets currently being received to be done.
* Does not block later packets from starting.
*/
synchronize_net();
}
注销一个 Netfilter hook 其实就是把我们之前注册插入的 struct nf_hook_ops 指针对象从链表中删除,从代码可以看出,它并没有销毁这个对象。
在后面还有个 synchronize_net(); 这个函数可能会引起睡眠,其目的是等待处理完数据包接收过程。
参考资料:
《深入Linux网络核心堆栈》
Linux kernel 3.14 sourcecode
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)