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

@ -19,7 +19,6 @@ HEADERS += \
debug.h \
defines.h \
managementserver.h \
message.h \
protocols/shadowsocksvpnprotocol.h \
runguard.h \
settings.h \
@ -37,7 +36,6 @@ SOURCES += \
debug.cpp \
main.cpp \
managementserver.cpp \
message.cpp \
protocols/shadowsocksvpnprotocol.cpp \
runguard.cpp \
settings.cpp \

View file

@ -34,8 +34,9 @@ enum ErrorCode
InternalError,
NotImplementedError,
// Server errorz
// Server errors
ServerCheckFailed,
ServerPortAlreadyAllocatedError,
// Ssh connection errors
SshSocketError, SshTimeoutError, SshProtocolError,
@ -62,6 +63,15 @@ enum ErrorCode
OpenVpnUnknownError
};
namespace config {
// config keys
static QString key_openvpn_config_data() { return "openvpn_config_data"; }
static QString key_openvpn_config_path() { return "openvpn_config_path"; }
static QString key_shadowsocks_config_data() { return "shadowsocks_config_data"; }
}
} // namespace amnezia
#endif // DEFS_H

View file

@ -11,7 +11,10 @@ static QString errorString(ErrorCode code){
case(NoError): return QObject::tr("No error");
case(UnknownError): return QObject::tr("Unknown Error");
case(NotImplementedError): return QObject::tr("Function not implemented");
// Server errors
case(ServerCheckFailed): return QObject::tr("Server check failed");
case(ServerPortAlreadyAllocatedError): return QObject::tr("Server port already used. Check for another software");
// Ssh connection errors
case(SshSocketError): return QObject::tr("Ssh connection error");

View file

@ -7,7 +7,18 @@ IpcClient &IpcClient::Instance()
return s;
}
QSharedPointer<IpcProcessInterfaceReplica> IpcClient::createPrivilegedProcess()
bool IpcClient::init()
{
Instance().m_localSocket->waitForConnected();
if (!Instance().m_ipcClient) {
qDebug() << "IpcClient::init failed";
return false;
}
return Instance().m_ipcClient->isReplicaValid();
}
QSharedPointer<IpcProcessInterfaceReplica> IpcClient::CreatePrivilegedProcess()
{
if (! Instance().m_ipcClient || ! Instance().m_ipcClient->isReplicaValid()) {
qWarning() << "IpcClient::createPrivilegedProcess : IpcClient IpcClient replica is not valid";
@ -18,47 +29,40 @@ QSharedPointer<IpcProcessInterfaceReplica> IpcClient::createPrivilegedProcess()
futureResult.waitForFinished(1000);
int pid = futureResult.returnValue();
QSharedPointer<QRemoteObjectNode> replicaNode(new QRemoteObjectNode);
//Instance().m_processNodes.insert(pid, replica);
auto pd = QSharedPointer<ProcessDescriptor>(new ProcessDescriptor());
Instance().m_processNodes.insert(pid, pd);
QSharedPointer<QLocalSocket> socket(new QLocalSocket(replicaNode.data()));
QSharedPointer<IpcProcessInterfaceReplica> ptr;
pd->localSocket.reset(new QLocalSocket(pd->replicaNode.data()));
connect(socket.data(), &QLocalSocket::connected, replicaNode.data(), [socket, replicaNode, &ptr]() {
replicaNode->addClientSideConnection(socket.data());
connect(pd->localSocket.data(), &QLocalSocket::connected, pd->replicaNode.data(), [pd]() {
pd->replicaNode->addClientSideConnection(pd->localSocket.data());
ptr.reset(replicaNode->acquire<IpcProcessInterfaceReplica>());
pd->ipcProcess.reset(pd->replicaNode->acquire<IpcProcessInterfaceReplica>());
if (!pd->ipcProcess) {
qWarning() << "Acquire IpcProcessInterfaceReplica failed";
}
else {
pd->ipcProcess->waitForSource(1000);
if (!pd->ipcProcess->isReplicaValid()) {
qWarning() << "IpcProcessInterfaceReplica replica is not connected!";
}
ptr->waitForSource(1000);
if (!ptr->isReplicaValid()) {
qWarning() << "IpcProcessInterfaceReplica replica is not connected!";
connect(pd->ipcProcess.data(), &IpcProcessInterfaceReplica::destroyed, pd->ipcProcess.data(), [pd](){
pd->replicaNode->deleteLater();
});
}
});
socket->connectToServer(amnezia::getIpcProcessUrl(pid));
socket->waitForConnected();
auto proccessReplica = QSharedPointer<IpcProcessInterfaceReplica>(ptr);
// replica->connectToNode(QUrl(amnezia::getIpcProcessUrl(pid)));
// auto ptr = QSharedPointer<IpcProcessInterfaceReplica>(replica->acquire<IpcProcessInterfaceReplica>());
connect(proccessReplica.data(), &IpcProcessInterfaceReplica::destroyed, proccessReplica.data(), [replicaNode](){
replicaNode->deleteLater();
});
pd->localSocket->connectToServer(amnezia::getIpcProcessUrl(pid));
pd->localSocket->waitForConnected();
auto proccessReplica = QSharedPointer<IpcProcessInterfaceReplica>(pd->ipcProcess);
return proccessReplica;
}
IpcClient::IpcClient(QObject *parent) : QObject(parent)
{
// m_ClientNode.connectToNode(QUrl(amnezia::getIpcServiceUrl()));
// qDebug() << QUrl(amnezia::getIpcServiceUrl());
m_localSocket.reset(new QLocalSocket(this));
connect(m_localSocket.data(), &QLocalSocket::connected, &m_ClientNode, [this]() {
m_ClientNode.addClientSideConnection(m_localSocket.data());
@ -72,20 +76,4 @@ IpcClient::IpcClient(QObject *parent) : QObject(parent)
});
m_localSocket->connectToServer(amnezia::getIpcServiceUrl());
// connect(m_ipcClient.data(), &IpcInterfaceReplica::stateChanged, [&](QRemoteObjectReplica::State state, QRemoteObjectReplica::State oldState){
//// qDebug() << "state" << state;
//// for (int i = 0; i < 10; ++i) {
//// QRemoteObjectPendingReply<qint64> future = m_ipcClient->createPrivilegedProcess("", QStringList());
//// future.waitForFinished();
//// qDebug() << "QRemoteObjectPendingReply" << QDateTime::currentMSecsSinceEpoch() - future.returnValue();
//// }
// });
}

View file

@ -12,21 +12,31 @@ class IpcClient : public QObject
Q_OBJECT
public:
static IpcClient &Instance();
static bool init() { return Instance().m_ipcClient->isReplicaValid(); }
static QSharedPointer<IpcInterfaceReplica> ipcClient() { return Instance().m_ipcClient; }
static QSharedPointer<IpcProcessInterfaceReplica> createPrivilegedProcess();
static bool init();
static QSharedPointer<IpcInterfaceReplica> Interface() { return Instance().m_ipcClient; }
static QSharedPointer<IpcProcessInterfaceReplica> CreatePrivilegedProcess();
signals:
private:
explicit IpcClient(QObject *parent = nullptr);
QRemoteObjectNode m_ClientNode; // create remote object node
QRemoteObjectNode m_ClientNode;
QSharedPointer<IpcInterfaceReplica> m_ipcClient;
QSharedPointer<QLocalSocket> m_localSocket;
//QMap<int, QSharedPointer<QRemoteObjectNode>> m_processNodes;
struct ProcessDescriptor {
ProcessDescriptor () {
replicaNode = QSharedPointer<QRemoteObjectNode>(new QRemoteObjectNode());
ipcProcess = QSharedPointer<IpcProcessInterfaceReplica>();
localSocket = QSharedPointer<QLocalSocket>();
}
QSharedPointer<IpcProcessInterfaceReplica> ipcProcess;
QSharedPointer<QRemoteObjectNode> replicaNode;
QSharedPointer<QLocalSocket> localSocket;
};
QMap<int, QSharedPointer<ProcessDescriptor>> m_processNodes;
};
#endif // IPCCLIENT_H

View file

@ -195,6 +195,12 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
return connData;
}
Settings &OpenVpnConfigurator::m_settings()
{
static Settings s;
return s;
}
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials,
Protocol proto, ErrorCode *errorCode)
{
@ -217,6 +223,13 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
config.replace("$LOCAL_PROXY_PORT", QString::number(ServerController::ssContainerPort()));
}
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
if (m_settings().customRouting()) {
config.replace("redirect-gateway def1 bypass-dhcp", "");
}
config.replace("$REMOTE_HOST", connData.host);
config.replace("$REMOTE_PORT", "1194");
config.replace("$CA_CERT", connData.caCert);
@ -224,5 +237,6 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
config.replace("$PRIV_KEY", connData.privKey);
config.replace("$TA_KEY", connData.taKey);
//qDebug().noquote() << config;
return config;
}

