防火墙能否放行一条 VPN 隧道,取决于两条彼此独立的规则:客户端拨号所用的端口,以及承载载荷的协议。只开前者,隧道能完成认证,却不再传输任何数据。最低配置是:PPTP 需要一个 TCP 端口加 GRE,L2TP/IPsec 与 IKEv2 需要两个 UDP 端口加 ESP,SSTP、OpenVPN 和 WireGuard 各需一个端口。方向、状态跟踪和 NAT 决定其余部分。

从客户端拨号的端口开始

每一类协议都有一个客户端最先联系的入口,放行规则必须点名这个入口。PPTP 客户端连接 TCP 1723。L2TP/IPsec 在 UDP 500 上启动 IKE,启用 NAT 穿越后转到 UDP 4500,L2TP 帧本身位于隧道内的 UDP 1701。SSTP 用 TCP 443 上的 TLS 封装会话,IKEv2 在 UDP 500 和 4500 上协商,OpenVPN 默认用 UDP 1194,但常被改到 TCP 443,WireGuard 则在 UDP 51820 上监听。

FamilyRule to add on the gatewayTypical mistake
WireGuardUDP port from ListenPort, for the peer addressAssuming 51820 when the config says otherwise
OpenVPNThe configured UDP or TCP port, often 443Opening 1194 after the server moved
SSTPTCP 443 limited to the gateway IPAllowing 443 to any destination
IKEv2UDP 500 and UDP 4500, plus ESPAllowing only 500 and losing NAT-T
L2TP/IPsecUDP 500, 4500, ESP, and 1701 inside the tunnelExposing 1701 to the internet
PPTPTCP 1723 and IP protocol 47Writing a rule for TCP 47

这些数字应视为默认值,而非固定属性。WireGuard 接口使用其配置声明的任意监听端口,OpenVPN 服务器也可以停在管理员选定的任意端口上。写规则前先读服务器配置,因为为 1194 打开的防火墙对已迁到 443 的服务器毫无用处。

第三列正是大多数变更工单出错的地方。规则存在,却指向错误的目地、方向或传输方式。

GRE 与 ESP 是协议号,不是端口

GRE 与 ESP 根本没有端口,所以只接受端口号的防火墙表单无法表达它们。GRE 是 IP 协议 47,ESP 是 IP 协议 50,两者都通过 IP 头中的协议字段匹配。把规则写成 TCP 端口 47 什么也匹配不到,PPTP 策略看起来正确,却在握手之后丢弃每一个数据包。

家用路由器把这件事藏在“穿透”勾选框后面,勾选后会安装协议规则,对 GRE 还会装上映射流量所需的 NAT 辅助模块。在真正的防火墙上要自己加协议:允许 IP 协议 47 到 PPTP 服务器,允许 IP 协议 50 到 IPsec 网关。平台没有协议字段时,封装就是出路,这也是 IKEv2 能回落到 UDP 4500、OpenVPN 和 WireGuard 从不遇到该问题的原因。

责怪客户端之前,先确认规则实际匹配的是什么。网关上始终为零的包计数器说明规则从未触发,客户端怎么重装都改变不了这一点。

方向、状态与 NAT 会改变答案

客户端向外拨号与网关向内监听是两种不同需求,同一份端口清单可能在一个方向上正确、在另一个方向上错误。有状态防火墙会跟踪 500 和 4500 上的 UDP 流,无需第二条规则就能让回包通过。ESP 与 GRE 不带端口,NAT 设备没有可依据的字段,需要辅助模块或封装才能跟随会话。

NAT 穿越是最容易被漏掉的部分。IKEv2 从 UDP 500 开始,检测到 NAT 设备后继续用 UDP 4500,因此只放行 500 的策略会得到一条建立后随即沉默的隧道。L2TP/IPsec 也做同样动作。如果抓包只看到第一次交换而没有持续流量,就去找停在 500 的规则。

每条规则都要记下方向。“允许 UDP 4500”在没说清从哪到哪之前毫无意义,而对漫游客户端正确的规则,对站点到站点的对端通常是错的。

用抓包检查每条路径

抓包要在网关上做,而不是在客户端上:客户端只记录到达的东西。以下过滤器覆盖上述各类协议,并指出缺失的是哪一步:

sudo tcpdump -ni any tcp port 1723
sudo tcpdump -ni any udp port 500 or udp port 4500
sudo tcpdump -ni any proto gre
sudo tcpdump -ni any proto 50

把输出当作序列来读。协商出现而载荷协议不出现时,丢包发生在客户端与网关之间的某处。两者都出现而页面仍然失败时,防火墙已不再是嫌疑对象,去看路由、DNS 或分配给客户端的地址池。

没有 tcpdump 的机器上,同样的证据来自接口计数和规则计数。隧道接口上字节只进不出,指向的是回程路径,而不是最初的放行规则。

留下一套站得住脚的规则

TCP 443 上的 SSTP 对任何基于端口的过滤器来说都与普通 HTTPS 无法区分,网络只允许 Web 流量时这正是关键。443 规则因此应把网关而非整个互联网写成目的地。隧道一通就删掉临时的任意到任意规则。写清哪条规则命中、协议号(如有)以及方向,让下一个人从证据出发。

云上的点到站点网关让选择变得可见:下载的配置文件要么用 443 上的 SSTP,要么用 500 与 4500 上的 IKEv2,只应放行配置实际选中的那一个。在现代网络里 PPTP 不值得为它开 GRE 例外,因为移动运营商常常无视你的防火墙丢弃协议 47。关单前确认规则与服务器配置中的端口一致、协议字段在需要的地方已设置、目的地是网关而不是任意地址。

相关文章