From 319043818a75039ed13003375df5a090baaead0a Mon Sep 17 00:00:00 2001 From: Mykola Baibuz Date: Wed, 2 Apr 2025 11:33:15 +0300 Subject: [PATCH] Add DBus network checker for Linux --- client/mozilla/networkwatcher.cpp | 4 ++- client/mozilla/networkwatcher.h | 1 + client/mozilla/networkwatcherimpl.h | 2 ++ .../platforms/linux/linuxnetworkwatcher.cpp | 3 ++ .../linux/linuxnetworkwatcherworker.cpp | 33 ++++++++++++++++++- .../linux/linuxnetworkwatcherworker.h | 2 ++ client/vpnconnection.cpp | 14 ++++++-- client/vpnconnection.h | 1 + ipc/ipc_interface.rep | 3 +- ipc/ipcserver.h | 3 -- service/server/localserver.cpp | 6 ++-- service/server/localserver.h | 4 ++- 12 files changed, 65 insertions(+), 11 deletions(-) diff --git a/client/mozilla/networkwatcher.cpp b/client/mozilla/networkwatcher.cpp index 59caf1f2..5d7716f6 100644 --- a/client/mozilla/networkwatcher.cpp +++ b/client/mozilla/networkwatcher.cpp @@ -51,7 +51,7 @@ NetworkWatcher::NetworkWatcher() { MZ_COUNT_CTOR(NetworkWatcher); } NetworkWatcher::~NetworkWatcher() { MZ_COUNT_DTOR(NetworkWatcher); } void NetworkWatcher::initialize() { - logger.debug() << "Initialize"; + logger.debug() << "Initialize NetworkWatcher"; #if defined(MZ_WINDOWS) m_impl = new WindowsNetworkWatcher(this); @@ -73,6 +73,8 @@ void NetworkWatcher::initialize() { &NetworkWatcher::unsecuredNetwork); connect(m_impl, &NetworkWatcherImpl::networkChanged, this, &NetworkWatcher::networkChange); + connect(m_impl, &NetworkWatcherImpl::sleepMode, this, + &NetworkWatcher::sleepMode); m_impl->initialize(); diff --git a/client/mozilla/networkwatcher.h b/client/mozilla/networkwatcher.h index 43536dc3..4f86e2a4 100644 --- a/client/mozilla/networkwatcher.h +++ b/client/mozilla/networkwatcher.h @@ -33,6 +33,7 @@ public: signals: void networkChange(); + void sleepMode(); private: void settingsChanged(); diff --git a/client/mozilla/networkwatcherimpl.h b/client/mozilla/networkwatcherimpl.h index 78117dca..54bd8e87 100644 --- a/client/mozilla/networkwatcherimpl.h +++ b/client/mozilla/networkwatcherimpl.h @@ -41,6 +41,8 @@ signals: // TODO: Only windows-networkwatcher has this, the other plattforms should // too. void networkChanged(QString newBSSID); + void sleepMode(); + private: bool m_active = false; diff --git a/client/platforms/linux/linuxnetworkwatcher.cpp b/client/platforms/linux/linuxnetworkwatcher.cpp index c8ae0fea..22eba3c7 100644 --- a/client/platforms/linux/linuxnetworkwatcher.cpp +++ b/client/platforms/linux/linuxnetworkwatcher.cpp @@ -41,6 +41,9 @@ void LinuxNetworkWatcher::initialize() { connect(m_worker, &LinuxNetworkWatcherWorker::unsecuredNetwork, this, &LinuxNetworkWatcher::unsecuredNetwork); + connect(m_worker, &LinuxNetworkWatcherWorker::sleepMode, this, + &NetworkWatcherImpl::sleepMode); + // Let's wait a few seconds to allow the UI to be fully loaded and shown. // This is not strictly needed, but it's better for user experience because // it makes the UI faster to appear, plus it gives a bit of delay between the diff --git a/client/platforms/linux/linuxnetworkwatcherworker.cpp b/client/platforms/linux/linuxnetworkwatcherworker.cpp index 19ed3251..247a1d67 100644 --- a/client/platforms/linux/linuxnetworkwatcherworker.cpp +++ b/client/platforms/linux/linuxnetworkwatcherworker.cpp @@ -33,7 +33,21 @@ #define NM_802_11_AP_SEC_WEAK_CRYPTO \ (NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104) + +enum NMState { + NM_STATE_UNKNOWN = 0, + NM_STATE_ASLEEP = 10, + NM_STATE_DISCONNECTED = 20, + NM_STATE_DISCONNECTING = 30, + NM_STATE_CONNECTING = 40, + NM_STATE_CONNECTED_LOCAL = 50, + NM_STATE_CONNECTED_SITE = 60, + NM_STATE_CONNECTED_GLOBAL = 70 +}; + + constexpr const char* DBUS_NETWORKMANAGER = "org.freedesktop.NetworkManager"; +constexpr const char* DBUS_NETWORKMANAGER_PATH = "/org/freedesktop/NetworkManager"; namespace { Logger logger("LinuxNetworkWatcherWorker"); @@ -73,7 +87,7 @@ void LinuxNetworkWatcherWorker::initialize() { // documentation: // https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.html - QDBusInterface nm(DBUS_NETWORKMANAGER, "/org/freedesktop/NetworkManager", + QDBusInterface nm(DBUS_NETWORKMANAGER, DBUS_NETWORKMANAGER_PATH, DBUS_NETWORKMANAGER, QDBusConnection::systemBus()); if (!nm.isValid()) { logger.error() @@ -108,6 +122,12 @@ void LinuxNetworkWatcherWorker::initialize() { SLOT(propertyChanged(QString, QVariantMap, QStringList))); } + QDBusConnection::systemBus().connect(DBUS_NETWORKMANAGER, + DBUS_NETWORKMANAGER_PATH, + DBUS_NETWORKMANAGER, + "StateChanged", + this, SLOT(NMStateChanged(quint32))); + if (m_devicePaths.isEmpty()) { logger.warning() << "No wifi devices found"; return; @@ -173,5 +193,16 @@ void LinuxNetworkWatcherWorker::checkDevices() { emit unsecuredNetwork(ssid, bssid); break; } + } } + +void LinuxNetworkWatcherWorker::NMStateChanged(quint32 state) +{ + if (state == NM_STATE_ASLEEP) { + emit sleepMode(); + } + + logger.debug() << "NMStateChanged " << state; +} + diff --git a/client/platforms/linux/linuxnetworkwatcherworker.h b/client/platforms/linux/linuxnetworkwatcherworker.h index cc4c6a36..9579fcef 100644 --- a/client/platforms/linux/linuxnetworkwatcherworker.h +++ b/client/platforms/linux/linuxnetworkwatcherworker.h @@ -23,6 +23,7 @@ class LinuxNetworkWatcherWorker final : public QObject { signals: void unsecuredNetwork(const QString& networkName, const QString& networkId); + void sleepMode(); public slots: void initialize(); @@ -30,6 +31,7 @@ class LinuxNetworkWatcherWorker final : public QObject { private slots: void propertyChanged(QString interface, QVariantMap properties, QStringList list); + void NMStateChanged(quint32 state); private: // We collect the list of DBus wifi network device paths during the diff --git a/client/vpnconnection.cpp b/client/vpnconnection.cpp index ad2b591c..9978ddc0 100644 --- a/client/vpnconnection.cpp +++ b/client/vpnconnection.cpp @@ -286,6 +286,12 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede emit connectionStateChanged(Vpn::ConnectionState::Error); } +void VpnConnection::restartConnection() +{ + this->disconnectFromVpn(); + this->connectToVpn(m_serverIndex, m_serverCredentials, m_dockerContainer, m_vpnConfiguration); +} + void VpnConnection::createProtocolConnections() { connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError); @@ -299,8 +305,12 @@ void VpnConnection::createProtocolConnections() qDebug() << "Connection Lose"; auto result = IpcClient::Interface()->stopNetworkCheck(); result.waitForFinished(3000); - this->disconnectFromVpn(); - this->connectToVpn(m_serverIndex, m_serverCredentials, m_dockerContainer, m_vpnConfiguration); + this->restartConnection(); + }); + connect(IpcClient::Interface().data(), &IpcInterfaceReplica::networkChange, + this, [this]() { + qDebug() << "Network change"; + this->restartConnection(); }); #endif } diff --git a/client/vpnconnection.h b/client/vpnconnection.h index f590a07e..3d65e528 100644 --- a/client/vpnconnection.h +++ b/client/vpnconnection.h @@ -51,6 +51,7 @@ public slots: const ServerCredentials &credentials, DockerContainer container, const QJsonObject &vpnConfiguration); void disconnectFromVpn(); + void restartConnection(); void addRoutes(const QStringList &ips); diff --git a/ipc/ipc_interface.rep b/ipc/ipc_interface.rep index 41349647..1f4bcde9 100644 --- a/ipc/ipc_interface.rep +++ b/ipc/ipc_interface.rep @@ -35,6 +35,7 @@ class IpcInterface SLOT( bool startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address) ); SLOT( bool stopNetworkCheck() ); - SIGNAL( connectionLose() ); + SIGNAL( connectionLose() ); + SIGNAL( networkChange() ); }; diff --git a/ipc/ipcserver.h b/ipc/ipcserver.h index 86311c62..b4129f2d 100644 --- a/ipc/ipcserver.h +++ b/ipc/ipcserver.h @@ -42,9 +42,6 @@ public: virtual bool startNetworkCheck(const QString& serverIpv4Gateway, const QString& deviceIpv4Address) override; virtual bool stopNetworkCheck() override; -signals: - void ConnectionLose(); - private: int m_localpid = 0; diff --git a/service/server/localserver.cpp b/service/server/localserver.cpp index 8a5079cb..17869705 100644 --- a/service/server/localserver.cpp +++ b/service/server/localserver.cpp @@ -5,9 +5,7 @@ #include "ipc.h" #include "localserver.h" -#include "utilities.h" -#include "router.h" #include "logger.h" #ifdef Q_OS_WIN @@ -47,6 +45,10 @@ LocalServer::LocalServer(QObject *parent) : QObject(parent), return; } + m_networkWatcher.initialize(); + + connect(&m_networkWatcher, &NetworkWatcher::sleepMode, &m_ipcServer, &IpcServer::networkChange); + #ifdef Q_OS_LINUX // Signal handling for a proper shutdown. QObject::connect(qApp, &QCoreApplication::aboutToQuit, diff --git a/service/server/localserver.h b/service/server/localserver.h index 3c565d3b..47a7640d 100644 --- a/service/server/localserver.h +++ b/service/server/localserver.h @@ -11,7 +11,7 @@ #include "ipcserver.h" #include "../../client/daemon/daemonlocalserver.h" - +#include "../../client/mozilla/networkwatcher.h" #ifdef Q_OS_WIN #include "windows/daemon/windowsdaemon.h" @@ -41,6 +41,8 @@ public: IpcProcessTun2Socks m_tun2socks; QRemoteObjectHost m_serverNode; bool m_isRemotingEnabled = false; + + NetworkWatcher m_networkWatcher; #ifdef Q_OS_LINUX DaemonLocalServer server{qApp}; LinuxDaemon daemon;