Linux内核工程导论——网络:Netfilter概览


简介

最早的内核包过滤机制是ipfwadm,后来是ipchains,再后来就是iptables/netfilter了。再往后,也就是现在是nftables。不过nftables与iptables还处于争雄阶段,谁能胜出目前还没有定论。但是他们都属于netfilter项目的子成员。

钩子

netfilter基于钩子,在内核网络协议栈的几个固定的位置由netfilter的钩子。我们知道数据包有两种流向,一种是给本机的:驱动接收——》路由表——》本机协议栈——》驱动发送。一种是要转发给别人的:驱动接收——》路由表——》转发——》驱动发送。针对这几个关键位置,netfilter定义了几个钩子:NF_IP_PRE_ROUTING是在查路由表之前,NF_IP_LOCAL_IN实在查完路由表决定发送本机之后,NF_IP_FORWARD实在查完路由表决定转发的时候,NF_IP_POST_ROUTING是要交给驱动发送之前,NF_IP_LOCAL_OUT是本机产生的数据交给驱动发送之前。通过在这几个钩子位置注册函数,截断数据包的流动,可以完成数据包的过滤和转换功能。要知道的是,转发功能一般只在路由器上打开,一般的PC如果发现不是自己的数据包就会直接选择丢弃。所以,普通PC可以使用的钩子有NF_IP_PRE_ROUTING、NF_IP_LOCAL_IN、NF_IP_LOCAL_OUT、NF_IP_POST_ROUTING四个。可以看到都是在IP层的钩子,然而,这些钩子可不仅只可以处理IP层的数据,因为在IP层可以拿到完整的数据包,所以你想处理哪一层都是可以的。

iptables不是注册在钩子函数上,但是位置是一致的。是netfilter框架下的一个附属的功能,由table、chain、rule组成。

netfilter提供了几个重要的功能,方便无论是iptables还是nftables使用。caching功能可以有一个缓存,通过查询数据包的某个位置可以决定该数据包根本不会经过后面的过滤规则。

用户空间使用iptables

table、chain和rule

chain和rule是iptables自创的概念,我们知道在钩子函数的地方可以执行指定的函数调用。iptables系统就默认实现了几个调用,并且用统一的数据结构来组织这个调用的形式。这个组织结构就是table、chain和rule。

在任何一个hook点,都可以定义多个table,一个table有多个chain,每个chain中可以定义多个rule。要记住的是table和chain只是容器,里面的rule才是真正发挥作用的规则。理论上我们可以在任何一个hook点做过滤、nat、修改数据包等所有操作,但是iptables为了统一架构起见,在各个hook点定义了顺序的几个table,每个table用来完成一类的工作。预定义的table包括:filter、nat和mangle。这每一个table表示的是功能,并不是表示位置,一个table内部有多个chain,其中每个chain位于特定的位置。

下图是一个内部已经定义的table、chain关系图表:

https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg

\

FILTER: PREROUTING, FORWARD, POSTROUTING

NAT: PREROUTING, INPUT, OUTPUT, POSTROUTING

MANGLE: PREROUTING, INPUT, FORWARD, OUTPUT,POSTROUTING

可以看到,预定义的3个表表示3种不同的功能,每个表都在一些hook点定义了一组chain。如此,当一个用户想要在某一个hook点做某一件事情,就可以定位到table(功能)——》chain(位置)——rule(行为)来完成数据包操作。

每一条rule的格式都是相同的,包括源IP地址、目的IP地址、上层协议、接口、操作(target)。但是并不是每个域对于每个chain都是可用的,例如在INPUT的地方匹配输出接口就是永远匹配不到的。所以有效的rule在不同的chain上是不同的。

 

iptables是个可扩展的软件,其对TCP、UDP等常用协议的支持都是通过扩展,iptables本体只支持到ip层,你只要使用对应的选项就会自动的使用扩展。还有一些不是协议的扩展,这些扩展一般通过iptables –m 调用,例如iptables –m mac可以用来匹配mac地址。-m limit可以用来限制每秒钟匹配的数目,超过的就放行。这些扩展包括:

l xt_mac.ko:匹配mac地址

l xt_limit.ko:限制每秒钟匹配的数目,超过的就放行

l xt_owner.ko:用来匹配某个某个进程或用户创建的数据包

l xt_state.ko:用来匹配处于某个连接状态的数据包(例如NEW、ESTABLLISHED、RELATED)

l xt_pkttype.ko:用来根据多播、广播还是单播来匹配包

l xt_quota.ko:可以为一个rule设置quota,当quota达到后,改rule失效

l xt_recent.ko:允许你设置一个IP列表,后续的IP列表的用户都不生效

l xt_string.ko:允许你匹配数据包中的一个字符串

l xt_time.ko:允许你根据数据包的到达和离去时间进行匹配

l xt_u32.ko:通过匹配检查数据包的某4位是否与要求的一致来进行操作

还有很多target的扩展和conntrack的扩展、ipv6的扩展。可以根据应用的类型进行匹配,可以修改ttl、TOS等数据位。基本能用得上的功能都有对应的扩展。

操作(target)也是可以扩展的,常见的默认的操作有ACCEPT和DROP,扩展的还有LOG、REJECT等,用户还可以自己实现。还有两种默认是QUEUE和RETURN,RETURN实现了各个规则之间的函数式调用,QUEUE则实现了数据包的排队。这些操作也都对应着具体的模块:nft_queue.ko、nft_reject.ko、xt_LOG.ko、nft_log.ko等。

bpf

用户空间不止可以添加规则,还可以添加代码。这是通过xt_bpf模块实现的。iptables –m bpf –bytecode 后面跟具体的code就好了,从汇编编译成code的程序再linux内核的tool/net下有。

内核模块使用netfilter

不但是用户空间可以给iptables添加规则,内核模块添加规则的能力更强大。由于其具备编码能力,所以不只是可以丢弃一个数据包,还可以返回NF_STOLEN,这样这个数据包对于协议栈来说将会停止向上发送,而这个模块将会处理这个数据包的后续流程。

应该注意的是,netfilter这个名字指的是内核过滤数据包这个架构,而iptables则是table、chain、rule这套设计。内核里面一般直接使用netfilter的钩子,而不使用iptables的规则。

相关内容

    暂无相关文章