Ver Fonte

Add Windows WI-FI state support

世界 há 2 semanas atrás
pai
commit
6e8222f6ce
4 ficheiros alterados com 148 adições e 10 exclusões
  1. 1 1
      common/settings/wifi_stub.go
  2. 144 0
      common/settings/wifi_windows.go
  3. 1 1
      go.mod
  4. 2 8
      go.sum

+ 1 - 1
common/settings/wifi_stub.go

@@ -1,4 +1,4 @@
-//go:build !linux
+//go:build !linux && !windows
 
 package settings
 

+ 144 - 0
common/settings/wifi_windows.go

@@ -0,0 +1,144 @@
+//go:build windows
+
+package settings
+
+import (
+	"context"
+	"fmt"
+	"strings"
+	"sync"
+	"syscall"
+
+	"github.com/sagernet/sing-box/adapter"
+	"github.com/sagernet/sing/common/winwlanapi"
+
+	"golang.org/x/sys/windows"
+)
+
+type windowsWIFIMonitor struct {
+	handle    windows.Handle
+	callback  func(adapter.WIFIState)
+	cancel    context.CancelFunc
+	lastState adapter.WIFIState
+	mutex     sync.Mutex
+}
+
+func NewWIFIMonitor(callback func(adapter.WIFIState)) (WIFIMonitor, error) {
+	handle, err := winwlanapi.OpenHandle()
+	if err != nil {
+		return nil, err
+	}
+
+	interfaces, err := winwlanapi.EnumInterfaces(handle)
+	if err != nil {
+		winwlanapi.CloseHandle(handle)
+		return nil, err
+	}
+	if len(interfaces) == 0 {
+		winwlanapi.CloseHandle(handle)
+		return nil, fmt.Errorf("no wireless interfaces found")
+	}
+
+	return &windowsWIFIMonitor{
+		handle:   handle,
+		callback: callback,
+	}, nil
+}
+
+func (m *windowsWIFIMonitor) ReadWIFIState() adapter.WIFIState {
+	interfaces, err := winwlanapi.EnumInterfaces(m.handle)
+	if err != nil || len(interfaces) == 0 {
+		return adapter.WIFIState{}
+	}
+
+	for _, iface := range interfaces {
+		if iface.InterfaceState != winwlanapi.InterfaceStateConnected {
+			continue
+		}
+
+		guid := iface.InterfaceGUID
+		attrs, err := winwlanapi.QueryCurrentConnection(m.handle, &guid)
+		if err != nil {
+			continue
+		}
+
+		ssidLength := attrs.AssociationAttributes.SSID.Length
+		if ssidLength == 0 || ssidLength > winwlanapi.Dot11SSIDMaxLength {
+			continue
+		}
+
+		ssid := string(attrs.AssociationAttributes.SSID.SSID[:ssidLength])
+		bssid := formatBSSID(attrs.AssociationAttributes.BSSID)
+
+		return adapter.WIFIState{
+			SSID:  strings.TrimSpace(ssid),
+			BSSID: bssid,
+		}
+	}
+
+	return adapter.WIFIState{}
+}
+
+func formatBSSID(mac winwlanapi.Dot11MacAddress) string {
+	return fmt.Sprintf("%02X%02X%02X%02X%02X%02X",
+		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])
+}
+
+func (m *windowsWIFIMonitor) Start() error {
+	if m.callback == nil {
+		return nil
+	}
+
+	ctx, cancel := context.WithCancel(context.Background())
+	m.cancel = cancel
+
+	m.lastState = m.ReadWIFIState()
+
+	callbackFunc := func(data *winwlanapi.NotificationData, callbackContext uintptr) uintptr {
+		if data.NotificationSource != winwlanapi.NotificationSourceACM {
+			return 0
+		}
+		switch data.NotificationCode {
+		case winwlanapi.NotificationACMConnectionComplete,
+			winwlanapi.NotificationACMDisconnected:
+			m.checkAndNotify()
+		}
+		return 0
+	}
+
+	callbackPointer := syscall.NewCallback(callbackFunc)
+
+	err := winwlanapi.RegisterNotification(m.handle, winwlanapi.NotificationSourceACM, callbackPointer, 0)
+	if err != nil {
+		cancel()
+		return err
+	}
+
+	go func() {
+		<-ctx.Done()
+	}()
+
+	m.callback(m.lastState)
+	return nil
+}
+
+func (m *windowsWIFIMonitor) checkAndNotify() {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+
+	state := m.ReadWIFIState()
+	if state != m.lastState {
+		m.lastState = state
+		if m.callback != nil {
+			m.callback(state)
+		}
+	}
+}
+
+func (m *windowsWIFIMonitor) Close() error {
+	if m.cancel != nil {
+		m.cancel()
+	}
+	winwlanapi.UnregisterNotification(m.handle)
+	return winwlanapi.CloseHandle(m.handle)
+}

+ 1 - 1
go.mod

@@ -29,7 +29,7 @@ require (
 	github.com/sagernet/gomobile v0.1.8
 	github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
 	github.com/sagernet/quic-go v0.57.1-sing-box-mod.1
-	github.com/sagernet/sing v0.8.0-beta.6
+	github.com/sagernet/sing v0.8.0-beta.6.0.20251207063731-56fd482ce1c6
 	github.com/sagernet/sing-mux v0.3.3
 	github.com/sagernet/sing-quic v0.6.0-beta.5
 	github.com/sagernet/sing-shadowsocks v0.2.8

+ 2 - 8
go.sum

@@ -139,8 +139,6 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4=
 github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4=
-github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
-github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
 github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
 github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -162,17 +160,13 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN
 github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
 github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
 github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
-github.com/sagernet/quic-go v0.55.0-sing-box-mod.2 h1:I79gW4Xl5ciVARHfnp122lDAMhC0AwUCU765Q8Kxdfo=
-github.com/sagernet/quic-go v0.55.0-sing-box-mod.2/go.mod h1:IE9naq7Kekj0rPAdWc0GLW1ENR7gAOQV9VRTDlKN8Bk=
 github.com/sagernet/quic-go v0.57.1-sing-box-mod.1 h1:6fhKbfA0b7L1CVekayV1g87uJFtMXFE0rFXR48SRrWI=
 github.com/sagernet/quic-go v0.57.1-sing-box-mod.1/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4=
 github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
-github.com/sagernet/sing v0.8.0-beta.6 h1:GXv1j1xWHihx6ptyOXh0yp4jUqJoNjCqD8d+AI9rnLU=
-github.com/sagernet/sing v0.8.0-beta.6/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
+github.com/sagernet/sing v0.8.0-beta.6.0.20251207063731-56fd482ce1c6 h1:EYaDzllFzNYnzQ9xH/ieSAXct4wQ8pD45kgNMo7RPZc=
+github.com/sagernet/sing v0.8.0-beta.6.0.20251207063731-56fd482ce1c6/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
 github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw=
 github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
-github.com/sagernet/sing-quic v0.6.0-beta.4 h1:2k/+Xrv/pjl7AYC7LD9tcB7y1lIgw04LjJjqTI8q5Xk=
-github.com/sagernet/sing-quic v0.6.0-beta.4/go.mod h1:FNvKPADzMZprwm7UQCcCGPhYifpb5rxoCOntOupJU+8=
 github.com/sagernet/sing-quic v0.6.0-beta.5 h1:kZfRLmsPxAgl0usZUgomDurLn7ZZ26lJWIpGow9ZWR4=
 github.com/sagernet/sing-quic v0.6.0-beta.5/go.mod h1:9D9GANrK33NjWCe1VkU5L5+8MxU39WrduBSmHuHz8GA=
 github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=