fix: safe IpcClient calls (#2076)

* fix: safe IpcClient calls

* fix: double free by specifying parent

* fix: windows includes for ikev2
This commit is contained in:
Yaroslav Gurov
2025-12-19 04:09:50 +01:00
committed by GitHub
parent 6178b05643
commit 91cd9474ea
10 changed files with 274 additions and 201 deletions

View File

@@ -74,7 +74,11 @@ GatewayController::EncryptedRequestData GatewayController::prepareRequest(const
QString host = QUrl(encRequestData.request.url()).host(); QString host = QUrl(encRequestData.request.url()).host();
QString ip = NetworkUtilities::getIPAddress(host); QString ip = NetworkUtilities::getIPAddress(host);
if (!ip.isEmpty()) { if (!ip.isEmpty()) {
IpcClient::Interface()->addKillSwitchAllowedRange(QStringList { ip }); IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
QRemoteObjectPendingReply<bool> reply = iface->addKillSwitchAllowedRange(QStringList { ip });
if (!reply.waitForFinished(1000) || !reply.returnValue())
qWarning() << "GatewayController::prepareRequest(): Failed to execute remote addKillSwitchAllowedRange call";
});
} }
} }
#endif #endif

View File

@@ -10,16 +10,16 @@ namespace
IpcClient::IpcClient(QObject *parent) : QObject(parent) IpcClient::IpcClient(QObject *parent) : QObject(parent)
{ {
m_localSocket.setServerName(amnezia::getIpcServiceUrl());
connect(&m_localSocket, &QLocalSocket::connected, this, [this]() { connect(&m_localSocket, &QLocalSocket::connected, this, [this]() {
m_ClientNode.addClientSideConnection(&m_localSocket); m_ClientNode.reset(new QRemoteObjectNode);
m_ipcClient.reset(m_ClientNode.acquire<IpcInterfaceReplica>()); m_ClientNode->addClientSideConnection(&m_localSocket);
m_Tun2SocksClient.reset(m_ClientNode.acquire<IpcProcessTun2SocksReplica>()); m_ipcClient.reset(m_ClientNode->acquire<IpcInterfaceReplica>());
m_Tun2SocksClient.reset(m_ClientNode->acquire<IpcProcessTun2SocksReplica>());
m_isSocketConnected = true; m_isSocketConnected = true;
}); });
connect(&m_localSocket, &QLocalSocket::disconnected, this, [this]() { connect(&m_localSocket, &QLocalSocket::disconnected, this, [this]() {
m_ClientNode.clear();
m_ipcClient.clear(); m_ipcClient.clear();
m_Tun2SocksClient.clear(); m_Tun2SocksClient.clear();
m_isSocketConnected = false; m_isSocketConnected = false;
@@ -71,7 +71,7 @@ QSharedPointer<IpcProcessTun2SocksReplica> IpcClient::InterfaceTun2Socks()
bool IpcClient::establishConnection() bool IpcClient::establishConnection()
{ {
m_localSocket.connectToServer(); m_localSocket.connectToServer(amnezia::getIpcServiceUrl());
return m_localSocket.waitForConnected(); return m_localSocket.waitForConnected();
} }

View File

@@ -4,7 +4,6 @@
#include <QLocalSocket> #include <QLocalSocket>
#include <QObject> #include <QObject>
#include "ipc.h"
#include "rep_ipc_interface_replica.h" #include "rep_ipc_interface_replica.h"
#include "rep_ipc_process_tun2socks_replica.h" #include "rep_ipc_process_tun2socks_replica.h"
@@ -14,21 +13,52 @@ class IpcClient : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit IpcClient(QObject *parent = nullptr); explicit IpcClient(QObject *parent = nullptr);
static IpcClient *Instance(); static IpcClient *Instance();
static QSharedPointer<IpcInterfaceReplica> Interface();
static QSharedPointer<IpcProcessTun2SocksReplica> InterfaceTun2Socks();
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
bool isSocketConnected() const; static QSharedPointer<IpcInterfaceReplica> Interface();
static QSharedPointer<IpcProcessTun2SocksReplica> InterfaceTun2Socks();
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
template <typename Func>
static auto withInterface(Func func)
{
QSharedPointer<IpcInterfaceReplica> iface = Instance()->m_ipcClient;
using ReturnType = decltype(func(std::declval<QSharedPointer<IpcInterfaceReplica>>()));
if (iface.isNull() || !iface->isReplicaValid()) {
qWarning() << "IpcClient::withInterface(): Service is not running";
if constexpr (std::is_void_v<ReturnType>)
return;
else
return ReturnType{};
}
return func(iface);
}
template <typename OnSuccess, typename OnFailure>
static auto withInterface(OnSuccess onSuccess, OnFailure onFailure)
{
QSharedPointer<IpcInterfaceReplica> iface = Instance()->m_ipcClient;
if (iface.isNull() || !iface->isReplicaValid()) {
return onFailure();
}
return onSuccess(iface);
}
bool isSocketConnected() const;
signals: signals:
private: private:
bool establishConnection(); bool establishConnection();
QLocalSocket m_localSocket; QLocalSocket m_localSocket;
QRemoteObjectNode m_ClientNode; QSharedPointer<QRemoteObjectNode> m_ClientNode;
QSharedPointer<IpcInterfaceReplica> m_ipcClient; QSharedPointer<IpcInterfaceReplica> m_ipcClient;
QSharedPointer<IpcProcessTun2SocksReplica> m_Tun2SocksClient; QSharedPointer<IpcProcessTun2SocksReplica> m_Tun2SocksClient;

View File

@@ -6,6 +6,7 @@
#include <chrono> #include <chrono>
#include "ipc.h"
#include "logger.h" #include "logger.h"
#include "ikev2_vpn_protocol_windows.h" #include "ikev2_vpn_protocol_windows.h"
#include "utilities.h" #include "utilities.h"

View File

@@ -7,7 +7,7 @@
#include <QNetworkInterface> #include <QNetworkInterface>
#include "core/networkUtilities.h" #include "core/networkUtilities.h"
#include "logger.h" #include "ipc.h"
#include "openvpnprotocol.h" #include "openvpnprotocol.h"
#include "utilities.h" #include "utilities.h"
#include "version.h" #include "version.h"
@@ -56,8 +56,12 @@ void OpenVpnProtocol::stop()
} }
#if defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_MACOS) #if defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
QRemoteObjectPendingReply<bool> disableKillSwitchResp = IpcClient::Interface()->disableKillSwitch(); IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
disableKillSwitchResp.waitForFinished(1000); QRemoteObjectPendingReply<bool> reply = iface->disableKillSwitch();
if (!reply.waitForFinished(1000) && !reply.returnValue()) {
qWarning() << "OpenVpnProtocol::stop(): Failed to disable killswitch";
}
});
#endif #endif
setConnectionState(Vpn::ConnectionState::Disconnected); setConnectionState(Vpn::ConnectionState::Disconnected);
@@ -65,21 +69,24 @@ void OpenVpnProtocol::stop()
ErrorCode OpenVpnProtocol::prepare() ErrorCode OpenVpnProtocol::prepare()
{ {
if (!IpcClient::Interface()) { return IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
QRemoteObjectPendingReply<QStringList> listReply = iface->getTapList();
if (!listReply.waitForFinished(1000)) {
return ErrorCode::InternalError;
}
QStringList list = listReply.returnValue();
if (list.empty()) {
QRemoteObjectPendingReply<bool> installReply = iface->checkAndInstallDriver();
if (!installReply.waitForFinished() || !installReply.returnValue()) {
return ErrorCode::OpenVpnTapAdapterError;
}
}
return ErrorCode::NoError;
}, [] () {
return ErrorCode::AmneziaServiceConnectionFailed; return ErrorCode::AmneziaServiceConnectionFailed;
} });
QRemoteObjectPendingReply<QStringList> resultCheck = IpcClient::Interface()->getTapList();
resultCheck.waitForFinished();
if (resultCheck.returnValue().isEmpty()) {
QRemoteObjectPendingReply<bool> resultInstall = IpcClient::Interface()->checkAndInstallDriver();
resultInstall.waitForFinished();
if (!resultInstall.returnValue())
return ErrorCode::OpenVpnTapAdapterError;
}
return ErrorCode::NoError;
} }
void OpenVpnProtocol::killOpenVpnProcess() void OpenVpnProtocol::killOpenVpnProcess()
@@ -173,8 +180,17 @@ ErrorCode OpenVpnProtocol::start()
} }
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
IpcClient::Interface()->addKillSwitchAllowedRange(QStringList(NetworkUtilities::getIPAddress( const ErrorCode res = IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
m_configData.value(amnezia::config_key::hostName).toString()))); QString ip = NetworkUtilities::getIPAddress(m_configData.value(amnezia::config_key::hostName).toString());
QRemoteObjectPendingReply<bool> reply = iface->addKillSwitchAllowedRange(QStringList(ip));
if (!reply.waitForFinished(1000) || !reply.returnValue()) {
return ErrorCode::AmneziaServiceConnectionFailed;
}
return ErrorCode::NoError;
});
if (res != ErrorCode::NoError) {
return res;
}
#endif #endif
// Detect default gateway // Detect default gateway
@@ -337,30 +353,37 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
m_vpnGateway = l.split(" ").at(2); m_vpnGateway = l.split(" ").at(2);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QThread::msleep(300); QThread::msleep(300);
QList<QNetworkInterface> netInterfaces = QNetworkInterface::allInterfaces(); IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
for (int i = 0; i < netInterfaces.size(); i++) { QList<QNetworkInterface> netInterfaces = QNetworkInterface::allInterfaces();
for (int j=0; j < netInterfaces.at(i).addressEntries().size(); j++) for (int i = 0; i < netInterfaces.size(); i++) {
{ for (int j=0; j < netInterfaces.at(i).addressEntries().size(); j++)
// killSwitch toggle {
if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) { // killSwitch toggle
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { if (m_vpnLocalAddress == netInterfaces.at(i).addressEntries().at(j).ip().toString()) {
IpcClient::Interface()->enableKillSwitch(m_configData, netInterfaces.at(i).index()); if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
iface->enableKillSwitch(m_configData, netInterfaces.at(i).index());
}
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
m_configData.insert("vpnGateway", m_vpnGateway);
m_configData.insert("vpnServer",
NetworkUtilities::getIPAddress(m_configData.value(amnezia::config_key::hostName).toString()));
iface->enablePeerTraffic(m_configData);
} }
m_configData.insert("vpnAdapterIndex", netInterfaces.at(i).index());
m_configData.insert("vpnGateway", m_vpnGateway);
m_configData.insert("vpnServer",
NetworkUtilities::getIPAddress(m_configData.value(amnezia::config_key::hostName).toString()));
IpcClient::Interface()->enablePeerTraffic(m_configData);
} }
} }
} });
#endif #endif
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS) #if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
// killSwitch toggle // killSwitch toggle
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) { if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
m_configData.insert("vpnServer", m_configData.insert("vpnServer",
NetworkUtilities::getIPAddress(m_configData.value(amnezia::config_key::hostName).toString())); NetworkUtilities::getIPAddress(m_configData.value(amnezia::config_key::hostName).toString()));
IpcClient::Interface()->enableKillSwitch(m_configData, 0); IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
QRemoteObjectPendingReply<bool> reply = iface->enableKillSwitch(m_configData, 0);
if (!reply.waitForFinished(1000) || !reply.returnValue()) {
qWarning() << "OpenVpnProtocol::updateVpnGateway(): Failed to enable killswitch";
}
});
} }
#endif #endif
qDebug() << QString("Set vpn local address %1, gw %2").arg(m_vpnLocalAddress).arg(vpnGateway()); qDebug() << QString("Set vpn local address %1, gw %2").arg(m_vpnLocalAddress).arg(vpnGateway());

