Linux Netfilter:连接跟踪如何追踪被 NAT 改变的连接?

Linux Netfilter:连接跟踪如何追踪被 NAT 改变的连接?

目前,我正在深入研究 Linux 的 Netfilter 架构的细节。我已经熟悉了 Netfilter 钩子、表、链、不同的内核模块等。
但是,有一个关于 NAT 与连接跟踪结合的细节我不太明白。

我尝试用一​​个小的 SNAT 示例来解释我的问题。在这个例子中,我将忽略传输层,因为我认为理解我的问题不需要它。如果我错了,请纠正我!

本地网络上有一台客户端计算机,其 IP 地址为 192.168.2.55,NAT 网关的外部 IP 地址为 193.157.56.3。现在,客户端想要与 Internet 上的服务器和 IP 地址 217.254.1.76 进行通信。
因此,客户端向 NAT 网关(也是默认网关)发送一个数据包,其 src = 192.168.2.55/dst = 217.254.1.76。连接跟踪跟踪此新连接并创建两个新元组:

IP_CT_DIR_ORIGINAL: 源地址 = 192.168.2.55,目标地址 = 217.254.1.76
IP_CT_DIR_REPLY: 源地址 = 217.254.1.76,目标地址 = 192.168.2.55

IP_CT_DIR_ORIGINAL 和 IP_CT_DIR_REPLY 是用于访问二元组数组的宏。

在 POSTROUTING 钩子处,NAT 请求对现有连接的连接跟踪,如果成功,则更改数据包标头中的源地址。它还会默默创建 DNAT 规则来恢复回复的目标地址。
现在我到了问题的关键。NAT 将 IP_CT_DIR_REPLY 中的目标地址更改为其外部 IP 地址 193.157.56.3。因此元组如下所示:

IP_CT_DIR_ORIGINAL: 源地址 = 192.168.2.55,目标地址 = 217.254.1.76
IP_CT_DIR_REPLY: 源地址 = 217.254.1.76,目标地址 = 193.157.56.3

这就是为什么连接跟踪可以在 PREROUTING 钩子中跟踪回复的原因,因为回复有一个现有的元组。但是在跟踪数据包之后,NAT 将目标地址更改为客户端的地址 192.168.2.55。
现在我的问题是:连接跟踪如何在 POSTROUTING 钩子中跟踪此数据包?没有 src = 217.254.1.76/dst = 192.168.2.55 的回复元组,因为 NAT 已对其进行了更改。
我是否遗漏了什么?

答案1

你应该安装conntrack通常打包为 conntrack 或 conntrack-tools 的命令,来自http://conntrack-tools.netfilter.org/。它主要会显示相同的内容,/proc/net/nf_conntrack但可以做更多。

在 NAT 网关上以事件模式运行 conntrack:(conntrack -E或者您可以选择conntrack -E --proto tcp --orig-port-dst 443限制为 HTTPS)。现在,您之前使用 HTTPS 请求的示例将提供类似于以下内容的内容:

    [NEW] tcp      6 120 SYN_SENT src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 [UNREPLIED] src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798
 [UPDATE] tcp      6 60 SYN_RECV src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798
 [UPDATE] tcp      6 432000 ESTABLISHED src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]
 [UPDATE] tcp      6 120 FIN_WAIT src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]
 [UPDATE] tcp      6 60 CLOSE_WAIT src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]
 [UPDATE] tcp      6 30 LAST_ACK src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]
 [UPDATE] tcp      6 120 TIME_WAIT src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]
[DESTROY] tcp      6 src=192.168.2.55 dst=217.254.1.76 sport=50798 dport=443 src=217.254.1.76 dst=193.157.56.3 sport=443 dport=50798 [ASSURED]

nat 表比较特殊,因为它用过的仅有的每流一次*,当[NEW]状态创建时。其他一切都被找到的 conntrack 条目短路。POSTROUTING 中的 SNAT 规则没有为回复“悄悄创建 DNAT 规则”。它改变了 conntrack 条目,使回复 dst=193.157.56.3,并告诉 netfilter“我改变了一些东西”,这就是大部分。其他一切(包括源 ip 更改)都由 conntrack(模块 nf_conntrack、nf_conntrack_ipv4)和 nat(模块 nf_nat、nf_nat_ipv4 以及这里可能还有其他一些模块)处理,而不是由 iptables 处理。考虑这些条目是连接状态数据库。

当收到回复数据包时,将通过 conntrack 条目查找未存储关联的数据包(实际上在原始部分或回复部分中双向查找关联,这无关紧要),并且会找到匹配项,因为该条目之前已创建。然后使用此连接关联更新打包信息。以后无需再通过条目查找此数据包,即使其某些属性(源或目标...)发生更改,信息也直接可用。处理此问题的一些宏/内联函数定义在skbuff.h。查找_nfctnfct。数据包(又称为 skbuff)在查找后,在中收到该值skb->_nfct

以下是您可能错过的一些事项:

  • iptables 不是 netfilter。它是 netfilter 的一个用户。nftables 是 netfilter 的另一个用户。conntrack 和 nat(例如模块 nf_nat)是 netfilter 的一部分。
  • POSTROUTING 钩子永远不会看到回复数据包,因为该连接不是新的:对于此流和被标识为此流的一部分的数据包,不再调用 nat 表。
  • conntrack 和 nat 的大部分处理都是由 conntrack 和 nat 完成的,而不是由 iptables 完成的。iptables 可以使用 conntrack(例如:)-m conntrack --ctstate ESTABLISHED或 nat 的资源(nat 表中的任何内容都必须如此)。对于上述示例,conntrack 条目本身就具有“解除 SNAT”数据包的信息,实际上它看起来类似于具有最初入站连接的 DNAT。
  • 通常不需要多次查找现有连接的数据包部分的 conntrack 条目,“索引”会在查找后附加到数据包。

通过运行几次iptables-save -c并查看 nat 表中规则的计数器如何增加,您可以确信 nat 表在第一个数据包之后不会看到其他数据包:仅针对第一个数据包。

*查看 NAT 部分:

该表与“过滤器”表稍有不同,因为只有新连接的第一个数据包才会遍历该表:此遍历的结果将应用于同一连接中的所有未来数据包。

答案2

我认为,了解数据包如何在 Netfilter 子系统中遍历路径的清晰概念也可能帮助您摆脱这种困惑。

PREROUTING如果健全性检查得到满足,则是任何传入数据包的第一个钩子。DNAT(dst:193.157.56.3->dst:192.168.2.55) 和 NAPT 都在此钩子中实现。并且,在任何路由决策之前都会到达此钩子。(最后两行粗体字非常重要)。并且,在路由决策制成后,数据包命中FORWARDLOCAL_IN

另一方面,POST_ROUTING是离开机器的任何数据包的最后一个钩子。并且,SNAT(src:192.168.2.55->src:193.157.56.3) 已在此钩子中注册。

相关内容