View file

@ -5,6 +5,7 @@
#include <QProcessEnvironment>
#include "defs.h"
#include "settings.h"
#include "servercontroller.h"
@ -37,6 +38,8 @@ private:
static ConnectionData prepareOpenVpnConfig(const ServerCredentials &credentials,
Protocol proto, ErrorCode *errorCode = nullptr);
static Settings &m_settings();
};
#endif // OPENVPNCONFIGURATOR_H

View file

@ -7,6 +7,7 @@
#include <QTimer>
#include <QJsonObject>
#include <QJsonDocument>
#include <QApplication>
#include "sshconnectionmanager.h"
@ -23,7 +24,9 @@ QString ServerController::getContainerName(DockerContainer container)
}
ErrorCode ServerController::runScript(DockerContainer container,
const SshConnectionParameters &sshParams, QString script)
const SshConnectionParameters &sshParams, QString script,
const std::function<void(const QString &)> &cbReadStdOut,
const std::function<void(const QString &)> &cbReadStdErr)
{
QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false"));
@ -66,18 +69,20 @@ ErrorCode ServerController::runScript(DockerContainer container,
wait.quit();
});
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, [proc](){
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, &wait, [proc, cbReadStdOut](){
QString s = proc->readAllStandardOutput();
if (s != "." && !s.isEmpty()) {
qDebug().noquote() << s;
qDebug().noquote() << "stdout" << s;
}
if (cbReadStdOut) cbReadStdOut(s);
});
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, [proc](){
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, &wait, [proc, cbReadStdErr](){
QString s = proc->readAllStandardError();
if (s != "." && !s.isEmpty()) {
qDebug().noquote() << s;
qDebug().noquote() << "stderr" << s;
}
if (cbReadStdErr) cbReadStdErr(s);
});
proc->start();
@ -272,11 +277,12 @@ ErrorCode ServerController::removeServer(const ServerCredentials &credentials, P
QString scriptFileName;
DockerContainer container;
ErrorCode errorCode;
if (proto == Protocol::Any) {
removeServer(credentials, Protocol::OpenVpn);
removeServer(credentials, Protocol::ShadowSocks);
return ErrorCode::NoError;
ErrorCode e = removeServer(credentials, Protocol::OpenVpn);
if (e) {
return e;
}
return removeServer(credentials, Protocol::ShadowSocks);
}
else if (proto == Protocol::OpenVpn) {
scriptFileName = ":/server_scripts/remove_container.sh";
@ -309,14 +315,14 @@ ErrorCode ServerController::setupServer(const ServerCredentials &credentials, Pr
return setupShadowSocksServer(credentials);
}
else if (proto == Protocol::Any) {
return ErrorCode::NotImplementedError;
//return ErrorCode::NotImplementedError;
// TODO: run concurently
// return setupOpenVpnServer(credentials);
//setupShadowSocksServer(credentials);
setupOpenVpnServer(credentials);
setupShadowSocksServer(credentials);
}
return ErrorCode::NotImplementedError;
return ErrorCode::NoError;
}
ErrorCode ServerController::setupOpenVpnServer(const ServerCredentials &credentials)
@ -329,8 +335,20 @@ ErrorCode ServerController::setupOpenVpnServer(const ServerCredentials &credenti
scriptData = file.readAll();
if (scriptData.isEmpty()) return ErrorCode::InternalError;
ErrorCode e = runScript(DockerContainer::OpenVpn, sshParams(credentials), scriptData);
QString stdOut;
auto cbReadStdOut = [&](const QString &data) {
stdOut += data + "\n";
};
auto cbReadStdErr = [&](const QString &data) {
stdOut += data + "\n";
};
ErrorCode e = runScript(DockerContainer::OpenVpn, sshParams(credentials), scriptData, cbReadStdOut, cbReadStdErr);
if (e) return e;
QApplication::processEvents();
if (stdOut.contains("port is already allocated")) return ErrorCode::ServerPortAlreadyAllocatedError;
if (stdOut.contains("Error response from daemon")) return ErrorCode::ServerCheckFailed;
return checkOpenVpnServer(DockerContainer::OpenVpn, credentials);
}

View file

@ -48,7 +48,9 @@ public:
private:
static QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams);
static ErrorCode runScript(DockerContainer container,
const QSsh::SshConnectionParameters &sshParams, QString script);
const QSsh::SshConnectionParameters &sshParams, QString script,
const std::function<void(const QString &)> &cbReadStdOut = nullptr,
const std::function<void(const QString &)> &cbReadStdErr = nullptr);
static ErrorCode setupOpenVpnServer(const ServerCredentials &credentials);
static ErrorCode setupShadowSocksServer(const ServerCredentials &credentials);

