From 864b8c6f8a505b43689c8c8591b59dd198568bd6 Mon Sep 17 00:00:00 2001 From: cd-amn Date: Mon, 18 May 2026 16:44:42 +0000 Subject: [PATCH] feat: split daemon activation into bare bring-up and setPrimary --- client/daemon/daemon.cpp | 397 +++++++++--------- client/daemon/daemon.h | 34 +- client/daemon/daemonlocalserverconnection.cpp | 54 ++- client/daemon/daemonlocalserverconnection.h | 4 +- client/daemon/interfaceconfig.h | 2 + client/daemon/wireguardutils.h | 4 +- client/platforms/linux/daemon/linuxdaemon.cpp | 1 - client/platforms/linux/daemon/linuxdaemon.h | 9 - .../platforms/linux/daemon/linuxfirewall.cpp | 6 +- client/platforms/linux/daemon/linuxfirewall.h | 27 -- .../linux/daemon/linuxroutemonitor.cpp | 2 - .../linux/daemon/wireguardutilslinux.cpp | 50 +-- .../linux/daemon/wireguardutilslinux.h | 2 - .../platforms/macos/daemon/iputilsmacos.cpp | 24 +- client/platforms/macos/daemon/macosdaemon.cpp | 1 - client/platforms/macos/daemon/macosdaemon.h | 9 - client/platforms/macos/daemon/macosfirewall.h | 29 -- .../macos/daemon/wireguardutilsmacos.cpp | 51 +-- .../macos/daemon/wireguardutilsmacos.h | 3 - .../windows/daemon/windowsdaemon.cpp | 10 - .../platforms/windows/daemon/windowsdaemon.h | 3 - 21 files changed, 295 insertions(+), 427 deletions(-) diff --git a/client/daemon/daemon.cpp b/client/daemon/daemon.cpp index 8799e8572..e9d342960 100644 --- a/client/daemon/daemon.cpp +++ b/client/daemon/daemon.cpp @@ -34,8 +34,8 @@ Daemon::Daemon(QObject* parent) : QObject(parent) { Q_ASSERT(s_daemon == nullptr); s_daemon = this; - m_handshakeTimer.setSingleShot(true); - connect(&m_handshakeTimer, &QTimer::timeout, this, &Daemon::checkHandshake); + m_activationTimer.setSingleShot(false); + connect(&m_activationTimer, &QTimer::timeout, this, &Daemon::checkActivations); } Daemon::~Daemon() { @@ -43,6 +43,9 @@ Daemon::~Daemon() { logger.debug() << "Daemon released"; + qDeleteAll(m_tunnels); + m_tunnels.clear(); + Q_ASSERT(s_daemon == this); s_daemon = nullptr; } @@ -53,69 +56,36 @@ Daemon* Daemon::instance() { return s_daemon; } -bool Daemon::activate(const InterfaceConfig& config) { - Q_ASSERT(wgutils() != nullptr); +bool Daemon::activate(const QString& ifname, const InterfaceConfig& config) { + logger.debug() << "Activating tunnel"; - // There are 3 possible scenarios in which this method is called: - // - // 1. the VPN is off: the method tries to enable the VPN. - // 2. the VPN is on and the platform doesn't support the server-switching: - // this method calls deactivate() and then it continues as 1. - // 3. the VPN is on and the platform supports the server-switching: this - // method calls switchServer(). - // - // At the end, if the activation succeds, the `connected` signal is emitted. - // If the activation abort's for any reason `the `activationFailure` signal is - // emitted. - logger.debug() << "Activating interface"; - auto emit_failure_guard = qScopeGuard([this] { emit activationFailure(); }); - - if (m_connections.contains(config.m_hopType)) { - if (supportServerSwitching(config)) { - logger.debug() << "Already connected. Server switching supported."; - - if (!switchServer(config)) { - return false; - } - - if (!dnsutils()->restoreResolvers()) { - return false; - } - - if (!maybeUpdateResolvers(config)) { - return false; - } - - bool status = run(Switch, config); - logger.debug() << "Connection status:" << status; - if (status) { - m_connections[config.m_hopType] = ConnectionState(config); - m_handshakeTimer.start(HANDSHAKE_POLL_MSEC); - emit_failure_guard.dismiss(); - return true; - } + WireguardUtils* wg = m_tunnels.value(ifname); + if (!wg) { + wg = createWgUtils(); + if (!wg) { + logger.error() << "Failed to create wireguard utils."; return false; } - - logger.warning() << "Already connected. Server switching not supported."; - if (!deactivate(false)) { - return false; - } - - Q_ASSERT(!m_connections.contains(config.m_hopType)); - if (activate(config)) { - emit_failure_guard.dismiss(); - return true; - } - return false; + m_tunnels.insert(ifname, wg); } + if (m_primaryIfname.isEmpty()) { + m_primaryIfname = ifname; + } + + ConnectionState& cs = m_connections[ifname]; + cs.m_config = config; + cs.m_date = QDateTime(); + cs.m_deadline = QDateTime::currentDateTime().addMSecs(ACTIVATION_TIMEOUT_MSEC); + + auto failure_guard = qScopeGuard([this, ifname] { + deactivateTunnel(ifname); + }); prepareActivation(config); // Bring up the wireguard interface if not already done. - if (!wgutils()->interfaceExists()) { - // Create the interface. - if (!wgutils()->addInterface(config)) { + if (!wg->interfaceExists()) { + if (!wg->addInterface(config)) { logger.error() << "Interface creation failed."; return false; } @@ -131,38 +101,137 @@ bool Daemon::activate(const InterfaceConfig& config) { } } - // Configure routing for excluded addresses. - for (const QString& i : config.m_excludedAddresses) { - addExclusionRoute(IPAddress(i)); + if (!config.m_serverIpv4AddrIn.isEmpty()) { + addExclusionRoute(IPAddress(config.m_serverIpv4AddrIn)); + } + if (!config.m_serverIpv6AddrIn.isEmpty()) { + addExclusionRoute(IPAddress(config.m_serverIpv6AddrIn)); } // Add the peer to this interface. - if (!wgutils()->updatePeer(config)) { + if (!wg->updatePeer(config)) { logger.error() << "Peer creation failed."; return false; } - if (!maybeUpdateResolvers(config)) { - return false; + if (!m_activationTimer.isActive()) { + m_activationTimer.start(HANDSHAKE_POLL_MSEC); + } + + failure_guard.dismiss(); + return true; +} + +bool Daemon::setPrimary(const QString& ifname, const InterfaceConfig& config) { + WireguardUtils* wg = m_tunnels.value(ifname); + if (!wg) { + logger.error() << "setPrimary: no tunnel for" << ifname; + return false; + } + logger.debug() << "setPrimary" << wg->interfaceName(); + + const QString priorPrimary = m_primaryIfname; + m_primaryIfname = ifname; + + auto failure_guard = qScopeGuard([this, ifname, priorPrimary] { + deactivateTunnel(ifname); + m_primaryIfname = priorPrimary; + }); + + for (const QString& i : config.m_excludedAddresses) { + addExclusionRoute(IPAddress(i)); } - // set routing for (const IPAddress& ip : config.m_allowedIPAddressRanges) { - if (!wgutils()->updateRoutePrefix(ip)) { - logger.debug() << "Routing configuration failed for" << ip.toString(); - return false; + if (!wg->updateRoutePrefix(ip)) { + logger.warning() << "setPrimary: route setup failed for" << ip.toString(); } } - bool status = run(Up, config); - logger.debug() << "Connection status:" << status; - if (status) { - m_connections[config.m_hopType] = ConnectionState(config); - m_handshakeTimer.start(HANDSHAKE_POLL_MSEC); - emit_failure_guard.dismiss(); - return true; + if (!maybeUpdateResolvers(config)) { + logger.warning() << "setPrimary: DNS resolver update failed"; } - return false; + + if (!run(Up, config)) { + return false; + } + + m_connections[ifname].m_config = config; + + // Demote the prior primary AFTER the new primary is fully installed. + // Delete-after-install order preserves coverage during the make-before-break overlap. + if (!priorPrimary.isEmpty() && priorPrimary != ifname) { + demotePrimary(priorPrimary); + } + + failure_guard.dismiss(); + return true; +} + +void Daemon::demotePrimary(const QString& ifname) { + WireguardUtils* wg = wgutilsFor(ifname); + if (!wg) { + return; + } + const ConnectionState cs = m_connections.value(ifname); + const InterfaceConfig& config = cs.m_config; + + for (const IPAddress& ip : config.m_allowedIPAddressRanges) { + wg->deleteRoutePrefix(ip); + } + for (const QString& addr : config.m_excludedAddresses) { + if (addr.isEmpty()) { + continue; + } + IPAddress ip(addr); + if (m_excludedAddrSet.contains(ip)) { + delExclusionRoute(ip); + } + } +} + +bool Daemon::deactivateTunnel(const QString& ifname) { + WireguardUtils* wg = m_tunnels.value(ifname); + const ConnectionState cs = m_connections.value(ifname); + const InterfaceConfig& config = cs.m_config; + const bool wasPrimary = (ifname == m_primaryIfname); + + if (wg) { + logger.debug() << "deactivateTunnel" << wg->interfaceName(); + if (wasPrimary) { + for (const IPAddress& ip : config.m_allowedIPAddressRanges) { + wg->deleteRoutePrefix(ip); + } + } + wg->deletePeer(config); + + auto removeExclusion = [&](const QString& addr) { + if (addr.isEmpty()) { + return; + } + IPAddress ip(addr); + if (m_excludedAddrSet.contains(ip)) { + delExclusionRoute(ip); + } + }; + removeExclusion(config.m_serverIpv4AddrIn); + removeExclusion(config.m_serverIpv6AddrIn); + if (wasPrimary) { + for (const QString& i : config.m_excludedAddresses) { + removeExclusion(i); + } + } + + wg->deleteInterface(); + m_tunnels.remove(ifname); + delete wg; + } + + m_connections.remove(ifname); + if (wasPrimary) { + m_primaryIfname.clear(); + } + return true; } bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) { @@ -180,7 +249,8 @@ bool Daemon::maybeUpdateResolvers(const InterfaceConfig& config) { resolvers.append(QHostAddress(config.m_serverIpv6Gateway)); } - if (!dnsutils()->updateResolvers(wgutils()->interfaceName(), resolvers)) { + const QString ifname = wgutilsFor(config.m_ifname)->interfaceName(); + if (!dnsutils()->updateResolvers(ifname, resolvers)) { return false; } } @@ -214,7 +284,7 @@ bool Daemon::addExclusionRoute(const IPAddress& prefix) { m_excludedAddrSet[prefix]++; return true; } - if (!wgutils()->addExclusionRoute(prefix)) { + if (!primaryWgutils()->addExclusionRoute(prefix)) { return false; } m_excludedAddrSet[prefix] = 1; @@ -228,7 +298,8 @@ bool Daemon::delExclusionRoute(const IPAddress& prefix) { return true; } m_excludedAddrSet.remove(prefix); - return wgutils()->deleteExclusionRoute(prefix); + WireguardUtils* wg = primaryWgutils(); + return wg && wg->deleteExclusionRoute(prefix); } // static @@ -440,18 +511,16 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) { if (!obj.value("I5").isNull()) { config.m_specialJunk["I5"] = obj.value("I5").toString(); } - config.m_ifname = obj.value("ifname").toString(WG_INTERFACE); + config.m_ifname = obj.value("ifname").toString(); return true; } bool Daemon::deactivate(bool emitSignals) { - Q_ASSERT(wgutils() != nullptr); + const QString primary = m_primaryIfname; - // Deactivate the main interface. - if (!m_connections.isEmpty()) { - const ConnectionState& state = m_connections.first(); - if (!run(Down, state.m_config)) { + if (m_connections.contains(primary)) { + if (!run(Down, m_connections.value(primary).m_config)) { return false; } } @@ -460,31 +529,22 @@ bool Daemon::deactivate(bool emitSignals) { emit disconnected(); } - // Cleanup DNS if (!dnsutils()->restoreResolvers()) { logger.warning() << "Failed to restore DNS resolvers."; } - // Cleanup peers and routing - for (const ConnectionState& state : m_connections) { - const InterfaceConfig& config = state.m_config; - logger.debug() << "Deleting routes for" << config.m_hopType; - for (const IPAddress& ip : config.m_allowedIPAddressRanges) { - wgutils()->deleteRoutePrefix(ip); + const QStringList ifnames = m_tunnels.keys(); + for (const QString& ifname : ifnames) { + if (ifname != primary) { + deactivateTunnel(ifname); } - wgutils()->deletePeer(config); + } + if (m_tunnels.contains(primary)) { + deactivateTunnel(primary); } - // Cleanup routing for excluded addresses. - for (auto iterator = m_excludedAddrSet.constBegin(); - iterator != m_excludedAddrSet.constEnd(); ++iterator) { - wgutils()->deleteExclusionRoute(iterator.key()); - } - m_excludedAddrSet.clear(); - - m_connections.clear(); - // Delete the interface - return wgutils()->deleteInterface(); + m_activationTimer.stop(); + return true; } QString Daemon::logs() { @@ -493,79 +553,18 @@ QString Daemon::logs() { void Daemon::cleanLogs() { } -bool Daemon::supportServerSwitching(const InterfaceConfig& config) const { - if (!m_connections.contains(config.m_hopType)) { - return false; - } - const InterfaceConfig& current = - m_connections.value(config.m_hopType).m_config; - - return current.m_privateKey == config.m_privateKey && - current.m_deviceIpv4Address == config.m_deviceIpv4Address && - current.m_deviceIpv6Address == config.m_deviceIpv6Address && - current.m_serverIpv4Gateway == config.m_serverIpv4Gateway && - current.m_serverIpv6Gateway == config.m_serverIpv6Gateway; -} - -bool Daemon::switchServer(const InterfaceConfig& config) { - Q_ASSERT(wgutils() != nullptr); - - logger.debug() << "Switching server for" << config.m_hopType; - - Q_ASSERT(m_connections.contains(config.m_hopType)); - const InterfaceConfig& lastConfig = - m_connections.value(config.m_hopType).m_config; - - // Configure routing for new excluded addresses. - for (const QString& i : config.m_excludedAddresses) { - addExclusionRoute(IPAddress(i)); - } - - // Activate the new peer and its routes. - if (!wgutils()->updatePeer(config)) { - logger.error() << "Server switch failed to update the wireguard interface"; - return false; - } - for (const IPAddress& ip : config.m_allowedIPAddressRanges) { - if (!wgutils()->updateRoutePrefix(ip)) { - logger.error() << "Server switch failed to update the routing table"; - break; - } - } - - // Remove routing entries for the old peer. - for (const QString& i : lastConfig.m_excludedAddresses) { - delExclusionRoute(QHostAddress(i)); - } - for (const IPAddress& ip : lastConfig.m_allowedIPAddressRanges) { - if (!config.m_allowedIPAddressRanges.contains(ip)) { - wgutils()->deleteRoutePrefix(ip); - } - } - - // Remove the old peer if it is no longer necessary. - if (config.m_serverPublicKey != lastConfig.m_serverPublicKey) { - if (!wgutils()->deletePeer(lastConfig)) { - return false; - } - } - - m_connections[config.m_hopType] = ConnectionState(config); - return true; -} - QJsonObject Daemon::getStatus() { - Q_ASSERT(wgutils() != nullptr); QJsonObject json; logger.debug() << "Status request"; - if (!wgutils()->interfaceExists() || m_connections.isEmpty()) { + WireguardUtils* wg = primaryWgutils(); + if (!wg || !wg->interfaceExists() || !m_connections.contains(m_primaryIfname)) { json.insert("connected", QJsonValue(false)); return json; } - const ConnectionState& connection = m_connections.first(); - QList peers = wgutils()->getPeerStatus(); + const ConnectionState& connection = m_connections.value(m_primaryIfname); + QList peers = wg->getPeerStatus(); for (const WireguardUtils::PeerStatus& status : peers) { if (status.m_pubkey != connection.m_config.m_serverPublicKey) { continue; @@ -585,38 +584,50 @@ QJsonObject Daemon::getStatus() { return json; } -void Daemon::checkHandshake() { - Q_ASSERT(wgutils() != nullptr); +void Daemon::checkActivations() { + const QDateTime now = QDateTime::currentDateTime(); + QStringList timedOut; + bool anyPending = false; - logger.debug() << "Checking for handshake..."; + for (auto it = m_connections.begin(); it != m_connections.end(); ++it) { + const QString& ifname = it.key(); + ConnectionState& cs = it.value(); + if (cs.m_date.isValid()) { + continue; // already handshaked + } + logger.debug() << "awaiting" << cs.m_config.m_serverPublicKey; - int pendingHandshakes = 0; - QList peers = wgutils()->getPeerStatus(); - for (ConnectionState& connection : m_connections) { - const InterfaceConfig& config = connection.m_config; - if (connection.m_date.isValid()) { + WireguardUtils* wg = m_tunnels.value(ifname); + bool handshaked = false; + if (wg) { + for (const WireguardUtils::PeerStatus& status : wg->getPeerStatus()) { + if (status.m_pubkey != cs.m_config.m_serverPublicKey) { + continue; + } + if (status.m_handshake != 0) { + cs.m_date.setMSecsSinceEpoch(status.m_handshake); + emit tunnelConnected(ifname, status.m_pubkey); + handshaked = true; + } + } + } + if (handshaked) { continue; } - logger.debug() << "awaiting" << config.m_serverPublicKey; - - // Check if the handshake has completed. - for (const WireguardUtils::PeerStatus& status : peers) { - if (config.m_serverPublicKey != status.m_pubkey) { - continue; - } - if (status.m_handshake != 0) { - connection.m_date.setMSecsSinceEpoch(status.m_handshake); - emit connected(status.m_pubkey); - } - } - - if (!connection.m_date.isValid()) { - pendingHandshakes++; + if (cs.m_deadline.isValid() && now > cs.m_deadline) { + timedOut.append(ifname); + } else { + anyPending = true; } } - // Check again if there were connections that haven't completed a handshake. - if (pendingHandshakes > 0) { - m_handshakeTimer.start(HANDSHAKE_POLL_MSEC); + for (const QString& ifname : timedOut) { + logger.warning() << "Tunnel handshake timed out:" << m_tunnels.value(ifname)->interfaceName(); + emit tunnelHandshakeFailed(ifname); + deactivateTunnel(ifname); + } + + if (!anyPending) { + m_activationTimer.stop(); } } diff --git a/client/daemon/daemon.h b/client/daemon/daemon.h index 6a6addb9d..b9d0cf811 100644 --- a/client/daemon/daemon.h +++ b/client/daemon/daemon.h @@ -22,7 +22,6 @@ class Daemon : public QObject { enum Op { Up, Down, - Switch, }; explicit Daemon(QObject* parent); @@ -32,10 +31,15 @@ class Daemon : public QObject { static bool parseConfig(const QJsonObject& obj, InterfaceConfig& config); - virtual bool activate(const InterfaceConfig& config); + bool activate(const QString& ifname, const InterfaceConfig& config); + bool setPrimary(const QString& ifname, const InterfaceConfig& config); + bool deactivateTunnel(const QString& ifname); virtual bool deactivate(bool emitSignals = true); virtual QJsonObject getStatus(); + const QString& primaryIfname() const { return m_primaryIfname; } + WireguardUtils* wgutilsFor(const QString& ifname) const { return m_tunnels.value(ifname); } + // Callback before any Activating measure is done virtual void prepareActivation(const InterfaceConfig& config, int inetAdapterIndex = 0) { Q_UNUSED(config) }; @@ -46,12 +50,8 @@ class Daemon : public QObject { void cleanLogs(); signals: - void connected(const QString& pubkey); - /** - * Can be fired if a call to activate() was unsucessfull - * and connected systems should rollback - */ - void activationFailure(); + void tunnelConnected(const QString& ifname, const QString& pubkey); + void tunnelHandshakeFailed(const QString& ifname); void disconnected(); void backendFailure(DaemonError reason = DaemonError::ERROR_FATAL); @@ -59,6 +59,10 @@ class Daemon : public QObject { bool maybeUpdateResolvers(const InterfaceConfig& config); bool addExclusionRoute(const IPAddress& address); bool delExclusionRoute(const IPAddress& address); + void demotePrimary(const QString& ifname); + void checkActivations(); + WireguardUtils* primaryWgutils() const { return m_tunnels.value(m_primaryIfname); } + QTimer m_activationTimer; protected: virtual bool run(Op op, const InterfaceConfig& config) { @@ -66,13 +70,11 @@ class Daemon : public QObject { Q_UNUSED(config); return true; } - virtual bool supportServerSwitching(const InterfaceConfig& config) const; - virtual bool switchServer(const InterfaceConfig& config); - virtual WireguardUtils* wgutils() const = 0; virtual WireguardUtils* createWgUtils() = 0; - virtual void replaceActiveWgUtils(WireguardUtils* newUtils) = 0; - WireguardUtils* m_stagingWgutils = nullptr; + QMap m_tunnels; + QString m_primaryIfname; + virtual bool supportIPUtils() const { return false; } virtual IPUtils* iputils() { return nullptr; } virtual DnsUtils* dnsutils() { return nullptr; } @@ -80,18 +82,16 @@ class Daemon : public QObject { static bool parseStringList(const QJsonObject& obj, const QString& name, QStringList& list); - void checkHandshake(); - class ConnectionState { public: ConnectionState(){}; ConnectionState(const InterfaceConfig& config) { m_config = config; } QDateTime m_date; + QDateTime m_deadline; InterfaceConfig m_config; }; - QMap m_connections; + QMap m_connections; QHash m_excludedAddrSet; - QTimer m_handshakeTimer; }; #endif // DAEMON_H diff --git a/client/daemon/daemonlocalserverconnection.cpp b/client/daemon/daemonlocalserverconnection.cpp index bc57c71fb..4f859a0fd 100644 --- a/client/daemon/daemonlocalserverconnection.cpp +++ b/client/daemon/daemonlocalserverconnection.cpp @@ -31,8 +31,10 @@ DaemonLocalServerConnection::DaemonLocalServerConnection(QObject* parent, &DaemonLocalServerConnection::readData); Daemon* daemon = Daemon::instance(); - connect(daemon, &Daemon::connected, this, - &DaemonLocalServerConnection::connected); + connect(daemon, &Daemon::tunnelConnected, + this, &DaemonLocalServerConnection::onTunnelConnected); + connect(daemon, &Daemon::tunnelHandshakeFailed, + this, &DaemonLocalServerConnection::onTunnelHandshakeFailed); connect(daemon, &Daemon::disconnected, this, &DaemonLocalServerConnection::disconnected); connect(daemon, &Daemon::backendFailure, this, @@ -107,19 +109,44 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) { InterfaceConfig config; if (!Daemon::parseConfig(obj, config)) { logger.error() << "Invalid configuration"; - emit disconnected(); + disconnected(); return; } - - if (!Daemon::instance()->activate(config)) { + if (!Daemon::instance()->activate(config.m_ifname, config)) { logger.error() << "Failed to activate the interface"; - emit disconnected(); + disconnected(); } return; } if (type == "deactivate") { - Daemon::instance()->deactivate(true); + const QString ifname = obj.value("ifname").toString(); + if (!ifname.isEmpty()) { + Daemon::instance()->deactivateTunnel(ifname); + } else { + Daemon::instance()->deactivate(true); + } + return; + } + + if (type == "setPrimary") { + InterfaceConfig config; + if (!Daemon::parseConfig(obj, config)) { + logger.error() << "setPrimary: invalid configuration"; + return; + } + if (!Daemon::instance()->setPrimary(config.m_ifname, config)) { + logger.error() << "setPrimary failed"; + QJsonObject reply; + reply.insert("type", "primaryFailed"); + reply.insert("ifname", config.m_ifname); + write(reply); + return; + } + QJsonObject reply; + reply.insert("type", "primaryReady"); + reply.insert("ifname", config.m_ifname); + write(reply); return; } @@ -146,10 +173,19 @@ void DaemonLocalServerConnection::parseCommand(const QByteArray& data) { logger.warning() << "Invalid command:" << type; } -void DaemonLocalServerConnection::connected(const QString& pubkey) { +void DaemonLocalServerConnection::onTunnelConnected(const QString& ifname, + const QString& pubkey) { QJsonObject obj; obj.insert("type", "connected"); - obj.insert("pubkey", QJsonValue(pubkey)); + obj.insert("ifname", ifname); + obj.insert("pubkey", pubkey); + write(obj); +} + +void DaemonLocalServerConnection::onTunnelHandshakeFailed(const QString& ifname) { + QJsonObject obj; + obj.insert("type", "disconnected"); + obj.insert("ifname", ifname); write(obj); } diff --git a/client/daemon/daemonlocalserverconnection.h b/client/daemon/daemonlocalserverconnection.h index 34170cb31..e26c84fd7 100644 --- a/client/daemon/daemonlocalserverconnection.h +++ b/client/daemon/daemonlocalserverconnection.h @@ -6,6 +6,7 @@ #define DAEMONLOCALSERVERCONNECTION_H #include +#include #include "daemonerrors.h" @@ -23,7 +24,8 @@ class DaemonLocalServerConnection final : public QObject { void parseCommand(const QByteArray& json); - void connected(const QString& pubkey); + void onTunnelConnected(const QString& ifname, const QString& pubkey); + void onTunnelHandshakeFailed(const QString& ifname); void disconnected(); void backendFailure(DaemonError err); diff --git a/client/daemon/interfaceconfig.h b/client/daemon/interfaceconfig.h index e6b18e0cc..aa845f065 100644 --- a/client/daemon/interfaceconfig.h +++ b/client/daemon/interfaceconfig.h @@ -13,6 +13,8 @@ class QJsonObject; +constexpr int ACTIVATION_TIMEOUT_MSEC = 30000; + class InterfaceConfig { Q_GADGET diff --git a/client/daemon/wireguardutils.h b/client/daemon/wireguardutils.h index b600a923a..3f927c3ab 100644 --- a/client/daemon/wireguardutils.h +++ b/client/daemon/wireguardutils.h @@ -14,8 +14,6 @@ #include "interfaceconfig.h" -constexpr const char* WG_INTERFACE = "amn0"; - constexpr uint16_t WG_KEEPALIVE_PERIOD = 60; class WireguardUtils : public QObject { @@ -35,7 +33,7 @@ class WireguardUtils : public QObject { virtual ~WireguardUtils() = default; virtual bool interfaceExists() = 0; - virtual QString interfaceName() { return WG_INTERFACE; } + virtual QString interfaceName() = 0; virtual bool addInterface(const InterfaceConfig& config) = 0; virtual bool deleteInterface() = 0; diff --git a/client/platforms/linux/daemon/linuxdaemon.cpp b/client/platforms/linux/daemon/linuxdaemon.cpp index 6462c7851..2188cd281 100644 --- a/client/platforms/linux/daemon/linuxdaemon.cpp +++ b/client/platforms/linux/daemon/linuxdaemon.cpp @@ -29,7 +29,6 @@ LinuxDaemon::LinuxDaemon() : Daemon(nullptr) { logger.debug() << "Daemon created"; - m_wgutils = new WireguardUtilsLinux(this); m_dnsutils = new DnsUtilsLinux(this); m_iputils = new IPUtilsLinux(this); diff --git a/client/platforms/linux/daemon/linuxdaemon.h b/client/platforms/linux/daemon/linuxdaemon.h index 645004384..bd5349673 100644 --- a/client/platforms/linux/daemon/linuxdaemon.h +++ b/client/platforms/linux/daemon/linuxdaemon.h @@ -12,8 +12,6 @@ #include "wireguardutilslinux.h" class LinuxDaemon final : public Daemon { - friend class IPUtilsMacos; - public: LinuxDaemon(); ~LinuxDaemon(); @@ -23,7 +21,6 @@ class LinuxDaemon final : public Daemon { bool deactivate(bool emitSignals = true) override; protected: - WireguardUtils* wgutils() const override { return m_wgutils; } DnsUtils* dnsutils() override { return m_dnsutils; } bool supportIPUtils() const override { return true; } IPUtils* iputils() override { return m_iputils; } @@ -32,13 +29,7 @@ class LinuxDaemon final : public Daemon { return new WireguardUtilsLinux(this); } - void replaceActiveWgUtils(WireguardUtils* newUtils) override { - delete m_wgutils; - m_wgutils = static_cast(newUtils); - } - private: - WireguardUtilsLinux* m_wgutils = nullptr; DnsUtilsLinux* m_dnsutils = nullptr; IPUtilsLinux* m_iputils = nullptr; }; diff --git a/client/platforms/linux/daemon/linuxfirewall.cpp b/client/platforms/linux/daemon/linuxfirewall.cpp index c04770f1a..4f7658402 100644 --- a/client/platforms/linux/daemon/linuxfirewall.cpp +++ b/client/platforms/linux/daemon/linuxfirewall.cpp @@ -193,8 +193,8 @@ QStringList LinuxFirewall::getDNSRules(const QStringList& servers) QStringList result; for (const QString& server : servers) { - result << QStringLiteral("-o amn0+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server); - result << QStringLiteral("-o amn0+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server); + result << QStringLiteral("-o amn+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server); + result << QStringLiteral("-o amn+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server); result << QStringLiteral("-o tun0+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server); result << QStringLiteral("-o tun0+ -d %1 -p tcp --dport 53 -j ACCEPT").arg(server); result << QStringLiteral("-o tun2+ -d %1 -p udp --dport 53 -j ACCEPT").arg(server); @@ -278,7 +278,7 @@ void LinuxFirewall::install() }); installAnchor(Both, QStringLiteral("200.allowVPN"), { - QStringLiteral("-o amn0+ -j ACCEPT"), + QStringLiteral("-o amn+ -j ACCEPT"), QStringLiteral("-o tun0+ -j ACCEPT"), QStringLiteral("-o tun2+ -j ACCEPT"), }); diff --git a/client/platforms/linux/daemon/linuxfirewall.h b/client/platforms/linux/daemon/linuxfirewall.h index 380492657..a18707eda 100644 --- a/client/platforms/linux/daemon/linuxfirewall.h +++ b/client/platforms/linux/daemon/linuxfirewall.h @@ -37,33 +37,6 @@ #include #include -// Descriptor for a set of firewall rules to be appled. -// -struct FirewallParams -{ - QStringList dnsServers; - QVector excludeApps; // Apps to exclude if VPN exemptions are enabled - QStringList allowAddrs; - QStringList blockAddrs; - // The follow flags indicate which general rulesets are needed. Note that - // this is after some sanity filtering, i.e. an allow rule may be listed - // as not needed if there were no block rules preceding it. The rulesets - // should be thought of as in last-match order. - - bool blockAll; // Block all traffic by default - bool allowVPN; // Exempt traffic through VPN tunnel - bool allowDHCP; // Exempt DHCP traffic - bool blockIPv6; // Block all IPv6 traffic - bool allowLAN; // Exempt LAN traffic, including IPv6 LAN traffic - bool blockDNS; // Block all DNS traffic except specified DNS servers - bool allowPIA; // Exempt PIA executables - bool allowLoopback; // Exempt loopback traffic - bool allowHnsd; // Exempt Handshake DNS traffic - bool allowVpnExemptions; // Exempt specified traffic from the tunnel (route it over the physical uplink instead) - bool allowNets; - bool blockNets; -}; - class LinuxFirewall { public: diff --git a/client/platforms/linux/daemon/linuxroutemonitor.cpp b/client/platforms/linux/daemon/linuxroutemonitor.cpp index 2f9f6bdd2..dfd4872f9 100644 --- a/client/platforms/linux/daemon/linuxroutemonitor.cpp +++ b/client/platforms/linux/daemon/linuxroutemonitor.cpp @@ -39,8 +39,6 @@ typedef struct wg_allowedip { struct wg_allowedip *next_allowedip; } wg_allowedip; -constexpr const char* WG_INTERFACE = "amn0"; - static void nlmsg_append_attr(struct nlmsghdr* nlmsg, size_t maxlen, int attrtype, const void* attrdata, size_t attrlen); diff --git a/client/platforms/linux/daemon/wireguardutilslinux.cpp b/client/platforms/linux/daemon/wireguardutilslinux.cpp index 3c793d162..d4af49f56 100644 --- a/client/platforms/linux/daemon/wireguardutilslinux.cpp +++ b/client/platforms/linux/daemon/wireguardutilslinux.cpp @@ -14,7 +14,6 @@ #include #include -#include "linuxfirewall.h" #include "leakdetector.h" #include "logger.h" @@ -63,7 +62,7 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) { return false; } - const QString ifname = config.m_ifname.isEmpty() ? QString(WG_INTERFACE) : config.m_ifname; + const QString ifname = config.m_ifname; QDir wgRuntimeDir(WG_RUNTIME_DIR); if (!wgRuntimeDir.exists()) { @@ -147,29 +146,6 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) { int err = uapiErrno(uapiCommand(message)); if (err != 0) { logger.error() << "Interface configuration failed:" << strerror(err); - } else { - if (config.m_killSwitchEnabled) { - FirewallParams params { }; - params.dnsServers.append(config.m_primaryDnsServer); - if (!config.m_secondaryDnsServer.isEmpty()) { - params.dnsServers.append(config.m_secondaryDnsServer); - } - if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) { - params.blockAll = true; - if (config.m_excludedAddresses.size()) { - params.allowNets = true; - foreach (auto net, config.m_excludedAddresses) { - params.allowAddrs.append(net.toUtf8()); - } - } - } else { - params.blockNets = true; - foreach (auto net, config.m_allowedIPAddressRanges) { - params.blockAddrs.append(net.toString()); - } - } - applyFirewallRules(params); - } } return (err == 0); @@ -454,27 +430,3 @@ QString WireguardUtilsLinux::waitForTunnelName(const QString& filename) { return QString(); } - -void WireguardUtilsLinux::applyFirewallRules(FirewallParams& params) -{ - // double-check + ensure our firewall is installed and enabled - if (!LinuxFirewall::isInstalled()) LinuxFirewall::install(); - - // Note: rule precedence is handled inside IpTablesFirewall - LinuxFirewall::ensureRootAnchorPriority(); - - LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("000.allowLoopback"), true); - LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("100.blockAll"), params.blockAll); - LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("110.allowNets"), params.allowNets); - LinuxFirewall::updateAllowNets(params.allowAddrs); - LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("120.blockNets"), params.blockNets); - LinuxFirewall::updateBlockNets(params.blockAddrs); - LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("200.allowVPN"), true); - LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv6, QStringLiteral("250.blockIPv6"), true); - LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("290.allowDHCP"), true); - LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("300.allowLAN"), true); - LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("310.blockDNS"), true); - LinuxFirewall::updateDNSServers(params.dnsServers); - LinuxFirewall::setAnchorEnabled(LinuxFirewall::IPv4, QStringLiteral("320.allowDNS"), true); - LinuxFirewall::setAnchorEnabled(LinuxFirewall::Both, QStringLiteral("400.allowPIA"), true); -} diff --git a/client/platforms/linux/daemon/wireguardutilslinux.h b/client/platforms/linux/daemon/wireguardutilslinux.h index c324111de..512ff8eac 100644 --- a/client/platforms/linux/daemon/wireguardutilslinux.h +++ b/client/platforms/linux/daemon/wireguardutilslinux.h @@ -11,7 +11,6 @@ #include "daemon/wireguardutils.h" #include "linuxroutemonitor.h" -#include "linuxfirewall.h" class WireguardUtilsLinux final : public WireguardUtils { @@ -40,7 +39,6 @@ public: bool excludeLocalNetworks(const QList& lanAddressRanges) override; - void applyFirewallRules(FirewallParams& params); signals: void backendFailure(); diff --git a/client/platforms/macos/daemon/iputilsmacos.cpp b/client/platforms/macos/daemon/iputilsmacos.cpp index 901436ae7..31a2d41d6 100644 --- a/client/platforms/macos/daemon/iputilsmacos.cpp +++ b/client/platforms/macos/daemon/iputilsmacos.cpp @@ -39,8 +39,12 @@ bool IPUtilsMacos::addInterfaceIPs(const InterfaceConfig& config) { } bool IPUtilsMacos::setMTUAndUp(const InterfaceConfig& config) { - Q_UNUSED(config); - QString ifname = MacOSDaemon::instance()->m_wgutils->interfaceName(); + WireguardUtils* wg = MacOSDaemon::instance()->wgutilsFor(config.m_ifname); + if (!wg) { + logger.error() << "No wireguard interface for" << config.m_ifname; + return false; + } + QString ifname = wg->interfaceName(); struct ifreq ifr; // Create socket file descriptor to perform the ioctl operations on @@ -80,8 +84,12 @@ bool IPUtilsMacos::setMTUAndUp(const InterfaceConfig& config) { } bool IPUtilsMacos::addIP4AddressToDevice(const InterfaceConfig& config) { - Q_UNUSED(config); - QString ifname = MacOSDaemon::instance()->m_wgutils->interfaceName(); + WireguardUtils* wg = MacOSDaemon::instance()->wgutilsFor(config.m_ifname); + if (!wg) { + logger.error() << "No wireguard interface for" << config.m_ifname; + return false; + } + QString ifname = wg->interfaceName(); struct ifaliasreq ifr; struct sockaddr_in* ifrAddr = (struct sockaddr_in*)&ifr.ifra_addr; struct sockaddr_in* ifrMask = (struct sockaddr_in*)&ifr.ifra_mask; @@ -130,8 +138,12 @@ bool IPUtilsMacos::addIP4AddressToDevice(const InterfaceConfig& config) { } bool IPUtilsMacos::addIP6AddressToDevice(const InterfaceConfig& config) { - Q_UNUSED(config); - QString ifname = MacOSDaemon::instance()->m_wgutils->interfaceName(); + WireguardUtils* wg = MacOSDaemon::instance()->wgutilsFor(config.m_ifname); + if (!wg) { + logger.error() << "No wireguard interface for" << config.m_ifname; + return false; + } + QString ifname = wg->interfaceName(); struct in6_aliasreq ifr6; // Name the interface and set family diff --git a/client/platforms/macos/daemon/macosdaemon.cpp b/client/platforms/macos/daemon/macosdaemon.cpp index 296301eec..17bef9f8e 100644 --- a/client/platforms/macos/daemon/macosdaemon.cpp +++ b/client/platforms/macos/daemon/macosdaemon.cpp @@ -29,7 +29,6 @@ MacOSDaemon::MacOSDaemon() : Daemon(nullptr) { logger.debug() << "Daemon created"; - m_wgutils = new WireguardUtilsMacos(this); m_dnsutils = new DnsUtilsMacos(this); m_iputils = new IPUtilsMacos(this); diff --git a/client/platforms/macos/daemon/macosdaemon.h b/client/platforms/macos/daemon/macosdaemon.h index e590344fb..3d7bd1c4a 100644 --- a/client/platforms/macos/daemon/macosdaemon.h +++ b/client/platforms/macos/daemon/macosdaemon.h @@ -11,8 +11,6 @@ #include "wireguardutilsmacos.h" class MacOSDaemon final : public Daemon { - friend class IPUtilsMacos; - public: MacOSDaemon(); ~MacOSDaemon(); @@ -22,7 +20,6 @@ class MacOSDaemon final : public Daemon { bool deactivate(bool emitSignals = true) override; protected: - WireguardUtils* wgutils() const override { return m_wgutils; } DnsUtils* dnsutils() override { return m_dnsutils; } bool supportIPUtils() const override { return true; } IPUtils* iputils() override { return m_iputils; } @@ -31,13 +28,7 @@ class MacOSDaemon final : public Daemon { return new WireguardUtilsMacos(this); } - void replaceActiveWgUtils(WireguardUtils* newUtils) override { - delete m_wgutils; - m_wgutils = static_cast(newUtils); - } - private: - WireguardUtilsMacos* m_wgutils = nullptr; DnsUtilsMacos* m_dnsutils = nullptr; IPUtilsMacos* m_iputils = nullptr; }; diff --git a/client/platforms/macos/daemon/macosfirewall.h b/client/platforms/macos/daemon/macosfirewall.h index faa87c8ca..b1d86e139 100644 --- a/client/platforms/macos/daemon/macosfirewall.h +++ b/client/platforms/macos/daemon/macosfirewall.h @@ -36,35 +36,6 @@ #include #include -// Descriptor for a set of firewall rules to be appled. -// -struct FirewallParams -{ - QStringList dnsServers; - QVector excludeApps; // Apps to exclude if VPN exemptions are enabled - - QStringList allowAddrs; - QStringList blockAddrs; - - // The follow flags indicate which general rulesets are needed. Note that - // this is after some sanity filtering, i.e. an allow rule may be listed - // as not needed if there were no block rules preceding it. The rulesets - // should be thought of as in last-match order. - - bool blockAll; // Block all traffic by default - bool blockNets; - bool allowNets; - bool allowVPN; // Exempt traffic through VPN tunnel - bool allowDHCP; // Exempt DHCP traffic - bool blockIPv6; // Block all IPv6 traffic - bool allowLAN; // Exempt LAN traffic, including IPv6 LAN traffic - bool blockDNS; // Block all DNS traffic except specified DNS servers - bool allowPIA; // Exempt PIA executables - bool allowLoopback; // Exempt loopback traffic - bool allowHnsd; // Exempt Handshake DNS traffic - bool allowVpnExemptions; // Exempt specified traffic from the tunnel (route it over the physical uplink instead) -}; - class MacOSFirewall { diff --git a/client/platforms/macos/daemon/wireguardutilsmacos.cpp b/client/platforms/macos/daemon/wireguardutilsmacos.cpp index c1f6e8ca6..2aa6c6438 100644 --- a/client/platforms/macos/daemon/wireguardutilsmacos.cpp +++ b/client/platforms/macos/daemon/wireguardutilsmacos.cpp @@ -62,7 +62,7 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) { return false; } - const QString ifname = config.m_ifname.isEmpty() ? QString(WG_INTERFACE) : config.m_ifname; + const QString ifname = config.m_ifname; QDir wgRuntimeDir(WG_RUNTIME_DIR); if (!wgRuntimeDir.exists()) { @@ -146,30 +146,6 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) { int err = uapiErrno(uapiCommand(message)); if (err != 0) { logger.error() << "Interface configuration failed:" << strerror(err); - } else { - if (config.m_killSwitchEnabled) { - FirewallParams params { }; - params.dnsServers.append(config.m_primaryDnsServer); - if (!config.m_secondaryDnsServer.isEmpty()) { - params.dnsServers.append(config.m_secondaryDnsServer); - } - - if (config.m_allowedIPAddressRanges.contains(IPAddress("0.0.0.0/0"))) { - params.blockAll = true; - if (config.m_excludedAddresses.size()) { - params.allowNets = true; - foreach (auto net, config.m_excludedAddresses) { - params.allowAddrs.append(net.toUtf8()); - } - } - } else { - params.blockNets = true; - foreach (auto net, config.m_allowedIPAddressRanges) { - params.blockAddrs.append(net.toString()); - } - } - applyFirewallRules(params); - } } return (err == 0); } @@ -455,28 +431,3 @@ QString WireguardUtilsMacos::waitForTunnelName(const QString& filename) { return QString(); } - -void WireguardUtilsMacos::applyFirewallRules(FirewallParams& params) -{ - // double-check + ensure our firewall is installed and enabled. This is necessary as - // other software may disable pfctl before re-enabling with their own rules (e.g other VPNs) - if (!MacOSFirewall::isInstalled()) MacOSFirewall::install(); - - MacOSFirewall::ensureRootAnchorPriority(); - MacOSFirewall::setAnchorEnabled(QStringLiteral("000.allowLoopback"), true); - MacOSFirewall::setAnchorEnabled(QStringLiteral("100.blockAll"), params.blockAll); - MacOSFirewall::setAnchorEnabled(QStringLiteral("110.allowNets"), params.allowNets); - MacOSFirewall::setAnchorTable(QStringLiteral("110.allowNets"), params.allowNets, - QStringLiteral("allownets"), params.allowAddrs); - - MacOSFirewall::setAnchorEnabled(QStringLiteral("120.blockNets"), params.blockNets); - MacOSFirewall::setAnchorTable(QStringLiteral("120.blockNets"), params.blockNets, - QStringLiteral("blocknets"), params.blockAddrs); - - MacOSFirewall::setAnchorEnabled(QStringLiteral("200.allowVPN"), true); - MacOSFirewall::setAnchorEnabled(QStringLiteral("250.blockIPv6"), true); - MacOSFirewall::setAnchorEnabled(QStringLiteral("290.allowDHCP"), true); - MacOSFirewall::setAnchorEnabled(QStringLiteral("300.allowLAN"), true); - MacOSFirewall::setAnchorEnabled(QStringLiteral("310.blockDNS"), true); - MacOSFirewall::setAnchorTable(QStringLiteral("310.blockDNS"), true, QStringLiteral("dnsaddr"), params.dnsServers); -} diff --git a/client/platforms/macos/daemon/wireguardutilsmacos.h b/client/platforms/macos/daemon/wireguardutilsmacos.h index 3f0d33910..a85a69b45 100644 --- a/client/platforms/macos/daemon/wireguardutilsmacos.h +++ b/client/platforms/macos/daemon/wireguardutilsmacos.h @@ -10,7 +10,6 @@ #include "daemon/wireguardutils.h" #include "macosroutemonitor.h" -#include "macosfirewall.h" class WireguardUtilsMacos final : public WireguardUtils { Q_OBJECT @@ -38,8 +37,6 @@ class WireguardUtilsMacos final : public WireguardUtils { bool excludeLocalNetworks(const QList& lanAddressRanges) override; - void applyFirewallRules(FirewallParams& params); - signals: void backendFailure(); diff --git a/client/platforms/windows/daemon/windowsdaemon.cpp b/client/platforms/windows/daemon/windowsdaemon.cpp index c16df77af..8a414c076 100644 --- a/client/platforms/windows/daemon/windowsdaemon.cpp +++ b/client/platforms/windows/daemon/windowsdaemon.cpp @@ -35,14 +35,8 @@ WindowsDaemon::WindowsDaemon() : Daemon(nullptr) { m_firewallManager = WindowsFirewall::create(this); Q_ASSERT(m_firewallManager != nullptr); - m_wgutils = WireguardUtilsWindows::create(m_firewallManager, this); m_dnsutils = new DnsUtilsWindows(this); m_splitTunnelManager = WindowsSplitTunnel::create(m_firewallManager); - - connect(m_wgutils.get(), &WireguardUtilsWindows::backendFailure, this, - &WindowsDaemon::monitorBackendFailure); - connect(this, &WindowsDaemon::activationFailure, - [this]() { m_firewallManager->disableKillSwitch(); }); } WindowsDaemon::~WindowsDaemon() { @@ -120,7 +114,3 @@ WireguardUtils* WindowsDaemon::createWgUtils() { &WindowsDaemon::monitorBackendFailure); return utils.release(); } - -void WindowsDaemon::replaceActiveWgUtils(WireguardUtils* newUtils) { - m_wgutils.reset(static_cast(newUtils)); -} diff --git a/client/platforms/windows/daemon/windowsdaemon.h b/client/platforms/windows/daemon/windowsdaemon.h index bba2749cb..77a7f9499 100644 --- a/client/platforms/windows/daemon/windowsdaemon.h +++ b/client/platforms/windows/daemon/windowsdaemon.h @@ -28,10 +28,8 @@ class WindowsDaemon final : public Daemon { protected: bool run(Op op, const InterfaceConfig& config) override; - WireguardUtils* wgutils() const override { return m_wgutils.get(); } DnsUtils* dnsutils() override { return m_dnsutils; } WireguardUtils* createWgUtils() override; - void replaceActiveWgUtils(WireguardUtils* newUtils) override; private: void monitorBackendFailure(); @@ -44,7 +42,6 @@ class WindowsDaemon final : public Daemon { int m_inetAdapterIndex = -1; - std::unique_ptr m_wgutils; DnsUtilsWindows* m_dnsutils = nullptr; std::unique_ptr m_splitTunnelManager; QPointer m_firewallManager;