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 ip = NetworkUtilities::getIPAddress(host);
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

View File

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

View File

@@ -4,7 +4,6 @@
#include <QLocalSocket>
#include <QObject>
#include "ipc.h"
#include "rep_ipc_interface_replica.h"
#include "rep_ipc_process_tun2socks_replica.h"
@@ -14,21 +13,52 @@ class IpcClient : public QObject
{
Q_OBJECT
public:
explicit IpcClient(QObject *parent = nullptr);
explicit IpcClient(QObject *parent = nullptr);
static IpcClient *Instance();
static QSharedPointer<IpcInterfaceReplica> Interface();
static QSharedPointer<IpcProcessTun2SocksReplica> InterfaceTun2Socks();
static QSharedPointer<PrivilegedProcess> CreatePrivilegedProcess();
static IpcClient *Instance();
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:
private:
bool establishConnection();
QLocalSocket m_localSocket;
QRemoteObjectNode m_ClientNode;
QSharedPointer<QRemoteObjectNode> m_ClientNode;
QSharedPointer<IpcInterfaceReplica> m_ipcClient;
QSharedPointer<IpcProcessTun2SocksReplica> m_Tun2SocksClient;

View File

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

View File

@@ -7,7 +7,7 @@
#include <QNetworkInterface>
#include "core/networkUtilities.h"
#include "logger.h"
#include "ipc.h"
#include "openvpnprotocol.h"
#include "utilities.h"
#include "version.h"
@@ -56,8 +56,12 @@ void OpenVpnProtocol::stop()
}
#if defined(Q_OS_WIN) || defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
QRemoteObjectPendingReply<bool> disableKillSwitchResp = IpcClient::Interface()->disableKillSwitch();
disableKillSwitchResp.waitForFinished(1000);
IpcClient::withInterface([](QSharedPointer<IpcInterfaceReplica> iface) {
QRemoteObjectPendingReply<bool> reply = iface->disableKillSwitch();
if (!reply.waitForFinished(1000) && !reply.returnValue()) {
qWarning() << "OpenVpnProtocol::stop(): Failed to disable killswitch";
}
});
#endif
setConnectionState(Vpn::ConnectionState::Disconnected);
@@ -65,21 +69,24 @@ void OpenVpnProtocol::stop()
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;
}
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()
@@ -173,8 +180,17 @@ ErrorCode OpenVpnProtocol::start()
}
#ifdef AMNEZIA_DESKTOP
IpcClient::Interface()->addKillSwitchAllowedRange(QStringList(NetworkUtilities::getIPAddress(
m_configData.value(amnezia::config_key::hostName).toString())));
const ErrorCode res = IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
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
// Detect default gateway
@@ -337,30 +353,37 @@ void OpenVpnProtocol::updateVpnGateway(const QString &line)
m_vpnGateway = l.split(" ").at(2);
#ifdef Q_OS_WIN
QThread::msleep(300);
QList<QNetworkInterface> netInterfaces = QNetworkInterface::allInterfaces();
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()) {
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
IpcClient::Interface()->enableKillSwitch(m_configData, netInterfaces.at(i).index());
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
QList<QNetworkInterface> netInterfaces = QNetworkInterface::allInterfaces();
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()) {
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
#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
// killSwitch toggle
if (QVariant(m_configData.value(config_key::killSwitchOption).toString()).toBool()) {
m_configData.insert("vpnServer",
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
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()";
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);
return startTun2Sock();
@@ -44,45 +51,47 @@ ErrorCode XrayProtocol::startTun2Sock()
connect(m_t2sProcess.data(), &IpcProcessTun2SocksReplica::setConnectionState, this, [&](int vpnState) {
qDebug() << "PrivilegedProcess setConnectionState " << vpnState;
if (vpnState == Vpn::ConnectionState::Connected) {
setConnectionState(Vpn::ConnectionState::Connecting);
QList<QHostAddress> dnsAddr;
IpcClient::withInterface([&](QSharedPointer<IpcInterfaceReplica> iface) {
if (vpnState == Vpn::ConnectionState::Connected) {
setConnectionState(Vpn::ConnectionState::Connecting);
QList<QHostAddress> dnsAddr;
dnsAddr.push_back(QHostAddress(m_primaryDNS));
// We don't use secondary DNS if primary DNS is AmneziaDNS
if (!m_primaryDNS.contains(amnezia::protocols::dns::amneziaDnsIp)) {
dnsAddr.push_back(QHostAddress(m_secondaryDNS));
dnsAddr.push_back(QHostAddress(m_primaryDNS));
// We don't use secondary DNS if primary DNS is AmneziaDNS
if (!m_primaryDNS.contains(amnezia::protocols::dns::amneziaDnsIp)) {
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
QThread::msleep(8000);
#endif
#ifdef Q_OS_MACOS
QThread::msleep(5000);
IpcClient::Interface()->createTun("utun22", amnezia::protocols::xray::defaultLocalAddr);
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");
#if !defined(Q_OS_MACOS)
if (vpnState == Vpn::ConnectionState::Disconnected) {
setConnectionState(Vpn::ConnectionState::Disconnected);
iface->deleteTun("tun2");
iface->StartRoutingIpv6();
iface->clearSavedRoutes();
}
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
});
});
return ErrorCode::NoError;
@@ -90,19 +99,29 @@ ErrorCode XrayProtocol::startTun2Sock()
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()";
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) {
m_t2sProcess->stop();

View File

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

View File

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

View File

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

View File

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