Kill Switch 的目标很明确:隧道一旦断开,立即阻止设备的明文流量走原有网卡出去。名字相同的功能在不同客户端里可能工作在完全不同的层次,客户端崩溃、系统休眠唤醒这类边缘情况下的表现差别很大。

三个实现层次
为什么应用层 Kill Switch 不够可靠
应用层的做法是客户端自己监测隧道状态,发现断开后禁用网卡或结束指定程序。它的前提是客户端进程还活着。如果进程崩溃、被系统回收或被用户结束,这套机制和它一起消失,此时设备正好回到最危险的明文状态。
路由层的做法和局限
路由层的思路是把默认路由改到隧道网卡,并留一条优先级更低的“不可达”默认路由作为兜底。隧道网卡消失时,流量落到这条不可达路由上被丢弃,而不是回退到物理网卡。它不依赖客户端进程,但需要谨慎处理物理网卡上还留着的默认路由,容易和系统网络管理组件互相覆盖,而且拦不住已经指定了物理网卡的连接。
防火墙层为什么更稳妥
防火墙层把“默认拒绝出站,只放行隧道网卡和到服务端的握手包”写成内核规则。规则在内核里执行,和客户端进程是否存活无关,进程崩溃、休眠唤醒、网卡重置都不会让规则失效。这也是从安全角度通常推荐的方案。
三种实现的对照
| 实现层 | 客户端崩溃时 | 隧道断开时 | 实现复杂度 |
|---|---|---|---|
| 应用层 | 失效 | 取决于检测速度 | 低 |
| 路由层 | 仍有效 | 有效 | 中 |
| 防火墙层 | 仍有效 | 立即有效 | 中到高 |
一个防火墙层的示例
下面是用 nftables 写的思路示例,只允许回环、隧道网卡和到 VPN 服务器的握手流量,其余出站全部丢弃。服务器地址、端口和网卡名需要按实际环境修改:
table inet killswitch {
chain output {
type filter hook output priority 0; policy drop;
oifname "lo" accept
oifname "wg0" accept
ip daddr 203.0.113.10 udp dport 51820 accept
}
}
防火墙方案常见的坑
最常见的有三个:把局域网也一起拦了,打印机和 NAS 访问不了,需要单独放行私网段;只写了 IPv4 规则,IPv6 流量仍然直接出去,使用 inet 表可以一次覆盖两者;物理网卡求 DHCP 续租和 IPv6 邻居发现的报文被丢弃,导致过一段时间网络自己断掉,需要针对这些端口单独开洞。
Windows 和移动设备上怎么办
Windows 的防火墙支持类似的默认拒绝出站策略,部分客户端会在默认路由进隧道时自动添加这类规则。移动系统上则依赖系统提供的“始终开启 VPN”和“阻止没有 VPN 的连接”选项,这是系统层面的防护,比应用内的开关可靠。
怎么验证 Kill Switch 真的在工作
不要只看客户端里的开关状态。连接 VPN 后持续 ping 一个外网地址,然后模拟两种故障:用 ip link set wg0 down 让隧道网卡消失,用 kill 结束客户端进程。两种情况下 ping 都应该立即中断,而不是转为从物理网卡直连。恢复连接后流量应该自动可用。




