Netfilter/iptables是Linux内核内置的报文过滤框架,程序能够经过该框架完成报文过滤、地址转换(NAT)以及链接跟踪等功能。html
Netfilter/iptables由两部分组成,一部分是Netfilter的"钩子(hook)",这些"钩子"由Linux内核协议栈提供,内核模块能够经过注册"钩子"来完成各类各样的功能。 另外一部分是iptables的规则,这些规则规定了"钩子"如何工做。linux
下图很直观的说明了用户空间的iptables和内核空间的ip_tables模块、Netfilter之间的关系。数组
Netfilter是嵌入Linux内核协议栈的,设置在报文处理路径上的一系列调用入口。 Netfilter一共有5个"钩子"设置在IP协议栈的报文处理路径上,这5个"钩子"就是内嵌在内核协议栈的检查点。 咱们能够把处理函数注册到各个检查点,当报文通过各个检查点时,就能够经过"钩子"函数对报文进行处理完成相应功能。框架
下图说明了5个"钩子"在内核协议栈的位置。 函数
在内核中,"钩子"函数由一个全局二维数组nf_hooks按照协议族归类存储,在每一个协议族中,根据钩子点顺序排列,在钩子点内则根据钩子函数的优先级排列。 例如ipv4和ipv6就是两个协议族,每一个协议族都包含5个"钩子",每一个"钩子"下面保存了注册在这个"钩子"上的函数地址。 学习
Netfilter定义了每一个钩子函数的返回值,每一个钩子函数只能返回下面的返回值,而不能自定义返回值。.net
"钩子"的使用首先实例化一个nf_hook_ops对象,而后对其进行必要的初始化设置,最后经过nf_register_hook()函数将其注册到二维数组nf_hooks中。 咱们首先初始化nf_hook_ops中的经常使用字段:unix
<!-- lang: c --> 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; }
其中:code
而后在模块加载和退出函数中注册和移除钩子函数:htm
<!-- lang: c --> int init_module(void) { nf_register_hook(&nf_hook_test_ops); } void cleanup_module() { nf_unregister_hook(&nf_hook_test_ops); }
下面是回调函数的声明:
<!-- lang: c --> 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了。