View file

@ -54,8 +54,7 @@ void ManagementServer::onNewConnection()
void ManagementServer::onSocketError(QAbstractSocket::SocketError socketError)
{
Q_UNUSED(socketError);
Q_UNUSED(socketError)
qDebug().noquote() << QString("Mananement server error: %1").arg(m_socket->errorString());
}

View file

@ -1,106 +0,0 @@
#include "message.h"
Message::Message(State state, const QStringList& args) :
m_valid(true),
m_state(state),
m_args(args)
{
}
bool Message::isValid() const
{
return m_valid;
}
QString Message::textState() const
{
switch (m_state) {
case State::Unknown: return "Unknown";
case State::Initialize: return "Initialize";
case State::StartRequest: return "StartRequest";
case State::Started: return "Started";
case State::FinishRequest: return "FinishRequest";
case State::Finished: return "Finished";
case State::RoutesAddRequest: return "RoutesAddRequest";
case State::RouteDeleteRequest: return "RouteDeleteRequest";
case State::ClearSavedRoutesRequest: return "ClearSavedRoutesRequest";
case State::FlushDnsRequest: return "FlushDnsRequest";
case State::InstallDriverRequest: return "InstallDriverRequest";
default:
;
}
return QString();
}
QString Message::rawData() const
{
return m_rawData;
}
Message::State Message::state() const
{
return m_state;
}
QString Message::toString() const
{
if (!isValid()) {
return QString();
}
return QString("%1%2%3")
.arg(textState())
.arg(m_dataSeparator)
.arg(argsToString());
}
QString Message::argAtIndex(int index) const
{
if ((index + 1) > args().size()) {
return QString();
}
return args().at(index);
}
QStringList Message::args() const
{
return m_args;
}
QString Message::argsToString() const
{
return m_args.join(m_argSeparator);
}
Message::Message(const QString& data)
{
m_rawData = data;
m_valid = false;
if (data.isEmpty()) {
return;
}
QStringList dataList = data.split(m_dataSeparator);
if ((dataList.size() != 2)) {
return;
}
bool stateFound = false;
for (int i = static_cast<int>(State::Unknown); i <= static_cast<int>(State::InstallDriverRequest); i++ ) {
m_state = static_cast<State>(i);
if (textState() == dataList.at(0)) {
stateFound = true;
break;
}
}
if (!stateFound) {
return;
}
m_args = dataList.at(1).split(m_argSeparator);
m_valid = true;
}

