Ping 只能单向工作:Windows 为何丢弃服务器的回显
客户端 Ping 能成功,是因为防火墙放行了应答而非请求。沿相反方向追踪回显,并把一条规则限定在隧道上。
你的客户端能 Ping 通服务器,服务器却 Ping 不通客户端,而这两句话里隧道显然都在双向搬运数据包。不同的不是路径,而是每次测试的第一个数据包:一个是对 Windows 已在跟踪的流的应答,另一个是没有任何规则放行的全新入站请求。正是这个差别解释了大多数单向 Ping 的报告,并直接指向你要写的那条规则。朝两个相反方向各做一次测试,大约一分钟就能把两种情况分开。
两个方向,两种不同的判断
客户端发出回显请求时,Windows 防火墙看到的是一条它已经决定放行的出站连接。应答沿着这条已建立的流返回,于是有状态引擎直接放行,完全不去查询任何针对 ICMP 的入站规则。这就是有状态过滤在实践中的含义,而那条没人写过的规则根本没有参与。所以客户端的成功并不能说明入站策略如何。
服务器先发出请求时,没有任何状态与之匹配。Windows 把这个包当作新的入站连接,去询问入站策略,而默认策略对来自任意来源的回显请求毫无安排。
也就是说,客户端的成功只证明出站 ICMP 和返回路径是通的。它从未检验入站判断,而防火墙没问题这个自然的结论看似合理,其实是错的。这就是为什么这个错误会在已经带着证据的工单里反复出现。
跟踪数据包,直到它消失
改动之前先确认地址:使用客户端实际持有的隧道地址,并核实服务器路由到的是它,而不是客户端背后的局域网地址。从服务器的命令提示符看,两种故障完全一样,因为都以超时收场。数据包死在哪里,才是决定该改什么的唯一事实。
如果请求到达了隧道接口却没有东西出去,最可能的原因是本地防火墙。如果它根本没到达接口,答案就在上游:服务器上的路由、出站策略,或者 VPN 自身的对端投递。
在服务器 Ping 的同时,于客户端的隧道接口抓包。看到请求到达而旁边没有应答,就是支持写一条 Windows 规则的证据。什么都看不到则把你指向上游,而在那种状态下加规则,只会让这台机器对一个从未到达的数据包更宽松。无论哪种情况,抓包都比它替代的猜测便宜。
限定一条规则,而不是打开 ICMP
写任何东西之前,先确认适配器及其当前类别,因为两者都会出现在你即将设定的范围里。那个别名是 Windows 的接口名,未必是你导入的 VPN 配置文件的名称。下面的命令会列出存在的东西,然后在不应用的情况下预览一条限定范围的规则。
Get-NetConnectionProfile
Get-NetAdapter | Where-Object Status -eq 'Up'
New-NetFirewallRule -DisplayName "VPN server echo" -Direction Inbound -Protocol ICMPv4 -IcmpType 8 -RemoteAddress 10.63.0.1 -InterfaceAlias "Office VPN" -Profile Private -Action Allow -WhatIf
ICMPv4 类型 8 就是回显请求,是服务器唯一需要应答的消息。把它限定在服务器的隧道地址和隧道接口上,并让配置文件保持适配器真实的样子。为了迁就示例而重命名网络,是另一项自带后果的改动。
这条规则并不覆盖什么
IPv6 的回显是另一种协议、另一种消息类型,所以 ICMPv4 的规则对它什么也没说,而承载两套地址族的隧道需要为另一套单独写规则。这条规则也不打开别的任何东西:RDP、文件共享以及其他每项服务仍然取决于各自的策略。与其启用宽泛的 ICMP 许可,不如限定一条窄规则,这才是全部要义。宽泛的许可才是省事的修法,也是最长久的那一种,因为事后没人会注意到它。
在受管设备上,规则可能在下次策略刷新时被替换,所以必须由策略所有者而不是本地管理员做出等效改动。把意图连同命令一起写进工单,因为刷新会抹掉命令,却把需求原样留下。两者并不是同一件产物,而只有其中一件能存活。
从正确的方向读结果
规则生效后,从服务器 Ping 并确认应答到达客户端,再从仍应被排除的来源 Ping 并确认它到不了。如果隧道还承载另一套地址族,就在那边重复可达性测试。
Get-NetFirewallRule -DisplayName "VPN server echo" | Get-NetFirewallAddressFilter
ping 10.63.4.17
ping -6 fd00:63::17
打印真正生效的规则,比信任创建它的命令更有用,因为预览和应用后的规则是两种状态。如果地址筛选器显示的是你想要的来源,而被排除的来源仍然超时,那这条规则就确切做到了它范围所说的。从客户端发起的成功 Ping 永远证明不了这一点,所以每次测试的方向都该和结果一起记进记录。把两个方向都留在工单里,否则下一位读者会重复那个不可能失败的测试。