Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 33 additions & 35 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,57 +57,55 @@ jobs:
$fv = (Get-Item .\WarpGameBoost.exe).VersionInfo
"file version $($fv.FileVersion), product $($fv.ProductName) $($fv.ProductVersion)"
if (-not $fv.FileVersion.StartsWith($env:VERSION_NUM)) { throw "file version $($fv.FileVersion)" }
- name: Self-test with IPv4 exit (the runner has no IPv6, so IPv4 entries are allowed)
- name: Self-test -v6only with system DNS (the runner has no IPv6, so IPv4 entries)
shell: pwsh
run: |
.\WarpGameBoost.exe -selftest -ipv4 -v6only=false -count 80
if ($LASTEXITCODE -ne 0) { throw "selftest failed" }
.\WarpGameBoost.exe -selftest -v6only -dns system -diag=false -count 80
if ($LASTEXITCODE -ne 0) { throw "selftest -v6only failed" }
Start-Sleep 2
if (Get-NetAdapter -Name WarpGameBoost -ErrorAction SilentlyContinue) { throw "adapter left behind" }
- name: Self-test with defaults (IPv6-only exit; no IPv6 here, so IPv4 entries)
- name: Self-test with defaults (diagnosis, both exits, malware-blocking DNS)
shell: pwsh
run: |
.\WarpGameBoost.exe -selftest -count 80
if ($LASTEXITCODE -ne 0) { throw "selftest without IPv6 failed" }
- name: Whole-system traffic leaves over IPv6 only, and a killed process leaves no adapter
if ($LASTEXITCODE -ne 0) { throw "selftest failed" }
- name: Whole-system with defaults, and a killed process leaves no adapter
shell: pwsh
run: |
'' | Set-Content empty.txt
$p = Start-Process .\WarpGameBoost.exe -ArgumentList '-ipv4','-count','80' -RedirectStandardInput empty.txt -RedirectStandardOutput out.txt -PassThru
$ok = $false
foreach ($i in 1..30) {
Start-Sleep 3
$t = try { (Invoke-WebRequest https://www.cloudflare.com/cdn-cgi/trace -UseBasicParsing -TimeoutSec 5).Content } catch { '' }
if ($t -match 'warp=on') { $ok = $true; break }
}
"trace ip: $(($t -split "`n" | Where-Object { $_ -like 'ip=*' }))"
if ($t -notmatch 'ip=[0-9a-f]*:') { Stop-Process -Id $p.Id -Force; throw "exit is not IPv6" }
$c = New-Object Net.Sockets.TcpClient
$sw = [Diagnostics.Stopwatch]::StartNew()
$v4 = try { $c.ConnectAsync('1.1.1.1', 443).Wait(8000) -and $c.Connected } catch { $false }
$c.Dispose()
"IPv4 1.1.1.1:443 reachable: $v4 (answered in $($sw.ElapsedMilliseconds) ms)"
if ($v4) { Stop-Process -Id $p.Id -Force; throw "IPv4 not blocked" }
if ($sw.ElapsedMilliseconds -gt 6000) { Stop-Process -Id $p.Id -Force; throw "IPv4 is dropped, not refused" }
$addrs = [Net.Dns]::GetHostAddresses('www.cloudflare.com') -join ' '
"getaddrinfo: $addrs"
if ($addrs -notmatch ':') { Stop-Process -Id $p.Id -Force; throw "Windows does not hand out IPv6 addresses" }
$p = Start-Process .\WarpGameBoost.exe -ArgumentList '-diag=false','-count','80' -RedirectStandardInput empty.txt -RedirectStandardOutput out.txt -PassThru
function Fail($m) { Get-Content out.txt -Encoding utf8; Stop-Process -Id $p.Id -Force; throw $m }
foreach ($i in 1..40) { Start-Sleep 2; if ((Get-Content out.txt -Raw -Encoding utf8 -ErrorAction SilentlyContinue) -match '加速已开启|失败') { break } }
Get-Content out.txt -Encoding utf8
Get-NetRoute -DestinationPrefix 0.0.0.0/1, 128.0.0.0/1 -ErrorAction SilentlyContinue | Format-Table -AutoSize
# With -v6only the adapter carries Cloudflare's IPv6 resolver and
# nothing else (fec0:0:0:ffff::1-3 are Windows' placeholders).
$dns = (Get-DnsClientServerAddress -InterfaceAlias WarpGameBoost -ErrorAction SilentlyContinue).ServerAddresses | Where-Object { $_ -notlike 'fec0:0:0:ffff::*' }
$t4 = curl.exe -4 -s -m 10 https://www.cloudflare.com/cdn-cgi/trace
$t6 = curl.exe -6 -s -m 10 https://www.cloudflare.com/cdn-cgi/trace
"IPv4 exit: $($t4 | Select-String 'ip=|warp=')"
"IPv6 exit: $($t6 | Select-String 'ip=|warp=')"
if (-not ($t4 -match 'warp=on')) { Fail "IPv4 exit is not WARP" }
if (-not ($t6 -match 'warp=on')) { Fail "IPv6 exit is not WARP" }
# fec0:0:0:ffff::1-3 are the placeholders Windows shows on IPv6
# interfaces without DNS servers.
$dns = (Get-DnsClientServerAddress -InterfaceAlias WarpGameBoost).ServerAddresses | Where-Object { $_ -notlike 'fec0:0:0:ffff::*' }
"adapter DNS servers: [$($dns -join ', ')]"
if (($dns -join ',') -ne '2606:4700:4700::1111,2606:4700:4700::1001') { Stop-Process -Id $p.Id -Force; throw "unexpected adapter DNS: $dns" }
if (($dns -join ',') -ne '1.1.1.2,1.0.0.2,2606:4700:4700::1112,2606:4700:4700::1002') { Fail "unexpected adapter DNS: $dns" }
# The system resolver (no -Server) must be the malware-blocking one:
# Cloudflare's test name resolves to 0.0.0.0 there and normally elsewhere.
Clear-DnsClientCache
$sw = [Diagnostics.Stopwatch]::StartNew()
$resolved = Resolve-DnsName www.blizzard.com -ErrorAction SilentlyContinue | Select-Object -First 1
"system DNS still resolves: $($resolved.Name) in $($sw.ElapsedMilliseconds) ms"
if (-not $resolved) { Stop-Process -Id $p.Id -Force; throw "name resolution broken" }
$blocked = (Resolve-DnsName malware.testcategory.com -Type A -ErrorAction SilentlyContinue | Where-Object Type -eq 'A').IPAddress -join ','
$normal = (Resolve-DnsName www.blizzard.com -Type A -ErrorAction SilentlyContinue | Where-Object Type -eq 'A').IPAddress -join ','
"malware.testcategory.com -> $blocked; www.blizzard.com -> $normal"
if ($blocked -ne '0.0.0.0') { Fail "malware name not blocked" }
if (-not $normal) { Fail "name resolution broken" }
$addrs = [Net.Dns]::GetHostAddresses('www.cloudflare.com') -join ' '
"getaddrinfo: $addrs"
if ($addrs -notmatch ':') { Fail "Windows does not hand out IPv6 addresses" }
Stop-Process -Id $p.Id -Force
Start-Sleep 3
if (-not $ok) { throw "system traffic did not go through WARP" }
if (Get-NetAdapter -Name WarpGameBoost -ErrorAction SilentlyContinue) { throw "adapter left behind after kill" }
Clear-DnsClientCache
$after = (Resolve-DnsName malware.testcategory.com -Type A -ErrorAction SilentlyContinue | Where-Object Type -eq 'A').IPAddress -join ','
"after exit: malware.testcategory.com -> $after"
if ($after -eq '0.0.0.0') { throw "DNS not restored" }
$t = (Invoke-WebRequest https://www.cloudflare.com/cdn-cgi/trace -UseBasicParsing -TimeoutSec 10).Content
if ($t -notmatch 'warp=off') { throw "network not restored: $t" }
"network restored: warp=off"
Expand Down
57 changes: 26 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,30 @@

**Windows 一键 Cloudflare WARP 游戏加速:自动挑出最稳的入口,游戏的 UDP 流量也走加速,关掉窗口就恢复原网络。**

## 出口仅 IPv6(默认开启)
## 默认模式:阻止恶意软件 DNS + IPv4/IPv6 双栈

从 v0.5.0 起,默认**只用 IPv6 访问网络,IPv4 全部禁用**(`-v6only`)。入口用 IPv4 还是 IPv6 跟着你的网络走;出口一律是 Cloudflare 的 IPv6 地址。家里 Wi-Fi 只有 IPv4 也一样可以用。
从 v0.7.0 起,双击运行就是这个模式,不用加任何参数:

| | 默认(`-v6only`) | 加 `-v6only=false` |
| :--- | :--- | :--- |
| 网站看到的地址 | Cloudflare 的 IPv6 | 支持 IPv6 的网站看到 IPv6,其余看到 Cloudflare 的 IPv4 |
| 只有 IPv4 的网站、游戏 | **打不开**(立即被拒,不会卡住) | 正常 |
| DNS | Cloudflare `2606:4700:4700::1111`(经隧道) | 系统设置(仅流量模式) |

> **玩守望先锋等只有 IPv4 服务器的游戏,必须加 `-v6only=false`**,否则游戏连不上。做法:右键 exe →“创建快捷方式”→ 右键快捷方式 →“属性”→ 在“目标”最后加一个空格和 `-v6only=false`,以后打游戏双击这个快捷方式。

为什么 v6only 下 DNS 改用 Cloudflare:只有 IPv4 的网络上,Windows 只在“发出 DNS 查询的网卡有 IPv6”时才给程序 IPv6 地址,否则所有程序都只拿到 IPv4 地址、全部被拒。所以 v6only 给虚拟网卡配上 Cloudflare 的 IPv6 DNS,查询经隧道发出。
| | 默认 |
| :--- | :--- |
| 入口(连 WARP) | **IPv4 和 IPv6 入口一起优选**,选综合最稳的那个;本机没有 IPv6 时只用 IPv4 入口 |
| 出口(访问网站、游戏) | **IPv4 和 IPv6 都走 WARP**:只有 IPv4 的游戏(如守望先锋)照常能玩,支持 IPv6 的网站走 IPv6 |
| DNS | **Cloudflare 阻止恶意软件**(`1.1.1.2`、`1.0.0.2`、`2606:4700:4700::1112`、`2606:4700:4700::1002`),经隧道查询 |
| 加密设备到 Cloudflare 的连接 | 是 |
| 隐藏网站看到的原始公网 IP | 通常可以 |
| 提供匿名性 / 绕过所有封锁 | 不保证 |

## 仅流量模式(`-v6only=false`)
**阻止恶意软件**:Cloudflare 已知的恶意软件、钓鱼网站的域名会被解析成 `0.0.0.0`,直接打不开;其他网站不受影响,不过滤成人内容和广告。想确认生效,开着程序访问 Cloudflare 的测试地址 `malware.testcategory.com`,应该打不开。

加 `-v6only=false` 时,本程序工作在**仅流量模式(Traffic Only)**:网络流量经 Cloudflare WARP 加密隧道传输,但不接管 DNS。
### 其他模式

| 功能 | 仅流量模式 |
| 参数 | 效果 |
| :--- | :--- |
| 通过 Cloudflare WARP 隧道上网 | 是 |
| 加密设备到 Cloudflare 的网络连接 | 是 |
| 隐藏网站看到的原始公网 IP | 通常可以 |
| 使用 Cloudflare 的 DNS 过滤 | 不启用 |
| 改变 DNS 解析行为 | 不改变,保留系统 DNS 设置 |
| 提供匿名性 | 不保证 |
| 绕过所有网络封锁 | 不保证 |
| `-dns system` | **仅流量模式**:虚拟网卡不设 DNS,保持系统设置。路由器 DNS(如 `192.168.1.1`)的查询留在局域网;公网 DNS(如 `8.8.8.8`)的查询经隧道发出 |
| `-ipv4=false` | 只用 IPv6 入口(本机没有 IPv6 时无效,仍用 IPv4) |
| `-v6only` | 出口只走 IPv6,IPv4 全部禁用并立即拒绝。**只有 IPv4 的游戏(如守望先锋)会连不上**,不适合打游戏 |

DNS 怎么走:
- 系统 DNS 是路由器(如 `192.168.1.1`)时,查询留在局域网内,再由路由器交给运营商解析,**不经过隧道**。
- 系统 DNS 是公网服务器(如 `8.8.8.8`)时,查询经隧道到 Cloudflare 后再发往该服务器。
- 公司内网域名、路由器自带的本地域名都照常解析。
想固定用某个模式:右键 exe →“创建快捷方式”→ 右键快捷方式 →“属性”→ 在“目标”最后加一个空格和参数,以后双击这个快捷方式。

## 解决什么问题

Expand Down Expand Up @@ -63,7 +55,7 @@ DNS 怎么走:
| → 运营商 | 先 traceroute 找到第一个公网路由器,再 ping 它 | 运营商接入有问题,WARP 也要经过这一段,**帮不上** |
| → 暴雪(美东) | 对 `overwatch.blizzard.com`(AWS 弗吉尼亚)做 TLS 握手计时 | 前两段正常而这段不稳 = 运营商到暴雪的线路问题,**这种情况 WARP 可能有帮助** |

用 `-v6only=false` 运行时,连上 WARP 后还会**经 WARP 再测一次暴雪**,和直连并排对比,直接告诉你开加速更稳还是直连更好。
连上 WARP 后还会**经 WARP 再测一次暴雪**,和直连并排对比,直接告诉你开加速更稳还是直连更好。

说明:
- 测的是暴雪美东的网站服务器,不是对局服务器(对局服务器地址不公开),所以延迟数字只代表到暴雪美东的线路,和游戏里显示的不完全一样。
Expand Down Expand Up @@ -95,8 +87,9 @@ DNS 怎么走:
| 参数 | 作用 |
| :--- | :--- |
| `-diag=false` | 跳过启动时的网络诊断 |
| `-v6only=false` | 恢复 IPv4 出口(仅流量模式,DNS 用系统设置)。**玩只有 IPv4 的游戏(如守望先锋)时必须加** |
| `-ipv4` | 有 IPv6 时也同时测试 IPv4 入口(默认有 IPv6 就只用 IPv6 入口) |
| `-dns system` | DNS 保持系统设置(仅流量模式);默认 `malware` = Cloudflare 阻止恶意软件 |
| `-ipv4=false` | 只用 IPv6 入口(默认 IPv4、IPv6 入口一起优选) |
| `-v6only` | 出口只走 IPv6,禁用 IPv4(守望先锋会连不上) |
| `-count 200` | 每次优选测试的入口数量 |
| `-v` | 显示 WireGuard 调试日志(排查连不上时用) |
| `-version` | 显示版本号后退出 |
Expand All @@ -112,18 +105,19 @@ DNS 怎么走:

- **整台电脑都走 WARP**:开着时网站和游戏看到的是 Cloudflare 的地址,游戏可能按这个地址判断地区。在美国打美服,出口也在美国,影响不大。
- **Cloudflare 能看到你连了哪些服务器**,看不到加密的内容。
- **域名解析**:默认(v6only)DNS 经隧道发给 Cloudflare;加 `-v6only=false` 时用系统设置,不加密,运营商或路由器能看到你查询了哪些域名。这个程序是游戏加速,不是隐私工具。
- **域名解析**:默认经隧道发给 Cloudflare 的阻止恶意软件 DNS,运营商看不到;Cloudflare 能看到你查询了哪些域名。加 `-dns system` 时用系统设置,不加密,运营商或路由器能看到。这个程序是游戏加速,不是隐私工具。
- **不要同时开其他 VPN 或官方 WARP 客户端**,它们会争抢路由。
- 免费账号注册使用 WARP 官方 App 的同一接口(非公开 API),Cloudflare 可能随时更改或限制。
- 部分杀毒软件可能对虚拟网卡驱动或网络程序误报。

## 工作原理

1. **优选**:从 Cloudflare WARP 的入口地址段(IPv6 `2606:4700:d0::/48`、`d1::/48`,必要时 IPv4 `162.159.192–195.x`、`188.114.96–99.x`)和 50 多个 UDP 端口中随机抽约 200 个,每个发 5 次 WireGuard 握手,按“平均延迟 + 2×抖动 + 丢包”打分。
1. **优选**:从 Cloudflare WARP 的入口地址段(IPv6 `2606:4700:d0::/48`、`d1::/48` 和 IPv4 `162.159.192–195.x`、`188.114.96–99.x`)和 50 多个 UDP 端口中随机抽约 200 个,每个发 5 次 WireGuard 握手,按“平均延迟 + 2×抖动 + 丢包”打分。
- 所有探测包用同一把密钥,而 WARP 服务器会丢弃时间戳不比上一次新的握手。程序保证每个探测包的时间戳都比之前的新,否则会把服务器的丢弃误判成入口丢包(v0.2.0 修复前约每 5 次误判 1 次)。
2. **隧道**:用 [wireguard-go](https://git.zx2c4.com/wireguard-go) 和 WireGuard 官方的 [Wintun](https://www.wintun.net/) 虚拟网卡建立隧道,MTU 1280。
3. **路由**:加 `0.0.0.0/1`、`128.0.0.0/1`、`::/1`、`8000::/1` 四条路由,盖过默认路由但不修改它;隧道自己的 UDP 包绑定在实体网卡上发出。关闭虚拟网卡,这些路由随之消失。
4. **出口仅 IPv6**(默认):IPv4 仍然全部进虚拟网卡(不会绕过隧道直连),但在交给 WireGuard 之前就被拦下:TCP 回一个 RST、其他回 ICMP 不可达,程序立刻知道“连不上”并改用 IPv6,而不是干等超时。系统里原本的 IPv4 DNS 服务器例外放行。虚拟网卡另加一条 `::/0` 路由,让没有 IPv6 的网络上 Windows 也把 IPv6 当作可用。
4. **DNS**:虚拟网卡的接口优先级设为最高(metric 0)并配上 Cloudflare 阻止恶意软件的 DNS,Windows 优先问它,查询经隧道发出。程序退出、虚拟网卡删除后,DNS 自动回到系统原来的设置。
5. **出口仅 IPv6**(`-v6only`):IPv4 仍然全部进虚拟网卡(不会绕过隧道直连),但在交给 WireGuard 之前就被拦下:TCP 回一个 RST、其他回 ICMP 不可达,程序立刻知道“连不上”并改用 IPv6,而不是干等超时。系统里原本的 IPv4 DNS 服务器例外放行。虚拟网卡另加一条 `::/0` 路由,让没有 IPv6 的网络上 Windows 也把 IPv6 当作可用。

## 文件

Expand Down Expand Up @@ -159,6 +153,7 @@ go build -trimpath -ldflags "-s -w" -o WarpGameBoost.exe .

版本号显示在窗口标题和第一行,也可以右键 exe →“属性”→“详细信息”查看。

- **v0.7.0**:默认改为“阻止恶意软件 DNS(Cloudflare `1.1.1.2`)+ IPv4/IPv6 入口一起优选 + IPv4/IPv6 双出口”,守望先锋不用再加参数。`-v6only` 改为可选(默认关);原来的仅流量模式用 `-dns system`。
- **v0.6.0**:新增网络诊断(默认开启,`-diag=false` 跳过):启动时测“电脑→路由器”“→运营商”“→暴雪美东”三段的延迟、抖动、丢包,指出问题在哪一段并给出做法;`-v6only=false` 时连上后再经 WARP 测一次暴雪,与直连对比,告诉你开不开加速更好。
- **v0.5.0**:新增出口仅 IPv6(`-v6only`,默认开启):IPv4 全部禁用且立即拒绝,DNS 改用经隧道的 Cloudflare IPv6 解析;只有 IPv4 的游戏(如守望先锋)要加 `-v6only=false`。修复:本机没有 IPv6 时,以前经隧道的 IPv6 实际用不上(Windows 只给程序 IPv4 地址),现在可以正常使用。
- **v0.4.0**:改为仅流量模式:虚拟网卡不再设置 Cloudflare DNS,DNS 保持系统设置。
Expand Down
12 changes: 6 additions & 6 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
新增**网络诊断**(默认开启,加 `-diag=false` 跳过)。
默认模式改为:**阻止恶意软件 DNS + IPv4/IPv6 入口一起优选 + IPv4/IPv6 双出口**。双击运行即可,守望先锋不用再加参数。

启动时先花约 20 秒测三段的延迟、抖动、丢包:电脑→路由器、→运营商(traceroute 找到的第一个公网路由器)、→暴雪美东(`overwatch.blizzard.com` 的 TLS 握手计时)。然后告诉你问题在哪一段:
- 家里 Wi-Fi/路由器不稳:WARP 帮不上,给出插网线、5GHz、关定位、关网卡节能、开 SQM 等做法;
- 运营商接入不稳:WARP 也帮不上;
- 运营商到暴雪的线路不稳:WARP 可能有帮助。
- **DNS**:Cloudflare 阻止恶意软件(`1.1.1.2`、`1.0.0.2`、`2606:4700:4700::1112`、`2606:4700:4700::1002`),经隧道查询。已知的恶意软件、钓鱼域名解析为 `0.0.0.0`。程序退出后 DNS 回到系统设置。
- **入口**:IPv4 和 IPv6 入口一起优选(本机没有 IPv6 时只用 IPv4)。
- **出口**:IPv4 和 IPv6 都经 WARP,启动后显示两个出口地址。
- 连上后经 WARP 再测一次暴雪,与直连对比。

用 `-v6only=false` 运行(守望先锋需要)时,连上 WARP 后会**经 WARP 再测一次暴雪**,与直连并排对比,直接告诉你开加速更稳还是直连更好。
旧模式仍可用:`-dns system`(仅流量,DNS 保持系统设置)、`-v6only`(出口仅 IPv6,守望先锋会连不上)、`-ipv4=false`(只用 IPv6 入口)。
4 changes: 2 additions & 2 deletions diag.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,15 @@ func verdict(gw, isp, target *series, wifi bool) []string {
case bad(target, false):
return []string{
"问题在运营商到暴雪的线路:家里和运营商接入都正常,往后才不稳。",
" · 这种情况 WARP 加速可能有帮助:守望先锋只有 IPv4,请用 -v6only=false 运行,开和不开各打几局对比",
" · 这种情况 WARP 加速可能有帮助:开和不开各打几局,用游戏里的网络图(Ctrl+Shift+N)对比",
}
case !measured(target):
return []string{"家里网络和运营商接入正常;暴雪服务器没测到,无法判断后面的线路。"}
default:
return []string{
"三段都正常,网络本身没有明显问题。",
" · 游戏里仍然卡,可能是游戏服务器或本机(后台下载、同步、杀毒扫描)",
" · 不一定需要加速;想试试 WARP,守望先锋请用 -v6only=false",
" · 不一定需要加速;下面会经 WARP 再测一次,对比后再决定",
}
}
}
Expand Down
Loading
Loading