iptables nat&conntrack的特殊之处

最近分析istio的iptables规则遇到了一点麻烦,也让我对nat表和conntrack的原理有了更深刻的认识。

本文的阅读前提是你熟悉iptables,否则可能无法理解文章内容。

问题与解释

我在PREROUTING上做了一个REDIRECT端口改写,相应的服务处理请求后会返回应答。

按照我以往的认识,认为回包的流量应该先后经过OUTPUT和POSTROUTING,所以我利用iptables -t nat -nvL去查看NAT表在OUTPUT链和POSTROUTING链上的packge计数器,结果发现没有上涨,这让我陷入了沉思。

经过谷歌后找到了完美的解释:linux-netfilter-how-does-connection-tracking-track-connections-changed-by-nat

实际上我是知道OUTPUT链会先过conntrack表恢复原始IP关系的,但是超出我理解的是NAT表压根就不会再执行。

上述URL中给出了解释:NAT表只在连接状态是NEW的时候(也就是TCP的第一个握手包)才会执行计算,一旦改写关系存入了conntrack,那么这条连接后续的通讯就不会再过POSTROUTING和OUTPUT上面的NAT表了,而是直接换成了匹配conntrack来复原连接之前的改写状态。

因此,如果我们想看到回包的package计数器增长,就应该去看OUTPUT或者POSTROUTING上面的filter表计数,一定会看到上涨。

再次梳理流程

如果我们是服务端,那么SYN包到达的时候,在POSTROUTING链的NAT表执行过之后(可能做DNAT或者REDIRECT),路由表将决定是FORWARD还是INPUT:

  • 如果INPUT,那么conntrack记录就此生成,当回包的时候会首先根据conntrack作地址复原,并且是不会经过OUTPUT/POSTROUTING链NAT表(但是会经过filter表)的。
  • 如果FORWARD,那么conntrack记录不会立即生成,需要经过POSTROUTING之后才知道是否做了SNAT/MASQUERADE,此时才会生成conntrack记录。当收到上游回包的时候,不会过PREROUTING的NAT表,而是直接根据conntrack复原为原始IP地址,然后直接FORWARD->POSTROUTING(不会过NAT表)送回原始客户端。

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~