View file

@ -1,34 +0,0 @@
#ifndef MESSAGE_H
#define MESSAGE_H
#include <QStringList>
class Message {
public:
enum class State {Unknown, Initialize, StartRequest, Started, FinishRequest, Finished,
RoutesAddRequest, RouteDeleteRequest, ClearSavedRoutesRequest, FlushDnsRequest, InstallDriverRequest};
Message(State state, const QStringList& args);
Message(const QString& data);
QString argAtIndex(int index) const;
QString argsToString() const;
QString toString() const;
QStringList args() const;
State state() const;
bool isValid() const;
QString rawData() const;
protected:
QString textState() const;
const QString m_argSeparator = ",";
const QString m_dataSeparator = "|";
bool m_valid;
State m_state;
QStringList m_args;
QString m_rawData;
};
#endif // MESSAGE_H

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

View file

@ -12,6 +12,11 @@ tls-client
tls-version-min 1.2
key-direction 1
remote-cert-tls server
redirect-gateway def1 bypass-dhcp
dhcp-option DNS $PRIMARY_DNS
dhcp-option DNS $SECONDARY_DNS
block-outside-dns
remote $REMOTE_HOST $REMOTE_PORT

View file

@ -12,6 +12,11 @@ tls-client
tls-version-min 1.2
key-direction 1
remote-cert-tls server
redirect-gateway def1 bypass-dhcp
dhcp-option DNS $PRIMARY_DNS
dhcp-option DNS $SECONDARY_DNS
block-outside-dns
socks-proxy 127.0.0.1 $LOCAL_PROXY_PORT
route $REMOTE_HOST 255.255.255.255 net_gateway

View file

@ -6,27 +6,6 @@ Settings::Settings(QObject* parent) :
QObject(parent),
m_settings (ORGANIZATION_NAME, APPLICATION_NAME, this)
{
read();
}
void Settings::read()
{
m_settings.beginGroup("Server");
m_userName = m_settings.value("userName", QString()).toString();
m_password = m_settings.value("password", QString()).toString();
m_serverName = m_settings.value("serverName", QString()).toString();
m_serverPort = m_settings.value("serverPort", 22).toInt();
m_settings.endGroup();
}
void Settings::save()
{
m_settings.beginGroup("Server");
m_settings.setValue("userName", m_userName);
m_settings.setValue("password", m_password);
m_settings.setValue("serverName", m_serverName);
m_settings.setValue("serverPort", m_serverPort);
m_settings.endGroup();
}
bool Settings::haveAuthData() const
@ -34,26 +13,6 @@ bool Settings::haveAuthData() const
return (!serverName().isEmpty() && !userName().isEmpty() && !password().isEmpty());
}
void Settings::setUserName(const QString& login)
{
m_userName = login;
}
void Settings::setPassword(const QString& password)
{
m_password = password;
}
void Settings::setServerName(const QString& serverName)
{
m_serverName = serverName;
}
void Settings::setServerPort(int serverPort)
{
m_serverPort = serverPort;
}
void Settings::setServerCredentials(const ServerCredentials &credentials)
{
setServerName(credentials.hostName);

View file

@ -18,40 +18,50 @@ class Settings : public QObject
public:
explicit Settings(QObject* parent = nullptr);
void read();
void save();
QString userName() const { return m_settings.value("Server/userName", QString()).toString(); }
void setUserName(const QString& login) { m_settings.setValue("Server/userName", login); }
void setUserName(const QString& login);
void setPassword(const QString& password);
void setServerName(const QString& serverName);
void setServerPort(int serverPort = 22);
void setServerCredentials(const ServerCredentials &credentials);
QString password() const { return m_settings.value("Server/password", QString()).toString(); }
void setPassword(const QString& password) { m_settings.setValue("Server/password", password); }
QString serverName() const { return m_settings.value("Server/serverName", QString()).toString(); }
void setServerName(const QString& serverName) { m_settings.setValue("Server/serverName", serverName); }
int serverPort() const { return m_settings.value("Server/serverPort", 22).toInt(); }
void setServerPort(int serverPort = 22) { m_settings.setValue("Server/serverPort", serverPort); }
QString userName() const { return m_userName; }
QString password() const { return m_password; }
QString serverName() const { return m_serverName; }
int serverPort() const { return m_serverPort; }
ServerCredentials serverCredentials();
void setServerCredentials(const ServerCredentials &credentials);
bool haveAuthData() const;
bool customRouting() const { return m_settings.value("Conf/customRouting", false).toBool(); }
void setCustomRouting(bool customRouting) { m_settings.setValue("Conf/customRouting", customRouting); }
// list of sites to pass blocking added by user
QStringList customSites() { return m_settings.value("customSites").toStringList(); }
void setCustomSites(const QStringList &customSites) { m_settings.setValue("customSites", customSites); }
QStringList customSites() { return m_settings.value("Conf/customSites").toStringList(); }
void setCustomSites(const QStringList &customSites) { m_settings.setValue("Conf/customSites", customSites); }
// list of ips to pass blocking generated from customSites
QStringList customIps() { return m_settings.value("customIps").toStringList(); }
void setCustomIps(const QStringList &customIps) { m_settings.setValue("customIps", customIps); }
QStringList customIps() { return m_settings.value("Conf/customIps").toStringList(); }
void setCustomIps(const QStringList &customIps) { m_settings.setValue("Conf/customIps", customIps); }
QString primaryDns() const { return m_settings.value("Conf/primaryDns", cloudFlareNs1()).toString(); }
QString secondaryDns() const { return m_settings.value("Conf/secondaryDns", cloudFlareNs2()).toString(); }
protected:
//QString primaryDns() const { return m_primaryDns; }
void setPrimaryDns(const QString &primaryDns) { m_settings.setValue("Conf/primaryDns", primaryDns); }
//QString secondaryDns() const { return m_secondaryDns; }
void setSecondaryDns(const QString &secondaryDns) { m_settings.setValue("Conf/secondaryDns", secondaryDns); }
QString cloudFlareNs1() const { return "1.1.1.1"; }
QString cloudFlareNs2() const { return "1.0.0.1"; }
QString openNicNs5() const { return "94.103.153.176"; }
QString openNicNs13() const { return "144.76.103.143"; }
private:
QSettings m_settings;
QString m_userName;
QString m_password;
QString m_serverName;
int m_serverPort;
};
#endif // SETTINGS_H

