Windows 11 上封锁 Claude Code 出网:防火墙 + DNS + hosts 三层实战

3291 字
16 分钟
Windows 11 上封锁 Claude Code 出网:防火墙 + DNS + hosts 三层实战

适用机器:Windows 11(build 26200,x64)+ WSL2 Ubuntu-24.04 + Docker Desktop + Clash Verge
适用场景:本机跑 Claude Code / CPA / 浏览器,只有走代理才能连 Anthropic,直连必须死
对应服务器版:同目录 CLAUDE-EGRESS-BLOCK-TUTORIAL.md
最后更新:2026-10-22


0. 目标与效果#

目标是让本机上的任何进程:

  • 无法直接连接 Anthropic / Claude 官方域名和 IP(主机 / WSL2 / Docker Desktop 容器全覆盖);
  • 只能通过本机 Clash 代理访问;
  • 代理崩溃或配置出错时请求直接失败,绝不回落到直连;
  • 重启后规则、DNS 仍然生效。

最终效果(2026-10-22 实测):

主机 IPv4 直连 Anthropic 网段 -> 防火墙内核层丢弃
主机 IPv6 直连 Anthropic 网段 -> 防火墙内核层丢弃
WSL2 (Ubuntu-24.04) 直连 -> nftables 丢弃(双保险)
Docker Desktop 容器直连 -> Windows 防火墙出站规则同样生效(替身实测覆盖)
通过 Clash 代理 -> 不受影响(代理节点 IP 不在封锁集合内)
Clash 停止时直连 -> 仍然必死
重启后 -> 防火墙规则持久 + WSL systemd 自启

验证分两阶段:阶段一全程零 Anthropic 流量(替身 IP 223.5.5.5 + 中性域名 baidu.com); 阶段二端到端不连通实测已于 2026-10-22 执行通过,结果见第 7 节。


1. 原理:三层防线与 Windows 特有的坑#

服务器版三层(DNS 纠正 + Clash 显式规则 + nftables)在 Windows 上的对应:

服务器层Windows 对应说明
nftables output 链Windows Defender Firewall 出站规则(WFP 层)New-NetFirewallRule,按目的 IP 封,写入策略库、重启持久
nftables forward 链同上(实测覆盖 Docker Desktop NAT 流量)WSL 内再部署一套 nftables 双保险
netplan 公网 DNSSet-DnsClientServerAddress大陆家宽用 223.5.5.5 / 119.29.29.29,不要照抄服务器版的 1.1.1.1 / 8.8.8.8(大陆不可靠)
Clash 显式规则Clash Verge 中 anthropic/claude 域名 → 代理组保证”走代理可用”
systemd 开机顺序防火墙规则本身持久;WSL 用 systemd 单元无需额外开机脚本

Windows 特有的坑(本次实测/踩坑记录):

  1. PowerShell 5.1 把无 BOM 的 UTF-8 脚本按 GBK 解析。.ps1 里出现中文(例如 '以太网')会直接 ParserError,症状:UAC 点了”是”、日志没生成、提权窗口一闪而过。所有提权脚本必须纯 ASCII;网卡用 InterfaceDescription 过滤,不要写本地化网卡名。
  2. DoH 绕过 DNS/hosts:Chrome/Edge Secure DNS 不走系统 DNS。DNS/hosts 只是辅助层,最终保证是 IP 层封锁。
  3. IPv6 必须一起封(2607:6bc0::/32):Windows 优先走 v6。
  4. WSL2 / Docker Desktop 走 NAT 转发路径,理论上 Windows 防火墙出站规则(ALE 层)只管本机进程;但本次替身实测证明 Docker Desktop 容器流量实际被覆盖(见 6.2)。WSL 内仍按服务器方案部署 nftables 做双保险。
  5. hosts 是”失败安全”方向:将来若开 Clash TUN 模式,hosts 会让这些域名连代理路径一起报错(表现为连接失败,而非直连)。届时删掉 hosts 段即可,IP 层封锁仍在。

2. 前置检查#

在本机执行(全部只查本地状态,不连 Anthropic):

