隧道已经建立,网关能响应 ping,文件共享却仍然超时。这种组合很少是路由问题:Windows 把 VPN 适配器的子网放进了公用配置文件,而为专用或域配置文件编写的允许规则一条都没有生效。我在能正常访问办公室的笔记本上遇到过,也在为所有其他客户端提供服务的 RRAS 服务器上遇到过;只要点明当前生效的配置文件,修复就很短。下面是我的工作顺序,以及一个让你在进入下一步之前就该停下的检查。

查明流量实际落在哪个配置文件上

Windows 防火墙没有单一的全局模式。每个已连接的接口都带有一个类别,入站数据包按其所到达接口的类别过滤,所以决定隧道内客户端能访问什么的是 VPN 适配器的配置文件,而不是旁边的 Wi-Fi 或以太网适配器。改动之前先读清两件事:

Get-NetConnectionProfile | Select-Object Name, InterfaceAlias, NetworkCategory, IPv4Connectivity
Get-NetFirewallProfile -Name Public | Select-Object Name, Enabled, DefaultInboundAction

在标准的 OpenVPN 或 WireGuard 安装中,VPN 适配器会显示为未识别的网络并落入公用配置文件;这是 Windows 无法分类的任何网络的默认值:没有域控制器通过它应答,也没有任何网关配置文件匹配。接口名称在这里无关紧要,所以把适配器叫作“VPN”或“Corp”不会改变任何东西。DomainAuthenticated 需要一台已加入域的计算机, 而且它必须能通过该接口真正访问域控制器;只承载一个子网的拆分隧道无法满足这一条件。

如果你需要的规则已经限定在 VPN 池内,并且已经对你刚读到的类别生效,就停在这里:过滤不是你的层面,下一个要查的地方是服务配置。这一检查只需十秒,却能省下一小时的规则编辑。类别名称以及各类别覆盖的范围见Get-NetConnectionProfile 参考文档。

在修改规则之前,先确认是过滤而不是路由

Ping 是弱测试。ICMP 能通过,服务端口却可能被丢弃;主机能从局域网应答,却拒绝经隧道发来的同一请求。从客户端测试客户端需要的端口:

Test-NetConnection 10.8.0.1 -Port 445
Test-NetConnection 10.8.0.1 -Port 3389 -InformationLevel Detailed

如果端口测试失败,就把两层分开。隧道或路由故障通常表现为网关地址完全没有应答,而防火墙丢弃则表现为网关有应答、服务端口没有应答。在通过 RRAS 发布池的 Windows 服务器上,从客户端执行同样的测试,并读取服务器自身的配置文件:RAS 接口可能处在某个类别中,其入站规则从不提及客户端网段,这就是这台机器能服务自己的局域网、却拒绝所有隧道客户端的原因。

当结果仍然含糊时,为当前配置文件记录丢弃日志并阅读它们:

Set-NetFirewallProfile -Name Public -LogBlocked True `
  -LogFileName "$env:systemroot\system32\LogFiles\Firewall\pfirewall.log"

写明客户端地址和端口并标记 DROP 的条目是决定性的,它们同时告诉你缺了哪条规则。当日志为空、客户端的 SYN 从未出现时,问题指向主机上游,所以在动另一个防火墙对象之前,先回到隧道、NAT 规则或池路由。

把一条入站规则限定到客户端池

修复只需一条入站允许规则,其远程地址是池,而不是全世界。从提升权限的会话执行:

New-NetFirewallRule -DisplayName "VPN clients - SMB 445" `
  -Direction Inbound -Action Allow -Protocol TCP -LocalPort 445 `
  -RemoteAddress 10.8.0.0/24 -Profile Public

当服务是单个二进制文件时,优先使用按程序限定的规则,配-Program,而不是端口列表;这样例外同时被限制在进程和来源网段内。

配置文件选择正是同一个错误在反方向发生的地方。-Profile Public在适配器为公用且保持公用时就够了。-Profile Any在服务无论 Windows 如何分类适配器都必须工作时是站得住的,但前提是远程范围仍然保留。永远站不住的是-RemoteAddress Any用在公用配置文件上:那条规则会跟着笔记本进入它加入的每一家咖啡馆和酒店网络,并把端口开放给共享该子网的任何人。

把池记录在规则旁边。-RemoteAddress 10.8.0.0/24在 VPN 池重新编号的那天会悄然不再匹配,而故障看起来和最初的 bug 一模一样,这就是它会再吃掉一个下午的原因。按服务和来源网段给规则命名,用-Group把它们放在一起,并在池定义变化时重新阅读。能在一屏内审计的规则清单,胜过一条没人找得到的正确规则。

仅在类别本身就是决定因素时才改动类别

把接口改成专用同样可行,但那是错误的默认做法。专用配置文件带有大量内置允许规则,涵盖文件和打印机共享、网络发现、远程桌面,以及取决于基线的更多内容,因此把 VPN 适配器重新分类会一次性为隧道内的每个客户端全部启用。一条限定范围的规则只把一个服务授予一个网段。在同样会接入不受信任网络的笔记本上,这个差别不是表面的。

有些情况下分类确实是错的:承载办公子网的始终在线或站点到站点隧道属于可信基础设施,把该适配器标记为专用是一次性通过策略做出的合理设计选择,而不是每个工单都做一次。真要做时,就明确地做:

Set-NetConnectionProfile -InterfaceAlias "OpenVPN TAP-Windows6" -NetworkCategory Private

在受管设备上,先检查该设置是否由组策略或 MDM 基线掌管。如果由它们掌管,本地改动会在下次刷新时被撤销,而gpresult /h会指出掌管它的策略;要在那里修,而不是在终端上修。

从两端验证并留下记录

在改动之后,从客户端验证用户报告的流程:

Test-NetConnection 10.8.0.1 -Port 445
Get-NetFirewallRule -DisplayName "VPN clients - SMB 445" | Get-NetFirewallAddressFilter | Select-Object RemoteAddress
Get-NetFirewallRule -DisplayName "VPN clients - SMB 445" | Get-NetFirewallPortFilter | Select-Object Protocol, LocalPort

然后收尾那些下周会出问题的地方。重启主机并重新测试,因为限定在错误配置文件上的规则会一直有效,直到适配器以另一个类别回来。从第二个客户端测试,因为一个持有过期租约的客户端会掩盖池不匹配。把新增的规则与删除的规则对账,因为正是重叠的例外让两行修复变成没人能审阅的过滤策略。

在宣布完成之前:

  • 规则中写明的配置文件,就是流量所到达接口上的配置文件。
  • 远程范围是 VPN 池,而且该池与服务器实际分配的地址一致。
  • 你新增的规则没有一条使用-RemoteAddress Any于公用配置文件。
  • 没有为了通过测试而关闭任何东西,任何类别改动都记录了谁批准了它。

相关文章