跟我学Linux系列2:Netfilter/iptables知多少

1、netfilter是什么

netfilter.org是Linux 2.4.x及更高版本内核系列中包过滤框架软件。 通常与 netfilter.org相关的软件是iptables。

这个框架内的软件可以实现数据包过滤,网络地址和端口转换(NA [P] T)以及其他数据包转换。 它是以前的Linux 2.2.x ipchains和Linux 2.0.x ipfwadm系统的重新设计和大大改进的后续产品。

netfilter是Linux内核中的一组钩子,它允许内核模块向网络堆栈注册回调函数。 为通过网络堆栈内相应钩子的每个数据包回叫一个注册的回调函数。
iptables是为规则集定义的通用表结构。 IP table中的每个规则由多个分类器(iptables matches)和一个连接的动作(iptables target)组成。
netfilter,ip_tables,连接跟踪(ip_conntrack,nf_conntrack)和NAT子系统一起构建框架的主要部分。

netfilter下面包含众多子项目,其中就有大名顶顶的iptables:
最早的内核包过滤机制是ipfwadm,后来是ipchains,再后来是iptables/netfilter,再往后就是现在的nftables。不过nftables与iptabes还处于争锋阶段,二者都是netfilter项目的子成员。

2、netfilter/iptables都可以做什么?

  • 建立基于无状态和状态包过滤的互联网防火墙
  • 部署高可用性无状态和有状态的防火墙集群
  • 如果您没有足够的公共IP地址,可以使用NAT和masquerading 实现共享互联网访问权限
  • 使用NAT来实现透明代理
  • 帮助tc和iproute2系统用于构建复杂QoS和策略路由器
  • 进行进一步的数据包操作(mangling),如改变IP报头的TOS/DSCP/ECN位

3、netfilter钩子(hooks)

netfilter基于钩子,在内核网络协议栈的几个固定位置有netfilter的钩子。
数据包有两种流向:
  • 一种是给本机的:驱动接收-->路由表-->本机协议栈-->上层应用程序-->本机协议栈-->路由表-->驱动发送
  • 另一种是转发给别人:驱动接收-->路由表-->转发-->驱动发送
针对以上数据包流向中的几个关键位置,netfilter在内核协议栈中定义了5个钩子:
  • NF_IP_PRE_ROUTING: 在查找路由表之前,接收的数据包刚进来,还没有经过路由选择,即还不知道数据包是要发给本机还是其它机器。
  • NF_IP_LOCAL_IN: 是在查完路由表决定发送本机之后,已经经过路由选择,并且该数据包的目的IP是本机,进入本地数据包处理流程。
  • NF_IP_FORWARD: 是在查完路由表决定转发的时候,已经经过路由选择,但该数据包的目的IP不是本机,而是其它机器,进入forward流程。
  • NF_IP_LOCAL_OUT: 是本地产生的数据交给驱动发送之产有,本地程序要发出去的数据包刚到IP层,还没进行路由选择。
  • NF_IP_POST_ROUTING: 是要交给驱动发送之前,本地程序发出去的数据包,或者转发(forward)的数据包已经经过了路由选择,即将交由下层发送出去。
数据包经过每个钩子时,都会检查上面是否注册有函数,如果有的话,就会调用相应的函数处理该数据包。
如下图所示:
通过在这几个钩子位置注册函数,截断数据包的流动,就可以完成数据包的过滤和转发功能。这些虽然都是IP层的钩子,但这些钩子不仅可以处理IP层的数据,还可以拿到完整的数据包,所以想处理哪一层的数据都是可以的。
注意: netfilter所有的钩子(hooks)都是在内核协议栈的IP层,由于IPv4和IPv6用的是不同的IP层代码,所以iptables配置的rules只会影响IPv4的数据包,而IPv6相关的配置需要使用ip6tables。

4、什么是iptables?

iptables是用于配置Linux 2.4.x及更高版本数据包过滤规则集的 用户空间命令行程序,通过netlink和内核的netfilter框架打交道,负责往钩子上配置回调函数。
由于网络地址转换也是从数据包过滤器规则集中配置的,因此iptables也用于此目的。iptables包也包含ip6tables。 ip6tables用于配置IPv6数据包过滤器。

目前iptables系在2.4、2.6及3.0的内核底下运作,旧版的Linux内核(2.2)使用ipchains及ipwadm(Linux 2.0)来达成类似的功能,2014年1月19日起发行的新版Linux内核(3.13后)则使用nftables取而代之。

