Linux Netfilter实现机制和扩展技术
2.4.x的内核相对于2.2.x在IP协议栈部分有比较大的改动, Netfilter-iptables更是其一大特色,由于它功能强大,并且与内核完美结合,因此迅速成为Linux平台下进行网络应用扩展的主要利器,这些扩展不仅包括防火墙的实现--这只是Netfilter-iptables的基本功能--还包括各种报文处理工作(如报文加密、报文分类统计等),甚至还可以借助Netfilter-iptables机制来实现虚拟专用网(VPN)。本文将致力于深入剖析Netfilter-iptables的组织结构,并详细介绍如何对其进行扩展。Netfilter目前已在ARP、IPv4和IPv6中实现,考虑到IPv4是目前网络应用的主流,本文仅就IPv4的Netfilter实现进行分析。
要想理解Netfilter的工作原理,必须从对Linux IP报文处理流程的分析开始,Netfilter正是将自己紧密地构建在这一流程之中的。
图3 报文接收流程之协议栈阶段
如果报文需要转发,则在上图红箭头所指处调用ip_forward():
图4 报文转发流程
从上面的流程可以看出,Netfilter以NF_HOOK()的形式出现在报文处理的过程之中。
Netfilter框架为多种协议提供了一套类似的钩子(HOOK),用一个struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]二维数组结构存储,一维为协议族,二维为上面提到的各个调用入口。每个希望嵌入Netfilter中的模块都可以为多个协议族的多个调用点注册多个钩子函数(HOOK),这些钩子函数将形成一条函数指针链,每次协议栈代码执行到NF_HOOK()函数时(有多个时机),都会依次启动所有这些函数,处理参数所指定的协议栈内容。
每个注册的钩子函数经过处理后都将返回下列值之一,告知Netfilter核心代码处理结果,以便对报文采取相应的动作:
NF_ACCEPT:继续正常的报文处理;
NF_DROP:将报文丢弃;
NF_STOLEN:由钩子函数处理了该报文,不要再继续传送;
NF_QUEUE:将报文入队,通常交由用户程序处理;
NF_REPEAT:再次调用该钩子函数。
nf_sockopts是在iptables进行初始化时通过nf_register_sockopt()函数生成的一个struct nf_sockopt_ops结构,对于ipv4来说,在net/ipv4/netfilter/ip_tables.c中定义了一个ipt_sockopts变量(struct nf_sockopt_ops),其中的set操作指定为do_ipt_set_ctl(),因此,当nf_sockopt()调用对应的set操作时,控制将转入net/ipv4/netfilter/ip_tables.c::do_ipt_set_ctl()中。
对于IPT_SO_SET_REPLACE命令,do_ipt_set_ctl()调用do_replace()来处理,该函数将用户层传入的struct ipt_replace和struct ipt_entry组织到filter(根据struct ipt_replace::name项)表的hook_entry[NF_IP_FORWARD]所指向的区域,如果是添加规则,结果将是filter表的private(struct ipt_table_info)项的hook_entry[NF_IP_FORWARD]和underflow[NF_IP_FORWARD]的差值扩大(用于容纳该规则),private->number加1。
2.5.4 规则应用过程
以上描述了规则注入核内iptables的过程,这些规则都挂接在各自的表的相应HOOK入口处,当报文流经该HOOK时进行匹配,对于与规则匹配成功的报文,调用规则对应的Target来处理。仍以转发的报文为例,假定filter表中添加了如上所述的规则:拒绝所有转发报文。
如1.2节所示,经由本地转发的报文经过路由以后将调用ip_forward()来处理,在ip_forward()返回前,将调用如下代码:
2.5.5 Netfilter的结构特点
由上可见,nf_hooks链表数组是联系报文处理流程和iptables的纽带,在iptables初始化(各自的init()函数)时,一方面调用nf_register_table()建立规则容器,另一方面还要调用nf_register_hook()将自己的挂钩愿望表达给Netfilter框架。初始化完成之后,用户只需要通过用户级的iptables命令操作规则容器(添加规则、删除规则、修改规则等),而对规则的使用则完全不用操心。如果一个容器内没有规则,或者nf_hooks上没有需要表达的愿望,则报文处理照常进行,丝毫不受Netfilter-iptables的影响;即使报文经过了过滤规则的处理,它也会如同平时一样重新回到报文处理流程上来,因此从宏观上看,就像在行车过程中去了一趟加油站。
Netfilter不仅仅有此高效的设计,同时还具备很大的灵活性,这主要表现在Netfilter-iptables中的很多部分都是可扩充的,包括Table、Match、Target以及Connection Track Protocol Helper,下面一节将介绍这方面的内容。
对于外出报文(源于本地或内网),使用内部地址在FORWARD/OUTPUT点匹配成功,执行ENCRYPT,从Netfilter中返回后作为本地IPIP_EXT协议的报文继续往外发送。
对于接收到的报文,如果协议号为IPPROTO_IPIP_EXT,则匹配IPIP_EXT的Match成功,否则将在INPUT点被丢弃;继续传送的报文从IP层传给IPIP_EXT的协议处理代码接收,在其中恢复内网IP的报文头后调用netif_rx()重新流入协议栈。此时的报文将在INPUT/FORWARD点匹配规则,并执行DECRYPT,只有通过了DECRYPT的报文才能继续传送到本机的上层协议或者内网。
附:iptables设置指令(样例):
iptables -t vpn -P FORWARD DROPiptables -t vpn -A OUTPUT -d 192.168.0.0/24 -j ENCRYPTiptables -t vpn -A INPUT -s 192.168.0.0/24 -m ipip_ah -j DECRYPTiptables -t vpn -A FORWARD -s 192.168.0.0/24 -d 192.168.1.0 -j DECRYPTiptables -t vpn -A FORWARD -s 192.168.1.0/24 -d 192.168.0.0/24 -j ENCRYPT
其中192.168.0.0/24是目的子网,192.168.1.0/24是本地子网
<!-- CMA ID: 21678 --><!-- Site ID: 10 --><!-- XSLT stylesheet used to transform this file: dw-article-6.0-beta.xsl -->
参考资料
[Linus Torvalds,2003] Linux内核源码v2.4.21