最近分析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表)送回原始客户端。
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~

如果我们是服务端,那么SYN包到达的时候,在POSTROUTING链的NAT表执行过之后(可能做DNAT或者REDIRECT),路由表将决定是FORWARD还是INPUT:
這裡應該是寫作 PREROUTING
嗯,写错了,是PREROUTING,谢谢纠正。