netfilter
11.1.1 netfilter的结构框架(1)
1.Linux防火墙发展历程
最开始的ipfwadm是AlanCox在Linux Kernel发展的初期,从FreeBSD的内核代码中移植过来的。后来经历了ipchains,再经由Paul Russel在Linux Kernel 2.3系列的开发过程中发展了netfilter这个架构。而用户空间的防火墙管理工具,也相应的发展为iptables。在经历了Linux Kernel 2.4和2.6的发展以后,的确可以说,netfilter iptables经受住了大量用户广泛使用的考验。本文将基于Linux 2.6的内核来进行叙述。
2.什么是netfilter
netfilter是Linux 2.6内核实现的防火墙框架,它比以前任何一版Linux内核的防火墙子系统都要完善强大。netfilter提供了一个抽象、通用化的框架,该框架定义了一个子功能,实现的就是包过滤子系统。netfilter由一系列基于协议栈的钩子组成,这些钩子都对应某一具体的协议。
3.netfilter在IPv4中的结构
Linux 2.6支持对IPv4、IPv6及DECnet的钩子(本小节只提及IPv4的钩子)。IPv4协议栈为了实现对netfilter架构的支持,在IP包在IPv4协议栈上的游历路线(如图11.1所示)之中选择了5个检查点,可以在linux/netfilter_ipv4.h里面找到这些符号的定义,表11.1列出了IPv4中定义的钩子。
表11.1 IPv4中定义的钩子
钩子名称 |
调用时机 |
NF_IP_PRE_ROUTING |
完整性校验之后,路由决策之前 |
NF_IP_LOCAL_IN |
目的地为本机,路由决策之后 |
NF_IP_FORWARD |
数据包要到达另外一个接口 |
NF_IP_LOCAL_OUT |
本地进程的数据,发送出去的过程中 |
NF_IP_POST_ROUTING |
向外流出的数据上线之前 |
在这5个检查点上,各引入了一行对NF_HOOK()宏函数的相应调用。如果没配置防火墙,NF_HOOK()便从netfilter模块转回到IPv4协议栈继续往下处理。如果配置了防火墙,NF_HOOK()就转去调用nf_hook_slow()函数,该函数会按顺序调用在该检查点注册的钩子函数,不管钩子函数对数据包做了哪些处理,它都必须返回表11.2中的一个预定义的值。NF_IP_PRE_ROUTING钩子是数据包接收后第一个调用的钩子程序,这个钩子在后面编写的模块当中将会被用到。
表11.2 netfilter的返回值
返回值 |
含义 |
NF_DROP |
丢弃这个数据包 |
NF_ACCEPT |
保留这个数据包 |
NF_STOLEN |
忘掉这个数据包 |
NF_QUEUE |
让这个数据包在用户空间排队 |
NF_REPEAT |
再次调用这个钩子函数 |
NF_DROP表示要丢弃这个数据包,并且为这个数据包申请的所有资源都要得到释放。NF_ACCEPT告诉netfilter到目前为止,这个数据包仍然可以被接收,应该将它移到网络堆栈的下一层。NF_STOLEN是非常有趣的一个返回值,它告诉netfilter让其忘掉这个数据包,也就是说钩子函数会在这里对这个数据包进行完全处理,而netfilter应该放弃对它的任何处理。然而这并不意味着为该数据包申请的所有资源都要释放掉。这个数据包和它各自的sk_buff结构体依然有效,只是钩子函数从netfilter夺取了对这个数据包的掌控权。最后一个返回值NF_REPEAT,就是当用户改变了该数据包包头的某些信息时,那可以请求netfilter再次调用这个钩子函数对它进行操作。
4.注册和注销netfilter钩子函数
在上面提到了nf_hook_slow()函数会按顺序调用在该检查点注册的钩子函数,那钩子函数是怎样注册的呢?注册一个钩子函数是一个围绕nf_ hook_ ops结构体的简单过程,在linux/netfilter.h中有这个结构体的定义:
- struct nf_hook_ops
- {
- struct list_head list;
- nf_hookfn *hook;
- int pf;
- int hooknum;
- int priority;
- };