chain和rule是iptables自创的概念,在钩子函数的地方可以执行指定的函数调用,iptables系统默认实现了这几个调用,并用一个统一的数据结构来组织这个调用的形式。 这个组织结构就是table、chain和rule。在任何一个hook点都可以定义多个table,一个table有多个chain,每个chain中可以定义多个rule。需要注意的是table和chain只是容器,里面的rule才是真正发挥作用的规则。

iptables的扩展选项
iptables是个可扩展的软件,其对TCP、UDP等常用协议的支持都是通过扩展完成的。iptables本身只支持到IP层,但只要使用相应的选项就可以自动扩展到其它协议层。另有一些扩展并不是对协议做扩展。
这些扩展一般通过iptables -m调用,例如iptables -m mac可以用来匹配MAC地址。-m limit可以用来限制每秒匹配的数目,超过数目的就放行。

还有很多target的扩展、conntrack的扩展和IPv6的扩展,可以根据应用的类型进行匹配,可以修改TTL、TOS等数据位,基本能用得上的功能都有对应的扩展。
操作(target)也是可以扩展的,常见的默认操作有ACCEPT和DROP,扩展的还有LOG、REJECT等。用户还可以自己实现。此外还有两种默认的操作是QUEUE和RETURN。RETURN实现了各个规则之间的函数式调用;QUEUE实现了数据包的排队。这些操作也都有对应的具体模块,例如nft_queue.ko、nft_rejecvt.ko、xt_LOG.ko、nft_log.ko等。

注:TOS,服务类型字段。TOS包括共8位,包括3 bit的优先权字段(取值可以从000-111所有值),4 bit的TOS子字段和1 bit未用位但必须置0。位置参见下图IP报文结构。详情信息参见 IP首部中的服务类型(TOS) 。

5、iptables 表(tables)

出于统一架构起见,iptables在各个hook点定义了顺序的几个table,每个table用来完成一类的工作。
  • 表(tables)提供特定的功能。iptables内置了4个表,即filter表、nat表、mangle表和raw表,分别用于实现包过滤,网络地址转换、包重构(修改)和数据跟踪处理。规则表之间的优先顺序:Raw-->mangle-->nat-->filter 。
  • 链(chains)是数据包传播的路径,每一条链其实就是众多规则中的一个检查清单,每一条链中可以有一条或数条规则。当一个数据包到达一个链时,iptables就会从链中第一条规则开始检查,看该数据包是否满足规则所定义的条件。如果满足,系统就会根据该条规则所定义的方法处理该数据包;否则iptables将继续检查下一条规则,如果该数据包不符合链中任一条规则,iptables就会根据该链预先定义的默认策略来处理数据包。
每一个 table表示的是功能,而不是位置。一个table内部有多个chain,其中每个 chain位于特定的位置
下图是一个table、chain关系图表:

从上图可以看到,预定义的几个表分别表示不同的功能,每个表都在一些hook点定义了一组chain。
当一个用户想要在某一个hook点做某一件事时,就可以 定位到table(功能)-->chain(位置)-->rule(行为)来完成数据包的操作。

每一条rule的格式都是相同的,但不是每个域对于每个chain都是可用的,有效的rule在不同的chain上是不同的。rule的通用格式包括:
  • 源IP地址
  • 目的IP地址
  • 上层协议
  • 接口
  • 操作(target)

6、iptables链(chains)

iptables里面有5个内置的chains,分别对应netfilter的5个钩子:
  • PREROUTING: 数据包经过NF_IP_PRE_ROUTING时会触发该chain上的rule.
  • INPUT: 数据包经过NF_IP_LOCAL_IN时会触发该chain上的rule.
  • FORWARD: 数据包经过NF_IP_FORWARD时会触发该chain上的rule.
  • OUTPUT: 数据包经过NF_IP_LOCAL_OUT时会触发该chain上的rule.
  • POSTROUTING: 数据包经过NF_IP_POST_ROUTING时会触发该chain上的rule.
每个表里面都可以包含多个chains,但并不是每个表都能包含所有的chains,因为某些表在某些chain上没有意义或者有些多余,比如说raw表,它只有在connection tracking之前才有意义,所以它里面包含connection tracking之后的chain就没有意义。

chains之间的优先顺序(分三种情况):
  • 第一种情况:入站数据流向
    从外界到达防火墙的数据包,先被PREROUTING规则链处理(是否修改数据包地址等),之后会进行路由选择(判断该数据包应该发往何处),如果数据包的目标主机是防火墙本机(比如说Internet用户访问防火墙主机中的web服务器的数据包),那么内核将其传给INPUT链进行处理(决定是否允许通过等),通过以后再交给系统上层的应用程序(比如Apache服务器)进行响应。
  • 第二冲情况:转发数据流向
    来自外界的数据包到达防火墙后,首先被PREROUTING规则链处理,之后会进行路由选择,如果数据包的目标地址是其它外部地址(比如局域网用户通过网关访问QQ站点的数据包),则内核将其传递给FORWARD链进行处理(是否转发或拦截),然后再交给POSTROUTING规则链(是否修改数据包的地址等)进行处理。
  • 第三种情况:出站数据流向
     防火墙本机向外部地址发送的数据包(比如在防火墙主机中测试公网DNS服务器时),首先被OUTPUT规则链处理,之后进行路由选择,然后传递给POSTROUTING规则链(是否修改数据包的地址等)进行处理。

