- no dockerhub
- trafic masking
This commit is contained in:
parent
059c6404ab
commit
85b6b06cc9
31 changed files with 1106 additions and 256 deletions
|
@ -13,14 +13,19 @@ include("3rd/QRCodeGenerator/QRCodeGenerator.pri")
|
|||
|
||||
HEADERS += \
|
||||
../ipc/ipc.h \
|
||||
configurators/cloak_configurator.h \
|
||||
core/defs.h \
|
||||
core/errorstrings.h \
|
||||
core/ipcclient.h \
|
||||
core/openvpnconfigurator.h \
|
||||
configurators/openvpn_configurator.h \
|
||||
core/scripts_registry.h \
|
||||
core/server_defs.h \
|
||||
core/servercontroller.h \
|
||||
debug.h \
|
||||
defines.h \
|
||||
managementserver.h \
|
||||
protocols/openvpnovercloakprotocol.h \
|
||||
protocols/protocols_defs.h \
|
||||
protocols/shadowsocksvpnprotocol.h \
|
||||
settings.h \
|
||||
ui/Controls/SlidingStackedWidget.h \
|
||||
|
@ -32,12 +37,16 @@ HEADERS += \
|
|||
protocols/openvpnprotocol.h \
|
||||
|
||||
SOURCES += \
|
||||
configurators/cloak_configurator.cpp \
|
||||
core/ipcclient.cpp \
|
||||
core/openvpnconfigurator.cpp \
|
||||
configurators/openvpn_configurator.cpp \
|
||||
core/scripts_registry.cpp \
|
||||
core/server_defs.cpp \
|
||||
core/servercontroller.cpp \
|
||||
debug.cpp \
|
||||
main.cpp \
|
||||
managementserver.cpp \
|
||||
protocols/openvpnovercloakprotocol.cpp \
|
||||
protocols/shadowsocksvpnprotocol.cpp \
|
||||
settings.cpp \
|
||||
ui/Controls/SlidingStackedWidget.cpp \
|
||||
|
|
45
client/configurators/cloak_configurator.cpp
Normal file
45
client/configurators/cloak_configurator.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include "cloak_configurator.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "protocols/protocols_defs.h"
|
||||
|
||||
QJsonObject CloakConfigurator::genCloakConfig(const ServerCredentials &credentials,
|
||||
Protocol proto, ErrorCode *errorCode)
|
||||
{
|
||||
ErrorCode e = ErrorCode::NoError;
|
||||
|
||||
DockerContainer container = amnezia::containerForProto(proto);
|
||||
|
||||
QString cloakPublicKey = ServerController::getTextFileFromContainer(container, credentials,
|
||||
amnezia::protocols::cloak::ckPublicKeyPath(), &e);
|
||||
cloakPublicKey.replace("\n", "");
|
||||
|
||||
QString cloakBypassUid = ServerController::getTextFileFromContainer(container, credentials,
|
||||
amnezia::protocols::cloak::ckBypassUidKeyPath(), &e);
|
||||
cloakBypassUid.replace("\n", "");
|
||||
|
||||
if (e) {
|
||||
if (errorCode) *errorCode = e;
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
QJsonObject config;
|
||||
config.insert("Transport", "direct");
|
||||
config.insert("ProxyMethod", "openvpn");
|
||||
config.insert("EncryptionMethod", "aes-gcm");
|
||||
config.insert("UID", cloakBypassUid);
|
||||
config.insert("PublicKey", cloakPublicKey);
|
||||
config.insert("ServerName", amnezia::protocols::cloak::ckDefaultRedirSite());
|
||||
config.insert("NumConn", 4);
|
||||
config.insert("BrowserSig", "chrome");
|
||||
config.insert("StreamTimeout", 300);
|
||||
|
||||
// Amnezia field
|
||||
config.insert("Remote", credentials.hostName);
|
||||
|
||||
qDebug().noquote() << QJsonDocument(config).toJson();
|
||||
return config;
|
||||
}
|
18
client/configurators/cloak_configurator.h
Normal file
18
client/configurators/cloak_configurator.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef CLOAK_CONFIGURATOR_H
|
||||
#define CLOAK_CONFIGURATOR_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "core/defs.h"
|
||||
#include "settings.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
class CloakConfigurator
|
||||
{
|
||||
public:
|
||||
|
||||
static QJsonObject genCloakConfig(const ServerCredentials &credentials, Protocol proto,
|
||||
ErrorCode *errorCode = nullptr);
|
||||
};
|
||||
|
||||
#endif // CLOAK_CONFIGURATOR_H
|
|
@ -1,24 +1,15 @@
|
|||
#include "openvpnconfigurator.h"
|
||||
#include "openvpn_configurator.h"
|
||||
#include <QApplication>
|
||||
#include <QProcess>
|
||||
#include <QString>
|
||||
#include <QRandomGenerator>
|
||||
#include <QTemporaryDir>
|
||||
#include <QDebug>
|
||||
#include <QTemporaryFile>
|
||||
#include <utils.h>
|
||||
|
||||
QString OpenVpnConfigurator::getRandomString(int len)
|
||||
{
|
||||
const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
||||
|
||||
QString randomString;
|
||||
for(int i=0; i<len; ++i) {
|
||||
quint32 index = QRandomGenerator::global()->generate() % possibleCharacters.length();
|
||||
QChar nextChar = possibleCharacters.at(index);
|
||||
randomString.append(nextChar);
|
||||
}
|
||||
return randomString;
|
||||
}
|
||||
#include "core/server_defs.h"
|
||||
#include "protocols/protocols_defs.h"
|
||||
#include "core/scripts_registry.h"
|
||||
|
||||
QString OpenVpnConfigurator::getEasyRsaShPath()
|
||||
{
|
||||
|
@ -26,17 +17,10 @@ QString OpenVpnConfigurator::getEasyRsaShPath()
|
|||
// easyrsa sh path should looks like
|
||||
// "/Program Files (x86)/AmneziaVPN/easyrsa/easyrsa"
|
||||
QString easyRsaShPath = QDir::toNativeSeparators(QApplication::applicationDirPath()) + "\\easyrsa\\easyrsa";
|
||||
// easyRsaShPath.replace("C:\\", "/cygdrive/c/");
|
||||
// easyRsaShPath.replace("\\", "/");
|
||||
easyRsaShPath = "\"" + easyRsaShPath + "\"";
|
||||
|
||||
// easyRsaShPath = "\"/cygdrive/c/Program Files (x86)/AmneziaVPN/easyrsa/easyrsa\"";
|
||||
|
||||
// easyRsaShPath = "\"C:\\Program Files (x86)\\AmneziaVPN\\easyrsa\\easyrsa\"";
|
||||
qDebug().noquote() << "EasyRsa sh path" << easyRsaShPath;
|
||||
|
||||
return easyRsaShPath;
|
||||
// return "\"/Program Files (x86)/AmneziaVPN/easyrsa/easyrsa\"";
|
||||
#else
|
||||
return QDir::toNativeSeparators(QApplication::applicationDirPath()) + "/easyrsa";
|
||||
#endif
|
||||
|
@ -126,7 +110,7 @@ ErrorCode OpenVpnConfigurator::genReq(const QString &path, const QString &client
|
|||
OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::createCertRequest()
|
||||
{
|
||||
OpenVpnConfigurator::ConnectionData connData;
|
||||
connData.clientId = getRandomString(32);
|
||||
connData.clientId = Utils::getRandomString(32);
|
||||
|
||||
QTemporaryDir dir;
|
||||
// if (dir.isValid()) {
|
||||
|
@ -165,15 +149,11 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
|
|||
return connData;
|
||||
}
|
||||
|
||||
QString reqFileName = QString("/opt/amneziavpn_data/clients/%1.req").arg(connData.clientId);
|
||||
QString reqFileName = QString("%1/%2.req").
|
||||
arg(amnezia::protocols::openvpn::clientsDirPath()).
|
||||
arg(connData.clientId);
|
||||
|
||||
DockerContainer container;
|
||||
if (proto == Protocol::OpenVpn) container = DockerContainer::OpenVpn;
|
||||
else if (proto == Protocol::ShadowSocks) container = DockerContainer::ShadowSocks;
|
||||
else {
|
||||
if (errorCode) *errorCode = ErrorCode::InternalError;
|
||||
return connData;
|
||||
}
|
||||
DockerContainer container = amnezia::containerForProto(proto);
|
||||
|
||||
ErrorCode e = ServerController::uploadTextFileToContainer(container, credentials, connData.request, reqFileName);
|
||||
if (e) {
|
||||
|
@ -181,20 +161,22 @@ OpenVpnConfigurator::ConnectionData OpenVpnConfigurator::prepareOpenVpnConfig(co
|
|||
return connData;
|
||||
}
|
||||
|
||||
e = ServerController::signCert(container, credentials, connData.clientId);
|
||||
e = signCert(container, credentials, connData.clientId);
|
||||
if (e) {
|
||||
if (errorCode) *errorCode = e;
|
||||
return connData;
|
||||
}
|
||||
|
||||
connData.caCert = ServerController::getTextFileFromContainer(container, credentials, ServerController::caCertPath(), &e);
|
||||
connData.clientCert = ServerController::getTextFileFromContainer(container, credentials, ServerController::clientCertPath() + QString("%1.crt").arg(connData.clientId), &e);
|
||||
connData.caCert = ServerController::getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::caCertPath(), &e);
|
||||
connData.clientCert = ServerController::getTextFileFromContainer(container, credentials,
|
||||
QString("%1/%2.crt").arg(amnezia::protocols::openvpn::clientCertPath()).arg(connData.clientId), &e);
|
||||
|
||||
if (e) {
|
||||
if (errorCode) *errorCode = e;
|
||||
return connData;
|
||||
}
|
||||
|
||||
connData.taKey = ServerController::getTextFileFromContainer(container, credentials, ServerController::taKeyPath(), &e);
|
||||
connData.taKey = ServerController::getTextFileFromContainer(container, credentials, amnezia::protocols::openvpn::taKeyPath(), &e);
|
||||
|
||||
if (connData.caCert.isEmpty() || connData.clientCert.isEmpty() || connData.taKey.isEmpty()) {
|
||||
if (errorCode) *errorCode = ErrorCode::RemoteProcessCrashError;
|
||||
|
@ -214,23 +196,31 @@ Settings &OpenVpnConfigurator::m_settings()
|
|||
QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentials,
|
||||
Protocol proto, 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");
|
||||
}
|
||||
// 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();
|
||||
// configTemplFile.open(QIODevice::ReadOnly);
|
||||
// QString config = configTemplFile.readAll();
|
||||
|
||||
QString config = amnezia::scriptData(ProtocolScriptType::openvpn_template, proto);
|
||||
|
||||
ConnectionData connData = prepareOpenVpnConfig(credentials, proto, errorCode);
|
||||
if (errorCode && *errorCode) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (proto == Protocol::OpenVpn)
|
||||
config.replace("$PROTO", "udp");
|
||||
else if (proto == Protocol::ShadowSocks) {
|
||||
config.replace("$PROTO", "tcp");
|
||||
config.replace("$LOCAL_PROXY_PORT", QString::number(ServerController::ssContainerPort()));
|
||||
config.replace("$LOCAL_PROXY_PORT", QString::number(amnezia::protocols::shadowsocks::ssContainerPort()));
|
||||
}
|
||||
else if (proto == Protocol::OpenVpnOverCloak) {
|
||||
config.replace("$PROTO", "tcp");
|
||||
}
|
||||
|
||||
config.replace("$PRIMARY_DNS", m_settings().primaryDns());
|
||||
|
@ -241,7 +231,7 @@ QString OpenVpnConfigurator::genOpenVpnConfig(const ServerCredentials &credentia
|
|||
}
|
||||
|
||||
config.replace("$REMOTE_HOST", connData.host);
|
||||
config.replace("$REMOTE_PORT", "1194");
|
||||
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);
|
||||
|
@ -287,3 +277,23 @@ QString OpenVpnConfigurator::convertOpenSShKey(const QString &key)
|
|||
|
||||
return tmp.readAll();
|
||||
}
|
||||
|
||||
ErrorCode OpenVpnConfigurator::signCert(DockerContainer container,
|
||||
const ServerCredentials &credentials, QString clientId)
|
||||
{
|
||||
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::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(clientId);
|
||||
|
||||
QStringList scriptList {script_import, script_sign};
|
||||
QString script = ServerController::replaceVars(scriptList.join("\n"), ServerController::genVarsForScript(credentials, container));
|
||||
|
||||
return ServerController::runScript(ServerController::sshParams(credentials), script);
|
||||
}
|
|
@ -1,13 +1,12 @@
|
|||
#ifndef OPENVPNCONFIGURATOR_H
|
||||
#define OPENVPNCONFIGURATOR_H
|
||||
#ifndef OPENVPN_CONFIGURATOR_H
|
||||
#define OPENVPN_CONFIGURATOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcessEnvironment>
|
||||
|
||||
#include "defs.h"
|
||||
#include "core/defs.h"
|
||||
#include "settings.h"
|
||||
#include "servercontroller.h"
|
||||
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
class OpenVpnConfigurator
|
||||
{
|
||||
|
@ -28,8 +27,10 @@ public:
|
|||
|
||||
static QString convertOpenSShKey(const QString &key);
|
||||
|
||||
static ErrorCode signCert(DockerContainer container,
|
||||
const ServerCredentials &credentials, QString clientId);
|
||||
|
||||
private:
|
||||
static QString getRandomString(int len);
|
||||
static QString getEasyRsaShPath();
|
||||
|
||||
static QProcessEnvironment prepareEnv();
|
||||
|
@ -44,4 +45,4 @@ private:
|
|||
static Settings &m_settings();
|
||||
};
|
||||
|
||||
#endif // OPENVPNCONFIGURATOR_H
|
||||
#endif // OPENVPN_CONFIGURATOR_H
|
|
@ -9,15 +9,31 @@ enum class Protocol {
|
|||
Any,
|
||||
OpenVpn,
|
||||
ShadowSocks,
|
||||
OpenVpnOverCloak,
|
||||
WireGuard
|
||||
};
|
||||
|
||||
enum class DockerContainer {
|
||||
None,
|
||||
OpenVpn,
|
||||
ShadowSocks,
|
||||
OpenVpnOverCloak,
|
||||
WireGuard
|
||||
};
|
||||
|
||||
static DockerContainer containerForProto(Protocol proto)
|
||||
{
|
||||
Q_ASSERT(proto != Protocol::Any);
|
||||
|
||||
switch (proto) {
|
||||
case Protocol::OpenVpn: return DockerContainer::OpenVpn;
|
||||
case Protocol::OpenVpnOverCloak: return DockerContainer::OpenVpnOverCloak;
|
||||
case Protocol::ShadowSocks: return DockerContainer::ShadowSocks;
|
||||
case Protocol::WireGuard: return DockerContainer::WireGuard;
|
||||
case Protocol::Any: return DockerContainer::None;
|
||||
}
|
||||
}
|
||||
|
||||
struct ServerCredentials
|
||||
{
|
||||
QString hostName;
|
||||
|
@ -48,6 +64,7 @@ enum ErrorCode
|
|||
// Ssh remote process errors
|
||||
SshRemoteProcessCreationError,
|
||||
FailedToStartRemoteProcessError, RemoteProcessCrashError,
|
||||
SshSftpError,
|
||||
|
||||
// Local errors
|
||||
FailedToSaveConfigData,
|
||||
|
@ -59,6 +76,7 @@ enum ErrorCode
|
|||
OpenVpnExecutableMissing,
|
||||
EasyRsaExecutableMissing,
|
||||
ShadowSocksExecutableMissing,
|
||||
CloakExecutableMissing,
|
||||
AmneziaServiceConnectionFailed,
|
||||
|
||||
// VPN errors
|
||||
|
@ -67,7 +85,8 @@ enum ErrorCode
|
|||
|
||||
// 3rd party utils errors
|
||||
OpenVpnExecutableCrashed,
|
||||
ShadowSocksExecutableCrashed
|
||||
ShadowSocksExecutableCrashed,
|
||||
CloakExecutableCrashed
|
||||
};
|
||||
|
||||
namespace config {
|
||||
|
@ -75,10 +94,10 @@ namespace config {
|
|||
static QString key_openvpn_config_data() { return "openvpn_config_data"; }
|
||||
static QString key_openvpn_config_path() { return "openvpn_config_path"; }
|
||||
static QString key_shadowsocks_config_data() { return "shadowsocks_config_data"; }
|
||||
static QString key_cloak_config_data() { return "cloak_config_data"; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace amnezia
|
||||
|
||||
#endif // DEFS_H
|
||||
|
|
60
client/core/scripts_registry.cpp
Normal file
60
client/core/scripts_registry.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include "scripts_registry.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
|
||||
QString amnezia::scriptFolder(amnezia::Protocol proto)
|
||||
{
|
||||
switch (proto) {
|
||||
case Protocol::OpenVpn: return QLatin1String("openvpn");
|
||||
case Protocol::OpenVpnOverCloak: return QLatin1String("openvpn_cloak");
|
||||
case Protocol::ShadowSocks: return QLatin1String("openvpn_shadowsocks");
|
||||
case Protocol::WireGuard: return QLatin1String("wireguard");
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
QString amnezia::scriptName(SharedScriptType type)
|
||||
{
|
||||
switch (type) {
|
||||
case SharedScriptType::prepare_host: return QLatin1String("prepare_host.sh");
|
||||
case SharedScriptType::install_docker: return QLatin1String("install_docker.sh");
|
||||
case SharedScriptType::build_container: return QLatin1String("build_container.sh");
|
||||
case SharedScriptType::setup_host_firewall: return QLatin1String("setup_host_firewall.sh");
|
||||
}
|
||||
}
|
||||
|
||||
QString amnezia::scriptName(ProtocolScriptType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ProtocolScriptType::dockerfile: return QLatin1String("Dockerfile");
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
QString amnezia::scriptData(amnezia::SharedScriptType type)
|
||||
{
|
||||
QString fileName = QString(":/server_scripts/%1").arg(amnezia::scriptName(type));
|
||||
QFile file(fileName);
|
||||
if (! file.open(QIODevice::ReadOnly)) {
|
||||
qDebug() << "Error opening script" << fileName;
|
||||
return "";
|
||||
}
|
||||
return file.readAll();
|
||||
}
|
||||
|
||||
QString amnezia::scriptData(amnezia::ProtocolScriptType type, amnezia::Protocol proto)
|
||||
{
|
||||
QString fileName = QString(":/server_scripts/%1/%2").arg(amnezia::scriptFolder(proto), amnezia::scriptName(type));
|
||||
QFile file(fileName);
|
||||
if (! file.open(QIODevice::ReadOnly)) {
|
||||
qDebug() << "Error opening script" << fileName;
|
||||
return "";
|
||||
}
|
||||
QByteArray data = file.readAll();
|
||||
data.replace("\r", "");
|
||||
return data;
|
||||
}
|
34
client/core/scripts_registry.h
Normal file
34
client/core/scripts_registry.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef SCRIPTS_REGISTRY_H
|
||||
#define SCRIPTS_REGISTRY_H
|
||||
|
||||
#include <QLatin1String>
|
||||
#include "core/defs.h"
|
||||
|
||||
namespace amnezia {
|
||||
|
||||
enum SharedScriptType {
|
||||
// General scripts
|
||||
prepare_host,
|
||||
install_docker,
|
||||
build_container,
|
||||
setup_host_firewall,
|
||||
};
|
||||
enum ProtocolScriptType {
|
||||
// Protocol scripts
|
||||
dockerfile,
|
||||
configure_container,
|
||||
container_startup,
|
||||
openvpn_template
|
||||
};
|
||||
|
||||
|
||||
QString scriptFolder(Protocol proto);
|
||||
|
||||
QString scriptName(SharedScriptType type);
|
||||
QString scriptName(ProtocolScriptType type);
|
||||
|
||||
QString scriptData(SharedScriptType type);
|
||||
QString scriptData(ProtocolScriptType type, Protocol proto);
|
||||
}
|
||||
|
||||
#endif // SCRIPTS_REGISTRY_H
|
16
client/core/server_defs.cpp
Normal file
16
client/core/server_defs.cpp
Normal file
|
@ -0,0 +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::ShadowSocks): return "amnezia-shadowsocks";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
QString amnezia::server::getDockerfileFolder(amnezia::DockerContainer container)
|
||||
{
|
||||
return "/opt/amnezia/" + getContainerName(container);
|
||||
}
|
19
client/core/server_defs.h
Normal file
19
client/core/server_defs.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef SERVER_DEFS_H
|
||||
#define SERVER_DEFS_H
|
||||
|
||||
#include <QObject>
|
||||
#include "core/defs.h"
|
||||
|
||||
namespace amnezia {
|
||||
namespace server {
|
||||
QString getContainerName(amnezia::DockerContainer container);
|
||||
QString getDockerfileFolder(amnezia::DockerContainer container);
|
||||
|
||||
static QString vpnDefaultSubnetIp() { return "10.8.0.0"; }
|
||||
static QString vpnDefaultSubnetMask() { return "255.255.255.0"; }
|
||||
static QString vpnDefaultSubnetMaskVal() { return "24"; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SERVER_DEFS_H
|
|
@ -9,24 +9,20 @@
|
|||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QApplication>
|
||||
#include <QTemporaryFile>
|
||||
|
||||
#include "sftpchannel.h"
|
||||
#include "sshconnectionmanager.h"
|
||||
|
||||
#include "protocols/protocols_defs.h"
|
||||
#include "server_defs.h"
|
||||
#include "scripts_registry.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
using namespace QSsh;
|
||||
|
||||
QString ServerController::getContainerName(DockerContainer container)
|
||||
{
|
||||
switch (container) {
|
||||
case(DockerContainer::OpenVpn): return "amnezia-openvpn";
|
||||
case(DockerContainer::ShadowSocks): return "amnezia-shadowsocks";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode ServerController::runScript(const QHash<QString, QString> &vars,
|
||||
const SshConnectionParameters &sshParams, QString script,
|
||||
ErrorCode ServerController::runScript(const SshConnectionParameters &sshParams, QString script,
|
||||
const std::function<void(const QString &, QSharedPointer<SshRemoteProcess>)> &cbReadStdOut,
|
||||
const std::function<void(const QString &, QSharedPointer<SshRemoteProcess>)> &cbReadStdErr)
|
||||
{
|
||||
|
@ -39,21 +35,36 @@ ErrorCode ServerController::runScript(const QHash<QString, QString> &vars,
|
|||
|
||||
qDebug() << "Run script";
|
||||
|
||||
QString totalLine;
|
||||
const QStringList &lines = script.split("\n", QString::SkipEmptyParts);
|
||||
for (int i = 0; i < lines.count(); i++) {
|
||||
QString line = lines.at(i);
|
||||
QString currentLine = lines.at(i);
|
||||
QString nextLine;
|
||||
if (i + 1 < lines.count()) nextLine = lines.at(i+1);
|
||||
|
||||
for (const QString &var : vars.keys()) {
|
||||
//qDebug() << "Replacing" << var << vars.value(var);
|
||||
line.replace(var, vars.value(var));
|
||||
if (totalLine.isEmpty()) {
|
||||
totalLine = currentLine;
|
||||
}
|
||||
else {
|
||||
totalLine = totalLine + "\n" + currentLine;
|
||||
}
|
||||
|
||||
if (line.startsWith("#")) {
|
||||
QString lineToExec;
|
||||
if (currentLine.endsWith("\\")) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
lineToExec = totalLine;
|
||||
totalLine.clear();
|
||||
}
|
||||
|
||||
// Run collected line
|
||||
if (totalLine.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
qDebug().noquote() << "EXEC" << line;
|
||||
QSharedPointer<SshRemoteProcess> proc = client->createRemoteProcess(line.toUtf8());
|
||||
qDebug().noquote() << "EXEC" << lineToExec;
|
||||
QSharedPointer<SshRemoteProcess> proc = client->createRemoteProcess(lineToExec.toUtf8());
|
||||
|
||||
if (!proc) {
|
||||
qCritical() << "Failed to create SshRemoteProcess, breaking.";
|
||||
|
@ -103,61 +114,106 @@ ErrorCode ServerController::runScript(const QHash<QString, QString> &vars,
|
|||
return ErrorCode::NoError;
|
||||
}
|
||||
|
||||
ErrorCode ServerController::uploadTextFileToContainer(DockerContainer container,
|
||||
const ServerCredentials &credentials, QString &file, const QString &path)
|
||||
ErrorCode ServerController::installDocker(const ServerCredentials &credentials)
|
||||
{
|
||||
QString script = QString("sudo docker exec -i %1 sh -c \"echo \'%2\' > %3\"").
|
||||
arg(getContainerName(container)).arg(file).arg(path);
|
||||
// Setup openvpn part
|
||||
QString scriptData = amnezia::scriptData(SharedScriptType::install_docker);
|
||||
if (scriptData.isEmpty()) return ErrorCode::InternalError;
|
||||
|
||||
// qDebug().noquote() << "uploadTextFileToContainer\n" << script;
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
|
||||
stdOut += data + "\n";
|
||||
|
||||
SshConnection *client = connectToHost(sshParams(credentials));
|
||||
if (client->state() != SshConnection::State::Connected) {
|
||||
return fromSshConnectionErrorCode(client->errorState());
|
||||
if (data.contains("Automatically restart Docker daemon?")) {
|
||||
proc->write("yes\n");
|
||||
}
|
||||
};
|
||||
auto cbReadStdErr = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> ) {
|
||||
stdOut += data + "\n";
|
||||
};
|
||||
|
||||
QSharedPointer<SshRemoteProcess> proc = client->createRemoteProcess(script.toUtf8());
|
||||
return runScript(sshParams(credentials),
|
||||
replaceVars(scriptData, genVarsForScript(credentials, DockerContainer::OpenVpnOverCloak)),
|
||||
cbReadStdOut, cbReadStdErr);
|
||||
}
|
||||
|
||||
if (!proc) {
|
||||
qCritical() << "Failed to create SshRemoteProcess, breaking.";
|
||||
return ErrorCode::SshRemoteProcessCreationError;
|
||||
}
|
||||
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);
|
||||
|
||||
QEventLoop wait;
|
||||
int exitStatus = -1;
|
||||
e = runScript(sshParams(credentials),
|
||||
replaceVars(QString("sudo docker cp %1 $CONTAINER_NAME:/%2").arg(tmpFileName).arg(path),
|
||||
genVarsForScript(credentials, container)));
|
||||
|
||||
// QObject::connect(proc.data(), &SshRemoteProcess::started, &wait, [](){
|
||||
// qDebug() << "uploadTextFileToContainer started";
|
||||
if (e) return e;
|
||||
|
||||
runScript(sshParams(credentials),
|
||||
replaceVars(QString("sudo shred %1").arg(tmpFileName),
|
||||
genVarsForScript(credentials, container)));
|
||||
|
||||
runScript(sshParams(credentials),
|
||||
replaceVars(QString("sudo rm %1").arg(tmpFileName),
|
||||
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::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::readyReadStandardOutput, [proc](){
|
||||
qDebug().noquote() << proc->readAllStandardOutput();
|
||||
});
|
||||
// QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, [proc](){
|
||||
// qDebug().noquote() << proc->readAllStandardError();
|
||||
// });
|
||||
|
||||
QObject::connect(proc.data(), &SshRemoteProcess::readyReadStandardError, [proc](){
|
||||
qDebug().noquote() << proc->readAllStandardError();
|
||||
});
|
||||
// proc->start();
|
||||
|
||||
proc->start();
|
||||
// if (exitStatus < 0) {
|
||||
// wait.exec();
|
||||
// }
|
||||
|
||||
if (exitStatus < 0) {
|
||||
wait.exec();
|
||||
}
|
||||
|
||||
return fromSshProcessExitStatus(exitStatus);
|
||||
// return fromSshProcessExitStatus(exitStatus);
|
||||
}
|
||||
|
||||
QString ServerController::getTextFileFromContainer(DockerContainer container,
|
||||
const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode)
|
||||
{
|
||||
if (errorCode) *errorCode = ErrorCode::NoError;
|
||||
|
||||
QString script = QString("sudo docker exec -i %1 sh -c \"cat \'%2\'\"").
|
||||
arg(getContainerName(container)).arg(path);
|
||||
arg(amnezia::server::getContainerName(container)).arg(path);
|
||||
|
||||
qDebug().noquote() << "Copy file from container\n" << script;
|
||||
|
||||
|
@ -201,28 +257,12 @@ QString ServerController::getTextFileFromContainer(DockerContainer container,
|
|||
return proc->readAllStandardOutput();
|
||||
}
|
||||
|
||||
ErrorCode ServerController::signCert(DockerContainer container,
|
||||
const ServerCredentials &credentials, QString clientId)
|
||||
{
|
||||
QString script_import = QString("sudo docker exec -i %1 bash -c \"cd /opt/amneziavpn_data && "
|
||||
"easyrsa import-req /opt/amneziavpn_data/clients/%2.req %2\"")
|
||||
.arg(getContainerName(container)).arg(clientId);
|
||||
|
||||
QString script_sign = QString("sudo docker exec -i %1 bash -c \"export EASYRSA_BATCH=1; cd /opt/amneziavpn_data && "
|
||||
"easyrsa sign-req client %2\"")
|
||||
.arg(getContainerName(container)).arg(clientId);
|
||||
|
||||
QStringList script {script_import, script_sign};
|
||||
|
||||
return runScript(genVarsForScript(credentials, container), sshParams(credentials), script.join("\n"));
|
||||
}
|
||||
|
||||
ErrorCode ServerController::checkOpenVpnServer(DockerContainer container, const ServerCredentials &credentials)
|
||||
{
|
||||
QString caCert = ServerController::getTextFileFromContainer(container,
|
||||
credentials, ServerController::caCertPath());
|
||||
credentials, amnezia::protocols::openvpn::caCertPath());
|
||||
QString taKey = ServerController::getTextFileFromContainer(container,
|
||||
credentials, ServerController::taKeyPath());
|
||||
credentials, amnezia::protocols::openvpn::taKeyPath());
|
||||
|
||||
if (!caCert.isEmpty() && !taKey.isEmpty()) {
|
||||
return ErrorCode::NoError;
|
||||
|
@ -232,6 +272,68 @@ ErrorCode ServerController::checkOpenVpnServer(DockerContainer container, const
|
|||
}
|
||||
}
|
||||
|
||||
ErrorCode ServerController::uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath)
|
||||
{
|
||||
SshConnection *client = connectToHost(sshParams(credentials));
|
||||
if (client->state() != SshConnection::State::Connected) {
|
||||
return fromSshConnectionErrorCode(client->errorState());
|
||||
}
|
||||
|
||||
bool err = false;
|
||||
|
||||
QEventLoop wait;
|
||||
QTimer timer;
|
||||
timer.setSingleShot(true);
|
||||
timer.start(3000);
|
||||
|
||||
QSharedPointer<SftpChannel> sftp = client->createSftpChannel();
|
||||
sftp->initialize();
|
||||
|
||||
QObject::connect(sftp.data(), &SftpChannel::initialized, &wait, [&](){
|
||||
timer.stop();
|
||||
wait.quit();
|
||||
});
|
||||
QObject::connect(&timer, &QTimer::timeout, &wait, [&](){
|
||||
err= true;
|
||||
wait.quit();
|
||||
});
|
||||
|
||||
wait.exec();
|
||||
|
||||
if (!sftp) {
|
||||
qCritical() << "Failed to create SftpChannel, breaking.";
|
||||
return ErrorCode::SshRemoteProcessCreationError;
|
||||
}
|
||||
|
||||
QTemporaryFile localFile;
|
||||
localFile.open();
|
||||
localFile.write(data);
|
||||
localFile.close();
|
||||
|
||||
auto job = sftp->uploadFile(localFile.fileName(), remotePath, QSsh::SftpOverwriteMode::SftpOverwriteExisting);
|
||||
QObject::connect(sftp.data(), &SftpChannel::finished, &wait, [&](QSsh::SftpJobId j, const QString &error){
|
||||
if (job == j) {
|
||||
qDebug() << "Sftp finished with status" << error;
|
||||
wait.quit();
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(sftp.data(), &SftpChannel::channelError, &wait, [&](const QString &reason){
|
||||
qDebug() << "Sftp finished with error" << reason;
|
||||
err= true;
|
||||
wait.quit();
|
||||
});
|
||||
|
||||
wait.exec();
|
||||
|
||||
if (err) {
|
||||
return ErrorCode::SshSftpError;
|
||||
}
|
||||
else {
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
}
|
||||
|
||||
ErrorCode ServerController::fromSshConnectionErrorCode(SshError error)
|
||||
{
|
||||
switch (error) {
|
||||
|
@ -311,11 +413,16 @@ ErrorCode ServerController::removeServer(const ServerCredentials &credentials, P
|
|||
scriptData = file.readAll();
|
||||
if (scriptData.isEmpty()) return ErrorCode::InternalError;
|
||||
|
||||
return runScript(genVarsForScript(credentials, container), sshParams(credentials), scriptData);
|
||||
return runScript(sshParams(credentials), replaceVars(scriptData, genVarsForScript(credentials, container)));
|
||||
}
|
||||
|
||||
ErrorCode ServerController::setupServer(const ServerCredentials &credentials, Protocol proto)
|
||||
{
|
||||
ErrorCode e = runScript(sshParams(credentials),
|
||||
replaceVars(amnezia::scriptData(SharedScriptType::install_docker),
|
||||
genVarsForScript(credentials)));
|
||||
if (e) return e;
|
||||
|
||||
if (proto == Protocol::OpenVpn) {
|
||||
return ErrorCode::NoError;
|
||||
//return setupOpenVpnServer(credentials);
|
||||
|
@ -326,9 +433,9 @@ ErrorCode ServerController::setupServer(const ServerCredentials &credentials, Pr
|
|||
else if (proto == Protocol::Any) {
|
||||
//return ErrorCode::NotImplementedError;
|
||||
|
||||
// TODO: run concurently
|
||||
//setupOpenVpnServer(credentials);
|
||||
return setupShadowSocksServer(credentials);
|
||||
//return setupShadowSocksServer(credentials);
|
||||
return setupOpenVpnOverCloakServer(credentials);
|
||||
}
|
||||
|
||||
return ErrorCode::NoError;
|
||||
|
@ -336,100 +443,177 @@ ErrorCode ServerController::setupServer(const ServerCredentials &credentials, Pr
|
|||
|
||||
ErrorCode ServerController::setupOpenVpnServer(const ServerCredentials &credentials)
|
||||
{
|
||||
QString scriptData;
|
||||
QString scriptFileName = ":/server_scripts/setup_openvpn_server.sh";
|
||||
QFile file(scriptFileName);
|
||||
if (! file.open(QIODevice::ReadOnly)) return ErrorCode::InternalError;
|
||||
return ErrorCode::NotImplementedError;
|
||||
|
||||
scriptData = file.readAll();
|
||||
// QString scriptData;
|
||||
// QString scriptFileName = ":/server_scripts/setup_openvpn_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::OpenVpn), sshParams(credentials), scriptData, cbReadStdOut, cbReadStdErr);
|
||||
// if (e) return e;
|
||||
// QApplication::processEvents();
|
||||
|
||||
// if (stdOut.contains("port is already allocated")) return ErrorCode::ServerPortAlreadyAllocatedError;
|
||||
// if (stdOut.contains("Error response from daemon")) return ErrorCode::ServerCheckFailed;
|
||||
|
||||
// return checkOpenVpnServer(DockerContainer::OpenVpn, credentials);
|
||||
}
|
||||
|
||||
ErrorCode ServerController::setupOpenVpnOverCloakServer(const ServerCredentials &credentials)
|
||||
{
|
||||
ErrorCode e;
|
||||
DockerContainer container = DockerContainer::OpenVpnOverCloak;
|
||||
|
||||
// create folder on host
|
||||
e = runScript(sshParams(credentials),
|
||||
replaceVars(amnezia::scriptData(SharedScriptType::prepare_host),
|
||||
genVarsForScript(credentials, container)));
|
||||
if (e) return e;
|
||||
|
||||
uploadFileToHost(credentials, amnezia::scriptData(ProtocolScriptType::dockerfile, Protocol::OpenVpnOverCloak).toUtf8(),
|
||||
amnezia::server::getDockerfileFolder(container) + "/Dockerfile");
|
||||
|
||||
|
||||
// Setup openvpn part
|
||||
QString scriptData = amnezia::scriptData(SharedScriptType::build_container);
|
||||
if (scriptData.isEmpty()) return ErrorCode::InternalError;
|
||||
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
|
||||
stdOut += data + "\n";
|
||||
// QString stdOut;
|
||||
// auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
|
||||
// stdOut += data + "\n";
|
||||
// };
|
||||
// auto cbReadStdErr = [&](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 = runScript(sshParams(credentials),
|
||||
replaceVars(scriptData,
|
||||
genVarsForScript(credentials, container)));
|
||||
if (e) return e;
|
||||
QApplication::processEvents();
|
||||
|
||||
if (stdOut.contains("port is already allocated")) return ErrorCode::ServerPortAlreadyAllocatedError;
|
||||
if (stdOut.contains("Error response from daemon")) return ErrorCode::ServerCheckFailed;
|
||||
|
||||
return checkOpenVpnServer(DockerContainer::OpenVpn, credentials);
|
||||
runScript(sshParams(credentials),
|
||||
replaceVars(amnezia::scriptData(ProtocolScriptType::configure_container, Protocol::OpenVpnOverCloak),
|
||||
genVarsForScript(credentials, container)));
|
||||
if (e) return e;
|
||||
|
||||
uploadTextFileToContainer(DockerContainer::OpenVpnOverCloak, credentials,
|
||||
replaceVars(amnezia::scriptData(ProtocolScriptType::container_startup, Protocol::OpenVpnOverCloak),
|
||||
genVarsForScript(credentials, container)),
|
||||
"/opt/amnezia/start.sh");
|
||||
|
||||
// qDebug().noquote() << "AAAA"
|
||||
// << amnezia::scriptData(ProtocolScriptType::container_startup, Protocol::OpenVpnOverCloak),
|
||||
// replaceVars("/opt/amnezia/start.sh",
|
||||
// genVarsForScript(credentials, container));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ErrorCode ServerController::setupShadowSocksServer(const ServerCredentials &credentials)
|
||||
{
|
||||
// Setup openvpn part
|
||||
QString scriptData;
|
||||
QString scriptFileName = ":/server_scripts/setup_shadowsocks_server.sh";
|
||||
QFile file(scriptFileName);
|
||||
if (! file.open(QIODevice::ReadOnly)) return ErrorCode::InternalError;
|
||||
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;
|
||||
// scriptData = file.readAll();
|
||||
// if (scriptData.isEmpty()) return ErrorCode::InternalError;
|
||||
|
||||
QString stdOut;
|
||||
auto cbReadStdOut = [&](const QString &data, QSharedPointer<QSsh::SshRemoteProcess> proc) {
|
||||
stdOut += data + "\n";
|
||||
// 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";
|
||||
};
|
||||
// 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;
|
||||
// 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", ssRemotePort());
|
||||
ssConfig.insert("local_port", ssContainerPort());
|
||||
ssConfig.insert("password", QString(QCryptographicHash::hash(credentials.password.toUtf8(), QCryptographicHash::Sha256).toHex()));
|
||||
ssConfig.insert("timeout", 60);
|
||||
ssConfig.insert("method", ssEncryption());
|
||||
QString configData = QJsonDocument(ssConfig).toJson();
|
||||
QString sSConfigPath = "/opt/amneziavpn_data/ssConfig.json";
|
||||
// // 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;
|
||||
// configData.replace("\"", "\\\"");
|
||||
// //qDebug().noquote() << configData;
|
||||
|
||||
uploadTextFileToContainer(DockerContainer::ShadowSocks, credentials, configData, sSConfigPath);
|
||||
// uploadTextFileToContainer(DockerContainer::ShadowSocks, credentials, configData, sSConfigPath);
|
||||
|
||||
// Start ss
|
||||
QString script = QString("sudo docker exec -d %1 sh -c \"ss-server -c %2\"").
|
||||
arg(getContainerName(DockerContainer::ShadowSocks)).arg(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;
|
||||
// e = runScript(genVarsForScript(credentials, DockerContainer::ShadowSocks), sshParams(credentials), script);
|
||||
// return e;
|
||||
}
|
||||
|
||||
QHash<QString, QString> ServerController::genVarsForScript(const ServerCredentials &credentials, DockerContainer container)
|
||||
ServerController::Vars ServerController::genVarsForScript(const ServerCredentials &credentials, DockerContainer container)
|
||||
{
|
||||
QHash<QString, QString> vars;
|
||||
Vars vars;
|
||||
|
||||
vars.insert("$CONTAINER_NAME", getContainerName(container));
|
||||
vars.append(qMakePair<QString, QString>("$VPN_SUBNET_IP", amnezia::server::vpnDefaultSubnetIp()));
|
||||
vars.append(qMakePair<QString, QString>("$VPN_SUBNET_MASK_VAL", amnezia::server::vpnDefaultSubnetMaskVal()));
|
||||
vars.append(qMakePair<QString, QString>("$VPN_SUBNET_MASK", amnezia::server::vpnDefaultSubnetMask()));
|
||||
|
||||
vars.append(qMakePair<QString, QString>("$CONTAINER_NAME", amnezia::server::getContainerName(container)));
|
||||
vars.append(qMakePair<QString, QString>("$DOCKERFILE_FOLDER", "/opt/amnezia/" + amnezia::server::getContainerName(container)));
|
||||
|
||||
QString serverIp = Utils::getIPAddress(credentials.hostName);
|
||||
if (!serverIp.isEmpty()) {
|
||||
vars.insert("$SERVER_IP_ADDRESS", serverIp);
|
||||
vars.append(qMakePair<QString, QString>("$SERVER_IP_ADDRESS", serverIp));
|
||||
}
|
||||
else {
|
||||
qWarning() << "ServerController::genVarsForScript unable to resolve address for credentials.hostName";
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
if (container == DockerContainer::OpenVpn) {
|
||||
vars.append(qMakePair<QString, QString>("$SERVER_PORT", amnezia::protocols::openvpn::openvpnDefaultPort()));
|
||||
}
|
||||
else if (container == DockerContainer::OpenVpnOverCloak) {
|
||||
vars.append(qMakePair<QString, QString>("$SERVER_PORT", amnezia::protocols::cloak::ckDefaultPort()));
|
||||
vars.append(qMakePair<QString, QString>("$FAKE_WEB_SITE_ADDRESS", amnezia::protocols::cloak::ckDefaultRedirSite()));
|
||||
}
|
||||
else if (container == DockerContainer::ShadowSocks) {
|
||||
vars.append(qMakePair<QString, QString>("$SERVER_PORT", "6789"));
|
||||
}
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
|
@ -488,9 +672,17 @@ SshConnection *ServerController::connectToHost(const SshConnectionParameters &ss
|
|||
|
||||
ErrorCode ServerController::setupServerFirewall(const ServerCredentials &credentials)
|
||||
{
|
||||
QFile file(":/server_scripts/setup_firewall.sh");
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
||||
QString script = file.readAll();
|
||||
return runScript(genVarsForScript(credentials, DockerContainer::OpenVpn), sshParams(credentials), script);
|
||||
return runScript(sshParams(credentials),
|
||||
replaceVars(amnezia::scriptData(SharedScriptType::setup_host_firewall),
|
||||
genVarsForScript(credentials, DockerContainer::OpenVpnOverCloak)));
|
||||
}
|
||||
|
||||
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);
|
||||
s.replace(var.first, var.second);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -12,18 +12,13 @@ class ServerController : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef QList<QPair<QString, QString>> Vars;
|
||||
|
||||
static ErrorCode fromSshConnectionErrorCode(QSsh::SshError error);
|
||||
|
||||
// QSsh exitCode and exitStatus are different things
|
||||
static ErrorCode fromSshProcessExitStatus(int exitStatus);
|
||||
|
||||
static QString caCertPath() { return "/opt/amneziavpn_data/pki/ca.crt"; }
|
||||
static QString clientCertPath() { return "/opt/amneziavpn_data/pki/issued/"; }
|
||||
static QString taKeyPath() { return "/opt/amneziavpn_data/ta.key"; }
|
||||
|
||||
static QString getContainerName(amnezia::DockerContainer container);
|
||||
|
||||
static QSsh::SshConnectionParameters sshParams(const ServerCredentials &credentials);
|
||||
|
||||
static ErrorCode removeServer(const ServerCredentials &credentials, Protocol proto);
|
||||
|
@ -31,33 +26,32 @@ public:
|
|||
|
||||
static ErrorCode checkOpenVpnServer(DockerContainer container, const ServerCredentials &credentials);
|
||||
|
||||
static ErrorCode uploadFileToHost(const ServerCredentials &credentials, const QByteArray &data, const QString &remotePath);
|
||||
|
||||
static ErrorCode uploadTextFileToContainer(DockerContainer container,
|
||||
const ServerCredentials &credentials, QString &file, const QString &path);
|
||||
const ServerCredentials &credentials, const QString &file, const QString &path);
|
||||
|
||||
static QString getTextFileFromContainer(DockerContainer container,
|
||||
const ServerCredentials &credentials, const QString &path, ErrorCode *errorCode = nullptr);
|
||||
|
||||
static ErrorCode signCert(DockerContainer container,
|
||||
const ServerCredentials &credentials, QString clientId);
|
||||
|
||||
static int ssRemotePort() { return 6789; } // TODO move to ShadowSocksDefs.h
|
||||
static int ssContainerPort() { return 8585; } // TODO move to ShadowSocksDefs.h
|
||||
static QString ssEncryption() { return "chacha20-ietf-poly1305"; } // TODO move to ShadowSocksDefs.h
|
||||
|
||||
static ErrorCode setupServerFirewall(const ServerCredentials &credentials);
|
||||
private:
|
||||
static QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams);
|
||||
|
||||
static ErrorCode runScript(const QHash<QString, QString> &vars,
|
||||
const QSsh::SshConnectionParameters &sshParams, QString script,
|
||||
static QString replaceVars(const QString &script, const Vars &vars);
|
||||
|
||||
static ErrorCode runScript(const QSsh::SshConnectionParameters &sshParams, QString script,
|
||||
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdOut = nullptr,
|
||||
const std::function<void(const QString &, QSharedPointer<QSsh::SshRemoteProcess>)> &cbReadStdErr = nullptr);
|
||||
|
||||
static Vars genVarsForScript(const ServerCredentials &credentials, DockerContainer container = DockerContainer::None);
|
||||
|
||||
private:
|
||||
static QSsh::SshConnection *connectToHost(const QSsh::SshConnectionParameters &sshParams);
|
||||
|
||||
static ErrorCode installDocker(const ServerCredentials &credentials);
|
||||
|
||||
static ErrorCode setupOpenVpnServer(const ServerCredentials &credentials);
|
||||
static ErrorCode setupOpenVpnOverCloakServer(const ServerCredentials &credentials);
|
||||
static ErrorCode setupShadowSocksServer(const ServerCredentials &credentials);
|
||||
|
||||
|
||||
static QHash<QString, QString> genVarsForScript(const ServerCredentials &credentials, DockerContainer container);
|
||||
};
|
||||
|
||||
#endif // SERVERCONTROLLER_H
|
||||
|
|
105
client/protocols/openvpnovercloakprotocol.cpp
Normal file
105
client/protocols/openvpnovercloakprotocol.cpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
#include "openvpnovercloakprotocol.h"
|
||||
#include "core/servercontroller.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "protocols/protocols_defs.h"
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
OpenVpnOverCloakProtocol::OpenVpnOverCloakProtocol(const QJsonObject &configuration, QObject *parent):
|
||||
OpenVpnProtocol(configuration, parent)
|
||||
{
|
||||
readCloakConfiguration(configuration);
|
||||
}
|
||||
|
||||
OpenVpnOverCloakProtocol::~OpenVpnOverCloakProtocol()
|
||||
{
|
||||
qDebug() << "OpenVpnOverCloakProtocol::~OpenVpnOverCloakProtocol";
|
||||
OpenVpnOverCloakProtocol::stop();
|
||||
QThread::msleep(200);
|
||||
m_ckProcess.close();
|
||||
}
|
||||
|
||||
ErrorCode OpenVpnOverCloakProtocol::start()
|
||||
{
|
||||
if (Utils::processIsRunning(Utils::executable("ck-client", false))) {
|
||||
Utils::killProcessByName(Utils::executable("ck-client", false));
|
||||
}
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
m_cloakCfgFile.setAutoRemove(false);
|
||||
#endif
|
||||
m_cloakCfgFile.open();
|
||||
m_cloakCfgFile.write(QJsonDocument(m_cloakConfig).toJson());
|
||||
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();
|
||||
|
||||
qDebug().noquote() << "OpenVpnOverCloakProtocol::start()"
|
||||
<< cloakExecPath() << args.join(" ");
|
||||
|
||||
m_ckProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
m_ckProcess.setProgram(cloakExecPath());
|
||||
m_ckProcess.setArguments(args);
|
||||
|
||||
connect(&m_ckProcess, &QProcess::readyReadStandardOutput, this, [this](){
|
||||
qDebug().noquote() << "ck-client:" << m_ckProcess.readAllStandardOutput();
|
||||
});
|
||||
|
||||
connect(&m_ckProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, [this](int exitCode, QProcess::ExitStatus exitStatus){
|
||||
qDebug().noquote() << "OpenVpnOverCloakProtocol finished, exitCode, exiStatus" << exitCode << exitStatus;
|
||||
setConnectionState(VpnProtocol::ConnectionState::Disconnected);
|
||||
if (exitStatus != QProcess::NormalExit){
|
||||
emit protocolError(amnezia::ErrorCode::CloakExecutableCrashed);
|
||||
stop();
|
||||
}
|
||||
if (exitCode !=0 ){
|
||||
emit protocolError(amnezia::ErrorCode::InternalError);
|
||||
stop();
|
||||
}
|
||||
});
|
||||
|
||||
m_ckProcess.start();
|
||||
m_ckProcess.waitForStarted();
|
||||
|
||||
if (m_ckProcess.state() == QProcess::ProcessState::Running) {
|
||||
setConnectionState(ConnectionState::Connecting);
|
||||
|
||||
return OpenVpnProtocol::start();
|
||||
}
|
||||
else return ErrorCode::CloakExecutableMissing;
|
||||
}
|
||||
|
||||
void OpenVpnOverCloakProtocol::stop()
|
||||
{
|
||||
OpenVpnProtocol::stop();
|
||||
|
||||
qDebug() << "OpenVpnOverCloakProtocol::stop()";
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
Utils::signalCtrl(m_ckProcess.processId(), CTRL_C_EVENT);
|
||||
#endif
|
||||
|
||||
m_ckProcess.terminate();
|
||||
}
|
||||
|
||||
QString OpenVpnOverCloakProtocol::cloakExecPath()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
return Utils::executable(QString("cloak/ck-client"), true);
|
||||
#else
|
||||
return Utils::executable(QString("/ck-client"), true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OpenVpnOverCloakProtocol::readCloakConfiguration(const QJsonObject &configuration)
|
||||
{
|
||||
m_cloakConfig = configuration.value(config::key_cloak_config_data()).toObject();
|
||||
}
|
30
client/protocols/openvpnovercloakprotocol.h
Normal file
30
client/protocols/openvpnovercloakprotocol.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef OPENVPNOVERCLOAKPROTOCOL_H
|
||||
#define OPENVPNOVERCLOAKPROTOCOL_H
|
||||
|
||||
#include "openvpnprotocol.h"
|
||||
#include "QProcess"
|
||||
|
||||
class OpenVpnOverCloakProtocol : public OpenVpnProtocol
|
||||
{
|
||||
public:
|
||||
OpenVpnOverCloakProtocol(const QJsonObject& configuration, QObject* parent = nullptr);
|
||||
virtual ~OpenVpnOverCloakProtocol() override;
|
||||
|
||||
ErrorCode start() override;
|
||||
void stop() override;
|
||||
|
||||
protected:
|
||||
void readCloakConfiguration(const QJsonObject &configuration);
|
||||
|
||||
protected:
|
||||
QJsonObject m_cloakConfig;
|
||||
|
||||
private:
|
||||
static QString cloakExecPath();
|
||||
|
||||
private:
|
||||
QProcess m_ckProcess;
|
||||
QTemporaryFile m_cloakCfgFile;
|
||||
};
|
||||
|
||||
#endif // OPENVPNOVERCLOAKPROTOCOL_H
|
36
client/protocols/protocols_defs.h
Normal file
36
client/protocols/protocols_defs.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef PROTOCOLS_DEFS_H
|
||||
#define PROTOCOLS_DEFS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace amnezia {
|
||||
namespace protocols {
|
||||
namespace openvpn {
|
||||
static QString caCertPath() { return "/opt/amnezia/openvpn/pki/ca.crt"; }
|
||||
static QString clientCertPath() { return "/opt/amnezia/openvpn/pki/issued"; }
|
||||
static QString taKeyPath() { return "/opt/amnezia/openvpn/ta.key"; }
|
||||
static QString clientsDirPath() { return "/opt/amnezia/openvpn/clients"; }
|
||||
static QString openvpnDefaultPort() { return "1194"; }
|
||||
|
||||
}
|
||||
|
||||
namespace shadowsocks {
|
||||
static int ssRemotePort() { return 6789; }
|
||||
static int ssContainerPort() { return 8585; }
|
||||
static QString ssEncryption() { return "chacha20-ietf-poly1305"; }
|
||||
}
|
||||
|
||||
namespace cloak {
|
||||
static QString ckPublicKeyPath() { return "/opt/amnezia/cloak/cloak_public.key"; }
|
||||
static QString ckBypassUidKeyPath() { return "/opt/amnezia/cloak/cloak_bypass_uid.key"; }
|
||||
static QString ckAdminKeyPath() { return "/opt/amnezia/cloak/cloak_admin_uid.key"; }
|
||||
static QString ckDefaultPort() { return "443"; }
|
||||
static QString ckDefaultRedirSite() { return "mail.ru"; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace protocols
|
||||
} // namespace amnezia
|
||||
|
||||
#endif // PROTOCOLS_DEFS_H
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "debug.h"
|
||||
#include "utils.h"
|
||||
#include "protocols/protocols_defs.h"
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QJsonDocument>
|
||||
|
@ -99,11 +100,11 @@ QJsonObject ShadowSocksVpnProtocol::genShadowSocksConfig(const ServerCredentials
|
|||
{
|
||||
QJsonObject ssConfig;
|
||||
ssConfig.insert("server", credentials.hostName);
|
||||
ssConfig.insert("server_port", ServerController::ssRemotePort());
|
||||
ssConfig.insert("local_port", ServerController::ssContainerPort());
|
||||
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", ServerController::ssEncryption());
|
||||
ssConfig.insert("method", amnezia::protocols::shadowsocks::ssEncryption());
|
||||
return ssConfig;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,14 @@
|
|||
<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_firewall.sh</file>
|
||||
<file>server_scripts/setup_host_firewall.sh</file>
|
||||
<file>images/reload.png</file>
|
||||
<file>server_scripts/openvpn_cloak/Dockerfile</file>
|
||||
<file>server_scripts/openvpn_cloak/configure_container.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/start.sh</file>
|
||||
<file>server_scripts/openvpn_cloak/template.ovpn</file>
|
||||
<file>server_scripts/install_docker.sh</file>
|
||||
<file>server_scripts/build_container.sh</file>
|
||||
<file>server_scripts/prepare_host.sh</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
1
client/server_scripts/build_container.sh
Normal file
1
client/server_scripts/build_container.sh
Normal file
|
@ -0,0 +1 @@
|
|||
sudo docker build -t $CONTAINER_NAME $DOCKERFILE_FOLDER
|
6
client/server_scripts/install_docker.sh
Normal file
6
client/server_scripts/install_docker.sh
Normal file
|
@ -0,0 +1,6 @@
|
|||
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
|
||||
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
|
||||
|
52
client/server_scripts/openvpn_cloak/Dockerfile
Normal file
52
client/server_scripts/openvpn_cloak/Dockerfile
Normal file
|
@ -0,0 +1,52 @@
|
|||
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
|
||||
|
||||
RUN curl -L https://github.com/cbeuw/Cloak/releases/download/v2.5.3/ck-server-linux-amd64-v2.5.3 > /usr/bin/ck-server
|
||||
RUN chmod a+x /usr/bin/ck-server
|
||||
|
||||
# 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 [ "" ]
|
84
client/server_scripts/openvpn_cloak/configure_container.sh
Normal file
84
client/server_scripts/openvpn_cloak/configure_container.sh
Normal file
|
@ -0,0 +1,84 @@
|
|||
# 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 $SERVER_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 $SERVER_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\
|
||||
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\
|
||||
cipher AES-256-GCM \\n\
|
||||
ncp-ciphers AES-256-GCM:AES-256-CBC \\n\
|
||||
auth SHA512 \\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'
|
||||
|
||||
#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; \
|
||||
cd /opt/amnezia/cloak || exit 1; \
|
||||
CLOAK_ADMIN_UID=$(ck-server -u) && echo $CLOAK_ADMIN_UID > /opt/amnezia/cloak/cloak_admin_uid.key; \
|
||||
CLOAK_BYPASS_UID=$(ck-server -u) && echo $CLOAK_BYPASS_UID > /opt/amnezia/cloak/cloak_bypass_uid.key; \
|
||||
IFS=, read CLOAK_PUBLIC_KEY CLOAK_PRIVATE_KEY <<<$(ck-server -k); \
|
||||
echo $CLOAK_PUBLIC_KEY > /opt/amnezia/cloak/cloak_public.key; \
|
||||
echo $CLOAK_PRIVATE_KEY > /opt/amnezia/cloak/cloak_private.key; \
|
||||
echo -e "{\\n\
|
||||
\"ProxyBook\": {\\n\
|
||||
\"openvpn\": [\\n\
|
||||
\"tcp\",\\n\
|
||||
\"localhost:1194\"\\n\
|
||||
]\\n\
|
||||
},\\n\
|
||||
\"BypassUID\": [\\n\
|
||||
\"$CLOAK_BYPASS_UID\"\\n\
|
||||
],\\n\
|
||||
\"BindAddr\":[\":443\"],\\n\
|
||||
\"RedirAddr\": \"$FAKE_WEB_SITE_ADDRESS\",\\n\
|
||||
\"PrivateKey\": \"$CLOAK_PRIVATE_KEY\",\\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"
|
23
client/server_scripts/openvpn_cloak/start.sh
Normal file
23
client/server_scripts/openvpn_cloak/start.sh
Normal file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This scripts copied from Amnezia client to Docker container to /opt/amnezia and launched every time container starts
|
||||
|
||||
echo "Container Startup start"
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
tail -f /dev/null
|
35
client/server_scripts/openvpn_cloak/template.ovpn
Normal file
35
client/server_scripts/openvpn_cloak/template.ovpn
Normal file
|
@ -0,0 +1,35 @@
|
|||
client
|
||||
dev tun
|
||||
proto $PROTO
|
||||
resolv-retry infinite
|
||||
nobind
|
||||
persist-key
|
||||
persist-tun
|
||||
cipher AES-256-GCM
|
||||
auth SHA512
|
||||
verb 3
|
||||
tls-client
|
||||
tls-version-min 1.2
|
||||
key-direction 1
|
||||
remote-cert-tls server
|
||||
redirect-gateway def1 bypass-dhcp
|
||||
|
||||
dhcp-option DNS $PRIMARY_DNS
|
||||
dhcp-option DNS $SECONDARY_DNS
|
||||
block-outside-dns
|
||||
|
||||
route $REMOTE_HOST 255.255.255.255 net_gateway
|
||||
remote 127.0.0.1 1194
|
||||
|
||||
<ca>
|
||||
$CA_CERT
|
||||
</ca>
|
||||
<cert>
|
||||
$CLIENT_CERT
|
||||
</cert>
|
||||
<key>
|
||||
$PRIV_KEY
|
||||
</key>
|
||||
<tls-auth>
|
||||
$TA_KEY
|
||||
</tls-auth>
|
3
client/server_scripts/prepare_host.sh
Normal file
3
client/server_scripts/prepare_host.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
CUR_USER=$(whoami);\
|
||||
sudo mkdir -p $DOCKERFILE_FOLDER;\
|
||||
sudo chown $CUR_USER $DOCKERFILE_FOLDER
|
|
@ -1,24 +1,31 @@
|
|||
sudo sysctl -w net.ipv4.ip_forward=1
|
||||
sudo iptables -P FORWARD ACCEPT
|
||||
sudo iptables -C INPUT -p icmp --icmp-type echo-request -j DROP || sudo iptables -A INPUT -p icmp --icmp-type echo-request -j DROP
|
||||
|
||||
#sudo iptables -P FORWARD ACCEPT
|
||||
sudo iptables -A FORWARD -j DOCKER-USER
|
||||
sudo iptables -A FORWARD -j DOCKER-ISOLATION-STAGE-1
|
||||
sudo iptables -A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
sudo iptables -A FORWARD -o docker0 -j DOCKER
|
||||
sudo iptables -A FORWARD -i docker0 ! -o docker0 -j ACCEPT
|
||||
sudo iptables -A FORWARD -i docker0 -o docker0 -j ACCEPT
|
||||
|
||||
# Tuning network
|
||||
sudo sysctl fs.file-max=51200
|
||||
sudo sysctl net.core.rmem_max=67108864
|
||||
sudo sysctl net.core.wmem_max=67108864
|
||||
sudo sysctl net.core.netdev_max_backlog=250000
|
||||
sudo sysctl net.core.somaxconn=4096
|
||||
sudo sysctl net.ipv4.tcp_syncookies=1
|
||||
sudo sysctl net.ipv4.tcp_tw_reuse=1
|
||||
sudo sysctl net.ipv4.tcp_tw_recycle=0
|
||||
sudo sysctl net.ipv4.tcp_fin_timeout=30
|
||||
sudo sysctl net.ipv4.tcp_keepalive_time=1200
|
||||
sudo sysctl net.ipv4.ip_local_port_range="10000 65000"
|
||||
sudo sysctl net.ipv4.tcp_max_syn_backlog=8192
|
||||
sudo sysctl net.ipv4.tcp_max_tw_buckets=5000
|
||||
sudo sysctl net.ipv4.tcp_fastopen=3
|
||||
sudo sysctl net.ipv4.tcp_mem="25600 51200 102400"
|
||||
sudo sysctl net.ipv4.tcp_rmem="4096 87380 67108864"
|
||||
sudo sysctl net.ipv4.tcp_wmem="4096 65536 67108864"
|
||||
sudo sysctl net.ipv4.tcp_mtu_probing=1
|
||||
sudo sysctl fs.file-max=51200; \
|
||||
sudo sysctl net.core.rmem_max=67108864; \
|
||||
sudo sysctl net.core.wmem_max=67108864; \
|
||||
sudo sysctl net.core.netdev_max_backlog=250000; \
|
||||
sudo sysctl net.core.somaxconn=4096; \
|
||||
sudo sysctl net.ipv4.tcp_syncookies=1; \
|
||||
sudo sysctl net.ipv4.tcp_tw_reuse=1; \
|
||||
sudo sysctl net.ipv4.tcp_tw_recycle=0; \
|
||||
sudo sysctl net.ipv4.tcp_fin_timeout=30; \
|
||||
sudo sysctl net.ipv4.tcp_keepalive_time=1200; \
|
||||
sudo sysctl net.ipv4.ip_local_port_range="10000 65000"; \
|
||||
sudo sysctl net.ipv4.tcp_max_syn_backlog=8192; \
|
||||
sudo sysctl net.ipv4.tcp_max_tw_buckets=5000; \
|
||||
sudo sysctl net.ipv4.tcp_fastopen=3; \
|
||||
sudo sysctl net.ipv4.tcp_mem="25600 51200 102400"; \
|
||||
sudo sysctl net.ipv4.tcp_rmem="4096 87380 67108864"; \
|
||||
sudo sysctl net.ipv4.tcp_wmem="4096 65536 67108864"; \
|
||||
sudo sysctl net.ipv4.tcp_mtu_probing=1; \
|
||||
sudo sysctl net.ipv4.tcp_congestion_control=hybla
|
||||
|
|
|
@ -12,17 +12,18 @@ 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 1194:1194/tcp -p 6789:6789/tcp --name $CONTAINER_NAME 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"
|
||||
|
||||
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"
|
||||
# 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 -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"
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <protocols/shadowsocksvpnprotocol.h>
|
||||
|
||||
#include "core/errorstrings.h"
|
||||
#include "core/openvpnconfigurator.h"
|
||||
#include "configurators/openvpn_configurator.h"
|
||||
#include "core/servercontroller.h"
|
||||
#include "ui/qautostart.h"
|
||||
|
||||
|
@ -111,6 +111,9 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
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->toolBox_share_connection->removeItem(ui->toolBox_share_connection->indexOf(ui->page_share_shadowsocks));
|
||||
ui->page_share_shadowsocks->setVisible(false);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
|
|
|
@ -1918,7 +1918,7 @@ background: #211966;
|
|||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Software version: 1.5.3 (19.03.2021)</string>
|
||||
<string>Software version: 1.6.0 (31.03.2021)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
|
@ -2659,8 +2659,8 @@ background: #282932;
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>360</width>
|
||||
<height>500</height>
|
||||
<width>100</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
|
|
|
@ -4,11 +4,24 @@
|
|||
#include <QHostAddress>
|
||||
#include <QHostInfo>
|
||||
#include <QProcess>
|
||||
#include <QRandomGenerator>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "defines.h"
|
||||
#include "utils.h"
|
||||
|
||||
QString Utils::getRandomString(int len)
|
||||
{
|
||||
const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
||||
|
||||
QString randomString;
|
||||
for(int i=0; i<len; ++i) {
|
||||
quint32 index = QRandomGenerator::global()->generate() % possibleCharacters.length();
|
||||
QChar nextChar = possibleCharacters.at(index);
|
||||
randomString.append(nextChar);
|
||||
}
|
||||
return randomString;
|
||||
}
|
||||
|
||||
QString Utils::defaultVpnConfigFileName()
|
||||
{
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
class Utils {
|
||||
|
||||
public:
|
||||
static QString getRandomString(int len);
|
||||
|
||||
static QString configPath();
|
||||
static QString defaultVpnConfigFileName();
|
||||
static QString executable(const QString& baseName, bool absPath);
|
||||
|
|
|
@ -3,13 +3,16 @@
|
|||
#include <QFile>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <core/openvpnconfigurator.h>
|
||||
#include <configurators/openvpn_configurator.h>
|
||||
#include <configurators/cloak_configurator.h>
|
||||
#include <core/servercontroller.h>
|
||||
|
||||
#include "ipc.h"
|
||||
#include "core/ipcclient.h"
|
||||
#include "protocols/openvpnprotocol.h"
|
||||
#include "protocols/openvpnovercloakprotocol.h"
|
||||
#include "protocols/shadowsocksvpnprotocol.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "vpnconnection.h"
|
||||
|
||||
|
@ -80,7 +83,7 @@ ErrorCode VpnConnection::lastError() const
|
|||
ErrorCode VpnConnection::createVpnConfiguration(const ServerCredentials &credentials, Protocol protocol)
|
||||
{
|
||||
ErrorCode errorCode = ErrorCode::NoError;
|
||||
if (protocol == Protocol::OpenVpn || protocol == Protocol::ShadowSocks) {
|
||||
if (protocol == Protocol::OpenVpn || protocol == Protocol::ShadowSocks || protocol == Protocol::OpenVpnOverCloak) {
|
||||
QString openVpnConfigData = OpenVpnConfigurator::genOpenVpnConfig(credentials, protocol, &errorCode);
|
||||
m_vpnConfiguration.insert(config::key_openvpn_config_data(), openVpnConfigData);
|
||||
if (errorCode) {
|
||||
|
@ -91,6 +94,7 @@ ErrorCode VpnConnection::createVpnConfiguration(const ServerCredentials &credent
|
|||
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)){
|
||||
QTextStream stream(&file);
|
||||
stream << openVpnConfigData << endl;
|
||||
file.close();
|
||||
}
|
||||
else {
|
||||
return ErrorCode::FailedToSaveConfigData;
|
||||
|
@ -102,6 +106,11 @@ ErrorCode VpnConnection::createVpnConfiguration(const ServerCredentials &credent
|
|||
m_vpnConfiguration.insert(config::key_shadowsocks_config_data(), ssConfigData);
|
||||
}
|
||||
|
||||
if (protocol == Protocol::OpenVpnOverCloak) {
|
||||
QJsonObject cloakConfigData = CloakConfigurator::genCloakConfig(credentials, Protocol::OpenVpnOverCloak, &errorCode);
|
||||
m_vpnConfiguration.insert(config::key_cloak_config_data(), cloakConfigData);
|
||||
}
|
||||
|
||||
//qDebug().noquote() << "VPN config" << QJsonDocument(m_vpnConfiguration).toJson();
|
||||
return ErrorCode::NoError;
|
||||
}
|
||||
|
@ -111,7 +120,8 @@ ErrorCode VpnConnection::connectToVpn(const ServerCredentials &credentials, Prot
|
|||
qDebug() << "connectToVpn, CustomRouting is" << m_settings.customRouting();
|
||||
// qDebug() << "Cred" << m_settings.serverCredentials().hostName <<
|
||||
// m_settings.serverCredentials().password;
|
||||
protocol = Protocol::ShadowSocks;
|
||||
//protocol = Protocol::ShadowSocks;
|
||||
protocol = Protocol::OpenVpnOverCloak;
|
||||
|
||||
// TODO: Try protocols one by one in case of Protocol::Any
|
||||
// TODO: Implement some behavior in case if connection not stable
|
||||
|
@ -156,6 +166,20 @@ ErrorCode VpnConnection::connectToVpn(const ServerCredentials &credentials, Prot
|
|||
return e;
|
||||
}
|
||||
}
|
||||
else if (protocol == Protocol::OpenVpnOverCloak) {
|
||||
ErrorCode e = createVpnConfiguration(credentials, Protocol::OpenVpnOverCloak);
|
||||
if (e) {
|
||||
emit connectionStateChanged(VpnProtocol::ConnectionState::Error);
|
||||
return e;
|
||||
}
|
||||
|
||||
m_vpnProtocol.reset(new OpenVpnOverCloakProtocol(m_vpnConfiguration));
|
||||
e = static_cast<OpenVpnProtocol *>(m_vpnProtocol.data())->checkAndSetupTapDriver();
|
||||
if (e) {
|
||||
emit connectionStateChanged(VpnProtocol::ConnectionState::Error);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
connect(m_vpnProtocol.data(), &VpnProtocol::protocolError, this, &VpnConnection::vpnProtocolError);
|
||||
connect(m_vpnProtocol.data(), SIGNAL(connectionStateChanged(VpnProtocol::ConnectionState)), this, SLOT(onConnectionStateChanged(VpnProtocol::ConnectionState)));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue