1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-10 07:25:37 -05:00
Files
DankMaterialShell/backend/internal/server/network/backend_networkmanager_state.go
2025-11-12 17:18:45 -05:00

272 lines
6.6 KiB
Go

package network
import (
"time"
"github.com/AvengeMedia/DankMaterialShell/backend/internal/errdefs"
"github.com/AvengeMedia/DankMaterialShell/backend/internal/log"
"github.com/Wifx/gonetworkmanager/v2"
)
func (b *NetworkManagerBackend) updatePrimaryConnection() error {
nm := b.nmConn.(gonetworkmanager.NetworkManager)
activeConns, err := nm.GetPropertyActiveConnections()
if err != nil {
return err
}
hasActiveVPN := false
for _, activeConn := range activeConns {
connType, err := activeConn.GetPropertyType()
if err != nil {
continue
}
if connType == "vpn" || connType == "wireguard" {
state, _ := activeConn.GetPropertyState()
if state == 2 {
hasActiveVPN = true
break
}
}
}
if hasActiveVPN {
b.stateMutex.Lock()
b.state.NetworkStatus = StatusVPN
b.stateMutex.Unlock()
return nil
}
primaryConn, err := nm.GetPropertyPrimaryConnection()
if err != nil {
return err
}
if primaryConn == nil || primaryConn.GetPath() == "/" {
b.stateMutex.Lock()
b.state.NetworkStatus = StatusDisconnected
b.stateMutex.Unlock()
return nil
}
connType, err := primaryConn.GetPropertyType()
if err != nil {
return err
}
b.stateMutex.Lock()
switch connType {
case "802-3-ethernet":
b.state.NetworkStatus = StatusEthernet
case "802-11-wireless":
b.state.NetworkStatus = StatusWiFi
case "vpn", "wireguard":
b.state.NetworkStatus = StatusVPN
default:
b.state.NetworkStatus = StatusDisconnected
}
b.stateMutex.Unlock()
return nil
}
func (b *NetworkManagerBackend) updateEthernetState() error {
if b.ethernetDevice == nil {
return nil
}
dev := b.ethernetDevice.(gonetworkmanager.Device)
iface, err := dev.GetPropertyInterface()
if err != nil {
return err
}
state, err := dev.GetPropertyState()
if err != nil {
return err
}
connected := state == gonetworkmanager.NmDeviceStateActivated
var ip string
if connected {
ip = b.getDeviceIP(dev)
}
b.stateMutex.Lock()
b.state.EthernetDevice = iface
b.state.EthernetConnected = connected
b.state.EthernetIP = ip
b.stateMutex.Unlock()
return nil
}
func (b *NetworkManagerBackend) getDeviceStateReason(dev gonetworkmanager.Device) uint32 {
path := dev.GetPath()
obj := b.dbusConn.Object("org.freedesktop.NetworkManager", path)
variant, err := obj.GetProperty(dbusNMDeviceInterface + ".StateReason")
if err != nil {
return 0
}
if stateReasonStruct, ok := variant.Value().([]interface{}); ok && len(stateReasonStruct) >= 2 {
if reason, ok := stateReasonStruct[1].(uint32); ok {
return reason
}
}
return 0
}
func (b *NetworkManagerBackend) classifyNMStateReason(reason uint32) string {
switch reason {
case NmDeviceStateReasonWrongPassword,
NmDeviceStateReasonSupplicantTimeout,
NmDeviceStateReasonSupplicantFailed,
NmDeviceStateReasonSecretsRequired:
return errdefs.ErrBadCredentials
case NmDeviceStateReasonNoSecrets:
return errdefs.ErrUserCanceled
case NmDeviceStateReasonNoSsid:
return errdefs.ErrNoSuchSSID
case NmDeviceStateReasonDhcpClientFailed,
NmDeviceStateReasonIpConfigUnavailable:
return errdefs.ErrDhcpTimeout
case NmDeviceStateReasonSupplicantDisconnect,
NmDeviceStateReasonCarrier:
return errdefs.ErrAssocTimeout
default:
return errdefs.ErrConnectionFailed
}
}
func (b *NetworkManagerBackend) updateWiFiState() error {
if b.wifiDevice == nil {
return nil
}
dev := b.wifiDevice.(gonetworkmanager.Device)
iface, err := dev.GetPropertyInterface()
if err != nil {
return err
}
state, err := dev.GetPropertyState()
if err != nil {
return err
}
connected := state == gonetworkmanager.NmDeviceStateActivated
failed := state == gonetworkmanager.NmDeviceStateFailed
disconnected := state == gonetworkmanager.NmDeviceStateDisconnected
var ip, ssid, bssid string
var signal uint8
if connected {
if err := b.ensureWiFiDevice(); err == nil && b.wifiDev != nil {
w := b.wifiDev.(gonetworkmanager.DeviceWireless)
activeAP, err := w.GetPropertyActiveAccessPoint()
if err == nil && activeAP != nil && activeAP.GetPath() != "/" {
ssid, _ = activeAP.GetPropertySSID()
signal, _ = activeAP.GetPropertyStrength()
bssid, _ = activeAP.GetPropertyHWAddress()
}
}
ip = b.getDeviceIP(dev)
}
b.stateMutex.RLock()
wasConnecting := b.state.IsConnecting
connectingSSID := b.state.ConnectingSSID
b.stateMutex.RUnlock()
var reasonCode string
if wasConnecting && connectingSSID != "" && (failed || (disconnected && !connected)) {
reason := b.getDeviceStateReason(dev)
if reason == NmDeviceStateReasonNewActivation || reason == 0 {
return nil
}
log.Warnf("[updateWiFiState] Connection failed: SSID=%s, state=%d, reason=%d", connectingSSID, state, reason)
reasonCode = b.classifyNMStateReason(reason)
if reasonCode == errdefs.ErrConnectionFailed {
b.failedMutex.RLock()
if b.lastFailedSSID == connectingSSID {
elapsed := time.Now().Unix() - b.lastFailedTime
if elapsed < 5 {
reasonCode = errdefs.ErrBadCredentials
}
}
b.failedMutex.RUnlock()
}
}
b.stateMutex.Lock()
defer b.stateMutex.Unlock()
wasConnecting = b.state.IsConnecting
connectingSSID = b.state.ConnectingSSID
if wasConnecting && connectingSSID != "" {
if connected && ssid == connectingSSID {
log.Infof("[updateWiFiState] Connection successful: %s", ssid)
b.state.IsConnecting = false
b.state.ConnectingSSID = ""
b.state.LastError = ""
} else if failed || (disconnected && !connected) {
log.Warnf("[updateWiFiState] Connection failed: SSID=%s, state=%d", connectingSSID, state)
b.state.IsConnecting = false
b.state.ConnectingSSID = ""
b.state.LastError = reasonCode
// If user cancelled, delete the connection profile that was just created
if reasonCode == errdefs.ErrUserCanceled {
log.Infof("[updateWiFiState] User cancelled authentication, removing connection profile for %s", connectingSSID)
b.stateMutex.Unlock()
if err := b.ForgetWiFiNetwork(connectingSSID); err != nil {
log.Warnf("[updateWiFiState] Failed to remove cancelled connection: %v", err)
}
b.stateMutex.Lock()
}
b.failedMutex.Lock()
b.lastFailedSSID = connectingSSID
b.lastFailedTime = time.Now().Unix()
b.failedMutex.Unlock()
}
}
b.state.WiFiDevice = iface
b.state.WiFiConnected = connected
b.state.WiFiIP = ip
b.state.WiFiSSID = ssid
b.state.WiFiBSSID = bssid
b.state.WiFiSignal = signal
return nil
}
func (b *NetworkManagerBackend) getDeviceIP(dev gonetworkmanager.Device) string {
ip4Config, err := dev.GetPropertyIP4Config()
if err != nil || ip4Config == nil {
return ""
}
addresses, err := ip4Config.GetPropertyAddressData()
if err != nil || len(addresses) == 0 {
return ""
}
return addresses[0].Address
}