绑定到接口索引的 VPN 路由在重新连接后失效
绑定到适配器编号的路由会随着编号改变而失效。先查看路由存储,把前缀绑定到配置文件,再按新的顺序重新连接。
这条路由稳定运行了数周,随后开始把流量发往无处,而目标地址没有变化,也没有人修改过任何配置。变的是编号:一条针对某个具体接口索引创建的路由,在重新连接后指向了一个已不存在的适配器,而目标前缀仍然指向被替换掉的基础设施。给那条命令加上持久化并不管用,因为问题从来不是路由能否撑过重启。正确的做法是把意图绑定到连接上,连接在设计上就能承受适配器的更换。
先确认这条路由到底指向哪里
把路由条目和适配器列表并排读一遍。一条在 VPN 接口上设置下一跳、而索引与当前任何适配器都不匹配的路由,就是这种故障的特征;同一前缀挂在另一个索引上,要么是残留,要么正是你想要的路由。改动任何一边之前先把两份清单读完,因为真正值得比较的是路由里的编号与当前存在的编号。如果路由的索引出现在适配器列表里,那索引就不是问题所在,排查方向要转到度量值、策略或远端。如果索引根本不存在,就不必再往下诊断了:这条路由挂在一套已经不存在的基础设施上。
Get-NetRoute -DestinationPrefix '10.77.0.0/16' | Select-Object DestinationPrefix, NextHop, InterfaceIndex, Store
Get-NetAdapter | Where-Object InterfaceDescription -like '*VPN*' | Select-Object Name, InterfaceIndex, InterfaceDescription
Get-VpnConnection -Name 'Lab VPN' | Select-Object Name, ServerAddress, SplitTunneling
Store 列区分重启后仍然保留的条目与随适配器一起消失的条目,而这个差别决定了故障明天会不会重现。持久存储里指向已消失索引的条目是最坏情况,因为它能撑过重启,却永远匹配不上任何东西。
把前缀绑定到配置文件,而不是适配器
Windows 原生 VPN 可以携带自己的路由列表,于是连接每次建立时都会复用正确的适配器。路由随后跟随配置文件,而不是跟随你只观察过一次的编号,也不再有脚本需要在每次拨号后猜一个索引。添加前缀同样可以用对应的删除命令撤销,这让变更保持可审计。前缀随连接一起保存,而不是写在启动脚本里,因此复制给另一位用户的配置文件会把意图一并带走。
Add-VpnConnectionRoute -ConnectionName 'Lab VPN' -DestinationPrefix '10.77.0.0/16' -PassThru
Add-VpnConnectionRoute 的参考文档记录了与连接的关联,而电话簿的作用域很关键:单用户配置文件与所有用户配置文件是两个不同的对象。这套机制属于 Windows 自带的 VPN 客户端,因此由厂商自己的服务管理的适配器,可能完全从另一个策略来源取路由。
添加新路由之前先清理旧路由
同一前缀下存在两个不同归属的路由,比一条错路由更糟,因为谁胜出取决于没人记录过的度量值。先查清该前缀已经存在什么,包括持久存储里的条目,只删除属于那次失败尝试的部分。这一带常见上一版设计留下的残留,因为失效的路由通常替换掉了原本能用的东西。删除任何东西之前先记下哪条条目属于哪个连接,并把清单留在变更记录里。
Get-NetRoute -AddressFamily IPv4 | Where-Object DestinationPrefix -like '10.77.*'
Remove-NetRoute -DestinationPrefix '10.77.0.0/16' -NextHop '0.0.0.0' -Confirm:$false
把前缀、下一跳、存储与归属一起比对,而不是把所有看起来相似的条目一扫而空。另一个连接可能合法地依赖这段地址空间的一部分,一次性清空会把一次整洁的修复变成一起支持事件。
换一个顺序重新连接
复现那个条件,而不是寄望第一次尝试有代表性。断开、重连,并在隧道建立时确认通往同一远端资源的所选路径;如果有多个 VPN 参与,就换一个顺序把它们拉起来,观察所选路径是否改变。顺序是大多数人会跳过的那一项,而恰恰是它暴露了挂在错误连接上的路由。
rasdial 'Lab VPN' /disconnect
rasdial 'Lab VPN'
Find-NetRoute -RemoteIPAddress 10.77.5.20 | Select-Object -First 1
你要的结果不是适配器侥幸保住了编号一次。而是无论连接拿到哪个编号,路由每次都随之出现,并在连接关闭时消失。重连两次是区分这两种结局最便宜的办法。
要知道这条路由做不到什么
配置文件路由只提供一条路径,别的什么也不提供。它不会打开远端的防火墙,不会在远端建立回程路由,也不会解决两个站点使用同一地址段的问题;这些各自都是独立的配置,各有各的归属。因此确认路径只是验收测试的开始,而不是全部。
把前缀清单和配置文件放在一起,并注明它是在哪个作用域下添加的,这样后来者能读到原本的设计,而不必从路由表里反推。只存在于某人记忆里的路由,才是下一次重连后被错误重建的那些。部署笔记里一行注释,比花整个下午重新发现要便宜。