View file

@ -71,9 +71,9 @@ MainWindow::MainWindow(QWidget *parent) :
ui->pushButton_sites_add_custom->click();
});
initCustomSites();
updateSettings();
ui->pushButton_general_settings_exit->hide();
//ui->pushButton_general_settings_exit->hide();
//ui->pushButton_share_connection->hide();
setFixedSize(width(),height());
@ -101,7 +101,7 @@ MainWindow::~MainWindow()
for (int i = 0; i < 50; i++) {
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
QThread::msleep(100);
if (m_vpnConnection->onDisconnected()) {
if (m_vpnConnection->isDisconnected()) {
break;
}
}
@ -249,7 +249,6 @@ void MainWindow::onPushButtonNewServerConnectWithNewData(bool)
if (ok) {
m_settings.setServerCredentials(serverCredentials);
m_settings.save();
goToPage(Page::Vpn);
qApp->processEvents();
@ -272,7 +271,6 @@ void MainWindow::onPushButtonNewServerConnectWithExistingCode(bool)
credentials.password = o.value("w").toString();
m_settings.setServerCredentials(credentials);
m_settings.save();
goToPage(Page::Vpn);
qDebug() << QString("Added server %3@%1:%2").
@ -299,7 +297,7 @@ bool MainWindow::installServer(ServerCredentials credentials,
timer.start(1000);
ErrorCode e = ServerController::setupServer(credentials, Protocol::OpenVpn);
ErrorCode e = ServerController::setupServer(credentials, Protocol::Any);
if (e) {
page->setEnabled(true);
button->setVisible(true);
@ -377,14 +375,11 @@ void MainWindow::onPushButtonForgetServer(bool)
m_settings.setServerName("");
m_settings.setServerPort();
m_settings.save();
goToPage(Page::Start);
}
void MainWindow::onBytesChanged(quint64 receivedData, quint64 sentData)
{
qDebug() << "MainWindow::onBytesChanged" << receivedData << sentData;
ui->label_speed_received->setText(VpnConnection::bytesPerSecToText(receivedData));
ui->label_speed_sent->setText(VpnConnection::bytesPerSecToText(sentData));
}
@ -394,6 +389,7 @@ void MainWindow::onConnectionStateChanged(VpnProtocol::ConnectionState state)
qDebug() << "MainWindow::onConnectionStateChanged" << VpnProtocol::textConnectionState(state);
bool pushButtonConnectEnabled = false;
bool radioButtonsModeEnabled = false;
ui->label_state->setText(VpnProtocol::textConnectionState(state));
setTrayState(state);
@ -403,32 +399,41 @@ void MainWindow::onConnectionStateChanged(VpnProtocol::ConnectionState state)
onBytesChanged(0,0);
ui->pushButton_connect->setChecked(false);
pushButtonConnectEnabled = true;
radioButtonsModeEnabled = true;
break;
case VpnProtocol::ConnectionState::Preparing:
pushButtonConnectEnabled = false;
radioButtonsModeEnabled = false;
break;
case VpnProtocol::ConnectionState::Connecting:
pushButtonConnectEnabled = false;
radioButtonsModeEnabled = false;
break;
case VpnProtocol::ConnectionState::Connected:
pushButtonConnectEnabled = true;
radioButtonsModeEnabled = false;
break;
case VpnProtocol::ConnectionState::Disconnecting:
pushButtonConnectEnabled = false;
radioButtonsModeEnabled = false;
break;
case VpnProtocol::ConnectionState::TunnelReconnecting:
case VpnProtocol::ConnectionState::Reconnecting:
pushButtonConnectEnabled = true;
radioButtonsModeEnabled = false;
break;
case VpnProtocol::ConnectionState::Error:
ui->pushButton_connect->setChecked(false);
pushButtonConnectEnabled = true;
radioButtonsModeEnabled = true;
break;
case VpnProtocol::ConnectionState::Unknown:
default:
pushButtonConnectEnabled = true;
;
radioButtonsModeEnabled = true;
}
ui->pushButton_connect->setEnabled(pushButtonConnectEnabled);
ui->radioButton_mode_all_sites->setEnabled(radioButtonsModeEnabled);
ui->radioButton_mode_selected_sites->setEnabled(radioButtonsModeEnabled);
}
void MainWindow::onVpnProtocolError(ErrorCode errorCode)
@ -519,7 +524,7 @@ void MainWindow::setupUiConnections()
connect(ui->pushButton_server_settings_clear, SIGNAL(clicked(bool)), this, SLOT(onPushButtonClearServer(bool)));
connect(ui->pushButton_server_settings_forget, SIGNAL(clicked(bool)), this, SLOT(onPushButtonForgetServer(bool)));
connect(ui->pushButton_blocked_list, &QPushButton::clicked, this, [this](){ goToPage(Page::Sites); });
connect(ui->pushButton_vpn_add_site, &QPushButton::clicked, this, [this](){ goToPage(Page::Sites); });
connect(ui->pushButton_settings, &QPushButton::clicked, this, [this](){ goToPage(Page::GeneralSettings); });
connect(ui->pushButton_server_settings, &QPushButton::clicked, this, [this](){ goToPage(Page::ServerSettings); });
connect(ui->pushButton_share_connection, &QPushButton::clicked, this, [this](){
@ -545,6 +550,12 @@ void MainWindow::setupUiConnections()
connect(ui->pushButton_sites_add_custom, &QPushButton::clicked, this, [this](){ onPushButtonAddCustomSitesClicked(); });
connect(ui->pushButton_sites_delete_custom, &QPushButton::clicked, this, [this](){ onPushButtonDeleteCustomSiteClicked(); });
connect(ui->radioButton_mode_selected_sites, &QRadioButton::toggled, ui->pushButton_vpn_add_site, &QPushButton::setEnabled);
connect(ui->radioButton_mode_selected_sites, &QRadioButton::toggled, this, [this](bool toggled) {
m_settings.setCustomRouting(toggled);
});
}
void MainWindow::setTrayState(VpnProtocol::ConnectionState state)
@ -570,7 +581,7 @@ void MainWindow::setTrayState(VpnProtocol::ConnectionState state)
case VpnProtocol::ConnectionState::Disconnecting:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
break;
case VpnProtocol::ConnectionState::TunnelReconnecting:
case VpnProtocol::ConnectionState::Reconnecting:
setTrayIcon(QString(resourcesPath).arg(DisconnectedTrayIconName));
break;
case VpnProtocol::ConnectionState::Error:
@ -663,13 +674,13 @@ void MainWindow::onPushButtonAddCustomSitesClicked()
customIps.append(newIp);
m_settings.setCustomIps(customIps);
// add to routes immediatelly
// if (vpnStatus() == VPNStatusConnected) {
// //Router::Instance().routeAdd(newIp, vpnGate());
// }
if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) {
IpcClient::Interface()->routeAddList(m_vpnConnection->vpnProtocol()->vpnGateway(),
QStringList() << newIp);
}
}
initCustomSites();
updateSettings();
ui->lineEdit_sites_add_custom->clear();
}
@ -700,15 +711,19 @@ void MainWindow::onPushButtonDeleteCustomSiteClicked()
m_settings.setCustomIps(customIps);
initCustomSites();
updateSettings();
//Router::Instance().routeDelete(Utils::getIPAddress(ipToDelete));
//Router::Instance().flushDns();
if (m_vpnConnection->connectionState() == VpnProtocol::ConnectionState::Connected) {
IpcClient::Interface()->routeDelete(ipToDelete);
IpcClient::Interface()->flushDns();
}
}
void MainWindow::initCustomSites()
void MainWindow::updateSettings()
{
customSitesModel->setStringList(m_settings.customSites());
ui->radioButton_mode_selected_sites->setChecked(m_settings.customRouting());
ui->pushButton_vpn_add_site->setEnabled(m_settings.customRouting());
}
void MainWindow::updateShareCode()
@ -721,4 +736,6 @@ void MainWindow::updateShareCode()
QByteArray ba = QJsonDocument(o).toJson().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
ui->textEdit_sharing_code->setText(QString("vpn://%1").arg(QString(ba)));
//qDebug() << "Share code" << QJsonDocument(o).toJson();
}

