Multiprotocol support

This commit is contained in:
pokamest 2021-05-07 23:28:37 +03:00
parent d424bb24cf
commit de67f244da
44 changed files with 2159 additions and 863 deletions

View file

@ -14,6 +14,7 @@ include("3rd/QRCodeGenerator/QRCodeGenerator.pri")
HEADERS += \
../ipc/ipc.h \
configurators/cloak_configurator.h \
configurators/shadowsocks_configurator.h \
core/defs.h \
core/errorstrings.h \
core/ipcclient.h \
@ -39,6 +40,7 @@ HEADERS += \
SOURCES += \
configurators/cloak_configurator.cpp \
configurators/shadowsocks_configurator.cpp \
core/ipcclient.cpp \
configurators/openvpn_configurator.cpp \
core/scripts_registry.cpp \

View file

@ -6,8 +6,8 @@
#include "protocols/protocols_defs.h"
QJsonObject CloakConfigurator::genCloakConfig(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode)
QString CloakConfigurator::genCloakConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
{
ErrorCode e = ErrorCode::NoError;
@ -21,7 +21,7 @@ QJsonObject CloakConfigurator::genCloakConfig(const ServerCredentials &credentia
if (e) {
if (errorCode) *errorCode = e;
return QJsonObject();
return "";
}
QJsonObject config;
@ -30,14 +30,18 @@ QJsonObject CloakConfigurator::genCloakConfig(const ServerCredentials &credentia
config.insert("EncryptionMethod", "aes-gcm");
config.insert("UID", cloakBypassUid);
config.insert("PublicKey", cloakPublicKey);
config.insert("ServerName", amnezia::protocols::cloak::ckDefaultRedirSite);
config.insert("ServerName", "$FAKE_WEB_SITE_ADDRESS");
config.insert("NumConn", 4);
config.insert("BrowserSig", "chrome");
config.insert("StreamTimeout", 300);
// Amnezia field
config.insert("Remote", credentials.hostName);
// transfer params to protocol runner
config.insert(config_key::transport_proto, "$OPENVPN_TRANSPORT_PROTO");
config.insert(config_key::remote, credentials.hostName);
qDebug().noquote() << QJsonDocument(config).toJson();
return config;
QString textCfg = ServerController::replaceVars(QJsonDocument(config).toJson(),
ServerController::genVarsForScript(credentials, container, containerConfig));
// qDebug().noquote() << textCfg;
return textCfg;
}

View file

@ -11,8 +11,8 @@ class CloakConfigurator
{
public:
static QJsonObject genCloakConfig(const ServerCredentials &credentials, DockerContainer container,
ErrorCode *errorCode = nullptr);
static QString genCloakConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
};
#endif // CLOAK_CONFIGURATOR_H

View file

@ -192,35 +192,16 @@ Settings &OpenVpnConfigurator::m_settings()
}
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials,
DockerContainer container, ErrorCode *errorCode)
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
{
// QFile configTemplFile;
// if (proto == Protocol::OpenVpn)
// configTemplFile.setFileName(":/server_scripts/template_openvpn.ovpn");
// else if (proto == Protocol::ShadowSocks) {
// configTemplFile.setFileName(":/server_scripts/template_shadowsocks.ovpn");
// }
// configTemplFile.open(QIODevice::ReadOnly);
// QString config = configTemplFile.readAll();
QString config = amnezia::scriptData(ProtocolScriptType::openvpn_template, container);
QString config = ServerController::replaceVars(amnezia::scriptData(ProtocolScriptType::openvpn_template, container),
ServerController::genVarsForScript(credentials, container, containerConfig));
ConnectionData connData = prepareOpenVpnConfig(credentials, container, errorCode);
if (errorCode && *errorCode) {
return "";
}
if (container == DockerContainer::OpenVpn)
config.replace("$PROTO", "udp");
else if (container == DockerContainer::ShadowSocksOverOpenVpn) {
config.replace("$PROTO", "tcp");
config.replace("$LOCAL_PROXY_PORT", amnezia::protocols::shadowsocks::ssLocalProxyPort);
}
else if (container == DockerContainer::OpenVpnOverCloak) {
config.replace("$PROTO", "tcp");
}
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
config.replace("$SECONDARY_DNS", m_settings().secondaryDns());
@ -229,11 +210,11 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
}
config.replace("$REMOTE_HOST", connData.host);
config.replace("$REMOTE_PORT", amnezia::protocols::openvpn::openvpnDefaultPort);
config.replace("$CA_CERT", connData.caCert);
config.replace("$CLIENT_CERT", connData.clientCert);
config.replace("$PRIV_KEY", connData.privKey);
config.replace("$TA_KEY", connData.taKey);
config.replace("$REMOTE_PORT", amnezia::protocols::openvpn::defaultPort);
config.replace("$OPENVPN_CA_CERT", connData.caCert);
config.replace("$OPENVPN_CLIENT_CERT", connData.clientCert);
config.replace("$OPENVPN_PRIV_KEY", connData.privKey);
config.replace("$OPENVPN_TA_KEY", connData.taKey);
#ifdef Q_OS_MAC
config.replace("block-outside-dns", "");
@ -281,13 +262,13 @@ ErrorCode OpenVpnConfigurator::signCert(DockerContainer container,
{
QString script_import = QString("sudo docker exec -i %1 bash -c \"cd /opt/amnezia/openvpn && "
"easyrsa import-req %2/%3.req %3\"")
.arg(amnezia::server::getContainerName(container))
.arg(amnezia::containerToString(container))
.arg(amnezia::protocols::openvpn::clientsDirPath)
.arg(clientId);
QString script_sign = QString("sudo docker exec -i %1 bash -c \"export EASYRSA_BATCH=1; cd /opt/amnezia/openvpn && "
"easyrsa sign-req client %2\"")
.arg(amnezia::server::getContainerName(container))
.arg(amnezia::containerToString(container))
.arg(clientId);
QStringList scriptList {script_import, script_sign};

View file

@ -23,7 +23,7 @@ public:
};
static QString genOpenVpnConfig(const ServerCredentials &credentials, DockerContainer container,
ErrorCode *errorCode = nullptr);
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
static QString convertOpenSShKey(const QString &key);

View file

@ -0,0 +1,37 @@
#include "shadowsocks_configurator.h"
#include <QFile>
#include <QJsonObject>
#include <QJsonDocument>
#include "protocols/protocols_defs.h"
QString ShadowSocksConfigurator::genShadowSocksConfig(const ServerCredentials &credentials,
DockerContainer container, const QJsonObject &containerConfig, ErrorCode *errorCode)
{
ErrorCode e = ErrorCode::NoError;
QString ssKey = ServerController::getTextFileFromContainer(container, credentials,
amnezia::protocols::shadowsocks::ssKeyPath, &e);
ssKey.replace("\n", "");
if (e) {
if (errorCode) *errorCode = e;
return "";
}
QJsonObject config;
config.insert("server", credentials.hostName);
config.insert("server_port", "$SHADOWSOCKS_SERVER_PORT");
config.insert("local_port", "$SHADOWSOCKS_LOCAL_PORT");
config.insert("password", ssKey);
config.insert("timeout", 60);
config.insert("method", "$SHADOWSOCKS_CIPHER");
QString textCfg = ServerController::replaceVars(QJsonDocument(config).toJson(),
ServerController::genVarsForScript(credentials, container, containerConfig));
qDebug().noquote() << textCfg;
return textCfg;
}

View file

@ -0,0 +1,18 @@
#ifndef SHADOWSOCKS_CONFIGURATOR_H
#define SHADOWSOCKS_CONFIGURATOR_H
#include <QObject>
#include "core/defs.h"
#include "settings.h"
#include "core/servercontroller.h"
class ShadowSocksConfigurator
{
public:
static QString genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode *errorCode = nullptr);
};
#endif // SHADOWSOCKS_CONFIGURATOR_H

View file

