netfilter是linux2.4内核实现数据包过滤/数据包处理/nat等的功能框架。该文讨论了linux 2.4内核的netfilter功能框架,还对基于netfilter框架上的包过滤,nat和数据包处理(packet mangling)进行了讨论。阅读本文需要了解2.2内核中ipchains的原理和使用方法作为预备知识,若你没有这方面的知识,请阅读ipchains-howto。
第一部分:netfilter基础和概念
一、什么是netfilter
netfilter比以前任何一版linux内核的防火墙子系统都要完善强大。netfilter提供了一个抽象、通用化的框架,该框架定义的一个子功能的实现就是包过滤子系统。因此不要在2.4中期望讨论诸如”如何在2.4中架设一个防火墙或者伪装网关”这样的话题,这些只是netfilter功能的一部分。netfilter框架包含以下三部分:
1 为每种网络协议(ipv4、ipv6等)定义一套钩子函数(ipv4定义了5个钩子函数),这些钩子函数在数据报流过协议栈的几个关键点被调用。在这几个点中,协议栈将把数据报及钩子函数标号作为参数调用netfilter框架。
2 内核的任何模块可以对每种协议的一个或多个钩子进行注册,实现挂接,这样当某个数据包被传递给netfilter框架时,内核能检测是否有任何模块对该协议和钩子函数进行了注册。若注册了,则调用该模块的注册时使用的回调函数,这样这些模块就有机会检查(可能还会修改)该数据包、丢弃该数据包及指示netfilter将该数据包传入用户空间的队列。
3 那些排队的数据包是被传递给用户空间的异步地进行处理。一个用户进程能检查数据包,修改数据包,甚至可以重新将该数据包通过离开内核的同一个钩子函数中注入到内核中。
所有的包过滤/nat等等都基于该框架。内核网络代码中不再有到处都是的、混乱的修改数据包的代码了。当前netfilter框架在ipv4、ipv6及decnet网络栈中被实现。
二、为什么需要netfilter?
其实这个问题也可以变为ipchains有什么缺点导致被抛弃?下面只是其中的几个原因:
因为基于2.2内核的ipchains没有提供传递数据包到用户空间的框架,所以任何需要对数据包进行处理的代码都必须运行在内核空间,而内核编程却非常复杂,而且只能用c语言实现,并且容易出现错误并对内核稳定性造成威胁。
透明代理实现非常复杂,必须查看每个数据包来判断是否有专门处理该地址的socket。网络栈代码中在11个文件中共出现了34个”#ifdef”条件编译。
创建一个不依赖于接口地址的数据报过滤规则是不可能实现的。我们必须利用本地接口地址来判断数据报是本地发出、还是发给本地的或是转发的。转发链只有输出接口的信息,因此管理员必需考虑数据报的源。
伪装和数据包过滤都在同一个模块内实现,导致防火墙代码过于复杂。
ipchains代码即不模块化又不易于扩展(例如对mac地址的过滤)
三、netfilter的作者
netfilter框架的概念的提出及主要实现是由rusty russell完成的,他是ipchains的合作完成者及当前linux内核ip防火墙的维护者。还有marc boucher、james morris、harald welte等都参与了netfilter项目。
四、netfilter在ipv4中的结构
一个数据包按照如下图所示的过程通过netfilter系统:
—>[1]—>[route]—>[3]—>[4]—>
| ^
local| |
| [route]
v |
[2] [5]
| ^
| |
v |
从图中可以看到ipv4一共有5个钩子函数,分别为:
1 nf_ip_pre_routing
2 nf_ip_local_in
3 nf_ip_forward
4 nf_ip_post_routing
5 nf_ip_local_out
数据报从左边进入系统,进行ip校验以后,数据报经过第一个钩子函数nf_ip_pre_routing[1]进行处理;然后就进入路由代码,其决定该数据包是需要转发还是发给本机的;若该数据包是发被本机的,则该数据经过钩子函数nf_ip_local_in[2]处理以后然后传递给上层协议;若该数据包应该被转发则它被nf_ip_forward[3]处理;经过转发的数据报经过最后一个钩子函数nf_ip_post_routing[4]处理以后,再传输到网络上。
本地产生的数据经过钩子函数nf_ip_local_out [5]处理可以后,进行路由选择处理,然后经过nf_ip_post_routing[4]处理以后发送到网络上。
五、netfilter基础
从上面关于ipv4的netfilter的例子讨论,可以看到钩子函数是如何被激活的。
内核模块可以对一个或多个这样的钩子函数进行注册挂接,并且在数据报经过这些钩子函数时被调用,从而模块可以修改这些数据报,并向netfilter返回如下值:
nf_accept 继续正常传输数据报
nf_drop 丢弃该数据报,不再传输
nf_stolen 模块接管该数据报,不要继续传输该数据报
nf_queue 对该数据报进行排队(通常用于将数据报给用户空间的进程进行处理)
nf_repeat 再次调用该钩子函数
六、使用iptables进行数据报选择
一个基于netfilter框架的、称为iptables的数据报选择系统在linux2.4内核中被应用,其实它就是ipchains的后继工具,但却有更强的可扩展性。
内核模块可以注册一个新的规则表(table),并要求数据报流经指定的规则表。这种数据报选择用于实现数据报过滤(filter表),网络地址转换(nat表)及数据报处理(mangle表)。
linux2.4内核提供的这三种数据报处理功能都基于netfilter的钩子函数和ip表。它们是独立的模块,相互之间是独立的。它们都完美的集成到由netfileter提供的框架中。
包过滤
filter表格不会对数据报进行修改,而只对数据报进行过滤。iptables优于ipchains的一个方面就是它更为小巧和快速。它是通过钩子函数nf_ip_local_in, nf_ip_forward及nf_ip_local_out接入netfilter框架的。因此对于任何一个数据报只有一个地方对其进行过滤。这相对ipchains来说是一个巨大的改进,因为在ipchains中一个被转发的数据报会遍历三条链。
nat
nat表格监听三个netfilter钩子函数:nf_ip_pre_routing、nf_ip_post_routing及nf_ip_local_out。 nf_ip_pre_routing实现对需要转发的数据报的源地址进行地址转换而nf_ip_post_routing则对需要转发的数据包的目的地址进行地址转换。对于本地数据报的目的地址的转换则由nf_ip_local_out来实现。
nat表格不同于filter表格,因为只有新连接的第一个数据报将遍历表格,而随后的数据报将根据第一个数据报的结果进行同样的转换处理。
nat表格被用在源nat,目的nat,伪装(其是源nat的一个特例)及透明代理(其是目的nat的一个特例)。
数据报处理(packet mangling)
mangle表格在nf_ip_pre_routing和nf_ip_local_out钩子中进行注册。使用mangle表,可以实现对数据报的修改或给数据报附上一些带外数据。当前mangle表支持修改tos位及设置skb的nfmard字段。
七、连接跟踪
连接跟踪是nat的基础,但是已经作为一个单独的模块被实现。该功能用于对包过滤功能的一个扩展,使用连接跟踪来实现“基于状态”的防火墙。
第二部分 使用iptables及netfilter进行数据包过滤
一、概述
下面的内容要求具有对tcp/ip,路由,防火墙及包过滤的基本概念的了解。
在第一部分已经解释过,filter表和三个钩子进行了挂接,因此提供了三条链进行数据过滤。所有来自于网络,并且发给本机的数据报会遍历input规则链。所有被转发的数据报将仅仅遍历forward规则链。最后,本地发出的数据报将遍历output链。
二、向规则链中插入规则
linux2.4提供了一个简洁强大的工具”iptables”来插入/删除/修改规则链中的规则。这里并不对iptalbes进行详细的介绍,而只是讨论它的主要的一些特性:
该命令实现对所有的ip表进行处理,当前包括filter,nat及mangle三个表格,及以后扩展的表模块。
该命令支持插件来支持新的匹配参数和目标动作。因此对netfilter的任何扩展都非常的简单。仅仅需要编写一个完成实际目标动作处理的模块和iptalbes插件(动态连接库)来添加所需要的一切。它有两个实现:iptables(ipv4)及ip6tables。两者都基于相同的库和基本上相同的代码。
基本的iptables命令
一个iptables命令基本上包含如下五部分:
希望工作在哪个表上
希望使用该表的哪个链
进行的操作(插入,添加,删除,修改)
对特定规则的目标动作
匹配数据报条件
基本的语法为:
iptables -t table -operation chain -j target match(es)
例如希望添加一个规则,允许所有从任何地方到本地smtp端口的连接:
iptables -t filter -a input -j accept -p tcp –dport smtp
当然,还有其他的对规则进行操作的命令如:清空链表,设置链缺省策略,添加一个用户自定义的链….
基本操作:
-a 在链尾添加一条规则
-i 插入规则
-d 删除规则
-r 替代一条规则
-l 列出规则
基本目标动作,适用于所有的链
accept 接收该数据报
drop 丢弃该数据报
queue 排队该数据报到用户空间
return 返回到前面调用的链
foobar 用户自定义链
基本匹配条件,适用于所有的链
-p 指定协议(tcp/icmp/udp/…)
-s 源地址(ip address/masklen)
-d 目的地址(ip address/masklen)
-i 数据报输入接口
-o 数据报输出接口
出了基本的操作,匹配和目标还具有各种扩展。
三、iptables的数据报过滤匹配条件扩展
有各种各样的数据包选择匹配条件扩展用于数据包过滤。这里仅仅简单的说明来让你感受扩展匹配的强大之处。
这些匹配扩展给了我们强大的数据报匹配手段:
tcp匹配扩展能匹配源端口,目的端口,及tcp标记的任意组合,tcp选项等。
upd匹配扩展能匹配源端口和目的端口
icmp匹配扩展能匹配icmp类型
mac匹配扩展能匹配接收到的数据的mac地址
mark匹配扩展能匹配nfmark
owne匹配扩展(仅仅应用于本地产生的数据报)来匹配用户id,组id,进程id及会话id
limit扩展匹配用来匹配特定时间段内的数据报限制。这个扩展匹配对于限制dos攻击数据流非常有用。
state匹配扩展用来匹配特定状态下的数据报(由连接跟踪子系统来决定状态),可能的状态包括:
invalid (不匹配于任何连接)
established (属于某个已经建立的链接的数据报)
new (建立连接的数据报)
related (和某个已经建立的连接有一定相关的数据报,例如一个icmp错误消息或ftp数据连接)
tos匹配扩展用来匹配ip头的tos字段的值。
四、iptables的数据报过滤目标动作扩展
log 将匹配的数据报传递给syslog()进行记录
ulog 将匹配的数据适用用户空间的log进程进行记录
reject 不仅仅丢弃数据报,同时返回给发送者一个可配置的错误信息
mirror 互换源和目的地址以后重新传输该数据报
第三部分 利用iptables和netfilter进行nat
linux以前的内核仅仅支持有限的nat功能,被称为伪装。netfilter则支持任何一种nat。一般来讲nat可以分为源nat和目的nat。
源nat在数据报经过nf_ip_post_routing时修改数据报的源地址。伪装是一个特殊的snat。
目的nat在数据报经过nf_ip_local_out或nf_ip_pre_routing 时修改数据报目的地址。端口转发和透明代理都是dnat。
一、iptables的nat目标动作扩展
snat
变换数据包的源地址。
例:
iptables -t nat -a postrouting -j snat –to-source 1.2.3.4
masquerade
用于具有动态ip地址的拨号连接的snat,类似于snat,但是如果连接断开,所有的连接跟踪信息将被丢弃,而去使用重新连接以后的ip地址进行ip伪装。
例:
iptables -t nat -a postrouting -j masquerade -o ppp0
dnat
转换数据报的目的地址,这是在prerouting钩子链中处理的,也就是在数据报刚刚进入时。因此linux随后的处理得到的都是新的目的地址。
例:
iptables -t nat -a prerouting -j dnat –to-destination 1.2.3.4:8080 -p tcp –dport 80 -i eth1
redirect
重定向数据报为目的为本地,和dnat将目的地址修改为接到数据报的接口地址情况完全一样。
例:
iptables -t nat -a prerouting -j redirect –to-port 3128 -i eth1 -p tcp –dport 80
第四部分 利用iptables和netfilter进行数据报处理(packet mangling)
mangle表提供了修改数据报各个字段的值的方法。
一、针对数据包处理的目标扩展
mark
设置nfmark字段的值。我们可以修改nfmark字段的值。nfmark仅仅是一个用户定义的数据报的标记(可以是无符号长整数范围内的任何值)。该标记值用于基于策略的路由,通知ipqmpd (运行在用户空间的队列分捡器守护进程)将该数据报排队给哪个哪个进程等信息。
例: iptables -t mangle -a prerouting -j mark –set-mark 0x0a -p tcp
tos
设置数据报的ip头的tos字段值。若希望适用基于tos的数据报调度及路由,这个功能是非常有用处的。
例: iptables -t mangle -a prerouting -j tos –set-tos 0x10 -p tcp –dport ssh
第五部分 排队数据报到用户空间
前面已经提到,任何时候在任何nefilter规则链中,数据报都可以被排队转发到用户空间去。实际的排队是由内核模块来完成的(ip_queue.o)。
数据报(包括数据报的原[meta]数据如nfmark和mac地址)通过netlink socket被发送给用户空间进程.该进程能对数据报进行任何处理。处理结束以后,用户进程可以将该数据报重新注入内核或者设置一个对数据报的目标动作(如丢弃等)。
这是netfilter的一个关键技术,使用户进程可以进行复杂的数据报操作。从而减轻了内核空间的复杂度。用户空间的数据报操作进程能很容易的适用ntfilter提供的称为libipq的库来进行开发。
参考文献:
laforges talk about netfilter
http://www.lisoleg.org/forum-source/messages/1410.html
the netfilter framework in linux 2.4
http://www.gnumonks.org/papers/netfilter-lk2000/presentation.html
linux 2.4 packet filtering howto
http://netfilter.kernelnotes.org/unreliable-guides/packet-filtering-howto/index.html
linux 2.4 nat howto
http://netfilter.kernelnotes.org/unreliable-guides/nat-howto/index.html
netfilter hacking howto
http://netfilter.kernelnotes.org/unreliable-guides/netfilter-hacking-howto/index.html
(作者:ideal)