From 0c5e996bfd200ca6840c77fabeaaa193a39f7716 Mon Sep 17 00:00:00 2001 From: kevin Date: Tue, 7 Jul 2026 17:37:09 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20Windows=20=E7=AB=AF?= =?UTF-8?q?=20IPv6=20=E6=97=A0=E6=B3=95=E4=B8=8B=E8=A1=8C=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因: netsh interface ipv6 命令参数名用错 - configureIPv6Addr: name= → interface=,IPv6 地址未实际分配到适配器 - SetMTU IPv6: name= → interface= 路由修复: - cidrToV6Prefix: 用 Mask.Size() 取前缀长度,修复 fmt.Sprintf(%d, mask) 输出字节切片的 bug - addRoute6/deleteRoute6: netsh → route -6,用 :: 作 on-link gateway - addRouteVia6/deleteRouteVia6: 加 -6 flag - defaultGateway6: route -6 print :: → route -6 print(避免过滤掉 ::/0) - applyFull: IPv6 bypass 路由失败不再阻断全隧道路由 --- internal/route/route.go | 6 ++++-- internal/route/route_windows.go | 22 ++++++++-------------- internal/tun/tun_windows.go | 10 +++++++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/internal/route/route.go b/internal/route/route.go index 60c6e27..8c9b814 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -138,12 +138,14 @@ func (m *Manager) applyFull() error { } // Bypass: server's public IPv6 via the original v6 gateway. + // Non-fatal: if this fails, full-tunnel routes are still added. if v6 != "" && gw6 != "" { bypassSpec := v6 + "/128" if err := addRouteVia6(bypassSpec, gw6); err != nil { - return fmt.Errorf("add server bypass6 route: %w", err) + m.serverBypass6 = false + } else { + m.serverBypass6 = true } - m.serverBypass6 = true } // Two /1 routes cover the entire IPv4 space and are more specific diff --git a/internal/route/route_windows.go b/internal/route/route_windows.go index 1c530bd..1da09d1 100644 --- a/internal/route/route_windows.go +++ b/internal/route/route_windows.go @@ -75,7 +75,8 @@ func cidrToV6Prefix(cidr string) (network, prefix string, err error) { if err != nil { return "", "", err } - return ipNet.IP.String(), fmt.Sprintf("%d", ipNet.Mask), nil + ones, _ := ipNet.Mask.Size() + return ipNet.IP.String(), fmt.Sprintf("%d", ones), nil } func addRoute6(cidr, iface string) error { @@ -87,8 +88,8 @@ func addRoute6(cidr, iface string) error { if err != nil { return err } - return runCmd("netsh", "interface", "ipv6", "add", "route", - network+"/"+prefix, "interface="+fmt.Sprintf("%d", idx), "metric=1") + return runCmd("route", "-6", "add", network+"/"+prefix, "::", + "if", fmt.Sprintf("%d", idx), "metric", "1") } func deleteRoute6(cidr, iface string) error { @@ -96,12 +97,7 @@ func deleteRoute6(cidr, iface string) error { if err != nil { return err } - idx, err := ifaceIndex(iface) - if err != nil { - return err - } - return runCmd("netsh", "interface", "ipv6", "delete", "route", - network+"/"+prefix, "interface="+fmt.Sprintf("%d", idx)) + return runCmd("route", "-6", "delete", network+"/"+prefix, "::") } func addRouteVia6(cidr, gateway string) error { @@ -109,8 +105,7 @@ func addRouteVia6(cidr, gateway string) error { if err != nil { return err } - return runCmd("netsh", "interface", "ipv6", "add", "route", - network+"/"+prefix, gateway, "metric=1") + return runCmd("route", "-6", "add", network+"/"+prefix, gateway, "metric", "1") } func deleteRouteVia6(cidr, gateway string) error { @@ -118,8 +113,7 @@ func deleteRouteVia6(cidr, gateway string) error { if err != nil { return err } - return runCmd("netsh", "interface", "ipv6", "delete", "route", - network+"/"+prefix, gateway) + return runCmd("route", "-6", "delete", network+"/"+prefix, gateway) } // --- Default gateway --- @@ -133,7 +127,7 @@ func defaultGateway() (string, error) { } func defaultGateway6() (string, error) { - out, err := exec.Command("route", "-6", "print", "::").Output() + out, err := exec.Command("route", "-6", "print").Output() if err != nil { return "", err } diff --git a/internal/tun/tun_windows.go b/internal/tun/tun_windows.go index b39bd9f..7387edb 100644 --- a/internal/tun/tun_windows.go +++ b/internal/tun/tun_windows.go @@ -116,12 +116,16 @@ func (d *wintunDevice) ConfigureIPv6(localIP6 net.IP, prefix6 int) error { func (d *wintunDevice) configureIPv6Addr(ip net.IP, prefix int) error { addr := fmt.Sprintf("%s/%d", ip.String(), prefix) return execCmd("netsh", "interface", "ipv6", "add", "address", - "name="+d.name, "address="+addr) + "interface="+d.name, "address="+addr) } func (d *wintunDevice) SetMTU(mtu int) error { - return execCmd("netsh", "interface", "ipv4", "set", "subinterface", - "name="+d.name, fmt.Sprintf("mtu=%d", mtu)) + if err := execCmd("netsh", "interface", "ipv4", "set", "subinterface", + "name="+d.name, fmt.Sprintf("mtu=%d", mtu)); err != nil { + return err + } + return execCmd("netsh", "interface", "ipv6", "set", "subinterface", + "interface="+d.name, fmt.Sprintf("mtu=%d", mtu)) } // ensureWintunDLL extracts the embedded wintun.dll to the executable's