Custom routing done

ShadowSocks enabled by default
This commit is contained in:
pokamest 2021-02-18 15:00:41 +03:00
parent f91854594c
commit a1cb4ac544
36 changed files with 482 additions and 780 deletions

View file

@ -9,13 +9,10 @@
#include "openvpnprotocol.h"
#include "utils.h"
OpenVpnProtocol::OpenVpnProtocol(const QString& args, QObject* parent) :
VpnProtocol(args, parent)
//m_requestFromUserToStop(false)
OpenVpnProtocol::OpenVpnProtocol(const QJsonObject &configuration, QObject* parent) :
VpnProtocol(configuration, parent)
{
setConfigFile(args);
//connect(m_communicator, &Communicator::messageReceived, this, &OpenVpnProtocol::onMessageReceived);
readOpenVpnConfiguration(configuration);
connect(&m_managementServer, &ManagementServer::readyRead, this, &OpenVpnProtocol::onReadyReadDataFromManagementServer);
}
@ -25,35 +22,14 @@ OpenVpnProtocol::~OpenVpnProtocol()
OpenVpnProtocol::stop();
}
void OpenVpnProtocol::onMessageReceived(const Message& message)
{
if (!message.isValid()) {
qWarning().noquote() << QString("Message received: '%1', but it is not valid").arg(message.toString());
return;
}
switch (message.state()) {
case Message::State::Started:
qDebug() << "OpenVPN process started";
break;
case Message::State::Finished:
qDebug().noquote() << QString("OpenVPN process finished with status %1").arg(message.argAtIndex(1));
onOpenVpnProcessFinished(message.argAtIndex(1).toInt());
break;
default:
qDebug().noquote() << QString("Message received: '%1'").arg(message.toString());
;
}
}
void OpenVpnProtocol::stop()
{
// TODO: need refactoring
// sendTermSignal() will evet return true while server connected
// sendTermSignal() will even return true while server connected ???
if ((m_connectionState == VpnProtocol::ConnectionState::Preparing) ||
(m_connectionState == VpnProtocol::ConnectionState::Connecting) ||
(m_connectionState == VpnProtocol::ConnectionState::Connected) ||
(m_connectionState == VpnProtocol::ConnectionState::TunnelReconnecting)) {
(m_connectionState == VpnProtocol::ConnectionState::Reconnecting)) {
if (!sendTermSignal()) {
killOpenVpnProcess();
}
@ -61,27 +37,51 @@ void OpenVpnProtocol::stop()
}
}
void OpenVpnProtocol::killOpenVpnProcess()
ErrorCode OpenVpnProtocol::checkAndSetupTapDriver()
{
// send command to kill openvpn process (if any).
if (!IpcClient::Interface()) {
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::OpenVpnUnknownError;
}
return ErrorCode::NoError;
}
bool OpenVpnProtocol::setConfigFile(const QString& configFileNamePath)
void OpenVpnProtocol::killOpenVpnProcess()
{
m_configFileName = configFileNamePath;
QFileInfo file(m_configFileName);
if (file.fileName().isEmpty()) {
m_configFileName = Utils::defaultVpnConfigFileName();
if (m_openVpnProcess){
m_openVpnProcess->close();
}
}
if (m_configFileName.isEmpty()) {
return false;
void OpenVpnProtocol::readOpenVpnConfiguration(const QJsonObject &configuration)
{
if (configuration.contains(config::key_openvpn_config_data())) {
m_configFile.open();
m_configFile.write(configuration.value(config::key_openvpn_config_data()).toString().toUtf8());
m_configFile.close();
m_configFileName = m_configFile.fileName();
qDebug().noquote() << QString("Set config data") << m_configFileName;
}
else if (configuration.contains(config::key_openvpn_config_path())) {
m_configFileName = configuration.value(config::key_openvpn_config_path()).toString();
QFileInfo file(m_configFileName);
qDebug().noquote() << QString("Set config file: '%1'").arg(configPath());
if (file.fileName().isEmpty()) {
m_configFileName = Utils::defaultVpnConfigFileName();
}
return false;
qDebug().noquote() << QString("Set config file: '%1'").arg(configPath());
}
}
bool OpenVpnProtocol::openVpnProcessIsRunning() const
@ -99,7 +99,7 @@ QString OpenVpnProtocol::configPath() const
return m_configFileName;
}
void OpenVpnProtocol::writeCommand(const QString& command)
void OpenVpnProtocol::sendManagementCommand(const QString& command)
{
QIODevice *device = dynamic_cast<QIODevice*>(m_managementServer.socket().data());
if (device) {
@ -128,17 +128,9 @@ QString OpenVpnProtocol::openVpnExecPath() const
ErrorCode OpenVpnProtocol::start()
{
qDebug() << "Start OpenVPN connection";
//m_requestFromUserToStop = false;
m_openVpnStateSigTermHandlerTimer.stop();
//qDebug() << "Start OpenVPN connection";
OpenVpnProtocol::stop();
// if (communicator() && !communicator()->isConnected()) {
// setLastError(ErrorCode::AmneziaServiceConnectionFailed);
// return lastError();
// }
if (!QFileInfo::exists(openVpnExecPath())) {
setLastError(ErrorCode::OpenVpnExecutableMissing);
return lastError();
@ -152,13 +144,6 @@ ErrorCode OpenVpnProtocol::start()
QString vpnLogFileNamePath = Utils::systemLogPath() + "/openvpn.log";
Utils::createEmptyFile(vpnLogFileNamePath);
QStringList args({openVpnExecPath(),
"--config" , configPath(),
"--management", m_managementHost, QString::number(m_managementPort),
"--management-client",
"--log-append", vpnLogFileNamePath
});
if (!m_managementServer.start(m_managementHost, m_managementPort)) {
setLastError(ErrorCode::OpenVpnManagementServerError);
return lastError();
@ -166,16 +151,18 @@ ErrorCode OpenVpnProtocol::start()
setConnectionState(ConnectionState::Connecting);
m_openVpnProcess = IpcClient::createPrivilegedProcess();
m_openVpnProcess = IpcClient::CreatePrivilegedProcess();
if (!m_openVpnProcess) {
qWarning() << "IpcProcess replica is not created!";
//qWarning() << "IpcProcess replica is not created!";
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return ErrorCode::AmneziaServiceConnectionFailed;
}
m_openVpnProcess->waitForSource(1000);
if (!m_openVpnProcess->isInitialized()) {
qWarning() << "IpcProcess replica is not connected!";
setLastError(ErrorCode::AmneziaServiceConnectionFailed);
return ErrorCode::AmneziaServiceConnectionFailed;
}
m_openVpnProcess->setProgram(openVpnExecPath());
@ -195,6 +182,10 @@ ErrorCode OpenVpnProtocol::start()
qDebug() << "IpcProcessInterfaceReplica stateChanged" << newState;
});
connect(m_openVpnProcess.data(), &IpcProcessInterfaceReplica::finished, this, [&]() {
setConnectionState(ConnectionState::Disconnected);
});
m_openVpnProcess->start();
//m_communicator->sendMessage(Message(Message::State::StartRequest, args));
@ -203,20 +194,6 @@ ErrorCode OpenVpnProtocol::start()
return ErrorCode::NoError;
}
void OpenVpnProtocol::openVpnStateSigTermHandlerTimerEvent()
{
bool processStatus = openVpnProcessIsRunning();
if (processStatus) {
killOpenVpnProcess();
}
onOpenVpnProcessFinished(0);
}
void OpenVpnProtocol::openVpnStateSigTermHandler()
{
m_openVpnStateSigTermHandlerTimer.start(5000);
}
bool OpenVpnProtocol::sendTermSignal()
{
return m_managementServer.writeCommand("signal SIGTERM");
@ -256,10 +233,11 @@ void OpenVpnProtocol::onReadyReadDataFromManagementServer()
setConnectionState(VpnProtocol::ConnectionState::Connected);
continue;
} else if (line.contains("EXITING,SIGTER")) {
openVpnStateSigTermHandler();
//openVpnStateSigTermHandler();
setConnectionState(VpnProtocol::ConnectionState::Disconnecting);
continue;
} else if (line.contains("RECONNECTING")) {
setConnectionState(VpnProtocol::ConnectionState::TunnelReconnecting);
setConnectionState(VpnProtocol::ConnectionState::Reconnecting);
continue;
}
}
@ -294,19 +272,6 @@ void OpenVpnProtocol::onReadyReadDataFromManagementServer()
}
}
void OpenVpnProtocol::onOpenVpnProcessFinished(int exitCode)
{
m_openVpnStateSigTermHandlerTimer.stop();
if (m_connectionState == VpnProtocol::ConnectionState::Disconnected) {
qDebug() << "Already in disconnected state";
return;
}
qDebug().noquote() << QString("Process finished with code: %1").arg(exitCode);
setConnectionState(VpnProtocol::ConnectionState::Disconnected);
}
void OpenVpnProtocol::updateVpnGateway()
{
QProcess ipconfig;

View file

@ -6,7 +6,6 @@
#include <QTimer>
#include "managementserver.h"
#include "message.h"
#include "vpnprotocol.h"
#include "core/ipcclient.h"
@ -16,39 +15,35 @@ class OpenVpnProtocol : public VpnProtocol
Q_OBJECT
public:
explicit OpenVpnProtocol(const QString& args = QString(), QObject* parent = nullptr);
explicit OpenVpnProtocol(const QJsonObject& configuration, QObject* parent = nullptr);
virtual ~OpenVpnProtocol() override;
ErrorCode start() override;
void stop() override;
ErrorCode checkAndSetupTapDriver();
protected slots:
void onMessageReceived(const Message& message);
void onOpenVpnProcessFinished(int exitCode);
void onReadyReadDataFromManagementServer();
protected:
private:
QString configPath() const;
QString openVpnExecPath() const;
bool openVpnProcessIsRunning() const;
bool sendTermSignal();
bool setConfigFile(const QString& configFileNamePath);
void readOpenVpnConfiguration(const QJsonObject &configuration);
void disconnectFromManagementServer();
void killOpenVpnProcess();
void openVpnStateSigTermHandler();
void openVpnStateSigTermHandlerTimerEvent();
void sendByteCount();
void sendInitialData();
void writeCommand(const QString& command);
void sendManagementCommand(const QString& command);
const QString m_managementHost = "127.0.0.1";
const unsigned int m_managementPort = 57775;
ManagementServer m_managementServer;
QString m_configFileName;
QTimer m_openVpnStateSigTermHandlerTimer;
//bool m_requestFromUserToStop;
QTemporaryFile m_configFile;
private:
void updateRouteGateway(QString line);

View file

@ -8,31 +8,34 @@
#include <QJsonDocument>
#include <QJsonObject>
ShadowSocksVpnProtocol::ShadowSocksVpnProtocol(const QString &args, QObject *parent):
OpenVpnProtocol(args, parent)
ShadowSocksVpnProtocol::ShadowSocksVpnProtocol(const QJsonObject &configuration, QObject *parent):
OpenVpnProtocol(configuration, parent)
{
m_shadowSocksConfig = args;
readShadowSocksConfiguration(configuration);
}
ErrorCode ShadowSocksVpnProtocol::start()
{
qDebug() << "ShadowSocksVpnProtocol::start()";
QJsonObject config = QJsonDocument::fromJson(m_shadowSocksConfig.toUtf8()).object();
ssProcess.setProcessChannelMode(QProcess::MergedChannels);
m_ssProcess.setProcessChannelMode(QProcess::MergedChannels);
ssProcess.setProgram(shadowSocksExecPath());
ssProcess.setArguments(QStringList() << "-s" << config.value("server").toString()
<< "-p" << QString::number(config.value("server_port").toInt())
<< "-l" << QString::number(config.value("local_port").toInt())
<< "-m" << config.value("method").toString()
<< "-k" << config.value("password").toString()
m_ssProcess.setProgram(shadowSocksExecPath());
m_ssProcess.setArguments(QStringList() << "-s" << m_shadowSocksConfig.value("server").toString()
<< "-p" << QString::number(m_shadowSocksConfig.value("server_port").toInt())
<< "-l" << QString::number(m_shadowSocksConfig.value("local_port").toInt())
<< "-m" << m_shadowSocksConfig.value("method").toString()
<< "-k" << m_shadowSocksConfig.value("password").toString()
);
ssProcess.start();
ssProcess.waitForStarted();
connect(&m_ssProcess, &QProcess::readyRead, this, [this](){
qDebug().noquote() << m_ssProcess.readAll();
});
if (ssProcess.state() == QProcess::ProcessState::Running) {
m_ssProcess.start();
m_ssProcess.waitForStarted();
if (m_ssProcess.state() == QProcess::ProcessState::Running) {
setConnectionState(ConnectionState::Connecting);
return OpenVpnProtocol::start();
@ -42,8 +45,10 @@ ErrorCode ShadowSocksVpnProtocol::start()
void ShadowSocksVpnProtocol::stop()
{
OpenVpnProtocol::stop();
qDebug() << "ShadowSocksVpnProtocol::stop()";
ssProcess.kill();
m_ssProcess.close();
}
QString ShadowSocksVpnProtocol::shadowSocksExecPath() const
@ -55,7 +60,7 @@ QString ShadowSocksVpnProtocol::shadowSocksExecPath() const
#endif
}
QString ShadowSocksVpnProtocol::genShadowSocksConfig(const ServerCredentials &credentials, Protocol proto)
QJsonObject ShadowSocksVpnProtocol::genShadowSocksConfig(const ServerCredentials &credentials, Protocol proto)
{
QJsonObject ssConfig;
ssConfig.insert("server", credentials.hostName);
@ -64,5 +69,10 @@ QString ShadowSocksVpnProtocol::genShadowSocksConfig(const ServerCredentials &cr
ssConfig.insert("password", credentials.password);
ssConfig.insert("timeout", 60);
ssConfig.insert("method", ServerController::ssEncryption());
return QJsonDocument(ssConfig).toJson();
return ssConfig;
}
void ShadowSocksVpnProtocol::readShadowSocksConfiguration(const QJsonObject &configuration)
{
m_shadowSocksConfig = configuration.value(config::key_shadowsocks_config_data()).toObject();
}

View file

@ -7,21 +7,22 @@
class ShadowSocksVpnProtocol : public OpenVpnProtocol
{
public:
ShadowSocksVpnProtocol(const QString& args = QString(), QObject* parent = nullptr);
ShadowSocksVpnProtocol(const QJsonObject& configuration, QObject* parent = nullptr);
ErrorCode start() override;
void stop() override;
static QString genShadowSocksConfig(const ServerCredentials &credentials, Protocol proto = Protocol::ShadowSocks);
static QJsonObject genShadowSocksConfig(const ServerCredentials &credentials, Protocol proto = Protocol::ShadowSocks);
protected:
void readShadowSocksConfiguration(const QJsonObject &configuration);
QString shadowSocksExecPath() const;
protected:
QString m_shadowSocksConfig;
QJsonObject m_shadowSocksConfig;
private:
QProcess ssProcess;
QProcess m_ssProcess;
};
#endif // SHADOWSOCKSVPNPROTOCOL_H

View file

@ -1,42 +1,26 @@
#include <QDebug>
#include <QTimer>
//#include "communicator.h"
#include "vpnprotocol.h"
#include "core/errorstrings.h"
//Communicator* VpnProtocol::m_communicator = nullptr;
VpnProtocol::VpnProtocol(const QString& args, QObject* parent)
VpnProtocol::VpnProtocol(const QJsonObject &configuration, QObject* parent)
: QObject(parent),
m_connectionState(ConnectionState::Unknown),
m_rawConfig(configuration),
m_timeoutTimer(new QTimer(this)),
m_receivedBytes(0),
m_sentBytes(0)
{
m_timeoutTimer->setSingleShot(true);
connect(m_timeoutTimer, &QTimer::timeout, this, &VpnProtocol::onTimeout);
Q_UNUSED(args)
}
//void VpnProtocol::initializeCommunicator(QObject* parent)
//{
// if (!m_communicator) {
// m_communicator = new Communicator(parent);
// }
//}
//Communicator* VpnProtocol::communicator()
//{
// return m_communicator;
//}
void VpnProtocol::setLastError(ErrorCode lastError)
{
m_lastError = lastError;
if (lastError){
setConnectionState(ConnectionState::Disconnected);
setConnectionState(ConnectionState::Error);
}
qCritical().noquote() << "VpnProtocol error, code" << m_lastError << errorString(m_lastError);
}
@ -79,9 +63,14 @@ void VpnProtocol::setBytesChanged(quint64 receivedBytes, quint64 sentBytes)
void VpnProtocol::setConnectionState(VpnProtocol::ConnectionState state)
{
qDebug() << "VpnProtocol::setConnectionState" << textConnectionState(state);
if (m_connectionState == state) {
return;
}
if (m_connectionState == ConnectionState::Disconnected && state == ConnectionState::Disconnecting) {
return;
}
m_connectionState = state;
if (m_connectionState == ConnectionState::Disconnected) {
@ -113,7 +102,7 @@ QString VpnProtocol::textConnectionState(ConnectionState connectionState)
case ConnectionState::Connecting: return tr("Connecting...");
case ConnectionState::Connected: return tr("Connected");
case ConnectionState::Disconnecting: return tr("Disconnecting...");
case ConnectionState::TunnelReconnecting: return tr("Reconnecting...");
case ConnectionState::Reconnecting: return tr("Reconnecting...");
case ConnectionState::Error: return tr("Error");
default:
;
@ -127,12 +116,12 @@ QString VpnProtocol::textConnectionState() const
return textConnectionState(m_connectionState);
}
bool VpnProtocol::onConnected() const
bool VpnProtocol::isConnected() const
{
return m_connectionState == ConnectionState::Connected;
}
bool VpnProtocol::onDisconnected() const
bool VpnProtocol::isDisconnected() const
{
return m_connectionState == ConnectionState::Disconnected;
}

View file

@ -3,30 +3,29 @@
#include <QObject>
#include <QString>
#include <QJsonObject>
#include "core/defs.h"
using namespace amnezia;
class QTimer;
class Communicator;
class VpnProtocol : public QObject
{
Q_OBJECT
public:
explicit VpnProtocol(const QString& args = QString(), QObject* parent = nullptr);
explicit VpnProtocol(const QJsonObject& configuration, QObject* parent = nullptr);
virtual ~VpnProtocol() override = default;
enum class ConnectionState {Unknown, Disconnected, Preparing, Connecting, Connected, Disconnecting, TunnelReconnecting, Error};
enum ConnectionState {Unknown, Disconnected, Preparing, Connecting, Connected, Disconnecting, Reconnecting, Error};
Q_ENUM(ConnectionState)
static Communicator* communicator();
static QString textConnectionState(ConnectionState connectionState);
//static void initializeCommunicator(QObject* parent = nullptr);
virtual bool onConnected() const;
virtual bool onDisconnected() const;
virtual bool isConnected() const;
virtual bool isDisconnected() const;
virtual ErrorCode start() = 0;
virtual void stop() = 0;
@ -54,18 +53,17 @@ protected:
virtual void setBytesChanged(quint64 receivedBytes, quint64 sentBytes);
virtual void setConnectionState(VpnProtocol::ConnectionState state);
//static Communicator* m_communicator;
ConnectionState m_connectionState;
QString m_routeGateway;
QString m_vpnGateway;
QJsonObject m_rawConfig;
private:
QTimer* m_timeoutTimer;
ErrorCode m_lastError;
quint64 m_receivedBytes;
quint64 m_sentBytes;
};
#endif // VPNPROTOCOL_H