报文过滤和连接跟踪可以说是
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
以及各协议的私有信息。