View File

@@ -29,7 +29,14 @@ ErrorCode XrayProtocol::start()
{ {
qDebug() << "XrayProtocol::start()"; qDebug() << "XrayProtocol::start()";
IpcClient::Interface()->xrayStart(QJsonDocument(m_xrayConfig).toJson()); const ErrorCode err = IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
iface->xrayStart(QJsonDocument(m_xrayConfig).toJson());
return ErrorCode::NoError;
}, [] () {
return ErrorCode::AmneziaServiceConnectionFailed;
});
if (err != ErrorCode::NoError)
return err;
setConnectionState(Vpn::ConnectionState::Connecting); setConnectionState(Vpn::ConnectionState::Connecting);
return startTun2Sock(); return startTun2Sock();
@@ -44,45 +51,47 @@ ErrorCode XrayProtocol::startTun2Sock()
connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::setConnectionState, this, [&](int vpnState) { connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::setConnectionState, this, [&](int vpnState) {
qDebug() << "PrivilegedProcess setConnectionState " << vpnState; qDebug() << "PrivilegedProcess setConnectionState " << vpnState;
if (vpnState == Vpn::ConnectionState::Connected) { IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
setConnectionState(Vpn::ConnectionState::Connecting); if (vpnState == Vpn::ConnectionState::Connected) {
QList<QHostAddress> dnsAddr; setConnectionState(Vpn::ConnectionState::Connecting);
QList<QHostAddress> dnsAddr;
dnsAddr.push_back(QHostAddress(m_primaryDNS)); dnsAddr.push_back(QHostAddress(m_primaryDNS));
// We don't use secondary DNS if primary DNS is AmneziaDNS // We don't use secondary DNS if primary DNS is AmneziaDNS
if (!m_primaryDNS.contains(amnezia::protocols::dns::amneziaDnsIp)) { if (!m_primaryDNS.contains(amnezia::protocols::dns::amneziaDnsIp)) {
dnsAddr.push_back(QHostAddress(m_secondaryDNS)); dnsAddr.push_back(QHostAddress(m_secondaryDNS));
}
#ifdef Q_OS_WIN
QThread::msleep(8000);
#endif
#ifdef Q_OS_MACOS
QThread::msleep(5000);
iface->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr);
iface->updateResolvers("utun22", dnsAddr);
#endif
#ifdef Q_OS_LINUX
QThread::msleep(1000);
iface->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr);
iface->updateResolvers("tun2", dnsAddr);
#endif
if (m_routeMode == Settings::RouteMode::VpnAllSites) {
iface->routeAddList(m_vpnGateway, QStringList() << "1.0.0.0/8" << "2.0.0.0/7" << "4.0.0.0/6" << "8.0.0.0/5" << "16.0.0.0/4" << "32.0.0.0/3" << "64.0.0.0/2" << "128.0.0.0/1");
}
iface->StopRoutingIpv6();
#ifdef Q_OS_WIN
iface->updateResolvers("tun2", dnsAddr);
#endif
setConnectionState(Vpn::ConnectionState::Connected);
} }
#ifdef Q_OS_WIN #if !defined(Q_OS_MACOS)
QThread::msleep(8000); if (vpnState == Vpn::ConnectionState::Disconnected) {
#endif setConnectionState(Vpn::ConnectionState::Disconnected);
#ifdef Q_OS_MACOS iface->deleteTun("tun2");
QThread::msleep(5000); iface->StartRoutingIpv6();
IpcClient::Interface()->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr); iface->clearSavedRoutes();
IpcClient::Interface()->updateResolvers("utun22", dnsAddr);
#endif
#ifdef Q_OS_LINUX
QThread::msleep(1000);
IpcClient::Interface()->createTun("tun2", amnezia::protocols::xray::defaultLocalAddr);
IpcClient::Interface()->updateResolvers("tun2", dnsAddr);
#endif
if (m_routeMode == Settings::RouteMode::VpnAllSites) {
IpcClient::Interface()->routeAddList(m_vpnGateway, QStringList() << "1.0.0.0/8" << "2.0.0.0/7" << "4.0.0.0/6" << "8.0.0.0/5" << "16.0.0.0/4" << "32.0.0.0/3" << "64.0.0.0/2" << "128.0.0.0/1");
} }
IpcClient::Interface()->StopRoutingIpv6();
#ifdef Q_OS_WIN
IpcClient::Interface()->updateResolvers("tun2", dnsAddr);
#endif
setConnectionState(Vpn::ConnectionState::Connected);
}
#if !defined(Q_OS_MACOS)
if (vpnState == Vpn::ConnectionState::Disconnected) {
setConnectionState(Vpn::ConnectionState::Disconnected);
IpcClient::Interface()->deleteTun("tun2");
IpcClient::Interface()->StartRoutingIpv6();
IpcClient::Interface()->clearSavedRoutes();
}
#endif #endif
});
}); });
return ErrorCode::NoError; return ErrorCode::NoError;
@@ -90,19 +99,29 @@ ErrorCode XrayProtocol::startTun2Sock()
void XrayProtocol::stop() void XrayProtocol::stop()
{ {
#ifdef AMNEZIA_DESKTOP
QRemoteObjectPendingReply<bool> StartRoutingIpv6Resp = IpcClient::Interface()->StartRoutingIpv6();
StartRoutingIpv6Resp.waitForFinished(1000);
QRemoteObjectPendingReply<bool> restoreResolvers = IpcClient::Interface()->restoreResolvers();
restoreResolvers.waitForFinished(1000);
#if !defined(Q_OS_MACOS)
QRemoteObjectPendingReply<bool> deleteTunResp = IpcClient::Interface()->deleteTun("tun2");
deleteTunResp.waitForFinished(1000);
#endif
#endif
qDebug() << "XrayProtocol::stop()"; qDebug() << "XrayProtocol::stop()";
IpcClient::Interface()->xrayStop(); IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
#ifdef AMNEZIA_DESKTOP
QRemoteObjectPendingReply<bool> StartRoutingIpv6Resp = iface->StartRoutingIpv6();
if (!StartRoutingIpv6Resp.waitForFinished(1000)) {
qWarning() << "XrayProtocol::stop(): Failed to start routing ipv6";
}
QRemoteObjectPendingReply<bool> restoreResolvers = iface->restoreResolvers();
if (!restoreResolvers.waitForFinished(1000)) {
qWarning() << "XrayProtocol::stop(): Failed to restore resolvers";
}
#if !defined(Q_OS_MACOS)
QRemoteObjectPendingReply<bool> deleteTunResp = iface->deleteTun("tun2");
if (!deleteTunResp.waitForFinished(1000)) {
qWarning() << "XrayProtocol::stop(): Failed to delete tun";
}
#endif
#endif
iface->xrayStop();
});
if (m_t2sProcess) { if (m_t2sProcess) {
m_t2sProcess->stop(); m_t2sProcess->stop();

View File

@@ -6,6 +6,7 @@
#include <QApplication> #include <QApplication>
#endif #endif
#include "utilities.h"
#include "core/controllers/vpnConfigurationController.h" #include "core/controllers/vpnConfigurationController.h"
#include "version.h" #include "version.h"

View File

@@ -57,10 +57,13 @@ void VpnConnection::onBytesChanged(quint64 receivedBytes, quint64 sentBytes)
void VpnConnection::onKillSwitchModeChanged(bool enabled) void VpnConnection::onKillSwitchModeChanged(bool enabled)
{ {
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
if (InterfaceReady()) { IpcClient::withInterface([enabled](QSharedPointer<IpcInterfaceReplica> iface){
qDebug() << "Set KillSwitch Strict mode enabled " << enabled; QRemoteObjectPendingReply<bool> reply = iface->refreshKillSwitch(enabled);
IpcClient::Interface()->refreshKillSwitch(enabled); if (reply.waitForFinished(1000) && reply.returnValue())
} qDebug() << "VpnConnection::onKillSwitchModeChanged: Killswitch refreshed";
else
qWarning() << "VpnConnection::onKillSwitchModeChanged: Failed to execute remote refreshKillSwitch call";
});
#endif #endif
} }
@@ -69,29 +72,29 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
auto container = m_settings->defaultContainer(m_settings->defaultServerIndex()); auto container = m_settings->defaultContainer(m_settings->defaultServerIndex());
if (InterfaceReady()) { IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
if (state == Vpn::ConnectionState::Connected) { if (state == Vpn::ConnectionState::Connected) {
IpcClient::Interface()->resetIpStack(); iface->resetIpStack();
IpcClient::Interface()->flushDns(); iface->flushDns();
if (!ContainerProps::isAwgContainer(container) && if (!ContainerProps::isAwgContainer(container) &&
container != DockerContainer::WireGuard) { container != DockerContainer::WireGuard) {
QString dns1 = m_vpnConfiguration.value(config_key::dns1).toString(); QString dns1 = m_vpnConfiguration.value(config_key::dns1).toString();
QString dns2 = m_vpnConfiguration.value(config_key::dns2).toString(); QString dns2 = m_vpnConfiguration.value(config_key::dns2).toString();
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << dns1 << dns2); iface->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << dns1 << dns2);
if (m_settings->isSitesSplitTunnelingEnabled()) { if (m_settings->isSitesSplitTunnelingEnabled()) {
IpcClient::Interface()->routeDeleteList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0"); iface->routeDeleteList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0");
// qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << forwardIps.size(); // qDebug() << "VpnConnection::onConnectionStateChanged :: adding custom routes, count:" << forwardIps.size();
if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
QTimer::singleShot(1000, m_vpnProtocol.data(), QTimer::singleShot(1000, m_vpnProtocol.data(),
[this]() { addSitesRoutes(m_vpnProtocol->vpnGateway(), m_settings->routeMode()); }); [this]() { addSitesRoutes(m_vpnProtocol->vpnGateway(), m_settings->routeMode()); });
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) { } else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0/1"); iface->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "0.0.0.0/1");
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "128.0.0.0/1"); iface->routeAddList(m_vpnProtocol->vpnGateway(), QStringList() << "128.0.0.0/1");
IpcClient::Interface()->routeAddList(m_vpnProtocol->routeGateway(), QStringList() << remoteAddress()); iface->routeAddList(m_vpnProtocol->routeGateway(), QStringList() << remoteAddress());
addSitesRoutes(m_vpnProtocol->routeGateway(), m_settings->routeMode()); addSitesRoutes(m_vpnProtocol->routeGateway(), m_settings->routeMode());
} }
} }
@@ -111,21 +114,21 @@ void VpnConnection::onConnectionStateChanged(Vpn::ConnectionState state)
} else if (state == Vpn::ConnectionState::Error) { } else if (state == Vpn::ConnectionState::Error) {
m_pendingNetworkCheck = false; m_pendingNetworkCheck = false;
IpcClient::Interface()->flushDns(); iface->flushDns();
if (m_settings->isSitesSplitTunnelingEnabled()) { if (m_settings->isSitesSplitTunnelingEnabled()) {
if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
IpcClient::Interface()->clearSavedRoutes(); iface->clearSavedRoutes();
} }
} }
} else if (state == Vpn::ConnectionState::Connecting) { } else if (state == Vpn::ConnectionState::Connecting) {
} else if (state == Vpn::ConnectionState::Disconnected) { } else if (state == Vpn::ConnectionState::Disconnected) {
m_pendingNetworkCheck = false; m_pendingNetworkCheck = false;
auto result = IpcClient::Interface()->stopNetworkCheck(); auto result = iface->stopNetworkCheck();
result.waitForFinished(3000); result.waitForFinished(3000);
} }
} });
#endif #endif
#if defined(Q_OS_IOS) || defined(MACOS_NE) #if defined(Q_OS_IOS) || defined(MACOS_NE)
@@ -161,8 +164,9 @@ void VpnConnection::addSitesRoutes(const QString &gw, Settings::RouteMode mode)
} }
ips.removeDuplicates(); ips.removeDuplicates();
// add all IPs immediately IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
IpcClient::Interface()->routeAddList(gw, ips); iface->routeAddList(gw, ips);
});
// re-resolve domains // re-resolve domains
for (const QString &site : sites) { for (const QString &site : sites) {
@@ -174,7 +178,9 @@ void VpnConnection::addSitesRoutes(const QString &gw, Settings::RouteMode mode)
const QString &ip = addr.toString(); const QString &ip = addr.toString();
// qDebug() << "VpnConnection::addSitesRoutes updating site" << site << ip; // qDebug() << "VpnConnection::addSitesRoutes updating site" << site << ip;
if (!ips.contains(ip)) { if (!ips.contains(ip)) {
IpcClient::Interface()->routeAddList(gw, QStringList() << ip); IpcClient::withInterface([&gw, &ip](QSharedPointer<IpcInterfaceReplica> iface) {
iface->routeAddList(gw, QStringList() << ip);
});
m_settings->addVpnSite(mode, site, ip); m_settings->addVpnSite(mode, site, ip);
} }
flushDns(); flushDns();
@@ -195,48 +201,42 @@ QSharedPointer<VpnProtocol> VpnConnection::vpnProtocol() const
void VpnConnection::addRoutes(const QStringList &ips) void VpnConnection::addRoutes(const QStringList &ips)
{ {
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
if (connectionState() == Vpn::ConnectionState::Connected && IpcClient::Interface()) { IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { if (connectionState() == Vpn::ConnectionState::Connected) {
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), ips); if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) { iface->routeAddList(m_vpnProtocol->vpnGateway(), ips);
IpcClient::Interface()->routeAddList(m_vpnProtocol->routeGateway(), ips); } else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
iface->routeAddList(m_vpnProtocol->routeGateway(), ips);
}
} }
} });
#endif #endif
} }
void VpnConnection::deleteRoutes(const QStringList &ips) void VpnConnection::deleteRoutes(const QStringList &ips)
{ {
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
if (connectionState() == Vpn::ConnectionState::Connected && IpcClient::Interface()) { IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) { if (connectionState() == Vpn::ConnectionState::Connected) {
IpcClient::Interface()->routeDeleteList(vpnProtocol()->vpnGateway(), ips); if (m_settings->routeMode() == Settings::VpnOnlyForwardSites) {
} else if (m_settings->routeMode() == Settings::VpnAllExceptSites) { iface->routeDeleteList(vpnProtocol()->vpnGateway(), ips);
IpcClient::Interface()->routeDeleteList(m_vpnProtocol->routeGateway(), ips); } else if (m_settings->routeMode() == Settings::VpnAllExceptSites) {
iface->routeDeleteList(m_vpnProtocol->routeGateway(), ips);
}
} }
} });
#endif #endif
} }
// TODO: replace with something like
// VpnConnection::withInterface([](iface){ })
bool VpnConnection::InterfaceReady()
{
#ifdef AMNEZIA_DESKTOP
if (auto iface = IpcClient::Interface(); iface == nullptr) {
qWarning() << "Error occurred when init IPC client";
emit serviceIsNotReady();
return false;
}
#endif
return true;
}
void VpnConnection::flushDns() void VpnConnection::flushDns()
{ {
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
if (InterfaceReady()) IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
IpcClient::Interface()->flushDns(); auto reply = iface->flushDns();
if (reply.waitForFinished(1000) || !reply.returnValue()) {
qWarning() << "VpnConnection::flushDns(): Failed to flush DNS";
}
});
#endif #endif
} }
@@ -253,7 +253,7 @@ ErrorCode VpnConnection::lastError() const
return ErrorCode::AndroidError; return ErrorCode::AndroidError;
#endif #endif
if (!m_vpnProtocol.data()) { if (m_vpnProtocol.isNull()) {
return ErrorCode::InternalError; return ErrorCode::InternalError;
} }
@@ -268,11 +268,6 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
.arg(ContainerProps::containerToString(container)) .arg(ContainerProps::containerToString(container))
<< m_settings->routeMode(); << m_settings->routeMode();
if (!InterfaceReady()) {
emit connectionStateChanged(Vpn::ConnectionState::Error);
return;
}
m_remoteAddress = NetworkUtilities::getIPAddress(credentials.hostName); m_remoteAddress = NetworkUtilities::getIPAddress(credentials.hostName);
emit connectionStateChanged(Vpn::ConnectionState::Connecting); emit connectionStateChanged(Vpn::ConnectionState::Connecting);
@@ -314,7 +309,7 @@ void VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &crede
createProtocolConnections(); createProtocolConnections();
ErrorCode errorCode = m_vpnProtocol.data()->start(); ErrorCode errorCode = m_vpnProtocol->start();
if (errorCode != ErrorCode::NoError) if (errorCode != ErrorCode::NoError)
emit connectionStateChanged(Vpn::ConnectionState::Error); emit connectionStateChanged(Vpn::ConnectionState::Error);
} }
@@ -353,6 +348,7 @@ void VpnConnection::createProtocolConnections()
m_connectionLoseHandle = QMetaObject::Connection(); m_connectionLoseHandle = QMetaObject::Connection();
m_networkChangeHandle = QMetaObject::Connection(); m_networkChangeHandle = QMetaObject::Connection();
// TODO: replace unsafe IpcClient::Interface() calls
m_connectionLoseHandle = connect(IpcClient::Interface().data(), &IpcInterfaceReplica::connectionLose, m_connectionLoseHandle = connect(IpcClient::Interface().data(), &IpcInterfaceReplica::connectionLose,
this, [this]() { this, [this]() {
qDebug() << "Connection Lose"; qDebug() << "Connection Lose";
@@ -499,13 +495,10 @@ bool VpnConnection::startNetworkCheckIfReady()
return false; return false;
} }
auto iface = IpcClient::Interface(); return IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
if (!iface) { QRemoteObjectPendingReply<bool> reply = iface->startNetworkCheck(gateway, localAddress);
return false; return reply.waitForFinished() && reply.returnValue();
} });
iface->startNetworkCheck(gateway, localAddress);
return true;
#else #else
return false; return false;
#endif #endif
@@ -544,35 +537,40 @@ QString VpnConnection::bytesPerSecToText(quint64 bytes)
void VpnConnection::disconnectFromVpn() void VpnConnection::disconnectFromVpn()
{ {
#ifdef AMNEZIA_DESKTOP if (m_vpnProtocol.isNull()) {
if (InterfaceReady()) { emit connectionStateChanged(Vpn::ConnectionState::Disconnected);
return;
m_vpnProtocol.data()->stop();
qDebug() << "Interface is ready!";
QRemoteObjectPendingReply<bool> flushDnsResp = IpcClient::Interface()->flushDns();
flushDnsResp.waitForFinished(1000);
qDebug() << "Flushed DNS";
// delete cached routes
QRemoteObjectPendingReply<bool> clearSavedRoutesResp = IpcClient::Interface()->clearSavedRoutes();
clearSavedRoutesResp.waitForFinished(1000);
} }
m_vpnProtocol->stop();
#ifdef AMNEZIA_DESKTOP
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
QRemoteObjectPendingReply<bool> flushReply = iface->flushDns();
if (flushReply.waitForFinished(5000) && flushReply.returnValue())
qDebug() << "VpnConnection::disconnectFromVpn(): Successfully flushed DNS";
else
qWarning() << "VpnConnection::disconnectFromVpn(): Failed to flush DNS";
QRemoteObjectPendingReply<bool> clearSavedRoutesReply = iface->clearSavedRoutes();
if (clearSavedRoutesReply.waitForFinished(5000) && clearSavedRoutesReply.returnValue())
qDebug() << "VpnConnection::disconnectFromVpn(): Successfully cleared saved routes";
else
qWarning() << "VpnConnection::disconnectFromVpn(): Failed to clear saved routes";
});
#endif #endif
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
if (m_vpnProtocol && m_vpnProtocol.data()) { auto *const connection = new QMetaObject::Connection;
auto *const connection = new QMetaObject::Connection; *connection = connect(AndroidController::instance(), &AndroidController::vpnStateChanged, this,
*connection = connect(AndroidController::instance(), &AndroidController::vpnStateChanged, this, [this, connection](AndroidController::ConnectionState state) {
[this, connection](AndroidController::ConnectionState state) { if (state == AndroidController::ConnectionState::DISCONNECTED) {
if (state == AndroidController::ConnectionState::DISCONNECTED) { onConnectionStateChanged(Vpn::ConnectionState::Disconnected);
onConnectionStateChanged(Vpn::ConnectionState::Disconnected); disconnect(*connection);
disconnect(*connection); delete connection;
delete connection; }
} });
}); m_vpnProtocol->stop();
m_vpnProtocol.data()->stop();
}
#endif #endif
#if defined(Q_OS_IOS) || defined(MACOS_NE) #if defined(Q_OS_IOS) || defined(MACOS_NE)
@@ -580,15 +578,8 @@ void VpnConnection::disconnectFromVpn()
disconnect(&m_checkTimer, &QTimer::timeout, IosController::Instance(), &IosController::checkStatus); disconnect(&m_checkTimer, &QTimer::timeout, IosController::Instance(), &IosController::checkStatus);
#endif #endif
if (!m_vpnProtocol.data()) {
emit connectionStateChanged(Vpn::ConnectionState::Disconnected);
return;
}
#if !defined(Q_OS_ANDROID) && !defined(AMNEZIA_DESKTOP) #if !defined(Q_OS_ANDROID) && !defined(AMNEZIA_DESKTOP)
if (m_vpnProtocol) { m_vpnProtocol->deleteLater();
m_vpnProtocol->deleteLater();
}
#endif #endif
m_vpnProtocol = nullptr; m_vpnProtocol = nullptr;
@@ -603,18 +594,18 @@ Vpn::ConnectionState VpnConnection::connectionState()
bool VpnConnection::isConnected() const bool VpnConnection::isConnected() const
{ {
if (!m_vpnProtocol.data()) { if (m_vpnProtocol.isNull()) {
return false; return false;
} }
return m_vpnProtocol.data()->isConnected(); return m_vpnProtocol->isConnected();
} }
bool VpnConnection::isDisconnected() const bool VpnConnection::isDisconnected() const
{ {
if (!m_vpnProtocol.data()) { if (m_vpnProtocol.isNull()) {
return true; return true;
} }
return m_vpnProtocol.data()->isDisconnected(); return m_vpnProtocol->isDisconnected();
} }