View file

@ -74,7 +74,7 @@ private:
void setTrayIcon(const QString &iconPath);
void setupUiConnections();
void initCustomSites();
void updateSettings();
void updateShareCode();

View file

@ -259,7 +259,7 @@ QPushButton:hover {
<string notr="true"/>
</property>
<property name="currentIndex">
<number>0</number>
<number>2</number>
</property>
<widget class="QWidget" name="page_start">
<widget class="QLabel" name="label_23">
@ -315,32 +315,6 @@ color: #333333;</string>
<string>Connection code</string>
</property>
</widget>
<widget class="QProgressBar" name="progressBar_new_server_connection_3">
<property name="geometry">
<rect>
<x>40</x>
<y>220</y>
<width>301</width>
<height>41</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background: #181922;
border-radius: 4px;</string>
</property>
<property name="value">
<number>24</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="textVisible">
<bool>true</bool>
</property>
<property name="format">
<string>Connecting...</string>
</property>
</widget>
<widget class="QLabel" name="label_25">
<property name="geometry">
<rect>
@ -944,7 +918,10 @@ font: 16px &quot;Lato&quot;; </string>
</property>
</widget>
</widget>
<widget class="QPushButton" name="pushButton_blocked_list">
<widget class="QPushButton" name="pushButton_vpn_add_site">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>20</x>
@ -972,7 +949,10 @@ font-size: 16px;
line-height: 21px;
}
</string>
QPushButton:!enabled {
background: #484952;
}</string>
</property>
<property name="text">
<string>+ Add site</string>
@ -1099,7 +1079,7 @@ color: #181922;
</widget>
<widget class="QRadioButton" name="radioButton_mode_all_sites">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="geometry">
<rect>
@ -1116,9 +1096,9 @@ color: #181922;
<bool>true</bool>
</property>
</widget>
<widget class="QRadioButton" name="radioButton_mode_include_selected_sites">
<widget class="QRadioButton" name="radioButton_mode_selected_sites">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="geometry">
<rect>
@ -1157,23 +1137,6 @@ color: #181922;
<bool>true</bool>
</property>
</widget>
<widget class="QLabel" name="label_19">
<property name="geometry">
<rect>
<x>10</x>
<y>460</y>
<width>361</width>
<height>141</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/images/AmneziaVPN.png);
background-color: rgb(255, 255, 255);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</widget>
<widget class="QWidget" name="page_sites">
<property name="styleSheet">

