标签:
Netfilter/iptables是Linux内核内置的报文过滤框架,程序可以通过该框架完成报文过滤、地址转换(NAT)以及连接跟踪等功能。
Netfilter/iptables由两部分组成,一部分是Netfilter的"钩子(hook)“,这些"钩子"由Linux内核协议栈提供,内核模块可以通过注册"钩子"来完成各种各样的功能。
另一部分是iptables的规则,这些规则规定了"钩子"如何工作。
下图很直观的说明了用户空间的iptables和内核空间的ip_tables模块、Netfilter之间的关系。
Netfilter是嵌入Linux内核协议栈的,设置在报文处理路径上的一系列调用入口。
Netfilter一共有5个"钩子"设置在IP协议栈的报文处理路径上,这5个"钩子"就是内嵌在内核协议栈的检查点。
我们可以把处理函数注册到各个检查点,当报文经过各个检查点时,就可以通过"钩子"函数对报文进行处理完成相应功能。
下图说明了5个"钩子"在内核协议栈的位置。
在内核中,“钩子"函数由一个全局二维数组nf_hooks按照协议族归类存储,在每个协议族中,根据钩子点顺序排列,在钩子点内则根据钩子函数的优先级排列。
例如ipv4和ipv6就是两个协议族,每个协议族都包含5个"钩子”,每个"钩子"下面保存了注册在这个"钩子"上的函数地址。
Netfilter定义了每个钩子函数的返回值,每个钩子函数只能返回下面的返回值,而不能自定义返回值。
“钩子"的使用首先实例化一个nf_hook_ops对象,然后对其进行必要的初始化设置,最后通过nf_register_hook()函数将其注册到二维数组nf_hooks中。
我们首先初始化nf_hook_ops中的常用字段:
static struct nf_hook_ops nf_hook_test_ops =
{
.hook = test_hook_func;
.hooknum = NF_INET_PRE_ROUTING;
.pf = PF_INET;
.owner = THIS_MODULE;
.priority = NF_IP_PRI_FIRST;
}
其中:
然后在模块加载和退出函数中注册和移除钩子函数:
int init_module(void)
{
nf_register_hook(&nf_hook_test_ops);
}
void cleanup_module()
{
nf_unregister_hook(&nf_hook_test_ops);
}
下面是回调函数的声明:
static unsigned int test_hook(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff*)
从上述过程可以看出,钩子函数的使用与iptables没有任何关系,也就是说如果某个模块需要对协议栈的报文进行处理,但不需要用户空间的参数,那么完全可以只注册钩子函数,而不需要编写iptables的模块。
即使需要用户空间的参数,也可以通过proc或者netlink等其他用户态和内核态通信方式来传递参数,这样就可以更灵活的使用Netfilter了。
标签:
原文地址:http://my.oschina.net/hoolev/blog/389196