Kill Switch 实操:在 Windows 和 macOS 上把「隧道一断就断网」做出来,并验证它真的生效
这篇不解释概念,只把它配出来
想知道 Kill Switch 是什么、为什么需要它,看《Kill Switch 是如何保护你的网络安全的?》——那一页讲原理。
这一页只干一件事:在 Windows 和 macOS 上,用系统自己的东西,把「隧道一断就断网」做出来,然后验证它真的生效。
每一步的命令和参数说明都标了出处(微软官方文档、苹果官方文档、客户端自己的源码)。凡是我们没能核实的菜单路径或选项名,会直接写「没核实」,而不是猜一个。
先说结论
- Clash 系客户端没有 Kill Switch 选项。 我们逐个查了 Clash Verge Rev 仓库的界面语言文件,全部语言里都不存在这个功能;它的 TUN 设置只有九个选项(堆栈、虚拟网卡名称、自动设置全局路由、排除自定义网段、严格路由、自动选择流量出口接口、DNS 劫持、最大传输单元、自动重定向)。mihomo 内核的配置项里也没有对应字段。
- TUN 模式不等于 Kill Switch。 TUN 管的是「流量被不被接管」,Kill Switch 管的是「隧道没了之后会怎样」。内核进程一旦崩溃,虚拟网卡和路由被回收,流量就回到物理网卡直连。
- Windows 的正确做法是改默认出站动作,不是加一条阻止规则。 微软文档明写「明确的阻止规则优先于与之冲突的允许规则」——你写的那条 block all 会压掉自己后面所有的放行规则。
- macOS 系统设置里那个「防火墙」不是 Kill Switch。 苹果的原话是它保护 Mac「免受其他电脑发起的不必要联系」,管的是入方向。出方向要用系统自带的 pf。
- 必须留出的例外只有两类:本机回环,和你真正需要直连的局域网/国内服务。其余一律拦。
- 没有做过断线测试的配置不算配好。 每一节末尾都有一个两分钟的验证动作,用 IP 地址查询 和 DNS 泄露检测。
一句话原则:Kill Switch 必须由一个**「隧道挂了它还在」**的东西来执行。代理客户端自己做不到这件事——它就是那个会挂掉的东西。
一、先想清楚:拦什么,放什么
动手前把这张表想明白,否则你会把自己锁在门外。
| 类别 | 处理 | 为什么 |
|---|---|---|
| 发往隧道虚拟网卡的流量 | 放行 | 这是你唯一想留的出口 |
| 本机回环(127.0.0.1 / ::1) | 放行 | 拦掉它,很多本地软件会直接崩 |
| 局域网网段(如 192.168.0.0/16) | 按需放行 | 打印机、NAS、路由器管理页;不需要就别开 |
| 代理客户端进程本身连节点服务器 | 放行 | 否则隧道永远建立不起来——这是最容易漏掉的一条 |
| 其他所有出站 | 拦截 | 这才是 Kill Switch 的本体 |
第四行是最常见的翻车点。 如果你把出站全部拦死,代理客户端自己也连不上节点,结果是永远断网、隧道永远不恢复。Windows 侧的解法在下一节(按进程放行),macOS 侧在第三节(按目标地址放行)。
另外一类流量值得单独提醒:已经建立的连接。防火墙规则通常对新连接生效,旧的 TCP 连接可能还活着一小会儿;同样,DNS 缓存里已经解析过的记录不会因为断网而消失。所以「断流」不等于「瞬间什么都没有了」,它等于「不会有新的明文连接建立」。
二、Windows:改默认出站动作,再按网卡放行
为什么不能直接加一条「阻止全部出站」
微软在 Windows 防火墙规则文档里写明了三条优先级规则(原文):
- Explicitly defined allow rules take precedence over the default block setting.(明确定义的允许规则优先于默认阻止设置)
- Explicit block rules take precedence over any conflicting allow rules.(明确的阻止规则优先于任何与之冲突的允许规则)
- More specific rules take precedence over less specific rules, except if there are explicit block rules as mentioned in 2.(更具体的规则优先于更宽泛的规则,第 2 条所述的明确阻止规则除外)
这三条在原文里是放在「配置入站例外时」的语境下讲的,但同一节的标题就是 Rule precedence for inbound and outbound rules,并且紧接着补了一句:
Outbound rules follow the same precedence behaviors.
(出站规则遵循同样的优先级行为。)
所以把这三条用在出站上,是文档自己说明的用法,不是我们的推断。
第二条就是关键:如果你加一条「阻止全部出站」的显式规则,它会压过你之后所有的放行规则,结果是彻底断网。正确做法是用「默认」去阻止,用「显式规则」去放行——恰好对上第一条。
步骤
以下用 PowerShell(以管理员身份运行)。所有 cmdlet 的参数说明均来自微软官方文档。
第 1 步:先记下隧道网卡的名字。 连上代理、开启 TUN 模式,然后:
Get-NetAdapter | Select-Object Name, InterfaceDescription, Status
在输出里找出隧道创建的那块虚拟网卡(Clash Verge Rev 的 TUN 设置里有「虚拟网卡名称」一项,可以在那里看到或指定)。把它的 Name 记下来,下面用 <隧道网卡名> 代替。
第 2 步:放行隧道网卡。 先放行,再改默认——顺序反了你会立刻断网。
New-NetFirewallRule -DisplayName "KillSwitch-Allow-Tunnel" `
-Direction Outbound -Action Allow -InterfaceAlias "<隧道网卡名>" -Enabled True
参数依据(微软文档原文):-Direction 的取值是 Inbound 或 Outbound,默认是 Inbound,所以必须显式写 Outbound;-Action 的取值是 Allow 或 Block,Allow 表示「匹配本规则全部条件的网络包被允许通过防火墙」;-InterfaceAlias 指定「适用于该流量的网卡别名」;-Enabled 的类型不是布尔值,文档特别提醒「$true 和 $false 变量在这里不是可接受的值,请使用 “True” 和 “False” 文本字符串」。
第 3 步:放行代理客户端进程本身。 否则它连不上节点。
New-NetFirewallRule -DisplayName "KillSwitch-Allow-Client" `
-Direction Outbound -Action Allow -Program "C:\Path\To\你的客户端.exe" -Enabled True
-Program 的文档说明是「指定允许其流量通过的程序的路径和文件名,需填写应用程序文件的完整路径」。
第 4 步:按需放行局域网。
New-NetFirewallRule -DisplayName "KillSwitch-Allow-LAN" `
-Direction Outbound -Action Allow -RemoteAddress LocalSubnet -Enabled True
-RemoteAddress 接受单个 IP、网段、范围或关键字,LocalSubnet 是文档列出的可用关键字之一。
第 5 步:把默认出站动作改成阻止。
Set-NetFirewallProfile -Name Domain,Public,Private -DefaultOutboundAction Block
-DefaultOutboundAction 的文档说明是「指定如何过滤出站流量」,Block 的含义是「阻止不匹配任何出站规则的出站流量」,并注明「在管理一台计算机时,默认设置是 Allow」。-Name 接受 Domain、Public、Private 三种配置文件类型,逗号分隔。
这一步之后,Kill Switch 就成立了:隧道在,虚拟网卡在,第 2 步的规则有匹配对象,流量放行;隧道一断,虚拟网卡消失,那条规则不再匹配任何东西,默认阻止立刻接管。
怎么撤销
撤销的顺序和配置的顺序正好相反:先把默认动作放开,再删规则。 反过来做的话,你会在「默认还是 Block、放行规则已经删掉」的那几秒里彻底断网。
Set-NetFirewallProfile -Name Domain,Public,Private -DefaultOutboundAction Allow
Remove-NetFirewallRule -DisplayName "KillSwitch-Allow-Tunnel"
Remove-NetFirewallRule -DisplayName "KillSwitch-Allow-Client"
Remove-NetFirewallRule -DisplayName "KillSwitch-Allow-LAN"
逐条对得上:
| 配置时做的 | 撤销时做的 |
|---|---|
第 1 步 Get-NetAdapter 看网卡名 | 只是查看,没有改动,不需要撤销 |
| 第 2 步 新建 KillSwitch-Allow-Tunnel | Remove-NetFirewallRule -DisplayName "KillSwitch-Allow-Tunnel" |
| 第 3 步 新建 KillSwitch-Allow-Client | Remove-NetFirewallRule -DisplayName "KillSwitch-Allow-Client" |
| 第 4 步 新建 KillSwitch-Allow-LAN | Remove-NetFirewallRule -DisplayName "KillSwitch-Allow-LAN" |
| 第 5 步 默认出站动作改成 Block | Set-NetFirewallProfile … -DefaultOutboundAction Allow(Allow 就是微软文档说的「管理一台计算机时的默认设置」) |
如果你后来按第五节又加了按程序放行的规则,它们不在上面这张表里,要用你自己起的 -DisplayName 逐条 Remove-NetFirewallRule 删掉——这也是给每条规则起一个统一前缀(例如都用 KillSwitch-)的理由。
先做这一步的心理准备再动手:把撤销命令存成一个 .ps1 文件放桌面,比事后在断网状态下现查要从容得多。
验证(两分钟,别跳过)
- 连上代理,打开 IP 地址查询,记下显示的出口 IP。
- 打开任务管理器,直接结束代理客户端的进程——不要点客户端里的「断开」,那是优雅退出,模拟不了真实的崩溃。
- 立刻刷新 IP 查询页面。合格的结果是加载失败或超时。 如果它显示出了你的真实 IP,说明规则没生效,回头检查第 2 步的网卡名是否写对。
- 再打开 DNS 泄露检测 重复一次。DNS 经常是第一个漏出去的,单测 IP 不够。
三、macOS:系统自带的 pf
先澄清:系统设置里那个「防火墙」不是这个东西
苹果在自己的支持文档里对那道防火墙的定义是:「A firewall can protect your Mac from unwanted contact initiated by other computers when you’re connected to the internet or a network.」——保护你的 Mac 免受其他电脑发起的不必要联系。它管的是入方向。
同一页给出的开启路径原文是:「choose Apple menu > System Settings, click Network in the sidebar, then click Firewall.」(苹果菜单 → 系统设置 → 侧边栏点「网络」→ 点「防火墙」)。这条路径对入方向防护是对的,但它不是 Kill Switch。
出方向要用 pf
macOS 自带包过滤器 pf。在本文核对时所用的 macOS 26.6.2 上,以下几件东西都随系统附带(不需要装任何第三方软件):
- 命令:
/sbin/pfctl - 默认规则文件:
/etc/pf.conf - 两份手册:
man 8 pfctl与man 5 pf.conf
先读懂 pf 的两条语义规则,否则写出来的规则行为会和你想的相反。pf.conf 手册原文:
For each packet processed by the packet filter, the filter rules are evaluated in sequential order, from first to last. The last matching rule decides what action is taken. If no rule matches the packet, the default action is to pass the packet.
(规则从上到下依次求值,最后一条匹配的规则决定动作;如果没有规则匹配,默认动作是放行。)
以及 quick 关键字:
If a packet matches a rule which has the quick option set, this rule is considered the last matching rule, and evaluation of subsequent rules is skipped.
(带 quick 的规则一旦匹配,就被视为最后一条匹配规则,后续规则不再求值。)
手册还直接给出了「默认拦截、只放行明确规则」的写法:
The simplest mechanism to block everything by default and only pass packets that match explicit rules is specify a first filter rule of:
block all
这两条合起来决定了写法:因为是「最后一条匹配的规则决定动作」,所以 block 写在最前面、pass 写在后面,是正确的顺序——和很多人从别处抄来的直觉相反。
规则文件
新建一个文件(例如 /etc/pf.anchors/killswitch.conf),内容形如:
# 1) 默认全部拦住(放最前面,因为最后匹配的规则才算数)
block out all
# 2) 放行回环
pass out quick on lo0 all
# 3) 放行隧道网卡(名字用你实际那块,macOS 上必须是 utun 开头)
pass out quick on utun4 all
# 4) 放行到节点服务器本身,否则隧道建立不起来
pass out quick proto { tcp udp } from any to 203.0.113.10
# 5) 按需放行局域网
pass out quick from any to 192.168.0.0/16
第 4 条里的 203.0.113.10 是占位用的示例地址,来自 RFC 5737 专门留给文档使用的 TEST-NET-3 段。把它换成你自己节点服务器的 IP,不要加尖括号。 在 pf 里 <名字> 不是「请在此填写」的意思,而是表(table)引用——to <203.0.113.10> 会被当成「一张叫 203.0.113.10 的表」,而不是那个地址。pf.conf 手册里表的用法是先 table <名字> { … } 定义、再引用;一张没装地址的表谁也匹配不上,结果是这条放行规则形同虚设、代理客户端连不上节点,而且文件本身语法是对的,你不会收到任何报错。这种「不报错但不生效」比报错更难查。
第 4、5 两条写成 from any to … 的完整形式,是为了和 pf.conf 手册里的规则语法一一对上——手册中所有示例规则都带 from,照着手册核对自己的配置时不会卡住。
关于第 3 条的网卡名:mihomo 官方文档写明「MacOS 设备只能使用 utun 开头的网卡名」。实际是哪一个,连上代理后用 ifconfig 看,或在客户端的 TUN 设置里指定。
载入之前,先只做语法检查
pfctl 手册对 -n 的定义是「Do not actually load rules, just parse them.」(不真的载入规则,只解析它们)。这一步不改动系统任何状态,所以永远应该先跑它:
sudo pfctl -nf /etc/pf.anchors/killswitch.conf # 只解析,不载入
怎么看结果:
- 文件语法正确时,它只打印
pfctl: Use of -f option, could result in flushing of rules…这段-f的固定提醒(这句话对-n同样会打出来,它不是错误),没有别的输出,退出码为 0。 - 文件有语法错误时,它会多打出一行
文件名:行号: syntax error,指出第几行写错了,退出码为 1。
想确认自己读对了这个信号,可以故意在一个临时文件里写一行无效规则跑一次,看它确实报出行号——先验证「检查工具本身会不会报错」,再去相信它给你的绿灯,和本文最后那个断线测试是同一个道理。
确认无误后再载入与启用。依据 pfctl 手册:-f file 是「Load the rules contained in file」,-e 是「Enable the packet filter」,-d 是「Disable the packet filter」,-s info 是「Show filter information (statistics and counters)」。
sudo pfctl -s info # 动手前先记下 pf 现在是开是关
sudo pfctl -f /etc/pf.anchors/killswitch.conf # 载入规则
sudo pfctl -e # 启用
怎么撤销
同样是倒着来,而且每一步都对得上前面做过的动作:
sudo pfctl -d # 撤销「启用」
sudo pfctl -f /etc/pf.conf # 撤销「载入」,换回系统默认规则文件
sudo rm /etc/pf.anchors/killswitch.conf # 撤销「新建规则文件」(想留着以后再用就跳过)
| 配置时做的 | 撤销时做的 |
|---|---|
新建 /etc/pf.anchors/killswitch.conf | sudo rm 删掉它(或留着备用) |
sudo pfctl -nf … 语法检查 | 只解析不载入,没有改动,不需要撤销 |
sudo pfctl -f … 载入规则 | sudo pfctl -f /etc/pf.conf 载回系统默认规则 |
sudo pfctl -e 启用 | sudo pfctl -d 关闭 |
有一个坑要特别注意:pfctl -d 是把整个包过滤器关掉,不只是关掉你那几条规则。如果你动手之前 pf 本来就是开着的(这就是前面让你先跑一次 pfctl -s info 的原因),撤销时应该在载回 /etc/pf.conf 之后再 sudo pfctl -e 把它开回去,而不是让系统停在「pf 全关」的状态。
必须如实说明的三件事
- 这不是苹果面向普通用户提供的功能。 pf 随系统附带、手册也随系统附带,但苹果的用户文档里没有「用 pf 做断流保护」这样的指引。上面的语义全部来自
pf.conf与pfctl手册原文,写法是我们据此组合的,不是苹果的官方推荐配置。 - 系统可能在升级或某些网络事件后重新加载自己的规则集,你的规则不一定长期驻留。把加载命令写成一个你随手能跑的脚本,比假设它永远在更稳妥。每次重要操作前重新验证一次,是唯一可靠的做法。
- 我们没有核实的部分会直说:pf 与 macOS 上某些系统级网络扩展(内容过滤、部分系统服务)的相互作用,我们没有找到苹果的公开说明,因此本文不对此下结论。如果你的场景要求「一次泄漏都不能有」,把验证做成每次开工前的固定动作,不要只依赖一次配置成功。
验证
和 Windows 一节完全一样:连上 → 记下 IP → 直接结束客户端进程 → 刷新 IP 地址查询 → 再跑一次 DNS 泄露检测。看到真实 IP 就是没生效。
四、Clash 侧能做什么、不能做什么
先把话说死:我们在 Clash Verge Rev 仓库的界面语言文件里找不到任何 kill switch 选项,mihomo 内核的配置项与官方文档中也没有对应字段。这个功能它没有。
它的 TUN 设置一共九项,界面原文是:TUN 模式堆栈、虚拟网卡名称、自动设置全局路由、排除自定义网段、严格路由、自动选择流量出口接口、DNS 劫持、最大传输单元、自动重定向。
其中「严格路由」(strict-route)值得单独说,因为它常被误当成 Kill Switch。mihomo 官方文档对它的说明是:
- 在 Windows 中:「添加防火墙规则以阻止 Windows 的普通多宿主 DNS 解析行为造成的 DNS 泄露」,并提醒「它可能会使某些应用程序(如 VirtualBox)在某些情况下无法正常工作」。
- 在 Linux 中:「让不支持的网络无法到达」「将所有连接路由到 tun」,文档说它「可以防止地址泄漏,并使 DNS 劫持在 Android 上工作」。
所以它减少的是「运行期间的泄漏」,不是「隧道消失之后的泄漏」。 这是两个不同的问题:严格路由在内核活着的时候收紧路径;Kill Switch 要管的是内核死了之后。内核一旦退出,它加的规则和路由也跟着走了。
同一份文档还写明另外两条限制,配置时会用到:dns-hijack 在 macOS / Windows 上「无法自动劫持发往局域网的 dns 请求」,在 Android 上「如开启 私人dns 则无法自动劫持 dns 请求」;auto-redirect 仅支持 Linux 且要求 auto-route 已启用。
如果开 TUN 时遇到「TUN 模式需要安装服务模式或管理员模式」「由于服务不可用,TUN 模式已自动关闭」这类提示,那是权限问题,处理方法在《Clash 报错对照表》的 TUN 一节。
五、给卖家:只保护一个浏览器配置文件
如果你的诉求不是「整机不泄漏」,而是「这一个店铺后台绝不能出现真实 IP」,全机断网反而碍事——你还要用微信、还要查国内物流。
这种场景下可用的是按程序放行:Windows 侧把默认出站设为 Block 之后,只给隧道网卡、代理客户端、以及你打算让它上网的那几个程序加放行规则,其余程序自然出不去。New-NetFirewallRule 的 -Program 参数正是为此而设。
但要清楚它的代价,微软文档的第二条优先级规则在这里又会咬人一次:规则一多,你就很难再说清某个程序到底走了哪条路。所以更现实的顺序是:
- 先按上面第二节做整机的 Kill Switch,验证通过;
- 再逐个添加你确实需要放行的程序;
- 每加一个就重新跑一次验证,而不是全部加完再测。
店铺后台的 IP 关联问题不只是「会不会泄漏」,还包括出口地址本身的口碑,那是另一个话题:《为什么到处都要你「证明你是人」?IP 风险分入门》 和跨境电商卖家网络指南。
六、开着 Kill Switch 也仍然会漏的东西
配好之后,下面这几项它管不着,需要单独处理:
| 仍可能泄漏的东西 | 为什么 Kill Switch 管不着 | 怎么办 |
|---|---|---|
| DNS 缓存 | 已经解析过的记录存在本机,不需要联网 | 切换环境后清一次系统 DNS 缓存;原理见《DNS 泄漏是什么,怎么修》 |
| WebRTC | 浏览器主动把本机地址交给网页,不经过你拦截的那条路径 | 用 WebRTC 泄露测试 查,浏览器侧关掉 |
| 已经建立的连接 | 防火墙规则通常对新连接生效 | 断线后重启相关应用,别只刷新页面 |
| 浏览器指纹、Cookie、账号历史 | 和 IP 完全无关 | 属于另一套问题,见《VPN 泄露检测》 |
| 代理开着但某个程序绕过了它 | 终端工具和守护进程不读系统代理 | 见《代理开着却还是超时》 |
最后一句,也是这篇最想让你记住的:Kill Switch 的价值不在于配好那一刻,而在于你真的断线测过。一个没验证过的 Kill Switch,和没有 Kill Switch 的区别只是你更放心了——而这恰恰是最危险的状态。
参考资料
以下文档与源码于 2026 年 9 月 20—21 日核对;macOS 侧的命令、手册页与文件路径在 macOS 26.6.2 上确认存在。
微软官方文档(Windows 防火墙)
- Windows Firewall rules — Rule precedence for inbound and outbound rules — 三条优先级规则的原文,以及「Outbound rules follow the same precedence behaviors.」这一句(说明同样适用于出站)
New-NetFirewallRule—-Direction(默认 Inbound)、-Action(Allow / Block)、-InterfaceAlias、-Program、-RemoteAddress(含LocalSubnet关键字)、-Enabled(必须用 “True”/“False” 字符串)的参数说明Set-NetFirewallProfile—-DefaultOutboundAction Block的定义「阻止不匹配任何出站规则的出站流量」,以及「管理一台计算机时默认设置是 Allow」
苹果官方文档(macOS)
- Block connections to your Mac with a firewall — 该防火墙针对入方向的原文定义,以及「Apple menu > System Settings → Network → Firewall」的路径
- macOS 随系统附带的手册页
man 5 pf.conf与man 8 pfctl(本机路径/usr/share/man/man5/pf.conf.5、/usr/share/man/man8/pfctl.8;命令/sbin/pfctl,默认规则文件/etc/pf.conf)— 规则求值顺序、quick语义、block all写法、表(table <名字>)必须先定义再引用、以及-e/-d/-f/-n/-s info的定义。这两份手册在你自己的 Mac 上就能查,是最可靠的一手来源。 - RFC 5737 — IPv4 Address Blocks Reserved for Documentation — 第三节规则示例里
203.0.113.10的出处(TEST-NET-3,专供文档使用,不会和真实地址冲突)
客户端与内核
- mihomo 官方文档 — 入站 Tun —
strict-route在 Windows / Linux 上的行为、dns-hijack的平台限制、auto-redirect仅支持 Linux、macOS 网卡名必须以utun开头(页面标注更新于 2026 年 9 月 14 日) - Clash Verge Rev 简体中文语言文件
settings.json— TUN 设置的九个选项原文,以及全部语言文件中不存在 kill switch 相关条目这一事实的依据 - mihomo 配置源码
config/config.go— 内核配置项中不含断流保护字段
将本指南加入收藏夹
跨境网络环境瞬息万变。建议按下 Ctrl+D (Windows) 或 Cmd+D (Mac) 收藏本页,以便在连接波动时快速查阅解决方案。
加入 5,000+ 跨境从业者,第一时间获取最新的 GFW 封锁动态与协议升级提醒。
* 我们绝不发送垃圾邮件,您可以随时取消订阅。
KUAJIE VPN