View file

@ -1,26 +1,31 @@
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QJsonObject>
#include <core/openvpnconfigurator.h>
#include <core/servercontroller.h>
#include "ipc.h"
#include "core/ipcclient.h"
#include "protocols/openvpnprotocol.h"
#include "protocols/shadowsocksvpnprotocol.h"
#include "utils.h"
#include "vpnconnection.h"
//#include "communicator.h"
VpnConnection::VpnConnection(QObject* parent) : QObject(parent)
{
QTimer::singleShot(0, [](){
QTimer::singleShot(0, this, [this](){
if (!IpcClient::init()) {
qWarning() << "Error occured when init IPC client";
emit serviceIsNotReady();
}
});
}
//VpnProtocol::initializeCommunicator(parent);
VpnConnection::~VpnConnection()
{
m_vpnProtocol.clear();
}
void VpnConnection::onBytesChanged(quint64 receivedBytes, quint64 sentBytes)
@ -30,28 +35,37 @@ void VpnConnection::onBytesChanged(quint64 receivedBytes, quint64 sentBytes)
void VpnConnection::onConnectionStateChanged(VpnProtocol::ConnectionState state)
{
// if (state == VpnProtocol::ConnectionState::Connected){
// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::FlushDnsRequest, QStringList()));
if (IpcClient::Interface()) {
if (state == VpnProtocol::ConnectionState::Connected && IpcClient::Interface()){
IpcClient::Interface()->flushDns();
// // add routes
// const QStringList &black_custom = m_settings.customIps();
// qDebug() << "onConnect :: adding custom black routes, count:" << black_custom.size();
if (m_settings.customRouting()) {
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(),
QStringList() << m_settings.primaryDns() << m_settings.secondaryDns());
const QStringList &black_custom = m_settings.customIps();
qDebug() << "onConnect :: adding custom black routes, count:" << black_custom.size();
// QStringList args;
// args << m_vpnProtocol->vpnGateway();
// args << black_custom;
IpcClient::Interface()->routeAddList(m_vpnProtocol->vpnGateway(), black_custom);
}
}
else if (state == VpnProtocol::ConnectionState::Error || state == VpnProtocol::ConnectionState::Disconnected) {
IpcClient::Interface()->flushDns();
if (m_settings.customRouting()) {
IpcClient::Interface()->clearSavedRoutes();
}
}
}
// Message m(Message::State::RoutesAddRequest, args);
// m_vpnProtocol->communicator()->sendMessage(m);
// }
// else if (state == VpnProtocol::ConnectionState::Error) {
// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::ClearSavedRoutesRequest, QStringList()));
// m_vpnProtocol->communicator()->sendMessage(Message(Message::State::FlushDnsRequest, QStringList()));
// }
emit connectionStateChanged(state);
}
QSharedPointer<VpnProtocol> VpnConnection::vpnProtocol() const
{
return m_vpnProtocol;
}
ErrorCode VpnConnection::lastError() const
{
if (!m_vpnProtocol.data()) {
@ -61,11 +75,12 @@ ErrorCode VpnConnection::lastError() const
return m_vpnProtocol.data()->lastError();
}
ErrorCode VpnConnection::requestVpnConfig(const ServerCredentials &credentials, Protocol protocol)
ErrorCode VpnConnection::createVpnConfiguration(const ServerCredentials &credentials, Protocol protocol)
{
ErrorCode errorCode = ErrorCode::NoError;
if (protocol == Protocol::OpenVpn || protocol == Protocol::ShadowSocks) {
QString configData = OpenVpnConfigurator::genOpenVpnConfig(credentials, protocol, &errorCode);
QString openVpnConfigData = OpenVpnConfigurator::genOpenVpnConfig(credentials, protocol, &errorCode);
m_vpnConfiguration.insert(config::key_openvpn_config_data(), openVpnConfigData);
if (errorCode) {
return errorCode;
}
@ -73,57 +88,64 @@ ErrorCode VpnConnection::requestVpnConfig(const ServerCredentials &credentials,
QFile file(Utils::defaultVpnConfigFileName());
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)){
QTextStream stream(&file);
stream << configData << endl;
return ErrorCode::NoError;
stream << openVpnConfigData << endl;
}
else {
return ErrorCode::FailedToSaveConfigData;
}
return ErrorCode::FailedToSaveConfigData;
}
else {
return ErrorCode::NotImplementedError;
}
return ErrorCode::NotImplementedError;
if (protocol == Protocol::ShadowSocks) {
QJsonObject ssConfigData = ShadowSocksVpnProtocol::genShadowSocksConfig(credentials);
m_vpnConfiguration.insert(config::key_shadowsocks_config_data(), ssConfigData);
}
return ErrorCode::NoError;
}
ErrorCode VpnConnection::connectToVpn(const ServerCredentials &credentials, Protocol protocol)
{
// protocol = Protocol::ShadowSocks;
qDebug() << "connectToVpn, CustomRouting is" << m_settings.customRouting();
//protocol = Protocol::ShadowSocks;
// TODO: Try protocols one by one in case of Protocol::Any
// TODO: Implement some behavior in case if connection not stable
qDebug() << "Connect to VPN";
emit connectionStateChanged(VpnProtocol::ConnectionState::Connecting);
if (m_vpnProtocol) {
disconnect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
m_vpnProtocol->stop();
m_vpnProtocol->deleteLater();
}
qApp->processEvents();
if (protocol == Protocol::Any || protocol == Protocol::OpenVpn) {
ErrorCode e = requestVpnConfig(credentials, Protocol::OpenVpn);
ErrorCode e = createVpnConfiguration(credentials, Protocol::OpenVpn);
if (e) {
emit connectionStateChanged(VpnProtocol::ConnectionState::Error);
return e;
}
if (m_vpnProtocol) {
disconnect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
m_vpnProtocol.reset(new OpenVpnProtocol(m_vpnConfiguration));
e = static_cast<OpenVpnProtocol *>(m_vpnProtocol.data())->checkAndSetupTapDriver();
if (e) {
emit connectionStateChanged(VpnProtocol::ConnectionState::Error);
return e;
}
m_vpnProtocol.reset(new OpenVpnProtocol());
connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
}
else if (protocol == Protocol::ShadowSocks) {
ErrorCode e = requestVpnConfig(credentials, Protocol::ShadowSocks);
ErrorCode e = createVpnConfiguration(credentials, Protocol::ShadowSocks);
if (e) {
emit connectionStateChanged(VpnProtocol::ConnectionState::Error);
return e;
}
if (m_vpnProtocol) {
disconnect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
}
m_vpnProtocol.reset(new ShadowSocksVpnProtocol(ShadowSocksVpnProtocol::genShadowSocksConfig(credentials)));
connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
m_vpnProtocol.reset(new ShadowSocksVpnProtocol(m_vpnConfiguration));
}
connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(VpnProtocol::ConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::ConnectionState)));
connect(m_vpnProtocol.data(), SIGNAL(bytesChanged(quint64, quint64)), this, SLOT(onBytesChanged(quint64, quint64)));
@ -155,20 +177,20 @@ VpnProtocol::ConnectionState VpnConnection::connectionState()
return m_vpnProtocol->connectionState();
}
bool VpnConnection::onConnected() const
bool VpnConnection::isConnected() const
{
if (!m_vpnProtocol.data()) {
return false;
}
return m_vpnProtocol.data()->onConnected();
return m_vpnProtocol.data()->isConnected();
}
bool VpnConnection::onDisconnected() const
bool VpnConnection::isDisconnected() const
{
if (!m_vpnProtocol.data()) {
return true;
}
return m_vpnProtocol.data()->onDisconnected();
return m_vpnProtocol.data()->isDisconnected();
}

