报文过滤 和连接跟踪 可以说是
Netfilter
提供的两大基本功能。前者被大多数人熟知,因为我们对防火墙的第一印象就是可以阻止有害的报文伤害计算机;而后者就没这么有名了,很多人甚至不知道Netfilter
有这项功能。
Why 使用连接跟踪
顾名思义,连接跟踪 是保存连接状态的一种机制。为什么要保存连接状态呢?举个例子,当你通过浏览器访问一个网站 (连接网站的80
端口)时,预期会收到服务器发送的源端口为 80
的报文回应,防火墙自然应该放行这些回应报文。那是不是所有源端口为 80
端口的报文都应该放行呢?显然不是,我们只应该放行源 IP 为服务器地址,源端口为 80
的报文,而应该阻止源地址不符的报文,即使它的源端口也是 80
。总结一下这种情况就是, 我们只应该让主动发起的连接产生的双向报文通过。
另一个例子是 NAT
。我们可以使用iptables
配置 nat
表进行地址或者端口转换的规则。如果每一个报文都去查询规则,这样效率太低了,因为同一个连接的转换方式是不变的!连接跟踪 提供了一种 缓存 解决方案:当一条连接的第一个数据包通过时查询 nat
表时,连接跟踪 将转换方法保存下来,后续的报文只需要根据 连接跟踪 里保存的转换方法就可以了。
连接跟踪发生在哪里
Connection tracking hooks into high-priority
NF_IP_LOCAL_OUT
andNF_IP_PRE_ROUTING
hooks, in order to see packets before they enter the system.
连接跟踪 需要拿到报文的第一手资料,因此它们的入口是以高优先级存在于 LOCAL_OUT
(本机发送) 和PRE_ROUTING
(报文接收)这两个链。
既然有入口,自然就有出口。连接跟踪 采用的方案是在入口记录,在出口确认 (confirm
)。以IPv4
为例:
当连接的第一个 skb
通过入口时,连接跟踪 会将 连接跟踪信息 保存在 skb->nfctinfo
,而在出口处, 连接跟踪 会从 skb
上取下 连接跟踪信息 ,保存在自己的hash
表中。当然,如果这个数据包在中途其他 HOOK
点被丢弃了,也就不存在最后的 confirm
过程了。
连接跟踪信息是什么
连接跟踪信息 会在入口处进行计算,保存在 skb
上,信息具体包括 tuple
信息(地址、端口、协议号等)、扩展信息以及各协议的私有信息。
-
tuple
信息包括发送和接收两个方向,对TCP
和UDP
来说,是IP
加Port
;对ICMP
来说是IP
加Type
和Code
, 等等; - 扩展信息比较复杂,本文暂时略过;
- 各协议的私有信息,比如对
TCP
就是序号、重传次数、缩放因子等。
报文的连接跟踪状态
途径 Netfilter
框架的每一个报文总是会在入口处 (PRE ROUTING
或者 LOCAL OUT
) 被赋予一个连接跟踪状态。这个状态存储在skb->nfctinfo
,有以下常见的取值:
-
IP_CT_ESTABLISHED:这是一个属于已经建立连接的报文,
Netfilter
目击过两个方向都互通过报文了 -
IP_CT_RELATED:这个状态的报文所处的连接与另一个 IP_CT_ESTABLISHED 状态的连接是有联系的。比如典型的
ftp
,ftp-data
的连接就是ftp-control
派生出来的,它就是RELATED
状态 -
IP_CT_NEW:这是连接的第一个包,常见的就是
TCP
中的SYN
包,UDP
、ICMP
中第一个包, - IP_CT_ESTABLISHED + IP_CT_IS_REPLY:与 IP_CT_ESTABLISHED 类似,但是是在回复方向
- IP_CT_RELATED + IP_CT_IS_REPLY:与 IP_CT_RELATED 类似,但是是在回复方向
总结
-
连接跟踪 是
Netfilter
提供的一项基本功能,它可以保存连接的状态。用户可以为不同状态的连接的报文制定不同的策略; -
连接跟踪 在报文进入
Netfilter
的入口 将信息记录在报文上,在 出口 进行confirm
. 确认后的连接信息可以影响之后的报文; -
连接跟踪 的信息主要包括基本的描述连接的
tuple
以及各协议的私有信息。