Netfilter-iptabes报文过滤框架(一)

什么是Netfilter/iptable

Netfilter/iptables是Linux内核内置的报文过滤框架,程序能够经过该框架完成报文过滤、地址转换(NAT)以及链接跟踪等功能。html

Netfilter/iptables由两部分组成,一部分是Netfilter的"钩子(hook)",这些"钩子"由Linux内核协议栈提供,内核模块能够经过注册"钩子"来完成各类各样的功能。 另外一部分是iptables的规则,这些规则规定了"钩子"如何工做。linux

下图很直观的说明了用户空间的iptables和内核空间的ip_tables模块、Netfilter之间的关系。数组

Netfilter

Netfilter是嵌入Linux内核协议栈的,设置在报文处理路径上的一系列调用入口。 Netfilter一共有5个"钩子"设置在IP协议栈的报文处理路径上,这5个"钩子"就是内嵌在内核协议栈的检查点。 咱们能够把处理函数注册到各个检查点,当报文通过各个检查点时,就能够经过"钩子"函数对报文进行处理完成相应功能。框架

下图说明了5个"钩子"在内核协议栈的位置。 函数

"钩子"的存储及管理机制

在内核中,"钩子"函数由一个全局二维数组nf_hooks按照协议族归类存储,在每一个协议族中,根据钩子点顺序排列,在钩子点内则根据钩子函数的优先级排列。 例如ipv4和ipv6就是两个协议族,每一个协议族都包含5个"钩子",每一个"钩子"下面保存了注册在这个"钩子"上的函数地址。 学习

  • 这个二维数组的每一项表明了一个钩子被调用的点,NF_PROTO表明协议栈,NF_HOOK表明协议栈中某个路径点。
  • 全部模块均可以经过nf_register_hook()函数将一个钩子函数挂入想要被调用点的链表中(经过Protocol和hook指定一个点)。 这样,该钩子函数就可以处理从指定Protocol和指定hook点流过的数据包。
  • Netfilter在不一样协议栈的不一样点上放置钩子函数,当数据包通过某个协议栈(NF_PROTO)的某个点(NF_HOOK)时,该协议栈会经过NF_HOOK()函数调用对应钩子链表(nf_hooks[NF_PROTO][NF_HOOK])中注册的每个钩子项来处理该数据包。

Netfilter定义了每一个钩子函数的返回值,每一个钩子函数只能返回下面的返回值,而不能自定义返回值。.net

  • NF_DROP(0):数据包被丢弃,即不被下一个钩子函数处理,同时也再也不被协议栈处理,并释放数据包。
  • NF_ACCEPT(1):数据包被接受,即交给下一个钩子或协议栈继续处理。
  • NF_STOLEN(2):数据包被中止处理,即不被下一个钩子函数处理,同时也再也不被协议栈处理,但不释放数据包。
  • NF_QUEUE(3):将数据包交给nf_queue子系统处理,即不被下一个钩子函数处理,同时也再也不被协议栈处理,也不释放数据包。
  • NF_REPEAT(4):数据包将被该返回值的钩子函数再次处理一遍。
  • NF_STOP(5): 数据包中止被该HOOK点的后续钩子函数处理,交给协议栈继续处理。

"钩子"的使用方法

"钩子"的使用首先实例化一个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

  • hook是钩子函数
  • hooknum是钩子点
  • pf是协议栈
  • priority是钩子函数的优先级

而后在模块加载和退出函数中注册和移除钩子函数: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了。

参考资料:

相关文章
相关标签/搜索