diff --git a/README.md b/README.md index 517a404..7c5ac43 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ - **当前入口失效**(连续 15 秒不通,或 3 分钟没有握手):自动重新优选并切换。 - **网络变了**(Wi-Fi 重连、插上网线、电脑睡眠后唤醒):隧道自动改走新的网卡。 - **重复打开**:提示“已经在运行”,不会开第二个。 +- **官方 WARP 客户端或其他 VPN 还连着**:提示先断开再运行。两个同时开会变成隧道套隧道,延迟翻倍。 - **程序被强制结束或崩溃**:虚拟网卡和路由由系统随之清除,网络自动恢复。 ### 参数 @@ -153,6 +154,7 @@ go build -trimpath -ldflags "-s -w" -o WarpGameBoost.exe . 版本号显示在窗口标题和第一行,也可以右键 exe →“属性”→“详细信息”查看。 +- **v0.7.1**:检测到官方 WARP 客户端或其他 VPN 正在连接时提示先断开(同时开会隧道套隧道,延迟翻倍)。 - **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 地址),现在可以正常使用。 diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index ea8e59e..e9aeba9 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,8 +1 @@ -默认模式改为:**阻止恶意软件 DNS + IPv4/IPv6 入口一起优选 + IPv4/IPv6 双出口**。双击运行即可,守望先锋不用再加参数。 - -- **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 再测一次暴雪,与直连对比。 - -旧模式仍可用:`-dns system`(仅流量,DNS 保持系统设置)、`-v6only`(出口仅 IPv6,守望先锋会连不上)、`-ipv4=false`(只用 IPv6 入口)。 +检测到官方 WARP 客户端或其他 VPN 正在连接时,提示先断开再运行。两个同时开会变成隧道套隧道,延迟翻倍(实际遇到:游戏里 140ms)。 diff --git a/main_windows.go b/main_windows.go index 098d250..1efb337 100644 --- a/main_windows.go +++ b/main_windows.go @@ -120,6 +120,11 @@ func run() int { fmt.Println("-dns 只能是 malware 或 system") return 1 } + if name := otherVPN(); name != "" { + fmt.Printf("检测到另一个 VPN 正在连接:%s\n", name) + fmt.Println("两个同时开会变成隧道套隧道,延迟翻倍。请先断开它(官方 WARP 客户端点“断开连接”),再运行本程序。") + return 1 + } physIndex6 = defaultInterface(winipcfg.AddressFamily(windows.AF_INET6), 0) if physIndex6 == 0 { // Without IPv6 the only way in is IPv4; say so and carry on rather than @@ -642,6 +647,43 @@ func warpTrace(network string, tries int) string { return "" } +// otherVPN names a connected VPN adapter that would carry this program's own +// tunnel inside it: the official WARP client, or any tunnel adapter holding a +// default route. +func otherVPN() string { + adapters, err := winipcfg.GetAdaptersAddresses(windows.AF_UNSPEC, winipcfg.GAAFlagDefault) + if err != nil { + return "" + } + defaults := map[winipcfg.LUID]bool{} + for _, fam := range []winipcfg.AddressFamily{windows.AF_INET, windows.AF_INET6} { + rows, _ := winipcfg.GetIPForwardTable2(fam) + for i := range rows { + if rows[i].DestinationPrefix.PrefixLength <= 1 { + defaults[rows[i].InterfaceLUID] = true + } + } + } + for _, ad := range adapters { + if ad.OperStatus != winipcfg.IfOperStatusUp || ad.FriendlyName() == adapterName { + continue + } + name := ad.FriendlyName() + " " + ad.Description() + if strings.Contains(strings.ToLower(strings.ReplaceAll(name, " ", "")), "cloudflarewarp") { + return "Cloudflare WARP 官方客户端" + } + tunnelish := ad.IfType == winipcfg.IfTypePropVirtual || ad.IfType == winipcfg.IfTypeTunnel || ad.IfType == winipcfg.IfTypePPP + builtin := false // Windows' own IPv6 transition tunnels are not VPNs + for _, w := range []string{"teredo", "6to4", "isatap", "ip-https"} { + builtin = builtin || strings.Contains(strings.ToLower(name), w) + } + if tunnelish && !builtin && defaults[ad.LUID] { + return ad.FriendlyName() + "(" + ad.Description() + ")" + } + } + return "" +} + // defaultInterface returns the index of the interface holding the preferred // default route of a family, ignoring our own adapter. 0 means none. func defaultInterface(family winipcfg.AddressFamily, skip winipcfg.LUID) uint32 {