@ -5,44 +5,6 @@
#include <QObject>
namespace amnezia {
Q_NAMESPACE
enum class Protocol {
Any,
OpenVpn,
ShadowSocks,
Cloak,
WireGuard
};
Q_ENUM_NS(Protocol)
inline Protocol protoFromString(QString proto){
auto&& metaEnum = QMetaEnum::fromType<Protocol>();
return static_cast<Protocol>(metaEnum.keyToValue(proto.toStdString().c_str()));
}
inline QString protoToString(Protocol proto){
return QVariant::fromValue(proto).toString();
}
enum class DockerContainer {
None,
OpenVpn,
ShadowSocksOverOpenVpn,
OpenVpnOverCloak,
WireGuard
};
Q_ENUM_NS(DockerContainer)
inline DockerContainer containerFromString(QString container){
auto&& metaEnum = QMetaEnum::fromType<DockerContainer>();
return static_cast<DockerContainer>(metaEnum.keyToValue(container.toStdString().c_str()));
}
inline QString containerToString(DockerContainer container){
return QVariant::fromValue(container).toString();
}
//static DockerContainer containerForProto(Protocol proto)
//{
@ -78,6 +40,7 @@ enum ErrorCode
// Server errors
ServerCheckFailed,
ServerPortAlreadyAllocatedError,
ServerContainerMissingError,
// Ssh connection errors
SshSocketError, SshTimeoutError, SshProtocolError,

View file

@ -9,7 +9,7 @@ QString amnezia::scriptFolder(amnezia::DockerContainer container)
switch (container) {
case DockerContainer::OpenVpn: return QLatin1String("openvpn");
case DockerContainer::OpenVpnOverCloak: return QLatin1String("openvpn_cloak");
case DockerContainer::ShadowSocksOverOpenVpn: return QLatin1String("openvpn_shadowsocks");
case DockerContainer::OpenVpnOverShadowSocks: return QLatin1String("openvpn_shadowsocks");
case DockerContainer::WireGuard: return QLatin1String("wireguard");
default: return "";
}
@ -32,6 +32,7 @@ QString amnezia::scriptName(ProtocolScriptType type)
{
switch (type) {
case ProtocolScriptType::dockerfile: return QLatin1String("Dockerfile");
case ProtocolScriptType::run_container: return QLatin1String("run_container.sh");
case ProtocolScriptType::configure_container: return QLatin1String("configure_container.sh");
case ProtocolScriptType::container_startup: return QLatin1String("start.sh");
case ProtocolScriptType::openvpn_template: return QLatin1String("template.ovpn");
@ -46,7 +47,11 @@ QString amnezia::scriptData(amnezia::SharedScriptType type)
qDebug() << "Error opening script" << fileName;
return "";
}
return file.readAll();
QByteArray ba = file.readAll();
if (ba.isEmpty()) {
qDebug() << "Error, script is empty" << fileName;
}
return ba;
}
QString amnezia::scriptData(amnezia::ProtocolScriptType type, DockerContainer container)

View file

@ -3,6 +3,7 @@
#include <QLatin1String>
#include "core/defs.h"
#include "protocols/protocols_defs.h""
namespace amnezia {
@ -19,6 +20,7 @@ enum SharedScriptType {
enum ProtocolScriptType {
// Protocol scripts
dockerfile,
run_container,
configure_container,
container_startup,
openvpn_template

View file

@ -1,16 +1,16 @@
#include "server_defs.h"
QString amnezia::server::getContainerName(amnezia::DockerContainer container)
{
switch (container) {
case(DockerContainer::OpenVpn): return "amnezia-openvpn";
case(DockerContainer::OpenVpnOverCloak): return "amnezia-openvpn-cloak";
case(DockerContainer::ShadowSocksOverOpenVpn): return "amnezia-shadowsocks";
default: return "";
}
}
//QString amnezia::containerToString(amnezia::DockerContainer container)
//{
// switch (container) {
// case(DockerContainer::OpenVpn): return "amnezia-openvpn";
// case(DockerContainer::OpenVpnOverCloak): return "amnezia-openvpn-cloak";
// case(DockerContainer::OpenVpnOverShadowSocks): return "amnezia-shadowsocks";
// default: return "";
// }
//}
QString amnezia::server::getDockerfileFolder(amnezia::DockerContainer container)
{
return "/opt/amnezia/" + getContainerName(container);
return "/opt/amnezia/" + containerToString(container);
}

View file

@ -2,11 +2,11 @@
#define SERVER_DEFS_H
#include <QObject>
#include "core/defs.h"
#include "protocols/protocols_defs.h""
namespace amnezia {
namespace server {
QString getContainerName(amnezia::DockerContainer container);
//QString getContainerName(amnezia::DockerContainer container);
QString getDockerfileFolder(amnezia::DockerContainer container);
}

View file

@ -119,41 +119,27 @@ ErrorCode ServerController::runScript(const SshConnectionParameters &sshParams,
return ErrorCode::NoError;
}
ErrorCode ServerController::installDocker(const ServerCredentials &credentials)
{
// Setup openvpn part
QString scriptData = amnezia::scriptData(SharedScriptType::install_docker);
if (scriptData.isEmpty()) return ErrorCode::InternalError;
QString stdOut;
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
stdOut += data + "\n";
if (data.contains("Automatically restart Docker daemon?")) {
proc->write("yes\n");
}
};
auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> ) {
stdOut += data + "\n";
};
return runScript(sshParams(credentials),
replaceVars(scriptData, genVarsForScript(credentials, DockerContainer::OpenVpnOverCloak)),
cbReadStdOut, cbReadStdErr);
}
ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
const ServerCredentials &credentials, const QString &file, const QString &path)
{
ErrorCode e;
QString tmpFileName = QString("/tmp/%1.tmp").arg(Utils::getRandomString(16));
uploadFileToHost(credentials, file.toUtf8(), tmpFileName);
e = uploadFileToHost(credentials, file.toUtf8(), tmpFileName);
if (e) return e;
QString stdOut;
auto cbReadStd = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> ) {
stdOut += data + "\n";
};
e = runScript(sshParams(credentials),
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(path),
genVarsForScript(credentials, container)));
genVarsForScript(credentials, container)), cbReadStd, cbReadStd);
if (e) return e;
if (stdOut.contains("Error: No such container:")) {
return ErrorCode::ServerContainerMissingError;
}
runScript(sshParams(credentials),
replaceVars(QString("sudo shred %1").arg(tmpFileName),
@ -164,52 +150,6 @@ ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
genVarsForScript(credentials, container)));
return e;
// QString script = QString("sudo docker exec -i %1 sh -c \"echo \'%2\' > %3\"").
// arg(amnezia::server::getContainerName(container)).arg(file).arg(path);
// qDebug().noquote() << "uploadTextFileToContainer\n" << script;
// SshConnection *client = connectToHost(sshParams(credentials));
// if (client->state() != SshConnection::State::Connected) {
// return fromSshConnectionErrorCode(client->errorState());
// }
// QSharedPointer<SshRemoteProcess> proc = client->createRemoteProcess(script.toUtf8());
// if (!proc) {
// qCritical() << "Failed to create SshRemoteProcess, breaking.";
// return ErrorCode::SshRemoteProcessCreationError;
// }
// QEventLoop wait;
// int exitStatus = -1;
//// QObject::connect(proc.data(), &SshRemoteProcess::started, &wait, [](){
//// qDebug() << "uploadTextFileToContainer started";
//// });
// QObject::connect(proc.data(), &SshRemoteProcess::closed, &wait, [&](int status){
// //qDebug() << "Remote process exited with status" << status;
// exitStatus = status;
// wait.quit();
// });
// QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardOutput, [proc](){
// qDebug().noquote() << proc->readAllStandardOutput();
// });
// QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, [proc](){
// qDebug().noquote() << proc->readAllStandardError();
// });
// proc->start();
// if (exitStatus < 0) {
// wait.exec();
// }
// return fromSshProcessExitStatus(exitStatus);
}
QString ServerController::getTextFileFromContainer(DockerContainer container,
@ -218,7 +158,7 @@ QString ServerController::getTextFileFromContainer(DockerContainer container,
if (errorCode) *errorCode = ErrorCode::NoError;
QString script = QString("sudo docker exec -i %1 sh -c \"cat \'%2\'\"").
arg(amnezia::server::getContainerName(container)).arg(path);
arg(amnezia::containerToString(container)).arg(path);
qDebug().noquote() << "Copy file from container\n" << script;
@ -402,77 +342,151 @@ ErrorCode ServerController::removeContainer(const ServerCredentials &credentials
ErrorCode ServerController::setupContainer(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
{
ErrorCode e = runScript(sshParams(credentials),
replaceVars(amnezia::scriptData(SharedScriptType::install_docker),
genVarsForScript(credentials)));
qDebug().noquote() << "ServerController::setupContainer" << containerToString(container);
qDebug().noquote() << QJsonDocument(config).toJson();
ErrorCode e = ErrorCode::NoError;
// e = runScript(sshParams(credentials),
// replaceVars(amnezia::scriptData(SharedScriptType::install_docker),
// genVarsForScript(credentials)));
// if (e) return e;
e = prepareHostWorker(credentials, container, config);
if (e) return e;
removeContainer(credentials, container);
e = buildContainerWorker(credentials, container, config);
if (e) return e;
e = runContainerWorker(credentials, container, config);
if (e) return e;
e = configureContainerWorker(credentials, container, config);
if (e) return e;
return startupContainerWorker(credentials, container, config);
// if (container == DockerContainer::OpenVpn) {
// return setupOpenVpnServer(credentials, config);
// }
// else if (container == DockerContainer::OpenVpnOverShadowSocks) {
// return setupShadowSocksServer(credentials, config);
// }
// else if (container == DockerContainer::OpenVpnOverCloak) {
// return setupOpenVpnOverCloakServer(credentials, config);
// }
// return ErrorCode::NoError;
}
ErrorCode ServerController::updateContainer(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &oldConfig, const QJsonObject &newConfig)
{
if (isReinstallContainerRequred(container, oldConfig, newConfig)) {
return setupContainer(credentials, container, newConfig);
}
else {
ErrorCode e = configureContainerWorker(credentials, container, newConfig);
if (e) return e;
return startupContainerWorker(credentials, container, newConfig);
}
}
bool ServerController::isReinstallContainerRequred(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig)
{
if (container == DockerContainer::OpenVpn) {
return ErrorCode::NoError;
//return setupOpenVpnServer(credentials, config);
}
else if (container == DockerContainer::ShadowSocksOverOpenVpn) {
return setupShadowSocksServer(credentials, config);
}
else if (container == DockerContainer::OpenVpnOverCloak) {
return setupOpenVpnOverCloakServer(credentials, config);
const QJsonObject &oldProtoConfig = oldConfig[config_key::openvpn].toObject();
const QJsonObject &newProtoConfig = newConfig[config_key::openvpn].toObject();
if (oldProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto) !=
newProtoConfig.value(config_key::transport_proto).toString(protocols::openvpn::defaultTransportProto))
return true;
if (oldProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort) !=
newProtoConfig.value(config_key::port).toString(protocols::openvpn::defaultPort))
return true;
}
return ErrorCode::NoError;
if (container == DockerContainer::OpenVpnOverCloak) {
const QJsonObject &oldProtoConfig = oldConfig[config_key::cloak].toObject();
const QJsonObject &newProtoConfig = newConfig[config_key::cloak].toObject();
if (oldProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort) !=
newProtoConfig.value(config_key::port).toString(protocols::cloak::defaultPort))
return true;
}
return false;
}
ErrorCode ServerController::setupOpenVpnServer(const ServerCredentials &credentials, const QJsonObject &config)
{
return ErrorCode::NotImplementedError;
//ErrorCode ServerController::setupOpenVpnServer(const ServerCredentials &credentials, const QJsonObject &config)
//{
// return ErrorCode::NotImplementedError;
//}
// QString scriptData;
// QString scriptFileName = ":/server_scripts/setup_openvpn_server.sh";
// QFile file(scriptFileName);
// if (! file.open(QIODevice::ReadOnly)) return ErrorCode::InternalError;
//ErrorCode ServerController::setupOpenVpnOverCloakServer(const ServerCredentials &credentials, const QJsonObject &config)
//{
// ErrorCode e;
// DockerContainer container = DockerContainer::OpenVpnOverCloak;
// scriptData = file.readAll();
// if (scriptData.isEmpty()) return ErrorCode::InternalError;
// QString stdOut;
// auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
// stdOut += data + "\n";
// if (data.contains("Automatically restart Docker daemon?")) {
// proc->write("yes\n");
// }
// };
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
// stdOut += data + "\n";
// };
// ErrorCode e = runScript(genVarsForScript(credentials, DockerContainer::OpenVpn), sshParams(credentials), scriptData, cbReadStdOut, cbReadStdErr);
// e = prepareHostWorker(credentials, container, config);
// 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;
// removeContainer(credentials, container);
// return checkOpenVpnServer(DockerContainer::OpenVpn, credentials);
// e = buildContainerWorker(credentials, container, config);
// if (e) return e;
// e = runContainerWorker(credentials, container, config);
// if (e) return e;
// e = configureContainerWorker(credentials, container, config);
// if (e) return e;
// return startupContainerWorker(credentials, container, config);
//}
ErrorCode ServerController::installDockerWorker(const ServerCredentials &credentials, DockerContainer container)
{
QString stdOut;
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
stdOut += data + "\n";
if (data.contains("Automatically restart Docker daemon?")) {
proc->write("yes\n");
}
};
auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> ) {
stdOut += data + "\n";
};
return runScript(sshParams(credentials),
replaceVars(amnezia::scriptData(SharedScriptType::install_docker),
genVarsForScript(credentials, container)),
cbReadStdOut, cbReadStdErr);
}
ErrorCode ServerController::setupOpenVpnOverCloakServer(const ServerCredentials &credentials, const QJsonObject &config)
ErrorCode ServerController::prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
{
ErrorCode e;
DockerContainer container = DockerContainer::OpenVpnOverCloak;
// create folder on host
e = runScript(sshParams(credentials),
return runScript(sshParams(credentials),
replaceVars(amnezia::scriptData(SharedScriptType::prepare_host),
genVarsForScript(credentials, container)));
if (e) return e;
}
uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, DockerContainer::OpenVpnOverCloak).toUtf8(),
ErrorCode ServerController::buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
{
ErrorCode e = uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, container).toUtf8(),
amnezia::server::getDockerfileFolder(container) + "/Dockerfile");
QString scriptData = amnezia::scriptData(SharedScriptType::build_container);
if (scriptData.isEmpty()) return ErrorCode::InternalError;
if (e) return e;
// QString stdOut;
// auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
@ -482,91 +496,118 @@ ErrorCode ServerController::setupOpenVpnOverCloakServer(const ServerCredentials
// stdOut += data + "\n";
// };
e = runScript(sshParams(credentials),
replaceVars(scriptData,
genVarsForScript(credentials, container)));
if (e) return e;
runScript(sshParams(credentials),
replaceVars(amnezia::scriptData(ProtocolScriptType::configure_container, DockerContainer::OpenVpnOverCloak),
genVarsForScript(credentials, container)));
if (e) return e;
uploadTextFileToContainer(DockerContainer::OpenVpnOverCloak, credentials,
replaceVars(amnezia::scriptData(ProtocolScriptType::container_startup, DockerContainer::OpenVpnOverCloak),
genVarsForScript(credentials, container)),
"/opt/amnezia/start.sh");
runScript(sshParams(credentials),
replaceVars("sudo docker exec -d $CONTAINER_NAME sh -c \"chmod a+x /opt/amnezia/start.sh && /opt/amnezia/start.sh\"",
genVarsForScript(credentials, container)));
if (e) return e;
return e;
return runScript(sshParams(credentials),
replaceVars(amnezia::scriptData(SharedScriptType::build_container),
genVarsForScript(credentials, container, config)));
}
ErrorCode ServerController::setupShadowSocksServer(const ServerCredentials &credentials, const QJsonObject &config)
ErrorCode ServerController::runContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
{
return ErrorCode::NotImplementedError;
// // Setup openvpn part
// QString scriptData;
// QString scriptFileName = ":/server_scripts/setup_shadowsocks_server.sh";
// QFile file(scriptFileName);
// if (! file.open(QIODevice::ReadOnly)) return ErrorCode::InternalError;
// scriptData = file.readAll();
// if (scriptData.isEmpty()) return ErrorCode::InternalError;
// QString stdOut;
// auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
// stdOut += data + "\n";
// if (data.contains("Automatically restart Docker daemon?")) {
// proc->write("yes\n");
// }
// };
// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
// stdOut += data + "\n";
// };
// ErrorCode e = runScript(genVarsForScript(credentials, DockerContainer::ShadowSocks), sshParams(credentials), scriptData, cbReadStdOut, cbReadStdErr);
// if (e) return e;
// // Create ss config
// QJsonObject ssConfig;
// ssConfig.insert("server", "0.0.0.0");
// ssConfig.insert("server_port", amnezia::protocols::shadowsocks::ssRemotePort());
// ssConfig.insert("local_port", amnezia::protocols::shadowsocks::ssContainerPort());
// ssConfig.insert("password", QString(QCryptographicHash::hash(credentials.password.toUtf8(), QCryptographicHash::Sha256).toHex()));
// ssConfig.insert("timeout", 60);
// ssConfig.insert("method", amnezia::protocols::shadowsocks::ssEncryption());
// QString configData = QJsonDocument(ssConfig).toJson();
// QString sSConfigPath = "/opt/amneziavpn_data/ssConfig.json";
// configData.replace("\"", "\\\"");
// //qDebug().noquote() << configData;
// uploadTextFileToContainer(DockerContainer::ShadowSocks, credentials, configData, sSConfigPath);
// // Start ss
// QString script = QString("sudo docker exec -d %1 sh -c \"ss-server -c %2\"").
// arg(amnezia::server::getContainerName(DockerContainer::ShadowSocks)).arg(sSConfigPath);
// e = runScript(genVarsForScript(credentials, DockerContainer::ShadowSocks), sshParams(credentials), script);
// return e;
return runScript(sshParams(credentials),
replaceVars(amnezia::scriptData(ProtocolScriptType::run_container, container),
genVarsForScript(credentials, container, config)));
}
ErrorCode ServerController::configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
{
return runScript(sshParams(credentials),
replaceVars(amnezia::scriptData(ProtocolScriptType::configure_container, container),
genVarsForScript(credentials, container, config)));
}
ErrorCode ServerController::startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
{
ErrorCode e = uploadTextFileToContainer(container, credentials,
replaceVars(amnezia::scriptData(ProtocolScriptType::container_startup, container),
genVarsForScript(credentials, container, config)),
"/opt/amnezia/start.sh");
if (e) return e;
return runScript(sshParams(credentials),
replaceVars("sudo docker exec -d $CONTAINER_NAME sh -c \"chmod a+x /opt/amnezia/start.sh && /opt/amnezia/start.sh\"",
genVarsForScript(credentials, container, config)));
}
//ErrorCode ServerController::setupShadowSocksServer(const ServerCredentials &credentials, const QJsonObject &config)
//{
// return ErrorCode::NotImplementedError;
//// // Setup openvpn part
//// QString scriptData;
//// QString scriptFileName = ":/server_scripts/setup_shadowsocks_server.sh";
//// QFile file(scriptFileName);
//// if (! file.open(QIODevice::ReadOnly)) return ErrorCode::InternalError;
//// scriptData = file.readAll();
//// if (scriptData.isEmpty()) return ErrorCode::InternalError;
//// QString stdOut;
//// auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
//// stdOut += data + "\n";
//// if (data.contains("Automatically restart Docker daemon?")) {
//// proc->write("yes\n");
//// }
//// };
//// auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
//// stdOut += data + "\n";
//// };
//// ErrorCode e = runScript(genVarsForScript(credentials, DockerContainer::ShadowSocks), sshParams(credentials), scriptData, cbReadStdOut, cbReadStdErr);
//// if (e) return e;
//// // Create ss config
//// QJsonObject ssConfig;
//// ssConfig.insert("server", "0.0.0.0");
//// ssConfig.insert("server_port", amnezia::protocols::shadowsocks::ssRemotePort());
//// ssConfig.insert("local_port", amnezia::protocols::shadowsocks::ssContainerPort());
//// ssConfig.insert("password", QString(QCryptographicHash::hash(credentials.password.toUtf8(), QCryptographicHash::Sha256).toHex()));
//// ssConfig.insert("timeout", 60);
//// ssConfig.insert("method", amnezia::protocols::shadowsocks::ssEncryption());
//// QString configData = QJsonDocument(ssConfig).toJson();
//// QString sSConfigPath = "/opt/amneziavpn_data/ssConfig.json";
//// configData.replace("\"", "\\\"");
//// //qDebug().noquote() << configData;
//// uploadTextFileToContainer(DockerContainer::ShadowSocks, credentials, configData, sSConfigPath);
//// // Start ss
//// QString script = QString("sudo docker exec -d %1 sh -c \"ss-server -c %2\"").
//// arg(amnezia::containerToString(DockerContainer::ShadowSocks)).arg(sSConfigPath);
//// e = runScript(genVarsForScript(credentials, DockerContainer::ShadowSocks), sshParams(credentials), script);
// // return e;
//}
ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config)
{
const QJsonObject &openvpnConfig = config.value(config_key::openvpn).toObject();
const QJsonObject &cloakConfig = config.value(config_key::cloak).toObject();
const QJsonObject &ssConfig = config.value(config_key::shadowsocks).toObject();
//
Vars vars;
vars.append({{"$VPN_SUBNET_IP", nonEmpty(config.value(config_key::subnet_address).toString(), amnezia::protocols::vpnDefaultSubnetAddress) }});
vars.append({{"$VPN_SUBNET_MASK_VAL", nonEmpty(config.value(config_key::subnet_mask_val).toString(), amnezia::protocols::vpnDefaultSubnetMaskVal) }});
vars.append({{"$VPN_SUBNET_MASK", nonEmpty(config.value(config_key::subnet_mask).toString(), amnezia::protocols::vpnDefaultSubnetMask) }});
// OpenVPN vars
vars.append({{"$VPN_SUBNET_IP", openvpnConfig.value(config_key::subnet_address).toString(amnezia::protocols::vpnDefaultSubnetAddress) }});
vars.append({{"$VPN_SUBNET_MASK_VAL", openvpnConfig.value(config_key::subnet_mask_val).toString(amnezia::protocols::vpnDefaultSubnetMaskVal) }});
vars.append({{"$VPN_SUBNET_MASK", openvpnConfig.value(config_key::subnet_mask).toString(amnezia::protocols::vpnDefaultSubnetMask) }});
vars.append({{"$CONTAINER_NAME", amnezia::server::getContainerName(container)}});
vars.append({{"$DOCKERFILE_FOLDER", "/opt/amnezia/" + amnezia::server::getContainerName(container)}});
vars.append({{"$OPENVPN_PORT", openvpnConfig.value(config_key::port).toString(amnezia::protocols::openvpn::defaultPort) }});
vars.append({{"$OPENVPN_TRANSPORT_PROTO", openvpnConfig.value(config_key::transport_proto).toString(amnezia::protocols::openvpn::defaultTransportProto) }});
bool isNcpDisabled = openvpnConfig.value(config_key::ncp_disable).toBool(amnezia::protocols::openvpn::defaultNcpDisable);
vars.append({{"$OPENVPN_NCP_DISABLE", isNcpDisabled ? protocols::openvpn::ncpDisableString : "" }});
vars.append({{"$OPENVPN_CIPHER", openvpnConfig.value(config_key::cipher).toString(amnezia::protocols::openvpn::defaultCipher) }});
vars.append({{"$OPENVPN_HASH", openvpnConfig.value(config_key::hash).toString(amnezia::protocols::openvpn::defaultHash) }});
// ShadowSocks vars
vars.append({{"$SHADOWSOCKS_SERVER_PORT", ssConfig.value(config_key::port).toString(amnezia::protocols::shadowsocks::defaultPort) }});
vars.append({{"$SHADOWSOCKS_LOCAL_PORT", ssConfig.value(config_key::local_port).toString(amnezia::protocols::shadowsocks::defaultLocalProxyPort) }});
vars.append({{"$SHADOWSOCKS_CIPHER", ssConfig.value(config_key::cipher).toString(amnezia::protocols::shadowsocks::defaultCipher) }});
vars.append({{"$CONTAINER_NAME", amnezia::containerToString(container)}});
vars.append({{"$DOCKERFILE_FOLDER", "/opt/amnezia/" + amnezia::containerToString(container)}});
QString serverIp = Utils::getIPAddress(credentials.hostName);
if (!serverIp.isEmpty()) {
@ -576,22 +617,19 @@ ServerController::Vars ServerController::genVarsForScript(const ServerCredential
qWarning() << "ServerController::genVarsForScript unable to resolve address for credentials.hostName";
}
//
const QJsonObject &openvpnConfig = config.value(config_key::openvpn).toObject();
const QJsonObject &cloakConfig = config.value(config_key::cloak).toObject();
const QJsonObject &ssConfig = config.value(config_key::shadowsocks).toObject();
if (container == DockerContainer::OpenVpn) {
vars.append({{"$DOCKER_PORT", nonEmpty(config.value(config_key::port).toString(), protocols::openvpn::openvpnDefaultPort) }});
vars.append({{"$DOCKER_PORT", config.value(config_key::port).toString(protocols::openvpn::defaultPort) }});
}
else if (container == DockerContainer::OpenVpnOverCloak) {
vars.append({{"$DOCKER_PORT", nonEmpty(config.value(config_key::port).toString(), protocols::cloak::ckDefaultPort) }});
vars.append({{"$DOCKER_PORT", config.value(config_key::port).toString(protocols::cloak::defaultPort) }});
vars.append({{"$FAKE_WEB_SITE_ADDRESS", nonEmpty(cloakConfig.value(config_key::site).toString(), protocols::cloak::ckDefaultRedirSite) }});
vars.append({{"$FAKE_WEB_SITE_ADDRESS", cloakConfig.value(config_key::site).toString(protocols::cloak::defaultRedirSite) }});
}
else if (container == DockerContainer::ShadowSocksOverOpenVpn) {
vars.append({{"$DOCKER_PORT", nonEmpty(config.value(config_key::port).toString(), protocols::shadowsocks::ssDefaultPort) }});
else if (container == DockerContainer::OpenVpnOverShadowSocks) {
vars.append({{"$DOCKER_PORT", config.value(config_key::port).toString(protocols::shadowsocks::defaultPort) }});
}
return vars;
@ -686,7 +724,7 @@ QString ServerController::replaceVars(const QString &script, const Vars &vars)
{
QString s = script;
for (const QPair<QString, QString> &var : vars) {
//qDebug() << "Replacing" << var << vars.value(var);
//qDebug() << "Replacing" << var.first << var.second;
s.replace(var.first, var.second);
}
return s;

View file

@ -6,6 +6,8 @@
#include "sshconnection.h"
#include "sshremoteprocess.h"
#include "defs.h"
#include "protocols/protocols_defs.h""
using namespace amnezia;
@ -26,6 +28,10 @@ public:
static ErrorCode removeAllContainers(const ServerCredentials &credentials);
static ErrorCode removeContainer(const ServerCredentials &credentials, DockerContainer container);
static ErrorCode setupContainer(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
static ErrorCode updateContainer(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &oldConfig, const QJsonObject &newConfig = QJsonObject());
static bool isReinstallContainerRequred(DockerContainer container, const QJsonObject &oldConfig, const QJsonObject &newConfig);
static ErrorCode checkOpenVpnServer(DockerContainer container, const ServerCredentials &credentials);
@ -51,11 +57,18 @@ public:
private:
static QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams);
static ErrorCode installDocker(const ServerCredentials &credentials);
static ErrorCode installDockerWorker(const ServerCredentials &credentials, DockerContainer container);
//static ErrorCode setupOpenVpnServer(const ServerCredentials &credentials, const QJsonObject &config = QJsonObject());
//static ErrorCode setupOpenVpnOverCloakServer(const ServerCredentials &credentials, const QJsonObject &config = QJsonObject());
// static ErrorCode setupShadowSocksServer(const ServerCredentials &credentials, const QJsonObject &config = QJsonObject());
static ErrorCode prepareHostWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
static ErrorCode buildContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
static ErrorCode runContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
static ErrorCode configureContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
static ErrorCode startupContainerWorker(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &config = QJsonObject());
static ErrorCode setupOpenVpnServer(const ServerCredentials &credentials, const QJsonObject &config = QJsonObject());
static ErrorCode setupOpenVpnOverCloakServer(const ServerCredentials &credentials, const QJsonObject &config = QJsonObject());
static ErrorCode setupShadowSocksServer(const ServerCredentials &credentials, const QJsonObject &config = QJsonObject());
};
#endif // SERVERCONTROLLER_H

View file

@ -37,9 +37,13 @@ ErrorCode OpenVpnOverCloakProtocol::start()
m_cloakCfgFile.close();
QStringList args = QStringList() << "-c" << m_cloakCfgFile.fileName()
<< "-s" << m_cloakConfig.value("Remote").toString()
<< "-p" << amnezia::protocols::cloak::ckDefaultPort
<< "-l" << amnezia::protocols::openvpn::openvpnDefaultPort;
<< "-s" << m_cloakConfig.value(config_key::remote).toString()
<< "-p" << amnezia::protocols::cloak::defaultPort
<< "-l" << amnezia::protocols::openvpn::defaultPort;
if (m_cloakConfig.value(config_key::transport_proto).toString() == protocols::UDP) {
args << "-u";
}
qDebug().noquote() << "OpenVpnOverCloakProtocol::start()"
<< cloakExecPath() << args.join(" ");

View file

@ -4,78 +4,148 @@
#include <QObject>
namespace amnezia {
inline QString nonEmpty(const QString &val, const QString &deflt) { return val.isEmpty() ? deflt : val; }
namespace config_key {
// Json config strings
const char hostName[] = "hostName";
const char userName[] = "userName";
const char password[] = "password";
const char port[] = "port";
const char description[] = "description";
constexpr char hostName[] = "hostName";
constexpr char userName[] = "userName";
constexpr char password[] = "password";
constexpr char port[] = "port";
constexpr char local_port[] = "local_port";
constexpr char description[] = "description";
const char containers[] = "containers";
const char container[] = "container";
const char defaultContainer[] = "defaultContainer";
constexpr char containers[] = "containers";
constexpr char container[] = "container";
constexpr char defaultContainer[] = "defaultContainer";
const char protocols[] = "protocols";
const char protocol[] = "protocol";
constexpr char protocols[] = "protocols";
//constexpr char protocol[] = "protocol";
const char transport_protocol[] = "transport_protocol";
const char cipher[] = "cipher";
const char hash[] = "hash";
constexpr char remote[] = "remote";
constexpr char transport_proto[] = "transport_proto";
constexpr char cipher[] = "cipher";
constexpr char hash[] = "hash";
constexpr char ncp_disable[] = "ncp_disable";
const char site[] = "site";
constexpr char site[] = "site";
constexpr char block_outside_dns[] = "block_outside_dns";
const char subnet_address[] = "subnet_address";
const char subnet_mask[] = "subnet_mask";
const char subnet_mask_val[] = "subnet_mask_val";
constexpr char subnet_address[] = "subnet_address";
constexpr char subnet_mask[] = "subnet_mask";
constexpr char subnet_mask_val[] = "subnet_mask_val";
const char openvpn[] = "openvpn";
const char shadowsocks[] = "shadowsocks";
const char cloak[] = "cloak";
// proto config keys
constexpr char last_config[] = "last_config";
constexpr char openvpn[] = "openvpn";
constexpr char shadowsocks[] = "shadowsocks";
constexpr char cloak[] = "cloak";
constexpr char wireguard[] = "wireguard";
// containers config keys
constexpr char amnezia_openvpn[] = "amnezia-openvpn";
constexpr char amnezia_shadowsocks[] = "amnezia-shadowsocks";
constexpr char amnezia_openvpn_cloak[] = "amnezia-openvpn-cloak";
constexpr char amnezia_wireguard[] = "amnezia-wireguard";
}
namespace protocols {
const char vpnDefaultSubnetAddress[] = "10.8.0.0";
const char vpnDefaultSubnetMask[] = "255.255.255.0";
const char vpnDefaultSubnetMaskVal[] = "24";
constexpr char vpnDefaultSubnetAddress[] = "10.8.0.0";
constexpr char vpnDefaultSubnetMask[] = "255.255.255.0";
constexpr char vpnDefaultSubnetMaskVal[] = "24";
constexpr char UDP[] = "udp"; // case sens
constexpr char TCP[] = "tcp";
namespace openvpn {
const char caCertPath[] = "/opt/amnezia/openvpn/pki/ca.crt";
const char clientCertPath[] = "/opt/amnezia/openvpn/pki/issued";
const char taKeyPath[] = "/opt/amnezia/openvpn/ta.key";
const char clientsDirPath[] = "/opt/amnezia/openvpn/clients";
const char openvpnDefaultPort[] = "1194";
const char openvpnDefaultProto[] = "UDP";
const char openvpnDefaultCipher[] = "AES-256-GCM";
const char openvpnDefaultHash[] = "SHA512";
const bool blockOutsideDNS = true;
constexpr char caCertPath[] = "/opt/amnezia/openvpn/pki/ca.crt";
constexpr char clientCertPath[] = "/opt/amnezia/openvpn/pki/issued";
constexpr char taKeyPath[] = "/opt/amnezia/openvpn/ta.key";
constexpr char clientsDirPath[] = "/opt/amnezia/openvpn/clients";
constexpr char defaultPort[] = "1194";
constexpr char defaultTransportProto[] = amnezia::protocols::UDP;
constexpr char defaultCipher[] = "AES-256-GCM";
constexpr char defaultHash[] = "SHA512";
constexpr bool defaultBlockOutsideDns = true;
constexpr bool defaultNcpDisable = false;
constexpr char ncpDisableString[] = "ncp-disable";
}
namespace shadowsocks {
const char ssDefaultPort[] = "6789";
const char ssLocalProxyPort[] = "8585";
const char ssDefaultCipher[] = "chacha20-ietf-poly1305";
constexpr char ssKeyPath[] = "/opt/amnezia/shadowsocks/shadowsocks.key";
constexpr char defaultPort[] = "6789";
constexpr char defaultLocalProxyPort[] = "8585";
constexpr char defaultCipher[] = "chacha20-ietf-poly1305";
}
namespace cloak {
const char ckPublicKeyPath[] = "/opt/amnezia/cloak/cloak_public.key";
const char ckBypassUidKeyPath[] = "/opt/amnezia/cloak/cloak_bypass_uid.key";
const char ckAdminKeyPath[] = "/opt/amnezia/cloak/cloak_admin_uid.key";
const char ckDefaultPort[] = "443";
const char ckDefaultRedirSite[] = "mail.ru";
constexpr char ckPublicKeyPath[] = "/opt/amnezia/cloak/cloak_public.key";
constexpr char ckBypassUidKeyPath[] = "/opt/amnezia/cloak/cloak_bypass_uid.key";
constexpr char ckAdminKeyPath[] = "/opt/amnezia/cloak/cloak_admin_uid.key";
constexpr char defaultPort[] = "443";
constexpr char defaultRedirSite[] = "mail.ru";
}
} // namespace protocols
enum class Protocol {
Any,
OpenVpn,
ShadowSocks,
Cloak,
WireGuard
};
inline Protocol protoFromString(QString proto){
if (proto == config_key::openvpn) return Protocol::OpenVpn;
if (proto == config_key::cloak) return Protocol::Cloak;
if (proto == config_key::shadowsocks) return Protocol::ShadowSocks;
if (proto == config_key::wireguard) return Protocol::WireGuard;
return Protocol::Any;
}
inline QString protoToString(Protocol proto){
switch (proto) {
case(Protocol::OpenVpn): return config_key::openvpn;
case(Protocol::Cloak): return config_key::cloak;
case(Protocol::ShadowSocks): return config_key::shadowsocks;
case(Protocol::WireGuard): return config_key::wireguard;
default: return "";
}
}
enum class DockerContainer {
None,
OpenVpn,
OpenVpnOverShadowSocks,
OpenVpnOverCloak,
WireGuard
};
inline DockerContainer containerFromString(const QString &container){
if (container == config_key::amnezia_openvpn) return DockerContainer::OpenVpn;
if (container == config_key::amnezia_openvpn_cloak) return DockerContainer::OpenVpnOverCloak;
if (container == config_key::amnezia_shadowsocks) return DockerContainer::OpenVpnOverShadowSocks;
if (container == config_key::amnezia_wireguard) return DockerContainer::WireGuard;
return DockerContainer::None;
}
inline QString containerToString(DockerContainer container){
switch (container) {
case(DockerContainer::OpenVpn): return config_key::amnezia_openvpn;
case(DockerContainer::OpenVpnOverCloak): return config_key::amnezia_openvpn_cloak;
case(DockerContainer::OpenVpnOverShadowSocks): return config_key::amnezia_shadowsocks;
case(DockerContainer::WireGuard): return config_key::amnezia_wireguard;
default: return "";
}
}
} // namespace amnezia
#endif // PROTOCOLS_DEFS_H

View file

@ -96,18 +96,6 @@ QString ShadowSocksVpnProtocol::shadowSocksExecPath()
#endif
}
QJsonObject ShadowSocksVpnProtocol::genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container)
{
QJsonObject ssConfig;
ssConfig.insert("server", credentials.hostName);
ssConfig.insert("server_port", amnezia::protocols::shadowsocks::ssDefaultPort);
ssConfig.insert("local_port", amnezia::protocols::shadowsocks::ssLocalProxyPort);
ssConfig.insert("password", QString(QCryptographicHash::hash(credentials.password.toUtf8(), QCryptographicHash::Sha256).toHex()));
ssConfig.insert("timeout", 60);
ssConfig.insert("method", amnezia::protocols::shadowsocks::ssDefaultCipher);
return ssConfig;
}
void ShadowSocksVpnProtocol::readShadowSocksConfiguration(const QJsonObject &configuration)
{
m_shadowSocksConfig = configuration.value(config::key_shadowsocks_config_data).toObject();

View file

@ -3,6 +3,7 @@
#include "openvpnprotocol.h"
#include "QProcess"
#include "protocols/protocols_defs.h""
class ShadowSocksVpnProtocol : public OpenVpnProtocol
{
@ -13,8 +14,6 @@ public:
ErrorCode start() override;
void stop() override;
static QJsonObject genShadowSocksConfig(const ServerCredentials &credentials, DockerContainer container = DockerContainer::ShadowSocksOverOpenVpn);
protected:
void readShadowSocksConfiguration(const QJsonObject &configuration);

View file

@ -34,11 +34,7 @@
<file>images/server_settings.png</file>
<file>images/share.png</file>
<file>server_scripts/remove_container.sh</file>
<file>server_scripts/setup_openvpn_server.sh</file>
<file>server_scripts/template_openvpn.ovpn</file>
<file>images/background_connected.png</file>
<file>server_scripts/setup_shadowsocks_server.sh</file>
<file>server_scripts/template_shadowsocks.ovpn</file>
<file>server_scripts/setup_host_firewall.sh</file>
<file>images/reload.png</file>
<file>server_scripts/openvpn_cloak/Dockerfile</file>
@ -54,5 +50,16 @@
<file>images/plus.png</file>
<file>server_scripts/check_connection.sh</file>
<file>server_scripts/remove_all_containers.sh</file>
<file>server_scripts/openvpn_cloak/run_container.sh</file>
<file>server_scripts/openvpn/configure_container.sh</file>
<file>server_scripts/openvpn/run_container.sh</file>
<file>server_scripts/openvpn/template.ovpn</file>
<file>server_scripts/openvpn/Dockerfile</file>
<file>server_scripts/openvpn/start.sh</file>
<file>server_scripts/openvpn_shadowsocks/configure_container.sh</file>
<file>server_scripts/openvpn_shadowsocks/Dockerfile</file>
<file>server_scripts/openvpn_shadowsocks/run_container.sh</file>
<file>server_scripts/openvpn_shadowsocks/start.sh</file>
<file>server_scripts/openvpn_shadowsocks/template.ovpn</file>
</qresource>
</RCC>

View file

@ -0,0 +1,49 @@
FROM alpine:latest
LABEL maintainer="AmneziaVPN"
#Install required packages
RUN apk add --no-cache curl openvpn easy-rsa bash netcat-openbsd dumb-init rng-tools
RUN apk --update upgrade --no-cache
ENV EASYRSA_BATCH 1
ENV PATH="/usr/share/easy-rsa:${PATH}"
RUN mkdir -p /opt/amnezia
RUN echo -e "#!/bin/bash\ntail -f /dev/null" > /opt/amnezia/start.sh
RUN chmod a+x /opt/amnezia/start.sh
# Tune network
RUN echo -e " \n\
fs.file-max = 51200 \n\
\n\
net.core.rmem_max = 67108864 \n\
net.core.wmem_max = 67108864 \n\
net.core.netdev_max_backlog = 250000 \n\
net.core.somaxconn = 4096 \n\
\n\
net.ipv4.tcp_syncookies = 1 \n\
net.ipv4.tcp_tw_reuse = 1 \n\
net.ipv4.tcp_tw_recycle = 0 \n\
net.ipv4.tcp_fin_timeout = 30 \n\
net.ipv4.tcp_keepalive_time = 1200 \n\
net.ipv4.ip_local_port_range = 10000 65000 \n\
net.ipv4.tcp_max_syn_backlog = 8192 \n\
net.ipv4.tcp_max_tw_buckets = 5000 \n\
net.ipv4.tcp_fastopen = 3 \n\
net.ipv4.tcp_mem = 25600 51200 102400 \n\
net.ipv4.tcp_rmem = 4096 87380 67108864 \n\
net.ipv4.tcp_wmem = 4096 65536 67108864 \n\
net.ipv4.tcp_mtu_probing = 1 \n\
net.ipv4.tcp_congestion_control = hybla \n\
# for low-latency network, use cubic instead \n\
# net.ipv4.tcp_congestion_control = cubic \n\
" | sed -e 's/^\s\+//g' | tee -a /etc/sysctl.conf && \
mkdir -p /etc/security && \
echo -e " \n\
* soft nofile 51200 \n\
* hard nofile 51200 \n\
" | sed -e 's/^\s\+//g' | tee -a /etc/security/limits.conf
ENTRYPOINT [ "dumb-init", "/opt/amnezia/start.sh" ]
CMD [ "" ]

View file

@ -0,0 +1,27 @@
sudo docker exec -i $CONTAINER_NAME bash -c '\
echo -e "\
port $OPENVPN_PORT \\n\
proto $OPENVPN_TRANSPORT_PROTO \\n\
dev tun \\n\
ca /opt/amnezia/openvpn/ca.crt \\n\
cert /opt/amnezia/openvpn/AmneziaReq.crt \\n\
key /opt/amnezia/openvpn/AmneziaReq.key \\n\
dh /opt/amnezia/openvpn/dh.pem \\n\
server $VPN_SUBNET_IP $VPN_SUBNET_MASK \\n\
ifconfig-pool-persist ipp.txt \\n\
duplicate-cn \\n\
keepalive 10 120 \\n\
$OPENVPN_NCP_DISABLE \\n\
cipher $OPENVPN_CIPHER \\n\
data-ciphers $OPENVPN_CIPHER \\n\
auth $OPENVPN_HASH \\n\
user nobody \\n\
group nobody \\n\
persist-key \\n\
persist-tun \\n\
status openvpn-status.log \\n\
verb 1 \\n\
tls-server \\n\
tls-version-min 1.2 \\n\
tls-auth /opt/amnezia/openvpn/ta.key 0" >>/opt/amnezia/openvpn/server.conf'

View file

@ -0,0 +1,18 @@
# Run container
sudo docker run -d --restart always --cap-add=NET_ADMIN -p $OPENVPN_PORT:$OPENVPN_PORT/$OPENVPN_TRANSPORT_PROTO --name $CONTAINER_NAME $CONTAINER_NAME
# Create tun device if not exist
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'
# Prevent to route packets outside of the container in case if server behind of the NAT
sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up"
# OpenVPN config
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /opt/amnezia/openvpn/clients; \
cd /opt/amnezia/openvpn && easyrsa init-pki; \
cd /opt/amnezia/openvpn && easyrsa gen-dh; \
cd /opt/amnezia/openvpn && cp pki/dh.pem /opt/amnezia/openvpn && easyrsa build-ca nopass << EOF yes EOF && easyrsa gen-req AmneziaReq nopass << EOF2 yes EOF2;\
cd /opt/amnezia/openvpn && easyrsa sign-req server AmneziaReq << EOF3 yes EOF3;\
cd /opt/amnezia/openvpn && openvpn --genkey --secret ta.key << EOF4;\
cd /opt/amnezia/openvpn && cp pki/ca.crt pki/issued/AmneziaReq.crt pki/private/AmneziaReq.key /opt/amnezia/openvpn'

View file

@ -0,0 +1,26 @@
#!/bin/bash
# This scripts copied from Amnezia client to Docker container to /opt/amnezia and launched every time container starts
echo "Container startup"
if [ ! -c /dev/net/tun ]; then mkdir -p /dev/net; mknod /dev/net/tun c 10 200; fi
# Allow traffic on the TUN interface.
iptables -A INPUT -i tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -j ACCEPT
iptables -A OUTPUT -o tun0 -j ACCEPT
# Allow forwarding traffic only from the VPN.
iptables -A FORWARD -i tun0 -o eth0 -s $VPN_SUBNET_IP/$VPN_SUBNET_MASK_VAL -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $VPN_SUBNET_IP/$VPN_SUBNET_MASK_VAL -o eth0 -j MASQUERADE
# kill daemons in case of restart
killall -KILL openvpn
# start daemons if configured
if [ -f /opt/amnezia/openvpn/ca.crt ]; then (openvpn --config /opt/amnezia/openvpn/server.conf --daemon); fi
tail -f /dev/null

View file

@ -1,12 +1,13 @@
client
dev tun
proto $PROTO
proto $OPENVPN_TRANSPORT_PROTO
resolv-retry infinite
nobind
persist-key
persist-tun
cipher AES-256-GCM
auth SHA512
$OPENVPN_NCP_DISABLE
cipher $OPENVPN_CIPHER
auth $OPENVPN_HASH
verb 3
tls-client
tls-version-min 1.2
@ -21,14 +22,14 @@ block-outside-dns
remote $REMOTE_HOST $REMOTE_PORT
<ca>
$CA_CERT
$OPENVPN_CA_CERT
</ca>
<cert>
$CLIENT_CERT
$OPENVPN_CLIENT_CERT
</cert>
<key>
$PRIV_KEY
$OPENVPN_PRIV_KEY
</key>
<tls-auth>
$TA_KEY
$OPENVPN_TA_KEY
</tls-auth>

View file

@ -1,35 +1,7 @@
# CONTAINER_NAME=... this var will be set in ServerController
# Don't run commands in background like sh -c "openvpn &"
# SERVER_PORT=443
#sudo docker stop $CONTAINER_NAME
#sudo docker rm -f $CONTAINER_NAME
#sudo docker pull amneziavpn/openvpn-cloak:latest
#sudo docker run -d --restart always --cap-add=NET_ADMIN -p $DOCKER_PORT:443/tcp --name $CONTAINER_NAME amneziavpn/openvpn-cloak:latest
sudo docker stop $CONTAINER_NAME
sudo docker rm -f $CONTAINER_NAME
sudo docker run -d --restart always --cap-add=NET_ADMIN -p $DOCKER_PORT:443/tcp --name $CONTAINER_NAME $CONTAINER_NAME
# Create tun device if not exist
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'
# Prevent to route packets outside of the container in case if server behind of the NAT
sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up"
# OpenVPN config
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /opt/amnezia/openvpn/clients; \
cd /opt/amnezia/openvpn && easyrsa init-pki; \
cd /opt/amnezia/openvpn && easyrsa gen-dh; \
cd /opt/amnezia/openvpn && cp pki/dh.pem /opt/amnezia/openvpn && easyrsa build-ca nopass << EOF yes EOF && easyrsa gen-req AmneziaReq nopass << EOF2 yes EOF2;\
cd /opt/amnezia/openvpn && easyrsa sign-req server AmneziaReq << EOF3 yes EOF3;\
cd /opt/amnezia/openvpn && openvpn --genkey --secret ta.key << EOF4;\
cd /opt/amnezia/openvpn && cp pki/ca.crt pki/issued/AmneziaReq.crt pki/private/AmneziaReq.key /opt/amnezia/openvpn'
sudo docker exec -i $CONTAINER_NAME bash -c '\
echo -e "\
port 1194 \\n\
proto tcp \\n\
port $OPENVPN_PORT \\n\
proto $OPENVPN_TRANSPORT_PROTO \\n\
dev tun \\n\
ca /opt/amnezia/openvpn/ca.crt \\n\
cert /opt/amnezia/openvpn/AmneziaReq.crt \\n\
@ -39,9 +11,10 @@ server $VPN_SUBNET_IP $VPN_SUBNET_MASK \\n\
ifconfig-pool-persist ipp.txt \\n\
duplicate-cn \\n\
keepalive 10 120 \\n\
cipher AES-256-GCM \\n\
ncp-ciphers AES-256-GCM:AES-256-CBC \\n\
auth SHA512 \\n\
$OPENVPN_NCP_DISABLE \\n\
cipher $OPENVPN_CIPHER \\n\
data-ciphers $OPENVPN_CIPHER \\n\
auth $OPENVPN_HASH \\n\
user nobody \\n\
group nobody \\n\
persist-key \\n\
@ -52,8 +25,6 @@ tls-server \\n\
tls-version-min 1.2 \\n\
tls-auth /opt/amnezia/openvpn/ta.key 0" >>/opt/amnezia/openvpn/server.conf'
#sudo docker exec -d $CONTAINER_NAME sh -c "openvpn --config /opt/amnezia/openvpn/server.conf"
# Cloak config
sudo docker exec -i $CONTAINER_NAME bash -c '\
mkdir -p /opt/amnezia/cloak; \
@ -66,8 +37,8 @@ echo $CLOAK_PRIVATE_KEY > /opt/amnezia/cloak/cloak_private.key; \
echo -e "{\\n\
\"ProxyBook\": {\\n\
\"openvpn\": [\\n\
\"tcp\",\\n\
\"localhost:1194\"\\n\
\"$OPENVPN_TRANSPORT_PROTO\",\\n\
\"localhost:$OPENVPN_PORT\"\\n\
]\\n\
},\\n\
\"BypassUID\": [\\n\
@ -79,6 +50,4 @@ echo -e "{\\n\
\"AdminUID\": \"$CLOAK_ADMIN_UID\",\\n\
\"DatabasePath\": \"userinfo.db\",\\n\
\"StreamTimeout\": 300\\n\
}" >>/opt/amnezia/cloak/ck-config.json'
#sudo docker exec -d $CONTAINER_NAME sh -c "/usr/bin/ck-server -c /opt/amnezia/cloak/ck-config.json"
}" >/opt/amnezia/cloak/ck-config.json'

View file

@ -0,0 +1,17 @@
# Run container
sudo docker run -d --restart always --cap-add=NET_ADMIN -p $DOCKER_PORT:443/tcp --name $CONTAINER_NAME $CONTAINER_NAME
# Create tun device if not exist
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'
# Prevent to route packets outside of the container in case if server behind of the NAT
sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up"
# OpenVPN config
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /opt/amnezia/openvpn/clients; \
cd /opt/amnezia/openvpn && easyrsa init-pki; \
cd /opt/amnezia/openvpn && easyrsa gen-dh; \
cd /opt/amnezia/openvpn && cp pki/dh.pem /opt/amnezia/openvpn && easyrsa build-ca nopass << EOF yes EOF && easyrsa gen-req AmneziaReq nopass << EOF2 yes EOF2;\
cd /opt/amnezia/openvpn && easyrsa sign-req server AmneziaReq << EOF3 yes EOF3;\
cd /opt/amnezia/openvpn && openvpn --genkey --secret ta.key << EOF4;\
cd /opt/amnezia/openvpn && cp pki/ca.crt pki/issued/AmneziaReq.crt pki/private/AmneziaReq.key /opt/amnezia/openvpn'

View file

@ -2,7 +2,7 @@
# This scripts copied from Amnezia client to Docker container to /opt/amnezia and launched every time container starts
echo "Container Startup start"
echo "Container startup"
if [ ! -c /dev/net/tun ]; then mkdir -p /dev/net; mknod /dev/net/tun c 10 200; fi
@ -17,6 +17,11 @@ iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $VPN_SUBNET_IP/$VPN_SUBNET_MASK_VAL -o eth0 -j MASQUERADE
# kill daemons in case of restart
killall -KILL openvpn
killall -KILL ck-server
# start daemons if configured
if [ -f /opt/amnezia/openvpn/ca.crt ]; then (openvpn --config /opt/amnezia/openvpn/server.conf --daemon); fi
if [ -f /opt/amnezia/cloak/ck-config.json ]; then (ck-server -c /opt/amnezia/cloak/ck-config.json &); fi

View file

@ -1,12 +1,13 @@
client
dev tun
proto $PROTO
proto $OPENVPN_TRANSPORT_PROTO
resolv-retry infinite
nobind
persist-key
persist-tun
cipher AES-256-GCM
auth SHA512
$OPENVPN_NCP_DISABLE
cipher $OPENVPN_CIPHER
auth $OPENVPN_HASH
verb 3
tls-client
tls-version-min 1.2
@ -22,14 +23,14 @@ route $REMOTE_HOST 255.255.255.255 net_gateway
remote 127.0.0.1 1194
<ca>
$CA_CERT
$OPENVPN_CA_CERT
</ca>
<cert>
$CLIENT_CERT
$OPENVPN_CLIENT_CERT
</cert>
<key>
$PRIV_KEY
$OPENVPN_PRIV_KEY
</key>
<tls-auth>
$TA_KEY
$OPENVPN_TA_KEY
</tls-auth>

View file

@ -0,0 +1,53 @@
FROM alpine:latest
LABEL maintainer="AmneziaVPN"
#Install required packages
RUN apk add --no-cache curl openvpn easy-rsa bash netcat-openbsd dumb-init rng-tools xz
RUN apk --update upgrade --no-cache
ENV EASYRSA_BATCH 1
ENV PATH="/usr/share/easy-rsa:${PATH}"
RUN mkdir -p /opt/amnezia
RUN echo -e "#!/bin/bash\ntail -f /dev/null" > /opt/amnezia/start.sh
RUN chmod a+x /opt/amnezia/start.sh
RUN curl -L https://github.com/shadowsocks/shadowsocks-rust/releases/download/v1.10.9/shadowsocks-v1.10.9.x86_64-unknown-linux-musl.tar.xz > /usr/bin/ss.tar.xz
RUN tar -Jxvf /usr/bin/ss.tar.xz -C /usr/bin/
RUN chmod a+x /usr/bin/ssserver
# Tune network
RUN echo -e " \n\
fs.file-max = 51200 \n\
\n\
net.core.rmem_max = 67108864 \n\
net.core.wmem_max = 67108864 \n\
net.core.netdev_max_backlog = 250000 \n\
net.core.somaxconn = 4096 \n\
\n\
net.ipv4.tcp_syncookies = 1 \n\
net.ipv4.tcp_tw_reuse = 1 \n\
net.ipv4.tcp_tw_recycle = 0 \n\
net.ipv4.tcp_fin_timeout = 30 \n\
net.ipv4.tcp_keepalive_time = 1200 \n\
net.ipv4.ip_local_port_range = 10000 65000 \n\
net.ipv4.tcp_max_syn_backlog = 8192 \n\
net.ipv4.tcp_max_tw_buckets = 5000 \n\
net.ipv4.tcp_fastopen = 3 \n\
net.ipv4.tcp_mem = 25600 51200 102400 \n\
net.ipv4.tcp_rmem = 4096 87380 67108864 \n\
net.ipv4.tcp_wmem = 4096 65536 67108864 \n\
net.ipv4.tcp_mtu_probing = 1 \n\
net.ipv4.tcp_congestion_control = hybla \n\
# for low-latency network, use cubic instead \n\
# net.ipv4.tcp_congestion_control = cubic \n\
" | sed -e 's/^\s\+//g' | tee -a /etc/sysctl.conf && \
mkdir -p /etc/security && \
echo -e " \n\
* soft nofile 51200 \n\
* hard nofile 51200 \n\
" | sed -e 's/^\s\+//g' | tee -a /etc/security/limits.conf
ENTRYPOINT [ "dumb-init", "/opt/amnezia/start.sh" ]
CMD [ "" ]

View file

@ -0,0 +1,40 @@
sudo docker exec -i $CONTAINER_NAME bash -c '\
echo -e "\
port $OPENVPN_PORT \\n\
proto tcp \\n\
dev tun \\n\
ca /opt/amnezia/openvpn/ca.crt \\n\
cert /opt/amnezia/openvpn/AmneziaReq.crt \\n\
key /opt/amnezia/openvpn/AmneziaReq.key \\n\
dh /opt/amnezia/openvpn/dh.pem \\n\
server $VPN_SUBNET_IP $VPN_SUBNET_MASK \\n\
ifconfig-pool-persist ipp.txt \\n\
duplicate-cn \\n\
keepalive 10 120 \\n\
$OPENVPN_NCP_DISABLE \\n\
cipher $OPENVPN_CIPHER \\n\
data-ciphers $OPENVPN_CIPHER \\n\
auth $OPENVPN_HASH \\n\
user nobody \\n\
group nobody \\n\
persist-key \\n\
persist-tun \\n\
status openvpn-status.log \\n\
verb 1 \\n\
tls-server \\n\
tls-version-min 1.2 \\n\
tls-auth /opt/amnezia/openvpn/ta.key 0" >>/opt/amnezia/openvpn/server.conf'
# Cloak config
sudo docker exec -i $CONTAINER_NAME bash -c '\
mkdir -p /opt/amnezia/shadowsocks; \
cd /opt/amnezia/shadowsocks || exit 1; \
SHADOWSOCKS_PASSWORD=$(openssl rand -base64 32 | tr "=" "A" | tr "+" "A" | tr "/" "A") && echo $SHADOWSOCKS_PASSWORD > /opt/amnezia/shadowsocks/shadowsocks.key; \
echo -e "{\\n\
\"local_port\": 8585,\\n\
\"method\": \"$SHADOWSOCKS_CIPHER\",\\n\
\"password\": \"$SHADOWSOCKS_PASSWORD\",\\n\
\"server\": \"0.0.0.0\",\\n\
\"server_port\": $SHADOWSOCKS_SERVER_PORT,\\n\
\"timeout\": 60\\n\
}" >/opt/amnezia/shadowsocks/ss-config.json'

View file

@ -0,0 +1,17 @@
# Run container
sudo docker run -d --restart always --cap-add=NET_ADMIN -p $SHADOWSOCKS_SERVER_PORT:$SHADOWSOCKS_SERVER_PORT/tcp --name $CONTAINER_NAME $CONTAINER_NAME
# Create tun device if not exist
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /dev/net; if [ ! -c /dev/net/tun ]; then mknod /dev/net/tun c 10 200; fi'
# Prevent to route packets outside of the container in case if server behind of the NAT
sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up"
# OpenVPN config
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /opt/amnezia/openvpn/clients; \
cd /opt/amnezia/openvpn && easyrsa init-pki; \
cd /opt/amnezia/openvpn && easyrsa gen-dh; \
cd /opt/amnezia/openvpn && cp pki/dh.pem /opt/amnezia/openvpn && easyrsa build-ca nopass << EOF yes EOF && easyrsa gen-req AmneziaReq nopass << EOF2 yes EOF2;\
cd /opt/amnezia/openvpn && easyrsa sign-req server AmneziaReq << EOF3 yes EOF3;\
cd /opt/amnezia/openvpn && openvpn --genkey --secret ta.key << EOF4;\
cd /opt/amnezia/openvpn && cp pki/ca.crt pki/issued/AmneziaReq.crt pki/private/AmneziaReq.key /opt/amnezia/openvpn'

View file

@ -0,0 +1,27 @@
#!/bin/bash
# This scripts copied from Amnezia client to Docker container to /opt/amnezia and launched every time container starts
echo "Container startup"
if [ ! -c /dev/net/tun ]; then mkdir -p /dev/net; mknod /dev/net/tun c 10 200; fi
# Allow traffic on the TUN interface.
iptables -A INPUT -i tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -j ACCEPT
iptables -A OUTPUT -o tun0 -j ACCEPT
# Allow forwarding traffic only from the VPN.
iptables -A FORWARD -i tun0 -o eth0 -s $VPN_SUBNET_IP/$VPN_SUBNET_MASK_VAL -j ACCEPT
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -A POSTROUTING -s $VPN_SUBNET_IP/$VPN_SUBNET_MASK_VAL -o eth0 -j MASQUERADE
# kill daemons in case of restart
killall -KILL openvpn
killall -KILL ssserver
# start daemons if configured
if [ -f /opt/amnezia/openvpn/ca.crt ]; then (openvpn --config /opt/amnezia/openvpn/server.conf --daemon); fi
if [ -f /opt/amnezia/shadowsocks/ss-config.json ]; then (ssserver -c /opt/amnezia/shadowsocks/ss-config.json &); fi
tail -f /dev/null

View file

@ -1,12 +1,13 @@
client
dev tun
proto $PROTO
proto tcp
resolv-retry infinite
nobind
persist-key
persist-tun
cipher AES-256-GCM
auth SHA512
$OPENVPN_NCP_DISABLE
cipher $OPENVPN_CIPHER
auth $OPENVPN_HASH
verb 3
tls-client
tls-version-min 1.2
@ -18,19 +19,19 @@ dhcp-option DNS $PRIMARY_DNS
dhcp-option DNS $SECONDARY_DNS
block-outside-dns
socks-proxy 127.0.0.1 $LOCAL_PROXY_PORT
socks-proxy 127.0.0.1 $SHADOWSOCKS_LOCAL_PORT
route $REMOTE_HOST 255.255.255.255 net_gateway
remote $REMOTE_HOST $REMOTE_PORT
<ca>
$CA_CERT
$OPENVPN_CA_CERT
</ca>
<cert>
$CLIENT_CERT
$OPENVPN_CLIENT_CERT
</cert>
<key>
$PRIV_KEY
$OPENVPN_PRIV_KEY
</key>
<tls-auth>
$TA_KEY
$OPENVPN_TA_KEY
</tls-auth>

View file

@ -1,3 +1,3 @@
sudo docker ps | grep amnezia | awk '{print $1}' | xargs sudo docker stop
sudo docker ps | grep amnezia | awk '{print $1}' | xargs sudo docker rm
sudo docker images -a | grep amnezia | awk '{print $3}' | xargs docker rmi
sudo docker images -a | grep amnezia | awk '{print $3}' | xargs sudo docker rmi

View file

@ -1,28 +0,0 @@
# CONTAINER_NAME=... this var will be set in ServerController
# Don't run commands in background like sh -c "openvpn &"
pm_apt="/usr/bin/apt-get"; pm_yum="/usr/bin/yum"; if [[ -f "$pm_apt" ]]; then pm=$pm_apt; else pm=$pm_yum; fi; if [[ ! -f "/usr/bin/sudo" ]]; then $pm update -y -q; $pm install -y -q sudo; fi
sudo iptables -P FORWARD ACCEPT
pm_apt="/usr/bin/apt-get"; pm_yum="/usr/bin/yum"; if [[ -f "$pm_apt" ]]; then pm=$pm_apt; else pm=$pm_yum; fi; sudo $pm update -y -q
pm_apt="/usr/bin/apt-get"; pm_yum="/usr/bin/yum"; if [[ -f "$pm_apt" ]]; then pm=$pm_apt; else pm=$pm_yum; fi; sudo $pm install -y -q curl
pm_apt="/usr/bin/apt-get"; pm_yum="/usr/bin/yum"; if [[ -f "$pm_apt" ]]; then sudo export DEBIAN_FRONTEND=noninteractive; sudo $pm_apt install -y -q docker.io; else sudo $pm_yum install -y -q docker; fi
sudo systemctl start docker
sudo docker stop $CONTAINER_NAME
sudo docker rm -f $CONTAINER_NAME
sudo docker pull amneziavpn/openvpn:latest
sudo docker run -d --restart always --cap-add=NET_ADMIN -p 1194:1194/udp --name $CONTAINER_NAME amneziavpn/openvpn:latest
# Prevent to route packets outside of the container in case if server behind of the NAT
sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up"
sudo docker exec -i $CONTAINER_NAME sh -c "mkdir -p /opt/amneziavpn_data/clients"
sudo docker exec -i $CONTAINER_NAME sh -c "cd /opt/amneziavpn_data && easyrsa init-pki"
sudo docker exec -i $CONTAINER_NAME sh -c "cd /opt/amneziavpn_data && easyrsa gen-dh"
sudo docker exec -i $CONTAINER_NAME sh -c "cd /opt/amneziavpn_data && cp pki/dh.pem /etc/openvpn && easyrsa build-ca nopass << EOF yes EOF && easyrsa gen-req MyReq nopass << EOF2 yes EOF2"
sudo docker exec -i $CONTAINER_NAME sh -c "cd /opt/amneziavpn_data && easyrsa sign-req server MyReq << EOF3 yes EOF3"
sudo docker exec -i $CONTAINER_NAME sh -c "cd /opt/amneziavpn_data && openvpn --genkey --secret ta.key << EOF4"
sudo docker exec -i $CONTAINER_NAME sh -c "cd /opt/amneziavpn_data && cp pki/ca.crt pki/issued/MyReq.crt pki/private/MyReq.key ta.key /etc/openvpn"
sudo docker exec -d $CONTAINER_NAME sh -c "openvpn --config /etc/openvpn/server.conf"

View file

@ -1,29 +0,0 @@
# CONTAINER_NAME=... this var will be set in ServerController
# Don't run commands in background like sh -c "openvpn &"
pm_apt="/usr/bin/apt-get"; pm_yum="/usr/bin/yum"; if [[ -f "$pm_apt" ]]; then pm=$pm_apt; else pm=$pm_yum; fi; if [[ ! -f "/usr/bin/sudo" ]]; then $pm update -y -q; $pm install -y -q sudo; fi
sudo iptables -P FORWARD ACCEPT
pm_apt="/usr/bin/apt-get"; pm_yum="/usr/bin/yum"; if [[ -f "$pm_apt" ]]; then pm=$pm_apt; else pm=$pm_yum; fi; sudo $pm update -y -q
pm_apt="/usr/bin/apt-get"; pm_yum="/usr/bin/yum"; if [[ -f "$pm_apt" ]]; then pm=$pm_apt; else pm=$pm_yum; fi; sudo $pm install -y -q curl
pm_apt="/usr/bin/apt-get"; pm_yum="/usr/bin/yum"; if [[ -f "$pm_apt" ]]; then sudo export DEBIAN_FRONTEND=noninteractive; sudo $pm_apt install -y -q docker.io; else sudo $pm_yum install -y -q docker; fi
sudo systemctl start docker
sudo docker stop $CONTAINER_NAME
sudo docker rm -f $CONTAINER_NAME
sudo docker pull amneziavpn/shadowsocks:latest
sudo docker run -d --restart always --cap-add=NET_ADMIN -p 6789:6789/tcp --name $CONTAINER_NAME amneziavpn/shadowsocks:latest
# Prevent to route packets outside of the container in case if server behind of the NAT
sudo docker exec -i $CONTAINER_NAME sh -c "ifconfig eth0:0 $SERVER_IP_ADDRESS netmask 255.255.255.255 up"
# OpenVpn
sudo docker exec -i $CONTAINER_NAME bash -c 'mkdir -p /opt/amneziavpn_data/clients;\
cd /opt/amneziavpn_data && easyrsa init-pki;\
cd /opt/amneziavpn_data && easyrsa gen-dh;\
cd /opt/amneziavpn_data && cp pki/dh.pem /etc/openvpn && easyrsa build-ca nopass << EOF yes EOF && easyrsa gen-req MyReq nopass << EOF2 yes EOF2;\
cd /opt/amneziavpn_data && easyrsa sign-req server MyReq << EOF3 yes EOF3;\
cd /opt/amneziavpn_data && openvpn --genkey --secret ta.key << EOF4;\
cd /opt/amneziavpn_data && cp pki/ca.crt pki/issued/MyReq.crt pki/private/MyReq.key ta.key /etc/openvpn'
sudo docker exec -d $CONTAINER_NAME sh -c "openvpn --config /etc/openvpn/server.conf"

View file

@ -88,33 +88,112 @@ QString Settings::defaultContainerName(int serverIndex) const
else return name;
}
QMap<DockerContainer, QJsonObject> Settings::containers(int serverIndex) const
{
const QJsonArray &containers = server(serverIndex).value(config_key::containers).toArray();
QMap<DockerContainer, QJsonObject> containersMap;
for (const QJsonValue &val : containers) {
containersMap.insert(containerFromString(val.toObject().value(config_key::container).toString()), val.toObject());
}
return containersMap;
}
void Settings::setContainers(int serverIndex, const QMap<DockerContainer, QJsonObject> &containers)
{
QJsonObject s = server(serverIndex);
QJsonArray c;
for (const QJsonObject &o: containers) {
c.append(o);
}
s.insert(config_key::containers, c);
editServer(serverIndex, s);
}
QJsonObject Settings::containerConfig(int serverIndex, DockerContainer container)
{
if (container == DockerContainer::None) return QJsonObject();
const QJsonArray &containers = server(serverIndex).value(config_key::containers).toArray();
for (const QJsonValue &val : containers) {
if (val.toObject().value(config_key::container).toString() == containerToString(container)) {
return val.toObject();
}
}
return QJsonObject();
return containers(serverIndex).value(container);
}
//QJsonObject Settings::containerConfig(int serverIndex, DockerContainer container)
//{
// if (container == DockerContainer::None) return QJsonObject();
// const QJsonArray &containers = server(serverIndex).value(config_key::containers).toArray();
// for (const QJsonValue &val : containers) {
// if (val.toObject().value(config_key::container).toString() == containerToString(container)) {
// return val.toObject();
// }
// }
// return QJsonObject();
//}
void Settings::setContainerConfig(int serverIndex, DockerContainer container, const QJsonObject &config)
{
if (container == DockerContainer::None) return;
auto c = containers(serverIndex);
c[container] = config;
c[container][config_key::container] = containerToString(container);
setContainers(serverIndex, c);
}
void Settings::removeContainerConfig(int serverIndex, DockerContainer container)
{
if (container == DockerContainer::None) return;
auto c = containers(serverIndex);
c.remove(container);
setContainers(serverIndex, c);
}
//void Settings::setContainerConfig(int serverIndex, DockerContainer container, const QJsonObject &config)
//{
// if (container == DockerContainer::None) return;
// QJsonObject s = server(serverIndex);
// QJsonArray c = s.value(config_key::containers).toArray();
// for (int i = c.size() - 1; i >= 0; i--) {
// if (c.at(i).toObject().value(config_key::container).toString() == containerToString(container)) {
// c.removeAt(i);
// }
// }
// c.append(config);
// s.insert(config_key::containers, c);
// editServer(serverIndex, s);
//}
QJsonObject Settings::protocolConfig(int serverIndex, DockerContainer container, Protocol proto)
{
const QJsonObject &c = containerConfig(serverIndex, container);
return c.value(protoToString(proto)).toObject();
}
switch (proto) {
case Protocol::OpenVpn:
return c.value(config_key::openvpn).toObject();
case Protocol::ShadowSocks:
return c.value(config_key::shadowsocks).toObject();
case Protocol::Cloak:
return c.value(config_key::cloak).toObject();
default:
return QJsonObject();
void Settings::setProtocolConfig(int serverIndex, DockerContainer container, Protocol proto, const QJsonObject &config)
{
QJsonObject c = containerConfig(serverIndex, container);
c.insert(protoToString(proto), config);
setContainerConfig(serverIndex, container, c);
}
void Settings::clearLastConnectionConfig(int serverIndex, DockerContainer container, Protocol proto)
{
if (proto == Protocol::Any) {
for (Protocol p: { Protocol::OpenVpn, Protocol::ShadowSocks, Protocol::Cloak, Protocol::WireGuard}) {
clearLastConnectionConfig(serverIndex, container, p);
}
return;
}
QJsonObject c = protocolConfig(serverIndex, container, proto);
c.remove(config_key::last_config);
setProtocolConfig(serverIndex, container, proto, c);
qDebug() << "Settings::clearLastConnectionConfig for" << protoToString(proto);
}
bool Settings::haveAuthData() const
@ -127,7 +206,6 @@ bool Settings::haveAuthData() const
QString Settings::nextAvailableServerName() const
{
int i = 0;
//bool found = false;
bool nameExist = false;
do {

View file

@ -10,6 +10,7 @@
#include <QJsonObject>
#include "core/defs.h"
#include "protocols/protocols_defs.h"
using namespace amnezia;
@ -57,8 +58,17 @@ public:
DockerContainer defaultContainer(int serverIndex) const;
QString defaultContainerName(int serverIndex) const;
QMap<DockerContainer, QJsonObject> containers(int serverIndex) const;
void setContainers(int serverIndex, const QMap<DockerContainer, QJsonObject> &containers);
QJsonObject containerConfig(int serverIndex, DockerContainer container);
void setContainerConfig(int serverIndex, DockerContainer container, const QJsonObject &config);
void removeContainerConfig(int serverIndex, DockerContainer container);
QJsonObject protocolConfig(int serverIndex, DockerContainer container, Protocol proto);
void setProtocolConfig(int serverIndex, DockerContainer container, Protocol proto, const QJsonObject &config);
void clearLastConnectionConfig(int serverIndex, DockerContainer container, Protocol proto = Protocol::Any);
bool haveAuthData() const;
QString nextAvailableServerName() const;

View file

@ -1,5 +1,6 @@
#include <QApplication>
#include <QClipboard>
#include <QDebug>
#include <QDesktopServices>
#include <QHBoxLayout>
#include <QJsonDocument>
@ -115,11 +116,14 @@ MainWindow::MainWindow(QWidget *parent) :
m_ipAddressValidator.setRegExp(Utils::ipAddressRegExp());
m_ipAddressPortValidator.setRegExp(Utils::ipAddressPortRegExp());
m_ipNetwok24Validator.setRegExp(Utils::ipNetwork24RegExp());
ui->lineEdit_new_server_ip->setValidator(&m_ipAddressPortValidator);
ui->lineEdit_network_settings_dns1->setValidator(&m_ipAddressValidator);
ui->lineEdit_network_settings_dns2->setValidator(&m_ipAddressValidator);
ui->lineEdit_proto_openvpn_subnet->setValidator(&m_ipNetwok24Validator);
ui->toolBox_share_connection->removeItem(ui->toolBox_share_connection->indexOf(ui->page_share_shadowsocks));
ui->page_share_shadowsocks->setVisible(false);
}
@ -148,40 +152,28 @@ void MainWindow::goToPage(Page page, bool reset, bool slide)
qDebug() << "goToPage" << page;
if (reset) {
if (page == Page::ServerSettings) {
updateSettings();
ui->label_server_settings_wait_info->hide();
ui->label_server_settings_wait_info->clear();
QJsonObject server = m_settings.server(selectedServerIndex);
QString port = server.value(config_key::port).toString();
ui->label_server_settings_server->setText(QString("%1@%2%3%4")
.arg(server.value(config_key::userName).toString())
.arg(server.value(config_key::hostName).toString())
.arg(port.isEmpty() ? "" : ":")
.arg(port));
ui->lineEdit_server_settings_description->setText(server.value(config_key::description).toString());
updateServerPage();
}
if (page == Page::ShareConnection) {
QJsonObject ssConfig = ShadowSocksVpnProtocol::genShadowSocksConfig(m_settings.defaultServerCredentials());
// QJsonObject ssConfig = ShadowSocksVpnProtocol::genShadowSocksConfig(m_settings.defaultServerCredentials());
QString ssString = QString("%1:%2@%3:%4")
.arg(ssConfig.value("method").toString())
.arg(ssConfig.value("password").toString())
.arg(ssConfig.value("server").toString())
.arg(QString::number(ssConfig.value("server_port").toInt()));
// QString ssString = QString("%1:%2@%3:%4")
// .arg(ssConfig.value("method").toString())
// .arg(ssConfig.value("password").toString())
// .arg(ssConfig.value("server").toString())
// .arg(QString::number(ssConfig.value("server_port").toInt()));
ssString = "ss://" + ssString.toUtf8().toBase64();
ui->lineEdit_share_ss_string->setText(ssString);
updateQRCodeImage(ssString, ui->label_share_ss_qr_code);
// ssString = "ss://" + ssString.toUtf8().toBase64();
// ui->lineEdit_share_ss_string->setText(ssString);
// updateQRCodeImage(ssString, ui->label_share_ss_qr_code);
ui->label_share_ss_server->setText(ssConfig.value("server").toString());
ui->label_share_ss_port->setText(QString::number(ssConfig.value("server_port").toInt()));
ui->label_share_ss_method->setText(ssConfig.value("method").toString());
ui->label_share_ss_password->setText(ssConfig.value("password").toString());
// ui->label_share_ss_server->setText(ssConfig.value("server").toString());
// ui->label_share_ss_port->setText(QString::number(ssConfig.value("server_port").toInt()));
// ui->label_share_ss_method->setText(ssConfig.value("method").toString());
// ui->label_share_ss_password->setText(ssConfig.value("password").toString());
}
if (page == Page::ServersList) {
updateServersPage();
updateServersListPage();
}
if (page == Page::Start) {
ui->label_new_server_wait_info->hide();
@ -200,14 +192,26 @@ void MainWindow::goToPage(Page page, bool reset, bool slide)
ui->pushButton_new_server_settings_openvpn->setChecked(true);
ui->pushButton_new_server_settings_openvpn->setChecked(false);
ui->lineEdit_new_server_cloak_port->setText(amnezia::protocols::cloak::ckDefaultPort);
ui->lineEdit_new_server_cloak_site->setText(amnezia::protocols::cloak::ckDefaultRedirSite);
ui->lineEdit_new_server_cloak_port->setText(amnezia::protocols::cloak::defaultPort);
ui->lineEdit_new_server_cloak_site->setText(amnezia::protocols::cloak::defaultRedirSite);
ui->lineEdit_new_server_ss_port->setText(amnezia::protocols::shadowsocks::ssDefaultPort);
ui->comboBox_new_server_ss_cipher->setCurrentText(amnezia::protocols::shadowsocks::ssDefaultCipher);
ui->lineEdit_new_server_ss_port->setText(amnezia::protocols::shadowsocks::defaultPort);
ui->comboBox_new_server_ss_cipher->setCurrentText(amnezia::protocols::shadowsocks::defaultCipher);
ui->lineEdit_new_server_openvpn_port->setText(amnezia::protocols::openvpn::openvpnDefaultPort);
ui->comboBox_new_server_openvpn_proto->setCurrentText(amnezia::protocols::openvpn::openvpnDefaultProto);
ui->lineEdit_new_server_openvpn_port->setText(amnezia::protocols::openvpn::defaultPort);
ui->comboBox_new_server_openvpn_proto->setCurrentText(amnezia::protocols::openvpn::defaultTransportProto);
}
if (page == Page::ServerVpnProtocols) {
updateProtocolsPage();
}
if (page == Page::AppSettings) {
updateAppSettingsPage();
}
if (page == Page::Sites) {
updateSitesPage();
}
if (page == Page::Vpn) {
updateVpnPage();
}
ui->pushButton_new_server_connect_key->setChecked(false);
@ -424,23 +428,23 @@ void MainWindow::onPushButtonNewServerConnectConfigure(bool)
{
QJsonObject cloakConfig {
{ config_key::port, ui->lineEdit_new_server_cloak_port->text() },
{ config_key::container, amnezia::server::getContainerName(DockerContainer::OpenVpnOverCloak) },
{ config_key::container, amnezia::containerToString(DockerContainer::OpenVpnOverCloak) },
{ config_key::cloak, QJsonObject {
{ config_key::site, ui->lineEdit_new_server_cloak_site->text() }}
}
};
QJsonObject ssConfig {
{ config_key::port, ui->lineEdit_new_server_ss_port->text() },
{ config_key::container, amnezia::server::getContainerName(DockerContainer::ShadowSocksOverOpenVpn) },
{ config_key::container, amnezia::containerToString(DockerContainer::OpenVpnOverShadowSocks) },
{ config_key::shadowsocks, QJsonObject {
{ config_key::cipher, ui->comboBox_new_server_ss_cipher->currentText() }}
}
};
QJsonObject openVpnConfig {
{ config_key::port, ui->lineEdit_new_server_openvpn_port->text() },
{ config_key::container, amnezia::server::getContainerName(DockerContainer::OpenVpn) },
{ config_key::container, amnezia::containerToString(DockerContainer::OpenVpn) },
{ config_key::openvpn, QJsonObject {
{ config_key::transport_protocol, ui->comboBox_new_server_openvpn_proto->currentText() }}
{ config_key::transport_proto, ui->comboBox_new_server_openvpn_proto->currentText() }}
}
};
@ -454,20 +458,20 @@ void MainWindow::onPushButtonNewServerConnectConfigure(bool)
if (ui->checkBox_new_server_ss->isChecked()) {
containerConfigs.append(ssConfig);
containers.append(DockerContainer::ShadowSocksOverOpenVpn);
containers.append(DockerContainer::OpenVpnOverShadowSocks);
}
if (ui->checkBox_new_server_openvpn->isChecked()) {
containerConfigs.append(openVpnConfig);
containers.append(DockerContainer::ShadowSocksOverOpenVpn);
containers.append(DockerContainer::OpenVpnOverShadowSocks);
}
bool ok = true;
// bool ok = installServer(installCredentials, containers, configs,
// ui->page_new_server,
// ui->progressBar_new_server_connection,
// ui->pushButton_new_server_connect,
// ui->label_new_server_wait_info);
// bool ok = true;
bool ok = installServer(installCredentials, containers, containerConfigs,
ui->page_new_server_2,
ui->progressBar_new_server_connection,
ui->pushButton_new_server_connect,
ui->label_new_server_wait_info);
if (ok) {
QJsonObject server;
@ -587,6 +591,69 @@ bool MainWindow::installServer(ServerCredentials credentials,
return true;
}
ErrorCode MainWindow::doInstallAction(const std::function<ErrorCode()> &action, QWidget *page, QProgressBar *progress, QPushButton *button, QLabel *info)
{
progress->show();
if (page) page->setEnabled(false);
if (button) button->setVisible(false);
if (info) info->setVisible(true);
if (info) info->setText(tr("Please wait, configuring process may take up to 5 minutes"));
QTimer timer;
connect(&timer, &QTimer::timeout, [progress](){
progress->setValue(progress->value() + 1);
});
progress->setValue(0);
timer.start(1000);
ErrorCode e = action();
qDebug() << "doInstallAction finished with code" << e;
if (e) {
if (page) page->setEnabled(true);
if (button) button->setVisible(true);
if (info) info->setVisible(false);
QMessageBox::warning(this, APPLICATION_NAME,
tr("Error occurred while configuring server.") + "\n" +
errorString(e));
progress->hide();
return e;
}
// just ui progressbar tweak
timer.stop();
int remaining_val = progress->maximum() - progress->value();
if (remaining_val > 0) {
QTimer timer1;
QEventLoop loop1;
connect(&timer1, &QTimer::timeout, [&](){
progress->setValue(progress->value() + 1);
if (progress->value() >= progress->maximum()) {
loop1.quit();
}
});
timer1.start(5);
loop1.exec();
}
progress->hide();
if (button) button->show();
if (page) page->setEnabled(true);
if (info) info->setText(tr("Operation finished"));
return ErrorCode::NoError;
}
void MainWindow::onPushButtonReinstallServer(bool)
{
// onDisconnect();
@ -606,7 +673,7 @@ void MainWindow::onPushButtonClearServer(bool)
onDisconnect();
}
ErrorCode e = ServerController::removeContainer(m_settings.serverCredentials(selectedServerIndex), DockerContainer::None);
ErrorCode e = ServerController::removeAllContainers(m_settings.serverCredentials(selectedServerIndex));
ServerController::disconnectFromHost(m_settings.serverCredentials(selectedServerIndex));
if (e) {
QMessageBox::warning(this, APPLICATION_NAME,
@ -630,9 +697,10 @@ void MainWindow::onPushButtonForgetServer(bool)
onDisconnect();
}
m_settings.removeServer(selectedServerIndex);
m_settings.setDefaultServer(0);
closePage();
updateServersPage();
updateServersListPage();
}
void MainWindow::onBytesChanged(quint64 receivedData, quint64 sentData)
@ -877,7 +945,7 @@ void MainWindow::setupUiConnections()
QJsonObject server = m_settings.server(selectedServerIndex);
server.insert(config_key::description, newText);
m_settings.editServer(selectedServerIndex, server);
updateServersPage();
updateServersListPage();
});
connect(ui->lineEdit_server_settings_description, &QLineEdit::returnPressed, this, [this](){
@ -890,32 +958,128 @@ void MainWindow::setupUiConnections()
void MainWindow::setupProtocolsPageConnections()
{
QJsonObject openvpnConfig;
// default buttons
QList<DockerContainer> containers {
DockerContainer::OpenVpn,
DockerContainer::OpenVpnOverShadowSocks,
DockerContainer::OpenVpnOverCloak
};
// default buttons
QList<QPushButton *> defaultButtons {
ui->pushButton_proto_openvpn_cont_default,
ui->pushButton_proto_ss_openvpn_cont_default,
ui->pushButton_proto_cloak_openvpn_cont_default
};
for (int i = 0; i < containers.size(); ++i) {
connect(defaultButtons.at(i), &QPushButton::clicked, this, [this, containers, i](){
m_settings.setDefaultContainer(selectedServerIndex, containers.at(i));
updateProtocolsPage();
});
}
// install buttons
QList<QPushButton *> installButtons {
ui->pushButton_proto_openvpn_cont_install,
ui->pushButton_proto_ss_openvpn_cont_install,
ui->pushButton_proto_cloak_openvpn_cont_install
};
for (int i = 0; i < containers.size(); ++i) {
QPushButton *button = installButtons.at(i);
DockerContainer container = containers.at(i);
connect(button, &QPushButton::clicked, this, [this, container, button](bool checked){
if (checked) {
ErrorCode e = doInstallAction([this, container](){
return ServerController::setupContainer(m_settings.serverCredentials(selectedServerIndex), container);
},
ui->page_server_protocols, ui->progressBar_protocols_container_reinstall,
nullptr, nullptr);
if (!e) {
m_settings.setContainerConfig(selectedServerIndex, container, QJsonObject());
}
}
else {
button->setEnabled(false);
ErrorCode e = ServerController::removeContainer(m_settings.serverCredentials(selectedServerIndex), container);
m_settings.removeContainerConfig(selectedServerIndex, container);
button->setEnabled(true);
}
updateProtocolsPage();
});
}
// settings buttons
// settings openvpn container
connect(ui->pushButton_proto_openvpn_cont_openvpn_config, &QPushButton::clicked, this, [this](){
//updateOpenVpnPage(m_settings.server(selectedServerIndex).value());
updateOpenVpnPage(m_settings.protocolConfig(selectedServerIndex, DockerContainer::OpenVpn, Protocol::OpenVpn));
selectedDockerContainer = DockerContainer::OpenVpn;
goToPage(Page::OpenVpnSettings);
});
// settings shadowsocks container
connect(ui->pushButton_proto_ss_openvpn_cont_openvpn_config, &QPushButton::clicked, this, [this](){
updateOpenVpnPage(m_settings.protocolConfig(selectedServerIndex, DockerContainer::OpenVpnOverShadowSocks, Protocol::OpenVpn),
DockerContainer::OpenVpnOverShadowSocks);
selectedDockerContainer = DockerContainer::OpenVpnOverShadowSocks;
goToPage(Page::OpenVpnSettings);
});
connect(ui->pushButton_proto_ss_openvpn_cont_ss_config, &QPushButton::clicked, this, [this](){
updateOpenVpnPage(m_settings.protocolConfig(selectedServerIndex, DockerContainer::OpenVpnOverShadowSocks, Protocol::ShadowSocks));
selectedDockerContainer = DockerContainer::OpenVpnOverShadowSocks;
goToPage(Page::ShadowSocksSettings);
});
// settings cloak container
connect(ui->pushButton_proto_cloak_openvpn_cont_openvpn_config, &QPushButton::clicked, this, [this](){
updateOpenVpnPage(m_settings.protocolConfig(selectedServerIndex, DockerContainer::OpenVpnOverCloak, Protocol::OpenVpn));
selectedDockerContainer = DockerContainer::OpenVpnOverCloak;
goToPage(Page::OpenVpnSettings);
});
connect(ui->pushButton_proto_cloak_openvpn_cont_default, &QPushButton::clicked, this, [this](){
m_settings.setDefaultContainer(selectedServerIndex, DockerContainer::OpenVpnOverCloak);
updateSettings();
connect(ui->pushButton_proto_cloak_openvpn_cont_ss_config, &QPushButton::clicked, this, [this](){
updateOpenVpnPage(m_settings.protocolConfig(selectedServerIndex, DockerContainer::OpenVpnOverCloak, Protocol::ShadowSocks));
selectedDockerContainer = DockerContainer::OpenVpnOverCloak;
goToPage(Page::ShadowSocksSettings);
});
connect(ui->pushButton_proto_cloak_openvpn_cont_cloak_config, &QPushButton::clicked, this, [this](){
updateOpenVpnPage(m_settings.protocolConfig(selectedServerIndex, DockerContainer::OpenVpnOverCloak, Protocol::Cloak));
selectedDockerContainer = DockerContainer::OpenVpnOverCloak;
goToPage(Page::CloakSettings);
});
connect(ui->pushButton_proto_ss_openvpn_cont_default, &QPushButton::clicked, this, [this](){
m_settings.setDefaultContainer(selectedServerIndex, DockerContainer::ShadowSocksOverOpenVpn);
updateSettings();
///
// Protocols pages
connect(ui->checkBox_proto_openvpn_auto_encryption, &QCheckBox::stateChanged, this, [this](){
ui->comboBox_proto_openvpn_cipher->setDisabled(ui->checkBox_proto_openvpn_auto_encryption->isChecked());
ui->comboBox_proto_openvpn_hash->setDisabled(ui->checkBox_proto_openvpn_auto_encryption->isChecked());
});
connect(ui->pushButton_proto_openvpn_cont_default, &QPushButton::clicked, this, [this](){
m_settings.setDefaultContainer(selectedServerIndex, DockerContainer::OpenVpn);
updateSettings();
});
connect(ui->pushButton_proto_openvpn_save, &QPushButton::clicked, this, [this](){
QJsonObject protocolConfig = m_settings.protocolConfig(selectedServerIndex, selectedDockerContainer, Protocol::OpenVpn);
protocolConfig = getOpenVpnConfigFromPage(protocolConfig);
QJsonObject containerConfig = m_settings.containerConfig(selectedServerIndex, selectedDockerContainer);
QJsonObject newContainerConfig = containerConfig;
newContainerConfig.insert(config_key::openvpn, protocolConfig);
ErrorCode e = doInstallAction([this, containerConfig, newContainerConfig](){
return ServerController::updateContainer(m_settings.serverCredentials(selectedServerIndex), selectedDockerContainer, containerConfig, newContainerConfig);
},
ui->page_proto_openvpn, ui->progressBar_proto_openvpn_reset,
ui->pushButton_proto_openvpn_save, ui->label_proto_openvpn_info);
if (!e) {
m_settings.setContainerConfig(selectedServerIndex, selectedDockerContainer, newContainerConfig);
m_settings.clearLastConnectionConfig(selectedServerIndex, selectedDockerContainer);
}
});
}
void MainWindow::setupNewServerPageConnections()
@ -1019,15 +1183,23 @@ void MainWindow::onTrayActivated(QSystemTrayIcon::ActivationReason reason)
}
void MainWindow::onConnect()
{
int serverIndex = m_settings.defaultServerIndex();
ServerCredentials credentials = m_settings.serverCredentials(serverIndex);
DockerContainer container = m_settings.defaultContainer(serverIndex);
const QJsonObject &containerConfig = m_settings.containerConfig(serverIndex, container);
onConnectWorker(serverIndex, credentials, container, containerConfig);
}
void MainWindow::onConnectWorker(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig)
{
ui->label_error_text->clear();
ui->pushButton_connect->setChecked(true);
qApp->processEvents();
// TODO: Call connectToVpn with restricted server account
ServerCredentials credentials = m_settings.defaultServerCredentials();
ErrorCode errorCode = m_vpnConnection->connectToVpn(credentials);
ErrorCode errorCode = m_vpnConnection->connectToVpn(serverIndex, credentials, container, containerConfig);
if (errorCode) {
//ui->pushButton_connect->setChecked(false);
QMessageBox::critical(this, APPLICATION_NAME, errorString(errorCode));
@ -1121,34 +1293,56 @@ void MainWindow::onPushButtonDeleteCustomSiteClicked(const QString &siteToDelete
}
void MainWindow::updateSettings()
{
}
void MainWindow::updateSitesPage()
{
ui->listWidget_sites->clear();
for (const QString &site : m_settings.customSites()) {
makeSitesListItem(ui->listWidget_sites, site);
}
}
void MainWindow::updateVpnPage()
{
ui->radioButton_mode_selected_sites->setChecked(m_settings.customRouting());
ui->pushButton_vpn_add_site->setEnabled(m_settings.customRouting());
}
void MainWindow::updateAppSettingsPage()
{
ui->checkBox_autostart->setChecked(Autostart::isAutostart());
ui->checkBox_autoconnect->setChecked(m_settings.isAutoConnect());
ui->lineEdit_network_settings_dns1->setText(m_settings.primaryDns());
ui->lineEdit_network_settings_dns2->setText(m_settings.secondaryDns());
}
ui->listWidget_sites->clear();
for(const QString &site : m_settings.customSites()) {
makeSitesListItem(ui->listWidget_sites, site);
}
void MainWindow::updateServerPage()
{
ui->label_server_settings_wait_info->hide();
ui->label_server_settings_wait_info->clear();
QJsonObject server = m_settings.server(selectedServerIndex);
QString port = server.value(config_key::port).toString();
ui->label_server_settings_server->setText(QString("%1@%2%3%4")
.arg(server.value(config_key::userName).toString())
.arg(server.value(config_key::hostName).toString())
.arg(port.isEmpty() ? "" : ":")
.arg(port));
ui->lineEdit_server_settings_description->setText(server.value(config_key::description).toString());
QJsonObject selectedServer = m_settings.server(selectedServerIndex);
QString selectedContainerName = m_settings.defaultContainerName(selectedServerIndex);
ui->label_server_settings_current_vpn_protocol->setText(tr("Protocol: ") + selectedContainerName);
qDebug() << "DefaultContainer(selectedServerIndex)" << selectedServerIndex << m_settings.defaultContainer(selectedServerIndex);
ui->pushButton_proto_cloak_openvpn_cont_default->setChecked(m_settings.defaultContainer(selectedServerIndex) == DockerContainer::OpenVpnOverCloak);
ui->pushButton_proto_ss_openvpn_cont_default->setChecked(m_settings.defaultContainer(selectedServerIndex) == DockerContainer::ShadowSocksOverOpenVpn);
ui->pushButton_proto_openvpn_cont_default->setChecked(m_settings.defaultContainer(selectedServerIndex) == DockerContainer::OpenVpn);
//qDebug() << "DefaultContainer(selectedServerIndex)" << selectedServerIndex << containerToString(m_settings.defaultContainer(selectedServerIndex));
}
void MainWindow::updateServersPage()
void MainWindow::updateServersListPage()
{
ui->listWidget_servers->clear();
const QJsonArray &servers = m_settings.serversArray();
@ -1161,6 +1355,34 @@ void MainWindow::updateServersPage()
ui->listWidget_servers->setUpdatesEnabled(true);
}
void MainWindow::updateProtocolsPage()
{
ui->progressBar_protocols_container_reinstall->hide();
auto containers = m_settings.containers(selectedServerIndex);
DockerContainer defaultContainer = m_settings.defaultContainer(selectedServerIndex);
ui->pushButton_proto_cloak_openvpn_cont_default->setChecked(defaultContainer == DockerContainer::OpenVpnOverCloak);
ui->pushButton_proto_ss_openvpn_cont_default->setChecked(defaultContainer == DockerContainer::OpenVpnOverShadowSocks);
ui->pushButton_proto_openvpn_cont_default->setChecked(defaultContainer == DockerContainer::OpenVpn);
ui->pushButton_proto_cloak_openvpn_cont_default->setVisible(containers.contains(DockerContainer::OpenVpnOverCloak));
ui->pushButton_proto_ss_openvpn_cont_default->setVisible(containers.contains(DockerContainer::OpenVpnOverShadowSocks));
ui->pushButton_proto_openvpn_cont_default->setVisible(containers.contains(DockerContainer::OpenVpn));
ui->pushButton_proto_cloak_openvpn_cont_share->setVisible(containers.contains(DockerContainer::OpenVpnOverCloak));
ui->pushButton_proto_ss_openvpn_cont_share->setVisible(containers.contains(DockerContainer::OpenVpnOverShadowSocks));
ui->pushButton_proto_openvpn_cont_share->setVisible(containers.contains(DockerContainer::OpenVpn));
ui->pushButton_proto_cloak_openvpn_cont_install->setChecked(containers.contains(DockerContainer::OpenVpnOverCloak));
ui->pushButton_proto_ss_openvpn_cont_install->setChecked(containers.contains(DockerContainer::OpenVpnOverShadowSocks));
ui->pushButton_proto_openvpn_cont_install->setChecked(containers.contains(DockerContainer::OpenVpn));
ui->frame_openvpn_ss_cloak_settings->setVisible(containers.contains(DockerContainer::OpenVpnOverCloak));
ui->frame_openvpn_ss_settings->setVisible(containers.contains(DockerContainer::OpenVpnOverShadowSocks));
ui->frame_openvpn_settings->setVisible(containers.contains(DockerContainer::OpenVpn));
}
void MainWindow::updateShareCodePage()
{
// QJsonObject o;
@ -1175,22 +1397,37 @@ void MainWindow::updateShareCodePage()
//qDebug() << "Share code" << QJsonDocument(o).toJson();
}
void MainWindow::updateOpenVpnPage(const QJsonObject &openvpnConfig)
{
ui->lineEdit_proto_openvpn_subnet->setText(nonEmpty(openvpnConfig.value(config_key::subnet_address).toString(),
protocols::vpnDefaultSubnetAddress));
void MainWindow::updateOpenVpnPage(const QJsonObject &openvpnConfig, DockerContainer container)
{
ui->radioButton_proto_openvpn_udp->setEnabled(true);
ui->radioButton_proto_openvpn_tcp->setEnabled(true);
QString trasnsport = nonEmpty(openvpnConfig.value(config_key::transport_protocol).toString(),
protocols::openvpn::openvpnDefaultProto);
ui->lineEdit_proto_openvpn_subnet->setText(openvpnConfig.value(config_key::subnet_address).
toString(protocols::vpnDefaultSubnetAddress));
ui->radioButton_proto_openvpn_udp->setChecked(trasnsport == protocols::openvpn::openvpnDefaultProto);
ui->radioButton_proto_openvpn_tcp->setChecked(trasnsport != protocols::openvpn::openvpnDefaultProto);
QString trasnsport = openvpnConfig.value(config_key::transport_proto).
toString(protocols::openvpn::defaultTransportProto);
ui->comboBox_proto_openvpn_cipher->setCurrentText(nonEmpty(openvpnConfig.value(config_key::cipher).toString(),
protocols::openvpn::openvpnDefaultCipher));
ui->radioButton_proto_openvpn_udp->setChecked(trasnsport == protocols::openvpn::defaultTransportProto);
ui->radioButton_proto_openvpn_tcp->setChecked(trasnsport != protocols::openvpn::defaultTransportProto);
ui->comboBox_proto_openvpn_cipher->setCurrentText(nonEmpty(openvpnConfig.value(config_key::hash).toString(),
protocols::openvpn::openvpnDefaultHash));
ui->comboBox_proto_openvpn_cipher->setCurrentText(openvpnConfig.value(config_key::cipher).
toString(protocols::openvpn::defaultCipher));
ui->comboBox_proto_openvpn_hash->setCurrentText(openvpnConfig.value(config_key::hash).
toString(protocols::openvpn::defaultHash));
bool blockOutsideDns = openvpnConfig.value(config_key::block_outside_dns).toBool(protocols::openvpn::defaultBlockOutsideDns);
ui->checkBox_proto_openvpn_block_dns->setChecked(blockOutsideDns);
bool isNcpDisabled = openvpnConfig.value(config_key::ncp_disable).toBool(protocols::openvpn::defaultNcpDisable);
ui->checkBox_proto_openvpn_auto_encryption->setChecked(!isNcpDisabled);
if (container == DockerContainer::OpenVpnOverShadowSocks) {
ui->radioButton_proto_openvpn_udp->setEnabled(false);
ui->radioButton_proto_openvpn_tcp->setEnabled(false);
ui->radioButton_proto_openvpn_tcp->setChecked(true);
}
}
void MainWindow::makeSitesListItem(QListWidget *listWidget, const QString &address)
@ -1232,7 +1469,7 @@ void MainWindow::makeServersListItem(QListWidget *listWidget, const QJsonObject
connect(widget->ui->pushButton_default, &QPushButton::clicked, this, [this, index](){
m_settings.setDefaultServer(index);
updateSettings();
updateServersPage();
updateServersListPage();
});
connect(widget->ui->pushButton_share, &QPushButton::clicked, this, [this, index](){
@ -1275,3 +1512,15 @@ void MainWindow::updateQRCodeImage(const QString &text, QLabel *label)
label->setPixmap(QPixmap::fromImage(encodeImage.scaledToWidth(label->width())));
}
QJsonObject MainWindow::getOpenVpnConfigFromPage(QJsonObject oldConfig)
{
oldConfig.insert(config_key::subnet_address, ui->lineEdit_proto_openvpn_subnet->text());
oldConfig.insert(config_key::transport_proto, ui->radioButton_proto_openvpn_udp->isChecked() ? protocols::UDP : protocols::TCP);
oldConfig.insert(config_key::ncp_disable, ! ui->checkBox_proto_openvpn_auto_encryption->isChecked());
oldConfig.insert(config_key::cipher, ui->comboBox_proto_openvpn_cipher->currentText());
oldConfig.insert(config_key::hash, ui->comboBox_proto_openvpn_hash->currentText());
oldConfig.insert(config_key::block_outside_dns, ui->checkBox_proto_openvpn_block_dns->isChecked());
return oldConfig;
}

View file

@ -68,6 +68,7 @@ private slots:
void onTrayActivated(QSystemTrayIcon::ActivationReason reason);
void onConnect();
void onConnectWorker(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig);
void onDisconnect();
@ -81,6 +82,8 @@ private:
bool installServer(ServerCredentials credentials, QList<DockerContainer> containers, QJsonArray configs,
QWidget *page, QProgressBar *progress, QPushButton *button, QLabel *info);
ErrorCode doInstallAction(const std::function<ErrorCode()> &action, QWidget *page, QProgressBar *progress, QPushButton *button, QLabel *info);
void setupTray();
void setTrayIcon(const QString &iconPath);
@ -89,15 +92,23 @@ private:
void setupNewServerPageConnections();
void updateSettings();
void updateServersPage();
void updateSitesPage();
void updateVpnPage();
void updateAppSettingsPage();
void updateServerPage();
void updateServersListPage();
void updateProtocolsPage();
void updateShareCodePage();
void updateOpenVpnPage(const QJsonObject &openvpnConfig);
void updateOpenVpnPage(const QJsonObject &openvpnConfig, DockerContainer container = DockerContainer::None);
void makeSitesListItem(QListWidget* listWidget, const QString &address);
void makeServersListItem(QListWidget* listWidget, const QJsonObject &server, bool isDefault, int index);
void updateQRCodeImage(const QString &text, QLabel *label);
QJsonObject getOpenVpnConfigFromPage(QJsonObject oldConfig);
private:
Ui::MainWindow *ui;
VpnConnection* m_vpnConnection;
@ -111,6 +122,7 @@ private:
QRegExpValidator m_ipAddressValidator;
QRegExpValidator m_ipAddressPortValidator;
QRegExpValidator m_ipNetwok24Validator;
CQR_Encode m_qrEncode;
@ -129,6 +141,7 @@ private:
QStack<Page> pagesStack;
int selectedServerIndex = -1; // server index to use when proto settings page opened
DockerContainer selectedDockerContainer; // same
ServerCredentials installCredentials; // used to save cred between pages new_server and new_server_2
};

File diff suppressed because it is too large Load diff

View file

@ -27,6 +27,9 @@ public:
static QRegExp ipAddressPortRegExp() { return QRegExp("^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}"
"(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(\\:[0-9]{1,5}){0,1}$"); }
static QRegExp ipNetwork24RegExp() { return QRegExp("^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}"
"0$"); }
static bool processIsRunning(const QString& fileName);
static void killProcessByName(const QString &name);

View file

@ -5,6 +5,7 @@
#include <configurators/openvpn_configurator.h>
#include <configurators/cloak_configurator.h>
#include <configurators/shadowsocks_configurator.h>
#include <core/servercontroller.h>
#include "ipc.h"
@ -80,11 +81,78 @@ ErrorCode VpnConnection::lastError() const
return m_vpnProtocol.data()->lastError();
}
ErrorCode VpnConnection::createVpnConfiguration(const ServerCredentials &credentials, DockerContainer container)
QMap<Protocol, QString> VpnConnection::getLastVpnConfig(const QJsonObject &containerConfig)
{
QMap<Protocol, QString> configs;
for (Protocol proto: { Protocol::OpenVpn,
Protocol::ShadowSocks,
Protocol::Cloak,
Protocol::WireGuard}) {
QString cfg = containerConfig.value(protoToString(proto)).toObject().value(config_key::last_config).toString();
if (!cfg.isEmpty()) configs.insert(proto, cfg);
}
return configs;
}
QString VpnConnection::createVpnConfigurationForProto(int serverIndex,
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, Protocol proto,
ErrorCode *errorCode)
{
ErrorCode e = ErrorCode::NoError;
auto lastVpnConfig = getLastVpnConfig(containerConfig);
QString configData;
if (lastVpnConfig.contains(proto)) {
configData = lastVpnConfig.value(proto);
qDebug() << "VpnConnection::createVpnConfiguration using saved config for " << protoToString(proto);
}
else {
if (proto == Protocol::OpenVpn) {
configData = OpenVpnConfigurator::genOpenVpnConfig(credentials,
container, containerConfig, &e);
}
else if (proto == Protocol::Cloak) {
configData = CloakConfigurator::genCloakConfig(credentials,
container, containerConfig, &e);
}
else if (proto == Protocol::ShadowSocks) {
configData = ShadowSocksConfigurator::genShadowSocksConfig(credentials,
container, containerConfig, &e);
}
if (errorCode && e) {
*errorCode = e;
return "";
}
if (serverIndex >= 0) {
QJsonObject protoObject = m_settings.protocolConfig(serverIndex, container, proto);
protoObject.insert(config_key::last_config, configData);
m_settings.setProtocolConfig(serverIndex, container, proto, protoObject);
}
}
if (errorCode) *errorCode = e;
return configData;
}
ErrorCode VpnConnection::createVpnConfiguration(int serverIndex,
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig)
{
ErrorCode errorCode = ErrorCode::NoError;
if (container == DockerContainer::OpenVpn || container == DockerContainer::ShadowSocksOverOpenVpn || container == DockerContainer::OpenVpnOverCloak) {
QString openVpnConfigData = OpenVpnConfigurator::genOpenVpnConfig(credentials, container, &errorCode);
if (container == DockerContainer::OpenVpn ||
container == DockerContainer::OpenVpnOverShadowSocks ||
container == DockerContainer::OpenVpnOverCloak) {
QString openVpnConfigData =
createVpnConfigurationForProto(
serverIndex, credentials, container, containerConfig, Protocol::OpenVpn, &errorCode);
m_vpnConfiguration.insert(config::key_openvpn_config_data, openVpnConfigData);
if (errorCode) {
return errorCode;
@ -101,13 +169,21 @@ ErrorCode VpnConnection::createVpnConfiguration(const ServerCredentials &credent
}
}
if (container == DockerContainer::ShadowSocksOverOpenVpn) {
QJsonObject ssConfigData = ShadowSocksVpnProtocol::genShadowSocksConfig(credentials);
if (container == DockerContainer::OpenVpnOverShadowSocks) {
QJsonObject ssConfigData = QJsonDocument::fromJson(
createVpnConfigurationForProto(
serverIndex, credentials, container, containerConfig, Protocol::ShadowSocks, &errorCode).toUtf8()).
object();
m_vpnConfiguration.insert(config::key_shadowsocks_config_data, ssConfigData);
}
if (container == DockerContainer::OpenVpnOverCloak) {
QJsonObject cloakConfigData = CloakConfigurator::genCloakConfig(credentials, DockerContainer::OpenVpnOverCloak, &errorCode);
QJsonObject cloakConfigData = QJsonDocument::fromJson(
createVpnConfigurationForProto(
serverIndex, credentials, container, containerConfig, Protocol::Cloak, &errorCode).toUtf8()).
object();
m_vpnConfiguration.insert(config::key_cloak_config_data, cloakConfigData);
}
@ -115,17 +191,9 @@ ErrorCode VpnConnection::createVpnConfiguration(const ServerCredentials &credent
return ErrorCode::NoError;
}
ErrorCode VpnConnection::connectToVpn(const ServerCredentials &credentials, DockerContainer container)
ErrorCode VpnConnection::connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig)
{
qDebug() << "connectToVpn, CustomRouting is" << m_settings.customRouting();
// qDebug() << "Cred" << m_settings.serverCredentials().hostName <<
// m_settings.serverCredentials().password;
//protocol = Protocol::ShadowSocks;
container = DockerContainer::OpenVpnOverCloak;
// 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";
qDebug() << "СonnectToVpn, CustomRouting is" << m_settings.customRouting();
emit connectionStateChanged(VpnProtocol::ConnectionState::Connecting);
@ -133,13 +201,10 @@ ErrorCode VpnConnection::connectToVpn(const ServerCredentials &credentials, Dock
disconnect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
m_vpnProtocol->stop();
m_vpnProtocol.reset();
//m_vpnProtocol->deleteLater();
}
//qApp->processEvents();
if (container == DockerContainer::None || container == DockerContainer::OpenVpn) {
ErrorCode e = createVpnConfiguration(credentials, DockerContainer::OpenVpn);
ErrorCode e = createVpnConfiguration(serverIndex, credentials, DockerContainer::OpenVpn, containerConfig);
if (e) {
emit connectionStateChanged(VpnProtocol::ConnectionState::Error);
return e;
@ -152,8 +217,8 @@ ErrorCode VpnConnection::connectToVpn(const ServerCredentials &credentials, Dock
return e;
}
}
else if (container == DockerContainer::ShadowSocksOverOpenVpn) {
ErrorCode e = createVpnConfiguration(credentials, DockerContainer::ShadowSocksOverOpenVpn);
else if (container == DockerContainer::OpenVpnOverShadowSocks) {
ErrorCode e = createVpnConfiguration(serverIndex, credentials, DockerContainer::OpenVpnOverShadowSocks, containerConfig);
if (e) {
emit connectionStateChanged(VpnProtocol::ConnectionState::Error);
return e;
@ -167,7 +232,7 @@ ErrorCode VpnConnection::connectToVpn(const ServerCredentials &credentials, Dock
}
}
else if (container == DockerContainer::OpenVpnOverCloak) {
ErrorCode e = createVpnConfiguration(credentials, DockerContainer::OpenVpnOverCloak);
ErrorCode e = createVpnConfiguration(serverIndex, credentials, DockerContainer::OpenVpnOverCloak, containerConfig);
if (e) {
emit connectionStateChanged(VpnProtocol::ConnectionState::Error);
return e;

View file

@ -24,9 +24,16 @@ public:
static QString bytesPerSecToText(quint64 bytes);
ErrorCode lastError() const;
ErrorCode createVpnConfiguration(const ServerCredentials &credentials, DockerContainer container);
ErrorCode connectToVpn(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None);
static QMap<Protocol, QString> getLastVpnConfig(const QJsonObject &containerConfig);
QString createVpnConfigurationForProto(int serverIndex,
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, Protocol proto,
ErrorCode *errorCode = nullptr);
ErrorCode createVpnConfiguration(int serverIndex,
const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig);
ErrorCode connectToVpn(int serverIndex, const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig);
void disconnectFromVpn();
bool isConnected() const;