问 Windows 防火墙能否单独充当网络锁,你会得到两个自信却互不相容的答案。一种说法是按接口类型的规则就能包办一切;另一种说没有脚本根本不行。两者描述的其实是同一机制的一半。防火墙能够表达阻断,而结果是否真正故障关闭取决于三件事:Windows 如何归类隧道网卡、端点例外是否仍然有效,以及名称解析与 IPv6 是否被覆盖。任何一项出错,机器要么泄漏,要么彻底断网。

三个条件,顺序如下

第一个条件是分类,它决定你想要的规则是否表达得出来。Windows 防火墙规则可按接口类型限定:有线、无线或远程访问。若策略要在物理类型上拦截出站流量、同时放行隧道,只有当 Windows 把该隧道识别为远程访问时才成立。

第二个条件是端点例外。在任何隧道建立之前,客户端必须通过物理网卡访问 VPN 服务器,因此对那块网卡的全面拦截,恰好会挡住那个让拦截变得多余的连接。例外必须指明服务器及其端口,数据包必须从物理网关出去,而不是进入一条尚未建立的隧道。

第三个是覆盖面。只拦 IPv4 却忘了 IPv6 的规则集,或者为了端点查询放行本地解析器、从而放行其他所有查询的规则集,恰恰会在网络锁本该覆盖的那个窗口里失败放行。这是设计缺口,而非防火墙缺陷。它也是任何桌面测试都发现不了的缺口。

分类是第一道关卡

在写下第一条规则之前,先看看 Windows 如何看待各网卡。Windows 原生 VPN 连接通常显示为远程访问。自行创建虚拟网卡的第三方客户端常常显示为有线,这意味着限定有线网卡的拦截同时也会拦住隧道。

Get-NetConnectionProfile | Select-Object Name,InterfaceAlias,NetworkCategory
Get-NetAdapter | Select-Object Name,InterfaceDescription,Status,ifIndex
Get-NetFirewallProfile | Select-Object Name,Enabled,DefaultOutboundAction

第三条命令告诉你默认出站阻断是否已经生效,这会改变整个设计的形态。若默认已是阻断,你写的就是放行规则,而不是在宽松基础上的例外,这种姿态更容易推理。

如果隧道网卡报告为有线,单靠防火墙就不是故障关闭设计的合适工具,再怎么调规则也改变不了。这正是每个论坛帖里第二种意见正确的场合。

端点例外需要的不只是规则,还需要路由

假设分类没问题。例外由两部分组成,而它们分属不同的子系统。防火墙规则放行流量,主机路由让它在隧道断开时从正确的接口出去。

New-NetFirewallRule -DisplayName "VPN endpoint allow" -Direction Outbound -Action Allow \
  -Protocol TCP -RemoteAddress 203.0.113.9 -RemotePort 443 -InterfaceType Wired,Wireless
New-NetRoute -DestinationPrefix 203.0.113.9/32 -InterfaceIndex 12 -NextHop 192.168.1.1
Get-NetRoute -DestinationPrefix 203.0.113.9/32

没有路由,例外只在默认路由仍指向物理网关时有效。一旦客户端装好自己的默认路由然后挂掉,被放行的数据包就无处可去,连接也无法重建。这种故障看起来像客户端坏了,实际是缺少路由。

例外范围要尽可能窄。一个地址加一个端口可以审查;覆盖服务商整个网段的区间不行。那条更宽的规则还会放行同一服务商托管的其它一切,通常超出你的本意。

DNS 和 IPv6 正是失败放行的地方

名称解析是经典的泄漏点。若端点是主机名,客户端必须在隧道存在之前解析它,这就意味着必须允许物理网卡访问解析器。同一份许可也把其他所有查询放了出去,而一次查询就足以暴露你即将访问什么。

IPv6 是第二处。为 IPv4 写的规则覆盖不了另一个协议族,而许多客户端只安装 IPv4 路由。因此具备原生 IPv6 连接的机器可以在 IPv4 侧被牢牢阻断时继续与互联网通信,而网络锁始终报告成功。

GapWhat leaksControl
Resolver permitted for endpoint lookupEvery name queried while downPin the endpoint as an address, or block non-tunnel DNS
Rules only for IPv4Full IPv6 connectivityAdd the same rules for the other family
Application bound to physical interfaceIts own trafficFirewall cannot fix this; change the binding

第三行值得理解而非绕开。防火墙决定的是数据包,而不是应用请求使用哪块网卡;显式绑定网卡的程序往往难以约束。这正是支持在应用之下工作的客户端侧网络锁的理由,而不是增加规则的借口。

测试要停掉客户端,而不是拔掉网线

唯一有意义的测试,是模仿你所防范的那种故障。停掉服务、杀掉进程,或者禁用客户端创建的网卡,然后尝试访问互联网和一个域名:

Stop-Service -Name "YourVpnService" -Force
Test-NetConnection -ComputerName 1.1.1.1 -Port 443
Resolve-DnsName example.com
Test-NetConnection -ComputerName 2606:4700:4700::1111 -Port 443

三者都应当失败。若第一项成功,说明阻断未生效;若第一项失败而第二项成功,说明存在 DNS 泄漏;若第三项成功,说明 IPv6 未被覆盖。每种结果都恰好指向上面的一处缺口。

睡眠和唤醒之后要重测,因为当 Windows 判定网络为公用或专用时,防火墙配置文件会切换,限定于某个配置文件的规则也随之改变。只在桌面上成立、一上火车就失效的设计,是只测过一次的设计。

如果分类关卡或 DNS 要求让单靠防火墙的方案行不通,客户端侧网络锁才是诚实的答案。如果隧道终止在路由器上,策略就该由路由器掌管,因为那里的一条规则覆盖其后的所有设备,也不取决于 Windows 如何命名网卡。

相关文章