用户自定义的chain:
除了iptables预定义的5个chain之外,用户还可以在表中定义自己的chain,用户自定义的chain中的rule和预定义chain里的rule没有区别,不过由于自定义的chain没有和netfilter里面的钩子进行绑定,所以它不会自动触发,只能从其它chain的rule中跳转过来。

7、iptables 规则(rules)

Rule存放在特定表的特定chain上。 每条rule 包含一个匹配规则和一个目标。
  • 如果条件匹配,则转到目标中指定的规则(或)执行目标中提到的特殊值。
  • 如果规则未匹配,则转到下一个规则。
Matching
Matching就是如何匹配一个数据包,匹配条件很多,比如协议类型、源/目的IP、源/目的端口、in/out接口、包头里面的数据以及连接状态等,这些条件可以任意组合从而实现复杂情况下的匹配。详情请参考 Iptables matches  .
Targets
Targets就是找到匹配的数据包之后怎么办,常见的有下面几种:
  • DROP:直接将数据包丢弃,不再进行后续的处理
  • RETURN: 跳出当前chain,该chain里后续的rule不再执行
  • QUEUE: 将数据包放入用户空间的队列,供用户空间的程序处理
  • ACCEPT: 同意数据包通过,继续执行后续的rule
  • 跳转到其它用户自定义的chain继续执行
当然iptables包含的targets很多很多,但并不是每个表都支持所有的targets, rule所支持的target由它所在的表和chain以及所开启的扩展功能来决定,具体每个表支持的targets请参考 Iptables targets and jumps

8、iptables 连接追踪(Connection Tracking)

Connection Tracking发生在 NF_IP_PRE_ROUTING和NF_IP_LOCAL_OUT这两个地方,一旦开启该功能,Connection Tracking模块将会追踪每个数据包(被raw表中的rule标记过的除外),维护所有的连接状态,然后这些状态可以供其它表中的rule引用,用户空间的程序也可以通过/proc/net/ip_conntrack来获取连接信息。
下面是所有的连接状态:
  • NEW: 当检测到一个不和任何现有连接关联的新包时,如果该包是一个合法的建立连接的数据包(比如TCP的sync包或者任意的UDP包),一个新的连接将会被保存,并且标记为状态NEW。
  • ESTABLISHED: 对于状态是NEW的连接,当检测到一个相反方向的包时,连接的状态将会由NEW变成ESTABLISHED,表示连接成功建立。对于TCP连接,意味着收到了一个SYN/ACK包, 对于UDP和ICMP,任何反方向的包都可以。
  • RELATED: 数据包不属于任何现有的连接,但它跟现有的状态为ESTABLISHED的连接有关系,对于这种数据包,将会创建一个新的连接,且状态被标记为RELATED。这种连接一般是辅助连接,比如FTP的数据传输连接(FTP有两个连接,另一个是控制连接),或者和某些连接有关的ICMP报文。
  • INVALID: 数据包不和任何现有连接关联,并且不是一个合法的建立连接的数据包,对于这种连接,将会被标记为INVALID,一般这种都是垃圾数据包,比如收到一个TCP的RST包,但实际上没有任何相关的TCP连接,或者别的地方误发过来的ICMP包。
  • UNTRACKED: 被raw表里面的rule标记为不需要tracking的数据包,这种连接将会标记成UNTRACKED。

9、什么是nftable?

nftables是新的数据包分类框架,旨在取代现有的{ip,ip6,arp,eb} _tables基础设施。
简而言之:
  • 它在Linux内核> = 3.13中可用。
  • 它带有一个新的命令行实用程序nft,其语法与iptables不同。
  • 它还附带了一个兼容层,允许您通过新的nftables内核框架运行iptables命令。
  • 它提供了通用集合基础结构,允许您构建映射和连接。 您可以使用此新功能将您的规则集排列在多维树中,从而大大减少需要检查的规则数量,直到找到数据包的最终操作为止。
为什么需要nftable?
我们喜欢iptables,必竟这个工具曾经为我们服务(并可能会继续在一些发行版本中服务一段时间)于数据包过滤、执行NAT和许多其他事情。它带有超过一百个在过去15年中贡献的扩展!