Terminal window
# 提权状态与管理员组成员
([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
Get-LocalGroupMember -Group Administrators
# 现有防火墙规则(应为空)
Get-NetFirewallRule -DisplayName "claude-guard*"
# 网卡清单(决定 DNS 要设在哪些网卡上)
Get-NetAdapter | Select-Object Name, InterfaceDescription
# 代理形态(有无 TUN 网卡,决定 hosts 层取舍)
Get-Process | Where-Object Name -match "clash|mihomo|verge"
# WSL 与 Docker
wsl -l -v
docker ps

Anthropic 网段沿用服务器版 2026-10-21 值:

IPv4: 160.79.104.0/21
IPv6: 2607:6bc0::/32

3. 第一步:Windows 防火墙出站阻断(A)#

3.1 提权脚本 setup.ps1(必须纯 ASCII)#

创建 C:\Users\<你>\AppData\Local\Temp\claude-guard\setup.ps1:

Terminal window
# claude-guard setup for Windows 11 (run elevated) - ASCII only
$ErrorActionPreference = 'Continue'
$dir = 'C:\Users\<你>\AppData\Local\Temp\claude-guard'
$log = Join-Path $dir 'setup.log'
function Log([string]$m) {
Add-Content -Path $log -Value ('[{0}] {1}' -f (Get-Date -Format s), $m) -Encoding utf8
}
Log '=== setup start ==='
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
Log ("IsAdmin=$isAdmin")
if (-not $isAdmin) { Log 'ABORT: not elevated'; exit 1 }
# --- A: firewall block rules (kernel-level, persistent) ---
foreach ($n in @('claude-guard-v4','claude-guard-v6','claude-guard-selftest-v4')) {
Get-NetFirewallRule -DisplayName $n -ErrorAction SilentlyContinue | Remove-NetFirewallRule
}
New-NetFirewallRule -DisplayName 'claude-guard-v4' -Direction Outbound -Action Block -RemoteAddress '160.79.104.0/21' -Profile Any -Enabled True | Out-Null
New-NetFirewallRule -DisplayName 'claude-guard-v6' -Direction Outbound -Action Block -RemoteAddress '2607:6bc0::/32' -Profile Any -Enabled True | Out-Null
New-NetFirewallRule -DisplayName 'claude-guard-selftest-v4' -Direction Outbound -Action Block -RemoteAddress '223.5.5.5/32' -Profile Any -Enabled True | Out-Null
Log 'firewall: claude-guard-v4 / claude-guard-v6 / claude-guard-selftest-v4 created'
# --- E1: DNS on non-virtual adapters (anti-hijack) ---
$adapters = Get-NetAdapter | Where-Object { $_.InterfaceDescription -notmatch 'Hyper-V|Virtual|TAP-Windows|OpenVPN|WSL' }
foreach ($a in $adapters) {
Set-DnsClientServerAddress -InterfaceAlias $a.Name -ServerAddresses @('223.5.5.5','119.29.29.29')
$now = (Get-DnsClientServerAddress -InterfaceAlias $a.Name -AddressFamily 2).ServerAddresses -join ','
Log ('DNS set on [' + $a.Name + '] desc=[' + $a.InterfaceDescription + '] now=' + $now)
}
ipconfig /flushdns | Out-Null
Log 'dns cache flushed'
# --- E2: hosts (aux name-layer, fail-closed) ---
$hostsPath = Join-Path $env:SystemRoot 'System32\drivers\etc\hosts'
Copy-Item $hostsPath ($hostsPath + '.bak-claude-guard') -Force
$domains = @('anthropic.com','www.anthropic.com','api.anthropic.com','console.anthropic.com','docs.anthropic.com','code.anthropic.com','statsig.anthropic.com','claude.ai','www.claude.ai','claude.com','www.claude.com','claudeusercontent.com')
$text = [System.IO.File]::ReadAllText($hostsPath)
$add = @()
foreach ($d in $domains) {
if ($text -notmatch ('(?m)^\s*0\.0\.0\.0\s+' + [regex]::Escape($d) + '\s*$')) { $add += ('0.0.0.0 ' + $d) }
}
if ($add.Count -gt 0) {
$block = "`r`n# claude-guard: aux name-layer block (fail-closed)`r`n" + ($add -join "`r`n") + "`r`n"
[System.IO.File]::AppendAllText($hostsPath, $block, [System.Text.Encoding]::ASCII)
Log ('hosts: ' + $add.Count + ' lines added')
} else {
Log 'hosts: already up to date'
}
# --- summary ---
Get-NetFirewallRule -DisplayName 'claude-guard*' | ForEach-Object {
Log ('rule: ' + $_.DisplayName + ' enabled=' + $_.Enabled + ' action=' + $_.Action + ' dir=' + $_.Direction)
}
Log '=== setup done ==='

注意:$dir 换成你自己的实际路径;脚本幂等,重复执行会先删旧规则再重建。

脚本一次做三件事:A 防火墙规则、E1 DNS、E2 hosts。其中 claude-guard-selftest-v4(封 223.5.5.5)是替身规则,专门给第 6 节验证用,验证完必须删。

3.2 提权入口 run-elevated.ps1(必须纯 ASCII)#

Terminal window
# claude-guard elevated launcher (ASCII only)
$ErrorActionPreference = 'Continue'
$base = 'C:\Users\<你>\AppData\Local\Temp\claude-guard'
Start-Transcript -Path (Join-Path $base 'elev.transcript.log') -Force | Out-Null
try {
& (Join-Path $base 'setup.ps1')
Add-Content -Path (Join-Path $base 'elev.status.log') -Value 'WRAPPER_OK'
} catch {
Add-Content -Path (Join-Path $base 'elev.status.log') -Value ('WRAPPER_ERR: ' + ($_ | Out-String))
}
Stop-Transcript | Out-Null

普通终端执行(会弹 UAC,点”是”):

Terminal window
powershell -NoProfile -Command 'try { Start-Process powershell -Verb RunAs -Wait -ArgumentList "-NoProfile","-ExecutionPolicy","Bypass","-File","C:\Users\<你>\AppData\Local\Temp\claude-guard\run-elevated.ps1" -ErrorAction Stop; Write-Output UAC_OK } catch { Write-Output ("UAC_FAIL: " + $_.Exception.Message) }'

成功标志:UAC_OK + setup.log 里出现 === setup done ===。

3.3 提权失败排查(本次踩过的坑)#

症状:UAC_OK 打印了,但 setup.log 不存在、规则没生效、命令 1.5 秒就返回。

排查顺序:

Terminal window
# 1. 非提权直接跑,把 ParserError 打到控制台(会因 IsAdmin=False 中止,无副作用)
powershell -NoProfile -ExecutionPolicy Bypass -File C:\Users\<你>\AppData\Local\Temp\claude-guard\setup.ps1
# 2. 看包装器日志
type C:\Users\<你>\AppData\Local\Temp\claude-guard\elev.status.log
type C:\Users\<你>\AppData\Local\Temp\claude-guard\elev.transcript.log

本次根因即第 1 节坑 1:UTF-8 无 BOM + 中文 → GBK 解析 → ParserError。改成纯 ASCII 后一次通过。


4. 第二步:WSL2 内 nftables 移植(B)#

与服务器版同款,去掉服务商中转 set(那是服务器服务商特有的)。WSL 内是 systemd 环境(Ubuntu-24.04 默认 systemd=true),直接复用 claude-guard.service。

4.1 /etc/nftables.d/claude-guard.nft#

table inet claude_guard {
set anthropic_v4 {
type ipv4_addr
flags interval
elements = { 160.79.104.0/21 }
}
set anthropic_v6 {
type ipv6_addr
flags interval
elements = { 2607:6bc0::/32 }
}
chain output {
type filter hook output priority -200; policy accept;
ip daddr @anthropic_v4 counter limit rate 10/minute log prefix "claude-guard-out " level warn
ip daddr @anthropic_v4 counter drop
ip6 daddr @anthropic_v6 counter limit rate 10/minute log prefix "claude-guard-out6 " level warn
ip6 daddr @anthropic_v6 counter drop
}
chain forward {
type filter hook forward priority -200; policy accept;
ip daddr @anthropic_v4 counter limit rate 10/minute log prefix "claude-guard-fwd " level warn
ip daddr @anthropic_v4 counter drop
ip6 daddr @anthropic_v6 counter limit rate 10/minute log prefix "claude-guard-fwd6 " level warn
ip6 daddr @anthropic_v6 counter drop
}
}

4.2 /usr/local/sbin/claude-guard.sh#

#!/bin/sh
set -eu
nft delete table inet claude_guard 2>/dev/null || true
nft -f /etc/nftables.d/claude-guard.nft

4.3 /etc/systemd/system/claude-guard.service#

[Unit]
Description=Block direct egress to Anthropic/Claude IP ranges
After=network.target
Wants=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/claude-guard.sh
ExecStop=/usr/sbin/nft delete table inet claude_guard
[Install]
WantedBy=multi-user.target

4.4 部署(在 Windows 侧执行)#

Terminal window
# 装 nftables(WSL 默认没有 nft 二进制)
wsl -d Ubuntu-24.04 -u root -- bash -c "apt-get update -qq && apt-get install -y -qq nftables"
# 三个文件按上面内容写入后:
wsl -d Ubuntu-24.04 -u root -- bash -c "chmod 0755 /usr/local/sbin/claude-guard.sh; nft -c -f /etc/nftables.d/claude-guard.nft && systemctl daemon-reload && systemctl enable --now claude-guard.service"
# 验证
wsl -d Ubuntu-24.04 -u root -- bash -c "systemctl is-enabled claude-guard; systemctl is-active claude-guard; nft list table inet claude_guard"

期望:enabled / active,规则集列出两个 set 和两条链。WSL 每次启动由 systemd 自动拉起,等效开机持久。


5. 第三步:DNS 纠正 + hosts(E)#

这两步已包含在 setup.ps1(3.1 的 E1/E2 段),要点:

  • DNS 选 223.5.5.5 / 119.29.29.29(阿里 DNSPod):大陆家宽可达且不劫持 Anthropic 域名;服务器版的 1.1.1.1/8.8.8.8 在大陆不可靠,不要照抄。排除虚拟网卡(Hyper-V/WSL/OpenVPN/TAP),只设物理网卡。
  • hosts 指向 0.0.0.0:辅助名称层,共 12 条(anthropic.com / claude.ai / claude.com / claudeusercontent.com 及主要子域)。走 HTTP 代理时域名由代理端解析,hosts 不影响代理路径。
  • 两层都是辅助:DoH 应用会绕过它们,所以IP 层封锁(A/B)才是最终保证。

6. 验证:替身法(全程零 Anthropic 流量)#

原理:setup.ps1 额外创建了替身规则 claude-guard-selftest-v4(封 223.5.5.5/32)。它与正式规则构造完全一致,对它做行为测试即可证明正式规则的机制。

6.1 主机差异测试#

Terminal window
# 被替身规则封住的解析器:必须超时
nslookup -timeout=2 -retry=1 baidu.com 223.5.5.5
# 对照组(未封的解析器):必须正常
nslookup -timeout=2 -retry=1 baidu.com 119.29.29.29

期望:前者 DNS request timed out,后者返回 A 记录。

6.2 Docker Desktop 覆盖判定#

Terminal window
docker run --rm node:22-alpine sh -c "nslookup -timeout=2 baidu.com 223.5.5.5"
docker run --rm node:22-alpine sh -c "nslookup -timeout=2 baidu.com 119.29.29.29"

期望:前者 connection timed out; no servers could be reached,后者正常。 若前者正常,说明你的 Docker 网络路径没被 A 覆盖,需要把工作负载挪进 WSL(B 覆盖)再验。

6.3 本次实测记录(2026-10-22)#

测试结果
主机 nslookup baidu.com 223.5.5.5超时(被拦)✓
主机 nslookup baidu.com 119.29.29.29正常返回 ✓
容器 nslookup baidu.com 223.5.5.5无服务器可达(被拦)✓ → Docker Desktop 被 A 覆盖
容器 nslookup baidu.com 119.29.29.29正常返回 ✓
主机冒烟 curl https://www.baidu.com200,无误伤 ✓
WSL getent hosts baidu.com正常 ✓

6.4 清理替身规则(必须做)#

替身规则封的 223.5.5.5 现在是主 DNS,验证完立即删(会再弹一次 UAC):

teardown-selftest.ps1:

Terminal window
$log = 'C:\Users\<你>\AppData\Local\Temp\claude-guard\setup.log'
function Log([string]$m) {
Add-Content -Path $log -Value ('[{0}] {1}' -f (Get-Date -Format s), $m) -Encoding utf8
}
Get-NetFirewallRule -DisplayName 'claude-guard-selftest-v4' -ErrorAction SilentlyContinue | Remove-NetFirewallRule
Log 'selftest rule removed'
Get-NetFirewallRule -DisplayName 'claude-guard*' | ForEach-Object {
Log ('remaining: ' + $_.DisplayName + ' enabled=' + $_.Enabled)
}
Log '=== teardown done ==='
Terminal window
powershell -NoProfile -Command 'try { Start-Process powershell -Verb RunAs -Wait -ArgumentList "-NoProfile","-ExecutionPolicy","Bypass","-File","C:\Users\<你>\AppData\Local\Temp\claude-guard\teardown-selftest.ps1" -ErrorAction Stop; Write-Output UAC_OK } catch { Write-Output ("UAC_FAIL: " + $_.Exception.Message) }'

最终盘点(期望只剩两条正式规则):

Terminal window
Get-NetFirewallRule -DisplayName "claude-guard*" | Format-Table DisplayName,Enabled,Action,Direction,Profile
Get-DnsClientServerAddress -AddressFamily 2 | Format-Table InterfaceAlias,ServerAddresses
type C:\Windows\System32\drivers\etc\hosts

7. 端到端不连通实测(2026-10-22 已执行通过)#

上面的验证证明了”机制有效 + 无误伤”,但没有产生任何 Anthropic 流量。端到端确认方法如下(本次已执行,实测记录见 7.1):

Terminal window
# 1. 先验证代理路径(期望 401:网络可达,只是缺凭证)
curl.exe -x http://127.0.0.1:7890 -m 15 -o NUL -w "proxy_http=%{http_code}\n" https://api.anthropic.com/v1/models
# 2. 再验证直连路径(期望超时 / http=000)
curl.exe --noproxy "*" -m 6 -o NUL -w "direct_http=%{http_code}\n" https://api.anthropic.com/v1/models

务必先 1 后 2。若第 2 步返回任何非 000 状态,立即停止使用并回报,说明封锁有洞。

7.1 本次实测记录(2026-10-22)#

实际执行的是”不连通”电池:对照组 + 三层直击,用 --resolve 强制打真实 Anthropic IP(绕过 DNS/hosts,直击内核封锁层):

测试命令要点结果证据含义
对照组curl https://www.baidu.com200工具链正常,后续失败不是假象
hosts 层curl --noproxy "*" https://api.anthropic.com/v1/models(6) Could not resolve host,000名称层拒绝解析,零流量
内核层 IPv4--resolve api.anthropic.com:443:160.79.104.10(7) Failed after 0 ms,0000 ms 瞬时失败 = WFP 在 ALE connect 层本机拒绝,SYN 未出网卡
内核层 IPv6--resolve api.anthropic.com:443:[2607:6bc0::10](7) Failed after 0 ms,000v6 同样内核层拒绝
WSL 内核层WSL 内同款 --resolve + nft list 计数器(28) 超时,000;计数器 packets 6 bytes 360nftables 静默丢弃,计数器实锤

判定:“直连必死”端到端成立。主机签名 = 瞬时拒绝(无包发出);WSL 签名 = 丢弃 + 计数器递增。 代理路径未在本次测试(不发凭证请求);“走代理可用”由机制保证——封锁只按目的 IP 生效,代理节点 IP 不在封锁集合内,HTTP 代理下域名由代理端解析、hosts 不参与。


8. 维护#

8.1 Anthropic IP 段变化#

当前(2026-10-21):

160.79.104.0/21
2607:6bc0::/32

变更时改两处并重载:

  1. setup.ps1 里两条 New-NetFirewallRule 的 RemoteAddress → 重跑 run-elevated.ps1(幂等,会重建规则);
  2. WSL /etc/nftables.d/claude-guard.nft 的 elements → wsl -d Ubuntu-24.04 -u root -- /usr/local/sbin/claude-guard.sh。

8.2 换机器 / 重装#

复制 claude-guard\ 目录(含本教程的脚本)→ 改 $dir 路径 → 跑 run-elevated.ps1 → 第 4 节部署 WSL → 第 6 节替身验证。

8.3 已知观察#

  • nslookup 显示实际应答服务器可能是 fe80::1(路由器 RA 下发的 IPv6 DNS),IPv4 DNS 已固定 223.5.5.5/119.29.29.29。Anthropic 域名链路被 hosts + IP 层闭合,不受影响;仅影响其他域名的 DNS 洁净度。
  • 本机存在 OpenVPN 虚拟网卡,未动其 DNS(由 VPN 配置自理)。
  • Clash Verge(verge-mihomo)为显式代理模式;若将来开 TUN 模式见第 1 节坑 5。

9. 回滚#

Terminal window
# 1. 删防火墙规则(管理员)
Remove-NetFirewallRule -DisplayName "claude-guard*"
# 2. 还原 DNS(管理员)
Set-DnsClientServerAddress -InterfaceAlias WLAN -ResetServerAddresses
Set-DnsClientServerAddress -InterfaceAlias "以太网" -ResetServerAddresses
# 3. 还原 hosts(管理员)
copy C:\Windows\System32\drivers\etc\hosts.bak-claude-guard C:\Windows\System32\drivers\etc\hosts
Terminal window
# 4. WSL 内
wsl -d Ubuntu-24.04 -u root -- bash -c "systemctl disable --now claude-guard; nft delete table inet claude_guard 2>/dev/null; true"

回滚后直连恢复,这是预期行为。


10. 文件清单#

路径作用
C:\Users\<你>\AppData\Local\Temp\claude-guard\setup.ps1主脚本:防火墙 + DNS + hosts(纯 ASCII,幂等)
同目录 run-elevated.ps1提权入口(UAC + transcript)
同目录 teardown-selftest.ps1删除替身规则
同目录 setup.log全部操作审计日志
同目录 elev.status.log / elev.transcript.log提权执行诊断
C:\Windows\System32\drivers\etc\hosts.bak-claude-guardhosts 备份
WSL /etc/nftables.d/claude-guard.nftWSL 内核级封锁规则
WSL /usr/local/sbin/claude-guard.sh重载脚本
WSL /etc/systemd/system/claude-guard.serviceWSL 开机自启

Temp 目录会被系统清理,长期留底请复制到 <笔记目录>。


11. 一句话总结#

Windows 防火墙封 IP 段(主机+Docker 实测全覆盖)+ WSL 内 nftables 双保险 + 公网 DNS/hosts 辅助层,并且用”替身 IP 差异测试”在零 Anthropic 流量的前提下证明机制有效——代理可用、直连必死、代理崩溃不回落。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Windows 11 上封锁 Claude Code 出网:防火墙 + DNS + hosts 三层实战
https://guoxin.wiki/posts/claude-egress-block-win11/
作者
Guoxin
发布于
2026-10-21
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
Guoxin
写代码,也写思考。
公告
博客初建,笔记陆续搬家中。所有文章均经脱敏检查后发布。
分类
标签
最新动态
站点统计
文章
12
分类
6
标签
24
总字数
13,485
运行时长
0 天
最后活动
0 天前
站点信息
构建平台
Unknown CI
博客版本
Firefly v6.16.8
文章许可
CC BY-NC-SA 4.0
文章目录