放行 IKE 与 ESP 却不放行 UDP 1701 的防火墙会让 L2TP 连接中断,故障表现看起来像凭据问题。原因是 L2TP 是运行在第一层协议内部的第二层协议。IPsec 负责承载并认证这次交换,而 L2TP 在 UDP 1701 上运行自己的隧道,本地协议栈仍然必须把它投递上去。搞清楚每个报头出现在哪里,就能判断哪台设备需要哪条规则。

两套协议,两套端口

一条 L2TP/IPsec 连接在 UDP 500 上使用 IKE,在存在地址转换时于 UDP 4500 上使用 NAT 穿越,在没有转换时则使用 IP 协议 50 的 ESP。L2TP 本身是运行在 UDP 1701 上的隧道协议,它在 IPsec 完成对端认证之后才开始工作。两半的失败方式不同,报告它们的日志行也来自不同组件。只覆盖前半部分的规则集会产出一条能完成协商、随后却死在隧道阶段的连接。

端口号描述的是传输层端点,而 ESP 根本不是端口。这就是为什么只提供 TCP 与 UDP 规则的防火墙界面无法表达完整的 IPsec 策略。协议 50 必须作为协议被放行,只提到 UDP 的规则永远匹配不到它。

封装层解释了端口

在线路上,一条 L2TP/IPsec 连接通常表现为 500 上的 IKE 和 4500 上被封装的 ESP。UDP 1701 报头位于受保护载荷内部,因此在外部接口上抓包看不到它。本地主机仍须把这个数据报投递给 L2TP 守护进程,而投递发生在解封装之后。所以 1701 规则应该放在端点自身的防火墙上,即使没有任何中间设备看到这个端口。

处理顺序解释了大部分困惑。如果协议栈先应用 IPsec 策略再过主机过滤器,解封装后的 L2TP 报文就按 UDP 1701 匹配;如果顺序相反,规则集看到的就是外部端口。两种行为在实践中都存在,这就是同一套规则集在一个平台上能用、在另一个平台上却失败的原因。

按顺序检查路径

先在外部接口抓包,确认 IKE 和被封装的 ESP 双向都在流动。然后查看本地防火墙针对解封装流量的计数器。顺序很重要,因为完全抓不到包意味着问题出在主机上游。

sudo tcpdump -ni eth0 'udp port 500 or udp port 4500'
sudo nft list ruleset | grep -i -A2 1701
sudo ss -lunp | grep 1701

抓包确认了交换的前半部分,并显示对端是否在应答。规则列表显示是否存在 1701 规则,以及它相对于任何丢弃策略的位置。套接字列表确认 L2TP 守护进程已绑定并在监听,从而排除从未启动的服务。改规则之前先把这三样都读完,因为缺少监听器和端口被过滤给用户带来的抱怨一模一样。

端口扫描无法显示的东西

对配置正确的服务器从外部扫描 UDP 1701 通常什么也报不出来,而这正是预期结果。该端口并不暴露在互联网上,只有在 IPsec 完成对端认证之后才能到达它。把这种关闭的结果当成故障,会导致打开一个本应保持关闭的端口。扫描看不到隧道内部,正如它看不到应用流量一样。

改用真实客户端测试,并 阅读它到达的阶段。如果连接完成协商后停住,嫌疑对象是 L2TP 守护进程或本地过滤器;如果它根本无法协商,那就是外部端口。仅凭这一刀切分就能消除大部分关于该加哪条规则的猜测,而协议分层让这一切变得可预测,而不是神秘。

相关文章