View File

@@ -105,7 +105,6 @@ private:
void appendSplitTunnelingConfig(); void appendSplitTunnelingConfig();
void appendKillSwitchConfig(); void appendKillSwitchConfig();
bool startNetworkCheckIfReady(); bool startNetworkCheckIfReady();
bool InterfaceReady();
}; };
#endif // VPNCONNECTION_H #endif // VPNCONNECTION_H

View File

@@ -91,12 +91,14 @@ void Logger::deInit()
bool Logger::setServiceLogsEnabled(bool enabled) bool Logger::setServiceLogsEnabled(bool enabled)
{ {
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
if (auto iface = IpcClient::Interface(); iface) { return IpcClient::withInterface([enabled](QSharedPointer<IpcInterfaceReplica> iface) {
iface->setLogsEnabled(enabled); iface->setLogsEnabled(enabled);
} else { qDebug() << "Logger::setServiceLogsEnabled(): Logs transitioned to be " << (enabled ? "enabled" : "disabled");
qWarning() << "Error occurred setting up service logs"; return true;
},[](){
qWarning() << "Logger::setServiceLogsEnabled(): Service is not running";
return false; return false;
} });
#endif #endif
return true; return true;
@@ -199,9 +201,12 @@ void Logger::clearLogs(bool isServiceLogger)
void Logger::clearServiceLogs() void Logger::clearServiceLogs()
{ {
#ifdef AMNEZIA_DESKTOP #ifdef AMNEZIA_DESKTOP
if (auto iface = IpcClient::Interface(); iface) { IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
iface->clearLogs(); iface->clearLogs();
} qDebug() << "Logger::clearServiceLogs(): Logs cleared";
}, []() {
qWarning() << "Logger::clearServiceLogs(): Service is not running";
});
#endif #endif
} }