diff --git a/proxy/tun/tun_windows.go b/proxy/tun/tun_windows.go index 2097b6894..4c5a0ed88 100644 --- a/proxy/tun/tun_windows.go +++ b/proxy/tun/tun_windows.go @@ -3,14 +3,14 @@ package tun import ( - "context" "crypto/md5" "encoding/binary" go_errors "errors" "net" "net/netip" + "sort" + "strings" "sync" - "time" "unsafe" "github.com/xtls/xray-core/common/errors" @@ -31,14 +31,13 @@ func procyield(cycles uint32) type WindowsTun struct { sync.RWMutex - options *Config - adapter *wintun.Adapter - session wintun.Session - readWait windows.Handle - luid winipcfg.LUID - cbr winipcfg.ChangeCallback - cbi winipcfg.ChangeCallback - closed bool + options *Config + adapter *wintun.Adapter + session wintun.Session + readWait windows.Handle + luid winipcfg.LUID + changeCallback winipcfg.ChangeCallback + closed bool } // WindowsTun implements Tun @@ -86,37 +85,23 @@ func open(name, desc string) (*wintun.Adapter, error) { return nil, err } -func (t *WindowsTun) Start() (err error) { - var address4, address6 bool - addresses := make([]netip.Prefix, 0, len(t.options.Gateway)) - for _, cidr := range t.options.Gateway { - prefix := netip.MustParsePrefix(cidr) - if prefix.Addr().Is4() { - address4 = true - } else { - address6 = true - } - addresses = append(addresses, prefix) +func (t *WindowsTun) Start() error { + var has4, has6 bool + allowedIPs := make([]netip.Prefix, 0, len(t.options.AutoSystemRoutingTable)) + for _, route := range t.options.AutoSystemRoutingTable { + allowedIPs = append(allowedIPs, netip.MustParsePrefix(route)) } - - dns := make([]netip.Addr, 0, len(t.options.DNS)) - for _, ip := range t.options.DNS { - dns = append(dns, netip.MustParseAddr(ip)) - } - - var route4, route6 bool routesMap := make(map[winipcfg.RouteData]struct{}) - for _, cidr := range t.options.AutoSystemRoutingTable { - prefix := netip.MustParsePrefix(cidr) + for _, ip := range allowedIPs { route := winipcfg.RouteData{ - Destination: prefix.Masked(), + Destination: ip.Masked(), Metric: 0, } - if prefix.Addr().Is4() { - route4 = true + if ip.Addr().Is4() { + has4 = true route.NextHop = netip.IPv4Unspecified() } else { - route6 = true + has6 = true route.NextHop = netip.IPv6Unspecified() } routesMap[route] = struct{}{} @@ -126,40 +111,24 @@ func (t *WindowsTun) Start() (err error) { r := route routesData = append(routesData, &r) } - - var retryTimes int - var firstErr error -startOver: - if retryTimes > 0 { - if retryTimes > 15 { - return windows.ERROR_NOT_FOUND - } - errors.LogErrorInner(context.Background(), firstErr, "Interface configuration failed, retrying attempt ", retryTimes, "/15") - time.Sleep(time.Second) + err := t.luid.SetRoutes(routesData) + if err != nil { + return errors.New("unable to set routes").Base(err) } - retryTimes++ - for _, family := range []winipcfg.AddressFamily{windows.AF_INET, windows.AF_INET6} { - if family == windows.AF_INET && route4 || family == windows.AF_INET6 && route6 { - err = t.luid.SetRoutesForFamily(family, routesData) - if err != nil { - firstErr = errors.New("unable to set routes").Base(err) - if err == windows.ERROR_NOT_FOUND { - goto startOver - } - return firstErr - } + + if len(t.options.Gateway) > 0 { + addresses := make([]netip.Prefix, 0, len(t.options.Gateway)) + for _, address := range t.options.Gateway { + addresses = append(addresses, netip.MustParsePrefix(address)) } - if family == windows.AF_INET && address4 || family == windows.AF_INET6 && address6 { - err = t.luid.SetIPAddressesForFamily(family, addresses) - if err != nil { - firstErr = errors.New("unable to set ips").Base(err) - if err == windows.ERROR_NOT_FOUND { - goto startOver - } - return firstErr - } + err := t.luid.SetIPAddresses(addresses) + if err != nil { + return errors.New("unable to set ips").Base(err) } - ipif, err := t.luid.IPInterface(family) + } + + if has4 { + ipif, err := t.luid.IPInterface(windows.AF_INET) if err != nil { return err } @@ -167,45 +136,56 @@ startOver: ipif.DadTransmits = 0 ipif.ManagedAddressConfigurationSupported = false ipif.OtherStatefulConfigurationSupported = false - if family == windows.AF_INET && (address4 || route4) || family == windows.AF_INET6 && (address6 || route6) { - ipif.NLMTU = t.options.MTU - } - if family == windows.AF_INET && route4 || family == windows.AF_INET6 && route6 { - ipif.UseAutomaticMetric = false - ipif.Metric = 0 - } + ipif.NLMTU = t.options.MTU + ipif.UseAutomaticMetric = false + ipif.Metric = 0 err = ipif.Set() if err != nil { - firstErr = errors.New("unable to set metric and MTU").Base(err) - if err == windows.ERROR_NOT_FOUND { - goto startOver - } - return firstErr + return err } - err = t.luid.SetDNS(family, dns, nil) + } + if has6 { + ipif, err := t.luid.IPInterface(windows.AF_INET6) if err != nil { - firstErr = errors.New("unable to set DNS").Base(err) - if err == windows.ERROR_NOT_FOUND { - goto startOver - } - return firstErr + return err + } + ipif.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled + ipif.DadTransmits = 0 + ipif.ManagedAddressConfigurationSupported = false + ipif.OtherStatefulConfigurationSupported = false + ipif.NLMTU = t.options.MTU + ipif.UseAutomaticMetric = false + ipif.Metric = 0 + err = ipif.Set() + if err != nil { + return err + } + } + + if len(t.options.DNS) > 0 { + dns := make([]netip.Addr, 0, len(t.options.DNS)) + for _, ip := range t.options.DNS { + dns = append(dns, netip.MustParseAddr(ip)) + } + err := t.luid.SetDNS(windows.AF_INET, dns, nil) + if err != nil { + return err + } + err = t.luid.SetDNS(windows.AF_INET6, dns, nil) + if err != nil { + return err } } if updater != nil { - t.cbr, err = winipcfg.RegisterRouteChangeCallback(func(notificationType winipcfg.MibNotificationType, route *winipcfg.MibIPforwardRow2) { - updater.Update() - }) - if err != nil { - return err - } - t.cbi, err = winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) { + t.changeCallback, err = winipcfg.RegisterInterfaceChangeCallback(func(notificationType winipcfg.MibNotificationType, iface *winipcfg.MibIPInterfaceRow) { updater.Update() }) if err != nil { return err } } + return nil } @@ -217,26 +197,12 @@ func (t *WindowsTun) Close() error { } t.closed = true - if t.cbr != nil { - t.cbr.Unregister() - } - if t.cbi != nil { - t.cbi.Unregister() - } - if t.luid != 0 { - t.luid.FlushRoutes(windows.AF_INET) - t.luid.FlushIPAddresses(windows.AF_INET) - t.luid.FlushDNS(windows.AF_INET) - t.luid.FlushRoutes(windows.AF_INET6) - t.luid.FlushIPAddresses(windows.AF_INET6) - t.luid.FlushDNS(windows.AF_INET6) - } - if t.session != (wintun.Session{}) { - t.session.End() - } - if t.adapter != nil { - t.adapter.Close() + if t.changeCallback != nil { + t.changeCallback.Unregister() } + t.session.End() + _ = t.adapter.Close() + return nil } @@ -345,49 +311,75 @@ func setinterface(network, address string, fd uintptr, iface *net.Interface) err } func findOutboundInterface(tunIndex int, fixedName string) (*net.Interface, error) { - if fixedName != "" { - return net.InterfaceByName(fixedName) - } - - r, err := winipcfg.GetIPForwardTable2(windows.AF_UNSPEC) + interfaces, err := net.Interfaces() if err != nil { return nil, err } - lowestMetric := ^uint32(0) - index := uint32(0) - lowestMetricWifi := ^uint32(0) - indexWifi := uint32(0) - for i := range r { - if r[i].DestinationPrefix.PrefixLength != 0 || r[i].InterfaceIndex == uint32(tunIndex) { - continue - } - ifrow, err := r[i].InterfaceLUID.Interface() - if err != nil || ifrow.OperStatus != winipcfg.IfOperStatusUp { - continue - } - iface, err := r[i].InterfaceLUID.IPInterface(windows.AF_INET) - if err != nil { - iface, err = r[i].InterfaceLUID.IPInterface(windows.AF_INET6) - if err != nil { - continue + if fixedName != "" { + for _, iface := range interfaces { + if iface.Index != tunIndex && iface.Name == fixedName { + return &iface, nil } } + return nil, nil + } - if ifrow.Type == windows.IF_TYPE_IEEE80211 { - if r[i].Metric+iface.Metric < lowestMetricWifi { - lowestMetricWifi = r[i].Metric + iface.Metric - indexWifi = r[i].InterfaceIndex - } + var candidates []struct { + index int + score int + } + for i, iface := range interfaces { + if iface.Index == tunIndex { continue } - if r[i].Metric+iface.Metric < lowestMetric { - lowestMetric = r[i].Metric + iface.Metric - index = r[i].InterfaceIndex + if strings.Contains(iface.Name, "vEthernet") { + continue } + if iface.Flags&net.FlagUp == 0 { + continue + } + if iface.Flags&net.FlagLoopback != 0 { + continue + } + addrs, err := iface.Addrs() + if err != nil || len(addrs) == 0 { + continue + } + candidates = append(candidates, struct { + index int + score int + }{i, scoreWindowsInterface(&iface, addrs)}) } - if indexWifi != 0 { - index = indexWifi + + sort.Slice(candidates, func(i, j int) bool { + if candidates[i].score != candidates[j].score { + return candidates[i].score > candidates[j].score + } + return interfaces[candidates[i].index].Name < interfaces[candidates[j].index].Name + }) + if len(candidates) == 0 { + return nil, nil } - return net.InterfaceByIndex(int(index)) + + iface := interfaces[candidates[0].index] + return &iface, nil +} + +func scoreWindowsInterface(iface *net.Interface, addrs []net.Addr) int { + score := 0 + + name := strings.ToLower(iface.Name) + if strings.Contains(name, "wlan") || strings.Contains(name, "wi-fi") { + score += 2 + } + + for _, addr := range addrs { + if strings.HasPrefix(addr.String(), "192.168.") { + score++ + break + } + } + + return score }