ESP 是 IP 协议 50,不是 TCP 端口 50:该放行什么
协议号与端口号是两个不同的命名空间。为 TCP 端口 50 写的规则什么也放不进来,而 NAT 穿透会把 ESP 挪到 UDP 4500。
防火墙的表单只问 TCP 端口,最顺手的填法就是 50。这条规则什么都不会放行,因为 ESP 是 IP 协议号 50,而协议号不是端口。两个命名空间只是共用了一些小整数,别的毫无关系;这个错误在 IKE 完成、受保护流量始终不来之前一直看不见。
共用小整数的两个命名空间
IP 首部有一个协议字段,用来说明后面跟着什么:TCP 是 6,UDP 是 17,ICMP 是 1,ESP 是 50,AH 是 51。TCP 或 UDP 首部则带有端口号,用来在目标主机上选择进程。协议 50 和 TCP 端口 50 是互不相干的两个值,只是对话框容易让人以为可以互换。
所以端口转发规则表达不了原生 ESP。ESP 没有可转发的目标端口,而只懂端口规则的设备对这种报文根本没有词汇。正确的规则应当指明 IP 协议。任何端口对话框对这个报文都是错的工具。
这层混淆还有后半段。报文被加密后,里面的一切都不可见,包括原连接的 TCP 首部。防火墙去检查这种报文的端口,看的是外层首部,而原生情况下外层根本没有端口可查。
先原生 ESP,再谈封装替代
原生 ESP 直接作为 IP 协议承载,效率高和麻烦多是同一件事的两面。效率高是因为没有额外首部,麻烦多是因为任何做地址和端口转换的设备都跟不住它。NAT 穿透正是为此存在:把 ESP 报文包进 UDP,让转换设备有端口可改写。
| Form on the wire | How it is identified | What the firewall must permit |
|---|---|---|
| IKE negotiation | UDP with a destination port | UDP 500, and 4500 once traversal is detected |
| Native ESP | IP protocol 50 in the outer header | The protocol itself, with no port to name |
| ESP inside UDP | UDP 4500 carrying an ESP payload | The UDP port pair, which translation devices can track |
两种形态是同一数据通道的两种部署,不是一层套一层。放行原生 ESP 不等于放行封装形态,放行 UDP 4500 也不等于放行原生流量,所以规则集要跟部署对齐,而不是碰巧把两种都覆盖上。
识别同样重要。两端在协商时决定用哪种形态,切换通常发生在它们之间探测到 NAT 的时候。因此隧道建立之后路径一变,流量就可能跑进你的规则从未覆盖的命名空间里。
查清连接实际用的是哪种形态
去问端点,别对着防火墙猜。在 Linux 上,状态条目会报告关联是否使用 UDP 封装、涉及哪些端口。抓包能从线路上回答同一个问题,两者都比读一遍规则集然后祈祷快。
ip xfrm state | grep -A3 encap
tcpdump -ni any 'ip proto 50 or udp port 4500'
第一条命令在用到 NAT 穿透时给出封装类型,没用时什么也不显示。第二条显示两种形态里哪一种真的在过接口,这能把“配置看着没错”的争论一次了结。
反向证据要放在同一步里。一条报零命中的规则是在告诉你报文从没到过它,那是路由或选择器的问题,不是防火墙的问题。
然后单独确认控制通道。IKE 有自己的端口和日志,协商完成却没有数据,正是本文所说的那段割裂。
把规则写在正确的命名空间里
协议规则和端口规则是两条不同的指令,工具必须表达你想说的那一条。nftables 里协议匹配是显式的,封装形态则另有自己的 UDP 规则。两条规则放在一起,复核时才看得出这是一对。
nft add rule inet filter input ip protocol esp accept
nft add rule inet filter input udp dport { 500, 4500 } accept
别为了让错误诊断自圆其说而放宽任何一条规则。在每个接口上对 ESP 协议全放行,或者放开任意到任意的 UDP,能压住症状,却把你本来想建立的管控全拆了。形态一旦确定,窄口径的支持流向几乎总是够用。
最后,隧道通了应用不通时,别把层搞混。到达网关的报文仍然需要转发、回程路由和放行策略,这些都不是 ESP 规则能表达的。缺端口解释的是一类具体故障,不是所有 IPsec 故障。把改规则和查路由当成两个独立结论。
把观察到的形态、新增的协议规则、事后看到的计数器记下来。三行字,下一个人就能在一分钟内分清命名空间错误和路由错误,而不是耗掉一下午。