PPTP 分流不起作用:先修好 GRE 通路
PPTP 分流失败有两个不同原因:GRE 被拦截,或内部路由缺失。先测传输,再测策略。
看着 PPTP 连接建立起来,很容易以为难的部分已经完成:客户端通过认证,出现 ppp0 适配器或 WAN Miniport,状态窗口变成绿色。接着第一个发往内部主机的请求超时,于是有人怪罪配置文件。实际上有两层彼此独立的东西要处理:承载 TCP 1723 与 GRE 的外层传输,以及决定哪些目标走 PPP 接口的内层策略。绿色状态只能证明第一层协商成功,对第二层只字未提。
从配置文件到控制套接字,一步步追客户端的流程
打开客户端日志,找到它联系服务器的那一步。PPTP 先向 1723 端口建立 TCP 连接,并在这条通道上协商隧道参数。这一步失败,后面都无从谈起,错误通常点出服务器地址或超时。
在改动任何路由之前,先在线路上确认控制连接。在客户端或镜像端口上,抓一次连接尝试的 TCP 1723:
sudo tcpdump -ni any 'tcp port 1723' -c 20
握手完成并建立会话,说明外层控制通道是通的。始终收不到 SYN-ACK 的 SYN 指向防火墙、错误的服务器地址或过滤该端口的运营商。握手后立即复位,往往意味着服务器拒绝了凭据或隧道类型。
GRE 是第二种协议,不是端口
PPTP 把 PPP 载荷封装在增强型 GRE 里,也就是 IP 协议 47,它没有路由器能追踪的端口号。所以只放行 TCP 1723 的规则仍可能让隧道没有数据通路。有状态 NAT 设备必须理解 GRE 内部的呼叫 ID 才能把回包映射回来,很多设备做不到。PPTP 规范把控制通道与 GRE 载荷当作两个独立部分,测试计划也应如此。
在同一次抓包里观察协议 47,然后比较发出去和收回来的东西:
sudo tcpdump -ni any 'proto gre' -c 20
TCP 1723 保持正常、只出不回,就是典型的 GRE 被拦截。家用路由器的 PPTP 穿透是特定固件的功能,因此一家酒店网络能用,并不能说明下一家。如果路由器没有穿透选项且你无法更改,问题就在协议选择,而不在路由表。
证明隧道能送出一个包
GRE 一通,PPP 协商就会给客户端接口分配地址。去读这个分配,而不是想当然:
ip -4 addr show ppp0
对点到点链路对端地址发 ping。这一阶段有回包,说明封装后的通路端到端可用,服务器在隧道内应答。对端能回而内部主机不能回,说明外层传输没问题,故障已经转移到内层。
在做任何分流路由之前先完成这一步。传输还是坏的就改路由,只会多出一个变量,把第一个变量藏起来。
写分流策略,包括 DNS
分流路由是一串决策,不是一个勾选框。每个必须走隧道的私有前缀都需要一条经 PPP 接口的路由,每个必须留在本地的前缀都不该出现在其中。给应用子网加了路由,却没给它私有解析器加对应路由,是制造“应用坏了”这类故障的常见做法。
检查内核为每类各取一个地址时做出的决定:
ip route get 10.20.5.10
ip route get 203.0.113.25
第一个应显示 ppp0,第二个应是普通网关。两个都指向同一接口,说明策略根本没有分流。把 DNS 服务器自身的地址加入隧道列表,否则内部主机的域名解析会走本地解析器,拿不到有用的结果。
五步可重复的检查
按顺序逐层执行,第一次失败就停:控制通道、GRE 可见性、PPP 对端回包、一条内部地址的分流路由,以及一次经隧道的应用请求。每一步都有自己的命令,故障可以定位,而不是变成谜。
Linux 客户端的精简版如下:
sudo tcpdump -ni any 'tcp port 1723 or proto gre' -c 40
ip -4 addr show ppp0
ping -c 3 192.0.2.1
ip route get 10.20.5.10
Windows 上同样的顺序适用于 route print 和客户端显示的适配器状态。PPTP 是过时协议,如果服务器提供 SSTP 或 IKEv2,迁移通常比调一条依赖协议 47 逐跳通过的路径更值。检查替代方案的证书与认证约定,而不是把旧配置直接复制到新版本。