View file

@ -19,34 +19,40 @@ class VpnConnection : public QObject
public:
explicit VpnConnection(QObject* parent = nullptr);
~VpnConnection() override = default;
~VpnConnection() override;
static QString bytesPerSecToText(quint64 bytes);
ErrorCode lastError() const;
ErrorCode requestVpnConfig(const ServerCredentials &credentials, Protocol protocol);
ErrorCode createVpnConfiguration(const ServerCredentials &credentials, Protocol protocol);
ErrorCode connectToVpn(const ServerCredentials &credentials, Protocol protocol = Protocol::Any);
bool onConnected() const;
bool onDisconnected() const;
void disconnectFromVpn();
bool isConnected() const;
bool isDisconnected() const;
VpnProtocol::ConnectionState connectionState();
QSharedPointer<VpnProtocol> vpnProtocol() const;
signals:
void bytesChanged(quint64 receivedBytes, quint64 sentBytes);
void connectionStateChanged(VpnProtocol::ConnectionState state);
void vpnProtocolError(amnezia::ErrorCode error);
void serviceIsNotReady();
protected slots:
void onBytesChanged(quint64 receivedBytes, quint64 sentBytes);
void onConnectionStateChanged(VpnProtocol::ConnectionState state);
protected:
QScopedPointer<VpnProtocol> m_vpnProtocol;
QSharedPointer<VpnProtocol> m_vpnProtocol;
private:
Settings m_settings;
QJsonObject m_vpnConfiguration;
};