283 lines
9.1 KiB
C++
283 lines
9.1 KiB
C++
#include <QCoreApplication>
|
|
#include <QFileInfo>
|
|
#include <QProcess>
|
|
#include <QTcpSocket>
|
|
#include <QThread>
|
|
|
|
#include "logger.h"
|
|
#include "utilities.h"
|
|
#include "wireguardprotocol.h"
|
|
|
|
#include "mozilla/localsocketcontroller.h"
|
|
|
|
WireguardProtocol::WireguardProtocol(const QJsonObject &configuration, QObject *parent)
|
|
: VpnProtocol(configuration, parent)
|
|
{
|
|
m_configFile.setFileName(QDir::tempPath() + QDir::separator() + serviceName() + ".conf");
|
|
writeWireguardConfiguration(configuration);
|
|
|
|
// MZ
|
|
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_LINUX)
|
|
m_impl.reset(new LocalSocketController());
|
|
connect(m_impl.get(), &ControllerImpl::connected, this,
|
|
[this](const QString &pubkey, const QDateTime &connectionTimestamp) {
|
|
emit connectionStateChanged(Vpn::ConnectionState::Connected);
|
|
});
|
|
connect(m_impl.get(), &ControllerImpl::disconnected, this,
|
|
[this]() { emit connectionStateChanged(Vpn::ConnectionState::Disconnected); });
|
|
m_impl->initialize(nullptr, nullptr);
|
|
#endif
|
|
}
|
|
|
|
WireguardProtocol::~WireguardProtocol()
|
|
{
|
|
WireguardProtocol::stop();
|
|
QThread::msleep(200);
|
|
}
|
|
|
|
void WireguardProtocol::stop()
|
|
{
|
|
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_LINUX)
|
|
stopMzImpl();
|
|
return;
|
|
#endif
|
|
|
|
if (!QFileInfo::exists(Utils::wireguardExecPath())) {
|
|
qCritical() << "Wireguard executable missing!";
|
|
setLastError(ErrorCode::ExecutableMissing);
|
|
return;
|
|
}
|
|
|
|
m_wireguardStopProcess = IpcClient::CreatePrivilegedProcess();
|
|
|
|
if (!m_wireguardStopProcess) {
|
|
qCritical() << "IpcProcess replica is not created!";
|
|
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
|
return;
|
|
}
|
|
|
|
m_wireguardStopProcess->waitForSource(1000);
|
|
if (!m_wireguardStopProcess->isInitialized()) {
|
|
qWarning() << "IpcProcess replica is not connected!";
|
|
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
|
return;
|
|
}
|
|
|
|
m_wireguardStopProcess->setProgram(PermittedProcess::Wireguard);
|
|
|
|
m_wireguardStopProcess->setArguments(stopArgs());
|
|
qDebug() << stopArgs().join(" ");
|
|
|
|
connect(m_wireguardStopProcess.data(), &PrivilegedProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
|
|
qDebug() << "WireguardProtocol::WireguardProtocol Stop errorOccurred" << error;
|
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
|
});
|
|
|
|
connect(m_wireguardStopProcess.data(), &PrivilegedProcess::stateChanged, this,
|
|
[this](QProcess::ProcessState newState) {
|
|
qDebug() << "WireguardProtocol::WireguardProtocol Stop stateChanged" << newState;
|
|
});
|
|
|
|
#ifdef Q_OS_LINUX
|
|
if (IpcClient::Interface()) {
|
|
QRemoteObjectPendingReply<bool> result = IpcClient::Interface()->isWireguardRunning();
|
|
if (result.returnValue()) {
|
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
|
return;
|
|
}
|
|
} else {
|
|
qCritical() << "IPC client not initialized";
|
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
m_wireguardStopProcess->start();
|
|
m_wireguardStopProcess->waitForFinished(10000);
|
|
|
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
|
}
|
|
|
|
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_LINUX)
|
|
ErrorCode WireguardProtocol::startMzImpl()
|
|
{
|
|
|
|
qDebug() << "WireguardProtocol::startMzImpl():" << m_rawConfig;
|
|
m_impl->activate(m_rawConfig);
|
|
return ErrorCode::NoError;
|
|
}
|
|
|
|
ErrorCode WireguardProtocol::stopMzImpl()
|
|
{
|
|
m_impl->deactivate();
|
|
return ErrorCode::NoError;
|
|
}
|
|
#endif
|
|
|
|
void WireguardProtocol::writeWireguardConfiguration(const QJsonObject &configuration)
|
|
{
|
|
QJsonObject jConfig = configuration.value(ProtocolProps::key_proto_config_data(Proto::WireGuard)).toObject();
|
|
|
|
if (!m_configFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
|
qCritical() << "Failed to save wireguard config to" << m_configFile.fileName();
|
|
return;
|
|
}
|
|
|
|
m_configFile.write(jConfig.value(config_key::config).toString().toUtf8());
|
|
m_configFile.close();
|
|
|
|
#if 0
|
|
if (IpcClient::Interface()) {
|
|
QRemoteObjectPendingReply<bool> result = IpcClient::Interface()->copyWireguardConfig(m_configFile.fileName());
|
|
if (result.returnValue()) {
|
|
qCritical() << "Failed to copy wireguard config";
|
|
return;
|
|
}
|
|
} else {
|
|
qCritical() << "IPC client not initialized";
|
|
return;
|
|
}
|
|
m_configFileName = "/etc/wireguard/wg99.conf";
|
|
#else
|
|
m_configFileName = m_configFile.fileName();
|
|
#endif
|
|
|
|
m_isConfigLoaded = true;
|
|
|
|
qDebug().noquote() << QString("Set config data") << configPath();
|
|
qDebug().noquote() << QString("Set config data")
|
|
<< configuration.value(ProtocolProps::key_proto_config_data(Proto::WireGuard)).toString().toUtf8();
|
|
}
|
|
|
|
QString WireguardProtocol::configPath() const
|
|
{
|
|
return m_configFileName;
|
|
}
|
|
|
|
void WireguardProtocol::updateRouteGateway(QString line)
|
|
{
|
|
// TODO: fix for macos
|
|
line = line.split("ROUTE_GATEWAY", Qt::SkipEmptyParts).at(1);
|
|
if (!line.contains("/"))
|
|
return;
|
|
m_routeGateway = line.split("/", Qt::SkipEmptyParts).first();
|
|
m_routeGateway.replace(" ", "");
|
|
qDebug() << "Set VPN route gateway" << m_routeGateway;
|
|
}
|
|
|
|
ErrorCode WireguardProtocol::start()
|
|
{
|
|
if (!m_isConfigLoaded) {
|
|
setLastError(ErrorCode::ConfigMissing);
|
|
return lastError();
|
|
}
|
|
|
|
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_LINUX)
|
|
return startMzImpl();
|
|
#endif
|
|
|
|
if (!QFileInfo::exists(Utils::wireguardExecPath())) {
|
|
setLastError(ErrorCode::ExecutableMissing);
|
|
return lastError();
|
|
}
|
|
|
|
if (IpcClient::Interface()) {
|
|
QRemoteObjectPendingReply<bool> result = IpcClient::Interface()->isWireguardConfigExists(configPath());
|
|
if (result.returnValue()) {
|
|
setLastError(ErrorCode::ConfigMissing);
|
|
return lastError();
|
|
}
|
|
} else {
|
|
qCritical() << "IPC client not initialized";
|
|
setLastError(ErrorCode::InternalError);
|
|
return lastError();
|
|
}
|
|
|
|
setConnectionState(Vpn::ConnectionState::Connecting);
|
|
|
|
m_wireguardStartProcess = IpcClient::CreatePrivilegedProcess();
|
|
|
|
if (!m_wireguardStartProcess) {
|
|
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
|
return ErrorCode::AmneziaServiceConnectionFailed;
|
|
}
|
|
|
|
m_wireguardStartProcess->waitForSource(1000);
|
|
if (!m_wireguardStartProcess->isInitialized()) {
|
|
qWarning() << "IpcProcess replica is not connected!";
|
|
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
|
|
return ErrorCode::AmneziaServiceConnectionFailed;
|
|
}
|
|
|
|
m_wireguardStartProcess->setProgram(PermittedProcess::Wireguard);
|
|
|
|
m_wireguardStartProcess->setArguments(startArgs());
|
|
qDebug() << startArgs().join(" ");
|
|
|
|
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
|
|
qDebug() << "WireguardProtocol::WireguardProtocol errorOccurred" << error;
|
|
setConnectionState(Vpn::ConnectionState::Disconnected);
|
|
});
|
|
|
|
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::stateChanged, this,
|
|
[this](QProcess::ProcessState newState) {
|
|
qDebug() << "WireguardProtocol::WireguardProtocol stateChanged" << newState;
|
|
});
|
|
|
|
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::finished, this,
|
|
[this]() { setConnectionState(Vpn::ConnectionState::Connected); });
|
|
|
|
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::readyRead, this, [this]() {
|
|
QRemoteObjectPendingReply<QByteArray> reply = m_wireguardStartProcess->readAll();
|
|
reply.waitForFinished(1000);
|
|
qDebug() << "WireguardProtocol::WireguardProtocol readyRead" << reply.returnValue();
|
|
});
|
|
|
|
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::readyReadStandardOutput, this, [this]() {
|
|
QRemoteObjectPendingReply<QByteArray> reply = m_wireguardStartProcess->readAllStandardOutput();
|
|
reply.waitForFinished(1000);
|
|
qDebug() << "WireguardProtocol::WireguardProtocol readAllStandardOutput" << reply.returnValue();
|
|
});
|
|
|
|
connect(m_wireguardStartProcess.data(), &PrivilegedProcess::readyReadStandardError, this, [this]() {
|
|
QRemoteObjectPendingReply<QByteArray> reply = m_wireguardStartProcess->readAllStandardError();
|
|
reply.waitForFinished(10);
|
|
qDebug() << "WireguardProtocol::WireguardProtocol readAllStandardError" << reply.returnValue();
|
|
});
|
|
|
|
m_wireguardStartProcess->start();
|
|
m_wireguardStartProcess->waitForFinished(10000);
|
|
|
|
return ErrorCode::NoError;
|
|
}
|
|
|
|
void WireguardProtocol::updateVpnGateway(const QString &line)
|
|
{
|
|
}
|
|
|
|
QString WireguardProtocol::serviceName() const
|
|
{
|
|
return "AmneziaVPN.WireGuard0";
|
|
}
|
|
|
|
QStringList WireguardProtocol::stopArgs()
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
return { "--remove", configPath() };
|
|
#elif defined Q_OS_LINUX
|
|
return { "down", "wg99" };
|
|
#else
|
|
return {};
|
|
#endif
|
|
}
|
|
|
|
QStringList WireguardProtocol::startArgs()
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
return { "--add", configPath() };
|
|
#elif defined Q_OS_LINUX
|
|
return { "up", "wg99" };
|
|
#else
|
|
return {};
|
|
#endif
|
|
}
|