ACK 包上的 conntrack NEW:它不能证明什么
标为 NEW 的 ACK 只说明追踪器当时没有匹配的状态,并不说明 VPN 建立了会话。要看 hook、tuple 和抓包窗口。
防火墙日志里有一行你没预料到:一个 ACK 包,conntrack 状态为 NEW,源地址不是你的,目的端口处于开放状态。很容易把它读成一条无人授权的新入站连接。这行实际说的要窄得多:当这个包到达这个 hook 时,追踪器没有匹配的状态,而这个包带的是 ACK。这是关于两件不同事情的两个事实,两者都不是一次握手的完整记录。下面是我下结论之前会走的顺序。
从包开始,不要从结论开始
在解释之前先把观察分开。TCP 标志描述的是这个包,追踪器的状态描述的是它在该 hook 处知道什么,而你的抓包只描述你录下的那段窗口。
把这三者混为一谈,就是一个 ACK 被读成“服务商把某人放进来了”的过程。
NEW 在 hook 处到底意味着什么
iptables 的 conntrack 匹配 把 NEW 记录为发起连接的包,或者与一个尚未在两个方向上都见到流量的连接相关联的包。ESTABLISHED 意味着追踪器已经在两个方向上都看到包。两个定义都没有说这个包是 SYN,也没有说它是在没有历史的情况下到达的。
从中间开始观察一条流的追踪器,会按自己已知的信息去分类下一个包,而这个信息可能什么都没有。这是关于追踪器记忆的陈述,不是关于远端主机意图的陈述。
宽松追踪解释了大多数 ACK 带来的意外
内核记录了 nf_conntrack_tcp_loose,它允许追踪器接管它没有看到开始的 TCP 连接。在该选项取默认值时,来自流中段的 ACK 可能被当作已建立的流接收。把它关掉,同一个包更可能被分类为 INVALID 而不是 NEW。两种结果描述的都是追踪器的规则,而不是应用的经历。
所以在把标签当作理论依据之前,先检查这个设置。
按这个顺序排除无趣的原因
我跟过的 NEW-on-ACK 事件大多落在这几条里,而且每一条检查起来都很便宜:
- conntrack 表被清空,或者追踪器重启过。
- 主机重启过,或者这条流迁移到了别的 namespace 或设备。
- 非对称路由把 SYN 送上了你没有抓的路径。
- NAT 改写了 tuple,所以这条表项不再对应你读到的内容。
- 抓包开始得太晚,从来没有看到开头。
每一条都会把更早的包从追踪器的视野里移走,同时让更晚的包保持完整。重启或清表最容易用 uptime 和日志确认。非对称路由表现为单向抓包。NAT 是最阴的一条,因为追踪器存的 tuple 并不是日志里打印的那个 tuple。
在继续之前,写下你排除了哪几条,以及怎么排除的。
读 tuple、接口和 hook
conntrack 表项以地址、端口和协议为键,所以任何转换都会改变哪一条表项匹配。也要记下接口和 hook,因为出现在错误接口上、或者经过别的链之后的包,说明路径和图里画的不一样。当事件涉及 VPN 时, 判断你看的是内层包还是外层承载。然后和网关针对同一个五元组记录的内容对比。
对同一条流的两种互相矛盾的视角,比其中任何一种单独看都更有信息量。
什么时候值得升级处理
当你能拿出一个本不该可达却可达的服务,并附带这条流、放行它的策略以及两端的证据时,才升级处理。不要只凭一个状态标签或一次不完整的抓包就报告服务商缺陷,因为那份报告会被你刚读到的解释直接关掉。如果服务确实暴露了,那条边界的负责人就是该修它的人,而委托出去的端口映射或意外的监听者,比一个 bug 更可能是原因。
然后再补上让一个包看起来像整段会话的可见性缺口。