家用路由器后的 PPTP 服务器:先修 1723 和 GRE
在家用路由器后运行 PPTP:TCP 1723、IP 协议 47、穿透勾选框与 MTU 计算,以及何时 L2TP 或 OpenVPN 是更划算的替换。
家用路由器后的 PPTP 会以两种互不相关的方式失败,混为一谈会白白耗掉一整晚。一类故障是转发缺口:路由器放行 TCP 1723 却丢弃 IP 协议 47,客户端就卡在 619 错误上。另一类是尺寸问题:隧道建立并通过认证,随后在必须传输满尺寸数据包时僵住。先弄清你遇到的是哪一种,才是真正的第一步;其余部分比较的是路由器能表达什么,而不是哪个品牌更好。
两种传输,只有一个有端口
PPTP 分成两条传输:TCP 1723 上的控制连接,以及封装在扩展 GRE(即 IP 协议 47)中的 PPP 帧。GRE 没有端口号,所以写成“转发 1723 端口”的规则覆盖不到它,无论网页界面把那个字段叫什么。家用路由器通常提供名为 PPTP 穿透的勾选框而不是协议规则,这个勾选框做两件事:让协议 47 穿过防火墙,并教会 NAT 跟踪 GRE 流。在 Linux 路由器上这两件事是不同模块和不同规则,所以只配一半的穿透仍能得到可用的控制通道。改动任何设置前,先确定缺的是哪一半。
服务器自身的防火墙也必须放行来自路由器地址的协议 47。只接受 1723/tcp 的主机防火墙会从局域网内部复现 619 错误,使转发中断和主机规则中断看起来一模一样。
sudo iptables -S FORWARD | grep -i gre
sudo nft list ruleset | grep -i gre
lsmod | grep -E 'nf_conntrack_proto_gre|nf_nat_proto_gre'
缺少模块时,用 sudo modprobe nf_conntrack_proto_gre nf_nat_proto_gre 加载并让加载持久化,因为重启后忘记加载会把可用的隧道重新变成 619 错误。转发规则只应放行指向服务器地址的协议 47,而不是整个局域网。RFC 2637 的定义把控制路径与数据路径分开,因此没有任何单个端口转发界面能完整描述 PPTP。
穿透勾选框还是明确的协议规则
只打开防火墙的穿透勾选框比改写呼叫标识符的 ALG 更接近正确做法。防火墙这一半是可预测的:协议 47 要么被接受要么被丢弃,计数器会告诉你是哪种。改写那一半才是各厂商分歧所在,因为 PPTP 的呼叫标识符是每个隧道独立的,负责编辑它们的 NAT 必须跟踪每一个被触碰的呼叫。当一个客户端能连而两个不能时,ALG 是第一嫌疑人。
为 1723 设置的目标 NAT 规则也有归属问题。如果旧规则仍把 1723 送到已经停止运行服务器的机器,数据包落在关闭的端口上,路由器自带的 PPTP 服务也停止应答,看起来像防火墙故障,实际是过时的目标。添加第二条规则前,先读清楚规则及其目标。在自行终结 PPTP 的路由器上,WAN 规则会与内置服务竞争,所以 1723 和协议 47 只能有一个归属者。
同一 NAT 后面的两个客户端,正是区分简单转发与聪明转发的情形。不改写呼叫标识符而直接转发协议 47,通常比试图替它修修补补的助手表现更好。
先测量隧道,再怪路由器
PPTP 会缩小可用负载,而这点缩小是算术,不是谜题。每个隧道包都带一层外部 IP 头、一层扩展 GRE 头、一层 PPP 头,启用加密时再加一层 MPPE 头。当路径无法承载由此产生的帧时,小包能过去,登录也能完成,而在文件传输或 TLS 握手第一次发出满尺寸包时,会话就停住了。
算出数字,别猜。扩展 GRE 占 8 字节,PPP 占 4,MPPE 占 4,外部 IP 头占 20,所以隧道在任何负载之前先吃掉 36 字节。在 1492 结束的 PPPoE WAN 上,能容纳的最大 PPP MTU 是 1492 减 36,即 1456。在 PPP 选项里把 mtu 和 mru 设为该值,再用不分片的 ping 复测。
ping -M do -s 1464 198.51.100.7
grep -E '^(mtu|mru)' /etc/ppp/options.pptpd
ping 测的是路径而不是隧道:1464 字节负载加上 28 字节 IP 与 ICMP 头,正好填满 1492 字节的帧。如果这个 ping 失败,就往下调数字直到通过,再从结果里减去 36。把隧道 MTU 设在路径上限之上,就会在没有一行提到尺寸的日志的情况下造成卡死。
同一台路由器上的 PPTP、L2TP/IPsec 或 OpenVPN
同一台路由器可以承载三种常见隧道中的任何一种,区别在于它必须表达什么。PPTP 需要在两个不同层上各写一条规则。IPsec 之上的 L2TP 需要 UDP 500 和 4500 做密钥交换,如果 NAT-T 不承载,还需要协议 50 承载负载。OpenVPN 只需要一个 UDP 端口,完全不需要助手。
| Tunnel | What the router must allow | Practical note |
|---|---|---|
| PPTP | TCP 1723 and IP protocol 47 | Two transports, two rules |
| L2TP/IPsec | UDP 500, UDP 4500, protocol 50 without NAT-T | ESP has no port either |
| OpenVPN | UDP 1194 or a chosen TCP port | Single rule, no helper |
L2TP 这一栏并不自动比 GRE 更友好。ESP 是 IP 协议 50,同样没有端口,所以对协议 47 有困难的路由器可能因同样原因对协议 50 也有困难。NAT-T 的存在是为了把 ESP 包进 UDP 4500,两端都支持时协议 50 的规则就不再需要。这是两端的特性,不是路由器 PPTP 勾选框的特性。为两者写规则之前,先确认客户端实际协商的是哪种封装。
OpenVPN 是路由器侧活动部件最少的选项。一个 UDP 端口、一条转发、没有连接跟踪助手,也没有呼叫标识符改写。交换条件是要安装客户端而不是用内置拨号器,这常常是 PPTP 仍留在讨论里的唯一原因。
该修什么,该换什么
修好转发和 MTU 得到的是能用的隧道,而不是该长期保留的隧道。PPTP 的 MSCHAPv2 认证多年前就可被攻击,一条能用的隧道会传输可离线还原的凭据。如果远端设备能跑 L2TP/IPsec 或 OpenVPN,就把修复当作带日期的临时措施。
决定因素在于远端支持什么,以及这套安排需要撑多久。只会 PPTP 的老设备得到修复;任何能安装客户端的地方都迁移。
关闭工单前,确认客户端能扛住一次大传输而不只是登录成功,并确认重启后路由器仍保留协议 47 规则。只过了一次文件拷贝、在下一次固件升级后就失效的隧道,从来都不算完成。