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 公网 DNS | Set-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 特有的坑(本次实测/踩坑记录):
- PowerShell 5.1 把无 BOM 的 UTF-8 脚本按 GBK 解析。
.ps1里出现中文(例如'以太网')会直接 ParserError,症状:UAC 点了”是”、日志没生成、提权窗口一闪而过。所有提权脚本必须纯 ASCII;网卡用InterfaceDescription过滤,不要写本地化网卡名。 - DoH 绕过 DNS/hosts:Chrome/Edge Secure DNS 不走系统 DNS。DNS/hosts 只是辅助层,最终保证是 IP 层封锁。
- IPv6 必须一起封(2607:6bc0::/32):Windows 优先走 v6。
- WSL2 / Docker Desktop 走 NAT 转发路径,理论上 Windows 防火墙出站规则(ALE 层)只管本机进程;但本次替身实测证明 Docker Desktop 容器流量实际被覆盖(见 6.2)。WSL 内仍按服务器方案部署 nftables 做双保险。
- hosts 是”失败安全”方向:将来若开 Clash TUN 模式,hosts 会让这些域名连代理路径一起报错(表现为连接失败,而非直连)。届时删掉 hosts 段即可,IP 层封锁仍在。
2. 前置检查
在本机执行(全部只查本地状态,不连 Anthropic):
# 提权状态与管理员组成员([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 与 Dockerwsl -l -vdocker psAnthropic 网段沿用服务器版 2026-10-21 值:
IPv4: 160.79.104.0/21IPv6: 2607:6bc0::/323. 第一步:Windows 防火墙出站阻断(A)
3.1 提权脚本 setup.ps1(必须纯 ASCII)
创建 C:\Users\<你>\AppData\Local\Temp\claude-guard\setup.ps1:
# 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-NullNew-NetFirewallRule -DisplayName 'claude-guard-v6' -Direction Outbound -Action Block -RemoteAddress '2607:6bc0::/32' -Profile Any -Enabled True | Out-NullNew-NetFirewallRule -DisplayName 'claude-guard-selftest-v4' -Direction Outbound -Action Block -RemoteAddress '223.5.5.5/32' -Profile Any -Enabled True | Out-NullLog '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-NullLog '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)
# 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-Nulltry { & (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,点”是”):
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 秒就返回。
排查顺序:
# 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.logtype 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/shset -eunft delete table inet claude_guard 2>/dev/null || truenft -f /etc/nftables.d/claude-guard.nft4.3 /etc/systemd/system/claude-guard.service
[Unit]Description=Block direct egress to Anthropic/Claude IP rangesAfter=network.targetWants=network.target
[Service]Type=oneshotRemainAfterExit=yesExecStart=/usr/local/sbin/claude-guard.shExecStop=/usr/sbin/nft delete table inet claude_guard
[Install]WantedBy=multi-user.target4.4 部署(在 Windows 侧执行)
# 装 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 主机差异测试
# 被替身规则封住的解析器:必须超时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 覆盖判定
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.com | 200,无误伤 ✓ |
WSL getent hosts baidu.com | 正常 ✓ |
6.4 清理替身规则(必须做)
替身规则封的 223.5.5.5 现在是主 DNS,验证完立即删(会再弹一次 UAC):
teardown-selftest.ps1:
$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-NetFirewallRuleLog 'selftest rule removed'Get-NetFirewallRule -DisplayName 'claude-guard*' | ForEach-Object { Log ('remaining: ' + $_.DisplayName + ' enabled=' + $_.Enabled)}Log '=== teardown done ==='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) }'最终盘点(期望只剩两条正式规则):
Get-NetFirewallRule -DisplayName "claude-guard*" | Format-Table DisplayName,Enabled,Action,Direction,ProfileGet-DnsClientServerAddress -AddressFamily 2 | Format-Table InterfaceAlias,ServerAddressestype C:\Windows\System32\drivers\etc\hosts7. 端到端不连通实测(2026-10-22 已执行通过)
上面的验证证明了”机制有效 + 无误伤”,但没有产生任何 Anthropic 流量。端到端确认方法如下(本次已执行,实测记录见 7.1):
# 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.com | 200 | 工具链正常,后续失败不是假象 |
| 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,000 | 0 ms 瞬时失败 = WFP 在 ALE connect 层本机拒绝,SYN 未出网卡 |
| 内核层 IPv6 | --resolve api.anthropic.com:443:[2607:6bc0::10] | (7) Failed after 0 ms,000 | v6 同样内核层拒绝 |
| WSL 内核层 | WSL 内同款 --resolve + nft list 计数器 | (28) 超时,000;计数器 packets 6 bytes 360 | nftables 静默丢弃,计数器实锤 |
判定:“直连必死”端到端成立。主机签名 = 瞬时拒绝(无包发出);WSL 签名 = 丢弃 + 计数器递增。 代理路径未在本次测试(不发凭证请求);“走代理可用”由机制保证——封锁只按目的 IP 生效,代理节点 IP 不在封锁集合内,HTTP 代理下域名由代理端解析、hosts 不参与。
8. 维护
8.1 Anthropic IP 段变化
当前(2026-10-21):
160.79.104.0/212607:6bc0::/32变更时改两处并重载:
setup.ps1里两条New-NetFirewallRule的RemoteAddress→ 重跑run-elevated.ps1(幂等,会重建规则);- 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. 回滚
# 1. 删防火墙规则(管理员)Remove-NetFirewallRule -DisplayName "claude-guard*"
# 2. 还原 DNS(管理员)Set-DnsClientServerAddress -InterfaceAlias WLAN -ResetServerAddressesSet-DnsClientServerAddress -InterfaceAlias "以太网" -ResetServerAddresses
# 3. 还原 hosts(管理员)copy C:\Windows\System32\drivers\etc\hosts.bak-claude-guard C:\Windows\System32\drivers\etc\hosts# 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-guard | hosts 备份 |
WSL /etc/nftables.d/claude-guard.nft | WSL 内核级封锁规则 |
WSL /usr/local/sbin/claude-guard.sh | 重载脚本 |
WSL /etc/systemd/system/claude-guard.service | WSL 开机自启 |
Temp目录会被系统清理,长期留底请复制到<笔记目录>。
11. 一句话总结
Windows 防火墙封 IP 段(主机+Docker 实测全覆盖)+ WSL 内 nftables 双保险 + 公网 DNS/hosts 辅助层,并且用”替身 IP 差异测试”在零 Anthropic 流量的前提下证明机制有效——代理可用、直连必死、代理崩溃不回落。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!














