pptpd 上的 GRE 写入失败不是密码问题
协议 47 不是端口 47。把 pptpd 的两条消息当作两种不同故障来读,在主机真正转发的地方放行 GRE,并保留 MPPE 而不是关闭它。
日志里出现 GRE 写入失败,第一反应是重置用户密码。这个反应几乎总是错的。这些消息描述的是数据路径,而不是凭据校验:客户端可能已通过认证,却卡在向网络注册的阶段。两条不同的消息指向两种不同的故障,换新密码一条都解决不了。
两条消息,两种故障
读取失败意味着 GRE 数据包从未到达守护进程,或在入口处被丢弃。控制连接看起来可能完全正常,但数据路径上没有任何东西通过。认证是唯一被证明有效的环节。
写入失败通常意味着会话协商出了内核或客户端无法使用的东西。控制通道已经完成,而那次交换中商定的选项与端点实际能力不符。这是配置分歧,不是认证事件。
在改动任何东西之前,先读清楚出现的是哪一种。它们指向不同层次,把它们当成同一个症状,正是一台服务器因无关原因被修两次的由来。日志行是你唯一免费拿到的诊断。
协议 47 不是端口 47
PPTP 用 TCP 1723 建立呼叫,用 GRE 承载负载。GRE 是 IP 协议 47,不是端口号,所以打开端口 47 的防火墙规则放行不了任何有用的东西。
路径上的路由器需要 PPTP 透传功能或明确的 GRE 放行。没有它,TCP 握手能完成,隧道却一个包也带不过去,正好产生上面的读取失败。防火墙里的端口 47 规则是这个协议中最常被浪费的下午。
与其猜哪一侧丢弃流量,不如在服务器上同时观察两个方向:tcpdump -ni any port 1723 or proto gre。
如果 1723 显示呼叫建立而 GRE 保持沉默,阻断在主机上游。如果 GRE 到达而守护进程仍然失败,问题在本地,选项就是下一个要看的地方。
在主机真正转发的地方放行 GRE
为 GRE 插入一条 forward 规则,在转发隧道流量的主机上是合理的测试,而不是策略。接受某个协议全部流量的测试规则是诊断,不是设计。放足够久以学到东西,然后换成范围受限的规则。
为发往服务器自身的包添加 input 规则,因为 forward 链看不到它们。然后在连接尝试前后观察规则计数器,这能告诉你包到底有没有到达。
通过发行版的防火墙服务让规则持久,而不是每次重启后重新执行。在 nftables 主机上,在 input 和 forward 两条链中都匹配 ip protocol gre。
确认 ppp_generic 模块也已加载,并检查连接跟踪是否丢弃了返回方向。两者都会造成看似防火墙问题、实则不是的故障。缺少内核模块在检查之前看起来和协议被封堵一模一样。
让选项匹配你实际拥有的客户端
另一份报告的修法在 /etc/ppp/pptpd-options 里:配方拒绝 PAP、CHAP 和 MSCHAP,注释掉对应的 require 行,并保留有状态 MPPE。那份配方是为一种客户端组合写的,盲目照搬会破坏常见情形。把拒绝行读作关于作者当时有哪些客户端的陈述,而不是推荐。
Windows 客户端通常需要 MS-CHAPv2 配合 MPPE-128。保留这些要求,只删掉客户端确实无法协商的选项。
# keep encryption; drop only what this client cannot negotiate
refuse-pap
refuse-chap
refuse-mschap
mppe-stateful
require-mschap-v2
require-mppe-128为了让连接成功而关闭加密是降级,不是修复。这种变体要在实验线路上测试,然后在服务面对真实客户端之前恢复加密。不安全但能连上的连接,比诚实失败的连接更糟。
读客户端的错误号
客户端的数字错误码比服务器日志更快锁定阶段。先读它,再读别的。691 表示凭据被拒绝,721 表示服务器从未应答,619 表示连接断开。花两分钟看这个号码,能省下配置上的一小时。
编辑任何东西之前,先把那个错误码和服务器日志对照,每次改动后用同一个客户端重测。否则第二个故障躲在第一个后面,修复看起来毫无效果。
当登录成功却没有流量移动时,GRE 仍是嫌疑对象。那一刻该回到抓包,而不是回凭据库。