尽管如此,iptables框架的局限性不容易解决:
  • 避免代码重复和不一致:许多iptables扩展都是特定于协议的,所以没有一种整合的方式来匹配数据包字段,而是我们为它支持的每个协议都有一个扩展。这扩大了与代码非常相似的代码,以执行类似的任务:有效负载匹配。
  • 通过增强的通用集和地图基础设施实现更快的数据包分类。
  • 简化的双堆栈IPv4 / IPv6管理,通过新的inet系列,允许您注册可同时查看IPv4和IPv6流量的基础链。
  • 更好的动态规则集更新支持。
  • 像其他Linux Networking和Netfilter子系统一样,为第三方应用程序提供Netlink API。
  • 解决语法不一致问题并提供更好更紧凑的语法。
  • 除此之外,以及这里没有列出的一些原因,这引发了最初在法国巴黎举行的第六届Netfilter研讨会上向Netfilter社区提交的nftables开发。

10、nftables和iptables的主要区别

从用户的角度来看,二者的主要区别是:
  • 语法。 iptables命令行工具使用基于getopt_long()的解析器,其中的键始终是双减号,例如。 -- 键或单个减号,例如。 -p tcp。 在这方面,nftables使用受tcpdump启发的更好,更直观,更紧凑的语法。
  • 表和链是完全可配置的。 在nftables中,表是没有特定语义的链的容器。 请注意,iptables带有预定义数量的基本链表,即使你只需要其中一个链,也会注册所有链。 过去我们得到了一些报告,即使没有添加任何规则,未使用的基础链也会损害性能。 采用这种新方法,你可以根据你的设置注册所需的链条。 此外,你还可以按照你需要的方式使用链优先级对流水线进行建模,并为你的表和链选择任何名称。
  • 不再有匹配和目标之间的区别。 在nftables中,表达式是规则的基本构建块,因此,规则基本上是从左到右线性评估的表达式组合:如果第一个表达式匹配,则下一个表达式将被评估,直到我们到达作为规则一部分的最后一个表达式。 表达式可以匹配某些特定的有效负载字段,数据包/流元数据和任何操作。
  • 你可以在单个规则中指定多个操作。 在iptables中,你只能指定一个目标。 这是用户通过跳转到定制链来解决的一个长期限制,其代价是使规则集结构稍微复杂一些。
  • 每个链条和规则没有内置的计数器。 在nftables中,这些是可选的,因此你可以按需启用计数器。
  • 更好地支持动态规则集更新。 在nftables中,如果添加新规则,则剩余的现有规则保持不变。
  • 简化的双栈IPv4 / IPv6管理,通过新的inet系列,允许你注册可同时查看IPv4和IPv6流量的基础链。 因此,你不需要依赖脚本来重复你的规则集。
  • 通用集合和地图基础结构。 这种新的基础架构紧密集成到nftables核心中,它允许高级配置(如字典,地图和间隔)实现面向性能的数据包分类。 最重要的是你可以使用任何支持的选择器来分类流量。
  • 支持连接。 从Linux内核4.1,你可以连接几个键并将它们与字典和地图结合使用。 这个想法是构建一个元组,其值经过散列处理以获得将要执行的动作,执行效率近O(1)。
  • 支持新的协议,无需内核升级。 内核升级可能是一项耗时且艰巨的任务。 特别是如果你必须在网络中维护多个单一防火墙。 由于稳定性的原因,分销商通常会包含一些较旧的Linux内核版本。 使用新的nftables虚拟机方法,你很可能不需要此类升级来支持新的协议。 一个相对简单的用户空间软件更新应该足以支持新的协议。
Netfilter hooks
如果你熟悉Netfilter,不用担心,大部分基础架构仍然保持不变。 nftables重用了现有的钩子基础设施,连接跟踪系统,NAT引擎,日志记录基础设施,用户空间排队等。 因此,我们只更换了分组分类框架。

Ingress hook
从Linux内核4.2开始,Netfilter还附带了一个可以在nftables中使用的ingress hook。
所以现在netfilter packet flow看起来是这样的:
                                 .-----------.             
                                 |           |-----> input ...
---> ingress ---> prerouting --->|  Routing  |
                                 | Decision  |
                                 |           |
                                 |           |-----> forward ...
                                 .-----------.

你可以使用这个新的ingress钩子来过滤来自第2层的流量。这个新的钩子在prerouting之前就已经调用了,所以这允许你强制实施非常早的过滤策略。 这个新的钩子基本上提供了一个tc的替代方案。


《深入Linux内核架构与底层原理》第7章